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

199 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:35 +0000

1# sqlalchemy/exc.py 

2# Copyright (C) 2005-2023 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 .util import _preloaded 

17from .util import compat 

18 

19_version_token = None 

20 

21 

22class HasDescriptionCode(object): 

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

24 

25 code = None 

26 

27 def __init__(self, *arg, **kw): 

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

29 if code is not None: 

30 self.code = code 

31 super(HasDescriptionCode, self).__init__(*arg, **kw) 

32 

33 def _code_str(self): 

34 if not self.code: 

35 return "" 

36 else: 

37 return ( 

38 "(Background on this error at: " 

39 "https://sqlalche.me/e/%s/%s)" 

40 % ( 

41 _version_token, 

42 self.code, 

43 ) 

44 ) 

45 

46 def __str__(self): 

47 message = super(HasDescriptionCode, self).__str__() 

48 if self.code: 

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

50 return message 

51 

52 

53class SQLAlchemyError(HasDescriptionCode, Exception): 

54 """Generic error class.""" 

55 

56 def _message(self, as_unicode=compat.py3k): 

57 # rules: 

58 # 

59 # 1. under py2k, for __str__ return single string arg as it was 

60 # given without converting to unicode. for __unicode__ 

61 # do a conversion but check that it's not unicode already just in 

62 # case 

63 # 

64 # 2. under py3k, single arg string will usually be a unicode 

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

66 # bytestring just in case 

67 # 

68 # 3. for multiple self.args, this is not a case in current 

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

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

71 # 

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

73 text = self.args[0] 

74 

75 if as_unicode and isinstance(text, compat.binary_types): 

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

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

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

79 # non-string arguments. 

80 elif compat.py3k or not as_unicode: 

81 text = str(text) 

82 else: 

83 text = compat.text_type(text) 

84 

85 return text 

86 else: 

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

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

89 # a repr() of the tuple 

90 return str(self.args) 

91 

92 def _sql_message(self, as_unicode): 

93 message = self._message(as_unicode) 

94 

95 if self.code: 

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

97 

98 return message 

99 

100 def __str__(self): 

101 return self._sql_message(compat.py3k) 

102 

103 def __unicode__(self): 

104 return self._sql_message(as_unicode=True) 

105 

106 

107class ArgumentError(SQLAlchemyError): 

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

109 

110 This error generally corresponds to construction time state errors. 

111 

112 """ 

113 

114 

115class ObjectNotExecutableError(ArgumentError): 

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

117 executed as SQL. 

118 

119 .. versionadded:: 1.1 

120 

121 """ 

122 

123 def __init__(self, target): 

124 super(ObjectNotExecutableError, self).__init__( 

125 "Not an executable object: %r" % target 

126 ) 

127 self.target = target 

128 

129 def __reduce__(self): 

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

131 

132 

133class NoSuchModuleError(ArgumentError): 

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

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

136 

137 

138class NoForeignKeysError(ArgumentError): 

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

140 during a join.""" 

141 

142 

143class AmbiguousForeignKeysError(ArgumentError): 

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

145 between two selectables during a join.""" 

146 

147 

148class CircularDependencyError(SQLAlchemyError): 

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

150 

151 There are two scenarios where this error occurs: 

152 

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

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

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

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

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

158 this cycle. 

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

160 :class:`_schema.ForeignKey` 

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

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

163 see :ref:`use_alter`. 

164 

165 """ 

166 

167 def __init__(self, message, cycles, edges, msg=None, code=None): 

168 if msg is None: 

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

170 else: 

171 message = msg 

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

173 self.cycles = cycles 

174 self.edges = edges 

175 

176 def __reduce__(self): 

177 return ( 

178 self.__class__, 

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

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

181 ) 

182 

183 

184class CompileError(SQLAlchemyError): 

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

186 

187 

188class UnsupportedCompilationError(CompileError): 

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

190 

191 .. seealso:: 

192 

193 :ref:`faq_sql_expression_string` 

194 

195 :ref:`error_l7de` 

196 """ 

197 

198 code = "l7de" 

199 

200 def __init__(self, compiler, element_type, message=None): 

201 super(UnsupportedCompilationError, self).__init__( 

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

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

204 ) 

205 self.compiler = compiler 

206 self.element_type = element_type 

207 self.message = message 

208 

209 def __reduce__(self): 

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

211 

212 

213class IdentifierError(SQLAlchemyError): 

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

215 

216 

217class DisconnectionError(SQLAlchemyError): 

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

219 

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

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

222 event so that the host pool 

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

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

225 regarding the connection attempt. 

226 

227 """ 

228 

229 invalidate_pool = False 

230 

231 

232class InvalidatePoolError(DisconnectionError): 

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

234 

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

236 disconnect situation encountered on the connection probably means the 

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

238 

239 This exception will be handled otherwise the same way as 

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

241 before giving up. 

242 

243 .. versionadded:: 1.2 

244 

245 """ 

246 

247 invalidate_pool = True 

248 

249 

250class TimeoutError(SQLAlchemyError): # noqa 

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

252 

253 

