diff options
author | Colin Watson <cjwatson@debian.org> | 2017-03-31 19:14:27 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2017-03-31 21:16:19 +0100 |
commit | bdb7a6c2cff31b152393f24243f9c1e8424252e3 (patch) | |
tree | 447d75815541fb066d2222e16c93c4dde0521ad4 | |
parent | 611cbe3d729b8253519a696db780ae74c50d8e6a (diff) | |
parent | d73804c7759eef8d3bb469686eba71c5cafa6824 (diff) |
New upstream release (1.3.1)
-rw-r--r-- | .bumpversion.cfg | 4 | ||||
-rw-r--r-- | .cookiecutterrc | 8 | ||||
-rw-r--r-- | .travis.yml | 40 | ||||
-rw-r--r-- | AUTHORS.rst | 1 | ||||
-rw-r--r-- | CHANGELOG.rst | 6 | ||||
-rw-r--r-- | CONTRIBUTING.rst | 2 | ||||
-rw-r--r-- | LICENSE | 2 | ||||
-rw-r--r-- | PKG-INFO | 47 | ||||
-rw-r--r-- | README.rst | 56 | ||||
-rw-r--r-- | appveyor.yml | 12 | ||||
-rw-r--r-- | ci/appveyor-bootstrap.py | 19 | ||||
-rwxr-xr-x | ci/appveyor-download.py | 6 | ||||
-rwxr-xr-x | ci/bootstrap.py | 13 | ||||
-rw-r--r-- | ci/templates/.travis.yml | 16 | ||||
-rw-r--r-- | ci/templates/appveyor.yml | 2 | ||||
-rw-r--r-- | debian/.git-dpm | 14 | ||||
-rw-r--r-- | debian/changelog | 6 | ||||
-rw-r--r-- | docs/conf.py | 6 | ||||
-rw-r--r-- | setup.cfg | 3 | ||||
-rw-r--r-- | setup.py | 4 | ||||
-rw-r--r-- | src/tblib.egg-info/PKG-INFO | 47 | ||||
-rw-r--r-- | src/tblib/__init__.py | 54 | ||||
-rw-r--r-- | tox.ini | 13 |
23 files changed, 264 insertions, 117 deletions
diff --git a/.bumpversion.cfg b/.bumpversion.cfg index e8a0d70..e4f2adf 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,10 +1,12 @@ [bumpversion] -current_version = 1.3.0 +current_version = 1.3.1 commit = True tag = True [bumpversion:file:setup.py] +[bumpversion:file:README.rst] + [bumpversion:file:docs/conf.py] [bumpversion:file:src/tblib/__init__.py] diff --git a/.cookiecutterrc b/.cookiecutterrc index ab6d10a..04e27da 100644 --- a/.cookiecutterrc +++ b/.cookiecutterrc @@ -2,7 +2,7 @@ cookiecutter: appveyor: 'yes' - c_extension_cython: 'yes' + c_extension_cython: 'no' c_extension_optional: 'no' c_extension_support: 'no' codacy: 'yes' @@ -19,7 +19,7 @@ cookiecutter: package_name: tblib project_name: tblib project_short_description: Traceback serialization library. - release_date: '2015-12-18' + release_date: '2016-03-08' repo_name: python-tblib requiresio: 'yes' scrutinizer: 'yes' @@ -29,6 +29,6 @@ cookiecutter: test_matrix_separate_coverage: 'no' test_runner: pytest travis: 'yes' - version: 1.2.0 + version: 1.3.0 website: http://blog.ionelmc.ro - year: 2013-2016 + year: 2013-2017 diff --git a/.travis.yml b/.travis.yml index db8c283..fd82b90 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: python -python: '3.5' sudo: false +cache: pip env: global: - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so @@ -8,19 +8,26 @@ env: matrix: - TOXENV=check - TOXENV=docs - - - TOXENV=py26,coveralls,codecov - - - TOXENV=py27,coveralls,codecov - - - TOXENV=py33,coveralls,codecov - - - TOXENV=py34,coveralls,codecov - - - TOXENV=py35,coveralls,codecov - - - TOXENV=pypy,coveralls,codecov - +matrix: + include: + - python: 2.7 + env: + - TOXENV=py27,report,coveralls,codecov + - python: 3.3 + env: + - TOXENV=py33,report,coveralls,codecov + - python: 3.4 + env: + - TOXENV=py34,report,coveralls,codecov + - python: 3.5 + env: + - TOXENV=py35,report,coveralls,codecov + - python: 3.6 + env: + - TOXENV=py36,report,coveralls,codecov + - python: pypy + env: + - TOXENV=pypy,report,coveralls,codecov before_install: - python --version - uname -a @@ -36,11 +43,6 @@ script: after_failure: - more .tox/log/* | cat - more .tox/*/log/* | cat -before_cache: - - rm -rf $HOME/.cache/pip/log -cache: - directories: - - $HOME/.cache/pip notifications: email: on_success: never diff --git a/AUTHORS.rst b/AUTHORS.rst index 20d39ce..59052f3 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -6,3 +6,4 @@ Authors * Arcadiy Ivanov - https://github.com/arcivanov * Beckjake - https://github.com/beckjake * DRayX - https://github.com/DRayX +* Jason Madden - https://github.com/jamadden diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 422a3ce..f2992e7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,12 @@ Changelog ========= +1.3.1 (2017-03-27) +~~~~~~~~~~~~~~~~~~ + +* Fixed handling for tracebacks due to exceeding the recursion limit. + Fixes `#15 <https://github.com/ionelmc/python-tblib/issues/15>`_. + 1.3.0 (2016-03-08) ~~~~~~~~~~~~~~~~~~ diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 85e6472..a4d4ef1 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -49,7 +49,7 @@ To set up `python-tblib` for local development: Now you can make your changes locally. -4. When you're done making changes, run all the checks, doc builder and spell checker with `tox <http://tox.readthedocs.org/en/latest/install.html>`_ one command:: +4. When you're done making changes, run all the checks, doc builder and spell checker with `tox <http://tox.readthedocs.io/en/latest/install.html>`_ one command:: tox @@ -1,4 +1,4 @@ -Copyright (c) 2013-2016, Ionel Cristian Mărieș +Copyright (c) 2013-2017, Ionel Cristian Mărieș All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: tblib -Version: 1.3.0 +Version: 1.3.1 Summary: Traceback serialization library. Home-page: https://github.com/ionelmc/python-tblib Author: Ionel Cristian Mărieș @@ -18,10 +18,15 @@ Description: ======== It allows you to: - * Pickle tracebacks and raise exceptions with pickled tracebacks in different processes. - This allows better error handling when running code over multiple processes (imagine multiprocessing, billiard, futures, - celery etc). - * Parse traceback strings and raise with the parsed tracebacks. + * `Pickle <https://docs.python.org/3/library/pickle.html>`_ tracebacks and raise exceptions + with pickled tracebacks in different processes. This allows better error handling when running + code over multiple processes (imagine multiprocessing, billiard, futures, celery etc). + * Create traceback objects from strings (the ``from_string`` method). *No pickling is used*. + * Serialize tracebacks to/from plain dicts (the ``from_dict`` and ``to_dict`` methods). *No pickling is used*. + * Raise the tracebacks created from the aforementioned sources. + + **Again, note that using the pickle support is completely optional. You are solely responsible for + security problems should you decide to use the pickle support.** Installation ============ @@ -232,6 +237,28 @@ Description: ======== raise Exception("boom!") Exception: boom! + Or a traceback that's caused by exceeding the recursion limit (here we're + forcing the type and value to have consistency across platforms):: + + >>> def f(): f() + >>> try: + ... f() + ... except RuntimeError: + ... et, ev, tb = sys.exc_info() + ... tb = Traceback(tb) + ... + >>> reraise(RuntimeError, RuntimeError("maximum recursion depth exceeded"), tb.as_traceback()) + Traceback (most recent call last): + ... + File "<doctest README.rst[32]>", line 1, in f + def f(): f() + File "<doctest README.rst[32]>", line 1, in f + def f(): f() + File "<doctest README.rst[32]>", line 1, in f + def f(): f() + ... + RuntimeError: maximum recursion depth exceeded + Reference ~~~~~~~~~ @@ -278,7 +305,7 @@ Description: ======== ... tb = Traceback(tb) ... tb_dict = tb.to_dict() ... pprint(tb_dict) - {'tb_frame': {'f_code': {'co_filename': '<doctest README.rst[37]>', + {'tb_frame': {'f_code': {'co_filename': '<doctest README.rst[...]>', 'co_name': '<module>'}, 'f_globals': {'__name__': '__main__'}}, 'tb_lineno': 2, @@ -532,6 +559,12 @@ Description: ======== Changelog ========= + 1.3.1 (2017-03-27) + ~~~~~~~~~~~~~~~~~~ + + * Fixed handling for tracebacks due to exceeding the recursion limit. + Fixes `#15 <https://github.com/ionelmc/python-tblib/issues/15>`_. + 1.3.0 (2016-03-08) ~~~~~~~~~~~~~~~~~~ @@ -564,12 +597,12 @@ Classifier: Operating System :: Unix Classifier: Operating System :: POSIX Classifier: Operating System :: Microsoft :: Windows Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Utilities @@ -14,7 +14,8 @@ Overview | |coveralls| |codecov| | |landscape| |scrutinizer| |codacy| |codeclimate| * - package - - |version| |downloads| |wheel| |supported-versions| |supported-implementations| + - | |version| |wheel| |supported-versions| |supported-implementations| + | |commits-since| .. |docs| image:: https://readthedocs.org/projects/python-tblib/badge/?style=flat :target: https://readthedocs.org/projects/python-tblib @@ -52,27 +53,27 @@ Overview :target: https://codeclimate.com/github/ionelmc/python-tblib :alt: CodeClimate Quality Status -.. |version| image:: https://img.shields.io/pypi/v/tblib.svg?style=flat +.. |version| image:: https://img.shields.io/pypi/v/tblib.svg :alt: PyPI Package latest release :target: https://pypi.python.org/pypi/tblib -.. |downloads| image:: https://img.shields.io/pypi/dm/tblib.svg?style=flat - :alt: PyPI Package monthly downloads - :target: https://pypi.python.org/pypi/tblib +.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-tblib/v1.3.1.svg + :alt: Commits since latest release + :target: https://github.com/ionelmc/python-tblib/compare/v1.3.1...master -.. |wheel| image:: https://img.shields.io/pypi/wheel/tblib.svg?style=flat +.. |wheel| image:: https://img.shields.io/pypi/wheel/tblib.svg :alt: PyPI Wheel :target: https://pypi.python.org/pypi/tblib -.. |supported-versions| image:: https://img.shields.io/pypi/pyversions/tblib.svg?style=flat +.. |supported-versions| image:: https://img.shields.io/pypi/pyversions/tblib.svg :alt: Supported versions :target: https://pypi.python.org/pypi/tblib -.. |supported-implementations| image:: https://img.shields.io/pypi/implementation/tblib.svg?style=flat +.. |supported-implementations| image:: https://img.shields.io/pypi/implementation/tblib.svg :alt: Supported implementations :target: https://pypi.python.org/pypi/tblib -.. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/ionelmc/python-tblib/master.svg?style=flat +.. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/ionelmc/python-tblib/master.svg :alt: Scrutinizer Status :target: https://scrutinizer-ci.com/g/ionelmc/python-tblib/ @@ -85,10 +86,15 @@ Traceback serialization library. It allows you to: -* Pickle tracebacks and raise exceptions with pickled tracebacks in different processes. - This allows better error handling when running code over multiple processes (imagine multiprocessing, billiard, futures, - celery etc). -* Parse traceback strings and raise with the parsed tracebacks. +* `Pickle <https://docs.python.org/3/library/pickle.html>`_ tracebacks and raise exceptions + with pickled tracebacks in different processes. This allows better error handling when running + code over multiple processes (imagine multiprocessing, billiard, futures, celery etc). +* Create traceback objects from strings (the ``from_string`` method). *No pickling is used*. +* Serialize tracebacks to/from plain dicts (the ``from_dict`` and ``to_dict`` methods). *No pickling is used*. +* Raise the tracebacks created from the aforementioned sources. + +**Again, note that using the pickle support is completely optional. You are solely responsible for +security problems should you decide to use the pickle support.** Installation ============ @@ -299,6 +305,28 @@ Or other import failures:: raise Exception("boom!") Exception: boom! +Or a traceback that's caused by exceeding the recursion limit (here we're +forcing the type and value to have consistency across platforms):: + + >>> def f(): f() + >>> try: + ... f() + ... except RuntimeError: + ... et, ev, tb = sys.exc_info() + ... tb = Traceback(tb) + ... + >>> reraise(RuntimeError, RuntimeError("maximum recursion depth exceeded"), tb.as_traceback()) + Traceback (most recent call last): + ... + File "<doctest README.rst[32]>", line 1, in f + def f(): f() + File "<doctest README.rst[32]>", line 1, in f + def f(): f() + File "<doctest README.rst[32]>", line 1, in f + def f(): f() + ... + RuntimeError: maximum recursion depth exceeded + Reference ~~~~~~~~~ @@ -345,7 +373,7 @@ json.JSONDecoder:: ... tb = Traceback(tb) ... tb_dict = tb.to_dict() ... pprint(tb_dict) - {'tb_frame': {'f_code': {'co_filename': '<doctest README.rst[37]>', + {'tb_frame': {'f_code': {'co_filename': '<doctest README.rst[...]>', 'co_name': '<module>'}, 'f_globals': {'__name__': '__main__'}}, 'tb_lineno': 2, diff --git a/appveyor.yml b/appveyor.yml index 8df0ae8..776475e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -49,6 +49,18 @@ environment: PYTHON_VERSION: '3.5' PYTHON_ARCH: '64' + - TOXENV: 'py36,codecov' + TOXPYTHON: C:\Python36\python.exe + PYTHON_HOME: C:\Python36 + PYTHON_VERSION: '3.6' + PYTHON_ARCH: '32' + + - TOXENV: 'py36,codecov' + TOXPYTHON: C:\Python36-x64\python.exe + PYTHON_HOME: C:\Python36-x64 + PYTHON_VERSION: '3.6' + PYTHON_ARCH: '64' + init: - ps: echo $env:TOXENV - ps: ls C:\Python* diff --git a/ci/appveyor-bootstrap.py b/ci/appveyor-bootstrap.py index 74abd0b..d4d09dc 100644 --- a/ci/appveyor-bootstrap.py +++ b/ci/appveyor-bootstrap.py @@ -18,15 +18,17 @@ BASE_URL = "https://www.python.org/ftp/python/" GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py" GET_PIP_PATH = "C:\get-pip.py" URLS = { - ("2.7", "64"): BASE_URL + "2.7.10/python-2.7.10.amd64.msi", - ("2.7", "32"): BASE_URL + "2.7.10/python-2.7.10.msi", + ("2.7", "64"): BASE_URL + "2.7.10/python-2.7.13.amd64.msi", + ("2.7", "32"): BASE_URL + "2.7.10/python-2.7.13.msi", # NOTE: no .msi installer for 3.3.6 - ("3.3", "64"): BASE_URL + "3.3.3/python-3.3.3.amd64.msi", - ("3.3", "32"): BASE_URL + "3.3.3/python-3.3.3.msi", - ("3.4", "64"): BASE_URL + "3.4.3/python-3.4.3.amd64.msi", - ("3.4", "32"): BASE_URL + "3.4.3/python-3.4.3.msi", - ("3.5", "64"): BASE_URL + "3.5.0/python-3.5.0-amd64.exe", - ("3.5", "32"): BASE_URL + "3.5.0/python-3.5.0.exe", + ("3.3", "64"): BASE_URL + "3.3.3/python-3.3.5.amd64.msi", + ("3.3", "32"): BASE_URL + "3.3.3/python-3.3.5.msi", + ("3.4", "64"): BASE_URL + "3.4.3/python-3.4.6.amd64.msi", + ("3.4", "32"): BASE_URL + "3.4.3/python-3.4.6.msi", + ("3.5", "64"): BASE_URL + "3.5.0/python-3.5.3-amd64.exe", + ("3.5", "32"): BASE_URL + "3.5.0/python-3.5.3.exe", + ("3.6", "64"): BASE_URL + "3.6.0/python-3.6.0-amd64.exe", + ("3.6", "32"): BASE_URL + "3.6.0/python-3.6.0.exe", } INSTALL_CMD = { # Commands are allowed to fail only if they are not the last command. Eg: uninstall (/x) allowed to fail. @@ -37,6 +39,7 @@ INSTALL_CMD = { "3.4": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"], ["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]], "3.5": [["{path}", "/quiet", "TargetDir={home}"]], + "3.6": [["{path}", "/quiet", "TargetDir={home}"]], } diff --git a/ci/appveyor-download.py b/ci/appveyor-download.py index 3160d2e..c6fb081 100755 --- a/ci/appveyor-download.py +++ b/ci/appveyor-download.py @@ -10,9 +10,10 @@ from __future__ import unicode_literals import argparse import os -import requests import zipfile +import requests + def make_auth_headers(): """Make the authentication headers needed to use the Appveyor API.""" @@ -64,7 +65,7 @@ def download_latest_artifacts(account_project, build_id): def ensure_dirs(filename): """Make sure the directories exist for `filename`.""" - dirname, _ = os.path.split(filename) + dirname = os.path.dirname(filename) if dirname and not os.path.exists(dirname): os.makedirs(dirname) @@ -90,6 +91,7 @@ def unpack_zipfile(filename): ensure_dirs(name) z.extract(name) + parser = argparse.ArgumentParser(description='Download artifacts from AppVeyor.') parser.add_argument('--id', metavar='PROJECT_ID', diff --git a/ci/bootstrap.py b/ci/bootstrap.py index 0283662..e5292aa 100755 --- a/ci/bootstrap.py +++ b/ci/bootstrap.py @@ -4,10 +4,10 @@ from __future__ import absolute_import, print_function, unicode_literals import os import sys +from os.path import abspath +from os.path import dirname from os.path import exists from os.path import join -from os.path import dirname -from os.path import abspath if __name__ == "__main__": @@ -20,21 +20,22 @@ if __name__ == "__main__": bin_path = join(env_path, "bin") if not exists(env_path): import subprocess + print("Making bootstrap env in: {0} ...".format(env_path)) try: subprocess.check_call(["virtualenv", env_path]) - except Exception: + except subprocess.CalledProcessError: subprocess.check_call([sys.executable, "-m", "virtualenv", env_path]) - print("Installing `jinja2` into bootstrap environment ...") + print("Installing `jinja2` into bootstrap environment...") subprocess.check_call([join(bin_path, "pip"), "install", "jinja2"]) activate = join(bin_path, "activate_this.py") + # noinspection PyCompatibility exec(compile(open(activate, "rb").read(), activate, "exec"), dict(__file__=activate)) import jinja2 import subprocess - jinja = jinja2.Environment( loader=jinja2.FileSystemLoader(join(base_path, "ci", "templates")), trim_blocks=True, @@ -44,11 +45,11 @@ if __name__ == "__main__": tox_environments = [ line.strip() + # WARNING: 'tox' must be installed globally or in the project's virtualenv for line in subprocess.check_output(['tox', '--listenvs'], universal_newlines=True).splitlines() ] tox_environments = [line for line in tox_environments if line not in ['clean', 'report', 'docs', 'check']] - for name in os.listdir(join("ci", "templates")): with open(join(base_path, name), "w") as fh: fh.write(jinja.get_template(name).render(tox_environments=tox_environments)) diff --git a/ci/templates/.travis.yml b/ci/templates/.travis.yml index a7e364c..6c04ae0 100644 --- a/ci/templates/.travis.yml +++ b/ci/templates/.travis.yml @@ -1,6 +1,6 @@ language: python -python: '3.5' sudo: false +cache: pip env: global: - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so @@ -8,10 +8,13 @@ env: matrix: - TOXENV=check - TOXENV=docs -{% for env in tox_environments %}{{ '' }} - - TOXENV={{ env }},coveralls,codecov +matrix: + include: +{% for env in tox_environments %} + - python: {{ env.split('-')[0] if env.startswith('pypy') else '{0[2]}.{0[3]}'.format(env) }} + env: + - TOXENV={{ env }},report,coveralls,codecov {% endfor %} - before_install: - python --version - uname -a @@ -27,11 +30,6 @@ script: after_failure: - more .tox/log/* | cat - more .tox/*/log/* | cat -before_cache: - - rm -rf $HOME/.cache/pip/log -cache: - directories: - - $HOME/.cache/pip notifications: email: on_success: never diff --git a/ci/templates/appveyor.yml b/ci/templates/appveyor.yml index d164d6a..2d175da 100644 --- a/ci/templates/appveyor.yml +++ b/ci/templates/appveyor.yml @@ -11,7 +11,7 @@ environment: PYTHON_VERSION: '2.7' PYTHON_ARCH: '32' -{% for env in tox_environments %}{% if env.startswith(('py27', 'py34', 'py35')) %} +{% for env in tox_environments %}{% if env.startswith(('py2', 'py3')) %} - TOXENV: '{{ env }},codecov' TOXPYTHON: C:\Python{{ env[2:4] }}\python.exe PYTHON_HOME: C:\Python{{ env[2:4] }} diff --git a/debian/.git-dpm b/debian/.git-dpm index 7ef51fc..183bee6 100644 --- a/debian/.git-dpm +++ b/debian/.git-dpm @@ -1,8 +1,8 @@ # see git-dpm(1) from git-dpm package -fe522b0c47d430ac13bc4c4c8a091b8cef2085ee -fe522b0c47d430ac13bc4c4c8a091b8cef2085ee -fe522b0c47d430ac13bc4c4c8a091b8cef2085ee -fe522b0c47d430ac13bc4c4c8a091b8cef2085ee -python-tblib_1.3.0.orig.tar.gz -a30938cd77d090a10ac13c9901669cdc43b75142 -25295 +d73804c7759eef8d3bb469686eba71c5cafa6824 +d73804c7759eef8d3bb469686eba71c5cafa6824 +d73804c7759eef8d3bb469686eba71c5cafa6824 +d73804c7759eef8d3bb469686eba71c5cafa6824 +python-tblib_1.3.1.orig.tar.gz +f62dfdde3587172f1ab5e570929fe84a5e1b69b0 +25038 diff --git a/debian/changelog b/debian/changelog index 8e8685f..b68bd9c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +python-tblib (1.3.1-1) UNRELEASED; urgency=medium + + * New upstream release. + + -- Colin Watson <cjwatson@debian.org> Fri, 31 Mar 2017 19:14:33 +0100 + python-tblib (1.3.0-2) unstable; urgency=medium * Upgrade to debhelper v9. diff --git a/docs/conf.py b/docs/conf.py index 80205b5..be4aa37 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -23,10 +23,10 @@ if os.getenv('SPELLCHECK'): source_suffix = '.rst' master_doc = 'index' project = 'tblib' -year = '2013-2016' +year = '2013-2017' author = 'Ionel Cristian Mărieș' copyright = '{0}, {1}'.format(year, author) -version = release = '1.3.0' +version = release = '1.3.1' pygments_style = 'trac' templates_path = ['.'] @@ -43,7 +43,7 @@ html_theme_options = { html_use_smartypants = True html_last_updated_fmt = '%b %d, %Y' -html_split_index = True +html_split_index = False html_sidebars = { '**': ['searchbox.html', 'globaltoc.html', 'sourcelink.html'], } @@ -5,7 +5,7 @@ universal = 1 max-line-length = 140 exclude = tests/*,*/migrations/*,*/south_migrations/* -[pytest] +[tool:pytest] norecursedirs = .git .tox @@ -39,5 +39,4 @@ skip = migrations, south_migrations [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 @@ -24,7 +24,7 @@ def read(*names, **kwargs): setup( name='tblib', - version='1.3.0', + version='1.3.1', license='BSD', description='Traceback serialization library.', long_description='%s\n%s' % ( @@ -48,12 +48,12 @@ setup( 'Operating System :: POSIX', 'Operating System :: Microsoft :: Windows', 'Programming Language :: Python', - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Utilities', diff --git a/src/tblib.egg-info/PKG-INFO b/src/tblib.egg-info/PKG-INFO index c276c52..f73edc0 100644 --- a/src/tblib.egg-info/PKG-INFO +++ b/src/tblib.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: tblib -Version: 1.3.0 +Version: 1.3.1 Summary: Traceback serialization library. Home-page: https://github.com/ionelmc/python-tblib Author: Ionel Cristian Mărieș @@ -18,10 +18,15 @@ Description: ======== It allows you to: - * Pickle tracebacks and raise exceptions with pickled tracebacks in different processes. - This allows better error handling when running code over multiple processes (imagine multiprocessing, billiard, futures, - celery etc). - * Parse traceback strings and raise with the parsed tracebacks. + * `Pickle <https://docs.python.org/3/library/pickle.html>`_ tracebacks and raise exceptions + with pickled tracebacks in different processes. This allows better error handling when running + code over multiple processes (imagine multiprocessing, billiard, futures, celery etc). + * Create traceback objects from strings (the ``from_string`` method). *No pickling is used*. + * Serialize tracebacks to/from plain dicts (the ``from_dict`` and ``to_dict`` methods). *No pickling is used*. + * Raise the tracebacks created from the aforementioned sources. + + **Again, note that using the pickle support is completely optional. You are solely responsible for + security problems should you decide to use the pickle support.** Installation ============ @@ -232,6 +237,28 @@ Description: ======== raise Exception("boom!") Exception: boom! + Or a traceback that's caused by exceeding the recursion limit (here we're + forcing the type and value to have consistency across platforms):: + + >>> def f(): f() + >>> try: + ... f() + ... except RuntimeError: + ... et, ev, tb = sys.exc_info() + ... tb = Traceback(tb) + ... + >>> reraise(RuntimeError, RuntimeError("maximum recursion depth exceeded"), tb.as_traceback()) + Traceback (most recent call last): + ... + File "<doctest README.rst[32]>", line 1, in f + def f(): f() + File "<doctest README.rst[32]>", line 1, in f + def f(): f() + File "<doctest README.rst[32]>", line 1, in f + def f(): f() + ... + RuntimeError: maximum recursion depth exceeded + Reference ~~~~~~~~~ @@ -278,7 +305,7 @@ Description: ======== ... tb = Traceback(tb) ... tb_dict = tb.to_dict() ... pprint(tb_dict) - {'tb_frame': {'f_code': {'co_filename': '<doctest README.rst[37]>', + {'tb_frame': {'f_code': {'co_filename': '<doctest README.rst[...]>', 'co_name': '<module>'}, 'f_globals': {'__name__': '__main__'}}, 'tb_lineno': 2, @@ -532,6 +559,12 @@ Description: ======== Changelog ========= + 1.3.1 (2017-03-27) + ~~~~~~~~~~~~~~~~~~ + + * Fixed handling for tracebacks due to exceeding the recursion limit. + Fixes `#15 <https://github.com/ionelmc/python-tblib/issues/15>`_. + 1.3.0 (2016-03-08) ~~~~~~~~~~~~~~~~~~ @@ -564,12 +597,12 @@ Classifier: Operating System :: Unix Classifier: Operating System :: POSIX Classifier: Operating System :: Microsoft :: Windows Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Utilities diff --git a/src/tblib/__init__.py b/src/tblib/__init__.py index 3a6abf6..6bb2fd2 100644 --- a/src/tblib/__init__.py +++ b/src/tblib/__init__.py @@ -15,7 +15,7 @@ except ImportError: if not tb_set_next and not tproxy: raise ImportError("Cannot use tblib. Runtime not supported.") -__version__ = '1.3.0' +__version__ = '1.3.1' __all__ = 'Traceback', PY3 = sys.version_info[0] == 3 @@ -53,21 +53,38 @@ class Frame(object): 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) - if tb.tb_next is None: - self.tb_next = None - else: - self.tb_next = Traceback(tb.tb_next) + + # 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) - elif tb_set_next: - f_code = self.tb_frame.f_code - code = compile('\n' * (self.tb_lineno - 1) + 'raise __traceback_maker', self.tb_frame.f_code.co_filename, 'exec') + if not tb_set_next: + raise RuntimeError("Unsupported Python interpreter!") + + 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, @@ -87,13 +104,22 @@ class Traceback(object): # noinspection PyBroadException try: - exec(code, self.tb_frame.f_globals, {}) + exec(code, current.tb_frame.f_globals, {}) except: - tb = sys.exc_info()[2].tb_next - tb_set_next(tb, self.tb_next and self.tb_next.as_traceback()) - return tb - else: - raise RuntimeError("Cannot re-create traceback !") + 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): @@ -4,20 +4,19 @@ envlist = clean, check, - {py26,py27,py33,py34,py35,pypy}, + {py27,py33,py34,py35,py36,pypy}, report, docs [testenv] basepython = pypy: {env:TOXPYTHON:pypy} - py26: {env:TOXPYTHON:python2.6} {py27,docs,spell}: {env:TOXPYTHON:python2.7} py33: {env:TOXPYTHON:python3.3} py34: {env:TOXPYTHON:python3.4} py35: {env:TOXPYTHON:python3.5} - {clean,check,report,coveralls,codecov}: python3.5 - bootstrap: python + py36: {env:TOXPYTHON:python3.6} + {bootstrap,clean,check,report,coveralls,codecov}: python3 setenv = PYTHONPATH={toxinidir}/tests PYTHONUNBUFFERED=yes @@ -80,8 +79,6 @@ deps = coveralls skip_install = true commands = - coverage combine - coverage report coveralls [] [testenv:codecov] @@ -89,8 +86,6 @@ deps = codecov skip_install = true commands = - coverage combine - coverage report coverage xml --ignore-errors codecov [] @@ -99,7 +94,7 @@ commands = deps = coverage skip_install = true commands = - coverage combine + coverage combine --append coverage report coverage html |