Beispiel #1
0
    def create_from(self, annotation: Any, ctx: CreationContext) -> Optional[TypeChecker]:
        if hasattr(annotation, '__origin__') and hasattr(annotation,
                                                         '__args__') and annotation.__origin__ in InterfaceMapping:
            (protocol,) = InterfaceMapping[annotation.__origin__]
            bindings = protocol.__parameters__  # args of Generic super class
            origin = annotation.__origin__

            inner_checkers = []
            for param in annotation.__args__:
                ch = ctx.find_checker(param)
                if ch is None:
                    raise UntypyAttributeError(f"Could not resolve annotation {param} inside of {annotation}")
                inner_checkers.append(ch)
            if len(inner_checkers) != len(bindings):
                raise UntypyAttributeError(f"Expected {len(bindings)} type arguments inside of {annotation}")

            name = f"{origin.__name__}[" + (', '.join(map(lambda t: t.describe(), inner_checkers))) + "]"

            bindings = dict(zip(bindings, annotation.__args__))
            ctx.with_typevars(bindings)
            template = WrappedType(protocol, ctx.with_typevars(bindings), name=name, implementation_template=origin,
                                   declared=ctx.declared_location())
            return InterfaceChecker(origin, template, name)
        else:
            return None
Beispiel #2
0
def find_signature(member, ctx: CreationContext):
    signature = inspect.signature(member)

    checkers = {}
    for key in signature.parameters:
        if key == 'self':
            checkers[key] = SelfChecker()
        else:
            param = signature.parameters[key]
            if param.annotation is inspect.Parameter.empty:
                checkers[key] = AnyChecker()
                continue

            checker = ctx.find_checker(param.annotation)
            if checker is None:
                checkers[key] = AnyChecker()
                continue
            checkers[key] = checker

    if signature.return_annotation is inspect.Parameter.empty:
        checkers['return'] = AnyChecker()
    else:
        return_checker = ctx.find_checker(signature.return_annotation)
        if return_checker is None:
            raise ctx.wrap(
                UntypyAttributeError(
                    f"\n\tUnsupported Type Annotation: {signature.return_annotation}\n"
                    f"for Return Value of function {member.__name__}\n"))
        checkers['return'] = return_checker
    return signature, checkers
Beispiel #3
0
    def create_from(self, annotation: Any,
                    ctx: CreationContext) -> Optional[TypeChecker]:
        if type(annotation) in [
                GeneratorTypeA, GeneratorTypeB
        ] and annotation.__origin__ == collections.abc.Generator:
            if len(annotation.__args__) != 3:
                raise ctx.wrap(
                    UntypyAttributeError(
                        f"Expected 3 type arguments for Generator."))

            (yield_checker, send_checker, return_checker) = list(
                map(lambda a: ctx.find_checker(a), annotation.__args__))

            if yield_checker is None:
                raise ctx.wrap(
                    UntypyAttributeError(
                        f"The Yield Annotation of the Generator could not be resolved."
                    ))
            if send_checker is None:
                raise ctx.wrap(
                    UntypyAttributeError(
                        f"The Send Annotation of the Generator could not be resolved."
                    ))
            if return_checker is None:
                raise ctx.wrap(
                    UntypyAttributeError(
                        f"The Return Annotation of the Generator could not be resolved."
                    ))

            return GeneratorChecker(yield_checker, send_checker,
                                    return_checker)
        else:
            return None
