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-2026 the SQLAlchemy authors and contributors 

3# <see AUTHORS file> 

4# 

5# This module is part of SQLAlchemy and is released under 

6# the MIT License: https://www.opensource.org/licenses/mit-license.php 

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""" 

15 

16from __future__ import annotations 

17 

18import typing 

19from typing import Any 

20from typing import List 

21from typing import Optional 

22from typing import overload 

23from typing import Tuple 

24from typing import Type 

25from typing import Union 

26 

27from .util import compat 

28from .util import preloaded as _preloaded 

29 

30if typing.TYPE_CHECKING: 

31 from .engine.interfaces import _AnyExecuteParams 

32 from .engine.interfaces import Dialect 

33 from .sql.compiler import Compiled 

34 from .sql.compiler import TypeCompiler 

35 from .sql.elements import ClauseElement 

36 

37if typing.TYPE_CHECKING: 

38 _version_token: str 

39else: 

40 # set by __init__.py 

41 _version_token = None 

42 

43 

44class HasDescriptionCode: 

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

46 

47 code: Optional[str] = None 

48 

49 def __init__(self, *arg: Any, **kw: Any): 

50 code = kw.pop("code", None) 

51 if code is not None: 

52 self.code = code 

53 super().__init__(*arg, **kw) 

54 

55 _what_are_we = "error" 

56 

57 def _code_str(self) -> str: 

58 if not self.code: 

59 return "" 

60 else: 

61 return ( 

62 f"(Background on this {self._what_are_we} at: " 

63 f"https://sqlalche.me/e/{_version_token}/{self.code})" 

64 ) 

65 

66 def __str__(self) -> str: 

67 message = super().__str__() 

68 if self.code: 

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

70 return message 

71 

72 

73class SQLAlchemyError(HasDescriptionCode, Exception): 

74 """Generic error class.""" 

75 

76 def _message(self) -> str: 

77 # rules: 

78 # 

79 # 1. single arg string will usually be a unicode 

80 # object, but since __str__() must return unicode, check for 

81 # bytestring just in case 

82 # 

83 # 2. for multiple self.args, this is not a case in current 

84 # SQLAlchemy though this is happening in at least one known external 

85 # library, call str() which does a repr(). 

86 # 

87 text: str 

88 

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

90 arg_text = self.args[0] 

91 

92 if isinstance(arg_text, bytes): 

93 text = compat.decode_backslashreplace(arg_text, "utf-8") 

94 # This is for when the argument is not a string of any sort. 

95 # Otherwise, converting this exception to string would fail for 

96 # non-string arguments. 

97 else: 

98 text = str(arg_text) 

99 

100 return text 

101 else: 

102 # this is not a normal case within SQLAlchemy but is here for 

103 # compatibility with Exception.args - the str() comes out as 

104 # a repr() of the tuple 

105 return str(self.args) 

106 

107 def _sql_message(self) -> str: 

108 message = self._message() 

109 

110 if self.code: 

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

112 

113 return message 

114 

115 def __str__(self) -> str: 

116 return self._sql_message() 

117 

118 

119class ArgumentError(SQLAlchemyError): 

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

121 

122 This error generally corresponds to construction time state errors. 

123 

124 """ 

125 

126 

127class DuplicateColumnError(ArgumentError): 

128 """a Column is being added to a Table that would replace another 

129 Column, without appropriate parameters to allow this in place. 

130 

131 .. versionadded:: 2.0.0b4 

132 

133 """ 

134 

135 

136class ObjectNotExecutableError(ArgumentError): 

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

138 executed as SQL. 

139 

140 """ 

141 

142 def __init__(self, target: Any): 

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

144 self.target = target 

145 

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

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

148 

149 

150class NoSuchModuleError(ArgumentError): 

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

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

153 

154 

155class NoForeignKeysError(ArgumentError): 

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

157 during a join.""" 

158 

159 

160class AmbiguousForeignKeysError(ArgumentError): 

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

162 between two selectables during a join.""" 

163 

164 

165class ConstraintColumnNotFoundError(ArgumentError): 

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

167 is not present in the table being constrained. 

168 

169 .. versionadded:: 2.0 

170 

171 """ 

172 

173 

174class CircularDependencyError(SQLAlchemyError): 

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

176 

177 There are two scenarios where this error occurs: 

178 

