Beispiel #1
0
def ProtocolWrapper(protocolchecker: ProtocolChecker, original: type,
                    members: Dict[str, Tuple[inspect.Signature,
                                             dict[str, TypeChecker],
                                             FunctionCondition]],
                    ctx: ExecutionContext):
    list_of_attr = dict()
    for fnname in members:
        if not hasattr(original, fnname):
            raise ctx.wrap(
                UntypyTypeError(expected=protocolchecker.describe(),
                                given=original.__name__)
            ).with_note(
                f"Type {original.__name__} does not meet the requirements of protocol {protocolchecker.proto.__name__}. It is missing the function '{fnname}'"
            )

        original_fn = getattr(original, fnname)
        try:
            # fails on built ins - YEAH
            original_fn_signature = inspect.signature(original_fn)
        except:
            original_fn_signature = None

        if hasattr(original_fn, '__wf'):
            original_fn = getattr(original_fn, '__wf')
        (sig, argdict, fc) = members[fnname]

        for param in sig.parameters:
            if original_fn_signature is not None and param not in original_fn_signature.parameters:
                raise ctx.wrap(
                    UntypyTypeError(expected=protocolchecker.describe(),
                                    given=original.__name__)
                ).with_note(
                    f"Type {original.__name__} does not meet the requirements of protocol {protocolchecker.proto.__name__}. The signature of '{fnname}' does not match. Missing required parameter {param}"
                )

        list_of_attr[fnname] = ProtocolWrappedFunction(original_fn, sig,
                                                       argdict,
                                                       protocolchecker,
                                                       fc).build()

    def constructor(me, inner, ctx):
        me._ProtocolWrappedFunction__inner = inner
        me._ProtocolWrappedFunction__ctx = ctx

    def __getattr__(me, name):
        return getattr(me._ProtocolWrappedFunction__inner, name)

    def __setattr__(me, name, value):
        if name == '_ProtocolWrappedFunction__inner':
            super(type(me), me).__setattr__('_ProtocolWrappedFunction__inner',
                                            value)
        else:
            return setattr(me._ProtocolWrappedFunction__inner, name, value)

    list_of_attr['__init__'] = constructor
    list_of_attr['__getattr__'] = __getattr__  # allow access of attributes
    list_of_attr['__setattr__'] = __setattr__  # allow access of attributes
    name = f"{protocolchecker.proto.__name__}For{original.__name__}"
    return type(name, (), list_of_attr)
Beispiel #2
0
    def check_and_wrap(self, arg: Any, ctx: ExecutionContext) -> Any:
        if not inspect.isgenerator(arg):
            raise ctx.wrap(UntypyTypeError(arg, self.describe()))

        me = self
        yield_ctx = TypedGeneratorYieldReturnContext(arg, self, True, ctx)
        return_ctx = TypedGeneratorYieldReturnContext(arg, self, False, ctx)

        def wrapped():
            try:
                sent = None
                while True:
                    value_yield = arg.send(sent)
                    # check value_yield (arg is responsable)
                    value_yield = me.yield_checker.check_and_wrap(
                        value_yield, yield_ctx)

                    sent = yield value_yield

                    caller = sys._getframe(1)

                    # check sent value (caller is responsable)
                    sent = me.send_checker.check_and_wrap(
                        sent, TypedGeneratorSendContext(caller, me, ctx))

            except StopIteration as e:
                # check value_returned (arg is responsable)
                ret = me.return_checker.check_and_wrap(e.value, return_ctx)
                return ret

        return wrapped()
Beispiel #3
0
 def check_and_wrap(self, arg: Any, ctx: ExecutionContext) -> Any:
     if not type(arg) is tuple:
         raise ctx.wrap(UntypyTypeError(arg, self.describe()))
     out = []
     for elm in arg:
         out.append(self.inner.check_and_wrap(elm, VariadicTupleExecutionContext(ctx)))
     return tuple(out)
    def posthook(self, ret, boundargs, ctx: ExecutionContext):
        for p in self.postcondition:
            bindings = {}
            for name in inspect.signature(p).parameters:
                if name == "ret":
                    bindings["ret"] = ret
                elif name in boundargs.arguments:
                    bindings[name] = boundargs.arguments[name]
                else:
                    raise UntypyAttributeError(
                        f"Did not find argument {name} of postcondition in function.",
                        locations=[
                            WrappedFunction.find_location(p),
                            WrappedFunction.find_location(self.func),
                        ]
                    )
            if not p(**bindings):
                lsource = find_lambdasource(p)
                if lsource is not None:
                    expected = f"passing: {lsource}"
                else:
                    expected = "passing postcondition"

                given = ret.__repr__()
                err = UntypyTypeError(
                    given,
                    expected,
                ).with_note("Failed postcondition").with_frame(Frame(
                    expected,
                    "",
                    declared=WrappedFunction.find_location(p),
                    responsable=None,
                ))
                raise ctx.wrap(err)
