summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2017-12-08 18:08:40 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2017-12-27 10:33:22 -0500
commit064f82986ca3573b124fc88518e99d3d43874b61 (patch)
treee3d4fa7c0983c4a0b36b4b2af2ee9ce4e11c2789 /lib/sqlalchemy
parent1abc8e5500f23e0cfdf4d125d354065dad28aa7a (diff)
downloadsqlalchemy-064f82986ca3573b124fc88518e99d3d43874b61.tar.gz
Implement an error lookup
Add codes to commonly raised error messages and classes that link back to fixed documentation sections giving background on these messages. Change-Id: I78d0660add7026bb662e20305a59283b20616954
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/exc.py91
-rw-r--r--lib/sqlalchemy/orm/exc.py2
-rw-r--r--lib/sqlalchemy/pool.py2
-rw-r--r--lib/sqlalchemy/sql/compiler.py10
4 files changed, 87 insertions, 18 deletions
diff --git a/lib/sqlalchemy/exc.py b/lib/sqlalchemy/exc.py
index 3db3c1085..9a5dc0159 100644
--- a/lib/sqlalchemy/exc.py
+++ b/lib/sqlalchemy/exc.py
@@ -13,10 +13,50 @@ raised as a result of DBAPI exceptions are all subclasses of
"""
+from .util import compat
+
class SQLAlchemyError(Exception):
"""Generic error class."""
+ code = None
+
+ def __init__(self, *arg, **kw):
+ code = kw.pop('code', None)
+ if code is not None:
+ self.code = code
+ super(SQLAlchemyError, self).__init__(*arg, **kw)
+
+ def _code_str(self):
+ if not self.code:
+ return ""
+ else:
+ return (
+ "(Background on this error at: "
+ "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
+ if len(self.args) == 1:
+ return compat.text_type(self.args[0])
+ else:
+ return compat.text_type(self.args)
+
+ def __str__(self):
+ message = self._message()
+
+ if self.code:
+ message = (
+ "%s %s" % (message, self._code_str())
+ )
+
+ return message
+
+ def __unicode__(self):
+ return self.__str__()
+
class ArgumentError(SQLAlchemyError):
"""Raised when an invalid or conflicting function argument is supplied.
@@ -72,12 +112,12 @@ class CircularDependencyError(SQLAlchemyError):
see :ref:`use_alter`.
"""
- def __init__(self, message, cycles, edges, msg=None):
+ def __init__(self, message, cycles, edges, msg=None, code=None):
if msg is None:
message += " (%s)" % ", ".join(repr(s) for s in cycles)
else:
message = msg
- SQLAlchemyError.__init__(self, message)
+ SQLAlchemyError.__init__(self, message, code=code)
self.cycles = cycles
self.edges = edges
@@ -137,6 +177,7 @@ class InvalidatePoolError(DisconnectionError):
"""
invalidate_pool = True
+
class TimeoutError(SQLAlchemyError):
"""Raised when a connection pool times out on getting a connection."""
@@ -258,8 +299,8 @@ class StatementError(SQLAlchemyError):
orig = None
"""The DBAPI exception object."""
- def __init__(self, message, statement, params, orig):
- SQLAlchemyError.__init__(self, message)
+ def __init__(self, message, statement, params, orig, code=None):
+ SQLAlchemyError.__init__(self, message, code=code)
self.statement = statement
self.params = params
self.orig = orig
@@ -275,19 +316,19 @@ class StatementError(SQLAlchemyError):
def __str__(self):
from sqlalchemy.sql import util
- details = [SQLAlchemyError.__str__(self)]
+ details = [self._message()]
if self.statement:
details.append("[SQL: %r]" % self.statement)
if self.params:
params_repr = util._repr_params(self.params, 10)
details.append("[parameters: %r]" % params_repr)
+ code_str = self._code_str()
+ if code_str:
+ details.append(code_str)
return ' '.join([
"(%s)" % det for det in self.detail
] + details)
- def __unicode__(self):
- return self.__str__()
-
class DBAPIError(StatementError):
"""Raised when the execution of a database operation fails.
@@ -312,6 +353,8 @@ class DBAPIError(StatementError):
"""
+ code = 'dbapi'
+
@classmethod
def instance(cls, statement, params,
orig, dbapi_base_err,
@@ -327,7 +370,14 @@ class DBAPIError(StatementError):
if orig is not None:
# not a DBAPI error, statement is present.
# raise a StatementError
- if not isinstance(orig, dbapi_base_err) and statement:
+ if isinstance(orig, SQLAlchemyError) and statement:
+ return StatementError(
+ "(%s.%s) %s" %
+ (orig.__class__.__module__, orig.__class__.__name__,
+ orig.args[0]),
+ statement, params, orig, code=orig.code
+ )
+ elif not isinstance(orig, dbapi_base_err) and statement:
return StatementError(
"(%s.%s) %s" %
(orig.__class__.__module__, orig.__class__.__name__,
@@ -345,13 +395,15 @@ class DBAPIError(StatementError):
cls = glob[name]
break
- return cls(statement, params, orig, connection_invalidated)
+ return cls(statement, params, orig, connection_invalidated,
+ code=cls.code)
def __reduce__(self):
return self.__class__, (self.statement, self.params,
self.orig, self.connection_invalidated)
- def __init__(self, statement, params, orig, connection_invalidated=False):
+ def __init__(self, statement, params, orig, connection_invalidated=False,
+ code=None):
try:
text = str(orig)
except Exception as e:
@@ -362,7 +414,7 @@ class DBAPIError(StatementError):
orig.__class__.__module__, orig.__class__.__name__, text, ),
statement,
params,
- orig
+ orig, code=code
)
self.connection_invalidated = connection_invalidated
@@ -370,34 +422,49 @@ class DBAPIError(StatementError):
class InterfaceError(DBAPIError):
"""Wraps a DB-API InterfaceError."""
+ code = "rvf5"
+
class DatabaseError(DBAPIError):
"""Wraps a DB-API DatabaseError."""
+ code = "4xp6"
+
class DataError(DatabaseError):
"""Wraps a DB-API DataError."""
+ code = "9h9h"
+
class OperationalError(DatabaseError):
"""Wraps a DB-API OperationalError."""
+ code = "e3q8"
+
class IntegrityError(DatabaseError):
"""Wraps a DB-API IntegrityError."""
+ code = "gkpj"
+
class InternalError(DatabaseError):
"""Wraps a DB-API InternalError."""
+ code = "2j85"
+
class ProgrammingError(DatabaseError):
"""Wraps a DB-API ProgrammingError."""
+ code = "f405"
+
class NotSupportedError(DatabaseError):
"""Wraps a DB-API NotSupportedError."""
+ code = "tw8g"
# Warnings
diff --git a/lib/sqlalchemy/orm/exc.py b/lib/sqlalchemy/orm/exc.py
index bd63a1b5a..41624c38d 100644
--- a/lib/sqlalchemy/orm/exc.py
+++ b/lib/sqlalchemy/orm/exc.py
@@ -60,6 +60,8 @@ class DetachedInstanceError(sa_exc.SQLAlchemyError):
"""An attempt to access unloaded attributes on a
mapped instance that is detached."""
+ code = "bhk3"
+
class UnmappedInstanceError(UnmappedError):
"""An mapping operation was requested for an unknown instance."""
diff --git a/lib/sqlalchemy/pool.py b/lib/sqlalchemy/pool.py
index ef49ffd60..71d090839 100644
--- a/lib/sqlalchemy/pool.py
+++ b/lib/sqlalchemy/pool.py
@@ -1176,7 +1176,7 @@ class QueuePool(Pool):
raise exc.TimeoutError(
"QueuePool limit of size %d overflow %d reached, "
"connection timed out, timeout %d" %
- (self.size(), self.overflow(), self._timeout))
+ (self.size(), self.overflow(), self._timeout), code="3o7r")
if self._inc_overflow():
try:
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index 9ed75ca06..cb058affa 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -271,7 +271,7 @@ class Compiled(object):
if e is None:
raise exc.UnboundExecutionError(
"This Compiled object is not bound to any Engine "
- "or Connection.")
+ "or Connection.", code="2afi")
return e._execute_compiled(self, multiparams, params)
def scalar(self, *multiparams, **params):
@@ -540,11 +540,11 @@ class SQLCompiler(Compiled):
raise exc.InvalidRequestError(
"A value is required for bind parameter %r, "
"in parameter group %d" %
- (bindparam.key, _group_number))
+ (bindparam.key, _group_number), code="cd3x")
else:
raise exc.InvalidRequestError(
"A value is required for bind parameter %r"
- % bindparam.key)
+ % bindparam.key, code="cd3x")
elif bindparam.callable:
pd[name] = bindparam.effective_value
@@ -559,11 +559,11 @@ class SQLCompiler(Compiled):
raise exc.InvalidRequestError(
"A value is required for bind parameter %r, "
"in parameter group %d" %
- (bindparam.key, _group_number))
+ (bindparam.key, _group_number), code="cd3x")
else:
raise exc.InvalidRequestError(
"A value is required for bind parameter %r"
- % bindparam.key)
+ % bindparam.key, code="cd3x")
if bindparam.callable:
pd[self.bind_names[bindparam]] = bindparam.effective_value