Exemplo n.º 1
0
 def test_callable(self):
     samples = [Callable, Callable[..., int],
                Callable[[int, int], Iterable[str]]]
     nonsamples = [int, type, 42, [], List[int],
                   Union[callable, Callable[..., int]]]
     self.sample_test(is_callable_type, samples, nonsamples)
     class MyClass(Callable[[int], int]):
         pass
     self.assertTrue(is_callable_type(MyClass))
Exemplo n.º 2
0
 def test_callable(self):
     samples = [Callable, Callable[..., int],
                Callable[[int, int], Iterable[str]]]
     nonsamples = [int, type, 42, [], List[int]]
     if UNION_SUPPORTS_BUILTIN_CALLABLE:
         nonsamples.append(Union[callable, Callable[..., int]])
     self.sample_test(is_callable_type, samples, nonsamples)
     if SUBCLASSABLE_CALLABLES:
         class MyClass(Callable[[int], int]):
             pass
         self.assertTrue(is_callable_type(MyClass))
Exemplo n.º 3
0
 def _get_checker(self, expect_tp):
     if expect_tp is t.Any:
         return lambda v: True
     # about type determination of typing objs
     # see: https://github.com/python/typing/issues/528
     elif ti.is_union_type(expect_tp):
         return lambda v: isinstance(v, expect_tp.__args__)
     elif ti.is_callable_type(expect_tp):
         return lambda v: callable(v)
     elif isinstance(expect_tp, str):
         return self._get_str_checker(expect_tp)
     else:
         return lambda v: isinstance(v, expect_tp)
Exemplo n.º 4
0
def _eval_args(args):
    """Internal helper for get_args."""
    res = []
    for arg in args:
        if not isinstance(arg, tuple):
            res.append(arg)
        elif is_callable_type(arg[0]):
            callable_args = _eval_args(arg[1:])
            if len(arg) == 2:
                res.append(Callable[[], callable_args[0]])
            elif arg[1] is Ellipsis:
                res.append(Callable[..., callable_args[1]])
            else:
                res.append(Callable[[*callable_args[:-1]], callable_args[-1]])
        else:
            res.append(type(arg[0]).__getitem__(arg[0], _eval_args(arg[1:])))
    return tuple(res)
Exemplo n.º 5
0
    def get(cls, type_or_hint, *, is_argument: bool = False) -> "TypeChecker":
        # This ensures the validity of the type passed (see typing documentation for info)
        type_or_hint = is_valid_type(type_or_hint, "Invalid type.",
                                     is_argument)

        if type_or_hint is Any:
            return AnyTypeChecker()

        if is_type(type_or_hint):
            return TypeTypeChecker.make(type_or_hint, is_argument)

        if is_literal_type(type_or_hint):
            return LiteralTypeChecker.make(type_or_hint, is_argument)

        if is_generic_type(type_or_hint):
            origin = get_origin(type_or_hint)
            if issubclass(origin, MappingCol):
                return MappingTypeChecker.make(type_or_hint, is_argument)

            if issubclass(origin, Collection):
                return CollectionTypeChecker.make(type_or_hint, is_argument)

            # CONSIDER: how to cater for exhaustible generators?
            if issubclass(origin, Iterable):
                raise NotImplementedError(
                    "No type-checker is setup for iterables that exhaust.")

            return GenericTypeChecker.make(type_or_hint, is_argument)

        if is_tuple_type(type_or_hint):
            return TupleTypeChecker.make(type_or_hint, is_argument)

        if is_callable_type(type_or_hint):
            return CallableTypeChecker.make(type_or_hint, is_argument)

        if isclass(type_or_hint):
            if is_typed_dict(type_or_hint):
                return TypedDictChecker.make(type_or_hint, is_argument)
            return ConcreteTypeChecker.make(type_or_hint, is_argument)

        if is_union_type(type_or_hint):
            return UnionTypeChecker.make(type_or_hint, is_argument)

        if is_typevar(type_or_hint):
            bound_type = get_bound(type_or_hint)
            if bound_type:
                return cls.get(bound_type)
            constraints = get_constraints(type_or_hint)
            if constraints:
                union_type_checkers = tuple(
                    cls.get(type_) for type_ in constraints)
                return UnionTypeChecker(Union.__getitem__(constraints),
                                        union_type_checkers)
            else:
                return AnyTypeChecker()

        if is_new_type(type_or_hint):
            super_type = getattr(type_or_hint, "__supertype__", None)
            if super_type is None:
                raise TypeError(
                    f"No supertype for NewType: {type_or_hint}. This is not allowed."
                )
            return cls.get(super_type)

        if is_forward_ref(type_or_hint):
            return ForwardTypeChecker.make(type_or_hint,
                                           is_argument=is_argument)

        if is_classvar(type_or_hint):
            var_type = get_args(type_or_hint, evaluate=True)[0]
            return cls.get(var_type)

        raise NotImplementedError(
            f"No {TypeChecker.__qualname__} is available for type or hint: '{type_or_hint}'"
        )
