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

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

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

120 a DBAPI exception hierrchy needs to be emulated. 

121 

122 The current example is the asyncpg dialect. 

123 

124 .. versionadded:: 2.1 

125 

126 """ 

127 

128 orig: Exception | None 

129 

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 

135 

136 @property 

137 def driver_exception(self) -> Exception: 

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

139 

140 This exception object will always originate from outside of 

141 SQLAlchemy. 

142 

143 """ 

144 

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 

151 

152 def __reduce__(self) -> Any: 

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

154 

155 

156class ArgumentError(SQLAlchemyError): 

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

158 

159 This error generally corresponds to construction time state errors. 

160 

161 """ 

162 

163 

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. 

167 

168 .. versionadded:: 2.0.0b4 

169 

170 """ 

171 

172 

173class ObjectNotExecutableError(ArgumentError): 

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

175 executed as SQL. 

176 

177 """ 

178 

179 def __init__(self, target: Any): 

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

181 self.target = target 

182 

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

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

185 

186 

187class NoSuchModuleError(ArgumentError): 

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

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

190 

191 

192class NoForeignKeysError(ArgumentError): 

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

194 during a join.""" 

195 

196 

197class AmbiguousForeignKeysError(ArgumentError): 

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

199 between two selectables during a join.""" 

200 

201 

202class ConstraintColumnNotFoundError(ArgumentError): 

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

204 is not present in the table being constrained. 

205 

206 .. versionadded:: 2.0 

207 

208 """ 

209 

210 

211class CircularDependencyError(SQLAlchemyError): 

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

213 

214 There are two scenarios where this error occurs: 

215 

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

227 

228 """ 

229 

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 

245 

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 ) 

252 

253 

254class CompileError(SQLAlchemyError): 

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

256 

257 

258class UnsupportedCompilationError(CompileError): 

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

260 

261 .. seealso:: 

262 

263 :ref:`faq_sql_expression_string` 

264 

265 :ref:`error_l7de` 

266 """ 

267 

268 code = "l7de" 

269 

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 

283 

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

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

286 

287 

288class IdentifierError(SQLAlchemyError): 

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

290 

291 

292class DisconnectionError(SQLAlchemyError): 

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

294 

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. 

301 

302 """ 

303 

304 invalidate_pool: bool = False 

305 

306 

307class InvalidatePoolError(DisconnectionError): 

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

309 

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. 

313 

314 This exception will be handled otherwise the same way as 

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

316 before giving up. 

317 

318 """ 

319 

320 invalidate_pool: bool = True 

321 

322 

323class TimeoutError(SQLAlchemyError): # noqa 

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

325 

326 

327class InvalidRequestError(SQLAlchemyError): 

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

329 

330 This error generally corresponds to runtime state errors. 

331 

332 """ 

333 

334 

335class IllegalStateChangeError(InvalidRequestError): 

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

337 of some kind. 

338 

339 .. versionadded:: 2.0 

340 

341 """ 

342 

343 

344class NoInspectionAvailable(InvalidRequestError): 

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

346 no context for inspection.""" 

347 

348 

349class PendingRollbackError(InvalidRequestError): 

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

351 continuing. 

352 

353 .. versionadded:: 1.4 

354 

355 """ 

356 

357 

358class ResourceClosedError(InvalidRequestError): 

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

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

361 

362 

363class NoSuchColumnError(InvalidRequestError, KeyError): 

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

365 

366 

367class NoResultFound(InvalidRequestError): 

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

369 

370 

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

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

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

374 

375 

376 """ 

377 

378 

379class MultipleResultsFound(InvalidRequestError): 

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

381 

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

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

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

385 

386 

387 """ 

388 

389 

390class NoReferenceError(InvalidRequestError): 

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

392 

393 table_name: str 

394 

395 

396class AwaitRequired(InvalidRequestError): 

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

398 was awaited when it required one. 

399 

400 """ 

401 

402 code = "xd1r" 

403 

404 

405class MissingGreenlet(InvalidRequestError): 

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

407 the greenlet spawn context. 

408 

409 """ 

410 

411 code = "xd2s" 

412 

413 

414class NoReferencedTableError(NoReferenceError): 

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

416 located. 

417 

418 """ 

419 

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

421 NoReferenceError.__init__(self, message) 

422 self.table_name = tname 

423 

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

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

426 

427 

428class NoReferencedColumnError(NoReferenceError): 

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

430 located. 

431 

432 """ 

433 

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

435 NoReferenceError.__init__(self, message) 

436 self.table_name = tname 

437 self.column_name = cname 

438 

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

440 return ( 

441 self.__class__, 

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

443 ) 

444 

445 

446class NoSuchTableError(InvalidRequestError): 

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

448 

449 

450class UnreflectableTableError(InvalidRequestError): 

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

452 

453 

454class UnboundExecutionError(InvalidRequestError): 

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

456 

457 

458class DontWrapMixin: 

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

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

461 emitted within the process of executing a statement. 

462 

463 E.g.:: 

464 

465 from sqlalchemy.exc import DontWrapMixin 

