def test_generic_type(self): T = TypeVar('T') class Node(Generic[T]): pass self.assertIs(get_generic_type(Node()), Node) self.assertIs(get_generic_type(Node[int]()), Node[int]) self.assertIs(get_generic_type(Node[T]()), Node[T],) self.assertIs(get_generic_type(1), int)
def test_generic_type(self): T = TypeVar('T') class Node(Generic[T]): pass self.assertIs(get_generic_type(Node()), Node) if not LEGACY_TYPING: self.assertIs(get_generic_type(Node[int]()), Node[int]) self.assertIs(get_generic_type(Node[T]()), Node[T],) else: # Node[int]() was creating an object of NEW type Node[~T] # and Node[T]() was creating an object of NEW type Node[~T] pass self.assertIs(get_generic_type(1), int)
def __eq__(self, grid: Any) -> bool: if type(grid) is not Grid: return False self_type = get_generic_type(self) grid_type = get_generic_type(grid) if self_type != grid_type: return False if self.dimension != grid.dimension: return False for self_item, grid_item in zip(self, grid): if self_item != grid_item: return False return True
def get_type(v: T) -> typing.Type[T]: """ Returns the type of the value with generic arguments preserved. """ if isinstance(v, functools.partial): # type: ignore inner_type = get_type(v.func) # type: ignore if v.keywords: # type: ignore raise TypeError inner_args, inner_return = typing_inspect.get_args(inner_type) mapping: TypeVarMapping = merge_typevars(*( match_type(arg_type, arg) for (arg_type, arg) in zip(inner_args, v.args) # type: ignore )) rest_arg_types = inner_args[len(v.args):] # type: ignore return typing.Callable[ [replace_typevars(mapping, arg) for arg in rest_arg_types], replace_typevars(mapping, inner_return), ] if isinstance(v, Infer): return get_function_type(v.fn) # type: ignore if isinstance(v, BoundInfer): return get_bound_infer_type(v) # type: ignore tp = typing_inspect.get_generic_type(v) # Special case, only support homogoneous tuple that are inferred to iterables if tp == tuple: return typing.Iterable[get_type(v[0]) if v else typing.Any] # type: ignore # Special case, also support function types. if tp == types.FunctionType: return get_function_type(v) # type: ignore return tp
def __setitem__(self, index: Tuple[int, int], value: _Type) -> None: row, col = index if row not in range(self.__rows) or col not in range(self.__cols): raise IndexError(f"[row, col]= [{row}, {col}] is not a valid index on Grid") grid_type = get_args(get_generic_type(self)) value_type = (type(value), ) if grid_type != value_type: raise TypeError(f"value type is not valid , expected {grid_type} but got {value_type}") self.__grid[row][col] = value
def _check_types(func_arguments: BoundArguments) -> _RuntimeCheckResult: error_details: Set[str] = set() checks_passed: bool = True func_sig: Signature = func_arguments.signature func_params = func_sig.parameters for func_param_key in func_params: func_param: Parameter = func_params[func_param_key] param_type: Type[_A] = func_param.annotation param_actual_value = func_arguments.arguments[func_param_key] value_type: Type[_A] = get_generic_type(param_actual_value) if value_type != param_type: checks_passed = False error = f" ERROR: param {func_param_key} expected {param_type} got {value_type} instead!" error_details.add(error) return _RuntimeCheckResult(details=error_details, passed=checks_passed)
def replace_typevars_expression(expression: object, typevars: TypeVarMapping) -> object: """ Replaces all typevars found in the classmethods of an expression. """ if isinstance(expression, Expression): new_args = [ replace_typevars_expression(a, typevars) for a in expression.args ] new_kwargs = { k: replace_typevars_expression(v, typevars) for k, v in expression.kwargs.items() } new_fn = replace_fn_typevars(expression.function, typevars) return replace_typevars(typevars, typing_inspect.get_generic_type(expression))( new_fn, new_args, new_kwargs) return replace_fn_typevars( expression, typevars, lambda e: replace_typevars_expression(e, typevars))
def test_type_inspect(): ty = typing basic_type = int list_type = ty.List[int] dict_type = ty.Dict[int, str] tuple_type = ty.Tuple[ty.Dict[int, str], str, ty.List[str]] union_type = ty.Union[list_type, dict_type, None] type_a = ty.TypeVar('TA') type_b = ty.TypeVar('TB') gen_list_type = ty.List[type_a] gen_dict_type = ty.Dict[type_a, type_b] gen_tuple_type = ty.Tuple[type_a, type_b] test_types = [ basic_type, list_type, dict_type, tuple_type, union_type, gen_list_type, gen_dict_type, gen_tuple_type ] print("ti.get_origin:\n") for t in test_types: print(" ", ti.get_origin(t)) print("ti.get_parameters:\n") for t in test_types: print(" ", ti.get_parameters(t)) print("ti.get_args:\n") for t in test_types: print(" ", ti.get_args(t)) print("ti.get_generic_type:\n") for t in test_types: print(" ", ti.get_generic_type(t)) print("ti.get_generic_bases:\n") for t in test_types: print(" ", ti.get_generic_bases(t)) print("ti.typed_dict_keys:\n") for t in test_types: print(" ", ti.get_generic_bases(t))
def _get_generic_types( instance: _tp.Any, count: _tp.Union[int, _tp.Set[int]], *, module_from: _tp.Any, hint: str = "" ) -> _tp.Tuple[_tp.Type[_tp.Any], ...]: types = _typing_inspect.get_args(_typing_inspect.get_generic_type(instance)) if not types: types = _typing_inspect.get_args(_typing_inspect.get_generic_bases(instance)[0]) globalns = _sys.modules[module_from.__module__].__dict__ _eval_type = _tp._eval_type # type: ignore types = tuple(_eval_type(i, globalns, None) for i in types) if isinstance(count, int): count = {count} if count != {-1} and len(types) not in count or any(_typing_inspect.is_typevar(i) for i in types): raise TypeError(f"{instance.__class__.__name__} generic was not properly parameterized{hint}: {types}") return types
def _get_storage_class(self) -> Type[TStorage]: generic_type = typing_inspect.get_generic_type(self) type_parameters = typing_inspect.get_args(generic_type) return type_parameters[0]
def _get_registered_type(self) -> Type[T]: cls = typing_inspect.get_generic_type(self) tp = typing_inspect.get_args(cls)[0] return tp
def get_inner_type(self) -> typing.Type[T]: return typing_inspect.get_args(typing_inspect.get_generic_type(self))[0]
def match_expression( wildcards: typing.List[Expression], template: object, expr: object) -> typing.Tuple[TypeVarMapping, WildcardMapping]: """ Returns a mapping of wildcards to the objects at that level, or None if it does not match. A wildcard can match either an expression or a value. If it matches two nodes, they must be equal. """ if template in wildcards: # If we are matching against a placeholder and the expression is not resolved to that placeholder, don't match. if (isinstance(template, PlaceholderExpression) and isinstance(expr, Expression) and not typing_inspect.is_typevar( typing_inspect.get_args( typing_inspect.get_generic_type(template))[0])): raise NoMatch # Match type of wildcard with type of expression try: return ( match_values(template, expr), UnhashableMapping(Item(typing.cast(Expression, template), expr)), ) except TypeError: raise NoMatch if isinstance(expr, Expression): if not isinstance(template, Expression): raise NoMatch # Any typevars in the template that are unbound should be matched with their # versions in the expr try: fn_type_mapping: TypeVarMapping = match_functions( template.function, expr.function) except TypeError: raise NoMatch if set(expr.kwargs.keys()) != set(template.kwargs.keys()): raise TypeError("Wrong kwargs in match") template_args: typing.Iterable[object] expr_args: typing.Iterable[object] # Process args in the template that can represent any number of args. # These are the "IteratedPlaceholder"s # Allow one iterated placeholder in the template args # For example fn(a, b, [...], *c, d, e, [...]) # Here `c` should take as many args as it can between the ends, # Each of those should be matched against the inner iterated_args = [ arg for arg in template.args if isinstance(arg, IteratedPlaceholder) ] if iterated_args: # template args, minus the iterator, is the minimum length of the values # If they have less values than this, raise an error if len(expr.args) < len(template.args) - 1: raise TypeError("Wrong number of args in match") template_args_ = list(template.args) # Only support one iterated arg for now # TODO: Support more than one, would require branching template_iterated, = iterated_args template_index_iterated = list( template.args).index(template_iterated) # Swap template iterated with inner wildcard template_args_[template_index_iterated], = template_iterated.args template_args = template_args_ expr_args = collapse_tuple( expr.args, template_index_iterated, # The number we should preserve on the right, is the number of template # args after index len(template.args) - template_index_iterated - 1, ) else: if len(template.args) != len(expr.args): raise TypeError("Wrong number of args in match") template_args = template.args expr_args = expr.args type_mappings, expr_mappings = list( zip( *(match_expression(wildcards, arg_template, arg_value) for arg_template, arg_value in zip(template_args, expr_args) ), *(match_expression(wildcards, template.kwargs[key], expr.kwargs[key]) for key in template.kwargs.keys()), )) or ((), ()) try: merged_typevars: TypeVarMapping = merge_typevars( fn_type_mapping, *type_mappings) except TypeError: raise NoMatch try: return ( merged_typevars, safe_merge(*expr_mappings, dict_constructor=UnhashableMapping), ) except ValueError: raise NoMatch if template != expr: raise NoMatch return match_values(template, expr), UnhashableMapping()
def wildcard_inner_type(wildcard: object) -> typing.Type: """ Return inner type for a wildcard """ return typing_inspect.get_args( typing_inspect.get_generic_type(wildcard))[0]