Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy/exc.py: 69%

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

254 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 EmulatedDBAPIException(Exception): 

120 """Serves as the base of the DBAPI ``Error`` class for dialects where 

121 a DBAPI exception hierrchy needs to be emulated. 

122 

123 The current example is the asyncpg dialect. 

124 

125 .. versionadded:: 2.1 

126 

127 """ 

128 

129 orig: Exception | None 

130 

131 def __init__(self, message: str, orig: Exception | None = None): 

132 # we accept None for Exception since all DBAPI.Error objects 

133 # need to support construction with a message alone 

134 super().__init__(message) 

135 self.orig = orig 

136 

137 @property 

138 def driver_exception(self) -> Exception: 

139 """The original driver exception that was raised. 

140 

141 This exception object will always originate from outside of 

142 SQLAlchemy. 

143 

144 """ 

145 

146 if self.orig is None: 

147 raise ValueError( 

148 "No original exception is present. Was this " 

149 "EmulatedDBAPIException constructed without a driver error?" 

150 ) 

151 return self.orig 

152 

153 def __reduce__(self) -> Any: 

154 return self.__class__, (self.args[0], self.orig) 

155 

156 

157class ArgumentError(SQLAlchemyError): 

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

159 

160 This error generally corresponds to construction time state errors. 

161 

162 """ 

163 

164 

165class DuplicateColumnError(ArgumentError): 

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

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

168 

169 .. versionadded:: 2.0.0b4 

170 

171 """ 

172 

173 

174class ObjectNotExecutableError(ArgumentError): 

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

176 executed as SQL. 

177 

178 """ 

179 

180 def __init__(self, target: Any): 

181 super().__init__(f"Not an executable object: {target!r}") 

182 self.target = target 

183 

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

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

186 

187 

188class NoSuchModuleError(ArgumentError): 

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

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

191 

192 

193class NoForeignKeysError(ArgumentError): 

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

195 during a join.""" 

196 

197 

198class AmbiguousForeignKeysError(ArgumentError): 

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

200 between two selectables during a join.""" 

201 

202 

203class ConstraintColumnNotFoundError(ArgumentError): 

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

205 is not present in the table being constrained. 

206 

207 .. versionadded:: 2.0 

208 

209 """ 

210 

211 

212class CircularDependencyError(SQLAlchemyError): 

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

214 

215 There are two scenarios where this error occurs: 

216 

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

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

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

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

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

222 this cycle. 

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

224 :class:`_schema.ForeignKey` 

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

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

227 see :ref:`use_alter`. 

228 

229 """ 

230 

231 def __init__( 

232 self, 

233 message: str, 

234 cycles: Any, 

235 edges: Any, 

236 msg: Optional[str] = None, 

237 code: Optional[str] = None, 

238 ): 

239 if msg is None: 

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

241 else: 

242 message = msg 

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

244 self.cycles = cycles 

245 self.edges = edges 

246 

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

248 return ( 

249 self.__class__, 

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

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

252 ) 

253 

254 

255class CompileError(SQLAlchemyError): 

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

257 

258 

259class UnsupportedCompilationError(CompileError): 

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

261 

262 .. seealso:: 

263 

264 :ref:`faq_sql_expression_string` 

265 

266 :ref:`error_l7de` 

267 """ 

268 

269 code = "l7de" 

270 

271 def __init__( 

272 self, 

273 compiler: Union[Compiled, TypeCompiler], 

274 element_type: Type[ClauseElement], 

275 message: Optional[str] = None, 

276 ): 

277 super().__init__( 

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

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

280 ) 

281 self.compiler = compiler 

282 self.element_type = element_type 

283 self.message = message 

284 

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

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

287 

288 

289class IdentifierError(SQLAlchemyError): 

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

291 

292 

293class DisconnectionError(SQLAlchemyError): 

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

295 

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

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

298 event so that the host pool 

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

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

301 regarding the connection attempt. 

302 

303 """ 

304 

305 invalidate_pool: bool = False 

306 

307 

308class InvalidatePoolError(DisconnectionError): 

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

310 

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

312 disconnect situation encountered on the connection probably means the 

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

314 

315 This exception will be handled otherwise the same way as 

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

317 before giving up. 

318 

319 """ 

320 

321 invalidate_pool: bool = True 

322 

323 

324class TimeoutError(SQLAlchemyError): # noqa 

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

326 

327 

328class InvalidRequestError(SQLAlchemyError): 

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

330 

331 This error generally corresponds to runtime state errors. 

332 

333 """ 

334 

335 

336class IllegalStateChangeError(InvalidRequestError): 

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

338 of some kind. 

339 

340 .. versionadded:: 2.0 

341 

342 """ 

343 

344 

345class NoInspectionAvailable(InvalidRequestError): 

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

