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

232 statements  

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 

7 

8"""Exceptions used with SQLAlchemy. 

9 

10The base exception class is :exc:`.SQLAlchemyError`. Exceptions which are 

11raised as a result of DBAPI exceptions are all subclasses of 

12:exc:`.DBAPIError`. 

13 

14""" 

15from __future__ import annotations 

16 

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 

25 

26from .util import compat 

27from .util import preloaded as _preloaded 

28 

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 

35 

36if typing.TYPE_CHECKING: 

37 _version_token: str 

38else: 

39 # set by __init__.py 

40 _version_token = None 

41 

42 

43class HasDescriptionCode: 

44 """helper which adds 'code' as an attribute and '_code_str' as a method""" 

45 

46 code: Optional[str] = None 

47 

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) 

53 

54 _what_are_we = "error" 

55 

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 ) 

64 

65 def __str__(self) -> str: 

66 message = super().__str__() 

67 if self.code: 

68 message = "%s %s" % (message, self._code_str()) 

69 return message 

70 

71 

72class SQLAlchemyError(HasDescriptionCode, Exception): 

73 """Generic error class.""" 

74 

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 

87 

88 if len(self.args) == 1: 

89 arg_text = self.args[0] 

90 

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) 

98 

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) 

105 

106 def _sql_message(self) -> str: 

107 message = self._message() 

108 

109 if self.code: 

110 message = "%s %s" % (message, self._code_str()) 

111 

112 return message 

113 

114 def __str__(self) -> str: 

115 return self._sql_message() 

116 

117 

118class ArgumentError(SQLAlchemyError): 

119 """Raised when an invalid or conflicting function argument is supplied. 

120 

121 This error generally corresponds to construction time state errors. 

122 

123 """ 

124 

125 

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. 

129 

130 .. versionadded:: 2.0.0b4 

131 

132 """ 

133 

134 

135class ObjectNotExecutableError(ArgumentError): 

136 """Raised when an object is passed to .execute() that can't be 

137 executed as SQL. 

138 

139 """ 

140 

141 def __init__(self, target: Any): 

142 super().__init__("Not an executable object: %r" % target) 

143 self.target = target 

144 

145 def __reduce__(self) -> Union[str, Tuple[Any, ...]]: 

146 return self.__class__, (self.target,) 

147 

148 

149class NoSuchModuleError(ArgumentError): 

150 """Raised when a dynamically-loaded module (usually a database dialect) 

151 of a particular name cannot be located.""" 

152 

153 

154class NoForeignKeysError(ArgumentError): 

155 """Raised when no foreign keys can be located between two selectables 

156 during a join.""" 

157 

158 

159class AmbiguousForeignKeysError(ArgumentError): 

160 """Raised when more than one foreign key matching can be located 

161 between two selectables during a join.""" 

162 

163 

164class ConstraintColumnNotFoundError(ArgumentError): 

165 """raised when a constraint refers to a string column name that 

166 is not present in the table being constrained. 

167 

168 .. versionadded:: 2.0 

169 

170 """ 

171 

172 

173class CircularDependencyError(SQLAlchemyError): 

174 """Raised by topological sorts when a circular dependency is detected. 

175 

176 There are two scenarios where this error occurs: 

