### Set up Development Environment Source: https://github.com/jellezijlstra/pycroscope/blob/main/CONTRIBUTING.md Use these commands to set up a virtual environment and install development dependencies. ```bash $ cd pycroscope $ uv sync --frozen --extra tests --extra full --group docs ``` -------------------------------- ### Install Pycroscope Source: https://github.com/jellezijlstra/pycroscope/blob/main/README.md Install pycroscope using pip. For full functionality including optional dependencies, use `pip install pycroscope[full]`. ```bash pip install pycroscope ``` -------------------------------- ### Install Pycroscope CLI Source: https://context7.com/jellezijlstra/pycroscope/llms.txt Install Pycroscope and its optional extras for enhanced functionality. ```bash pip install pycroscope pip install pycroscope[full] # asynq, codemod, ast_decompiler extras ``` -------------------------------- ### PredicateProvider Example Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/stacked_scopes.md Demonstrates how a PredicateProvider is used to create constraints based on a predicate function. Equality checks on the return value generate a constraint that filters values. ```python def two_lengths(tpl: tuple[int] | tuple[str, int]) -> int: if len(tpl) == 1: return tpl[0] else: return tpl[1] ``` -------------------------------- ### dump_value() usage example Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/value.md Demonstrates how to use dump_value() to show inferred values during type checking. ```APIDOC ## dump_value() ### Description Can be used to show inferred values during type checking. ### Method `dump_value(value: Any)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```python from typing import Any from pycroscope import dump_value def function(x: int, y: list[int], z: Any): dump_value(1) # Literal[1] dump_value(x) # int dump_value(y) # list[int] dump_value(z) # Any ``` ### Response None ERROR HANDLING: None ``` -------------------------------- ### Pycroscope Visitor Output Example Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/design.md Demonstrates the command-line output when running the `BadStatementFinder` visitor on a file containing `import a` and `assert True`. Shows error messages with location information. ```text $ python example_visitor.py example.py Error: found_import (code: found_import) In example.py at line 1: 1: import a ^ 2: assert True 3: Error: found_assert (code: found_assert) In example.py at line 2: 1: import a 2: assert True ^ 3: ``` -------------------------------- ### AsynqCallable Type Hint Examples Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/extensions.md Illustrates how to use AsynqCallable for type hinting asynchronous functions decorated with @asynq(). Supports various argument and return type specifications. ```python AsynqCallable[..., int] # may take any arguments, returns an int AsynqCallable[[int], str] # takes an int, returns a str ``` -------------------------------- ### ParameterTypeGuard Example Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/extensions.md Demonstrates using ParameterTypeGuard with Annotated to create a type guard for a function parameter. Ensures the parameter matches a specific type before proceeding. ```python def is_int(arg: object) -> Annotated[bool, ParameterTypeGuard["arg", int]]: return isinstance(arg, int) ``` -------------------------------- ### Get Generic Bases with Typed Values Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/value.md Demonstrates how to retrieve base classes for a type with specific generic arguments. Useful for understanding type inheritance with generics. ```default { dict: [TypedValue(int), TypedValue(str)], Mapping: [TypedValue(int), TypedValue(str)], Iterable: [TypedValue(int)], Sized: [], } ``` -------------------------------- ### Pycroscope Node Visitor: Finding Assert and Import Statements Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/design.md Shows a custom visitor extending `pycroscope.node_visitor.BaseNodeVisitor` to identify and report `assert` and `import` statements. This example requires `enum` and `pycroscope.node_visitor`. Errors can be suppressed via command-line arguments. ```python import enum from pycroscope import node_visitor class ErrorCode(enum.Enum): found_assert = 1 found_import = 2 class BadStatementFinder(node_visitor.BaseNodeVisitor): error_code_enum = ErrorCode def visit_Assert(self, node): self.show_error(node, error_code=ErrorCode.found_assert) def visit_Import(self, node): self.show_error(node, error_code=ErrorCode.found_import) if __name__ == '__main__': BadStatementFinder.main() ``` -------------------------------- ### ValidRegex Custom Check Example Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/extensions.md Shows how to use the ValidRegex custom check to ensure string arguments are valid regular expressions. Prevents runtime errors from invalid regex patterns. ```python def func(arg: Annotated[str, ValidRegex()]) -> None: ... func(".*") # ok func("[") # error ``` -------------------------------- ### Get Runtime Overloads Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/extensions.md Retrieve all defined runtime overloads for a given fully qualified function name. ```python get_overloads("some_module.some_function") ``` -------------------------------- ### CustomCheck with LiteralOnly Example Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/extensions.md Demonstrates how to create a CustomCheck subclass to enforce literal values. Use when values must be statically known and not dynamically generated. ```python class LiteralOnly(CustomCheck): def can_assign(self, value: "Value", ctx: "CanAssignContext") -> "CanAssign": for subval in pycroscope.value.flatten_values(value): if not isinstance(subval, pycroscope.value.KnownValue): return pycroscope.value.CanAssignError("Value must be a literal") return {} def func(arg: Annotated[str, LiteralOnly()]) -> None: ... func("x") # ok func(str(some_call())) # error ``` -------------------------------- ### FunctionScope Variable Tracking Example Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/stacked_scopes.md Illustrates how FunctionScope infers the final value of a variable across multiple assignments, contrasting with the base Scope's MultiValuedValue. ```default x = 3 x = 4 print(x) ``` -------------------------------- ### Selectively Run Pytest Tests Source: https://github.com/jellezijlstra/pycroscope/blob/main/CONTRIBUTING.md Use the -k option with Pytest to run specific tests, for example, tests related to PEP673. ```bash $ uv run --extra tests pytest -v pycroscope -k PEP673 ``` -------------------------------- ### Annotated Types Integration for Type Narrowing Source: https://context7.com/jellezijlstra/pycroscope/llms.txt Demonstrates how Pycroscope integrates with the annotated-types library to enforce predicates and perform flow-sensitive narrowing. This includes examples with Gt, MinLen, and MultipleOf. ```python from typing import Annotated from annotated_types import Gt, Ge, Lt, Le, MinLen, MaxLen, MultipleOf def takes_positive(x: Annotated[int, Gt(0)]) -> None: ... def takes_nonempty(xs: Annotated[list[str], MinLen(1)]) -> None: ... def takes_even(n: Annotated[int, MultipleOf(2)]) -> None: ... def caller(i: int, items: list[str]) -> None: takes_positive(i) # ERROR: i might be <= 0 if i > 0: takes_positive(i) # ok — pycroscope narrows via comparison takes_nonempty(items) # ERROR: items might be empty if len(items) >= 1: takes_nonempty(items) # ok — pycroscope narrows via len() check takes_even(4) # ok takes_even(3) # ERROR: 3 % 2 != 0 ``` -------------------------------- ### Detect invalid argument usage with is_provided() Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/type_evaluation.md This example demonstrates an error case where `is_provided()` is called with an identifier `x` that is not a function parameter, highlighting the importance of correct argument referencing. ```python def invalid(arg: object) -> None: if is_provided(x): # error, not a function parameter show_error("error") ``` -------------------------------- ### Simple Evaluated Function Example Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/type_evaluation.md Demonstrates a basic `@evaluated` function that returns different types (`int` or `str`) based on the presence of arguments. This function can be used to dynamically determine a return type. ```python from pycroscope.extensions import evaluated, is_provided from typing import Union @evaluated def simple_evaluated(x: int, y: str = ""): if is_provided(y): return int else: return str def simple_evaluated(*args: object) -> Union[int, str]: if len(args) >= 2: return 1 else: return "x" ``` -------------------------------- ### ParameterTypeGuard for Multiple Parameters Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/typesystem.md Illustrates Pycroscope's extension of PEP 647's `TypeGuard` using `Annotated` to support type guards on any function parameter, not just the first. This example narrows the types of 'args' and 'keywords' parameters. ```python from typing import Iterable, Annotated from pycroscope.extensions import ParameterTypeGuard from pycroscope.value import KnownValue, Value def _can_perform_call( args: Iterable[Value], keywords: Iterable[Value] ) -> Annotated[ bool, ParameterTypeGuard["args", Iterable[KnownValue]], ParameterTypeGuard["keywords", Iterable[KnownValue]], ]: return all(isinstance(arg, KnownValue) for arg in args) and all( isinstance(kwarg, KnownValue) for kwarg in keywords ) ``` -------------------------------- ### Extended Literals with Callables in Pycroscope Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/typesystem.md Demonstrates how Pycroscope accepts compatible callables for Literal types over function types, allowing for more flexible callable type annotations. This example shows both accepted and rejected callable assignments. ```python from typing_extensions import Literal def template(x: int, y: str = "") -> None: pass def takes_template(func: Literal[template]) -> None: func(x=1, y="x") def good_callable(x: int, y: str = "default", z: float = 0.0) -> None: pass takes_template(good_callable) # accepted def bad_callable(not_x: int, y: str = "") -> None: pass takes_template(bad_callable) # rejected ``` -------------------------------- ### Define Generic CustomCheck for Integer Range Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/typesystem.md Implement a generic CustomCheck to support types with additional constraints, like integers within a specific range. This example shows the setup for such a check. ```python from dataclasses import dataclass from pycroscope.extensions import CustomCheck from pycroscope.value import ( AnyValue, flatten_values, CanAssign, CanAssignError, CanAssignContext, KnownValue, TypeVarMap, TypeVarValue, Value, ) from typing_extensions import Annotated, TypeGuard from typing import Iterable, TypeVar, Union ``` -------------------------------- ### Get Signature Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/value.md Retrieves the signature for a given object. Returns None if the object is not callable. ```default get_signature(obj: object) → [Signature](signature.md#pycroscope.signature.Signature) | [OverloadedSignature](signature.md#pycroscope.signature.OverloadedSignature) | None ``` -------------------------------- ### Run Conformance CI Source: https://github.com/jellezijlstra/pycroscope/blob/main/AGENTS.md Use this command from the repo root to run conformance CI with a specific Python version and typing repository. ```bash UV_CACHE_DIR=/tmp/uv-cache uv run --python 3.12 python tools/conformance_ci.py --typing-repo ~/py/typing ``` -------------------------------- ### Configure Third-Party CI Local Paths Source: https://github.com/jellezijlstra/pycroscope/blob/main/CONTRIBUTING.md Define local checkout paths for third-party repositories in the tools/third_party_ci_local.toml file. Command-line values override this configuration. ```toml [local] taxonomy = "/path/to/taxonomy" ``` -------------------------------- ### Get MRO of a Class Source: https://context7.com/jellezijlstra/pycroscope/llms.txt Demonstrates how to retrieve the Method Resolution Order (MRO) of a class using the get_mro function. ```python print(get_mro(int)) # (, ) ``` -------------------------------- ### Format Code with Black Source: https://github.com/jellezijlstra/pycroscope/blob/main/CONTRIBUTING.md Run the Black formatter to ensure code adheres to project style guidelines. ```bash $ uv run --with black black pycroscope ``` -------------------------------- ### Get Relation Cache Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/value.md Retrieves the storage used for relation memoization, if supported by the current context. Returns None if not supported. ```default get_relation_cache() → MutableMapping[object, object] | None ``` -------------------------------- ### Python AST Module: Finding Import Statements with NodeVisitor Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/design.md Illustrates how to subclass `ast.NodeVisitor` to create a custom visitor that specifically finds and reports `import` statements within a Python AST. Requires the `ast` module. ```python class ImportFinder(ast.NodeVisitor): def visit_Import(self, node): print("Found import statement: %s" % ast.dump(node)) ``` -------------------------------- ### Get Type Parameters Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/value.md Returns the declared generic parameters for a type, such as TypeVars or ParamSpecs. Essential for understanding type definitions. ```default get_type_parameters(typ: type | [ClassOwner](#pycroscope.value.ClassOwner)) → Sequence[[TypeVarParam](#pycroscope.value.TypeVarParam) | [ParamSpecParam](#pycroscope.value.ParamSpecParam) | [TypeVarTupleParam](#pycroscope.value.TypeVarTupleParam)] ``` -------------------------------- ### Lint and Sort Imports with Ruff Source: https://github.com/jellezijlstra/pycroscope/blob/main/CONTRIBUTING.md Execute Ruff for code linting and import sorting to maintain code quality. ```bash $ uv run --with ruff ruff check pycroscope ``` -------------------------------- ### Get Type Evaluation Functions Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/extensions.md Retrieve the type evaluation function for a given fully qualified name, if one exists. ```python get_type_evaluations("some_module.some_function") ``` -------------------------------- ### make Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/signature.md Class method to create a Signature object, abstracting away the underlying inspect.Signature creation. ```APIDOC ## make ### Description Create a [`Signature`](#pycroscope.signature.Signature) object. This is more convenient to use than the constructor because it abstracts away the creation of the underlying `inspect.Signature`. ### Class Method Signature `*classmethod* make(parameters: Iterable[[SigParameter](#pycroscope.signature.SigParameter)], return_annotation: [Value](value.md#pycroscope.value.Value) | None = None, impl: Callable[[[CallContext](#pycroscope.signature.CallContext)], [Value](value.md#pycroscope.value.Value) | [ImplReturn](#pycroscope.signature.ImplReturn)] | None = None, callable: object | None = None, has_return_annotation: bool = True, is_asynq: bool = False, allow_call: bool = False, allow_partial_call: bool = False, evaluator: Evaluator | None = None, deprecated: str | None = None, self_param: [TypeVarParam](value.md#pycroscope.value.TypeVarParam) | None = None, bound_receiver_param_name: str | None = None, bound_receiver_composite: [Composite](stacked_scopes.md#pycroscope.stacked_scopes.Composite) | None = None) → [Signature](#pycroscope.signature.Signature)` ``` -------------------------------- ### Get Generic Bases Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/value.md Retrieves the base classes for a given type, including their generic arguments. Useful for static analysis of generic types. ```default get_generic_bases(typ: type | [ClassOwner](#pycroscope.value.ClassOwner), generic_args: Sequence[[Value](#pycroscope.value.Value)] = ()) → Mapping[type | [ClassOwner](#pycroscope.value.ClassOwner), [TypeVarMap](#pycroscope.value.TypeVarMap)] ``` -------------------------------- ### Concise Output Format with Pycroscope CLI Source: https://context7.com/jellezijlstra/pycroscope/llms.txt Configure pycroscope to output results in a concise format using the --output-format flag. ```bash # Output in concise format python -m pycroscope --output-format concise mymodule.py ``` -------------------------------- ### Get Call Result Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/value.md Returns the result of calling a callee Value with provided arguments and keyword arguments. Supports AST nodes for context. ```default get_call_result(callee: [Value](#pycroscope.value.Value), args: Iterable[[Value](#pycroscope.value.Value)] = (), kwargs: Iterable[tuple[str | None, [Value](#pycroscope.value.Value)]] = (), node: AST | None = None) → [Value](#pycroscope.value.Value) ``` -------------------------------- ### Basic Pycroscope Configuration in pyproject.toml Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/configuration.md Defines default paths, import paths, and enables/disables specific checks. Module-specific overrides can also be set. ```toml [tool.pycroscope] # Paths pycroscope should check by default paths = ["my_module/"] # Paths to import from import_paths = ["."] # Enable or disable some checks possibly_undefined_name = true duplicate_dict_key = false # Output style for reported errors ("detailed" or "concise") output_format = "concise" # But re-enable it for a specific module [[tool.pycroscope.overrides]] module = "my_module.submodule" duplicate_dict_key = true ``` -------------------------------- ### Get MRO Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/value.md Returns the runtime Method Resolution Order (MRO) for a class. During static analysis, it provides a value-level MRO that preserves generic specialization. ```default get_mro(typ: object, , include_virtual: bool = False) → tuple[type, ...] ``` -------------------------------- ### Check Full Coverage Source: https://github.com/jellezijlstra/pycroscope/blob/main/AGENTS.md Run the full coverage check script using the generated coverage.json file and a list of files to check. ```bash python tools/check_full_coverage.py coverage.json tools/full_coverage_files.txt ``` -------------------------------- ### Extending Another Pycroscope Configuration File Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/configuration.md Include settings from another configuration file using the `extend_config` key. Options from the extended file have lower priority. ```toml [tool.pycroscope] extend_config = "../path/to/other/pyproject.toml" ``` -------------------------------- ### get(varname, node, state, fallback_value, can_assign_ctx) Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/stacked_scopes.md Retrieves a variable by its name from the current scope stack. Returns UNINITIALIZED_VALUE if the name is not found in any known scope. ```APIDOC ## get(varname, node, state, fallback_value, can_assign_ctx) ### Description Gets a variable of the given name from the current scope stack. ### Parameters #### Path Parameters - **varname** (str | CompositeVariable) - Required - [varname](../glossary.md#term-varname) of the variable to retrieve - **node** (object) - Required - AST node corresponding to the place where the variable lookup is happening. - **state** (VisitorState) - Required - The current [`VisitorState`](#pycroscope.stacked_scopes.VisitorState). - **fallback_value** (Value | None) - Optional - Default value to return if the variable is not found. - **can_assign_ctx** (CanAssignContext) - Optional - Context for checking assignability. ### Returns - **Value** - The value of the variable, or UNINITIALIZED_VALUE if not found. ``` -------------------------------- ### SysVersionInfoExtension Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/value.md Extension used for sys.version_info. ```APIDOC ## pycroscope.value.SysVersionInfoExtension ### Description Used for sys.version_info. ``` -------------------------------- ### Get Assignability Error with pycroscope.runtime.get_assignability_error Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/runtime.md Use `get_assignability_error` to obtain a detailed error message explaining why a value is not assignable to a type. Returns None if the value is assignable. ```python >>> print(get_assignability_error(42, list[int])) Cannot assign Literal[42] to list >>> print(get_assignability_error([], list[int])) None >>> print(get_assignability_error(["x"], list[int])) In element 0 Cannot assign Literal['x'] to int ``` -------------------------------- ### Displaying Current Pycroscope Configuration Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/configuration.md Use the `--display-options` flag to view the current configuration values applied by Pycroscope. ```bash $ python -m pycroscope --config-file pyproject.toml --display-options Options: add_import (value: True) ... ``` -------------------------------- ### Implementing amap with AsynqCallable Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/typesystem.md Shows how to use `AsynqCallable` to describe a callable with an `.asynq()` attribute, enabling both synchronous and asynchronous calls. This is used here to implement the `asynq.tools.amap` helper function. ```python from asynq import asynq from pycroscope.extensions import AsynqCallable from typing import TypeVar, List, Iterable T = TypeVar("T") U = TypeVar("U") @asynq() def amap(function: AsynqCallable[[T], U], sequence: Iterable[T]) -> List[U]: return (yield [function.asynq(elt) for elt in sequence]) ``` -------------------------------- ### Display Resolved Options with Pycroscope CLI Source: https://context7.com/jellezijlstra/pycroscope/llms.txt View all resolved configuration options for pycroscope by using the --display-options flag. ```bash # Display all resolved option values python -m pycroscope --config-file pyproject.toml --display-options ``` -------------------------------- ### FunctionScope Definition Node Mapping Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/stacked_scopes.md Demonstrates the basic mapping of a variable usage node to its potential definition nodes and their associated values. ```default x = 3 # (a) print(x) # (b) ``` -------------------------------- ### LiteralOnly Custom Check Usage Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/extensions.md Example of using the LiteralOnly custom check to ensure function arguments are literals. Useful for security-sensitive APIs to prevent user-controlled input. ```python def func(arg: Annotated[str, LiteralOnly()]) -> None: ... func("x") # ok func(str(some_call())) # error ``` -------------------------------- ### Run Unit Tests with Pytest Source: https://github.com/jellezijlstra/pycroscope/blob/main/CONTRIBUTING.md Execute the unit tests using Pytest. Use the -v flag for verbose output. ```bash $ uv run --extra tests pytest -v pycroscope ``` -------------------------------- ### Type Evaluation: Always Returns a Type Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/type_evaluation.md An example of a type-evaluated function that always returns a specific type, regardless of the input. Type checkers will evaluate the return statement symbolically. ```python @evaluated def always_returns(x: int): return str always_returns("x") # error: "x" is not an int always_returns() # error: not enough arguments reveal_type(always_returns(1)) # str ``` -------------------------------- ### preprocess_args Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/signature.md Preprocesses the argument list to produce an ActualArguments object. ```APIDOC ## preprocess_args ### Description Preprocess the argument list. Produces an ActualArguments object. ### Function Signature `preprocess_args(args: Iterable[tuple[Composite, None | str | PossibleArg | | | | ParamSpecParam]], ctx: CheckCallContext) → ActualArguments | None` ``` -------------------------------- ### CanAssignContext.make_type_object() Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/value.md Creates a TypeObject for a given concrete type. ```APIDOC ## CanAssignContext.make_type_object() ### Description Return a `pycroscope.type_object.TypeObject` for this concrete type. ### Method `make_type_object(typ: type | ClassOwner) -> TypeObject` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **TypeObject**: The TypeObject representation of the type. #### Response Example None ``` -------------------------------- ### Use Config File with Pycroscope CLI Source: https://context7.com/jellezijlstra/pycroscope/llms.txt Specify a custom configuration file for pycroscope using the --config-file option. ```bash # Use a specific config file python -m pycroscope --config-file pyproject.toml mymodule.py ``` -------------------------------- ### Extend Pycroscope with Custom Function Specifications Source: https://github.com/jellezijlstra/pycroscope/blob/main/README.md Define custom specifications for functions to enable pycroscope to detect errors in their arguments. This example shows how to validate SQL queries passed to `database.run_query()`. ```python from pycroscope.error_code import ErrorCode from pycroscope.signature import CallContext, Signature, SigParameter from pycroscope.value import KnownValue, TypedValue, AnyValue, AnySource, Value from database import run_query, parse_sql def run_query_impl(ctx: CallContext) -> Value: sql = ctx.vars["sql"] if not isinstance(sql, KnownValue) or not isinstance(sql.val, str): ctx.show_error( "Argument to run_query() must be a string literal", ErrorCode.incompatible_call, ) return AnyValue(AnySource.error) try: parsed = parse_sql(sql) except ValueError as e: ctx.show_error( f"Invalid sql passed to run_query(): {e}", ErrorCode.incompatible_call, ) return AnyValue(AnySource.error) # check that the parsed SQL is valid... # pycroscope will use this as the inferred return type for the function return TypedValue(list) # in pyproject.toml, set: # known_signatures = [".get_known_argspecs"] def get_known_argspecs(arg_spec_cache): return { # This infers the parameter types and names from the function signature run_query: arg_spec_cache.get_argspec( run_query, impl=run_query_impl ), # You can also write the signature manually run_query: Signature.make( [SigParameter("sql", annotation=TypedValue(str))], callable=run_query, impl=run_query_impl, ), } ``` -------------------------------- ### Specifying a Local Typeshed Path Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/configuration.md Configure Pycroscope to use a local typeshed checkout instead of the bundled copy by setting the `typeshed_path` option. ```toml [tool.pycroscope] typeshed_path = "../typeshed" ``` -------------------------------- ### get_with_scope(varname, node, state, fallback_value, can_assign_ctx) Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/stacked_scopes.md Similar to `get()`, but also returns the scope object where the name was found. Returns a tuple containing the Value, the Scope (or None if not found), and the origin. ```APIDOC ## get_with_scope(varname, node, state, fallback_value, can_assign_ctx) ### Description Like [`get()`](#pycroscope.stacked_scopes.StackedScopes.get), but also returns the scope object the name was found in. ### Parameters #### Path Parameters - **varname** (str | CompositeVariable) - Required - [varname](../glossary.md#term-varname) of the variable to retrieve - **node** (object) - Required - AST node corresponding to the place where the variable lookup is happening. - **state** (VisitorState) - Required - The current [`VisitorState`](#pycroscope.stacked_scopes.VisitorState). - **fallback_value** (Value | None) - Optional - Default value to return if the variable is not found. - **can_assign_ctx** (CanAssignContext) - Optional - Context for checking assignability. ### Returns - **tuple[Value, Scope | None, frozenset[object | None]]** - A tuple containing the Value, the Scope (or None if not found), and the origin. ``` -------------------------------- ### get_overloads Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/extensions.md Return all defined runtime overloads for this fully qualified name. ```APIDOC ## pycroscope.extensions.get_overloads(fully_qualified_name: str) → list[Callable[[...], Any]] Return all defined runtime overloads for this fully qualified name. ``` -------------------------------- ### Reproduce CI Coverage Run Source: https://github.com/jellezijlstra/pycroscope/blob/main/AGENTS.md Reproduce the CI coverage run locally using Python 3.14 and pytest-cov. This command generates detailed coverage reports. ```bash UV_CACHE_DIR=/tmp/uv-cache uv run --python 3.14 --extra tests --extra asynq --extra codemod --with pytest-cov pytest --cov=pycroscope --cov-report=term-missing --cov-report=json:coverage.json pycroscope ``` -------------------------------- ### mark_ellipsis_style_any_tail_parameters Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/signature.md Marks the `*args: Any, **kwargs: Any` parameters in a sequence of signature parameters as gradual-call tails, encoding this with `AnySource.ellipsis_callable`. ```APIDOC ### pycroscope.signature.mark_ellipsis_style_any_tail_parameters(params: Sequence[[SigParameter](#pycroscope.signature.SigParameter)]) → list[[SigParameter](#pycroscope.signature.SigParameter)] Mark `*args: Any, **kwargs: Any` tails as gradual-call tails. We encode this with `AnySource.ellipsis_callable` so it remains distinct from tails that become `Any` only after TypeVar substitution. ### Parameters - `params`: A sequence of SigParameter objects. ### Returns A list of SigParameter objects with ellipsis-style any tail parameters marked. ``` -------------------------------- ### Handling Loops in Scope Analysis Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/stacked_scopes.md Demonstrates how pycroscope analyzes loops by visiting the loop body twice to correctly map variable usages to their definitions, even when definitions occur later in the loop. ```default x = None for _ in (1, 2): if x: print(x[1]) # (a) else: x = (1, 2) # (b) ``` -------------------------------- ### Subclass NameCheckVisitor for Custom Behavior Source: https://context7.com/jellezijlstra/pycroscope/llms.txt Subclass NameCheckVisitor to add project-specific behavior. Override get_argspec_providers to add custom signature providers. ```python from pycroscope.name_check_visitor import NameCheckVisitor from pycroscope.options import Options, ConfigOption from pycroscope.value import KnownValue, Value from pycroscope.ast_annotator import annotate_code class MyVisitor(NameCheckVisitor): # Override to add project-specific behavior config = NameCheckVisitor.config @classmethod def get_argspec_providers(cls): providers = super().get_argspec_providers() # Add custom signature providers here return providers # Use the custom visitor with annotate_code tree = annotate_code( "x: int = 1", visitor_cls=MyVisitor, show_errors=True, ) ``` -------------------------------- ### Define Integer Range Constraint with GreaterThan Source: https://context7.com/jellezijlstra/pycroscope/llms.txt Implement a custom check for integer range validation. This example defines a `GreaterThan` check that ensures a value is strictly greater than a specified integer. It handles type variables and provides error messages for invalid assignments. ```python from dataclasses import dataclass from typing import TypeVar, Union from pycroscope.value import AnyValue, TypeVarValue, TypeVarMap @dataclass(frozen=True) class GreaterThan(CustomCheck): value: Union[int, TypeVar] def can_assign(self, value: Value, ctx: CanAssignContext) -> CanAssign: if isinstance(self.value, TypeVar): return {} for subval in flatten_values(value): if isinstance(subval, KnownValue): if not isinstance(subval.val, int) or subval.val <= self.value: return CanAssignError(f"{subval.val!r} is not > {self.value}") elif not isinstance(subval, AnyValue): return CanAssignError(f"Size of {subval} is unknown") return {} def walk_values(self): if isinstance(self.value, TypeVar): yield TypeVarValue(self.value) def substitute_typevars(self, typevars: TypeVarMap) -> "GreaterThan": if isinstance(self.value, TypeVar) and self.value in typevars: v = typevars[self.value] if isinstance(v, KnownValue) and isinstance(v.val, int): return GreaterThan(v.val) return self def takes_positive(n: Annotated[int, GreaterThan(0)]) -> None: ... takes_positive(5) # ok takes_positive(0) # ERROR: 0 is not > 0 takes_positive(-1) # ERROR: -1 is not > 0 ``` -------------------------------- ### TypeGuard for List Type Checking Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/extensions.md Demonstrates using TypeGuard for checking if a list contains elements of a specific type. Note that new code should use typing_extensions.TypeGuard or typing.TypeGuard. ```python def is_int_list(arg: list[Any]) -> TypeGuard[list[int]]: return all(isinstance(elt, int) for elt in arg) ``` -------------------------------- ### Python AST Module: Parsing an Import Statement Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/design.md Demonstrates how the `ast.parse` function represents a simple import statement as an Abstract Syntax Tree (AST). This is a fundamental step in understanding code structure. ```python # ast.parse considers everything to be a module Module(body=[ # the module contains one statement of type Import Import( # names is a list; it would contain multiple elements for "import a, b" names=[ alias( name='a', # if we did "import a as b", this would be "b" instead of None asname=None ) ] ) ]) ``` -------------------------------- ### Pycroscope Configuration in pyproject.toml Source: https://context7.com/jellezijlstra/pycroscope/llms.txt Configure pycroscope settings such as paths, error codes, and behavioral options within the [tool.pycroscope] section of pyproject.toml. ```toml [tool.pycroscope] # Files/packages to check paths = ["mypackage/"] # Import roots (avoids relying on sys.path) import_paths = ["пъл."] # Error format: "detailed" (default) or "concise" output_format = "concise" # Enable opt-in checks possibly_undefined_name = true missing_return_annotation = true missing_parameter_annotation = true unused_variable = true value_always_true = true suggested_parameter_type = true suggested_return_type = true incompatible_override = true missing_generic_parameters = true use_fstrings = true unreachable = true # Disable specific checks globally duplicate_dict_key = false # Fail CI when unused objects or attributes are found enforce_no_unused = true enforce_no_unused_attributes = true # Suppress known unused entries by fully-qualified path ignored_unused_attribute_paths = [ "mypackage.utils.Sentinel.name", ] # Custom function signatures plugin known_signatures = ["mypackage.pycroscope_plugin.get_known_argspecs"] # Use a local typeshed checkout typeshed_path = "../typeshed" # Per-module overrides [[tool.pycroscope.overrides]] module = "mypackage.legacy" implicit_any = true duplicate_dict_key = false # Extend another config (lower priority) # extend_config = "../shared/pyproject.toml" ``` -------------------------------- ### SysPlatformExtension Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/value.md Extension used for sys.platform. ```APIDOC ## pycroscope.value.SysPlatformExtension ### Description Used for sys.platform. ``` -------------------------------- ### Python Type Hinting with Union and None Check Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/design.md Demonstrates how type constraints are applied in function scopes. The `dump_value` calls illustrate how type information is refined based on conditional checks like `x is not None`. ```python def f(x: Union[int, None]) -> None: dump_value(x) # Union[int, None] if x is not None: dump_value(x) # int ``` -------------------------------- ### ANY_SIGNATURE Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/signature.md A Signature object compatible with any other Signature. ```APIDOC ## ANY_SIGNATURE ### Description [`Signature`](#pycroscope.signature.Signature) that should be compatible with any other [`Signature`](#pycroscope.signature.Signature). ### Value `Signature(parameters={'...': SigParameter(name='...', kind=, default=None, annotation=AnyValue(source=))}, return_value=AnyValue(source=), impl=None, callable=None, is_asynq=False, has_return_annotation=True, allow_call=False, allow_partial_call=False, evaluator=None, deprecated=None)* ``` -------------------------------- ### Check Package with Pycroscope CLI Source: https://context7.com/jellezijlstra/pycroscope/llms.txt Analyze an entire Python package by having pycroscope import each module within it. ```bash # Check an entire package (pycroscope will import each module) python -m pycroscope mypackage/ ``` -------------------------------- ### FunctionScope with Conditional Logic Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/stacked_scopes.md Shows how FunctionScope handles conditional assignments, resulting in a MultiValuedValue for a variable used after the condition. ```default if some_condition(): x = 3 # (a) else: x = 4 # (b) print(x) # (c) ``` -------------------------------- ### subscope() Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/stacked_scopes.md Creates and returns a new subscope, managed as an AbstractContextManager. ```APIDOC ## subscope() ### Description Creates a new subscope (see the [`FunctionScope`](#pycroscope.stacked_scopes.FunctionScope) docstring). ### Returns - **AbstractContextManager[dict[str | CompositeVariable, list[object]]])** - An AbstractContextManager for the new subscope. ``` -------------------------------- ### Scope Analysis for Try-Finally Blocks Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/stacked_scopes.md Illustrates the transformation of try-finally blocks into an if-else structure for scope analysis, ensuring variables in the finally block can reflect values from either the try block or preceding code. ```default try: TRY-BODY finally: FINALLY-BODY REST-OF-FUNCTION ``` ```default if : FINALLY-BODY return else: TRY-BODY FINALLY-BODY REST-OF-FUNCTION ``` -------------------------------- ### Conditional sum() implementation using @evaluated Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/type_evaluation.md Illustrates how to use the @evaluated decorator and argument kind functions to implement conditional logic for function signatures based on Python version and argument provision. ```python if sys.version_info >= (3, 8): @overload def sum(__iterable: Iterable[_T]) -> _T | Literal[0]: ... @overload def sum(__iterable: Iterable[_T], start: _S) -> _T | _S: ... else: @overload def sum(__iterable: Iterable[_T]) -> _T | Literal[0]: ... @overload def sum(__iterable: Iterable[_T], __start: _S) -> _T | _S: ... ``` ```python @evaluated def sum(__iterable: Iterable[_T], start: _S = ...): if not is_provided(start): return _T | Literal[0] if sys.version_info < (3, 8) and is_keyword(start): show_error("start is a positional-only argument in Python <3.8", argument=start) return _T | _S ``` -------------------------------- ### ParameterKind Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/signature.md Enumeration for different kinds of parameters. ```APIDOC ## class pycroscope.signature.ParameterKind ### Description Kinds of parameters. ### Parameters - **values** (*values) - The values defining the parameter kind. ``` -------------------------------- ### Scope Management Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/stacked_scopes.md Classes for managing scope levels and their associated variables and constraints. ```APIDOC ## Scope Represents a single level in the scope stack. May be a builtin, module, class, or function scope. ### Parameters - **scope_type** (ScopeType) - Required - The type of the scope. - **variables** (dict[str | CompositeVariable, Value]) - Optional - A dictionary of variables in the scope. - **parent_scope** (Scope | None) - Optional - The parent scope. - **scope_node** (object | None) - Optional - The AST node for the scope. - **scope_object** (object | None) - Optional - The object associated with the scope. - **simplification_limit** (int | None) - Optional - Limit for simplification. - **declared_types** (dict[str, tuple[Value | None, bool, AST]]) - Optional - Declared types for variables. ### Methods #### add_constraint(abstract_constraint: AbstractConstraint, node: object, state: VisitorState) -> None Adds a constraint to the current scope. Constraints are ignored outside of function scopes. #### scope_used_as_parent() -> Scope Returns the parent scope, skipping class scopes. ``` ```APIDOC ## ModuleScope Module scope with per-usage definition tracking across collect/check passes. ### Parameters - **variables** (dict[str | CompositeVariable, Value]) - Required - A dictionary of variables in the scope. - **parent_scope** (Scope) - Required - The parent scope. - **scope_object** (object | None) - Optional - The object associated with the scope. - **simplification_limit** (int | None) - Optional - Limit for simplification. ``` -------------------------------- ### Record Protocol Implementation Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/value.md Records that a specific class implements a given protocol. Used for type checking and analysis. ```default record_protocol_implementation(protocol: type[object], implementing_class: type[object]) → None ``` -------------------------------- ### Record Any Used Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/value.md Records that the 'Any' type was utilized during a match operation. This is typically for internal tracking. ```default record_any_used() → None ``` -------------------------------- ### pycroscope.ast_annotator.dump_annotated_code Source: https://github.com/jellezijlstra/pycroscope/blob/main/docs/reference/ast_annotator.md Prints an annotated AST in a human-readable format. ```APIDOC ## dump_annotated_code(node: AST, depth: int = 0, field_name: str | None = None) -> None ### Description Print an annotated AST in a readable format. ### Parameters #### Parameters - **node** (AST) - The AST node to print. - **depth** (int) - Optional. The current depth for indentation. Defaults to 0. - **field_name** (str | None) - Optional. The name of the field being processed. Defaults to None. ``` -------------------------------- ### Generate HTML Coverage Report Source: https://github.com/jellezijlstra/pycroscope/blob/main/AGENTS.md Add the --cov-report=html flag to the coverage command to generate an HTML line-by-line coverage report. ```bash UV_CACHE_DIR=/tmp/uv-cache uv run --python 3.14 --extra tests --extra asynq --extra codemod --with pytest-cov pytest --cov=pycroscope --cov-report=term-missing --cov-report=json:coverage.json --cov-report=html pycroscope ```