def prehook(self, boundargs, ctx: WrappedFunctionContextProvider):
        for p in self.precondition:
            bindings = {}
            for name in inspect.signature(p).parameters:
                if name in boundargs.arguments:
                    bindings[name] = boundargs.arguments[name]
                else:
                    raise UntypyAttributeError(
                        f"Did not find argument {name} of precondition 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 precondition"

                err = UntypyTypeError(
                    bindings,
                    expected
                )
                err = err.with_note("Failed precondition.")
                err = err.with_frame(Frame(
                    expected,
                    "",
                    declared=WrappedFunction.find_location(p),
                    responsable=None,
                ))
                raise ctx(0).wrap(err)
    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)
Example #3
0
    def wrap(self, err: UntypyTypeError) -> UntypyTypeError:
        (next_ty, indicator) = err.next_type_and_indicator()
        return_id = IndicatorStr(next_ty, indicator)

        original = WrappedFunction.find_original(self.fn)

        try:
            signature = inspect.signature(original)  # TODO:!!! FIX BUILTINS
            front_sig = []
            for name in signature.parameters:
                front_sig.append(
                    f"{name}: {self.fn.checker_for(name).describe()}")
            front_sig = f"{original.__name__}(" + (
                ", ".join(front_sig)) + ") -> "
            return_id = IndicatorStr(front_sig) + return_id
        except:
            return_id = IndicatorStr("???")

        declared = WrappedFunction.find_location(self.fn)
        return err.with_frame(
            Frame(
                return_id.ty,
                return_id.indicator,
                declared=declared,
                responsable=declared,
            ))
Example #4
0
    def wrap(self, err: UntypyTypeError) -> UntypyTypeError:
        (original_expected, _ind) = err.next_type_and_indicator()
        err = ArgumentExecutionContext(self.tc.inner, None,
                                       self.arg_name).wrap(err)

        func_decl = WrappedFunction.find_location(self.tc.inner)

        name = WrappedFunction.find_original(self.tc.inner).__name__

        (decl, ind) = err.next_type_and_indicator()
        err = err.with_frame(
            Frame(decl, ind, declared=None, responsable=func_decl))

        previous_chain = UntypyTypeError(
            f"def {name}{self.tc.inner.describe()}", f"{self.tc.describe()}")
        (decl, ind) = previous_chain.next_type_and_indicator()
        previous_chain = previous_chain.with_frame(
            Frame(decl, ind, declared=func_decl, responsable=None))

        err = err.with_note(
            f"The argument '{self.arg_name}' of method '{name}' violates the signature of {self.tc.describe()}."
        )

        previous_chain = self.upper.wrap(previous_chain)

        return err.with_previous_chain(previous_chain)
    def wrap(self, err: UntypyTypeError) -> UntypyTypeError:
        (next_ty, indicator) = err.next_type_and_indicator()
        error_id = IndicatorStr(next_ty, indicator)

        original = WrappedFunction.find_original(self.fn)
        try:
            signature = inspect.signature(original)
        except ValueError:
            # fails on some built-ins
            signature = inspect.signature(self.fn)

        wf = None
        if (hasattr(self.fn, '__wf')):
            wf = getattr(self.fn, '__wf')
        elif isinstance(self.fn, WrappedFunction):
            wf = self.fn

        arglist = []
        for name in signature.parameters:
            if name is self.argument_name:
                arglist.append(IndicatorStr(f"{name}: ") + error_id)
            else:
                if wf is not None:
                    arglist.append(
                        IndicatorStr(
                            f"{name}: {wf.checker_for(name).describe()}"))
                else:
                    arglist.append(IndicatorStr(f"{name}"))

        id = IndicatorStr(f"{format_name(original)}(") + IndicatorStr(
            ", ").join(arglist)

        if wf is not None:
            id += IndicatorStr(f") -> {wf.checker_for('return').describe()}")
        else:
            id += IndicatorStr(f")")

        if self.declared is None:
            declared = WrappedFunction.find_location(self.fn)
        else:
            declared = self.declared

        if self.stack is not None:
            responsable = Location.from_stack(self.stack)
        else:
            responsable = None

        frame = Frame(id.ty,
                      id.indicator,
                      declared=declared,
                      responsable=responsable)
        return err.with_frame(frame)
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 find_lambdasource(fn) -> Optional[str]:
    """
    tries to retuns body of precondition or postcondition annotation
    """
    try:
        fn = WrappedFunction.find_original(fn)
        source = inspect.getsource(fn).split('\n')
        m = re.match('@[a-zA-Z_\.]+\((.*)\)', source[0])
        if m is not None and len(m.groups()) == 1:
            return m.group(1)
    except:
        return None