466 

467 

468 class MyCustomException(Exception, DontWrapMixin): 

469 pass 

470 

471 

472 class MySpecialType(TypeDecorator): 

473 impl = String 

474 

475 def process_bind_param(self, value, dialect): 

476 if value == "invalid": 

477 raise MyCustomException("invalid!") 

478 

479 """ 

480 

481 

482class StatementError(SQLAlchemyError): 

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

484 

485 :class:`StatementError` wraps the exception raised 

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

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

488 the specifics of the statement which had an issue. 

489 

490 The wrapped exception object is available in 

491 the :attr:`.orig` attribute. 

492 

493 """ 

494 

495 statement: Optional[str] = None 

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

497 

498 params: Optional[_AnyExecuteParams] = None 

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

500 

501 orig: Optional[BaseException] = None 

502 """The original exception that was thrown. 

503 

504 .. seealso:: 

505 

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

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

508 party driver in use, even when using asyncio. 

509 

510 """ 

511 

512 ismulti: Optional[bool] = None 

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

514 

515 connection_invalidated: bool = False 

516 

517 def __init__( 

518 self, 

519 message: str, 

520 statement: Optional[str], 

521 params: Optional[_AnyExecuteParams], 

522 orig: Optional[BaseException], 

523 hide_parameters: bool = False, 

524 code: Optional[str] = None, 

525 ismulti: Optional[bool] = None, 

526 ): 

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

528 self.statement = statement 

529 self.params = params 

530 self.orig = orig 

531 self.ismulti = ismulti 

532 self.hide_parameters = hide_parameters 

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

534 

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

536 self.detail.append(msg) 

537 

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

539 return ( 

540 self.__class__, 

541 ( 

542 self.args[0], 

543 self.statement, 

544 self.params, 

545 self.orig, 

546 self.hide_parameters, 

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

548 self.ismulti, 

549 ), 

550 {"detail": self.detail}, 

551 ) 

552 

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

554 def _sql_message(self) -> str: 

555 util = _preloaded.sql_util 

556 

557 details = [self._message()] 

558 if self.statement: 

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

560 details.append(stmt_detail) 

561 if self.params: 

562 if self.hide_parameters: 

563 details.append( 

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

565 ) 

566 else: 

567 params_repr = util._repr_params( 

568 self.params, 10, ismulti=self.ismulti 

569 ) 

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

571 code_str = self._code_str() 

572 if code_str: 

573 details.append(code_str) 

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

575 

576 

577class DBAPIError(StatementError): 

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

579 

580 Wraps exceptions raised by the DB-API underlying the 

581 database operation. Driver-specific implementations of the standard 

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

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

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

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

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

587 

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

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

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

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

592 emitting a SQL statement. 

593 

594 The wrapped exception object is available in the 

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

596 DB-API implementation specific. 

597 

