i2.itypes¶
Types
Functions
A |
|
|
Yield, for each parametrized Callable, its |
The |
|
|
Whether |
|
|
|
Convert an iterable to a Literal type. |
|
Make a new type with (optional) doc and (optional) aka, set of var names it often appears as |
|
The name of a typing generic (its |
|
Decorator to validate (Literal-annotated) argument values at call time. |
Classes
|
Make a protocol to express the existence of specific attributes. |
|
A general-purpose classifier for objects based on a set of verifying functions. |
- class i2.itypes.HasAttrs[source]¶
Bases:
objectMake a protocol to express the existence of specific attributes.
>>> SizedAndAppendable = HasAttrs["__len__", "append"] >>> assert isinstance([1, 2, 3], SizedAndAppendable) # lists have both a length and an append >>> assert not isinstance((1, 2, 3), SizedAndAppendable) # tuples don't have an appendPython Protocols are a way to be able to do “behavior typing” (my bad terminology). Basically, if you want your static analyzer (the swingles in your IDE, or linter validation process…) to check if you’re manipulating the expected types, except the types (classes, subclasses, ABCs, abstract classes…) are too restrictive (they are!), you can use Protocols to fill the gap.
Except writing them can sometimes be verbose.
With HasAttrs you can have the basic “does it have these attributes” cases covered.
>>> assert isinstance(dict(), HasAttrs["items"]) >>> assert not isinstance(list(), HasAttrs["items"]) >>> assert not isinstance(dict(), HasAttrs["append"]) >>> >>> class A: ... prop = 2 ... ... def method(self): ... pass >>> >>> a = A() >>> assert isinstance(a, HasAttrs["method"]) >>> assert isinstance(a, HasAttrs["method", "prop"]) >>> assert not isinstance(a, HasAttrs["method", "prop", "this_attr_does_not_exist"])
- class i2.itypes.ObjectClassifier(verifiers)[source]¶
Bases:
objectA general-purpose classifier for objects based on a set of verifying functions.
Each “verifier” checks whether an object belongs to a certain kind (category).
Example usage:
>>> from typing import Mapping, Iterable >>> >>> obj = "test" >>> isa = lambda typ: lambda obj: isinstance(obj, typ) >>> verifiers = { ... 'str': isa(str), ... 'mapping': isa(Mapping), ... 'iterable': isa(Iterable) ... } >>> classifier = ObjectClassifier(verifiers)Check if the object matches any kind
>>> classifier.matches(obj) TrueCheck if the object matches a specific kind
>>> classifier.matches(obj, 'str') True >>> classifier.matches(obj, 'mapping') FalseGet all matches
>>> classifier.all_matches(obj) {'str': True, 'mapping': False, 'iterable': True}Find all matching kinds
>>> list(classifier.matching_kinds(obj)) ['str', 'iterable']Find the first matching kind (default is to ensure uniqueness, which will fail here)
>>> classifier.matching_kind(obj) Traceback (most recent call last): ... ValueError: Multiple matches found: ['str', 'iterable']Find the first matching kind without uniqueness check
>>> classifier.matching_kind(obj, assert_unique=False) 'str'- matches(obj, kind=None)[source]¶
Returns True if the object matches the given kind, or matches any kind if kind is None.
- i2.itypes.dot_string_of_callable_typ(typ)[source]¶
A
inputs -> Callable -> outputstring, with typing-generic names, for a parametrized Callable.>>> from typing import Callable, List, Dict >>> dot_string_of_callable_typ(Callable[[List, Dict], List]) 'List,Dict -> Callable -> List'
- i2.itypes.dot_strings_of_callable_types(*typs, func_shape='box')[source]¶
Yield, for each parametrized Callable, its
dot_string_of_callable_typline and a node-shape line.
- i2.itypes.input_and_output_types(typ)[source]¶
The
(input_types, output_type)pair of a parametrizedtyping.Callable.>>> from typing import Callable, Tuple >>> input_types, output_type = input_and_output_types(Callable[[float, int], str]) >>> assert input_types == [float, int] and output_type == str >>> input_types, output_type = input_and_output_types(Callable[[], str]) >>> assert input_types == [] and output_type == strBut will fail if
typisn’t aCallable:>>> input_and_output_types(Tuple[float, int, str]) Traceback (most recent call last): ... AssertionError: Is not a typing.Callable kind: typing.Tuple[float, int, str]Will also fail if
typis a Callable but not “parametrized”.>>> input_and_output_types(Callable) Traceback (most recent call last): ... AssertionError: Can only be used on a Callable[[...],...] kind: typing.Callable
- i2.itypes.is_a_new_type(typ)[source]¶
Whether
typis atyping.NewType(checked through its__qualname__and__supertype__).
- i2.itypes.is_callable_kind(typ)[source]¶
>>> from typing import Callable, Tuple >>> is_callable_kind(Callable) True >>> is_callable_kind(Callable[[int, float], str]) True >>> is_callable_kind(Tuple[int, float, str]) False
- i2.itypes.iterable_to_literal(iterable)[source]¶
Convert an iterable to a Literal type.
>>> iterable_to_literal([1, 2, 3]) typing.Literal[1, 2, 3]
- i2.itypes.new_type(name, tp, doc=None, aka=None, assign_to_globals=False)[source]¶
Make a new type with (optional) doc and (optional) aka, set of var names it often appears as
- Parameters:
name – Name to give the variable
tp – type (see typing module)
doc (
str|None) – Optional string to put in __doc__ attributeaka (
Iterable|None) – Optional set (or any iterable) to put in _aka attribute, meant to list names the variables of this type often appear as.assign_to_globals – If True, also bind the new type to
namein the globals of thei2.itypesmodule (not the caller’s).
- Returns:
The new type.
>>> from typing import Any, Union, List >>> MyType = new_type('MyType', int) >>> # TODO: Skipping the next part because outputs <class 'typing.NewType'> in 3.10 >>> type(MyType) <class 'function'> >>> Key = new_type('Key', Any, aka=['key', 'k']) >>> sorted(Key._aka) ['k', 'key'] >>> Val = new_type( ... 'Val', Union[int, float, List[Union[int, float]]], ... doc="A number or list of numbers.") >>> Val.__doc__ 'A number or list of numbers.'
- i2.itypes.typ_name(typ)[source]¶
The name of a typing generic (its
_name) or of a NewType (its__name__).
- i2.itypes.validate_literal(func)[source]¶
Decorator to validate (Literal-annotated) argument values at call time.
Wraps a function to add validation of the input arguments annotated with Literal against the values listed by the literal. If the input argument is not one of the literal values, a ValueError is raised.
>>> @validate_literal ... def f(x: Literal[1, 2, 3]): ... return x >>> f(1) 1 >>> f(4) Traceback (most recent call last): ... ValueError: 4 is an invalid value for x. Values should be one of the following: (1, 2, 3)