diff options
| author | mike bayer <mike_mp@zzzcomputing.com> | 2020-03-02 23:45:35 +0000 |
|---|---|---|
| committer | Gerrit Code Review <gerrit@bbpush.zzzcomputing.com> | 2020-03-02 23:45:35 +0000 |
| commit | b5050beb73b2e50b122c36e7dcdc06abffd472f2 (patch) | |
| tree | 6679019ff418d6c346d5bd4cdc4aab4a73d9303e /lib/sqlalchemy/util | |
| parent | 2d052d43518a0f4d9751db7e699cfebd3724c1e5 (diff) | |
| parent | 57dc36a01b2b334a996f73f6a78b3bfbe4d9f2ec (diff) | |
| download | sqlalchemy-b5050beb73b2e50b122c36e7dcdc06abffd472f2.tar.gz | |
Merge "Ensure all nested exception throws have a cause"
Diffstat (limited to 'lib/sqlalchemy/util')
| -rw-r--r-- | lib/sqlalchemy/util/__init__.py | 1 | ||||
| -rw-r--r-- | lib/sqlalchemy/util/compat.py | 63 | ||||
| -rw-r--r-- | lib/sqlalchemy/util/langhelpers.py | 6 |
3 files changed, 55 insertions, 15 deletions
diff --git a/lib/sqlalchemy/util/__init__.py b/lib/sqlalchemy/util/__init__.py index b4610a1b0..819d18018 100644 --- a/lib/sqlalchemy/util/__init__.py +++ b/lib/sqlalchemy/util/__init__.py @@ -67,6 +67,7 @@ from .compat import py33 # noqa from .compat import py36 # noqa from .compat import py3k # noqa from .compat import quote_plus # noqa +from .compat import raise_ # noqa from .compat import raise_from_cause # noqa from .compat import reduce # noqa from .compat import reraise # noqa diff --git a/lib/sqlalchemy/util/compat.py b/lib/sqlalchemy/util/compat.py index 104e8e03d..31654b97c 100644 --- a/lib/sqlalchemy/util/compat.py +++ b/lib/sqlalchemy/util/compat.py @@ -147,13 +147,42 @@ if py3k: def cmp(a, b): return (a > b) - (a < b) - def reraise(tp, value, tb=None, cause=None): - if cause is not None: - assert cause is not value, "Same cause emitted" - value.__cause__ = cause - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value + def raise_( + exception, with_traceback=None, replace_context=None, from_=False + ): + r"""implement "raise" with cause support. + + :param exception: exception to raise + :param with_traceback: will call exception.with_traceback() + :param replace_context: an as-yet-unsupported feature. This is + an exception object which we are "replacing", e.g., it's our + "cause" but we don't want it printed. Basically just what + ``__suppress_context__`` does but we don't want to suppress + the enclosing context, if any. So for now we make it the + cause. + :param from\_: the cause. this actually sets the cause and doesn't + hope to hide it someday. + + """ + if with_traceback is not None: + exception = exception.with_traceback(with_traceback) + + if from_ is not False: + exception.__cause__ = from_ + elif replace_context is not None: + # no good solution here, we would like to have the exception + # have only the context of replace_context.__context__ so that the + # intermediary exception does not change, but we can't figure + # that out. + exception.__cause__ = replace_context + + try: + raise exception + finally: + # credit to + # https://cosmicpercolator.com/2016/01/13/exception-leaks-in-python-2-and-3/ + # as the __traceback__ object creates a cycle + del exception, replace_context, from_, with_traceback def u(s): return s @@ -257,13 +286,13 @@ else: else: return text - # not as nice as that of Py3K, but at least preserves - # the code line where the issue occurred exec( - "def reraise(tp, value, tb=None, cause=None):\n" - " if cause is not None:\n" - " assert cause is not value, 'Same cause emitted'\n" - " raise tp, value, tb\n" + "def raise_(exception, with_traceback=None, replace_context=None, " + "from_=False):\n" + " if with_traceback:\n" + " raise type(exception), exception, with_traceback\n" + " else:\n" + " raise exception\n" ) TYPE_CHECKING = False @@ -370,6 +399,8 @@ else: def raise_from_cause(exception, exc_info=None): + r"""legacy. use raise\_()""" + if exc_info is None: exc_info = sys.exc_info() exc_type, exc_value, exc_tb = exc_info @@ -377,6 +408,12 @@ def raise_from_cause(exception, exc_info=None): reraise(type(exception), exception, tb=exc_tb, cause=cause) +def reraise(tp, value, tb=None, cause=None): + r"""legacy. use raise\_()""" + + raise_(value, with_traceback=tb, from_=cause) + + def with_metaclass(meta, *bases): """Create a base class with a metaclass. diff --git a/lib/sqlalchemy/util/langhelpers.py b/lib/sqlalchemy/util/langhelpers.py index 41a9698c7..09aa94bf2 100644 --- a/lib/sqlalchemy/util/langhelpers.py +++ b/lib/sqlalchemy/util/langhelpers.py @@ -65,7 +65,9 @@ class safe_reraise(object): exc_type, exc_value, exc_tb = self._exc_info self._exc_info = None # remove potential circular references if not self.warn_only: - compat.reraise(exc_type, exc_value, exc_tb) + compat.raise_( + exc_value, with_traceback=exc_tb, + ) else: if not compat.py3k and self._exc_info and self._exc_info[1]: # emulate Py3K's behavior of telling us when an exception @@ -76,7 +78,7 @@ class safe_reraise(object): "is:\n %s %s\n" % (self._exc_info[0], self._exc_info[1]) ) self._exc_info = None # remove potential circular references - compat.reraise(type_, value, traceback) + compat.raise_(value, with_traceback=traceback) def string_or_unprintable(element): |