Exemplo n.º 6
0
def is_impractical_type(python_type: PythonType) -> bool:
    # can't write code and pass it around in JSON!
    return (is_callable_type(python_type)
            or type(python_type) == enum.EnumMeta)
Exemplo n.º 7
0
def _type_from_runtime(val, ctx):
    if isinstance(val, str):
        return _eval_forward_ref(val, ctx)
    elif isinstance(val, tuple):
        # This happens under some Python versions for types
        # nested in tuples, e.g. on 3.6:
        # > typing_inspect.get_args(Union[Set[int], List[str]])
        # ((typing.Set, int), (typing.List, str))
        origin = val[0]
        if len(val) == 2:
            args = (val[1], )
        else:
            args = val[1:]
        return _value_of_origin_args(origin, args, val, ctx)
    elif typing_inspect.is_literal_type(val):
        args = typing_inspect.get_args(val)
        if len(args) == 0:
            return KnownValue(args[0])
        else:
            return unite_values(*[KnownValue(arg) for arg in args])
    elif typing_inspect.is_union_type(val):
        args = typing_inspect.get_args(val)
        return unite_values(*[_type_from_runtime(arg, ctx) for arg in args])
    elif typing_inspect.is_tuple_type(val):
        args = typing_inspect.get_args(val)
        if not args:
            return TypedValue(tuple)
        elif len(args) == 2 and args[1] is Ellipsis:
            return GenericValue(tuple, [_type_from_runtime(args[0], ctx)])
        else:
            args_vals = [_type_from_runtime(arg, ctx) for arg in args]
            return SequenceIncompleteValue(tuple, args_vals)
    elif is_instance_of_typing_name(val, "_TypedDictMeta"):
        return TypedDictValue({
            key: _type_from_runtime(value, ctx)
            for key, value in val.__annotations__.items()
        })
    elif typing_inspect.is_callable_type(val):
        return TypedValue(Callable)
    elif typing_inspect.is_generic_type(val):
        origin = typing_inspect.get_origin(val)
        args = typing_inspect.get_args(val)
        return _value_of_origin_args(origin, args, val, ctx)
    elif GenericAlias is not None and isinstance(val, GenericAlias):
        origin = get_origin(val)
        args = get_args(val)
        return GenericValue(origin,
                            [_type_from_runtime(arg, ctx) for arg in args])
    elif isinstance(val, type):
        if val is type(None):
            return KnownValue(None)
        return TypedValue(val)
    elif val is None:
        return KnownValue(None)
    elif is_typing_name(val, "NoReturn"):
        return NO_RETURN_VALUE
    elif val is typing.Any:
        return UNRESOLVED_VALUE
    elif hasattr(val, "__supertype__"):
        if isinstance(val.__supertype__, type):
            # NewType
            return NewTypeValue(val)
        elif typing_inspect.is_tuple_type(val.__supertype__):
            # TODO figure out how to make NewTypes over tuples work
            return UNRESOLVED_VALUE
        else:
            ctx.show_error("Invalid NewType %s" % (val, ))
            return UNRESOLVED_VALUE
    elif typing_inspect.is_typevar(val):
        # TypeVar; not supported yet
        return UNRESOLVED_VALUE
    elif typing_inspect.is_classvar(val):
        return UNRESOLVED_VALUE
    elif is_instance_of_typing_name(
            val, "_ForwardRef") or is_instance_of_typing_name(
                val, "ForwardRef"):
        # This has issues because the forward ref may be defined in a different file, in
        # which case we don't know which names are valid in it.
        with qcore.override(ctx, "suppress_undefined_name", True):
            return UNRESOLVED_VALUE
    elif val is Ellipsis:
        # valid in Callable[..., ]
        return UNRESOLVED_VALUE
    elif is_instance_of_typing_name(val, "_TypeAlias"):
        # typing.Pattern and Match, which are not normal generic types for some reason
        return GenericValue(val.impl_type,
                            [_type_from_runtime(val.type_var, ctx)])
    else:
        origin = get_origin(val)
        if origin is not None:
            return TypedValue(origin)
        ctx.show_error("Invalid type annotation %s" % (val, ))
        return UNRESOLVED_VALUE