diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-01-10 12:03:40 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-01-10 18:02:00 -0500 |
commit | 2db54ee92ebd0970f52b271e152a6df9b563693f (patch) | |
tree | 121e32a82892542086ee6418686daef9b9a6a07c /lib/sqlalchemy/exc.py | |
parent | f1706ae317ab5e3b263420e6218696821fbcd878 (diff) | |
download | sqlalchemy-2db54ee92ebd0970f52b271e152a6df9b563693f.tar.gz |
Leave bytestring exception messages as bytestrings
Fixed a regression introduced in version 1.2 where a refactor
of the :class:`.SQLAlchemyError` base exception class introduced an
inappropriate coercion of a plain string message into Unicode under
python 2k, which is not handled by the Python interpreter for characters
outside of the platform's encoding (typically ascii). The
:class:`.SQLAlchemyError` class now passes a bytestring through under
Py2K for ``__str__()`` as is the behavior of exception objects in general
under Py2K, does a safe coercion to unicode utf-8 with
backslash fallback for ``__unicode__()``. For Py3K the message is
typically unicode already, but if not is again safe-coerced with utf-8
with backslash fallback for the ``__str__()`` method.
Fixes: #4429
Change-Id: I2289da3f2c45c7d0041fa43d838958f7614defc3
Diffstat (limited to 'lib/sqlalchemy/exc.py')
-rw-r--r-- | lib/sqlalchemy/exc.py | 43 |
1 files changed, 33 insertions, 10 deletions
diff --git a/lib/sqlalchemy/exc.py b/lib/sqlalchemy/exc.py index e47df85af..cf16f9772 100644 --- a/lib/sqlalchemy/exc.py +++ b/lib/sqlalchemy/exc.py @@ -36,24 +36,47 @@ class SQLAlchemyError(Exception): "http://sqlalche.me/e/%s)" % (self.code,) ) - def _message(self): - # get string representation just like Exception.__str__(self), - # but also support if the string has non-ascii chars + def _message(self, as_unicode=compat.py3k): + # rules: + # + # 1. under py2k, for __str__ return single string arg as it was + # given without converting to unicode. for __unicode__ + # do a conversion but check that it's not unicode already just in + # case + # + # 2. under py3k, single arg string will usually be a unicode + # object, but since __str__() must return unicode, check for + # bytestring just in case + # + # 3. for multiple self.args, this is not a case in current + # SQLAlchemy though this is happening in at least one known external + # library, call str() which does a repr(). + # if len(self.args) == 1: - return compat.text_type(self.args[0]) + text = self.args[0] + if as_unicode and isinstance(text, compat.binary_types): + return compat.decode_backslashreplace(text, "utf-8") + else: + return self.args[0] else: - return compat.text_type(self.args) + # this is not a normal case within SQLAlchemy but is here for + # compatibility with Exception.args - the str() comes out as + # a repr() of the tuple + return str(self.args) - def __str__(self): - message = self._message() + def _sql_message(self, as_unicode): + message = self._message(as_unicode) if self.code: message = "%s %s" % (message, self._code_str()) return message + def __str__(self): + return self._sql_message(compat.py3k) + def __unicode__(self): - return self.__str__() + return self._sql_message(True) class ArgumentError(SQLAlchemyError): @@ -321,10 +344,10 @@ class StatementError(SQLAlchemyError): (self.args[0], self.statement, self.params, self.orig), ) - def __str__(self): + def _sql_message(self, as_unicode): from sqlalchemy.sql import util - details = [self._message()] + details = [self._message(as_unicode=as_unicode)] if self.statement: details.append("[SQL: %r]" % self.statement) if self.params: |