179 * In a Session flush operation, if two objects are mutually dependent 

180 on each other, they can not be inserted or deleted via INSERT or 

181 DELETE statements alone; an UPDATE will be needed to post-associate 

182 or pre-deassociate one of the foreign key constrained values. 

183 The ``post_update`` flag described at :ref:`post_update` can resolve 

184 this cycle. 

185 * In a :attr:`_schema.MetaData.sorted_tables` operation, two 

186 :class:`_schema.ForeignKey` 

187 or :class:`_schema.ForeignKeyConstraint` objects mutually refer to each 

188 other. Apply the ``use_alter=True`` flag to one or both, 

189 see :ref:`use_alter`. 

190 

191 """ 

192 

193 def __init__( 

194 self, 

195 message: str, 

196 cycles: Any, 

197 edges: Any, 

198 msg: Optional[str] = None, 

199 code: Optional[str] = None, 

200 ): 

201 if msg is None: 

202 message += " (%s)" % ", ".join(repr(s) for s in cycles) 

203 else: 

204 message = msg 

205 SQLAlchemyError.__init__(self, message, code=code) 

206 self.cycles = cycles 

207 self.edges = edges 

208 

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

210 return ( 

211 self.__class__, 

212 (None, self.cycles, self.edges, self.args[0]), 

213 {"code": self.code} if self.code is not None else {}, 

214 ) 

215 

216 

217class CompileError(SQLAlchemyError): 

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

219 

220 

221class UnsupportedCompilationError(CompileError): 

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

223 

224 .. seealso:: 

225 

226 :ref:`faq_sql_expression_string` 

227 

228 :ref:`error_l7de` 

229 """ 

230 

231 code = "l7de" 

232 

233 def __init__( 

234 self, 

235 compiler: Union[Compiled, TypeCompiler], 

236 element_type: Type[ClauseElement], 

237 message: Optional[str] = None, 

238 ): 

239 super().__init__( 

240 "Compiler %r can't render element of type %s%s" 

241 % (compiler, element_type, ": %s" % message if message else "") 

242 ) 

243 self.compiler = compiler 

244 self.element_type = element_type 

245 self.message = message 

246 

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

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

249 

250 

251class IdentifierError(SQLAlchemyError): 

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

253 

254 

255class DisconnectionError(SQLAlchemyError): 

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

257 

258 This error is raised and consumed internally by a connection pool. It can 

259 be raised by the :meth:`_events.PoolEvents.checkout` 

260 event so that the host pool 

261 forces a retry; the exception will be caught three times in a row before 

262 the pool gives up and raises :class:`~sqlalchemy.exc.InvalidRequestError` 

263 regarding the connection attempt. 

264 

265 """ 

266 

267 invalidate_pool: bool = False 

268 

269 

270class InvalidatePoolError(DisconnectionError): 

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

272 

273 A subclass of :class:`_exc.DisconnectionError` that indicates that the 

274 disconnect situation encountered on the connection probably means the 

275 entire pool should be invalidated, as the database has been restarted. 

276 

277 This exception will be handled otherwise the same way as 

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

279 before giving up. 

280 

281 .. versionadded:: 1.2 

282 

283 """ 

284 

285 invalidate_pool: bool = True 

286 

287 

288class TimeoutError(SQLAlchemyError): # noqa 

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

290 

291 

292class InvalidRequestError(SQLAlchemyError): 

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

294 

295 This error generally corresponds to runtime state errors. 

296 

297 """ 

298 

299 

300class IllegalStateChangeError(InvalidRequestError): 

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

302 of some kind. 

303 

304 .. versionadded:: 2.0 

305 

306 """ 

307 

308 

309class NoInspectionAvailable(InvalidRequestError): 

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

311 no context for inspection.""" 

312 

313 

314class PendingRollbackError(InvalidRequestError): 

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

316 continuing. 

317 

318 .. versionadded:: 1.4 

319 

320 """ 

321 

322 

323class ResourceClosedError(InvalidRequestError): 

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

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

326 

327 

328class NoSuchColumnError(InvalidRequestError, KeyError): 

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

330 

331 

332class NoResultFound(InvalidRequestError): 

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

334 

335 

336 .. versionchanged:: 1.4 This exception is now part of the 

337 ``sqlalchemy.exc`` module in Core, moved from the ORM. The symbol 

338 remains importable from ``sqlalchemy.orm.exc``. 