Beispiel #5
0
 def check_and_wrap(self, arg: Any, ctx: ExecutionContext) -> Any:
     if not isinstance(arg, self.proto):
         raise ctx.wrap(UntypyTypeError(
             expected=self.describe(),
             given=arg
         )).with_note(f"Type '{type(arg).__name__}' does not inherit from '{self.proto.__name__}'")
     return super().check_and_wrap(arg, ctx)
Beispiel #6
0
    def check_and_wrap(self, arg: Any, ctx: ExecutionContext) -> Any:
        if not issubclass(type(arg), self.origin):
            raise ctx.wrap(UntypyTypeError(arg, self.describe()))

        instance = self.template.__new__(self.template)
        instance._WrappedClassFunction__inner = arg
        instance._WrappedClassFunction__return_ctx = ReplaceTypeExecutionContext(ctx, self.name)
        return instance
Beispiel #7
0
 def check_and_wrap(self, arg: Any, ctx: ExecutionContext) -> Any:
     if simpleTypeCompat(arg, self.annotation) and not self.always_wrap:
         return arg
     if isinstance(arg, self.annotation):
         if self.parent_checker is None:
             return arg
         else:
             return self.parent_checker(arg, ctx)
     else:
         raise ctx.wrap(UntypyTypeError(arg, self.describe()))
    def check_and_wrap(self, arg: Any, upper: ExecutionContext) -> Any:
        idx = 0
        for checker in self.inner:
            ctx = UnionExecutionContext(upper, self.inner, idx)
            idx += 1
            try:
                return checker.check_and_wrap(arg, ctx)
            except UntypyTypeError as _e:
                pass

        raise upper.wrap(UntypyTypeError(arg, self.describe()))
Beispiel #9
0
    def check(self, arg: Any, ctx: ExecutionContext) -> None:
        if arg not in self.cont:
            # raise error on falsy value
            err = UntypyTypeError(
                given=arg, expected=self.annotated.describe()).with_note(
                    f"\n\nNote: {repr(arg)} is not in {repr(self.cont)}.")

            for info in self.annotated.info:
                err = err.with_note("    - " + info)

            raise ctx.wrap(err)
Beispiel #10
0
    def check_and_wrap(self, arg: Any, ctx: ExecutionContext) -> Any:
        if not type(arg) is tuple or len(arg) != len(self.inner):
            raise ctx.wrap(UntypyTypeError(arg, self.describe()))

        out = []
        idx = 0
        for elm, checker in zip(arg, self.inner):
            out.append(checker.check_and_wrap(elm, TupleExecutionContext(ctx, self.inner, idx)))
            idx += 1

        return tuple(out)
    def check_and_wrap(self, arg: Any, ctx: ExecutionContext) -> Any:
        if not hasattr(arg, '__next__') or not hasattr(arg, '__iter__'):
            raise ctx.wrap(UntypyTypeError(arg, self.describe()))

        me = self
        ctx = TypedIteratorExecutionContext(self.inner, arg, ctx)

        def wrapper():
            for item in arg:
                yield me.inner.check_and_wrap(item, ctx)

        return wrapper()
 def check(self, arg: Any, ctx: ExecutionContext) -> None:
     res = self.callable(arg)
     if not res:
         exp = self.annotated.describe()
         # raise error on falsy value
         err = UntypyTypeError(given=arg, expected=exp)
         if self.annotated.is_anonymous:
             err = err.with_note(f"condition in {exp} does not hold")
         (t, i) = err.next_type_and_indicator()
         for info in self.annotated.info:
             err = err.with_note("    - " + info)
         raise ctx.wrap(err)
Beispiel #13
0
    def check(self, arg: Any, ctx: ExecutionContext) -> None:
        res = self.callable(arg)
        if not res:
            # raise error on falsy value
            err = UntypyTypeError(given=arg,
                                  expected=self.annotated.describe())
            err = err.with_note(
                f"\n\nNote: Assertion in Callable failed with {repr(res)}.")
            (t, i) = err.next_type_and_indicator()
            err = err.with_frame(
                Frame(t, i, WrappedFunction.find_location(self.callable),
                      None))

            for info in self.annotated.info:
                err = err.with_note("    - " + info)

            raise ctx.wrap(err)
    def check_and_wrap(self, arg: Any, ctx: ExecutionContext) -> Any:
        if not issubclass(type(arg), list):
            raise ctx.wrap(UntypyTypeError(arg, self.describe()))

        return TypedList(arg, self.inner, ListExecutionContext(ctx),
                         self.declared)