347 no context for inspection.""" 

348 

349 

350class NoDBAPILoaded(InvalidRequestError): 

351 """A DBAPI-level attribute was requested from a dialect which has no 

352 DBAPI module loaded, or whose DBAPI does not publish the attribute. 

353 

354 This is not an error on the part of the dialect; a dialect which is 

355 used only to compile statements, rather than to interact with a 

356 database, has no DBAPI established, and a DBAPI module is not obliged 

357 to publish a version number of its own. 

358 

359 .. versionadded:: 2.1 

360 

361 """ 

362 

363 

364class PendingRollbackError(InvalidRequestError): 

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

366 continuing. 

367 

368 .. versionadded:: 1.4 

369 

370 """ 

371 

372 

373class ResourceClosedError(InvalidRequestError): 

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

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

376 

377 

378class NoSuchColumnError(InvalidRequestError, KeyError): 

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

380 

381 

382class AmbiguousColumnError(InvalidRequestError): 

383 """Raised when a column/attribute name is ambiguous across multiple 

384 entities. 

385 

386 This can occur when using :meth:`_sql.Select.filter_by` with multiple 

387 joined tables that have columns with the same name. 

388 

389 .. versionadded:: 2.1 

390 

391 """ 

392 

393 

394class NoResultFound(InvalidRequestError): 

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

396 

397 

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

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

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

401 

402 

403 """ 

404 

405 

406class MultipleResultsFound(InvalidRequestError): 

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

408 

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

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

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

412 

413 

414 """ 

415 

416 

417class NoReferenceError(InvalidRequestError): 

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

419 

420 table_name: str 

421 

422 

423class AwaitRequired(InvalidRequestError): 

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

425 was awaited when it required one. 

426 

427 """ 

428 

429 code = "xd1r" 

430 

431 

432class MissingGreenlet(InvalidRequestError): 

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

434 the greenlet spawn context. 

435 

436 """ 

437 

438 code = "xd2s" 

439 

440 

441class NoReferencedTableError(NoReferenceError): 

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

443 located. 

444 

445 """ 

446 

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

448 NoReferenceError.__init__(self, message) 

449 self.table_name = tname 

450 

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

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

453 

454 

455class NoReferencedColumnError(NoReferenceError): 

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

457 located. 

458 

459 """ 

460 

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

462 NoReferenceError.__init__(self, message) 

463 self.table_name = tname 

464 self.column_name = cname 

465 

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

467 return ( 

468 self.__class__, 

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

470 ) 

471 

472 

473class NoSuchTableError(InvalidRequestError): 

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

475 

476 

477class UnreflectableTableError(InvalidRequestError): 

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

479 

480 

481class UnboundExecutionError(InvalidRequestError): 

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

483 

484 

485class DontWrapMixin: 

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

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

488 emitted within the process of executing a statement. 

489 

490 E.g.:: 

491 

492 from sqlalchemy.exc import DontWrapMixin 

493 

494 

495 class MyCustomException(Exception, DontWrapMixin): 

496 pass 

497 

498 

499 class MySpecialType(TypeDecorator): 

500 impl = String 

501 

502 def process_bind_param(self, value, dialect): 

503 if value == "invalid": 

504 raise MyCustomException("invalid!") 

505 

506 """ 

507 

508 

509class StatementError(SQLAlchemyError): 

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

511 

512 :class:`StatementError` wraps the exception raised 

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

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

515 the specifics of the statement which had an issue. 

516 

517 The wrapped exception object is available in 

518 the :attr:`.orig` attribute. 

519 

520 """ 

521 

522 statement: Optional[str] = None 

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

524 

525 params: Optional[_AnyExecuteParams] = None 

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

527 

528 orig: Optional[BaseException] = None 

529 """The original exception that was thrown. 

530 

531 .. seealso:: 

532 

533 :attr:`.DBAPIError.driver_exception` - a more specific attribute that 

534 is guaranteed to return the exception object raised by the third 

535 party driver in use, even when using asyncio. 

536 

537 """ 

538 

539 ismulti: Optional[bool] = None 

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

541 

542 connection_invalidated: bool = False 

543 

544 def __init__( 

545 self, 

546 message: str, 

547 statement: Optional[str], 

548 params: Optional[_AnyExecuteParams], 

549 orig: Optional[BaseException], 

550 hide_parameters: bool = False, 

551 code: Optional[str] = None, 

552 ismulti: Optional[bool] = None, 

553 ): 

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

555 self.statement = statement 

556 self.params = params 

557 self.orig = orig 

558 self.ismulti = ismulti 

559 self.hide_parameters = hide_parameters 

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

561 

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

563 self.detail.append(msg) 

564 

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

