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 wrap(self, err: UntypyTypeError) -> UntypyTypeError: declared = [] if isinstance(self.declared, Location): declared.append(self.declared) if isinstance(self.declared, list): declared.extend(self.declared) responsable = [] if isinstance(self.responsable, Location): responsable.append(self.responsable) if isinstance(self.responsable, list): responsable.extend(self.responsable) while len(declared) < len(responsable): declared.append(None) while len(declared) > len(responsable): responsable.append(None) for (d, r) in zip(declared, responsable): (t, i) = err.next_type_and_indicator() err = err.with_frame(Frame(t, i, d, r)) if self.upper_ctx is not None: return self.upper_ctx.wrap(err) else: return err
def wrap(self, err: UntypyTypeError) -> UntypyTypeError: next_type, indicator = err.next_type_and_indicator() err = err.with_frame( Frame(f"list[{next_type}]", (" " * len("list[") + indicator), None, None)) return self.upper.wrap(err)
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, ))
def wrap(self, err: UntypyTypeError) -> UntypyTypeError: type_declared = self.name() + "[" indicator = " " * len(type_declared) for i, checker in enumerate(self.checkers): if i == self.idx: next_type, next_indicator = err.next_type_and_indicator() type_declared += next_type indicator += next_indicator else: type_declared += checker.describe() indicator += " " * len(checker.describe()) if i != len(self.checkers) - 1: # not last element type_declared += ", " indicator += " " type_declared += "]" err = err.with_frame( Frame( type_declared, indicator, declared=self.declared(), responsable=self.responsable(), )) return self.upper.wrap(err)
def wrap(self, err: UntypyTypeError) -> UntypyTypeError: t, i = err.next_type_and_indicator() return err.with_frame( Frame(t, i, responsable=Location.from_stack(self.caller), declared=Location.from_code(self.declared)))
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)
def wrap(self, err: UntypyTypeError) -> UntypyTypeError: (nt, ni) = err.next_type_and_indicator() if nt == err.expected and nt == self.bv.inner.describe(): err.expected = self.bv.describe() err.expected_indicator = "^" * len(self.bv.describe()) return self.upper.wrap(err)
def wrap(self, err: UntypyTypeError) -> UntypyTypeError: (t, i) = err.next_type_and_indicator() return err.with_frame( Frame(t, i, declared=None, responsable=Location(file="dummy", line_no=0, line_span=1)))
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 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)
def wrap(self, err: UntypyTypeError) -> UntypyTypeError: offset = self.ch.describe().find("[") + 1 (t, i) = err.next_type_and_indicator() err = err.with_frame( Frame(type_declared=self.ch.describe(), indicator_line=(" " * offset) + i, declared=None, responsable=None)) return self.upper.wrap(err)
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)
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 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)
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 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)
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()
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
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)
def wrap(self, err: UntypyTypeError) -> UntypyTypeError: (original_expected, _ind) = err.next_type_and_indicator() err = ArgumentExecutionContext(self.wf, None, self.arg_name).wrap(err) responsable = WrappedFunction.find_location(self.wf) (decl, ind) = err.next_type_and_indicator() err = err.with_frame( Frame(decl, ind, declared=self.wf.declared(), responsable=responsable)) err = err.with_note( f"Argument {self.arg_name} of method {WrappedFunction.find_original(self.wf).__name__} violates the type declared by the {self.wf.protocol.protocol_type()} {self.wf.protocol.proto.__name__}." ) err = err.with_note( f"Annotation {original_expected} is incompatible with the {self.wf.protocol.protocol_type()}'s annotation {self.wf.checker_for(self.arg_name).describe()}." ) previous_chain = UntypyTypeError( self.me, f"{self.wf.protocol.protoname()}" ).with_header( f"{type(self.me).__name__} does not implement {self.wf.protocol.protocol_type()} {self.wf.protocol.protoname()} correctly." ) previous_chain = self.ctx.wrap(previous_chain) # err = err.with_inverted_responsibility_type() return err.with_previous_chain(previous_chain)
def wrap(self, err: UntypyTypeError) -> UntypyTypeError: err = ReturnExecutionContext(self.wf).wrap(err) if err.responsibility_type is self.invert: return err responsable = WrappedFunction.find_location(self.wf) (decl, ind) = err.next_type_and_indicator() err = err.with_inverted_responsibility_type() err = err.with_frame( Frame(decl, ind, declared=self.wf.declared(), responsable=responsable)) inner = self.wf.inner if isinstance(inner, WrappedFunction): err = err.with_note( f"The return value of method '{WrappedFunction.find_original(self.wf).__name__}' does violate the {self.wf.protocol.protocol_type()} '{self.wf.protocol.proto.__name__}'." ) err = err.with_note( f"The annotation '{inner.checker_for('return').describe()}' is incompatible with the {self.wf.protocol.protocol_type()}'s annotation '{self.wf.checker_for('return').describe()}'\nwhen checking against the following value:" ) previous_chain = UntypyTypeError( self.me, f"{self.wf.protocol.protoname()}" ).with_note( f"Type '{type(self.me).__name__}' does not implement {self.wf.protocol.protocol_type()} '{self.wf.protocol.protoname()}' correctly." ) previous_chain = self.ctx.wrap(previous_chain) return err.with_previous_chain(previous_chain)
def wrap(self, err: UntypyTypeError) -> UntypyTypeError: (original_expected, _ind) = err.next_type_and_indicator() err = ArgumentExecutionContext(self.wf, None, self.arg_name).wrap(err) responsable = WrappedFunction.find_location(self.wf) (decl, ind) = err.next_type_and_indicator() err = err.with_frame( Frame(decl, ind, declared=self.wf.declared(), responsable=responsable)) err = err.with_note( f"The argument '{self.arg_name}' of method '{WrappedFunction.find_original(self.wf).__name__}' violates the {self.wf.protocol.protocol_type()} '{self.wf.protocol.proto.__name__}'." ) err = err.with_note( f"The annotation '{original_expected}' is incompatible with the {self.wf.protocol.protocol_type()}'s annotation '{self.wf.checker_for(self.arg_name).describe()}'\nwhen checking against the following value:" ) previous_chain = UntypyTypeError( self.me, f"{self.wf.protocol.protoname()}" ).with_note( f"Type '{type(self.me).__name__}' does not implement {self.wf.protocol.protocol_type()} '{self.wf.protocol.protoname()}' correctly." ) previous_chain = self.ctx.wrap(previous_chain) # err = err.with_inverted_responsibility_type() return err.with_previous_chain(previous_chain)
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 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, 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, 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()))
def wrap(self, err: UntypyTypeError) -> UntypyTypeError: full = self.upper.wrap(err) # now remove responsability in frames: frames_to_add = [] for frame in full.frames: if frame not in err.frames: frame.responsable = None frames_to_add.append(frame) for frame in frames_to_add: err = err.with_frame(frame) for note in full.notes: err = err.with_note(note) if full.previous_chain is not None: err = err.with_previous_chain(full.previous_chain) return err
def wrap_arguments(self, ctxprv: WrappedFunctionContextProvider, args, kwargs): try: bindings = self.signature.bind(*args, **kwargs) except TypeError as e: err = UntypyTypeError(header=str(e)) if "self" not in self.signature.parameters: err = err.with_note( "Hint: 'self'-parameter was omitted in declaration.") raise ctxprv("").wrap(err) bindings.apply_defaults() if self.fc is not None: self.fc.prehook(bindings, ctxprv) for name in bindings.arguments: check = self.checker[name] ctx = ctxprv(name) bindings.arguments[name] = check.check_and_wrap( bindings.arguments[name], ctx) return bindings.args, bindings.kwargs, bindings
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()