pyanalyze.signature¶
The Signature
object and associated functionality. This
provides a way to represent rich callable objects and type check
calls.
- class pyanalyze.signature.MaximumPositionalArgs(value: T, applicable_to: tuple[str, ...] = (), from_command_line: bool = False, priority: int = 0)¶
If calls have more than this many positional arguments, attempt to turn them into keyword arguments.
- exception pyanalyze.signature.InvalidSignature¶
Raised when an invalid signature is encountered.
- class pyanalyze.signature.PossibleArg(name: str | None)¶
- class pyanalyze.signature.PosOrKeyword(name: str, is_required: bool)¶
- class pyanalyze.signature.ActualArguments(positionals: list[tuple[bool, Composite]], star_args: Value | None, keywords: dict[str, tuple[bool, Composite]], star_kwargs: Value | None, kwargs_required: bool, pos_or_keyword_params: Container[int | str], ellipsis: bool = False, param_spec: TypeVarValue | None = None)¶
Represents the actual arguments to a call.
Before creating this class, we decompose
*args
and**kwargs
arguments of known composition into additional positional and keyword arguments, and we merge multiple*args
or**kwargs
.Creating the
ActualArguments
for a call is independent of the signature of the callee.
- class pyanalyze.signature.CallReturn(return_value: Value, sig: Signature, is_error: bool = False, used_any_for_match: bool = False, remaining_arguments: ActualArguments | None = None)¶
Return value of a preprocessed call.
This returns data that is useful for overload resolution.
- is_error: bool¶
Whether there was an error in this call. Used only for overload resolutioon.
- used_any_for_match: bool¶
Whether Any was used for this match. Used only for overload resolution.
- remaining_arguments: ActualArguments | None¶
Arguments that still need to be processed. Used only for overload resolution.
- class pyanalyze.signature.ImplReturn(return_value: Value, constraint: AbstractConstraint = NullConstraint(), no_return_unless: AbstractConstraint = NullConstraint())¶
Return value of impl functions.
These functions return either a single
pyanalyze.value.Value
object, indicating what the function returns, or an instance of this class.- constraint: AbstractConstraint¶
A
pyanalyze.stacked_scopes.Constraint
indicating things that are true if the function returns a truthy value.
- no_return_unless: AbstractConstraint¶
A
pyanalyze.stacked_scopes.Constraint
indicating things that are true unless the function does not return.
- class pyanalyze.signature.CallContext(vars: dict[str, Value], visitor: NameCheckVisitor, composites: dict[str, Composite], node: AST | None, sig: Signature, inferred_return_value: Value)¶
The context passed to an impl function.
- visitor: NameCheckVisitor¶
Using the visitor can allow various kinds of advanced logic in impl functions.
- node: AST | None¶
AST node corresponding to the function call. Useful for showing errors.
- varname_for_arg(arg: str) VarnameWithOrigin | None ¶
Return a varname corresponding to the given function argument.
This is useful for creating a
pyanalyze.stacked_scopes.Constraint
referencing the argument.
- show_error(message: str, error_code: Error = Error(name='incompatible_call', description='Incompatible arguments to a function call.'), *, arg: str | None = None, node: AST | None = None, detail: str | None = None) None ¶
Show an error.
If the arg parameter is given, we attempt to find the AST for that argument to the function and point the error to it.
- class pyanalyze.signature.ParameterKind(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)¶
Kinds of parameters.
- ELLIPSIS = 6¶
Special kind for Callable[…, T]. Such callables are compatible with any other callable. There can only be one ELLIPSIS parameter and it must be the last one.
- class pyanalyze.signature.SigParameter(name: str, kind: ~pyanalyze.signature.ParameterKind = ParameterKind.POSITIONAL_OR_KEYWORD, default: ~pyanalyze.value.Value | None = None, annotation: ~pyanalyze.value.Value = AnyValue(source=<AnySource.unannotated: 6>))¶
Represents a single parameter to a callable.
- name: str¶
Name of the parameter.
- kind: ParameterKind = 1¶
How the parameter can be passed.
- empty¶
alias of
_empty
- class pyanalyze.signature.Signature(parameters: dict[str, SigParameter], return_value: Value, impl: Callable[[CallContext], Value | ImplReturn] | None = None, callable: object | None = None, is_asynq: bool = False, has_return_annotation: bool = True, allow_call: bool = False, evaluator: Evaluator | None = None, deprecated: str | None = None)¶
Represents the signature of a Python callable.
This is used to type check function calls and it powers the
pyanalyze.value.CallableValue
class.- parameters: dict[str, SigParameter]¶
An ordered mapping of the signature’s parameters.
- impl: Callable[[CallContext], Value | ImplReturn] | None = None¶
impl function for this signature.
- callable: object | None = None¶
The callable that this signature represents.
- is_asynq: bool = False¶
Whether this signature represents an asynq function.
- allow_call: bool = False¶
Whether type checking can call the actual function to retrieve a precise return value.
- evaluator: Evaluator | None = None¶
Type evaluator for this function.
- deprecated: str | None = None¶
Deprecation message for this callable.
- bind_arguments(actual_args: ActualArguments, ctx: CheckCallContext) dict[str, tuple[int | str | ~typing.Literal[default, *args, **kwargs, unknown], ~pyanalyze.stacked_scopes.Composite]] | None ¶
Attempt to bind the parameters in the signature to the arguments actually passed in.
Nomenclature: - parameters: the formal parameters of the callable - arguments: the arguments passed in in this call - bound arguments: the mapping of parameter names to values produced by this call
- check_call(args: ~collections.abc.Iterable[tuple[~pyanalyze.stacked_scopes.Composite, None | str | ~pyanalyze.signature.PossibleArg | ~typing.Literal[*args, **kwargs, ellipsis] | ~pyanalyze.value.TypeVarValue | ~pyanalyze.signature.PosOrKeyword]], visitor: NameCheckVisitor, node: ~ast.AST | None) Value ¶
Type check a call to this Signature with the given arguments.
This may call the impl function or the underlying callable, but normally just uses
inspect.Signature.bind()
.
- maybe_show_too_many_pos_args_error(*, args: ~collections.abc.Sequence[tuple[~pyanalyze.stacked_scopes.Composite, None | str | ~pyanalyze.signature.PossibleArg | ~typing.Literal[*args, **kwargs, ellipsis] | ~pyanalyze.value.TypeVarValue | ~pyanalyze.signature.PosOrKeyword]], bound_args: dict[str, tuple[int | str | ~typing.Literal[default, *args, **kwargs, unknown], ~pyanalyze.stacked_scopes.Composite]], ctx: ~pyanalyze.signature.CheckCallContext, node: ~ast.Call) None ¶
Show an error if the call to this Signature has too many positional arguments.
- can_assign(other: Signature | OverloadedSignature, ctx: CanAssignContext) CanAssignError ¶
Equivalent of
pyanalyze.value.Value.can_assign()
. Checks whether anotherSignature
is compatible with thisSignature
.
- get_asynq_value() Signature ¶
Return the
Signature
for the .asynq attribute of anpyanalyze.extensions.AsynqCallable
.
- classmethod make(parameters: Iterable[SigParameter], return_annotation: Value | None = None, *, impl: Callable[[CallContext], Value | ImplReturn] | None = None, callable: object | None = None, has_return_annotation: bool = True, is_asynq: bool = False, allow_call: bool = False, evaluator: Evaluator | None = None, deprecated: str | None = None) Signature ¶
Create a
Signature
object.This is more convenient to use than the constructor because it abstracts away the creation of the underlying
inspect.Signature
.
- pyanalyze.signature.ANY_SIGNATURE = Signature(parameters={'...': SigParameter(name='...', kind=<ParameterKind.ELLIPSIS: 6>, default=None, annotation=AnyValue(source=<AnySource.unannotated: 6>))}, return_value=AnyValue(source=<AnySource.explicit: 2>), impl=None, callable=None, is_asynq=False, has_return_annotation=True, allow_call=False, evaluator=None, deprecated=None)¶
Signature
that should be compatible with any otherSignature
.
- pyanalyze.signature.preprocess_args(args: ~collections.abc.Iterable[tuple[~pyanalyze.stacked_scopes.Composite, None | str | ~pyanalyze.signature.PossibleArg | ~typing.Literal[*args, **kwargs, ellipsis] | ~pyanalyze.value.TypeVarValue | ~pyanalyze.signature.PosOrKeyword]], ctx: ~pyanalyze.signature.CheckCallContext) ActualArguments | None ¶
Preprocess the argument list. Produces an ActualArguments object.
- class pyanalyze.signature.OverloadedSignature(sigs: Sequence[Signature])¶
Represent an overloaded function.
- check_call(args: ~collections.abc.Iterable[tuple[~pyanalyze.stacked_scopes.Composite, None | str | ~pyanalyze.signature.PossibleArg | ~typing.Literal[*args, **kwargs, ellipsis] | ~pyanalyze.value.TypeVarValue | ~pyanalyze.signature.PosOrKeyword]], visitor: NameCheckVisitor, node: ~ast.AST | None) Value ¶
Check a call to an overloaded function.
The way overloads are handled is not well specified in any PEPs. Useful resources include:
Michael Lee’s specification of mypy’s behavior.
Eric Traut’s discussion of pyright’s behavior.
The documentation for pyright’s behavior.
Our behavior is closer to mypy. The general rule is to pick the first overload that matches and return an error otherwise, but there are two twists:
Any
and unions.Before we do a full check, we first check only whether the argument names and numbers match by calling
Signature.bind_arguments()
(a trick we picked up from pyright). This makes for better error messages.If an overload matched only due to
Any
, we continue looking for more overloads. If there are other matching overloads, we returnAny
(withAnySource.multiple_overload_matches
). This is different from pyright’s behavior: pyright picks the first overload regardless ofAny
, which is unsafe in general. Returning aUnion
would be more precise, but may lead to false positives according to experience from other type checkers. A match “due toAny
” is defined as a check that succeeded becauseAny
was on the right-hand side but not the left-hand side of a typecheck.This is implemented by setting a flag on the
pyanalyze.value.CanAssignContext
when a type check succeeds due toAny
. This flag gets propagated toImplReturn.used_any_for_match
.If an overload does not match, but one of the arguments passed was a
Union
, we try all the components of theUnion
separately. If some of them match, we subtract them from theUnion
and try the remaining overloads with a narrowerUnion
. In this case, we return aUnion
of the return values of all the matching overloads on success.The decomposition happens in the private
_check_param_type_compatibility
method ofSignature
. When we perform decomposition, this method returns apyanalyze.value.Value
representing the remaining union members. This value is then used to construct a newActualArguments
object, which ends up inImplReturn.remaining_arguments
.An overload that matches without requiring use of
Any
or union decomposition is called a “clean match”.
- class pyanalyze.signature.BoundMethodSignature(signature: Signature | OverloadedSignature, self_composite: Composite, return_override: Value | None = None)¶
Signature for a method bound to a particular value.