def analyse(item, ctx: CreationContext, e) -> UntypyAttributeError:
    org = WrappedFunction.find_original(item)
    source = inspect.getsource(item)
    fn_ast = ast.parse(source)

    for node in map_str_to_ast(fn_ast.body[0].args, fn_ast.body[0].returns):
        for rule in RULES:
            rule_result = rule(node)
            if rule_result:
                # Got a Match
                (n, message) = rule_result
                display = DisplayMatrix(source)
                display.write((n.col_offset - 1, n.lineno),
                              " " + "^" * (n.end_col_offset - n.col_offset) +
                              " - " + message)
                return ctx.wrap(
                    UntypyAttributeError(
                        f"Type annotation of function '{qualname(org)}' could not be resolved:\n"
                        f"{e}\n"
                        f"\n{display}"))

    return ctx.wrap(
        UntypyAttributeError(
            f"Type annotation of function '{qualname(org)}' could not be resolved:\n"
            f"{e}\n"))
    def create_from(self, annotation: Any,
                    ctx: CreationContext) -> Optional[TypeChecker]:
        if annotation in InterfaceMapping:
            # Assume Any if no parameters are given
            (protocol, ) = InterfaceMapping[annotation]
            bindings = protocol.__parameters__

            if len(bindings) == 0:
                raise AssertionError(
                    f"This is a BUG. {annotation} has no generic params.")

            # handle Python inconsistency
            if hasattr(annotation, '__class_getitem__'):
                return self.create_from(
                    annotation.__class_getitem__(*([Any] * len(bindings))),
                    ctx)
            elif hasattr(annotation, '__getitem__'):
                return self.create_from(
                    annotation.__getitem__(*([Any] * len(bindings))), ctx)

        elif hasattr(annotation, '__origin__') and hasattr(
                annotation,
                '__args__') and annotation.__origin__ in InterfaceMapping:
            (protocol, ) = InterfaceMapping[annotation.__origin__]
            bindings = protocol.__parameters__  # args of Generic super class
            origin = annotation.__origin__

            inner_checkers = []
            for param in annotation.__args__:
                ch = ctx.find_checker(param)
                if ch is None:
                    raise UntypyAttributeError(
                        f"Could not resolve annotation {param} inside of {annotation}"
                    )
                inner_checkers.append(ch)
            if len(inner_checkers) != len(bindings):
                raise UntypyAttributeError(
                    f"Expected {len(bindings)} type arguments inside of {annotation}"
                )

            name = f"{origin.__name__}[" + (', '.join(
                map(lambda t: t.describe(), inner_checkers))) + "]"

            bindings = dict(zip(bindings, annotation.__args__))
            ctx = ctx.with_typevars(bindings)
            if type(origin) == type:
                template = WrappedType(protocol,
                                       ctx.with_typevars(bindings),
                                       name=name,
                                       implementation_template=origin,
                                       declared=ctx.declared_location())
                return InterfaceChecker(origin, template, name)
            else:
                # type(origin) == collection.abc.ABCMeta
                return ProtocolChecker(protocol, ctx, altname=name)
        else:
            return None
    def create_from(self, annotation: Any, ctx: CreationContext) -> Optional[TypeChecker]:
        if type(annotation) in [IteratorTypeA, IteratorTypeB] and annotation.__origin__ == collections.abc.Iterator:
            if len(annotation.__args__) != 1:
                raise ctx.wrap(UntypyAttributeError(f"Expected 1 type arguments for iterator."))

            inner = ctx.find_checker(annotation.__args__[0])
            if inner is None:
                raise ctx.wrap(UntypyAttributeError(f"The inner type of the iterator could not be resolved."))
            return IteratorChecker(inner)
        else:
            return None
 def create_from(self, annotation: Any,
                 ctx: CreationContext) -> Optional[TypeChecker]:
     if (type(annotation) is GenericAlias and annotation.__origin__
             == list) or (type(annotation) is type(List[int])
                          and annotation.__origin__ == list):
         assert len(annotation.__args__) == 1
         inner = ctx.find_checker(annotation.__args__[0])
         if inner is None:
             return None
         return ListChecker(inner, ctx.declared_location())
     else:
         return None
    def create_from(self, annotation: Any, ctx: CreationContext) -> Optional[TypeChecker]:
        if type(annotation) is str:
            eval_args = [annotation, globals()]
            local = ctx.eval_context()
            if local is not None:
                eval_args.append(local)

            def resolver(eval_args):
                return eval(*eval_args)

            annotation = get_type_hints(eval_args, ctx, resolver=resolver)
            return ctx.find_checker(annotation)
Beispiel #9
0
    def create_from(self, annotation: Any,
                    ctx: CreationContext) -> Optional[TypeChecker]:
        if hasattr(annotation, '__metadata__') and hasattr(
                annotation, '__origin__'):
            inner = ctx.find_checker(annotation.__origin__)
            if inner is None:
                raise ctx.wrap(
                    UntypyAttributeError(f"Could not resolve annotation "
                                         f"'{repr(annotation.__origin__)}' "
                                         f"inside of '{annotation}'."))

            return AnnotatedChecker(annotation, inner, annotation.__metadata__,
                                    ctx)
        else:
            return None
    def __init__(self, annotated, inner: TypeChecker, metadata: Iterator,
                 ctx: CreationContext):
        self.annotated = annotated
        self.inner = inner

        meta = []
        info = []
        for m in metadata:
            if callable(m):
                meta.append(AnnotatedCheckerCallable(self, m))
            elif isinstance(m, str):
                info.append(m)
            elif hasattr(m, '__contains__'):
                meta.append(AnnotatedCheckerContainer(self, m))
            else:
                raise ctx.wrap(
                    UntypyAttributeError(
                        f"Unsupported metadata '{repr(m)}' in '{repr(self.annotated)}'.\n"
                        f"Only callables or objects providing __contains__ are allowed."
                    ))
        self.meta = meta
        self.info = info
        if len(info) == 1:
            self.name = info[0]
            self.info = []
        else:
            self.name = None
