def wrapped_func(func, *args, **kwargs): #pylint: disable=missing-docstring from .util import _is_tvm_arg_types if _is_tvm_arg_types(args): src = _pruned_source(func) closure_vars = inspect.getclosurevars(func).nonlocals closure_vars.update(inspect.getclosurevars(func).globals) return source_to_op(src, args, func.__globals__, closure_vars) from .runtime import _enter_hybrid_runtime, _restore_runtime intersect = _enter_hybrid_runtime(func) value = func(*args, **kwargs) _restore_runtime(func, intersect) return value
def _resolve_imports(func): ''' determine any modules the function might be using we cannot determine what possible closures do ''' cv = inspect.getclosurevars(func) candidates = (key for key in cv.globals if inspect.ismodule(cv.globals[key])) module_names = [key for key in candidates if key in sys.modules] return module_names
def __deepcopy__(self, clone_from_id): cls = self.__class__ result = cls.__new__(cls) clone_from_id[id(self)] = result for k, v in self.__dict__.items(): if k in ["renderer", "time_progression"]: continue if k == "camera_class": setattr(result, k, v) setattr(result, k, copy.deepcopy(v, clone_from_id)) # Update updaters for mobject in self.mobjects: cloned_updaters = [] for updater in mobject.updaters: # Make the cloned updater use the cloned Mobjects as free variables # rather than the original ones. Analyzing function bytecode with the # dis module will help in understanding this. # https://docs.python.org/3/library/dis.html # TODO: Do the same for function calls recursively. free_variable_map = inspect.getclosurevars(updater).nonlocals cloned_co_freevars = [] cloned_closure = [] for i, free_variable_name in enumerate( updater.__code__.co_freevars): free_variable_value = free_variable_map[free_variable_name] # If the referenced variable has not been cloned, raise. if id(free_variable_value) not in clone_from_id: raise Exception( f"{free_variable_name} is referenced from an updater " "but is not an attribute of the Scene, which isn't " "allowed.") # Add the cloned object's name to the free variable list. cloned_co_freevars.append(free_variable_name) # Add a cell containing the cloned object's reference to the # closure list. cloned_closure.append( types.CellType(clone_from_id[id(free_variable_value)])) cloned_updater = types.FunctionType( updater.__code__.replace( co_freevars=tuple(cloned_co_freevars)), updater.__globals__, updater.__name__, updater.__defaults__, tuple(cloned_closure), ) cloned_updaters.append(cloned_updater) clone_from_id[id(mobject)].updaters = cloned_updaters return result
def _cast_detection_model(model, device): # check model is an instance of one of the meta arch from detectron2.export.caffe2_modeling import Caffe2MetaArch from detectron2.modeling import META_ARCH_REGISTRY if isinstance(model, Caffe2MetaArch): model._wrapped_model = _cast_detection_model(model._wrapped_model, device) return model assert isinstance(model, tuple(META_ARCH_REGISTRY._obj_map.values())) model.to(device) # cast normalizer separately if hasattr(model, "normalizer") and not ( hasattr(model, "pixel_mean") and hasattr(model, "pixel_std") ): pixel_mean = inspect.getclosurevars(model.normalizer).nonlocals["pixel_mean"] pixel_std = inspect.getclosurevars(model.normalizer).nonlocals["pixel_std"] pixel_mean = pixel_mean.to(device) pixel_std = pixel_std.to(device) model.normalizer = lambda x: (x - pixel_mean) / pixel_std return model
def no_globals(*funcs): '''Warn about global variables in functions, a common source of problems''' import inspect NoGlobalVars = True for func in funcs: for gname, gvalue in inspect.getclosurevars(func).globals.items(): if not inspect.ismodule(gvalue) and not inspect.isfunction(gvalue): print( 'Warning: You appear to be using global variable "{}" in function "{}"' .format(gname, func.__name__)) NoGlobalVars = False assert NoGlobalVars, 'Use only parameters and local variables in your functions'
def test_wrap_r_function(is_method): r_code = 'function(x, y=FALSE, z="abc") TRUE' parameter_names = ('self', 'x', 'y', 'z') if is_method else ('x', 'y', 'z') r_func = robjects.r(r_code) foo = robjects.functions.wrap_r_function(r_func, 'foo', is_method=is_method) assert inspect.getclosurevars(foo).nonlocals['r_func'].rid == r_func.rid assert tuple(foo.__signature__.parameters.keys()) == parameter_names if not is_method: res = foo(1) assert res[0] is True
def replace_class_closure(func, class_): """ functions defined within classes that use super() are given a __class__ closure variable which is how the super() magic works. However, this messes up methods when they are attached to a diferent class. """ closurevars = inspect.getclosurevars(func) assert '__class__' in closurevars.nonlocals new_func = types.FunctionType(func.__code__, func.__globals__, closure=(make_cell(class_),)) return new_func
def function_by_value_reducer(fun): cl_vars = inspect.getclosurevars(fun) code = marshal.dumps(fun.__code__) basic_def = (fun.__name__, fun.__qualname__, code, fun.__closure__) global_refs = dict(cl_vars.globals) get_global_references_from_nested_code(fun.__code__, fun.__globals__, global_refs) fun_context = { 'global_refs': global_refs, 'defaults': fun.__defaults__, 'kwdefaults': fun.__kwdefaults__ } return function_unpickle, basic_def, fun_context, None, None, set_funcion_state
def __init__(self, mapping_func, clamp): self.mapping_func = mapping_func self.clamp = clamp tree = util.get_ast(mapping_func).body[0] closure_vars = inspect.getclosurevars(mapping_func) for var, value in closure_vars.nonlocals.items(): value = ast.parse(str(value)).body[0].value tree = util.inline_variable(var, value, tree) self.ast = tree self.ndim = len(self.ast.args.args) self.shape = mapping_func(*[1 for _ in range(self.ndim)])
def __deepcopy__(self, memo): cls = self.__class__ result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): if type(v) in [FrameServer, Event, Camera]: continue setattr(result, k, copy.deepcopy(v, memo)) # Update updaters for mobject in self.mobjects: cloned_updaters = [] for updater in mobject.updaters: # Make the cloned updater use the cloned Mobjects as free variables # rather than the original ones. # TODO: The the same for function calls recursively. free_variable_map = inspect.getclosurevars(updater).nonlocals cloned_co_freevars = [] cloned_closure = [] for i, free_variable_name in enumerate( updater.__code__.co_freevars): free_variable_value = free_variable_map[free_variable_name] if isinstance(free_variable_value, Mobject): random_name = get_random_name(free_variable_map) # Put the cloned Mobject in the function's scope. free_variable_map[random_name] = memo[id( free_variable_value)] # Add the cloned Mobject's name to the free variable list. cloned_co_freevars.append(random_name) # Add a cell containing the cloned Mobject's reference to the # closure list. cloned_closure.append( types.CellType(memo[id(free_variable_value)])) else: cloned_co_freevars.append(free_variable_name) cloned_closure.append(updater.__closure__[i]) cloned_updater = types.FunctionType( updater.__code__.replace( co_freevars=tuple(cloned_co_freevars)), updater.__globals__, updater.__name__, updater.__defaults__, tuple(cloned_closure), ) cloned_updaters.append(cloned_updater) memo[id(mobject)].updaters = cloned_updaters return result
def analyze(target: CallableFunction) -> Node: """Analyze specified target and return a Node representation. Args: target (CallableFunction): async function to analyze. Returns: (Node): a node instance representation of target function """ nonlocals = getclosurevars(target).nonlocals def _analyze_property(p): """Return a tuple (name, value) or (name, function name) as property.""" value = nonlocals[p] if p in nonlocals else None return p, value.__name__ if value and callable(value) else value def _analyze_edges(egde_name): """Lookup children node from egde_name local var.""" value = None if egde_name in nonlocals and nonlocals[egde_name]: edge = nonlocals[egde_name] # it could be a collection of node if hasattr(edge, "__iter__"): value = list(map(analyze, edge)) else: # or a single node value = [analyze(edge)] return (egde_name, value) if hasattr(target, "__node_metadata"): # its a node construct. node = target.__node_metadata if not isinstance(node, NodeMetadata): raise RuntimeError( f'attr __node_metadata of {target} is not a NodeMetadata!') return Node( name=node.name, properties=list(map(_analyze_property, node.properties)), edges=list( filter(lambda p: p is not None, map(_analyze_edges, node.edges))), ) # simple function return Node( name=target.__name__.lstrip("_") if hasattr(target, "__name__") else "anonymous", properties=list(map(_analyze_property, nonlocals.keys())), edges=[], )
def _inline_modules(fn, modules, constants): if sys.version_info.major == 2: return None cvs = inspect.getclosurevars(fn) for mk in cvs.globals.keys(): gv = cvs.globals[mk] if isinstance(gv, types.ModuleType): modules[mk] = gv.__name__ elif hasattr(gv, '__module__') and gv.__module__ != '__main__': modules[mk] = gv.__name__, gv.__module__ elif type(gv) == str or type(gv) == int or type(gv) == float or type(gv) == bool: constants[mk] = gv else: raise TypeError("Unsupported global closure {} type {} in {}".format(mk, gv, fn))
def test_precedence(order, allclose): closure_vars = inspect.getclosurevars(allclose) overrides = closure_vars.nonlocals["overrides"] assert len(overrides) == 1 pairs = get_vector_pairs(order, order * 2, np.random.RandomState(6)) if order in (1, 2): assert overrides[0] == dict(atol=order, rtol=order * 2) for x, y, close in pairs: assert allclose(y, x) == close else: assert overrides[0] == dict(atol=2, rtol=4) x, y, _ = pairs[0] assert not allclose(y, x)
def _rewrite_fn(self, fn): # Rewrite the operation so that its if statements are wrapped within a # matching context. node = ast.parse(_unindent(inspect.getsource(fn))) node = _RewriteOperation().visit(node) src = astunparse.unparse(node) exec(compile(src, filename='', mode='exec')) self._fn = locals()['_fn'] update_wrapper(self._fn, fn) self._fn.__qualname__ = fn.__qualname__ self._fn._original = fn self._fn._nonlocals = inspect.getclosurevars(self._fn._original).nonlocals
def get_currently_executing_function_call_arguments( include_module_name: bool = False, include_caller_names: bool = False, **kwargs) -> dict: cf: FrameType = currentframe() fb: FrameType = cf.f_back argvs: ArgInfo = getargvalues(fb) fc: CodeType = fb.f_code cur_func_obj: Callable = [ referer for referer in get_referrers(fc) if getattr(referer, "__code__", None) is fc and getclosurevars(referer).nonlocals.items() <= fb.f_locals.items() ][0] cur_mod = getmodule(cur_func_obj) sig: Signature = signature(cur_func_obj) params: dict = {} var_positional: dict = {} var_keyword: dict = {} for key, param in sig.parameters.items(): val: Any = argvs.locals[key] params[key] = val if param.kind == Parameter.VAR_POSITIONAL: var_positional[key] = val elif param.kind == Parameter.VAR_KEYWORD: var_keyword[key] = val bound_args: BoundArguments = sig.bind(**params) call_args: OrderedDict = bound_args.arguments call_args_dict: dict = dict(call_args) for key, value in var_positional.items(): call_args_dict[key] = value for key, value in var_keyword.items(): call_args_dict.pop(key) call_args_dict.update(value) if include_module_name: call_args_dict.update({"module_name": cur_mod.__name__}) if not include_caller_names: if call_args.get("cls"): call_args_dict.pop("cls", None) if call_args.get("self"): call_args_dict.pop("self", None) call_args_dict.update(**kwargs) return call_args_dict
def _get_loader_details(hook) -> tuple: """Return the loader_details for a given FileFinder closure :param hook: FileFinder closure :returns: loader_details tuple """ try: namespace = inspect.getclosurevars(hook) except TypeError as err: raise ValueError from err try: return namespace.nonlocals["loader_details"] except KeyError as err: raise ValueError from err
def can_process(self, view): if inspect.isclass(view): for func in self._get_method_decorators(view.dispatch): if 'user_passes_test' not in (func.__name__, func.__qualname__.split('.')[0]): continue test_func = inspect.getclosurevars(func).nonlocals['test_func'] if test_func.__name__ == 'check_perms': return True elif inspect.isfunction(view): # Unwrap the function and look for the has_perms property. return self._has_func_decorator(view, 'has_perms') return False
def _get_operation_spec(handler): closure_vars = inspect.getclosurevars(handler) description = closure_vars.nonlocals.get('description', '') payload_schema = closure_vars.nonlocals.get('payload_schema') response_schema = closure_vars.nonlocals.get('response_schema') success_response_code = closure_vars.nonlocals.get( 'success_response_code') openApiConverter = OpenAPIConverter(OPEN_API_VERSION, lambda s: None, None) request_body = {} response = {} if payload_schema: payload_schema_dict = openApiConverter.schema2jsonschema( payload_schema) request_body = dict(requestBody=dict( description=payload_schema.__name__, content={'application/json': { 'schema': payload_schema_dict }})) if response_schema: response_schema_dict = openApiConverter.schema2jsonschema( response_schema) response = { f'{success_response_code}': { 'description': 'success', 'content': { 'application/json': { 'schema': response_schema_dict } } } } else: response = {f'{success_response_code}': ''} return { 'description': description, 'responses': { **response }, **request_body }
def default(self, obj): """ This method is used to serialize objects to JSON format. If obj is a function, then it will return a dict with two keys : 'code', for the code source, and 'nonlocals' for all nonlocalsvalues. (including nonlocals functions, that will be serialized as this is recursive.) if obj is a np.darray, it converts it into a list. if obj is an object with __dict__ attribute, it returns its __dict__. Else, will let the JSONEncoder do the stuff, and throw an error if the type is not suitable for JSONEncoder. Parameters ---------- obj : Any Arbitrary object to convert Returns ------- Any Python object that JSON encoder will recognize """ if not (isinstance(obj, ModuleType)) and isinstance( obj, (MethodType, FunctionType) ): cvars = inspect.getclosurevars(obj) cvardict = {**copy.copy(cvars.globals), **copy.copy(cvars.nonlocals)} for i in list(cvardict): # NOTE : All module types objects are removed, because otherwise it throws ValueError: Circular reference detected if not. TODO if isinstance(cvardict[i], ModuleType): del cvardict[i] return self._check_iterable( {"code": inspect.getsource(obj), "nonlocals": cvardict} ) elif isinstance(obj, np.ndarray): if obj.size > 1000: obj = np.resize(obj, (100, 100)) return f"TRUNCATED ARRAY: {repr(obj)}" # We return the repr and not a list to avoid the JsonEncoder to iterate over it. return repr(obj) elif hasattr(obj, "__dict__"): temp = getattr(obj, "__dict__") # MappingProxy is not supported by the Json Encoder if isinstance(temp, MappingProxyType): return dict(temp) return self._check_iterable(temp) elif isinstance(obj, np.uint8): return int(obj) return f"Unsupported type for serializing -> {str(type(obj))}"
def test_make_validator(): def func(): ... key = "foo" params = {"bar": "xy", "baz": (1, -1)} name, validator = make_validator(func, key, **params).popitem() assert isinstance(validator, classmethod) assert name == func.__name__ assert getclosurevars(validator.__func__).nonlocals["params"] == params assert hasattr(validator, "__validator_config__") assert validator.__validator_config__[0] == (key, ) # validated key name, root_validator = make_validator(func, "", **params).popitem() assert hasattr(root_validator, "__root_validator_config__")
def _has_method_decorator(self, function, func_name): """ Checks if a function with the name `func_name` (str) is present within the ``@method_decorator`` on the provided function. """ closures = inspect.getclosurevars(function).nonlocals if 'decorators' in closures: for func in closures['decorators']: if func.__name__ == func_name or func.__qualname__.split( '.')[0] == func_name: return True if 'method' in closures: return self._has_method_decorator(closures['method'], func_name) return False
def get_bindable(obj, base): """ attr : dict of inspect.Attribute base : type Returns a obj/function that can properly be moved to another class. Largely this deals with Python 3 and super() binding the class via a closure. """ if not isinstance(obj, types.FunctionType): return obj closurevars = getclosurevars(obj) if '__class__' in closurevars.nonlocals: obj = replace_class_closure(obj, base) return obj
def _inspect_func_serialization(base_obj, depth, parent, failure_set): """Adds the first-found non-serializable element to the failure_set.""" assert inspect.isfunction(base_obj) closure = inspect.getclosurevars(base_obj) found = False if closure.globals: _printer.print( f"Detected {len(closure.globals)} global variables. " "Checking serializability..." ) with _printer.indent(): for name, obj in closure.globals.items(): serializable, _ = inspect_serializability( obj, name=name, depth=depth - 1, _parent=parent, _failure_set=failure_set, ) found = found or not serializable if found: break if closure.nonlocals: _printer.print( f"Detected {len(closure.nonlocals)} nonlocal variables. " "Checking serializability..." ) with _printer.indent(): for name, obj in closure.nonlocals.items(): serializable, _ = inspect_serializability( obj, name=name, depth=depth - 1, _parent=parent, _failure_set=failure_set, ) found = found or not serializable if found: break if not found: _printer.print( f"WARNING: Did not find non-serializable object in {base_obj}. " "This may be an oversight." ) return found
def decipher_done_callback(done_callback): closure = inspect.getclosurevars(done_callback).nonlocals state = f"progress: {closure['nfinished']}/{closure['nfuts']}" future = closure["outer"] print(future, state) children = closure["children"] for child in children: if child.done(): # resolved, exception, cancelled if child.cancelled(): print(child, "cancelled") elif child.exception(): print(child, child.exception()) else: print(child, child.result()) else: print(child, "pending")
def __init__(self, environment: Environment, function: FunctionType, globals_: Dict[str, Any] = None) -> None: """Construct a parser.""" self.environment = environment self.function = function _, self.line_offset = inspect.getsourcelines(function) self.filename: str = inspect.getfile(function) self.block_map: Dict[Block, Constant] = {} if globals_ is None: free_vars = inspect.getclosurevars(function) # type: ignore assert isinstance(free_vars.builtins, Dict) globals_ = free_vars.builtins globals_.update(free_vars.globals) globals_.update(free_vars.nonlocals) self.globals_ = globals_
def getAllGlobals(req, restrictTo=None): namespace = req.__globals__ if restrictTo is not None and restrictTo is not namespace: return {} externals = inspect.getclosurevars(req) assert not externals.nonlocals # TODO handle these globs = dict(externals.builtins) for name, value in externals.globals.items(): globs[name] = value if inspect.isfunction(value): subglobs = getAllGlobals(value, restrictTo=namespace) for name, value in subglobs.items(): if name in globs: assert value is globs[name] else: globs[name] = value return globs
def test_validator_getter(): # TODO: test all variations spec = { "validator": "range_check", "validator_params": {"min_key": "min"} # "validator_opts": FIXME: } key = "foo" validator = _validator(key, spec)[spec["validator"]] # FIXME: move to test_factory assert isinstance(validator, classmethod) # type assert validator.__validator_config__[0] == (key,) # validated key # list of all keys of parent assert ( getclosurevars(validator.__func__).nonlocals["params"] == spec["validator_params"] )
def global_getclosurevars(f: Callable) -> inspect.ClosureVars: """Grab the closure over all passed function. Add all known global variables in as well. Args: f (Callable): The function pointer Returns: inspect.ClosureVars: Standard thing returned from `inspect.getclosurevars`, with the global variables added into it. """ cv = inspect.getclosurevars(f) # Now, add all the globals that we might know about in case they are also # referenced inside this a nested lambda. cv.globals.update(f.__globals__) # type: ignore return cv
def _is_abstract_hard_check(cls, obj): try: closure_vars = inspect.getclosurevars(obj) for value in closure_vars.builtins.values(): if value is NotImplementedError or value is NotImplemented: break else: return False except AttributeError: # can not determine - probably native or builtin code return False try: for instruction in dis.get_instructions(obj): if instruction.opname == "RAISE_VARARGS" and instruction.arg == 1: return True except TypeError: pass return False
def getAllGlobals(req, restrictTo=None): """Find all names the given lambda depends on, along with their current bindings.""" namespace = req.__globals__ if restrictTo is not None and restrictTo is not namespace: return {} externals = inspect.getclosurevars(req) assert not externals.nonlocals # TODO handle these globs = dict(externals.builtins) for name, value in externals.globals.items(): globs[name] = value if inspect.isfunction(value): subglobs = getAllGlobals(value, restrictTo=namespace) for name, value in subglobs.items(): if name in globs: assert value is globs[name] else: globs[name] = value return globs
def default(self, obj): """ This method is used to serialize objects to JSON format. If obj is a function, then it will return a dict with two keys : 'code', for the code source, and 'nonlocals' for all nonlocalsvalues. (including nonlocals functions, that will be serialized as this is recursive.) if obj is a np.darray, it converts it into a list. if obj is an object with __dict__ attribute, it returns its __dict__. Else, will let the JSONEncoder do the stuff, and throw an error if the type is not suitable for JSONEncoder. Parameters ---------- obj : Any Arbitrary object to convert Returns ------- Any Python object that JSON encoder will recognize """ if inspect.isfunction(obj) and not isinstance(obj, ModuleType): cvars = inspect.getclosurevars(obj) cvardict = { **copy.copy(cvars.globals), **copy.copy(cvars.nonlocals) } for i in list(cvardict): # NOTE : All module types objects are removed, because otherwise it throws ValueError: Circular reference detected if not. TODO if isinstance(cvardict[i], ModuleType): del cvardict[i] return {"code": inspect.getsource(obj), "nonlocals": cvardict} elif isinstance(obj, np.ndarray): return list(obj) elif hasattr(obj, "__dict__"): temp = getattr(obj, "__dict__") return self._encode_dict(temp) elif isinstance(obj, np.uint8): return int(obj) try: return json.JSONEncoder.default(self, obj) except TypeError: # This is used when the user enters an unknown type in CONFIG. Rather than throwing an error, we transform # it into a string "Unsupported type for hashing" so that it won't affect the hash. return "Unsupported type for hashing"
def check(func): args = getargs(func.__code__) hints = get_type_hints(func) cv = getclosurevars(func) loc_vars = {n: Any for n in args.args} ret = hints.pop('return') if 'return' in hints else None loc_vars.update(hints) glob_vars = {} for k, v in cv.globals.items(): if v is np: glob_vars[k] = NumPy() else: glob_vars[k] = defines.get(v, None) or v source = getsource(func) f_ast = parse(source).body[0] body = f_ast.body exec_lines(source, body, loc_vars, glob_vars, ret) defines[func] = 1 return func
def kernel(func, **kwargs): """Decorator to simplify generation of pystencils Assignments. Changes the meaning of the '@=' operator. Each line containing this operator gives a symbolic assignment in the result list. Furthermore the meaning of the ternary inline 'if-else' changes meaning to denote a sympy Piecewise. The decorated function may not receive any arguments, with exception of an argument called 's' that specifies a SymbolCreator() Examples: >>> import pystencils as ps >>> @kernel ... def my_kernel(s): ... f, g = ps.fields('f, g: [2D]') ... s.neighbors @= f[0,1] + f[1,0] ... g[0,0] @= s.neighbors + f[0,0] if f[0,0] > 0 else 0 >>> f, g = ps.fields('f, g: [2D]') >>> assert my_kernel[0].rhs == f[0,1] + f[1,0] """ source = inspect.getsource(func) source = textwrap.dedent(source) a = ast.parse(source) KernelFunctionRewrite().visit(a) ast.fix_missing_locations(a) gl = func.__globals__.copy() assignments = [] def assignment_adder(lhs, rhs): assignments.append(Assignment(lhs, rhs)) gl['_add_assignment'] = assignment_adder gl['_Piecewise'] = sp.Piecewise gl.update(inspect.getclosurevars(func).nonlocals) exec(compile(a, filename="<ast>", mode="exec"), gl) func = gl[func.__name__] args = inspect.getfullargspec(func).args if 's' in args and 's' not in kwargs: kwargs['s'] = SymbolCreator() func(**kwargs) return assignments
def wrapped(*args, **kwargs): closure = inspect.getclosurevars(f) # Create locals local_context = inspect.getcallargs(f, *args, **kwargs) # Create globals global_context = closure.globals global_context.update(closure.builtins) global_context.update(closure.nonlocals) # Run function Requires for requirement, string in zip(requires, require_strings): assert eval(requirement, global_context, local_context), "Requirement failed: {}. Arguments: {}".format(string, args) # Run argument Requires for argument in local_context: # Optional, in case you want to use mypy. if type_checks: expected_type = f.__annotations__.get(argument) if expected_type: try: error_message = "{arg} ({val}) is not an instance of {typ} and it should be.".format(arg=argument, val=local_context[argument], typ=expected_type) assert isinstance(local_context[argument], expected_type), error_message except TypeError: # Because of the way the `typing` library works, it's not really feasible to check that the argument has the correct *type*. # isinstance(val, Type) (where Type is defined by the `typing` library) will generate a TypeError. # This is deeply unfortunate but unavoidable. pass requirements = annotation_requirements.get(argument, ()) compiled = compiled_annotations.get(argument, ()) for requirement, string in zip(compiled, requirements): assert eval(requirement, global_context, local_context), "Annotation requirement failed: {}. Arguments: {}".format(string, args) # Run Ensures return_value = f(*args, **kwargs) local_context[return_string] = return_value for guarantee, string in zip(ensures, ensure_strings): assert eval(guarantee, global_context, local_context), "Guarantee failed: {}. Return value: {}".format(string, return_value) return return_value