339 

340 

341 """ 

342 

343 

344class MultipleResultsFound(InvalidRequestError): 

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

346 

347 .. versionchanged:: 1.4 This exception is now part of the 

348 ``sqlalchemy.exc`` module in Core, moved from the ORM. The symbol 

349 remains importable from ``sqlalchemy.orm.exc``. 

350 

351 

352 """ 

353 

354 

355class NoReferenceError(InvalidRequestError): 

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

357 

358 table_name: str 

359 

360 

361class AwaitRequired(InvalidRequestError): 

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

363 was awaited when it required one. 

364 

365 """ 

366 

367 code = "xd1r" 

368 

369 

370class MissingGreenlet(InvalidRequestError): 

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

372 the greenlet spawn context. 

373 

374 """ 

375 

376 code = "xd2s" 

377 

378 

379class NoReferencedTableError(NoReferenceError): 

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

381 located. 

382 

383 """ 

384 

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

386 NoReferenceError.__init__(self, message) 

387 self.table_name = tname 

388 

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

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

391 

392 

393class NoReferencedColumnError(NoReferenceError): 

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

395 located. 

396 

397 """ 

398 

399 def __init__(self, message: str, tname: str, cname: str): 

400 NoReferenceError.__init__(self, message) 

401 self.table_name = tname 

402 self.column_name = cname 

403 

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

405 return ( 

406 self.__class__, 

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

408 ) 

409 

410 

411class NoSuchTableError(InvalidRequestError): 

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

413 

414 

415class UnreflectableTableError(InvalidRequestError): 

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

417 

418 .. versionadded:: 1.2 

419 

420 """ 

421 

422 

423class UnboundExecutionError(InvalidRequestError): 

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

425 

426 

427class DontWrapMixin: 

428 """A mixin class which, when applied to a user-defined Exception class, 

429 will not be wrapped inside of :exc:`.StatementError` if the error is 

430 emitted within the process of executing a statement. 

431 

432 E.g.:: 

433 

434 from sqlalchemy.exc import DontWrapMixin 

435 

436 

437 class MyCustomException(Exception, DontWrapMixin): 

438 pass 

439 

440 

441 class MySpecialType(TypeDecorator): 

442 impl = String 

443 

444 def process_bind_param(self, value, dialect): 

445 if value == "invalid": 

446 raise MyCustomException("invalid!") 

447 

448 """ 

449 

450 

451class StatementError(SQLAlchemyError): 

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

453 

454 :class:`StatementError` wraps the exception raised 

455 during execution, and features :attr:`.statement` 

456 and :attr:`.params` attributes which supply context regarding 

457 the specifics of the statement which had an issue. 

458 

459 The wrapped exception object is available in 

460 the :attr:`.orig` attribute. 

461 

462 """ 

463 

464 statement: Optional[str] = None 

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

466 

467 params: Optional[_AnyExecuteParams] = None 

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

469 

470 orig: Optional[BaseException] = None 

471 """The original exception that was thrown. 

472 

473 """ 

474 

475 ismulti: Optional[bool] = None 

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

477 

478 connection_invalidated: bool = False 

479 

480 def __init__( 

481 self, 

482 message: str, 

483 statement: Optional[str], 

484 params: Optional[_AnyExecuteParams], 

485 orig: Optional[BaseException], 

486 hide_parameters: bool = False, 

487 code: Optional[str] = None, 

488 ismulti: Optional[bool] = None, 

489 ): 

490 SQLAlchemyError.__init__(self, message, code=code) 

491 self.statement = statement 

492 self.params = params 

493 self.orig = orig 

494 self.ismulti = ismulti 

495 self.hide_parameters = hide_parameters 

496 self.detail: List[str] = [] 

497 

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

499 self.detail.append(msg) 

500 

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

502 return ( 

503 self.__class__, 

504 ( 

505 self.args[0], 

506 self.statement, 

507 self.params, 

508 self.orig, 

509 self.hide_parameters, 

510 self.__dict__.get("code"), 

511 self.ismulti, 

512 ), 

513 {"detail": self.detail}, 

514 ) 

515 

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

517 def _sql_message(self) -> str: 

518 util = _preloaded.sql_util 

519 

520 details = [self._message()] 

521 if self.statement: 

522 stmt_detail = "[SQL: %s]" % self.statement 