Beispiel #11
0
 def __init__(self, annotation: type, ctx: CreationContext):
     (proto, typevars) = _find_bound_typevars(annotation)
     ctx = ctx.with_typevars(typevars)
     members = get_proto_members(proto, ctx)
     self.proto = proto
     self.members = members
     self.typevars = typevars
     self.wrapper_types = dict()
Beispiel #12
0
 def create_from(self, annotation: Any, ctx: CreationContext) -> Optional[TypeChecker]:
     # TODO: Support other typevar features
     if type(annotation) is TypeVar:
         (found, replacement_annotation) = ctx.resolve_typevar(annotation)
         if found:
             inner = ctx.find_checker(replacement_annotation)
             if inner is not None:
                 return BoundTypeVar(inner, annotation)
             else:
                 return None
         else:
             return UnboundTypeVar(annotation)
     elif hasattr(annotation, '__args__') and hasattr(annotation.__origin__,
                                                      '__mro__') and typing.Generic in annotation.__origin__.__mro__:
         return GenericProtocolChecker(annotation, ctx)
     else:
         return None
def get_type_hints(item, ctx: CreationContext, resolver=_default_resolver):
    try:
        # SEE: https://www.python.org/dev/peps/pep-0563/#id7
        return resolver(item)
    except NameError as ne:
        org = WrappedFunction.find_original(item)
        if inspect.isclass(org):
            raise ctx.wrap(
                UntypyNameError(
                    f"{ne}.\nType annotation inside of class '{qualname(org)}' could not be resolved."
                ))
        else:
            raise ctx.wrap(
                UntypyNameError(
                    f"{ne}.\nType annotation of function '{qualname(org)}' could not be resolved."
                ))
    except Exception as e:
        # Try to find better cause in analyse
        raise analyse(item, ctx, e)
Beispiel #14
0
    def create_from(self, annotation: Any, ctx: CreationContext) -> Optional[TypeChecker]:
        if (type(annotation) is TupleType or type(annotation) is TupleTypeB) and annotation.__origin__ == tuple:
            args = annotation.__args__
            if len(args) == 2 and args[1] == Ellipsis:
                checker = ctx.find_checker(args[0])
                if checker is None:
                    return None
                else:
                    return VariadicTupleChecker(checker)
            inner = []
            for arg in args:
                checker = ctx.find_checker(arg)
                if checker is None:
                    return None
                else:
                    inner.append(checker)

            return TupleChecker(inner)
        else:
            return None
 def create_from(self, annotation: Any,
                 ctx: CreationContext) -> Optional[TypeChecker]:
     if type(annotation) is UnionType and len(
             annotation.__args__
     ) == 2 and annotation.__args__[1] is type(None):
         checker = ctx.find_checker(annotation.__args__[0])
         if checker is None:
             return None
         else:
             return OptionalChecker(checker)
     else:
         return None
Beispiel #16
0
 def __init__(self,
              annotation: type,
              ctx: CreationContext,
              *,
              altname: Optional[str] = None):
     (proto, typevars) = _find_bound_typevars(annotation)
     self.ctx = ctx.with_typevars(typevars)
     self.proto = proto
     self._members = None
     self.typevars = typevars
     self.wrapper_types = dict()
     self.altname = altname
