Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy/exc.py: 68%
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 EmulatedDBAPIException(Exception):
119 """Serves as the base of the DBAPI ``Error`` class for dialects where
120 a DBAPI exception hierrchy needs to be emulated.
122 The current example is the asyncpg dialect.
124 .. versionadded:: 2.1
126 """
128 orig: Exception | None
130 def __init__(self, message: str, orig: Exception | None = None):
131 # we accept None for Exception since all DBAPI.Error objects
132 # need to support construction with a message alone
133 super().__init__(message)
134 self.orig = orig
136 @property
137 def driver_exception(self) -> Exception:
138 """The original driver exception that was raised.
140 This exception object will always originate from outside of
141 SQLAlchemy.
143 """
145 if self.orig is None:
146 raise ValueError(
147 "No original exception is present. Was this "
148 "EmulatedDBAPIException constructed without a driver error?"
149 )
150 return self.orig
152 def __reduce__(self) -> Any:
153 return self.__class__, (self.args[0], self.orig)
156class ArgumentError(SQLAlchemyError):
157 """Raised when an invalid or conflicting function argument is supplied.
159 This error generally corresponds to construction time state errors.
161 """
164class DuplicateColumnError(ArgumentError):
165 """a Column is being added to a Table that would replace another
166 Column, without appropriate parameters to allow this in place.
168 .. versionadded:: 2.0.0b4
170 """
173class ObjectNotExecutableError(ArgumentError):
174 """Raised when an object is passed to .execute() that can't be
175 executed as SQL.
177 """
179 def __init__(self, target: Any):
180 super().__init__(f"Not an executable object: {target!r}")
181 self.target = target
183 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
184 return self.__class__, (self.target,)
187class NoSuchModuleError(ArgumentError):
188 """Raised when a dynamically-loaded module (usually a database dialect)
189 of a particular name cannot be located."""
192class NoForeignKeysError(ArgumentError):
193 """Raised when no foreign keys can be located between two selectables
194 during a join."""
197class AmbiguousForeignKeysError(ArgumentError):
198 """Raised when more than one foreign key matching can be located
199 between two selectables during a join."""
202class ConstraintColumnNotFoundError(ArgumentError):
203 """raised when a constraint refers to a string column name that
204 is not present in the table being constrained.
206 .. versionadded:: 2.0
208 """
211class CircularDependencyError(SQLAlchemyError):
212 """Raised by topological sorts when a circular dependency is detected.
214 There are two scenarios where this error occurs:
216 * In a Session flush operation, if two objects are mutually dependent
217 on each other, they can not be inserted or deleted via INSERT or
218 DELETE statements alone; an UPDATE will be needed to post-associate
219 or pre-deassociate one of the foreign key constrained values.
220 The ``post_update`` flag described at :ref:`post_update` can resolve
221 this cycle.
222 * In a :attr:`_schema.MetaData.sorted_tables` operation, two
223 :class:`_schema.ForeignKey`
224 or :class:`_schema.ForeignKeyConstraint` objects mutually refer to each
225 other. Apply the ``use_alter=True`` flag to one or both,
226 see :ref:`use_alter`.
228 """
230 def __init__(
231 self,
232 message: str,
233 cycles: Any,
234 edges: Any,
235 msg: Optional[str] = None,
236 code: Optional[str] = None,
237 ):
238 if msg is None:
239 message += " (%s)" % ", ".join(repr(s) for s in cycles)
240 else:
241 message = msg
242 SQLAlchemyError.__init__(self, message, code=code)
243 self.cycles = cycles
244 self.edges = edges
246 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
247 return (
248 self.__class__,
249 (None, self.cycles, self.edges, self.args[0]),
250 {"code": self.code} if self.code is not None else {},
251 )
254class CompileError(SQLAlchemyError):
255 """Raised when an error occurs during SQL compilation"""
258class UnsupportedCompilationError(CompileError):
259 """Raised when an operation is not supported by the given compiler.
261 .. seealso::
263 :ref:`faq_sql_expression_string`
265 :ref:`error_l7de`
266 """
268 code = "l7de"
270 def __init__(
271 self,
272 compiler: Union[Compiled, TypeCompiler],
273 element_type: Type[ClauseElement],
274 message: Optional[str] = None,
275 ):
276 super().__init__(
277 "Compiler %r can't render element of type %s%s"
278 % (compiler, element_type, ": %s" % message if message else "")
279 )
280 self.compiler = compiler
281 self.element_type = element_type
282 self.message = message
284 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
285 return self.__class__, (self.compiler, self.element_type, self.message)
288class IdentifierError(SQLAlchemyError):
289 """Raised when a schema name is beyond the max character limit"""
292class DisconnectionError(SQLAlchemyError):
293 """A disconnect is detected on a raw DB-API connection.
295 This error is raised and consumed internally by a connection pool. It can
296 be raised by the :meth:`_events.PoolEvents.checkout`
297 event so that the host pool
298 forces a retry; the exception will be caught three times in a row before
299 the pool gives up and raises :class:`~sqlalchemy.exc.InvalidRequestError`
300 regarding the connection attempt.
302 """
304 invalidate_pool: bool = False
307class InvalidatePoolError(DisconnectionError):
308 """Raised when the connection pool should invalidate all stale connections.
310 A subclass of :class:`_exc.DisconnectionError` that indicates that the
311 disconnect situation encountered on the connection probably means the
312 entire pool should be invalidated, as the database has been restarted.
314 This exception will be handled otherwise the same way as
315 :class:`_exc.DisconnectionError`, allowing three attempts to reconnect
316 before giving up.
318 """
320 invalidate_pool: bool = True
323class TimeoutError(SQLAlchemyError): # noqa
324 """Raised when a connection pool times out on getting a connection."""
327class InvalidRequestError(SQLAlchemyError):
328 """SQLAlchemy was asked to do something it can't do.
330 This error generally corresponds to runtime state errors.
332 """
335class IllegalStateChangeError(InvalidRequestError):
336 """An object that tracks state encountered an illegal state change
337 of some kind.
339 .. versionadded:: 2.0
341 """
344class NoInspectionAvailable(InvalidRequestError):
345 """A subject passed to :func:`sqlalchemy.inspection.inspect` produced
346 no context for inspection."""
349class PendingRollbackError(InvalidRequestError):
350 """A transaction has failed and needs to be rolled back before
351 continuing.
353 .. versionadded:: 1.4
355 """
358class ResourceClosedError(InvalidRequestError):
359 """An operation was requested from a connection, cursor, or other
360 object that's in a closed state."""
363class NoSuchColumnError(InvalidRequestError, KeyError):
364 """A nonexistent column is requested from a ``Row``."""
367class AmbiguousColumnError(InvalidRequestError):
368 """Raised when a column/attribute name is ambiguous across multiple
369 entities.
371 This can occur when using :meth:`_sql.Select.filter_by` with multiple
372 joined tables that have columns with the same name.
374 .. versionadded:: 2.1
376 """
379class NoResultFound(InvalidRequestError):
380 """A database result was required but none was found.
383 .. versionchanged:: 1.4 This exception is now part of the
384 ``sqlalchemy.exc`` module in Core, moved from the ORM. The symbol
385 remains importable from ``sqlalchemy.orm.exc``.
388 """
391class MultipleResultsFound(InvalidRequestError):
392 """A single database result was required but more than one were found.
394 .. versionchanged:: 1.4 This exception is now part of the
395 ``sqlalchemy.exc`` module in Core, moved from the ORM. The symbol
396 remains importable from ``sqlalchemy.orm.exc``.
399 """
402class NoReferenceError(InvalidRequestError):
403 """Raised by ``ForeignKey`` to indicate a reference cannot be resolved."""
405 table_name: str
408class AwaitRequired(InvalidRequestError):
409 """Error raised by the async greenlet spawn if no async operation
410 was awaited when it required one.
412 """
414 code = "xd1r"
417class MissingGreenlet(InvalidRequestError):
418 r"""Error raised by the async greenlet await\_ if called while not inside
419 the greenlet spawn context.
421 """
423 code = "xd2s"
426class NoReferencedTableError(NoReferenceError):
427 """Raised by ``ForeignKey`` when the referred ``Table`` cannot be
428 located.
430 """
432 def __init__(self, message: str, tname: str):
433 NoReferenceError.__init__(self, message)
434 self.table_name = tname
436 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
437 return self.__class__, (self.args[0], self.table_name)
440class NoReferencedColumnError(NoReferenceError):
441 """Raised by ``ForeignKey`` when the referred ``Column`` cannot be
442 located.
444 """
446 def __init__(self, message: str, tname: str, cname: str):
447 NoReferenceError.__init__(self, message)
448 self.table_name = tname
449 self.column_name = cname
451 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
452 return (
453 self.__class__,
454 (self.args[0], self.table_name, self.column_name),
455 )
458class NoSuchTableError(InvalidRequestError):
459 """Table does not exist or is not visible to a connection."""
462class UnreflectableTableError(InvalidRequestError):
463 """Table exists but can't be reflected for some reason."""
466class UnboundExecutionError(InvalidRequestError):
467 """SQL was attempted without a database connection to execute it on."""
470class DontWrapMixin:
471 """A mixin class which, when applied to a user-defined Exception class,
472 will not be wrapped inside of :exc:`.StatementError` if the error is
473 emitted within the process of executing a statement.
475 E.g.::
477 from sqlalchemy.exc import DontWrapMixin
480 class MyCustomException(Exception, DontWrapMixin):
481 pass
484 class MySpecialType(TypeDecorator):
485 impl = String
487 def process_bind_param(self, value, dialect):
488 if value == "invalid":
489 raise MyCustomException("invalid!")
491 """
494class StatementError(SQLAlchemyError):
495 """An error occurred during execution of a SQL statement.
497 :class:`StatementError` wraps the exception raised
498 during execution, and features :attr:`.statement`
499 and :attr:`.params` attributes which supply context regarding
500 the specifics of the statement which had an issue.
502 The wrapped exception object is available in
503 the :attr:`.orig` attribute.
505 """
507 statement: Optional[str] = None
508 """The string SQL statement being invoked when this exception occurred."""
510 params: Optional[_AnyExecuteParams] = None
511 """The parameter list being used when this exception occurred."""
513 orig: Optional[BaseException] = None
514 """The original exception that was thrown.
516 .. seealso::
518 :attr:`.DBAPIError.driver_exception` - a more specific attribute that
519 is guaranteed to return the exception object raised by the third
520 party driver in use, even when using asyncio.
522 """
524 ismulti: Optional[bool] = None
525 """multi parameter passed to repr_params(). None is meaningful."""
527 connection_invalidated: bool = False
529 def __init__(
530 self,
531 message: str,
532 statement: Optional[str],
533 params: Optional[_AnyExecuteParams],
534 orig: Optional[BaseException],
535 hide_parameters: bool = False,
536 code: Optional[str] = None,
537 ismulti: Optional[bool] = None,
538 ):
539 SQLAlchemyError.__init__(self, message, code=code)
540 self.statement = statement
541 self.params = params
542 self.orig = orig
543 self.ismulti = ismulti
544 self.hide_parameters = hide_parameters
545 self.detail: List[str] = []
547 def add_detail(self, msg: str) -> None:
548 self.detail.append(msg)
550 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
551 return (
552 self.__class__,
553 (
554 self.args[0],
555 self.statement,
556 self.params,
557 self.orig,
558 self.hide_parameters,
559 self.__dict__.get("code"),
560 self.ismulti,
561 ),
562 {"detail": self.detail},
563 )
565 @_preloaded.preload_module("sqlalchemy.sql.util")
566 def _sql_message(self) -> str:
567 util = _preloaded.sql_util
569 details = [self._message()]
570 if self.statement:
571 stmt_detail = "[SQL: %s]" % self.statement
572 details.append(stmt_detail)
573 if self.params:
574 if self.hide_parameters:
575 details.append(
576 "[SQL parameters hidden due to hide_parameters=True]"
577 )
578 else:
579 params_repr = util._repr_params(
580 self.params, 10, ismulti=self.ismulti
581 )
582 details.append("[parameters: %r]" % params_repr)
583 code_str = self._code_str()
584 if code_str:
585 details.append(code_str)
586 return "\n".join(["(%s)" % det for det in self.detail] + details)
589class DBAPIError(StatementError):
590 """Raised when the execution of a database operation fails.
592 Wraps exceptions raised by the DB-API underlying the
593 database operation. Driver-specific implementations of the standard
594 DB-API exception types are wrapped by matching sub-types of SQLAlchemy's
595 :class:`DBAPIError` when possible. DB-API's ``Error`` type maps to
596 :class:`DBAPIError` in SQLAlchemy, otherwise the names are identical. Note
597 that there is no guarantee that different DB-API implementations will
598 raise the same exception type for any given error condition.
600 :class:`DBAPIError` features :attr:`~.StatementError.statement`
601 and :attr:`~.StatementError.params` attributes which supply context
602 regarding the specifics of the statement which had an issue, for the
603 typical case when the error was raised within the context of
604 emitting a SQL statement.
606 The wrapped exception object is available in the
607 :attr:`~.StatementError.orig` attribute. Its type and properties are
608 DB-API implementation specific.
610 """
612 code = "dbapi"
614 orig: Optional[Exception]
616 @overload
617 @classmethod
618 def instance(
619 cls,
620 statement: Optional[str],
621 params: Optional[_AnyExecuteParams],
622 orig: Exception,
623 dbapi_base_err: Type[Exception],
624 hide_parameters: bool = False,
625 connection_invalidated: bool = False,
626 dialect: Optional[Dialect] = None,
627 ismulti: Optional[bool] = None,
628 ) -> StatementError: ...
630 @overload
631 @classmethod
632 def instance(
633 cls,
634 statement: Optional[str],
635 params: Optional[_AnyExecuteParams],
636 orig: DontWrapMixin,
637 dbapi_base_err: Type[Exception],
638 hide_parameters: bool = False,
639 connection_invalidated: bool = False,
640 dialect: Optional[Dialect] = None,
641 ismulti: Optional[bool] = None,
642 ) -> DontWrapMixin: ...
644 @overload
645 @classmethod
646 def instance(
647 cls,
648 statement: Optional[str],
649 params: Optional[_AnyExecuteParams],
650 orig: BaseException,
651 dbapi_base_err: Type[Exception],
652 hide_parameters: bool = False,
653 connection_invalidated: bool = False,
654 dialect: Optional[Dialect] = None,
655 ismulti: Optional[bool] = None,
656 ) -> BaseException: ...
658 @classmethod
659 def instance(
660 cls,
661 statement: Optional[str],
662 params: Optional[_AnyExecuteParams],
663 orig: Union[BaseException, DontWrapMixin],
664 dbapi_base_err: Type[Exception],
665 hide_parameters: bool = False,
666 connection_invalidated: bool = False,
667 dialect: Optional[Dialect] = None,
668 ismulti: Optional[bool] = None,
669 ) -> Union[BaseException, DontWrapMixin]:
670 # Don't ever wrap these, just return them directly as if
671 # DBAPIError didn't exist.
672 if (
673 isinstance(orig, BaseException) and not isinstance(orig, Exception)
674 ) or isinstance(orig, DontWrapMixin):
675 return orig
677 if orig is not None:
678 # not a DBAPI error, statement is present.
679 # raise a StatementError
680 if isinstance(orig, SQLAlchemyError) and statement:
681 return StatementError(
682 "(%s.%s) %s"
683 % (
684 orig.__class__.__module__,
685 orig.__class__.__name__,
686 orig.args[0],
687 ),
688 statement,
689 params,
690 orig,
691 hide_parameters=hide_parameters,
692 code=orig.code,
693 ismulti=ismulti,
694 )
695 elif not isinstance(orig, dbapi_base_err) and statement:
696 return StatementError(
697 "(%s.%s) %s"
698 % (
699 orig.__class__.__module__,
700 orig.__class__.__name__,
701 orig,
702 ),
703 statement,
704 params,
705 orig,
706 hide_parameters=hide_parameters,
707 ismulti=ismulti,
708 )
710 glob = globals()
711 for super_ in orig.__class__.__mro__:
712 name = super_.__name__
713 if dialect:
714 name = dialect.dbapi_exception_translation_map.get(
715 name, name
716 )
717 if name in glob and issubclass(glob[name], DBAPIError):
718 cls = glob[name]
719 break
721 return cls(
722 statement,
723 params,
724 orig,
725 connection_invalidated=connection_invalidated,
726 hide_parameters=hide_parameters,
727 code=cls.code,
728 ismulti=ismulti,
729 )
731 def __reduce__(self) -> Union[str, Tuple[Any, ...]]:
732 return (
733 self.__class__,
734 (
735 self.statement,
736 self.params,
737 self.orig,
738 self.hide_parameters,
739 self.connection_invalidated,
740 self.__dict__.get("code"),
741 self.ismulti,
742 ),
743 {"detail": self.detail},
744 )
746 def __init__(
747 self,
748 statement: Optional[str],
749 params: Optional[_AnyExecuteParams],
750 orig: BaseException,
751 hide_parameters: bool = False,
752 connection_invalidated: bool = False,
753 code: Optional[str] = None,
754 ismulti: Optional[bool] = None,
755 ):
756 try:
757 text = str(orig)
758 except Exception as e:
759 text = "Error in str() of DB-API-generated exception: " + str(e)
760 StatementError.__init__(
761 self,
762 "(%s.%s) %s"
763 % (orig.__class__.__module__, orig.__class__.__name__, text),
764 statement,
765 params,
766 orig,
767 hide_parameters,
768 code=code,
769 ismulti=ismulti,
770 )
771 self.connection_invalidated = connection_invalidated
773 @property
774 def driver_exception(self) -> Exception:
775 """The exception object originating from the driver (DBAPI) outside
776 of SQLAlchemy.
778 In the case of some asyncio dialects, special steps are taken to
779 resolve the exception to what the third party driver has raised, even
780 for SQLAlchemy dialects that include an "emulated" DBAPI exception
781 hierarchy.
783 For non-asyncio dialects, this attribute will be the same attribute
784 as the :attr:`.StatementError.orig` attribute.
786 For an asyncio dialect provided by SQLAlchemy, depending on if the
787 dialect provides an "emulated" exception hierarchy or if the underlying
788 DBAPI raises DBAPI-style exceptions, it will refer to either the
789 :attr:`.EmulatedDBAPIException.driver_exception` attribute on the
790 :class:`.EmulatedDBAPIException` that's thrown (such as when using
791 asyncpg), or to the actual exception object thrown by the
792 third party driver.
794 .. versionadded:: 2.1
796 """
798 if self.orig is None:
799 raise ValueError(
800 "No original exception is present. Was this "
801 "DBAPIError constructed without a driver error?"
802 )
804 if isinstance(self.orig, EmulatedDBAPIException):
805 return self.orig.driver_exception
806 else:
807 return self.orig
810class InterfaceError(DBAPIError):
811 """Wraps a DB-API InterfaceError."""
813 code = "rvf5"
816class DatabaseError(DBAPIError):
817 """Wraps a DB-API DatabaseError."""
819 code = "4xp6"
822class DataError(DatabaseError):
823 """Wraps a DB-API DataError."""
825 code = "9h9h"
828class OperationalError(DatabaseError):
829 """Wraps a DB-API OperationalError."""
831 code = "e3q8"
834class IntegrityError(DatabaseError):
835 """Wraps a DB-API IntegrityError."""
837 code = "gkpj"
840class InternalError(DatabaseError):
841 """Wraps a DB-API InternalError."""
843 code = "2j85"
846class ProgrammingError(DatabaseError):
847 """Wraps a DB-API ProgrammingError."""
849 code = "f405"
852class NotSupportedError(DatabaseError):
853 """Wraps a DB-API NotSupportedError."""
855 code = "tw8g"
858# Warnings
861class SATestSuiteWarning(Warning):
862 """warning for a condition detected during tests that is non-fatal
864 Currently outside of SAWarning so that we can work around tools like
865 Alembic doing the wrong thing with warnings.
867 """
870class SADeprecationWarning(HasDescriptionCode, DeprecationWarning):
871 """Issued for usage of deprecated APIs."""
873 deprecated_since: Optional[str] = None
874 "Indicates the version that started raising this deprecation warning"
877class Base20DeprecationWarning(SADeprecationWarning):
878 """Issued for usage of APIs specifically deprecated or legacy in
879 SQLAlchemy 2.0.
881 .. seealso::
883 :ref:`error_b8d9`.
885 :ref:`deprecation_20_mode`
887 """
889 deprecated_since: Optional[str] = "1.4"
890 "Indicates the version that started raising this deprecation warning"
892 def __str__(self) -> str:
893 return (
894 super().__str__()
895 + " (Background on SQLAlchemy 2.0 at: https://sqlalche.me/e/b8d9)"
896 )
899class LegacyAPIWarning(Base20DeprecationWarning):
900 """indicates an API that is in 'legacy' status, a long term deprecation."""
903class MovedIn20Warning(Base20DeprecationWarning):
904 """Subtype of Base20DeprecationWarning to indicate an API that moved
905 only.
906 """
909class SAPendingDeprecationWarning(PendingDeprecationWarning):
910 """A similar warning as :class:`_exc.SADeprecationWarning`, this warning
911 is not used in modern versions of SQLAlchemy.
913 """
915 deprecated_since: Optional[str] = None
916 "Indicates the version that started raising this deprecation warning"
919class SAWarning(HasDescriptionCode, RuntimeWarning):
920 """Issued at runtime."""
922 _what_are_we = "warning"