523 details.append(stmt_detail) 

524 if self.params: 

525 if self.hide_parameters: 

526 details.append( 

527 "[SQL parameters hidden due to hide_parameters=True]" 

528 ) 

529 else: 

530 params_repr = util._repr_params( 

531 self.params, 10, ismulti=self.ismulti 

532 ) 

533 details.append("[parameters: %r]" % params_repr) 

534 code_str = self._code_str() 

535 if code_str: 

536 details.append(code_str) 

537 return "\n".join(["(%s)" % det for det in self.detail] + details) 

538 

539 

540class DBAPIError(StatementError): 

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

542 

543 Wraps exceptions raised by the DB-API underlying the 

544 database operation. Driver-specific implementations of the standard 

545 DB-API exception types are wrapped by matching sub-types of SQLAlchemy's 

546 :class:`DBAPIError` when possible. DB-API's ``Error`` type maps to 

547 :class:`DBAPIError` in SQLAlchemy, otherwise the names are identical. Note 

548 that there is no guarantee that different DB-API implementations will 

549 raise the same exception type for any given error condition. 

550 

551 :class:`DBAPIError` features :attr:`~.StatementError.statement` 

552 and :attr:`~.StatementError.params` attributes which supply context 

553 regarding the specifics of the statement which had an issue, for the 

554 typical case when the error was raised within the context of 

555 emitting a SQL statement. 

556 

557 The wrapped exception object is available in the 

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

559 DB-API implementation specific. 

560 