Beispiel #17
0
def WrappedGenericAlias(alias, ctx: CreationContext):
    typevars = dict(zip(alias.__origin__.__parameters__, alias.__args__))
    for key, value in typevars.items():
        _checktypevar(key, value)
    ctx = ctx.with_typevars(typevars)
    # This WrappedType must also be a generic alias.
    # So it can be as Typennotation
    tname = []
    for t in typevars:
        a = ctx.find_checker(typevars[t])
        if a is None:
            tname.append(str(typevars[t]))
        else:
            tname.append(a.describe())

    wt = WrappedType(alias.__origin__,
                     ctx,
                     name=f"{alias.__origin__.__name__}[" +
                     (', '.join(tname)) + "]")
    wt.__origin__ = alias.__origin__
    wt.__args__ = alias.__args__
    return wt
    def __init__(self, annotation: Union[CallableTypeOne, CallableTypeTwo],
                 ctx: CreationContext):
        arguments_ty = annotation.__args__[:-1]
        return_ty = annotation.__args__[-1]

        return_checker = ctx.find_checker(return_ty)
        if return_checker is None:
            raise ctx.wrap(
                UntypyAttributeError(
                    f"Return Type Annotation not found. {return_ty}"))

        argument_checker = []
        for arg in arguments_ty:
            checker = ctx.find_checker(arg)
            if checker is None:
                raise ctx.wrap(
                    UntypyAttributeError(
                        f"Argument Type Annotation not found. {arg}"))
            argument_checker.append(checker)

        self.return_checker = return_checker
        self.argument_checker = argument_checker
    def create_from(self, annotation: Any,
                    ctx: CreationContext) -> Optional[TypeChecker]:
        if type(annotation) is UnionType:
            inner = []
            for arg in annotation.__args__:
                checker = ctx.find_checker(arg)
                if checker is None:
                    return None
                else:
                    inner.append(checker)

            return UnionChecker(inner, ctx)
        else:
            return None
Beispiel #20
0
    def create_from(self, annotation: Any,
                    ctx: CreationContext) -> Optional[TypeChecker]:
        if (type(annotation) is TupleType or type(annotation) is TupleTypeB
            ) and annotation.__origin__ == tuple:
            inner = []
            for arg in annotation.__args__:
                checker = ctx.find_checker(arg)
                if checker is None:
                    return None
                else:
                    inner.append(checker)

            return TupleChecker(inner)
        else:
            return None
 def create_from(self, annotation: Any, ctx: CreationContext) -> Optional[TypeChecker]:
     t = type(annotation)
     if (t in [SequenceTypeA, SequenceTypeB] and annotation.__origin__ in [Sequence, ABCSequence]) or \
             annotation in [Sequence, ABCSequence]:  # no args version
         try:
             args = annotation.__args__
         except AttributeError:
             args = []
         inner = []
         elemChecker = None
         if len(args) == 0:
             sf = SimpleFactory()
             inner = [sf.create_from(list, ctx),
                      sf.create_from(tuple, ctx),
                      sf.create_from(str, ctx)]
         elif len(args) == 1:
             elemChecker = ctx.find_checker(args[0])
             if elemChecker is None:
                 return None
             inner = [ListChecker(elemChecker, ctx.declared_location()),
                      VariadicTupleChecker(elemChecker)]
         return SequenceChecker(inner, ctx, elemChecker)
     else:
         return None
Beispiel #22
0
    def __init__(self, inner: Callable, ctx: CreationContext):
        self.inner = inner
        self.signature = inspect.signature(inner)

        # SEE: https://www.python.org/dev/peps/pep-0563/#id7
        annotations = typing.get_type_hints(inner, include_extras=True)

        checkers = {}
        checked_keys = list(self.signature.parameters)

        # Remove self and cls from checking
        if len(checked_keys) > 0 and checked_keys[0] in self.special_args:
            checkers[checked_keys[0]] = SelfChecker()
            checked_keys = checked_keys[1:]

        for key in checked_keys:
            if self.signature.parameters[
                    key].annotation is inspect.Parameter.empty:
                raise ctx.wrap(
                    UntypyAttributeError(
                        f"Missing annotation for argument '{key}' of function {inner.__name__}\n"
                        "Partial annotation are not supported."))
            annotation = annotations[key]
            checker = ctx.find_checker(annotation)
            if checker is None:
                raise ctx.wrap(
                    UntypyAttributeError(
                        f"\n\tUnsupported type annotation: {annotation}\n"
                        f"\tin argument '{key}'"))
            else:
                checkers[key] = checker

        if inner.__name__ in self.method_name_ignore_return:
            checkers['return'] = SelfChecker()
        else:
            if not 'return' in annotations:
                raise ctx.wrap(
                    UntypyAttributeError(
                        f"Missing annotation for return value of function {inner.__name__}\n"
                        "Partial annotation are not supported. Use 'None' or 'NoReturn'"
                        "for specifying no return value."))
            annotation = annotations['return']
            return_checker = ctx.find_checker(annotation)
            if return_checker is None:
                raise ctx.wrap(
                    UntypyAttributeError(
                        f"\n\tUnsupported type annotation: {annotation}\n"
                        f"\tin return"))

            checkers['return'] = return_checker

        self.fc = None
        if hasattr(self.inner, "__fc"):
            self.fc = getattr(self.inner, "__fc")
        self.checkers = checkers
 def __init__(self, inner: list[TypeChecker], ctx: CreationContext):
     # especially Protocols must be checked in a specific order.
     self.inner = sorted(inner, key=lambda t: -t.base_type_priority())
     dups = dict()
     for checker in inner:
         for base_type in checker.base_type():
             if base_type in dups:
                 raise ctx.wrap(
                     UntypyAttributeError(
                         f"{checker.describe()} is in conflict with "
                         f"{dups[base_type].describe()} "
                         f"in {self.describe()}. "
                         f"Types must be distinguishable inside one Union."
                         f"\nNote: Only one Protocol is allowed inside one Union. "
                         f"Classes could implement multiple Protocols by accident."
                         f"\nNote: Multiple Callables or Generics inside one Union are also unsupported."
                     ))
             else:
                 dups[base_type] = checker
