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-2025 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"""
15from __future__ import annotations
17import typing
18from typing import Any
19from typing import List
20from typing import Optional
21from typing import overload
22from typing import Tuple
23from typing import Type
24from typing import Union
26from .util import compat
27from .util import preloaded as _preloaded
29if typing.TYPE_CHECKING:
30 from .engine.interfaces import _AnyExecuteParams
31 from .engine.interfaces import Dialect
32 from .sql.compiler import Compiled
33 from .sql.compiler import TypeCompiler
34 from .sql.elements import ClauseElement
36if typing.TYPE_CHECKING:
37 _version_token: str
38else:
39 # set by __init__.py
40 _version_token = None
43class HasDescriptionCode:
44 """helper which adds 'code' as an attribute and '_code_str' as a method"""
46 code: Optional[str] = None
48 def __init__(self, *arg: Any, **kw: Any):
49 code = kw.pop("code", None)
50 if code is not None:
51 self.code = code
52 super().__init__(*arg, **kw)
54 _what_are_we = "error"
56 def _code_str(self) -> str:
57 if not self.code:
58 return ""
59 else:
60 return (
61 f"(Background on this {self._what_are_we} at: "
62 f"https://sqlalche.me/e/{_version_token}/{self.code})"
63 )
65 def __str__(self) -> str:
66 message = super().__str__()
67 if self.code:
68 message = "%s %s" % (message, self._code_str())
69 return message
72class SQLAlchemyError(HasDescriptionCode, Exception):
73 """Generic error class."""
75 def _message(self) -> str:
76 # rules:
77 #
78 # 1. single arg string will usually be a unicode
79 # object, but since __str__() must return unicode, check for
80 # bytestring just in case
81 #
82 # 2. for multiple self.args, this is not a case in current
83 # SQLAlchemy though this is happening in at least one known external
84 # library, call str() which does a repr().
85 #
86 text: str
88 if len(self.args) == 1:
89 arg_text = self.args[0]
91 if isinstance(arg_text, bytes):
92 text = compat.decode_backslashreplace(arg_text, "utf-8")
93 # This is for when the argument is not a string of any sort.
94 # Otherwise, converting this exception to string would fail for
95 # non-string arguments.
96 else:
97 text = str(arg_text)
99 return text
100 else:
101 # this is not a normal case within SQLAlchemy but is here for
102 # compatibility with Exception.args - the str() comes out as
103 # a repr() of the tuple
104 return str(self.args)
106 def _sql_message(self) -> str:
107 message = self._message()
109 if self.code:
110 message = "%s %s" % (message, self._code_str())
112 return message
114 def __str__(self) -> str:
115 return self._sql_message()
118class ArgumentError(SQLAlchemyError):
119 """Raised when an invalid or conflicting function argument is supplied.
121 This error generally corresponds to construction time state errors.
123 """
126class DuplicateColumnError(ArgumentError):
127 """a Column is being added to a Table that would replace another
128 Column, without appropriate parameters to allow this in place.
130 .. versionadded:: 2.0.0b4
132 """
135class ObjectNotExecutableError(ArgumentError):
136 """Raised when an object is passed to .execute() that can't be
137 executed as SQL.
139 """
141 def __init__(self, target: Any):
142 super().__init__("Not an executable object: %r" % target)
143 self.target = target
145 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
146 return self.__class__, (self.target,)
149class NoSuchModuleError(ArgumentError):
150 """Raised when a dynamically-loaded module (usually a database dialect)
151 of a particular name cannot be located."""
154class NoForeignKeysError(ArgumentError):
155 """Raised when no foreign keys can be located between two selectables
156 during a join."""
159class AmbiguousForeignKeysError(ArgumentError):
160 """Raised when more than one foreign key matching can be located
161 between two selectables during a join."""
164class ConstraintColumnNotFoundError(ArgumentError):
165 """raised when a constraint refers to a string column name that
166 is not present in the table being constrained.
168 .. versionadded:: 2.0
170 """
173class CircularDependencyError(SQLAlchemyError):
174 """Raised by topological sorts when a circular dependency is detected.
176 There are two scenarios where this error occurs:
178 * In a Session flush operation, if two objects are mutually dependent
179 on each other, they can not be inserted or deleted via INSERT or
180 DELETE statements alone; an UPDATE will be needed to post-associate
181 or pre-deassociate one of the foreign key constrained values.
182 The ``post_update`` flag described at :ref:`post_update` can resolve
183 this cycle.
184 * In a :attr:`_schema.MetaData.sorted_tables` operation, two
185 :class:`_schema.ForeignKey`
186 or :class:`_schema.ForeignKeyConstraint` objects mutually refer to each
187 other. Apply the ``use_alter=True`` flag to one or both,
188 see :ref:`use_alter`.
190 """
192 def __init__(
193 self,
194 message: str,
195 cycles: Any,
196 edges: Any,
197 msg: Optional[str] = None,
198 code: Optional[str] = None,
199 ):
200 if msg is None:
201 message += " (%s)" % ", ".join(repr(s) for s in cycles)
202 else:
203 message = msg
204 SQLAlchemyError.__init__(self, message, code=code)
205 self.cycles = cycles
206 self.edges = edges
208 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
209 return (
210 self.__class__,
211 (None, self.cycles, self.edges, self.args[0]),
212 {"code": self.code} if self.code is not None else {},
213 )
216class CompileError(SQLAlchemyError):
217 """Raised when an error occurs during SQL compilation"""
220class UnsupportedCompilationError(CompileError):
221 """Raised when an operation is not supported by the given compiler.
223 .. seealso::
225 :ref:`faq_sql_expression_string`
227 :ref:`error_l7de`
228 """
230 code = "l7de"
232 def __init__(
233 self,
234 compiler: Union[Compiled, TypeCompiler],
235 element_type: Type[ClauseElement],
236 message: Optional[str] = None,
237 ):
238 super().__init__(
239 "Compiler %r can't render element of type %s%s"
240 % (compiler, element_type, ": %s" % message if message else "")
241 )
242 self.compiler = compiler
243 self.element_type = element_type
244 self.message = message
246 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
247 return self.__class__, (self.compiler, self.element_type, self.message)
250class IdentifierError(SQLAlchemyError):
251 """Raised when a schema name is beyond the max character limit"""
254class DisconnectionError(SQLAlchemyError):
255 """A disconnect is detected on a raw DB-API connection.
257 This error is raised and consumed internally by a connection pool. It can
258 be raised by the :meth:`_events.PoolEvents.checkout`
259 event so that the host pool
260 forces a retry; the exception will be caught three times in a row before
261 the pool gives up and raises :class:`~sqlalchemy.exc.InvalidRequestError`
262 regarding the connection attempt.
264 """
266 invalidate_pool: bool = False
269class InvalidatePoolError(DisconnectionError):
270 """Raised when the connection pool should invalidate all stale connections.
272 A subclass of :class:`_exc.DisconnectionError` that indicates that the
273 disconnect situation encountered on the connection probably means the
274 entire pool should be invalidated, as the database has been restarted.
276 This exception will be handled otherwise the same way as
277 :class:`_exc.DisconnectionError`, allowing three attempts to reconnect
278 before giving up.
280 .. versionadded:: 1.2
282 """
284 invalidate_pool: bool = True
287class TimeoutError(SQLAlchemyError): # noqa
288 """Raised when a connection pool times out on getting a connection."""
291class InvalidRequestError(SQLAlchemyError):
292 """SQLAlchemy was asked to do something it can't do.
294 This error generally corresponds to runtime state errors.
296 """
299class IllegalStateChangeError(InvalidRequestError):
300 """An object that tracks state encountered an illegal state change
301 of some kind.
303 .. versionadded:: 2.0
305 """
308class NoInspectionAvailable(InvalidRequestError):
309 """A subject passed to :func:`sqlalchemy.inspection.inspect` produced
310 no context for inspection."""
313class PendingRollbackError(InvalidRequestError):
314 """A transaction has failed and needs to be rolled back before
315 continuing.
317 .. versionadded:: 1.4
319 """
322class ResourceClosedError(InvalidRequestError):
323 """An operation was requested from a connection, cursor, or other
324 object that's in a closed state."""
327class NoSuchColumnError(InvalidRequestError, KeyError):
328 """A nonexistent column is requested from a ``Row``."""
331class NoResultFound(InvalidRequestError):
332 """A database result was required but none was found.
335 .. versionchanged:: 1.4 This exception is now part of the
336 ``sqlalchemy.exc`` module in Core, moved from the ORM. The symbol
337 remains importable from ``sqlalchemy.orm.exc``.
340 """
343class MultipleResultsFound(InvalidRequestError):
344 """A single database result was required but more than one were found.
346 .. versionchanged:: 1.4 This exception is now part of the
347 ``sqlalchemy.exc`` module in Core, moved from the ORM. The symbol
348 remains importable from ``sqlalchemy.orm.exc``.
351 """
354class NoReferenceError(InvalidRequestError):
355 """Raised by ``ForeignKey`` to indicate a reference cannot be resolved."""
357 table_name: str
360class AwaitRequired(InvalidRequestError):
361 """Error raised by the async greenlet spawn if no async operation
362 was awaited when it required one.
364 """
366 code = "xd1r"
369class MissingGreenlet(InvalidRequestError):
370 r"""Error raised by the async greenlet await\_ if called while not inside
371 the greenlet spawn context.
373 """
375 code = "xd2s"
378class NoReferencedTableError(NoReferenceError):
379 """Raised by ``ForeignKey`` when the referred ``Table`` cannot be
380 located.
382 """
384 def __init__(self, message: str, tname: str):
385 NoReferenceError.__init__(self, message)
386 self.table_name = tname
388 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
389 return self.__class__, (self.args[0], self.table_name)
392class NoReferencedColumnError(NoReferenceError):
393 """Raised by ``ForeignKey`` when the referred ``Column`` cannot be
394 located.
396 """
398 def __init__(self, message: str, tname: str, cname: str):
399 NoReferenceError.__init__(self, message)
400 self.table_name = tname
401 self.column_name = cname
403 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
404 return (
405 self.__class__,
406 (self.args[0], self.table_name, self.column_name),
407 )
410class NoSuchTableError(InvalidRequestError):
411 """Table does not exist or is not visible to a connection."""
414class UnreflectableTableError(InvalidRequestError):
415 """Table exists but can't be reflected for some reason.
417 .. versionadded:: 1.2
419 """
422class UnboundExecutionError(InvalidRequestError):
423 """SQL was attempted without a database connection to execute it on."""
426class DontWrapMixin:
427 """A mixin class which, when applied to a user-defined Exception class,
428 will not be wrapped inside of :exc:`.StatementError` if the error is
429 emitted within the process of executing a statement.
431 E.g.::
433 from sqlalchemy.exc import DontWrapMixin
436 class MyCustomException(Exception, DontWrapMixin):
437 pass
440 class MySpecialType(TypeDecorator):
441 impl = String
443 def process_bind_param(self, value, dialect):
444 if value == "invalid":
445 raise MyCustomException("invalid!")
447 """
450class StatementError(SQLAlchemyError):
451 """An error occurred during execution of a SQL statement.
453 :class:`StatementError` wraps the exception raised
454 during execution, and features :attr:`.statement`
455 and :attr:`.params` attributes which supply context regarding
456 the specifics of the statement which had an issue.
458 The wrapped exception object is available in
459 the :attr:`.orig` attribute.
461 """
463 statement: Optional[str] = None
464 """The string SQL statement being invoked when this exception occurred."""
466 params: Optional[_AnyExecuteParams] = None
467 """The parameter list being used when this exception occurred."""
469 orig: Optional[BaseException] = None
470 """The original exception that was thrown.
472 """
474 ismulti: Optional[bool] = None
475 """multi parameter passed to repr_params(). None is meaningful."""
477 connection_invalidated: bool = False
479 def __init__(
480 self,
481 message: str,
482 statement: Optional[str],
483 params: Optional[_AnyExecuteParams],
484 orig: Optional[BaseException],
485 hide_parameters: bool = False,
486 code: Optional[str] = None,
487 ismulti: Optional[bool] = None,
488 ):
489 SQLAlchemyError.__init__(self, message, code=code)
490 self.statement = statement
491 self.params = params
492 self.orig = orig
493 self.ismulti = ismulti
494 self.hide_parameters = hide_parameters
495 self.detail: List[str] = []
497 def add_detail(self, msg: str) -> None:
498 self.detail.append(msg)
500 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
501 return (
502 self.__class__,
503 (
504 self.args[0],
505 self.statement,
506 self.params,
507 self.orig,
508 self.hide_parameters,
509 self.__dict__.get("code"),
510 self.ismulti,
511 ),
512 {"detail": self.detail},
513 )
515 @_preloaded.preload_module("sqlalchemy.sql.util")
516 def _sql_message(self) -> str:
517 util = _preloaded.sql_util
519 details = [self._message()]
520 if self.statement:
521 stmt_detail = "[SQL: %s]" % self.statement
522 details.append(stmt_detail)
523 if self.params:
524 if self.hide_parameters:
525 details.append(
526 "[SQL parameters hidden due to hide_parameters=True]"
527 )
528 else:
529 params_repr = util._repr_params(
530 self.params, 10, ismulti=self.ismulti
531 )
532 details.append("[parameters: %r]" % params_repr)
533 code_str = self._code_str()
534 if code_str:
535 details.append(code_str)
536 return "\n".join(["(%s)" % det for det in self.detail] + details)
539class DBAPIError(StatementError):
540 """Raised when the execution of a database operation fails.
542 Wraps exceptions raised by the DB-API underlying the
543 database operation. Driver-specific implementations of the standard
544 DB-API exception types are wrapped by matching sub-types of SQLAlchemy's
545 :class:`DBAPIError` when possible. DB-API's ``Error`` type maps to
546 :class:`DBAPIError` in SQLAlchemy, otherwise the names are identical. Note
547 that there is no guarantee that different DB-API implementations will
548 raise the same exception type for any given error condition.
550 :class:`DBAPIError` features :attr:`~.StatementError.statement`
551 and :attr:`~.StatementError.params` attributes which supply context
552 regarding the specifics of the statement which had an issue, for the
553 typical case when the error was raised within the context of
554 emitting a SQL statement.
556 The wrapped exception object is available in the
557 :attr:`~.StatementError.orig` attribute. Its type and properties are
558 DB-API implementation specific.
560 """
562 code = "dbapi"
564 @overload
565 @classmethod
566 def instance(
567 cls,
568 statement: Optional[str],
569 params: Optional[_AnyExecuteParams],
570 orig: Exception,
571 dbapi_base_err: Type[Exception],
572 hide_parameters: bool = False,
573 connection_invalidated: bool = False,
574 dialect: Optional[Dialect] = None,
575 ismulti: Optional[bool] = None,
576 ) -> StatementError: ...
578 @overload
579 @classmethod
580 def instance(
581 cls,
582 statement: Optional[str],
583 params: Optional[_AnyExecuteParams],
584 orig: DontWrapMixin,
585 dbapi_base_err: Type[Exception],
586 hide_parameters: bool = False,
587 connection_invalidated: bool = False,
588 dialect: Optional[Dialect] = None,
589 ismulti: Optional[bool] = None,
590 ) -> DontWrapMixin: ...
592 @overload
593 @classmethod
594 def instance(
595 cls,
596 statement: Optional[str],
597 params: Optional[_AnyExecuteParams],
598 orig: BaseException,
599 dbapi_base_err: Type[Exception],
600 hide_parameters: bool = False,
601 connection_invalidated: bool = False,
602 dialect: Optional[Dialect] = None,
603 ismulti: Optional[bool] = None,
604 ) -> BaseException: ...
606 @classmethod
607 def instance(
608 cls,
609 statement: Optional[str],
610 params: Optional[_AnyExecuteParams],
611 orig: Union[BaseException, DontWrapMixin],
612 dbapi_base_err: Type[Exception],
613 hide_parameters: bool = False,
614 connection_invalidated: bool = False,
615 dialect: Optional[Dialect] = None,
616 ismulti: Optional[bool] = None,
617 ) -> Union[BaseException, DontWrapMixin]:
618 # Don't ever wrap these, just return them directly as if
619 # DBAPIError didn't exist.
620 if (
621 isinstance(orig, BaseException) and not isinstance(orig, Exception)
622 ) or isinstance(orig, DontWrapMixin):
623 return orig
625 if orig is not None:
626 # not a DBAPI error, statement is present.
627 # raise a StatementError
628 if isinstance(orig, SQLAlchemyError) and statement:
629 return StatementError(
630 "(%s.%s) %s"
631 % (
632 orig.__class__.__module__,
633 orig.__class__.__name__,
634 orig.args[0],
635 ),
636 statement,
637 params,
638 orig,
639 hide_parameters=hide_parameters,
640 code=orig.code,
641 ismulti=ismulti,
642 )
643 elif not isinstance(orig, dbapi_base_err) and statement:
644 return StatementError(
645 "(%s.%s) %s"
646 % (
647 orig.__class__.__module__,
648 orig.__class__.__name__,
649 orig,
650 ),
651 statement,
652 params,
653 orig,
654 hide_parameters=hide_parameters,
655 ismulti=ismulti,
656 )
658 glob = globals()
659 for super_ in orig.__class__.__mro__:
660 name = super_.__name__
661 if dialect:
662 name = dialect.dbapi_exception_translation_map.get(
663 name, name
664 )
665 if name in glob and issubclass(glob[name], DBAPIError):
666 cls = glob[name]
667 break
669 return cls(
670 statement,
671 params,
672 orig,
673 connection_invalidated=connection_invalidated,
674 hide_parameters=hide_parameters,
675 code=cls.code,
676 ismulti=ismulti,
677 )
679 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
680 return (
681 self.__class__,
682 (
683 self.statement,
684 self.params,
685 self.orig,
686 self.hide_parameters,
687 self.connection_invalidated,
688 self.__dict__.get("code"),
689 self.ismulti,
690 ),
691 {"detail": self.detail},
692 )
694 def __init__(
695 self,
696 statement: Optional[str],
697 params: Optional[_AnyExecuteParams],
698 orig: BaseException,
699 hide_parameters: bool = False,
700 connection_invalidated: bool = False,
701 code: Optional[str] = None,
702 ismulti: Optional[bool] = None,
703 ):
704 try:
705 text = str(orig)
706 except Exception as e:
707 text = "Error in str() of DB-API-generated exception: " + str(e)
708 StatementError.__init__(
709 self,
710 "(%s.%s) %s"
711 % (orig.__class__.__module__, orig.__class__.__name__, text),
712 statement,
713 params,
714 orig,
715 hide_parameters,
716 code=code,
717 ismulti=ismulti,
718 )
719 self.connection_invalidated = connection_invalidated
722class InterfaceError(DBAPIError):
723 """Wraps a DB-API InterfaceError."""
725 code = "rvf5"
728class DatabaseError(DBAPIError):
729 """Wraps a DB-API DatabaseError."""
731 code = "4xp6"
734class DataError(DatabaseError):
735 """Wraps a DB-API DataError."""
737 code = "9h9h"
740class OperationalError(DatabaseError):
741 """Wraps a DB-API OperationalError."""
743 code = "e3q8"
746class IntegrityError(DatabaseError):
747 """Wraps a DB-API IntegrityError."""
749 code = "gkpj"
752class InternalError(DatabaseError):
753 """Wraps a DB-API InternalError."""
755 code = "2j85"
758class ProgrammingError(DatabaseError):
759 """Wraps a DB-API ProgrammingError."""
761 code = "f405"
764class NotSupportedError(DatabaseError):
765 """Wraps a DB-API NotSupportedError."""
767 code = "tw8g"
770# Warnings
773class SATestSuiteWarning(Warning):
774 """warning for a condition detected during tests that is non-fatal
776 Currently outside of SAWarning so that we can work around tools like
777 Alembic doing the wrong thing with warnings.
779 """
782class SADeprecationWarning(HasDescriptionCode, DeprecationWarning):
783 """Issued for usage of deprecated APIs."""
785 deprecated_since: Optional[str] = None
786 "Indicates the version that started raising this deprecation warning"
789class Base20DeprecationWarning(SADeprecationWarning):
790 """Issued for usage of APIs specifically deprecated or legacy in
791 SQLAlchemy 2.0.
793 .. seealso::
795 :ref:`error_b8d9`.
797 :ref:`deprecation_20_mode`
799 """
801 deprecated_since: Optional[str] = "1.4"
802 "Indicates the version that started raising this deprecation warning"
804 def __str__(self) -> str:
805 return (
806 super().__str__()
807 + " (Background on SQLAlchemy 2.0 at: https://sqlalche.me/e/b8d9)"
808 )
811class LegacyAPIWarning(Base20DeprecationWarning):
812 """indicates an API that is in 'legacy' status, a long term deprecation."""
815class MovedIn20Warning(Base20DeprecationWarning):
816 """Subtype of RemovedIn20Warning to indicate an API that moved only."""
819class SAPendingDeprecationWarning(PendingDeprecationWarning):
820 """A similar warning as :class:`_exc.SADeprecationWarning`, this warning
821 is not used in modern versions of SQLAlchemy.
823 """
825 deprecated_since: Optional[str] = None
826 "Indicates the version that started raising this deprecation warning"
829class SAWarning(HasDescriptionCode, RuntimeWarning):
830 """Issued at runtime."""
832 _what_are_we = "warning"