def c(code): """Execute inline C code respecting scoping rules. Parameters ---------- code : str C source code to execute. """ frame = sys._getframe().f_back entry = frame.f_code, frame.f_lineno cache = c._cache locals_ = frame.f_locals ns = ChainMap( locals_, {k: v for k, v in frame.f_globals.items() if _notdunder(k)}, ) try: f = cache[entry] except KeyError: f = cache[entry] = _make_c_func(code, frame) local_keys = locals_.keys() locals_.update({k: v for k, v in f(**dict(ns)).items() if k in local_keys}) pythonapi.PyFrame_LocalsToFast(py_object(frame), c_int(1))
def _bind_to_calling_scope(self): ''' Inject the result of a successful match into the calling scope. This only works inside of a decorated function; use dict style lookup syntax for use in a context manager. NOTE: This uses some not-so-nice abuse of stack frames and the ctypes API to make this work and as such it will probably not run under anything other than cPython. ''' # Grab the stack frame that the caller's code is running in frame = _getframe(2) # Dump the matched variables and their values into the frame frame.f_locals.update(self.map) # Force an update of the frame locals from the locals dict pythonapi.PyFrame_LocalsToFast(py_object(frame), c_int(0))
def true_exec(code, scope): """exec() a codeblock in given scope. Used by seapi repl scope 0 equals executing in context of caller of true_exec(). scope 1 equals executing in context of the caller for the caller of true_exec(). """ parent = sys._getframe(scope + 1) # +1 escapes true_exec itself parent_globals = parent.f_globals parent_locals = parent.f_locals try: exec(code, parent_globals, parent_locals) except KeyboardInterrupt: # emulate ctrl+c if code='input()' print("\nKeyboardInterrupt") except Exception: # catch arbitary exceptions from exec traceback.print_exc() # beware traveller. here lies dark spell of the olden times ! # the following call forces update to locals() # adding new variables is allowed but calling them requires # some indirection like using exec() or a placeholder # otherwise you will get nameError when calling the variable # the magic value 1 stands for ability to introduce new # variables. 0 for update-only pythonapi.PyFrame_LocalsToFast(py_object(parent), c_int(1))
def _replace_local_var(source, rel, new): source.f_locals[rel] = new api.PyFrame_LocalsToFast(ctypes.py_object(source), ctypes.c_int(0))
def locals_to_fast(frame, clear: int = 0, **_): # pylint: disable=missing-function-docstring pythonapi.PyFrame_LocalsToFast(py_object(frame), c_int(clear))