Beispiel #24
0
    def __init__(self, annotation: type, ctx: CreationContext):
        self.annotation = annotation
        self.always_wrap = False

        # use protocol like wrapping only if there are some signatures
        if ctx.should_be_inheritance_checked(annotation):
            if hasattr(annotation, '__patched'):
                p = ParentProtocolChecker(annotation, ctx)
                self.parent_checker = p.check_and_wrap
            else:
                # annotation is from an wrapped import
                t = WrappedType(annotation, ctx)

                def wrap(i, ctx):
                    instance = t.__new__(t)
                    instance._WrappedClassFunction__inner = i
                    instance._WrappedClassFunction__return_ctx = None
                    return instance

                # TODO: Use only on import_wrapped module
                # self.always_wrap = True
                self.parent_checker = wrap
        else:
            self.parent_checker = None
Beispiel #25
0
def get_proto_members(
    proto: type, ctx: CreationContext
) -> Dict[str, Tuple[inspect.Signature, dict[str, TypeChecker],
                     FunctionCondition]]:
    blacklist = [
        '__init__', '__class__', '__delattr__', '__dict__', '__dir__',
        '__doc__', '__getattribute__', '__getattr__', '__init_subclass__',
        '__new__', '__setattr__', '__subclasshook__', '__weakref__',
        '__abstractmethods__', '__class_getitem__'
    ]

    member_dict = {}
    for [name, member] in inspect.getmembers(proto):
        if name in blacklist:
            continue

        if inspect.isfunction(member):
            member = WrappedFunction.find_original(member)
            signature = inspect.signature(member)
            annotations = typing.get_type_hints(member, include_extras=True)
            checkers = {}
            for key in signature.parameters:
                if key == 'self':
                    checkers[key] = SelfChecker()
                else:
                    param = signature.parameters[key]
                    if param.annotation is inspect.Parameter.empty:
                        raise ctx.wrap(
                            UntypyAttributeError(
                                f"Missing annotation for argument '{key}' of function {member.__name__} "
                                f"in protocol {proto.__name__}\n"))

                    checker = ctx.find_checker(annotations[key])
                    if checker is None:
                        raise ctx.wrap(
                            UntypyAttributeError(
                                f"\n\tUnsupported type annotation: {param.annotation}\n"
                                f"for argument '{key}' of function {member.__name__} "
                                f"in protocol {proto.__name__}.\n"))
                    checkers[key] = checker

            if signature.return_annotation is inspect.Parameter.empty:
                raise ctx.wrap(
                    UntypyAttributeError(
                        f"Missing annotation for return value of function {member.__name__} "
                        f"in protocol {proto.__name__}. Use 'None' if there is no return value.\n"
                    ))
            return_annotation = annotations['return']
            if return_annotation is proto:  # Self as Return Type would led to endless recursion
                return_checker = SimpleInstanceOfChecker(proto, None)
            else:
                return_checker = ctx.find_checker(return_annotation)

            if return_checker is None:
                raise ctx.wrap(
                    UntypyAttributeError(
                        f"\n\tUnsupported type annotation: {signature.return_annotation}\n"
                        f"for return value of function {member.__name__} "
                        f"in protocol-like {proto.__name__}.\n"))
            fc = None
            if hasattr(member, '__fc'):
                fc = getattr(member, '__fc')
            checkers['return'] = return_checker
            member_dict[name] = (signature, checkers, fc)
    return member_dict