diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2020-02-29 14:40:45 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2020-03-02 17:24:19 -0500 |
commit | 57dc36a01b2b334a996f73f6a78b3bfbe4d9f2ec (patch) | |
tree | 77cbb0199ca91be3b0816e3a5bd4c217e36a7d1b /lib/sqlalchemy/sql/elements.py | |
parent | 649de79950dcf952d7a44069faf36925c23c4e63 (diff) | |
download | sqlalchemy-57dc36a01b2b334a996f73f6a78b3bfbe4d9f2ec.tar.gz |
Ensure all nested exception throws have a cause
Applied an explicit "cause" to most if not all internally raised exceptions
that are raised from within an internal exception catch, to avoid
misleading stacktraces that suggest an error within the handling of an
exception. While it would be preferable to suppress the internally caught
exception in the way that the ``__suppress_context__`` attribute would,
there does not as yet seem to be a way to do this without suppressing an
enclosing user constructed context, so for now it exposes the internally
caught exception as the cause so that full information about the context
of the error is maintained.
Fixes: #4849
Change-Id: I55a86b29023675d9e5e49bc7edc5a2dc0bcd4751
Diffstat (limited to 'lib/sqlalchemy/sql/elements.py')
-rw-r--r-- | lib/sqlalchemy/sql/elements.py | 66 |
1 files changed, 44 insertions, 22 deletions
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index df690c383..d0babb1be 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -747,10 +747,13 @@ class ColumnElement( def comparator(self): try: comparator_factory = self.type.comparator_factory - except AttributeError: - raise TypeError( - "Object %r associated with '.type' attribute " - "is not a TypeEngine class or object" % self.type + except AttributeError as err: + util.raise_( + TypeError( + "Object %r associated with '.type' attribute " + "is not a TypeEngine class or object" % self.type + ), + replace_context=err, ) else: return comparator_factory(self) @@ -758,10 +761,17 @@ class ColumnElement( def __getattr__(self, key): try: return getattr(self.comparator, key) - except AttributeError: - raise AttributeError( - "Neither %r object nor %r object has an attribute %r" - % (type(self).__name__, type(self.comparator).__name__, key) + except AttributeError as err: + util.raise_( + AttributeError( + "Neither %r object nor %r object has an attribute %r" + % ( + type(self).__name__, + type(self.comparator).__name__, + key, + ) + ), + replace_context=err, ) def operate(self, op, *other, **kwargs): @@ -1742,10 +1752,13 @@ class TextClause( # a unique/anonymous key in any case, so use the _orig_key # so that a text() construct can support unique parameters existing = new_params[bind._orig_key] - except KeyError: - raise exc.ArgumentError( - "This text() construct doesn't define a " - "bound parameter named %r" % bind._orig_key + except KeyError as err: + util.raise_( + exc.ArgumentError( + "This text() construct doesn't define a " + "bound parameter named %r" % bind._orig_key + ), + replace_context=err, ) else: new_params[existing._orig_key] = bind @@ -1753,10 +1766,13 @@ class TextClause( for key, value in names_to_values.items(): try: existing = new_params[key] - except KeyError: - raise exc.ArgumentError( - "This text() construct doesn't define a " - "bound parameter named %r" % key + except KeyError as err: + util.raise_( + exc.ArgumentError( + "This text() construct doesn't define a " + "bound parameter named %r" % key + ), + replace_context=err, ) else: new_params[key] = existing._with_value(value) @@ -3665,9 +3681,12 @@ class Over(ColumnElement): else: try: lower = int(range_[0]) - except ValueError: - raise exc.ArgumentError( - "Integer or None expected for range value" + except ValueError as err: + util.raise_( + exc.ArgumentError( + "Integer or None expected for range value" + ), + replace_context=err, ) else: if lower == 0: @@ -3678,9 +3697,12 @@ class Over(ColumnElement): else: try: upper = int(range_[1]) - except ValueError: - raise exc.ArgumentError( - "Integer or None expected for range value" + except ValueError as err: + util.raise_( + exc.ArgumentError( + "Integer or None expected for range value" + ), + replace_context=err, ) else: if upper == 0: |