Beispiel #15
0
 def check_and_wrap(self, arg: Any, ctx: ExecutionContext) -> Any:
     if isinstance(arg, self.annotation):
         return arg
     else:
         raise ctx.wrap(UntypyTypeError(arg, self.describe()))
Beispiel #16
0
 def check_and_wrap(self, arg: Any, ctx: ExecutionContext) -> Any:
     if callable(arg):
         return TypedCallable(arg, self.return_checker,
                              self.argument_checker, ctx)
     else:
         raise ctx.wrap(UntypyTypeError(arg, self.describe()))
Beispiel #17
0
 def check_and_wrap(self, arg: Any, ctx: ExecutionContext) -> Any:
     if arg in self.inner:
         return arg
     else:
         raise ctx.wrap(UntypyTypeError(arg, self.describe()))
Beispiel #18
0
def ProtocolWrapper(protocolchecker: ProtocolChecker, originalValue: Any,
                    members: dict[str, Tuple[inspect.Signature,
                                             dict[str, TypeChecker],
                                             FunctionCondition]],
                    ctx: ExecutionContext):
    list_of_attr = dict()
    original = type(originalValue)
    for fnname in members:
        if not hasattr(original, fnname):
            raise ctx.wrap(
                UntypyTypeError(expected=protocolchecker.describe(),
                                given=originalValue)
            ).with_header(
                f"{original.__name__} does not meet the requirements of protocol {protocolchecker.proto.__name__}."
            ).with_note(f"It is missing the function '{fnname}'.")

        original_fn = getattr(original, fnname)
        try:
            # fails on built ins - YEAH
            original_fn_signature = inspect.signature(original_fn)
        except:
            original_fn_signature = None

        if hasattr(original_fn, '__wf'):
            original_fn = getattr(original_fn, '__wf')
        (sig, argdict, fc) = members[fnname]

        for param in sig.parameters:
            if original_fn_signature is not None and param not in original_fn_signature.parameters:
                raise ctx.wrap(
                    UntypyTypeError(expected=protocolchecker.describe(),
                                    given=originalValue)
                ).with_header(
                    f"{original.__name__} does not meet the requirements of protocol {protocolchecker.proto.__name__}."
                ).with_note(
                    f"The signature of '{fnname}' does not match. Missing required parameter {param}."
                )

        list_of_attr[fnname] = ProtocolWrappedFunction(original_fn, sig,
                                                       argdict,
                                                       protocolchecker,
                                                       fc).build()

    def constructor(me, inner, ctx):
        me._ProtocolWrappedFunction__inner = inner
        me._ProtocolWrappedFunction__ctx = ctx

    def __getattr__(me, name):
        return getattr(me._ProtocolWrappedFunction__inner, name)

    def __setattr__(me, name, value):
        if name == '_ProtocolWrappedFunction__inner':
            super(type(me), me).__setattr__('_ProtocolWrappedFunction__inner',
                                            value)
            return
        if name == '_ProtocolWrappedFunction__ctx':
            super(type(me), me).__setattr__('_ProtocolWrappedFunction__ctx',
                                            value)
            return

        return setattr(me._ProtocolWrappedFunction__inner, name, value)

    list_of_attr['__init__'] = constructor
    list_of_attr['__getattr__'] = __getattr__  # allow access of attributes
    list_of_attr['__setattr__'] = __setattr__  # allow access of attributes

    name = f"WyppTypeCheck({original.__name__})"

    if type(original
            ) == type and original.__flags__ & 0x0400 and original not in [
                dict, list, set, tuple
            ]:
        # This class does not have any metaclass that may have unexpected side effects.
        # Also the Py_TPFLAGS_BASETYPE=0x0400 must be set to inheritable, as some classes like C-Based classes
        # like`dict_items` can not be inherited from.
        # Also some other built-in types have bugs when inherited from.
        orig_tuple = (original, )
    else:
        # Fall back to no inheritance, this should be an edge case.
        orig_tuple = ()

    t = type(name, orig_tuple, list_of_attr)

    if hasattr(original, '__module__'):
        t.__module__ = original.__module__

    return t