Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy/exc.py: 70%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# exc.py
2# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: https://www.opensource.org/licenses/mit-license.php
8"""Exceptions used with SQLAlchemy.
10The base exception class is :exc:`.SQLAlchemyError`. Exceptions which are
11raised as a result of DBAPI exceptions are all subclasses of
12:exc:`.DBAPIError`.
14"""
16from __future__ import annotations
18import typing
19from typing import Any
20from typing import List
21from typing import Optional
22from typing import overload
23from typing import Tuple
24from typing import Type
25from typing import Union
27from .util import compat
28from .util import preloaded as _preloaded
30if typing.TYPE_CHECKING:
31 from .engine.interfaces import _AnyExecuteParams
32 from .engine.interfaces import Dialect
33 from .sql.compiler import Compiled
34 from .sql.compiler import TypeCompiler
35 from .sql.elements import ClauseElement
37if typing.TYPE_CHECKING:
38 _version_token: str
39else:
40 # set by __init__.py
41 _version_token = None
44class HasDescriptionCode:
45 """helper which adds 'code' as an attribute and '_code_str' as a method"""
47 code: Optional[str] = None
49 def __init__(self, *arg: Any, **kw: Any):
50 code = kw.pop("code", None)
51 if code is not None:
52 self.code = code
53 super().__init__(*arg, **kw)
55 _what_are_we = "error"
57 def _code_str(self) -> str:
58 if not self.code:
59 return ""
60 else:
61 return (
62 f"(Background on this {self._what_are_we} at: "
63 f"https://sqlalche.me/e/{_version_token}/{self.code})"
64 )
66 def __str__(self) -> str:
67 message = super().__str__()
68 if self.code:
69 message = "%s %s" % (message, self._code_str())
70 return message
73class SQLAlchemyError(HasDescriptionCode, Exception):
74 """Generic error class."""
76 def _message(self) -> str:
77 # rules:
78 #
79 # 1. single arg string will usually be a unicode
80 # object, but since __str__() must return unicode, check for
81 # bytestring just in case
82 #
83 # 2. for multiple self.args, this is not a case in current
84 # SQLAlchemy though this is happening in at least one known external
85 # library, call str() which does a repr().
86 #
87 text: str
89 if len(self.args) == 1:
90 arg_text = self.args[0]
92 if isinstance(arg_text, bytes):
93 text = compat.decode_backslashreplace(arg_text, "utf-8")
94 # This is for when the argument is not a string of any sort.
95 # Otherwise, converting this exception to string would fail for
96 # non-string arguments.
97 else:
98 text = str(arg_text)
100 return text
101 else:
102 # this is not a normal case within SQLAlchemy but is here for
103 # compatibility with Exception.args - the str() comes out as
104 # a repr() of the tuple
105 return str(self.args)
107 def _sql_message(self) -> str:
108 message = self._message()
110 if self.code:
111 message = "%s %s" % (message, self._code_str())
113 return message
115 def __str__(self) -> str:
116 return self._sql_message()
119class ArgumentError(SQLAlchemyError):
120 """Raised when an invalid or conflicting function argument is supplied.
122 This error generally corresponds to construction time state errors.
124 """
127class DuplicateColumnError(ArgumentError):
128 """a Column is being added to a Table that would replace another
129 Column, without appropriate parameters to allow this in place.
131 .. versionadded:: 2.0.0b4
133 """
136class ObjectNotExecutableError(ArgumentError):
137 """Raised when an object is passed to .execute() that can't be
138 executed as SQL.
140 """
142 def __init__(self, target: Any):
143 super().__init__("Not an executable object: %r" % target)
144 self.target = target
146 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
147 return self.__class__, (self.target,)
150class NoSuchModuleError(ArgumentError):
151 """Raised when a dynamically-loaded module (usually a database dialect)
152 of a particular name cannot be located."""
155class NoForeignKeysError(ArgumentError):
156 """Raised when no foreign keys can be located between two selectables
157 during a join."""
160class AmbiguousForeignKeysError(ArgumentError):
161 """Raised when more than one foreign key matching can be located
162 between two selectables during a join."""
165class ConstraintColumnNotFoundError(ArgumentError):
166 """raised when a constraint refers to a string column name that
167 is not present in the table being constrained.
169 .. versionadded:: 2.0
171 """
174class CircularDependencyError(SQLAlchemyError):
175 """Raised by topological sorts when a circular dependency is detected.
177 There are two scenarios where this error occurs:
179 * In a Session flush operation, if two objects are mutually dependent
180 on each other, they can not be inserted or deleted via INSERT or
181 DELETE statements alone; an UPDATE will be needed to post-associate
182 or pre-deassociate one of the foreign key constrained values.
183 The ``post_update`` flag described at :ref:`post_update` can resolve
184 this cycle.
185 * In a :attr:`_schema.MetaData.sorted_tables` operation, two
186 :class:`_schema.ForeignKey`
187 or :class:`_schema.ForeignKeyConstraint` objects mutually refer to each
188 other. Apply the ``use_alter=True`` flag to one or both,
189 see :ref:`use_alter`.
191 """
193 def __init__(
194 self,
195 message: str,
196 cycles: Any,
197 edges: Any,
198 msg: Optional[str] = None,
199 code: Optional[str] = None,
200 ):
201 if msg is None:
202 message += " (%s)" % ", ".join(repr(s) for s in cycles)
203 else:
204 message = msg
205 SQLAlchemyError.__init__(self, message, code=code)
206 self.cycles = cycles
207 self.edges = edges
209 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
210 return (
211 self.__class__,
212 (None, self.cycles, self.edges, self.args[0]),
213 {"code": self.code} if self.code is not None else {},
214 )
217class CompileError(SQLAlchemyError):
218 """Raised when an error occurs during SQL compilation"""
221class UnsupportedCompilationError(CompileError):
222 """Raised when an operation is not supported by the given compiler.
224 .. seealso::
226 :ref:`faq_sql_expression_string`
228 :ref:`error_l7de`
229 """
231 code = "l7de"
233 def __init__(
234 self,
235 compiler: Union[Compiled, TypeCompiler],
236 element_type: Type[ClauseElement],
237 message: Optional[str] = None,
238 ):
239 super().__init__(
240 "Compiler %r can't render element of type %s%s"
241 % (compiler, element_type, ": %s" % message if message else "")
242 )
243 self.compiler = compiler
244 self.element_type = element_type
245 self.message = message
247 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
248 return self.__class__, (self.compiler, self.element_type, self.message)
251class IdentifierError(SQLAlchemyError):
252 """Raised when a schema name is beyond the max character limit"""
255class DisconnectionError(SQLAlchemyError):
256 """A disconnect is detected on a raw DB-API connection.
258 This error is raised and consumed internally by a connection pool. It can
259 be raised by the :meth:`_events.PoolEvents.checkout`
260 event so that the host pool
261 forces a retry; the exception will be caught three times in a row before
262 the pool gives up and raises :class:`~sqlalchemy.exc.InvalidRequestError`
263 regarding the connection attempt.
265 """
267 invalidate_pool: bool = False
270class InvalidatePoolError(DisconnectionError):
271 """Raised when the connection pool should invalidate all stale connections.
273 A subclass of :class:`_exc.DisconnectionError` that indicates that the
274 disconnect situation encountered on the connection probably means the
275 entire pool should be invalidated, as the database has been restarted.
277 This exception will be handled otherwise the same way as
278 :class:`_exc.DisconnectionError`, allowing three attempts to reconnect
279 before giving up.
281 .. versionadded:: 1.2
283 """
285 invalidate_pool: bool = True
288class TimeoutError(SQLAlchemyError): # noqa
289 """Raised when a connection pool times out on getting a connection."""
292class InvalidRequestError(SQLAlchemyError):
293 """SQLAlchemy was asked to do something it can't do.
295 This error generally corresponds to runtime state errors.
297 """
300class IllegalStateChangeError(InvalidRequestError):
301 """An object that tracks state encountered an illegal state change
302 of some kind.
304 .. versionadded:: 2.0
306 """
309class NoInspectionAvailable(InvalidRequestError):
310 """A subject passed to :func:`sqlalchemy.inspection.inspect` produced
311 no context for inspection."""
314class PendingRollbackError(InvalidRequestError):
315 """A transaction has failed and needs to be rolled back before
316 continuing.
318 .. versionadded:: 1.4
320 """
323class ResourceClosedError(InvalidRequestError):
324 """An operation was requested from a connection, cursor, or other
325 object that's in a closed state."""
328class NoSuchColumnError(InvalidRequestError, KeyError):
329 """A nonexistent column is requested from a ``Row``."""
332class NoResultFound(InvalidRequestError):
333 """A database result was required but none was found.
336 .. versionchanged:: 1.4 This exception is now part of the
337 ``sqlalchemy.exc`` module in Core, moved from the ORM. The symbol
338 remains importable from ``sqlalchemy.orm.exc``.
341 """
344class MultipleResultsFound(InvalidRequestError):
345 """A single database result was required but more than one were found.
347 .. versionchanged:: 1.4 This exception is now part of the
348 ``sqlalchemy.exc`` module in Core, moved from the ORM. The symbol
349 remains importable from ``sqlalchemy.orm.exc``.
352 """
355class NoReferenceError(InvalidRequestError):
356 """Raised by ``ForeignKey`` to indicate a reference cannot be resolved."""
358 table_name: str
361class AwaitRequired(InvalidRequestError):
362 """Error raised by the async greenlet spawn if no async operation
363 was awaited when it required one.
365 """
367 code = "xd1r"
370class MissingGreenlet(InvalidRequestError):
371 r"""Error raised by the async greenlet await\_ if called while not inside
372 the greenlet spawn context.
374 """
376 code = "xd2s"
379class NoReferencedTableError(NoReferenceError):
380 """Raised by ``ForeignKey`` when the referred ``Table`` cannot be
381 located.
383 """
385 def __init__(self, message: str, tname: str):
386 NoReferenceError.__init__(self, message)
387 self.table_name = tname
389 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
390 return self.__class__, (self.args[0], self.table_name)
393class NoReferencedColumnError(NoReferenceError):
394 """Raised by ``ForeignKey`` when the referred ``Column`` cannot be
395 located.
397 """
399 def __init__(self, message: str, tname: str, cname: str):
400 NoReferenceError.__init__(self, message)
401 self.table_name = tname
402 self.column_name = cname
404 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
405 return (
406 self.__class__,
407 (self.args[0], self.table_name, self.column_name),
408 )
411class NoSuchTableError(InvalidRequestError):
412 """Table does not exist or is not visible to a connection."""
415class UnreflectableTableError(InvalidRequestError):
416 """Table exists but can't be reflected for some reason.
418 .. versionadded:: 1.2
420 """
423class UnboundExecutionError(InvalidRequestError):
424 """SQL was attempted without a database connection to execute it on."""
427class DontWrapMixin:
428 """A mixin class which, when applied to a user-defined Exception class,
429 will not be wrapped inside of :exc:`.StatementError` if the error is
430 emitted within the process of executing a statement.
432 E.g.::
434 from sqlalchemy.exc import DontWrapMixin
437 class MyCustomException(Exception, DontWrapMixin):
438 pass
441 class MySpecialType(TypeDecorator):
442 impl = String
444 def process_bind_param(self, value, dialect):
445 if value == "invalid":
446 raise MyCustomException("invalid!")
448 """
451class StatementError(SQLAlchemyError):
452 """An error occurred during execution of a SQL statement.
454 :class:`StatementError` wraps the exception raised
455 during execution, and features :attr:`.statement`
456 and :attr:`.params` attributes which supply context regarding
457 the specifics of the statement which had an issue.
459 The wrapped exception object is available in
460 the :attr:`.orig` attribute.
462 """
464 statement: Optional[str] = None
465 """The string SQL statement being invoked when this exception occurred."""
467 params: Optional[_AnyExecuteParams] = None
468 """The parameter list being used when this exception occurred."""
470 orig: Optional[BaseException] = None
471 """The original exception that was thrown.
473 """
475 ismulti: Optional[bool] = None
476 """multi parameter passed to repr_params(). None is meaningful."""
478 connection_invalidated: bool = False
480 def __init__(
481 self,
482 message: str,
483 statement: Optional[str],
484 params: Optional[_AnyExecuteParams],
485 orig: Optional[BaseException],
486 hide_parameters: bool = False,
487 code: Optional[str] = None,
488 ismulti: Optional[bool] = None,
489 ):
490 SQLAlchemyError.__init__(self, message, code=code)
491 self.statement = statement
492 self.params = params
493 self.orig = orig
494 self.ismulti = ismulti
495 self.hide_parameters = hide_parameters
496 self.detail: List[str] = []
498 def add_detail(self, msg: str) -> None:
499 self.detail.append(msg)
501 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
502 return (
503 self.__class__,
504 (
505 self.args[0],
506 self.statement,
507 self.params,
508 self.orig,
509 self.hide_parameters,
510 self.__dict__.get("code"),
511 self.ismulti,
512 ),
513 {"detail": self.detail},
514 )
516 @_preloaded.preload_module("sqlalchemy.sql.util")
517 def _sql_message(self) -> str:
518 util = _preloaded.sql_util
520 details = [self._message()]
521 if self.statement:
522 stmt_detail = "[SQL: %s]" % self.statement
523 details.append(stmt_detail)
524 if self.params:
525 if self.hide_parameters:
526 details.append(
527 "[SQL parameters hidden due to hide_parameters=True]"
528 )
529 else:
530 params_repr = util._repr_params(
531 self.params, 10, ismulti=self.ismulti
532 )
533 details.append("[parameters: %r]" % params_repr)
534 code_str = self._code_str()
535 if code_str:
536 details.append(code_str)
537 return "\n".join(["(%s)" % det for det in self.detail] + details)
540class DBAPIError(StatementError):
541 """Raised when the execution of a database operation fails.
543 Wraps exceptions raised by the DB-API underlying the
544 database operation. Driver-specific implementations of the standard
545 DB-API exception types are wrapped by matching sub-types of SQLAlchemy's
546 :class:`DBAPIError` when possible. DB-API's ``Error`` type maps to
547 :class:`DBAPIError` in SQLAlchemy, otherwise the names are identical. Note
548 that there is no guarantee that different DB-API implementations will
549 raise the same exception type for any given error condition.
551 :class:`DBAPIError` features :attr:`~.StatementError.statement`
552 and :attr:`~.StatementError.params` attributes which supply context
553 regarding the specifics of the statement which had an issue, for the
554 typical case when the error was raised within the context of
555 emitting a SQL statement.
557 The wrapped exception object is available in the
558 :attr:`~.StatementError.orig` attribute. Its type and properties are
559 DB-API implementation specific.
561 """
563 code = "dbapi"
565 @overload
566 @classmethod
567 def instance(
568 cls,
569 statement: Optional[str],
570 params: Optional[_AnyExecuteParams],
571 orig: Exception,
572 dbapi_base_err: Type[Exception],
573 hide_parameters: bool = False,
574 connection_invalidated: bool = False,
575 dialect: Optional[Dialect] = None,
576 ismulti: Optional[bool] = None,
577 ) -> StatementError: ...
579 @overload
580 @classmethod
581 def instance(
582 cls,
583 statement: Optional[str],
584 params: Optional[_AnyExecuteParams],
585 orig: DontWrapMixin,
586 dbapi_base_err: Type[Exception],
587 hide_parameters: bool = False,
588 connection_invalidated: bool = False,
589 dialect: Optional[Dialect] = None,
590 ismulti: Optional[bool] = None,
591 ) -> DontWrapMixin: ...
593 @overload
594 @classmethod
595 def instance(
596 cls,
597 statement: Optional[str],
598 params: Optional[_AnyExecuteParams],
599 orig: BaseException,
600 dbapi_base_err: Type[Exception],
601 hide_parameters: bool = False,
602 connection_invalidated: bool = False,
603 dialect: Optional[Dialect] = None,
604 ismulti: Optional[bool] = None,
605 ) -> BaseException: ...
607 @classmethod
608 def instance(
609 cls,
610 statement: Optional[str],
611 params: Optional[_AnyExecuteParams],
612 orig: Union[BaseException, DontWrapMixin],
613 dbapi_base_err: Type[Exception],
614 hide_parameters: bool = False,
615 connection_invalidated: bool = False,
616 dialect: Optional[Dialect] = None,
617 ismulti: Optional[bool] = None,
618 ) -> Union[BaseException, DontWrapMixin]:
619 # Don't ever wrap these, just return them directly as if
620 # DBAPIError didn't exist.
621 if (
622 isinstance(orig, BaseException) and not isinstance(orig, Exception)
623 ) or isinstance(orig, DontWrapMixin):
624 return orig
626 if orig is not None:
627 # not a DBAPI error, statement is present.
628 # raise a StatementError
629 if isinstance(orig, SQLAlchemyError) and statement:
630 return StatementError(
631 "(%s.%s) %s"
632 % (
633 orig.__class__.__module__,
634 orig.__class__.__name__,
635 orig.args[0],
636 ),
637 statement,
638 params,
639 orig,
640 hide_parameters=hide_parameters,
641 code=orig.code,
642 ismulti=ismulti,
643 )
644 elif not isinstance(orig, dbapi_base_err) and statement:
645 return StatementError(
646 "(%s.%s) %s"
647 % (
648 orig.__class__.__module__,
649 orig.__class__.__name__,
650 orig,
651 ),
652 statement,
653 params,
654 orig,
655 hide_parameters=hide_parameters,
656 ismulti=ismulti,
657 )
659 glob = globals()
660 for super_ in orig.__class__.__mro__:
661 name = super_.__name__
662 if dialect:
663 name = dialect.dbapi_exception_translation_map.get(
664 name, name
665 )
666 if name in glob and issubclass(glob[name], DBAPIError):
667 cls = glob[name]
668 break
670 return cls(
671 statement,
672 params,
673 orig,
674 connection_invalidated=connection_invalidated,
675 hide_parameters=hide_parameters,
676 code=cls.code,
677 ismulti=ismulti,
678 )
680 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
681 return (
682 self.__class__,
683 (
684 self.statement,
685 self.params,
686 self.orig,
687 self.hide_parameters,
688 self.connection_invalidated,
689 self.__dict__.get("code"),
690 self.ismulti,
691 ),
692 {"detail": self.detail},
693 )
695 def __init__(
696 self,
697 statement: Optional[str],
698 params: Optional[_AnyExecuteParams],
699 orig: BaseException,
700 hide_parameters: bool = False,
701 connection_invalidated: bool = False,
702 code: Optional[str] = None,
703 ismulti: Optional[bool] = None,
704 ):
705 try:
706 text = str(orig)
707 except Exception as e:
708 text = "Error in str() of DB-API-generated exception: " + str(e)
709 StatementError.__init__(
710 self,
711 "(%s.%s) %s"
712 % (orig.__class__.__module__, orig.__class__.__name__, text),
713 statement,
714 params,
715 orig,
716 hide_parameters,
717 code=code,
718 ismulti=ismulti,
719 )
720 self.connection_invalidated = connection_invalidated
723class InterfaceError(DBAPIError):
724 """Wraps a DB-API InterfaceError."""
726 code = "rvf5"
729class DatabaseError(DBAPIError):
730 """Wraps a DB-API DatabaseError."""
732 code = "4xp6"
735class DataError(DatabaseError):
736 """Wraps a DB-API DataError."""
738 code = "9h9h"
741class OperationalError(DatabaseError):
742 """Wraps a DB-API OperationalError."""
744 code = "e3q8"
747class IntegrityError(DatabaseError):
748 """Wraps a DB-API IntegrityError."""
750 code = "gkpj"
753class InternalError(DatabaseError):
754 """Wraps a DB-API InternalError."""
756 code = "2j85"
759class ProgrammingError(DatabaseError):
760 """Wraps a DB-API ProgrammingError."""
762 code = "f405"
765class NotSupportedError(DatabaseError):
766 """Wraps a DB-API NotSupportedError."""
768 code = "tw8g"
771# Warnings
774class SATestSuiteWarning(Warning):
775 """warning for a condition detected during tests that is non-fatal
777 Currently outside of SAWarning so that we can work around tools like
778 Alembic doing the wrong thing with warnings.
780 """
783class SADeprecationWarning(HasDescriptionCode, DeprecationWarning):
784 """Issued for usage of deprecated APIs."""
786 deprecated_since: Optional[str] = None
787 "Indicates the version that started raising this deprecation warning"
790class Base20DeprecationWarning(SADeprecationWarning):
791 """Issued for usage of APIs specifically deprecated or legacy in
792 SQLAlchemy 2.0.
794 .. seealso::
796 :ref:`error_b8d9`.
798 :ref:`deprecation_20_mode`
800 """
802 deprecated_since: Optional[str] = "1.4"
803 "Indicates the version that started raising this deprecation warning"
805 def __str__(self) -> str:
806 return (
807 super().__str__()
808 + " (Background on SQLAlchemy 2.0 at: https://sqlalche.me/e/b8d9)"
809 )
812class LegacyAPIWarning(Base20DeprecationWarning):
813 """indicates an API that is in 'legacy' status, a long term deprecation."""
816class MovedIn20Warning(Base20DeprecationWarning):
817 """Subtype of RemovedIn20Warning to indicate an API that moved only."""
820class SAPendingDeprecationWarning(PendingDeprecationWarning):
821 """A similar warning as :class:`_exc.SADeprecationWarning`, this warning
822 is not used in modern versions of SQLAlchemy.
824 """
826 deprecated_since: Optional[str] = None
827 "Indicates the version that started raising this deprecation warning"
830class SAWarning(HasDescriptionCode, RuntimeWarning):
831 """Issued at runtime."""
833 _what_are_we = "warning"