566 return ( 

567 self.__class__, 

568 ( 

569 self.args[0], 

570 self.statement, 

571 self.params, 

572 self.orig, 

573 self.hide_parameters, 

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

575 self.ismulti, 

576 ), 

577 {"detail": self.detail}, 

578 ) 

579 

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

581 def _sql_message(self) -> str: 

582 util = _preloaded.sql_util 

583 

584 details = [self._message()] 

585 if self.statement: 

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

587 details.append(stmt_detail) 

588 if self.params: 

589 if self.hide_parameters: 

590 details.append( 

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

592 ) 

593 else: 

594 params_repr = util._repr_params( 

595 self.params, 10, ismulti=self.ismulti 

596 ) 

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

598 code_str = self._code_str() 

599 if code_str: 

600 details.append(code_str) 

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

602 

603 

604class DBAPIError(StatementError): 

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

606 

607 Wraps exceptions raised by the DB-API underlying the 

608 database operation. Driver-specific implementations of the standard 

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

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

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

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

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

614 

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

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

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

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

619 emitting a SQL statement. 

620 

621 The wrapped exception object is available in the 

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

623 DB-API implementation specific. 

624 

625 """ 

626 

627 code = "dbapi" 

628 

629 orig: Optional[Exception] 

630 

631 @overload 

632 @classmethod 

633 def instance( 

634 cls, 

635 statement: Optional[str], 

636 params: Optional[_AnyExecuteParams], 

637 orig: Exception, 

638 dbapi_base_err: Type[Exception], 

639 hide_parameters: bool = False, 

640 connection_invalidated: bool = False, 

641 dialect: Optional[Dialect] = None, 

642 ismulti: Optional[bool] = None, 

643 ) -> StatementError: ... 

644 

645 @overload 

646 @classmethod 

647 def instance( 

648 cls, 

649 statement: Optional[str], 

650 params: Optional[_AnyExecuteParams], 

651 orig: DontWrapMixin, 

652 dbapi_base_err: Type[Exception], 

653 hide_parameters: bool = False, 

654 connection_invalidated: bool = False, 

655 dialect: Optional[Dialect] = None, 

656 ismulti: Optional[bool] = None, 

657 ) -> DontWrapMixin: ... 

658 

659 @overload 

660 @classmethod 

661 def instance( 

662 cls, 

663 statement: Optional[str], 

664 params: Optional[_AnyExecuteParams], 

665 orig: BaseException, 

666 dbapi_base_err: Type[Exception], 

667 hide_parameters: bool = False, 

668 connection_invalidated: bool = False, 

669 dialect: Optional[Dialect] = None, 

670 ismulti: Optional[bool] = None, 

671 ) -> BaseException: ... 

672 

673 @classmethod 

674 def instance( 

675 cls, 

676 statement: Optional[str], 

677 params: Optional[_AnyExecuteParams], 

678 orig: Union[BaseException, DontWrapMixin], 

679 dbapi_base_err: Type[Exception], 

680 hide_parameters: bool = False, 

681 connection_invalidated: bool = False, 

682 dialect: Optional[Dialect] = None, 

683 ismulti: Optional[bool] = None, 

684 ) -> Union[BaseException, DontWrapMixin]: 

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

686 # DBAPIError didn't exist. 

687 if ( 

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

689 ) or isinstance(orig, DontWrapMixin): 

690 return orig 

691 

692 if orig is not None: 

693 # not a DBAPI error, statement is present. 

694 # raise a StatementError 

695 if isinstance(orig, SQLAlchemyError) and statement: 

696 return StatementError( 

697 "(%s.%s) %s" 

698 % ( 

699 orig.__class__.__module__, 

700 orig.__class__.__name__, 

701 orig.args[0], 

702 ), 

703 statement, 

704 params, 

705 orig, 

706 hide_parameters=hide_parameters, 

707 code=orig.code, 

708 ismulti=ismulti, 

709 ) 

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

711 return StatementError( 

712 "(%s.%s) %s" 

713 % ( 

714 orig.__class__.__module__, 

715 orig.__class__.__name__, 

716 orig, 

717 ), 

718 statement, 

719 params, 

720 orig, 

721 hide_parameters=hide_parameters, 

722 ismulti=ismulti, 

723 ) 

724 

725 glob = globals() 

726 for super_ in orig.__class__.__mro__: 

727 name = super_.__name__ 

728 if dialect: 

729 name = dialect.dbapi_exception_translation_map.get( 

730 name, name 

731 ) 

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

733 cls = glob[name] 

734 break 

735 

736 return cls( 

737 statement, 

738 params, 

739 orig, 

740 connection_invalidated=connection_invalidated, 

741 hide_parameters=hide_parameters, 

742 code=cls.code, 

743 ismulti=ismulti, 

744 ) 

745 

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

747 return ( 

748 self.__class__, 

749 ( 

750 self.statement, 

751 self.params, 

752 self.orig, 

753 self.hide_parameters, 

754 self.connection_invalidated, 

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

756 self.ismulti, 

757 ), 

758 {"detail": self.detail}, 

759 ) 

760 

761 def __init__( 

762 self, 

763 statement: Optional[str], 

764 params: Optional[_AnyExecuteParams], 

765 orig: BaseException, 

766 hide_parameters: bool = False, 

767 connection_invalidated: bool = False, 

768 code: Optional[str] = None, 

769 ismulti: Optional[bool] = None, 

770 ): 

771 try: 

772 text = str(orig) 

773 except Exception as e: 

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

775 StatementError.__init__( 

776 self, 

777 "(%s.%s) %s" 

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

779 statement, 

780 params, 

781 orig, 

782 hide_parameters, 

783 code=code, 

784 ismulti=ismulti, 

785 ) 

786 self.connection_invalidated = connection_invalidated 

787 

788 @property 

789 def driver_exception(self) -> Exception: 

790 """The exception object originating from the driver (DBAPI) outside 