254class InvalidRequestError(SQLAlchemyError): 

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

256 

257 This error generally corresponds to runtime state errors. 

258 

259 """ 

260 

261 

262class NoInspectionAvailable(InvalidRequestError): 

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

264 no context for inspection.""" 

265 

266 

267class PendingRollbackError(InvalidRequestError): 

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

269 continuing. 

270 

271 .. versionadded:: 1.4 

272 

273 """ 

274 

275 

276class ResourceClosedError(InvalidRequestError): 

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

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

279 

280 

281class NoSuchColumnError(InvalidRequestError, KeyError): 

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

283 

284 

285class NoResultFound(InvalidRequestError): 

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

287 

288 

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

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

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

292 

293 

294 """ 

295 

296 

297class MultipleResultsFound(InvalidRequestError): 

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

299 

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

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

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

303 

304 

305 """ 

306 

307 

308class NoReferenceError(InvalidRequestError): 

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

310 

311 

312class AwaitRequired(InvalidRequestError): 

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

314 was awaited when it required one. 

315 

316 """ 

317 

318 code = "xd1r" 

319 

320 

321class MissingGreenlet(InvalidRequestError): 

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

323 the greenlet spawn context. 

324 

325 """ 

326 

327 code = "xd2s" 

328 

329 

330class NoReferencedTableError(NoReferenceError): 

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

332 located. 

333 

334 """ 

335 

336 def __init__(self, message, tname): 

337 NoReferenceError.__init__(self, message) 

338 self.table_name = tname 

339 

340 def __reduce__(self): 

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

342 

343 

344class NoReferencedColumnError(NoReferenceError): 

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

346 located. 

347 

348 """ 

349 

350 def __init__(self, message, tname, cname): 

351 NoReferenceError.__init__(self, message) 

352 self.table_name = tname 

353 self.column_name = cname 

354 

355 def __reduce__(self): 

356 return ( 

357 self.__class__, 

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

359 ) 

360 

361 

362class NoSuchTableError(InvalidRequestError): 

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

364 

365 

366class UnreflectableTableError(InvalidRequestError): 

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

368 

369 .. versionadded:: 1.2 

370 

371 """ 

372 

373 

374class UnboundExecutionError(InvalidRequestError): 

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

376 

377 

378class DontWrapMixin(object): 

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

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

381 emitted within the process of executing a statement. 

382 

383 E.g.:: 

384 

385 from sqlalchemy.exc import DontWrapMixin 

386 

387 class MyCustomException(Exception, DontWrapMixin): 

388 pass 

389 

390 class MySpecialType(TypeDecorator): 

391 impl = String 

392 

393 def process_bind_param(self, value, dialect): 

394 if value == 'invalid': 

395 raise MyCustomException("invalid!") 

396 

397 """ 

398 

399 

400class StatementError(SQLAlchemyError): 

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

402 

403 :class:`StatementError` wraps the exception raised 

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

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

406 the specifics of the statement which had an issue. 

407 

408 The wrapped exception object is available in 

409 the :attr:`.orig` attribute. 

410 

411 """ 

412 

413 statement = None 

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

415 

416 params = None 

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

418 

419 orig = None 

420 """The DBAPI exception object.""" 

421 

422 ismulti = None 

423 

424 def __init__( 

425 self, 

426 message, 

427 statement, 

428 params, 

429 orig, 

430 hide_parameters=False, 

431 code=None, 

432 ismulti=None, 

433 ): 

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

435 self.statement = statement 

436 self.params = params 

437 self.orig = orig 

438 self.ismulti = ismulti 

439 self.hide_parameters = hide_parameters 

440 self.detail = [] 

441 

442 def add_detail(self, msg): 

443 self.detail.append(msg) 

444 

445 def __reduce__(self): 

446 return ( 

447 self.__class__, 

448 ( 

449 self.args[0], 

450 self.statement, 

451 self.params, 

452 self.orig, 

453 self.hide_parameters, 

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

455 self.ismulti, 

456 ), 

457 {"detail": self.detail}, 

458 ) 

459 

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

461 def _sql_message(self, as_unicode): 

462 util = _preloaded.preloaded.sql_util 

463 

464 details = [self._message(as_unicode=as_unicode)] 

465 if self.statement: 

466 if not as_unicode and not compat.py3k: 

467 stmt_detail = "[SQL: %s]" % compat.safe_bytestring( 

468 self.statement 

469 ) 

470 else: 

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

472 details.append(stmt_detail) 

473 if self.params: 

474 if self.hide_parameters: 

475 details.append( 

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

477 ) 

478 else: 

479 params_repr = util._repr_params( 

480 self.params, 10, ismulti=self.ismulti 

481 ) 

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

483 code_str = self._code_str() 

484 if code_str: 

485 details.append(code_str) 

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

487 

488 

489class DBAPIError(StatementError): 

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

491 

492 Wraps exceptions raised by the DB-API underlying the 

493 database operation. Driver-specific implementations of the standard 

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

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

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

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

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

499 

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

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

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

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

504 emitting a SQL statement. 

505 

