Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/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-2024 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
435 class MyCustomException(Exception, DontWrapMixin):
436 pass
438 class MySpecialType(TypeDecorator):
439 impl = String
441 def process_bind_param(self, value, dialect):
442 if value == 'invalid':
443 raise MyCustomException("invalid!")
445 """
448class StatementError(SQLAlchemyError):
449 """An error occurred during execution of a SQL statement.
451 :class:`StatementError` wraps the exception raised
452 during execution, and features :attr:`.statement`
453 and :attr:`.params` attributes which supply context regarding
454 the specifics of the statement which had an issue.
456 The wrapped exception object is available in
457 the :attr:`.orig` attribute.
459 """
461 statement: Optional[str] = None
462 """The string SQL statement being invoked when this exception occurred."""
464 params: Optional[_AnyExecuteParams] = None
465 """The parameter list being used when this exception occurred."""
467 orig: Optional[BaseException] = None
468 """The original exception that was thrown.
470 """
472 ismulti: Optional[bool] = None
473 """multi parameter passed to repr_params(). None is meaningful."""
475 connection_invalidated: bool = False
477 def __init__(
478 self,
479 message: str,
480 statement: Optional[str],
481 params: Optional[_AnyExecuteParams],
482 orig: Optional[BaseException],
483 hide_parameters: bool = False,
484 code: Optional[str] = None,
485 ismulti: Optional[bool] = None,
486 ):
487 SQLAlchemyError.__init__(self, message, code=code)
488 self.statement = statement
489 self.params = params
490 self.orig = orig
491 self.ismulti = ismulti
492 self.hide_parameters = hide_parameters
493 self.detail: List[str] = []
495 def add_detail(self, msg: str) -> None:
496 self.detail.append(msg)
498 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
499 return (
500 self.__class__,
501 (
502 self.args[0],
503 self.statement,
504 self.params,
505 self.orig,
506 self.hide_parameters,
507 self.__dict__.get("code"),
508 self.ismulti,
509 ),
510 {"detail": self.detail},
511 )
513 @_preloaded.preload_module("sqlalchemy.sql.util")
514 def _sql_message(self) -> str:
515 util = _preloaded.sql_util
517 details = [self._message()]
518 if self.statement:
519 stmt_detail = "[SQL: %s]" % self.statement
520 details.append(stmt_detail)
521 if self.params:
522 if self.hide_parameters:
523 details.append(
524 "[SQL parameters hidden due to hide_parameters=True]"
525 )
526 else:
527 params_repr = util._repr_params(
528 self.params, 10, ismulti=self.ismulti
529 )
530 details.append("[parameters: %r]" % params_repr)
531 code_str = self._code_str()
532 if code_str:
533 details.append(code_str)
534 return "\n".join(["(%s)" % det for det in self.detail] + details)
537class DBAPIError(StatementError):
538 """Raised when the execution of a database operation fails.
540 Wraps exceptions raised by the DB-API underlying the
541 database operation. Driver-specific implementations of the standard
542 DB-API exception types are wrapped by matching sub-types of SQLAlchemy's
543 :class:`DBAPIError` when possible. DB-API's ``Error`` type maps to
544 :class:`DBAPIError` in SQLAlchemy, otherwise the names are identical. Note
545 that there is no guarantee that different DB-API implementations will
546 raise the same exception type for any given error condition.
548 :class:`DBAPIError` features :attr:`~.StatementError.statement`
549 and :attr:`~.StatementError.params` attributes which supply context
550 regarding the specifics of the statement which had an issue, for the
551 typical case when the error was raised within the context of
552 emitting a SQL statement.
554 The wrapped exception object is available in the
555 :attr:`~.StatementError.orig` attribute. Its type and properties are
556 DB-API implementation specific.
558 """
560 code = "dbapi"
562 @overload
563 @classmethod
564 def instance(
565 cls,
566 statement: Optional[str],
567 params: Optional[_AnyExecuteParams],
568 orig: Exception,
569 dbapi_base_err: Type[Exception],
570 hide_parameters: bool = False,
571 connection_invalidated: bool = False,
572 dialect: Optional[Dialect] = None,
573 ismulti: Optional[bool] = None,
574 ) -> StatementError: ...
576 @overload
577 @classmethod
578 def instance(
579 cls,
580 statement: Optional[str],
581 params: Optional[_AnyExecuteParams],
582 orig: DontWrapMixin,
583 dbapi_base_err: Type[Exception],
584 hide_parameters: bool = False,
585 connection_invalidated: bool = False,
586 dialect: Optional[Dialect] = None,
587 ismulti: Optional[bool] = None,
588 ) -> DontWrapMixin: ...
590 @overload
591 @classmethod
592 def instance(
593 cls,
594 statement: Optional[str],
595 params: Optional[_AnyExecuteParams],
596 orig: BaseException,
597 dbapi_base_err: Type[Exception],
598 hide_parameters: bool = False,
599 connection_invalidated: bool = False,
600 dialect: Optional[Dialect] = None,
601 ismulti: Optional[bool] = None,
602 ) -> BaseException: ...
604 @classmethod
605 def instance(
606 cls,
607 statement: Optional[str],
608 params: Optional[_AnyExecuteParams],
609 orig: Union[BaseException, DontWrapMixin],
610 dbapi_base_err: Type[Exception],
611 hide_parameters: bool = False,
612 connection_invalidated: bool = False,
613 dialect: Optional[Dialect] = None,
614 ismulti: Optional[bool] = None,
615 ) -> Union[BaseException, DontWrapMixin]:
616 # Don't ever wrap these, just return them directly as if
617 # DBAPIError didn't exist.
618 if (
619 isinstance(orig, BaseException) and not isinstance(orig, Exception)
620 ) or isinstance(orig, DontWrapMixin):
621 return orig
623 if orig is not None:
624 # not a DBAPI error, statement is present.
625 # raise a StatementError
626 if isinstance(orig, SQLAlchemyError) and statement:
627 return StatementError(
628 "(%s.%s) %s"
629 % (
630 orig.__class__.__module__,
631 orig.__class__.__name__,
632 orig.args[0],
633 ),
634 statement,
635 params,
636 orig,
637 hide_parameters=hide_parameters,
638 code=orig.code,
639 ismulti=ismulti,
640 )
641 elif not isinstance(orig, dbapi_base_err) and statement:
642 return StatementError(
643 "(%s.%s) %s"
644 % (
645 orig.__class__.__module__,
646 orig.__class__.__name__,
647 orig,
648 ),
649 statement,
650 params,
651 orig,
652 hide_parameters=hide_parameters,
653 ismulti=ismulti,
654 )
656 glob = globals()
657 for super_ in orig.__class__.__mro__:
658 name = super_.__name__
659 if dialect:
660 name = dialect.dbapi_exception_translation_map.get(
661 name, name
662 )
663 if name in glob and issubclass(glob[name], DBAPIError):
664 cls = glob[name]
665 break
667 return cls(
668 statement,
669 params,
670 orig,
671 connection_invalidated=connection_invalidated,
672 hide_parameters=hide_parameters,
673 code=cls.code,
674 ismulti=ismulti,
675 )
677 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
678 return (
679 self.__class__,
680 (
681 self.statement,
682 self.params,
683 self.orig,
684 self.hide_parameters,
685 self.connection_invalidated,
686 self.__dict__.get("code"),
687 self.ismulti,
688 ),
689 {"detail": self.detail},
690 )
692 def __init__(
693 self,
694 statement: Optional[str],
695 params: Optional[_AnyExecuteParams],
696 orig: BaseException,
697 hide_parameters: bool = False,
698 connection_invalidated: bool = False,
699 code: Optional[str] = None,
700 ismulti: Optional[bool] = None,
701 ):
702 try:
703 text = str(orig)
704 except Exception as e:
705 text = "Error in str() of DB-API-generated exception: " + str(e)
706 StatementError.__init__(
707 self,
708 "(%s.%s) %s"
709 % (orig.__class__.__module__, orig.__class__.__name__, text),
710 statement,
711 params,
712 orig,
713 hide_parameters,
714 code=code,
715 ismulti=ismulti,
716 )
717 self.connection_invalidated = connection_invalidated
720class InterfaceError(DBAPIError):
721 """Wraps a DB-API InterfaceError."""
723 code = "rvf5"
726class DatabaseError(DBAPIError):
727 """Wraps a DB-API DatabaseError."""
729 code = "4xp6"
732class DataError(DatabaseError):
733 """Wraps a DB-API DataError."""
735 code = "9h9h"
738class OperationalError(DatabaseError):
739 """Wraps a DB-API OperationalError."""
741 code = "e3q8"
744class IntegrityError(DatabaseError):
745 """Wraps a DB-API IntegrityError."""
747 code = "gkpj"
750class InternalError(DatabaseError):
751 """Wraps a DB-API InternalError."""
753 code = "2j85"
756class ProgrammingError(DatabaseError):
757 """Wraps a DB-API ProgrammingError."""
759 code = "f405"
762class NotSupportedError(DatabaseError):
763 """Wraps a DB-API NotSupportedError."""
765 code = "tw8g"
768# Warnings
771class SATestSuiteWarning(Warning):
772 """warning for a condition detected during tests that is non-fatal
774 Currently outside of SAWarning so that we can work around tools like
775 Alembic doing the wrong thing with warnings.
777 """
780class SADeprecationWarning(HasDescriptionCode, DeprecationWarning):
781 """Issued for usage of deprecated APIs."""
783 deprecated_since: Optional[str] = None
784 "Indicates the version that started raising this deprecation warning"
787class Base20DeprecationWarning(SADeprecationWarning):
788 """Issued for usage of APIs specifically deprecated or legacy in
789 SQLAlchemy 2.0.
791 .. seealso::
793 :ref:`error_b8d9`.
795 :ref:`deprecation_20_mode`
797 """
799 deprecated_since: Optional[str] = "1.4"
800 "Indicates the version that started raising this deprecation warning"
802 def __str__(self) -> str:
803 return (
804 super().__str__()
805 + " (Background on SQLAlchemy 2.0 at: https://sqlalche.me/e/b8d9)"
806 )
809class LegacyAPIWarning(Base20DeprecationWarning):
810 """indicates an API that is in 'legacy' status, a long term deprecation."""
813class MovedIn20Warning(Base20DeprecationWarning):
814 """Subtype of RemovedIn20Warning to indicate an API that moved only."""
817class SAPendingDeprecationWarning(PendingDeprecationWarning):
818 """A similar warning as :class:`_exc.SADeprecationWarning`, this warning
819 is not used in modern versions of SQLAlchemy.
821 """
823 deprecated_since: Optional[str] = None
824 "Indicates the version that started raising this deprecation warning"
827class SAWarning(HasDescriptionCode, RuntimeWarning):
828 """Issued at runtime."""
830 _what_are_we = "warning"