561 """ 

562 

563 code = "dbapi" 

564 

565 @overload 

566 @classmethod 

567 def instance( 

568 cls, 

569 statement: Optional[str], 

570 params: Optional[_AnyExecuteParams], 

571 orig: Exception, 

572 dbapi_base_err: Type[Exception], 

573 hide_parameters: bool = False, 

574 connection_invalidated: bool = False, 

575 dialect: Optional[Dialect] = None, 

576 ismulti: Optional[bool] = None, 

577 ) -> StatementError: ... 

578 

579 @overload 

580 @classmethod 

581 def instance( 

582 cls, 

583 statement: Optional[str], 

584 params: Optional[_AnyExecuteParams], 

585 orig: DontWrapMixin, 

586 dbapi_base_err: Type[Exception], 

587 hide_parameters: bool = False, 

588 connection_invalidated: bool = False, 

589 dialect: Optional[Dialect] = None, 

590 ismulti: Optional[bool] = None, 

591 ) -> DontWrapMixin: ... 

592 

593 @overload 

594 @classmethod 

595 def instance( 

596 cls, 

597 statement: Optional[str], 

598 params: Optional[_AnyExecuteParams], 

599 orig: BaseException, 

600 dbapi_base_err: Type[Exception], 

601 hide_parameters: bool = False, 

602 connection_invalidated: bool = False, 

603 dialect: Optional[Dialect] = None, 

604 ismulti: Optional[bool] = None, 

605 ) -> BaseException: ... 

606 

607 @classmethod 

608 def instance( 

609 cls, 

610 statement: Optional[str], 

611 params: Optional[_AnyExecuteParams], 

612 orig: Union[BaseException, DontWrapMixin], 

613 dbapi_base_err: Type[Exception], 

614 hide_parameters: bool = False, 

615 connection_invalidated: bool = False, 

616 dialect: Optional[Dialect] = None, 

617 ismulti: Optional[bool] = None, 

618 ) -> Union[BaseException, DontWrapMixin]: 

619 # Don't ever wrap these, just return them directly as if 

620 # DBAPIError didn't exist. 

621 if ( 

622 isinstance(orig, BaseException) and not isinstance(orig, Exception) 

623 ) or isinstance(orig, DontWrapMixin): 

624 return orig 

625 

626 if orig is not None: 

627 # not a DBAPI error, statement is present. 

628 # raise a StatementError 

629 if isinstance(orig, SQLAlchemyError) and statement: 

630 return StatementError( 

631 "(%s.%s) %s" 

632 % ( 

633 orig.__class__.__module__, 

634 orig.__class__.__name__, 

635 orig.args[0], 

636 ), 

637 statement, 

638 params, 

639 orig, 

640 hide_parameters=hide_parameters, 

641 code=orig.code, 

642 ismulti=ismulti, 

643 ) 

644 elif not isinstance(orig, dbapi_base_err) and statement: 

645 return StatementError( 

646 "(%s.%s) %s" 

647 % ( 

648 orig.__class__.__module__, 

649 orig.__class__.__name__, 

650 orig, 

651 ), 

652 statement, 

653 params, 

654 orig, 

655 hide_parameters=hide_parameters, 

656 ismulti=ismulti, 

657 ) 

658 

659 glob = globals() 

660 for super_ in orig.__class__.__mro__: 

661 name = super_.__name__ 

662 if dialect: 

663 name = dialect.dbapi_exception_translation_map.get( 

664 name, name 

665 ) 

666 if name in glob and issubclass(glob[name], DBAPIError): 

667 cls = glob[name] 

668 break 

669 

670 return cls( 

671 statement, 

672 params, 

673 orig, 

674 connection_invalidated=connection_invalidated, 

675 hide_parameters=hide_parameters, 

676 code=cls.code, 

677 ismulti=ismulti, 

678 ) 

679 

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

681 return ( 

682 self.__class__, 

683 ( 

684 self.statement, 

685 self.params, 

686 self.orig, 

687 self.hide_parameters, 

688 self.connection_invalidated, 

689 self.__dict__.get("code"), 

690 self.ismulti, 

691 ), 

692 {"detail": self.detail}, 

693 ) 

694 

695 def __init__( 

696 self, 

697 statement: Optional[str], 

698 params: Optional[_AnyExecuteParams], 

699 orig: BaseException, 

700 hide_parameters: bool = False, 

701 connection_invalidated: bool = False, 

702 code: Optional[str] = None, 

703 ismulti: Optional[bool] = None, 

704 ): 

705 try: 

706 text = str(orig) 

707 except Exception as e: 

708 text = "Error in str() of DB-API-generated exception: " + str(e) 

709 StatementError.__init__( 

710 self, 

711 "(%s.%s) %s" 

712 % (orig.__class__.__module__, orig.__class__.__name__, text), 

713 statement, 

714 params, 

715 orig, 

716 hide_parameters, 

717 code=code, 

718 ismulti=ismulti, 

719 ) 

720 self.connection_invalidated = connection_invalidated 

721 

722 

723class InterfaceError(DBAPIError): 

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

725 

726 code = "rvf5" 

727 

728 

729class DatabaseError(DBAPIError): 

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

731 

732 code = "4xp6" 

733 

734 

735class DataError(DatabaseError): 

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

737 

738 code = "9h9h" 

739 

740 

741class OperationalError(DatabaseError): 

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

743 

744 code = "e3q8" 

745 

746 

747class IntegrityError(DatabaseError): 

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

749 

750 code = "gkpj" 

751 

752 

753class InternalError(DatabaseError): 

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

755 

756 code = "2j85" 

757 

758 

759class ProgrammingError(DatabaseError): 

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

761 

762 code = "f405" 

763 

764 

765class NotSupportedError(DatabaseError): 

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

767 

768 code = "tw8g" 

769 

770 

771# Warnings 

772 

773 

774class SATestSuiteWarning(Warning): 

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

776 

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

778 Alembic doing the wrong thing with warnings. 

779 

780 """ 

781 

782 

783class SADeprecationWarning(HasDescriptionCode, DeprecationWarning): 

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

785 

786 deprecated_since: Optional[str] = None 

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

788 

789 

790class Base20DeprecationWarning(SADeprecationWarning): 

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

792 SQLAlchemy 2.0. 

793 

794 .. seealso:: 

795 

796 :ref:`error_b8d9`. 

797 

798 :ref:`deprecation_20_mode` 

799 

800 """ 

801 

802 deprecated_since: Optional[str] = "1.4" 

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

804 

805 def __str__(self) -> str: 

806 return ( 

807 super().__str__() 

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

809 ) 

810 

811 

812class LegacyAPIWarning(Base20DeprecationWarning): 

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

814 

815 

816class MovedIn20Warning(Base20DeprecationWarning): 

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

818 

819 

820class SAPendingDeprecationWarning(PendingDeprecationWarning): 

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

822 is not used in modern versions of SQLAlchemy. 

823 

824 """ 

825 

826 deprecated_since: Optional[str] = None 

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

828 

829 

830class SAWarning(HasDescriptionCode, RuntimeWarning): 

831 """Issued at runtime.""" 

832 

833 _what_are_we = "warning"