506 The wrapped exception object is available in the 

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

508 DB-API implementation specific. 

509 

510 """ 

511 

512 code = "dbapi" 

513 

514 @classmethod 

515 def instance( 

516 cls, 

517 statement, 

518 params, 

519 orig, 

520 dbapi_base_err, 

521 hide_parameters=False, 

522 connection_invalidated=False, 

523 dialect=None, 

524 ismulti=None, 

525 ): 

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

527 # DBAPIError didn't exist. 

528 if ( 

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

530 ) or isinstance(orig, DontWrapMixin): 

531 return orig 

532 

533 if orig is not None: 

534 # not a DBAPI error, statement is present. 

535 # raise a StatementError 

536 if isinstance(orig, SQLAlchemyError) and statement: 

537 return StatementError( 

538 "(%s.%s) %s" 

539 % ( 

540 orig.__class__.__module__, 

541 orig.__class__.__name__, 

542 orig.args[0], 

543 ), 

544 statement, 

545 params, 

546 orig, 

547 hide_parameters=hide_parameters, 

548 code=orig.code, 

549 ismulti=ismulti, 

550 ) 

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

552 return StatementError( 

553 "(%s.%s) %s" 

554 % ( 

555 orig.__class__.__module__, 

556 orig.__class__.__name__, 

557 orig, 

558 ), 

559 statement, 

560 params, 

561 orig, 

562 hide_parameters=hide_parameters, 

563 ismulti=ismulti, 

564 ) 

565 

566 glob = globals() 

567 for super_ in orig.__class__.__mro__: 

568 name = super_.__name__ 

569 if dialect: 

570 name = dialect.dbapi_exception_translation_map.get( 

571 name, name 

572 ) 

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

574 cls = glob[name] 

575 break 

576 

577 return cls( 

578 statement, 

579 params, 

580 orig, 

581 connection_invalidated=connection_invalidated, 

582 hide_parameters=hide_parameters, 

583 code=cls.code, 

584 ismulti=ismulti, 

585 ) 

586 

587 def __reduce__(self): 

588 return ( 

589 self.__class__, 

590 ( 

591 self.statement, 

592 self.params, 

593 self.orig, 

594 self.hide_parameters, 

595 self.connection_invalidated, 

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

597 self.ismulti, 

598 ), 

599 {"detail": self.detail}, 

600 ) 

601 

602 def __init__( 

603 self, 

604 statement, 

605 params, 

606 orig, 

607 hide_parameters=False, 

608 connection_invalidated=False, 

609 code=None, 

610 ismulti=None, 

611 ): 

612 try: 

613 text = str(orig) 

614 except Exception as e: 

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

616 StatementError.__init__( 

617 self, 

618 "(%s.%s) %s" 

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

620 statement, 

621 params, 

622 orig, 

623 hide_parameters, 

624 code=code, 

625 ismulti=ismulti, 

626 ) 

627 self.connection_invalidated = connection_invalidated 

628 

629 

630class InterfaceError(DBAPIError): 

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

632 

633 code = "rvf5" 

634 

635 

636class DatabaseError(DBAPIError): 

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

638 

639 code = "4xp6" 

640 

641 

642class DataError(DatabaseError): 

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

644 

645 code = "9h9h" 

646 

647 

648class OperationalError(DatabaseError): 

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

650 

651 code = "e3q8" 

652 

653 

654class IntegrityError(DatabaseError): 

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

656 

657 code = "gkpj" 

658 

659 

660class InternalError(DatabaseError): 

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

662 

663 code = "2j85" 

664 

665 

666class ProgrammingError(DatabaseError): 

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

668 

669 code = "f405" 

670 

671 

672class NotSupportedError(DatabaseError): 

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

674 

675 code = "tw8g" 

676 

677 

678# Warnings 

679 

680 

681class SADeprecationWarning(HasDescriptionCode, DeprecationWarning): 

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

683 

684 deprecated_since = None 

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

686 

687 

688class Base20DeprecationWarning(SADeprecationWarning): 

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

690 SQLAlchemy 2.0. 

691 

692 .. seealso:: 

693 

694 :ref:`error_b8d9`. 

695 

696 :ref:`deprecation_20_mode` 

697 

698 """ 

699 

700 deprecated_since = "1.4" 

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

702 

703 def __str__(self): 

704 return ( 

705 super(Base20DeprecationWarning, self).__str__() 

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

707 ) 

708 

709 

710class LegacyAPIWarning(Base20DeprecationWarning): 

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

712 

713 

714class RemovedIn20Warning(Base20DeprecationWarning): 

715 """indicates an API that will be fully removed in SQLAlchemy 2.0.""" 

716 

717 

718class MovedIn20Warning(RemovedIn20Warning): 

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

720 

721 

722class SAPendingDeprecationWarning(PendingDeprecationWarning): 

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

724 is not used in modern versions of SQLAlchemy. 

725 

726 """ 

727 

728 deprecated_since = None 

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

730 

731 

732class SAWarning(HasDescriptionCode, RuntimeWarning): 

733 """Issued at runtime."""