Example #8
0
 def __init__(self, inner: Callable, return_checker: TypeChecker,
              argument_checker: list[TypeChecker], ctx: ExecutionContext):
     # unwrap if wrapped function
     self.ResponsibilityType = None
     if hasattr(inner, '__wf'):
         inner = getattr(inner, '__wf')
     self.inner = inner
     self.return_checker = return_checker
     self.argument_checker = argument_checker
     self.ctx = ctx
     self.fn = WrappedFunction.find_original(self.inner)
     setattr(self, '__wf', self)
Example #9
0
def wrap_function(fn: FunctionType, cfg: Config) -> Callable:
    if len(inspect.getfullargspec(fn).annotations) > 0:
        if cfg.verbose:
            print(f"Patching Function: {fn.__name__}")
        return TypedFunctionBuilder(
            fn,
            DefaultCreationContext(
                typevars=dict(),
                declared_location=WrappedFunction.find_location(fn),
                checkedpkgprefixes=cfg.checkedprefixes,
                eval_context=fn.__globals__)).build()
    else:
        return fn
    def wrap(self, err: UntypyTypeError) -> UntypyTypeError:
        (next_ty, indicator) = err.next_type_and_indicator()
        return_id = IndicatorStr(next_ty, indicator)

        original = WrappedFunction.find_original(self.fn)

        try:
            signature = inspect.signature(original)  # TODO:!!! FIX BUILTINS
            front_sig = []
            for name in signature.parameters:
                front_sig.append(
                    f"{name}: {self.fn.checker_for(name).describe()}")
            front_sig = f"{format_name(original)}(" + (
                ", ".join(front_sig)) + ") -> "
            return_id = IndicatorStr(front_sig) + return_id
        except:
            return_id = IndicatorStr("???")

        declared = WrappedFunction.find_location(self.fn)
        responsable = declared

        if responsable is not None:
            if err.expected is not None and err.given is None:
                # Missing Return-Value?
                err = err.with_note("Did you miss a return statement?")
                last_line = responsable.line_no + responsable.line_span - 1
                responsable = responsable.narrow_in_span(
                    (responsable.file, last_line))
            else:
                responsable = responsable.narrow_in_span(self.reti_loc)

        return err.with_frame(
            Frame(
                return_id.ty,
                return_id.indicator,
                declared=declared,
                responsable=responsable,
            ))
Example #11
0
    def wrap(self, err: UntypyTypeError) -> UntypyTypeError:
        (type_declared, indicator_line) = self.declared_and_indicator(err)

        declared = WrappedFunction.find_location(self.fn.inner)

        responsable = Location.from_stack(self.stack)

        frame = Frame(
            type_declared,
            indicator_line,
            declared=declared,
            responsable=responsable,
        )

        err = err.with_frame(frame)
        err = err.with_inverted_responsibility_type()
        return self.upper.wrap(err)
Example #12
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)
Example #13
0
    def wrap(self, err: UntypyTypeError) -> UntypyTypeError:
        if self.invert:
            err = ReturnExecutionContext(self.fn.inner).wrap(err)
            return err

        (next_ty, indicator) = err.next_type_and_indicator()

        desc = lambda s: s.describe()
        front_str = f"Callable[[{', '.join(map(desc, self.fn.argument_checker))}], "

        responsable = WrappedFunction.find_location(self.fn.inner)

        err = err.with_frame(
            Frame(f"{front_str}{next_ty}]", (" " * len(front_str)) + indicator,
                  declared=None,
                  responsable=responsable))

        return self.upper.wrap(err)
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)
def location_of(fn):
    return WrappedFunction.find_location(fn)
Example #16
0
 def declared(self) -> Location:
     if self._declared is None:
         return WrappedFunction.find_location(self.inner)
     else:
         return self._declared
Example #17
0
 def describe(self) -> str:
     fn = WrappedFunction.find_original(self.inner)
     return f"{fn.__name__}" + str(self.signature)