177 

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`. 

189 

190 """ 

191 

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 

207 

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 ) 

214 

215 

216class CompileError(SQLAlchemyError): 

217 """Raised when an error occurs during SQL compilation""" 

218 

219 

220class UnsupportedCompilationError(CompileError): 

221 """Raised when an operation is not supported by the given compiler. 

222 

223 .. seealso:: 

224 

225 :ref:`faq_sql_expression_string` 

226 

227 :ref:`error_l7de` 

228 """ 

229 

230 code = "l7de" 

231 

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 

245 

246 def __reduce__(self) -> Union[str, Tuple[Any, ...]]: 

247 return self.__class__, (self.compiler, self.element_type, self.message) 

248 

249 

250class IdentifierError(SQLAlchemyError): 

251 """Raised when a schema name is beyond the max character limit""" 

252 

253 

254class DisconnectionError(SQLAlchemyError): 

255 """A disconnect is detected on a raw DB-API connection. 

256 

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. 

263 

264 """ 

265 

266 invalidate_pool: bool = False 

267 

268 

269class InvalidatePoolError(DisconnectionError): 

270 """Raised when the connection pool should invalidate all stale connections. 

271 

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. 

275 

276 This exception will be handled otherwise the same way as 

277 :class:`_exc.DisconnectionError`, allowing three attempts to reconnect 

278 before giving up. 

279 

280 .. versionadded:: 1.2 

281 

282 """ 

283 

284 invalidate_pool: bool = True 

285 

286 

287class TimeoutError(SQLAlchemyError): # noqa 

288 """Raised when a connection pool times out on getting a connection.""" 

289 

290 

291class InvalidRequestError(SQLAlchemyError): 

292 """SQLAlchemy was asked to do something it can't do. 

293 

294 This error generally corresponds to runtime state errors. 

295 

296 """ 

297 

298 

299class IllegalStateChangeError(InvalidRequestError): 

300 """An object that tracks state encountered an illegal state change 

301 of some kind. 

302 

303 .. versionadded:: 2.0 

304 

305 """ 

306 

307 

308class NoInspectionAvailable(InvalidRequestError): 

309 """A subject passed to :func:`sqlalchemy.inspection.inspect` produced 

310 no context for inspection.""" 

311 

312 

313class PendingRollbackError(InvalidRequestError): 

314 """A transaction has failed and needs to be rolled back before 

315 continuing. 

316 

317 .. versionadded:: 1.4 

318 

319 """ 

320 

321 

322class ResourceClosedError(InvalidRequestError): 

323 """An operation was requested from a connection, cursor, or other 

324 object that's in a closed state.""" 

325 

326 

327class NoSuchColumnError(InvalidRequestError, KeyError): 

328 """A nonexistent column is requested from a ``Row``.""" 

329 

330 

331class NoResultFound(InvalidRequestError): 

332 """A database result was required but none was found. 

333 

334 

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``. 

338 

339 

340 """ 

341 

342 

343class MultipleResultsFound(InvalidRequestError): 

344 """A single database result was required but more than one were found. 

345 

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``. 

349 

350 

351 """ 

352 

353 

354class NoReferenceError(InvalidRequestError): 

355 """Raised by ``ForeignKey`` to indicate a reference cannot be resolved.""" 

356 

357 table_name: str 

358 

359 

360class AwaitRequired(InvalidRequestError): 

361 """Error raised by the async greenlet spawn if no async operation 

362 was awaited when it required one. 

363 

364 """ 

365 

366 code = "xd1r" 

367 

368 

369class MissingGreenlet(InvalidRequestError): 

370 r"""Error raised by the async greenlet await\_ if called while not inside 

371 the greenlet spawn context. 

372 

373 """ 

374 

375 code = "xd2s" 

376 

377 

378class NoReferencedTableError(NoReferenceError): 

379 """Raised by ``ForeignKey`` when the referred ``Table`` cannot be 

380 located. 

381 

382 """ 

383 

384 def __init__(self, message: str, tname: str): 

385 NoReferenceError.__init__(self, message) 

386 self.table_name = tname 

387 

388 def __reduce__(self) -> Union[str, Tuple[Any, ...]]: 

389 return self.__class__, (self.args[0], self.table_name) 

390 

391 

392class NoReferencedColumnError(NoReferenceError): 

393 """Raised by ``ForeignKey`` when the referred ``Column`` cannot be 

394 located. 

395 

396 """ 

397 

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 

402 

403 def __reduce__(self) -> Union[str, Tuple[Any, ...]]: 

404 return ( 

405 self.__class__, 

406 (self.args[0], self.table_name, self.column_name), 

407 ) 

408 

409 

410class NoSuchTableError(InvalidRequestError): 

411 """Table does not exist or is not visible to a connection.""" 

412 

413 

414class UnreflectableTableError(InvalidRequestError): 

415 """Table exists but can't be reflected for some reason. 

416 

417 .. versionadded:: 1.2 

418 

419 """ 

420 

421 

422class UnboundExecutionError(InvalidRequestError): 

423 """SQL was attempted without a database connection to execute it on.""" 

424 

425 

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. 

430 

431 E.g.:: 

432 

433 from sqlalchemy.exc import DontWrapMixin 

434 

435 

436 class MyCustomException(Exception, DontWrapMixin): 

437 pass 

438 

439 

440 class MySpecialType(TypeDecorator): 

441 impl = String 

442 

443 def process_bind_param(self, value, dialect): 

444 if value == "invalid": 

445 raise MyCustomException("invalid!") 

446 

447 """ 

448 

449 

450class StatementError(SQLAlchemyError): 

451 """An error occurred during execution of a SQL statement. 

452 

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. 

457 

458 The wrapped exception object is available in 

459 the :attr:`.orig` attribute. 

460 

461 """ 

462 

463 statement: Optional[str] = None 

464 """The string SQL statement being invoked when this exception occurred.""" 

465 

466 params: Optional[_AnyExecuteParams] = None 

467 """The parameter list being used when this exception occurred.""" 

468 

469 orig: Optional[BaseException] = None 

470 """The original exception that was thrown. 

471 

472 """ 

473 

474 ismulti: Optional[bool] = None 

475 """multi parameter passed to repr_params(). None is meaningful.""" 

476 

477 connection_invalidated: bool = False 

478 

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] = [] 

496 

497 def add_detail(self, msg: str) -> None: 

498 self.detail.append(msg) 

499 

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 ) 

514 

515 @_preloaded.preload_module("sqlalchemy.sql.util") 

516 def _sql_message(self) -> str: 

517 util = _preloaded.sql_util 

518 

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) 

537 

538 

539class DBAPIError(StatementError): 

540 """Raised when the execution of a database operation fails. 

541 

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. 

549 

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. 

555 

556 The wrapped exception object is available in the 

557 :attr:`~.StatementError.orig` attribute. Its type and properties are 

558 DB-API implementation specific. 

559 

560 """ 

561 

562 code = "dbapi" 

563 

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: ... 

577 

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: ... 

591 

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: ... 

605 

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 

624 

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 ) 

657 

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 

668 

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 ) 

678 

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 ) 

693 

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 

720 

721 

722class InterfaceError(DBAPIError): 

723 """Wraps a DB-API InterfaceError.""" 

724 

725 code = "rvf5" 

726 

727 

728class DatabaseError(DBAPIError): 

729 """Wraps a DB-API DatabaseError.""" 

730 

731 code = "4xp6" 

732 

733 

734class DataError(DatabaseError): 

735 """Wraps a DB-API DataError.""" 

736 

737 code = "9h9h" 

738 

739 

740class OperationalError(DatabaseError): 

741 """Wraps a DB-API OperationalError.""" 

742 

743 code = "e3q8" 

744 

745 

746class IntegrityError(DatabaseError): 

747 """Wraps a DB-API IntegrityError.""" 

748 

749 code = "gkpj" 

750 

751 

752class InternalError(DatabaseError): 

753 """Wraps a DB-API InternalError.""" 

754 

755 code = "2j85" 

756 

757 

758class ProgrammingError(DatabaseError): 

759 """Wraps a DB-API ProgrammingError.""" 

760 

761 code = "f405" 

762 

763 

764class NotSupportedError(DatabaseError): 

765 """Wraps a DB-API NotSupportedError.""" 

766 

767 code = "tw8g" 

768 

769 

770# Warnings 

771 

772 

773class SATestSuiteWarning(Warning): 

774 """warning for a condition detected during tests that is non-fatal 

775 

776 Currently outside of SAWarning so that we can work around tools like 

777 Alembic doing the wrong thing with warnings. 

778 

779 """ 

780 

781 

782class SADeprecationWarning(HasDescriptionCode, DeprecationWarning): 

783 """Issued for usage of deprecated APIs.""" 

784 

785 deprecated_since: Optional[str] = None 

786 "Indicates the version that started raising this deprecation warning" 

787 

788 

789class Base20DeprecationWarning(SADeprecationWarning): 

790 """Issued for usage of APIs specifically deprecated or legacy in 

791 SQLAlchemy 2.0. 

792 

793 .. seealso:: 

794 

795 :ref:`error_b8d9`. 

796 

797 :ref:`deprecation_20_mode` 

798 

799 """ 

800 

801 deprecated_since: Optional[str] = "1.4" 

802 "Indicates the version that started raising this deprecation warning" 

803 

804 def __str__(self) -> str: 

805 return ( 

806 super().__str__() 

807 + " (Background on SQLAlchemy 2.0 at: https://sqlalche.me/e/b8d9)" 

808 ) 

809 

810 

811class LegacyAPIWarning(Base20DeprecationWarning): 

812 """indicates an API that is in 'legacy' status, a long term deprecation.""" 

813 

814 

815class MovedIn20Warning(Base20DeprecationWarning): 

816 """Subtype of RemovedIn20Warning to indicate an API that moved only.""" 

817 

818 

819class SAPendingDeprecationWarning(PendingDeprecationWarning): 

820 """A similar warning as :class:`_exc.SADeprecationWarning`, this warning 

821 is not used in modern versions of SQLAlchemy. 

822 

823 """ 

824 

825 deprecated_since: Optional[str] = None 

826 "Indicates the version that started raising this deprecation warning" 

827 

828 

829class SAWarning(HasDescriptionCode, RuntimeWarning): 

830 """Issued at runtime.""" 

831 

832 _what_are_we = "warning"