598 """ 

599 

600 code = "dbapi" 

601 

602 orig: Optional[Exception] 

603 

604 @overload 

605 @classmethod 

606 def instance( 

607 cls, 

608 statement: Optional[str], 

609 params: Optional[_AnyExecuteParams], 

610 orig: Exception, 

611 dbapi_base_err: Type[Exception], 

612 hide_parameters: bool = False, 

613 connection_invalidated: bool = False, 

614 dialect: Optional[Dialect] = None, 

615 ismulti: Optional[bool] = None, 

616 ) -> StatementError: ... 

617 

618 @overload 

619 @classmethod 

620 def instance( 

621 cls, 

622 statement: Optional[str], 

623 params: Optional[_AnyExecuteParams], 

624 orig: DontWrapMixin, 

625 dbapi_base_err: Type[Exception], 

626 hide_parameters: bool = False, 

627 connection_invalidated: bool = False, 

628 dialect: Optional[Dialect] = None, 

629 ismulti: Optional[bool] = None, 

630 ) -> DontWrapMixin: ... 

631 

632 @overload 

633 @classmethod 

634 def instance( 

635 cls, 

636 statement: Optional[str], 

637 params: Optional[_AnyExecuteParams], 

638 orig: BaseException, 

639 dbapi_base_err: Type[Exception], 

640 hide_parameters: bool = False, 

641 connection_invalidated: bool = False, 

642 dialect: Optional[Dialect] = None, 

643 ismulti: Optional[bool] = None, 

644 ) -> BaseException: ... 

645 

646 @classmethod 

647 def instance( 

648 cls, 

649 statement: Optional[str], 

650 params: Optional[_AnyExecuteParams], 

651 orig: Union[BaseException, 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 ) -> Union[BaseException, DontWrapMixin]: 

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

659 # DBAPIError didn't exist. 

660 if ( 

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

662 ) or isinstance(orig, DontWrapMixin): 

663 return orig 

664 

665 if orig is not None: 

666 # not a DBAPI error, statement is present. 

667 # raise a StatementError 

668 if isinstance(orig, SQLAlchemyError) and statement: 

669 return StatementError( 

670 "(%s.%s) %s" 

671 % ( 

672 orig.__class__.__module__, 

673 orig.__class__.__name__, 

674 orig.args[0], 

675 ), 

676 statement, 

677 params, 

678 orig, 

679 hide_parameters=hide_parameters, 

680 code=orig.code, 

681 ismulti=ismulti, 

682 ) 

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

684 return StatementError( 

685 "(%s.%s) %s" 

686 % ( 

687 orig.__class__.__module__, 

688 orig.__class__.__name__, 

689 orig, 

690 ), 

691 statement, 

692 params, 

693 orig, 

694 hide_parameters=hide_parameters, 

695 ismulti=ismulti, 

696 ) 

697 

698 glob = globals() 

699 for super_ in orig.__class__.__mro__: 

700 name = super_.__name__ 

701 if dialect: 

702 name = dialect.dbapi_exception_translation_map.get( 

703 name, name 

704 ) 

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

706 cls = glob[name] 

707 break 

708 

709 return cls( 

710 statement, 

711 params, 

712 orig, 

713 connection_invalidated=connection_invalidated, 

714 hide_parameters=hide_parameters, 

715 code=cls.code, 

716 ismulti=ismulti, 

717 ) 

718 

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

720 return ( 

721 self.__class__, 

722 ( 

723 self.statement, 

724 self.params, 

725 self.orig, 

726 self.hide_parameters, 

727 self.connection_invalidated, 

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

729 self.ismulti, 

730 ), 

731 {"detail": self.detail}, 

732 ) 

733 

734 def __init__( 

735 self, 

736 statement: Optional[str], 

737 params: Optional[_AnyExecuteParams], 

738 orig: BaseException, 

739 hide_parameters: bool = False, 

740 connection_invalidated: bool = False, 

741 code: Optional[str] = None, 

742 ismulti: Optional[bool] = None, 

743 ): 

744 try: 

745 text = str(orig) 

746 except Exception as e: 

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

748 StatementError.__init__( 

749 self, 

750 "(%s.%s) %s" 

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

752 statement, 

753 params, 

754 orig, 

755 hide_parameters, 

756 code=code, 

757 ismulti=ismulti, 

758 ) 

759 self.connection_invalidated = connection_invalidated 

760 

761 @property 

762 def driver_exception(self) -> Exception: 

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

764 of SQLAlchemy. 

765 

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

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

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

769 hierarchy. 

770 

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

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

773 

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

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

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

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

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

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

780 third party driver. 

781 

782 .. versionadded:: 2.1 

783 

784 """ 

785 

786 if self.orig is None: 

787 raise ValueError( 

788 "No original exception is present. Was this " 

789 "DBAPIError constructed without a driver error?" 

790 ) 

791 

792 if isinstance(self.orig, EmulatedDBAPIException): 

793 return self.orig.driver_exception 

794 else: 

795 return self.orig 

796 

797 

798class InterfaceError(DBAPIError): 

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

800 

801 code = "rvf5" 

802 

803 

804class DatabaseError(DBAPIError): 

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

806 

807 code = "4xp6" 

808 

809 

810class DataError(DatabaseError): 

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

812 

813 code = "9h9h" 

814 

815 

816class OperationalError(DatabaseError): 

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

818 

819 code = "e3q8" 

820 

821 

822class IntegrityError(DatabaseError): 

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

824 

825 code = "gkpj" 

826 

827 

828class InternalError(DatabaseError): 

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

830 

831 code = "2j85" 

832 

833 

834class ProgrammingError(DatabaseError): 

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

836 

837 code = "f405" 

838 

839 

840class NotSupportedError(DatabaseError): 

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

842 

843 code = "tw8g" 

844 

845 

846# Warnings 

847 

848 

849class SATestSuiteWarning(Warning): 

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

851 

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

853 Alembic doing the wrong thing with warnings. 

854 

855 """ 

856 

857 

858class SADeprecationWarning(HasDescriptionCode, DeprecationWarning): 

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

860 

861 deprecated_since: Optional[str] = None 

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

863 

864 

865class Base20DeprecationWarning(SADeprecationWarning): 

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

867 SQLAlchemy 2.0. 

868 

869 .. seealso:: 

870 

871 :ref:`error_b8d9`. 

872 

873 :ref:`deprecation_20_mode` 

874 

875 """ 

876 

877 deprecated_since: Optional[str] = "1.4" 

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

879 

880 def __str__(self) -> str: 

881 return ( 

882 super().__str__() 

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

884 ) 

885 

886 

887class LegacyAPIWarning(Base20DeprecationWarning): 

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

889 

890 

891class MovedIn20Warning(Base20DeprecationWarning): 

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

893 only. 

894 """ 

895 

896 

897class SAPendingDeprecationWarning(PendingDeprecationWarning): 

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

899 is not used in modern versions of SQLAlchemy. 

900 

901 """ 

902 

903 deprecated_since: Optional[str] = None 

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

905 

906 

907class SAWarning(HasDescriptionCode, RuntimeWarning): 

908 """Issued at runtime.""" 

909 

910 _what_are_we = "warning"