791 of SQLAlchemy. 

792 

793 In the case of some asyncio dialects, special steps are taken to 

794 resolve the exception to what the third party driver has raised, even 

795 for SQLAlchemy dialects that include an "emulated" DBAPI exception 

796 hierarchy. 

797 

798 For non-asyncio dialects, this attribute will be the same attribute 

799 as the :attr:`.StatementError.orig` attribute. 

800 

801 For an asyncio dialect provided by SQLAlchemy, depending on if the 

802 dialect provides an "emulated" exception hierarchy or if the underlying 

803 DBAPI raises DBAPI-style exceptions, it will refer to either the 

804 :attr:`.EmulatedDBAPIException.driver_exception` attribute on the 

805 :class:`.EmulatedDBAPIException` that's thrown (such as when using 

806 asyncpg), or to the actual exception object thrown by the 

807 third party driver. 

808 

809 .. versionadded:: 2.1 

810 

811 """ 

812 

813 if self.orig is None: 

814 raise ValueError( 

815 "No original exception is present. Was this " 

816 "DBAPIError constructed without a driver error?" 

817 ) 

818 

819 if isinstance(self.orig, EmulatedDBAPIException): 

820 return self.orig.driver_exception 

821 else: 

822 return self.orig 

823 

824 

825class InterfaceError(DBAPIError): 

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

827 

828 code = "rvf5" 

829 

830 

831class DatabaseError(DBAPIError): 

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

833 

834 code = "4xp6" 

835 

836 

837class DataError(DatabaseError): 

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

839 

840 code = "9h9h" 

841 

842 

843class OperationalError(DatabaseError): 

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

845 

846 code = "e3q8" 

847 

848 

849class IntegrityError(DatabaseError): 

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

851 

852 code = "gkpj" 

853 

854 

855class InternalError(DatabaseError): 

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

857 

858 code = "2j85" 

859 

860 

861class ProgrammingError(DatabaseError): 

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

863 

864 code = "f405" 

865 

866 

867class NotSupportedError(DatabaseError): 

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

869 

870 code = "tw8g" 

871 

872 

873# Warnings 

874 

875 

876class SATestSuiteWarning(Warning): 

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

878 

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

880 Alembic doing the wrong thing with warnings. 

881 

882 """ 

883 

884 

885class SADeprecationWarning(HasDescriptionCode, DeprecationWarning): 

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

887 

888 deprecated_since: Optional[str] = None 

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

890 

891 

892class Base20DeprecationWarning(SADeprecationWarning): 

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

894 SQLAlchemy 2.0. 

895 

896 .. seealso:: 

897 

898 :ref:`error_b8d9`. 

899 

900 :ref:`deprecation_20_mode` 

901 

902 """ 

903 

904 deprecated_since: Optional[str] = "1.4" 

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

906 

907 def __str__(self) -> str: 

908 return ( 

909 super().__str__() 

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

911 ) 

912 

913 

914class LegacyAPIWarning(Base20DeprecationWarning): 

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

916 

917 

918class MovedIn20Warning(Base20DeprecationWarning): 

919 """Subtype of Base20DeprecationWarning to indicate an API that moved 

920 only. 

921 """ 

922 

923 

924class SAPendingDeprecationWarning(PendingDeprecationWarning): 

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

926 is not used in modern versions of SQLAlchemy. 

927 

928 """ 

929 

930 deprecated_since: Optional[str] = None 

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

932 

933 

934class SAWarning(HasDescriptionCode, RuntimeWarning): 

935 """Issued at runtime.""" 

936 

937 _what_are_we = "warning"