예제 #1
0
 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)
예제 #2
0
 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)
예제 #3
0
 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
예제 #4
0
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
예제 #5
0
 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
예제 #6
0
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)
예제 #7
0
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))
예제 #8
0
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))
예제 #9
0
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
예제 #10
0
 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]
예제 #11
0
 def _get_registered_type(self) -> Type[T]:
     cls = typing_inspect.get_generic_type(self)
     tp = typing_inspect.get_args(cls)[0]
     return tp
예제 #12
0
 def get_inner_type(self) -> typing.Type[T]:
     return typing_inspect.get_args(typing_inspect.get_generic_type(self))[0]
예제 #13
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()
예제 #14
0
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]