def copy_tb(base_tb, tb_next): # TracebackType has no public constructor, so allocate one the hard way try: raise ValueError except ValueError as exc: new_tb = exc.__traceback__ c_new_tb = CTraceback.from_address(id(new_tb)) # At the C level, tb_next either pointer to the next traceback or is # NULL. c_void_p and the .tb_next accessor both convert NULL to None, # but we shouldn't DECREF None just because we assigned to a NULL # pointer! Here we know that our new traceback has only 1 frame in it, # so we can assume the tb_next field is NULL. assert c_new_tb.tb_next is None # If tb_next is None, then we want to set c_new_tb.tb_next to NULL, # which it already is, so we're done. Otherwise, we have to actually # do some work: if tb_next is not None: _ctypes.Py_INCREF(tb_next) c_new_tb.tb_next = id(tb_next) assert c_new_tb.tb_frame is not None _ctypes.Py_INCREF(base_tb.tb_frame) old_tb_frame = new_tb.tb_frame c_new_tb.tb_frame = id(base_tb.tb_frame) _ctypes.Py_DECREF(old_tb_frame) c_new_tb.tb_lasti = base_tb.tb_lasti c_new_tb.tb_lineno = base_tb.tb_lineno return new_tb
def set_aio_task_coro( task: "asyncio.Task[Any]", new_coro: Coroutine[Any, Any, Any] ) -> None: try: task._coro = new_coro # type: ignore return except AttributeError as ex: if sys.implementation.name != "cpython": # pragma: no cover raise if "is not writable" not in str(ex): # pragma: no cover raise # If using the C accelerator on CPython, the setter isn't # even present and we need to use ctypes to change the # coroutine field. global aio_task_coro_c_offset import ctypes old_coro = get_aio_task_coro(task) if aio_task_coro_c_offset is None: # Deduce the offset by scanning the task object representation # for id(task._coro) aio_task_coro_c_offset = _aligned_ptr_offset_in_object(task, old_coro) if aio_task_coro_c_offset is None: # pragma: no cover raise RuntimeError("Couldn't determine C offset of asyncio.Task._coro") # (Explanation copied from trio._core._multierror, applies equally well here.) # How to handle refcounting? I don't want to use ctypes.py_object because # I don't understand or trust it, and I don't want to use # ctypes.pythonapi.Py_{Inc,Dec}Ref because we might clash with user code # that also tries to use them but with different types. So private _ctypes # APIs it is! import _ctypes # type: ignore coro_field = ctypes.c_size_t.from_address(id(task) + aio_task_coro_c_offset) assert coro_field.value == id(old_coro) _ctypes.Py_INCREF(new_coro) coro_field.value = id(new_coro) _ctypes.Py_DECREF(old_coro)