diff options
Diffstat (limited to 'python/gevent/_tblib.py')
-rw-r--r-- | python/gevent/_tblib.py | 432 |
1 files changed, 0 insertions, 432 deletions
diff --git a/python/gevent/_tblib.py b/python/gevent/_tblib.py deleted file mode 100644 index 1336401..0000000 --- a/python/gevent/_tblib.py +++ /dev/null @@ -1,432 +0,0 @@ -# -*- coding: utf-8 -*- -# A vendored version of part of https://github.com/ionelmc/python-tblib -# pylint:disable=redefined-outer-name,reimported,function-redefined,bare-except,no-else-return,broad-except -#### -# Copyright (c) 2013-2016, Ionel Cristian Mărieș -# All rights reserved. - -# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -# following conditions are met: - -# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -# disclaimer. - -# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided with the distribution. - -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#### - -# cpython.py - -""" -Taken verbatim from Jinja2. - -https://github.com/mitsuhiko/jinja2/blob/master/jinja2/debug.py#L267 -""" -# pylint:disable=consider-using-dict-comprehension -#import platform # XXX: gevent cannot import platform at the top level; interferes with monkey patching -import sys - - -def _init_ugly_crap(): - """This function implements a few ugly things so that we can patch the - traceback objects. The function returned allows resetting `tb_next` on - any python traceback object. Do not attempt to use this on non cpython - interpreters - """ - import ctypes - from types import TracebackType - - # figure out side of _Py_ssize_t - if hasattr(ctypes.pythonapi, 'Py_InitModule4_64'): - _Py_ssize_t = ctypes.c_int64 - else: - _Py_ssize_t = ctypes.c_int - - # regular python - class _PyObject(ctypes.Structure): - pass - - _PyObject._fields_ = [ - ('ob_refcnt', _Py_ssize_t), - ('ob_type', ctypes.POINTER(_PyObject)) - ] - - # python with trace - if hasattr(sys, 'getobjects'): - class _PyObject(ctypes.Structure): - pass - - _PyObject._fields_ = [ - ('_ob_next', ctypes.POINTER(_PyObject)), - ('_ob_prev', ctypes.POINTER(_PyObject)), - ('ob_refcnt', _Py_ssize_t), - ('ob_type', ctypes.POINTER(_PyObject)) - ] - - class _Traceback(_PyObject): - pass - - _Traceback._fields_ = [ - ('tb_next', ctypes.POINTER(_Traceback)), - ('tb_frame', ctypes.POINTER(_PyObject)), - ('tb_lasti', ctypes.c_int), - ('tb_lineno', ctypes.c_int) - ] - - def tb_set_next(tb, next): - """Set the tb_next attribute of a traceback object.""" - if not (isinstance(tb, TracebackType) and (next is None or isinstance(next, TracebackType))): - raise TypeError('tb_set_next arguments must be traceback objects') - obj = _Traceback.from_address(id(tb)) - if tb.tb_next is not None: - old = _Traceback.from_address(id(tb.tb_next)) - old.ob_refcnt -= 1 - if next is None: - obj.tb_next = ctypes.POINTER(_Traceback)() - else: - next = _Traceback.from_address(id(next)) - next.ob_refcnt += 1 - obj.tb_next = ctypes.pointer(next) - - return tb_set_next - - -tb_set_next = None -#try: -# if platform.python_implementation() == 'CPython': -# tb_set_next = _init_ugly_crap() -#except Exception as exc: -# sys.stderr.write("Failed to initialize cpython support: {!r}".format(exc)) -#del _init_ugly_crap - -# __init__.py -import re -from types import CodeType -from types import TracebackType - -try: - from __pypy__ import tproxy -except ImportError: - tproxy = None - -__version__ = '1.3.0' -__all__ = ('Traceback',) - -PY3 = sys.version_info[0] == 3 -FRAME_RE = re.compile(r'^\s*File "(?P<co_filename>.+)", line (?P<tb_lineno>\d+)(, in (?P<co_name>.+))?$') - - -class _AttrDict(dict): - __slots__ = () - __getattr__ = dict.__getitem__ - - -# noinspection PyPep8Naming -class __traceback_maker(Exception): - pass - - -class TracebackParseError(Exception): - pass - - -class Code(object): - def __init__(self, code): - self.co_filename = code.co_filename - self.co_name = code.co_name - # gevent: copy more attributes - self.co_nlocals = code.co_nlocals - self.co_stacksize = code.co_stacksize - self.co_flags = code.co_flags - self.co_firstlineno = code.co_firstlineno - - -class Frame(object): - def __init__(self, frame): - self.f_globals = dict([ - (k, v) - for k, v in frame.f_globals.items() - if k in ("__file__", "__name__") - ]) - self.f_code = Code(frame.f_code) - - def clear(self): - # For compatibility with PyPy 3.5; - # clear was added to frame in Python 3.4 - # and is called by traceback.clear_frames(), which - # in turn is called by unittest.TestCase.assertRaises - pass - -class Traceback(object): - - tb_next = None - - def __init__(self, tb): - self.tb_frame = Frame(tb.tb_frame) - # noinspection SpellCheckingInspection - self.tb_lineno = int(tb.tb_lineno) - - # Build in place to avoid exceeding the recursion limit - tb = tb.tb_next - prev_traceback = self - cls = type(self) - while tb is not None: - traceback = object.__new__(cls) - traceback.tb_frame = Frame(tb.tb_frame) - traceback.tb_lineno = int(tb.tb_lineno) - prev_traceback.tb_next = traceback - prev_traceback = traceback - tb = tb.tb_next - - def as_traceback(self): - if tproxy: - return tproxy(TracebackType, self.__tproxy_handler) - if not tb_set_next: - raise RuntimeError("Cannot re-create traceback !") - - current = self - top_tb = None - tb = None - while current: - f_code = current.tb_frame.f_code - code = compile('\n' * (current.tb_lineno - 1) + 'raise __traceback_maker', current.tb_frame.f_code.co_filename, 'exec') - if PY3: - code = CodeType( - 0, code.co_kwonlyargcount, - code.co_nlocals, code.co_stacksize, code.co_flags, - code.co_code, code.co_consts, code.co_names, code.co_varnames, - f_code.co_filename, f_code.co_name, - code.co_firstlineno, code.co_lnotab, (), () - ) - else: - code = CodeType( - 0, - code.co_nlocals, code.co_stacksize, code.co_flags, - code.co_code, code.co_consts, code.co_names, code.co_varnames, - f_code.co_filename.encode(), f_code.co_name.encode(), - code.co_firstlineno, code.co_lnotab, (), () - ) - - # noinspection PyBroadException - try: - exec(code, current.tb_frame.f_globals, {}) - except: - next_tb = sys.exc_info()[2].tb_next - if top_tb is None: - top_tb = next_tb - if tb is not None: - tb_set_next(tb, next_tb) - tb = next_tb - del next_tb - - current = current.tb_next - try: - return top_tb - finally: - del top_tb - del tb - - - # noinspection SpellCheckingInspection - def __tproxy_handler(self, operation, *args, **kwargs): - if operation in ('__getattribute__', '__getattr__'): - if args[0] == 'tb_next': - return self.tb_next and self.tb_next.as_traceback() - else: - return getattr(self, args[0]) - else: - return getattr(self, operation)(*args, **kwargs) - - def to_dict(self): - """Convert a Traceback into a dictionary representation""" - if self.tb_next is None: - tb_next = None - else: - tb_next = self.tb_next.to_dict() - - code = { - 'co_filename': self.tb_frame.f_code.co_filename, - 'co_name': self.tb_frame.f_code.co_name, - } - frame = { - 'f_globals': self.tb_frame.f_globals, - 'f_code': code, - } - return { - 'tb_frame': frame, - 'tb_lineno': self.tb_lineno, - 'tb_next': tb_next, - } - - @classmethod - def from_dict(cls, dct): - if dct['tb_next']: - tb_next = cls.from_dict(dct['tb_next']) - else: - tb_next = None - - code = _AttrDict( - co_filename=dct['tb_frame']['f_code']['co_filename'], - co_name=dct['tb_frame']['f_code']['co_name'], - ) - frame = _AttrDict( - f_globals=dct['tb_frame']['f_globals'], - f_code=code, - ) - tb = _AttrDict( - tb_frame=frame, - tb_lineno=dct['tb_lineno'], - tb_next=tb_next, - ) - return cls(tb) - - @classmethod - def from_string(cls, string, strict=True): - frames = [] - header = strict - - for line in string.splitlines(): - line = line.rstrip() - if header: - if line == 'Traceback (most recent call last):': - header = False - continue - frame_match = FRAME_RE.match(line) - if frame_match: - frames.append(frame_match.groupdict()) - elif line.startswith(' '): - pass - elif strict: - break # traceback ended - - if frames: - previous = None - for frame in reversed(frames): - previous = _AttrDict( - frame, - tb_frame=_AttrDict( - frame, - f_globals=_AttrDict( - __file__=frame['co_filename'], - __name__='?', - ), - f_code=_AttrDict(frame), - ), - tb_next=previous, - ) - return cls(previous) - else: - raise TracebackParseError("Could not find any frames in %r." % string) - -# pickling_support.py - - -def unpickle_traceback(tb_frame, tb_lineno, tb_next): - ret = object.__new__(Traceback) - ret.tb_frame = tb_frame - ret.tb_lineno = tb_lineno - ret.tb_next = tb_next - return ret.as_traceback() - - -def pickle_traceback(tb): - return unpickle_traceback, (Frame(tb.tb_frame), tb.tb_lineno, tb.tb_next and Traceback(tb.tb_next)) - - -def install(): - try: - import copy_reg - except ImportError: - import copyreg as copy_reg - - copy_reg.pickle(TracebackType, pickle_traceback) - -# Added by gevent - -# We have to defer the initialization, and especially the import of platform, -# until runtime. If we're monkey patched, we need to be sure to use -# the original __import__ to avoid switching through the hub due to -# import locks on Python 2. See also builtins.py for details. - - -def _unlocked_imports(f): - def g(a): - if sys is None: # pragma: no cover - # interpreter shutdown on Py2 - return - - gb = None - if 'gevent.builtins' in sys.modules: - gb = sys.modules['gevent.builtins'] - gb._unlock_imports() - try: - return f(a) - finally: - if gb is not None: - gb._lock_imports() - g.__name__ = f.__name__ - g.__module__ = f.__module__ - return g - - -def _import_dump_load(): - global dumps - global loads - try: - import cPickle as pickle - except ImportError: - import pickle - dumps = pickle.dumps - loads = pickle.loads - -dumps = loads = None - -_installed = False - - -def _init(): - global _installed - global tb_set_next - if _installed: - return - - _installed = True - import platform - try: - if platform.python_implementation() == 'CPython': - tb_set_next = _init_ugly_crap() - except Exception as exc: - sys.stderr.write("Failed to initialize cpython support: {!r}".format(exc)) - - try: - from __pypy__ import tproxy - except ImportError: - tproxy = None - - if not tb_set_next and not tproxy: - raise ImportError("Cannot use tblib. Runtime not supported.") - _import_dump_load() - install() - - -@_unlocked_imports -def dump_traceback(tb): - # Both _init and dump/load have to be unlocked, because - # copy_reg and pickle can do imports to resolve class names; those - # class names are in this module and greenlet safe though - _init() - return dumps(tb) - - -@_unlocked_imports -def load_traceback(s): - _init() - return loads(s) |