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 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 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)
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 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 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()))
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 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)
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)
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()))
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()))
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()))
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