Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/scoping.py: 56%

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

253 statements  

1# orm/scoping.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 

8from __future__ import annotations 

9 

10from typing import Any 

11from typing import Callable 

12from typing import Dict 

13from typing import Generic 

14from typing import Iterable 

15from typing import Iterator 

16from typing import Optional 

17from typing import overload 

18from typing import Protocol 

19from typing import Sequence 

20from typing import Tuple 

21from typing import Type 

22from typing import TYPE_CHECKING 

23from typing import TypeVar 

24from typing import Union 

25 

26from .session import _S 

27from .session import Session 

28from .. import exc as sa_exc 

29from .. import util 

30from ..util import create_proxy_methods 

31from ..util import ScopedRegistry 

32from ..util import ThreadLocalRegistry 

33from ..util import warn 

34from ..util import warn_deprecated 

35from ..util.typing import TupleAny 

36from ..util.typing import TypeVarTuple 

37from ..util.typing import Unpack 

38 

39if TYPE_CHECKING: 

40 from ._typing import _EntityType 

41 from ._typing import _IdentityKeyType 

42 from ._typing import OrmExecuteOptionsParameter 

43 from .identity import IdentityMap 

44 from .interfaces import ORMOption 

45 from .mapper import Mapper 

46 from .query import Query 

47 from .query import RowReturningQuery 

48 from .session import _BindArguments 

49 from .session import _EntityBindKey 

50 from .session import _PKIdentityArgument 

51 from .session import _SessionBind 

52 from .session import sessionmaker 

53 from .session import SessionTransaction 

54 from ..engine import Connection 

55 from ..engine import Engine 

56 from ..engine import Result 

57 from ..engine import Row 

58 from ..engine import RowMapping 

59 from ..engine.interfaces import _CoreAnyExecuteParams 

60 from ..engine.interfaces import _CoreSingleExecuteParams 

61 from ..engine.interfaces import CoreExecuteOptionsParameter 

62 from ..engine.result import ScalarResult 

63 from ..sql._typing import _ColumnsClauseArgument 

64 from ..sql._typing import _T0 

65 from ..sql._typing import _T1 

66 from ..sql._typing import _T2 

67 from ..sql._typing import _T3 

68 from ..sql._typing import _T4 

69 from ..sql._typing import _T5 

70 from ..sql._typing import _T6 

71 from ..sql._typing import _T7 

72 from ..sql._typing import _TypedColumnClauseArgument as _TCCA 

73 from ..sql.base import Executable 

74 from ..sql.elements import ClauseElement 

75 from ..sql.roles import TypedColumnsClauseRole 

76 from ..sql.selectable import ForUpdateParameter 

77 from ..sql.selectable import TypedReturnsRows 

78 

79 

80_T = TypeVar("_T", bound=Any) 

81_Ts = TypeVarTuple("_Ts") 

82 

83 

84class QueryPropertyDescriptor(Protocol): 

85 """Describes the type applied to a class-level 

86 :meth:`_orm.scoped_session.query_property` attribute. 

87 

88 .. versionadded:: 2.0.5 

89 

90 """ 

91 

92 def __get__(self, instance: Any, owner: Type[_T]) -> Query[_T]: ... 

93 

94 

95_O = TypeVar("_O", bound=object) 

96 

97__all__ = ["scoped_session"] 

98 

99 

100@create_proxy_methods( 

101 Session, 

102 ":class:`_orm.Session`", 

103 ":class:`_orm.scoping.scoped_session`", 

104 classmethods=["object_session", "identity_key"], 

105 methods=[ 

106 "__contains__", 

107 "__iter__", 

108 "add", 

109 "add_all", 

110 "begin", 

111 "begin_nested", 

112 "close", 

113 "reset", 

114 "commit", 

115 "connection", 

116 "delete", 

117 "delete_all", 

118 "execute", 

119 "expire", 

120 "expire_all", 

121 "expunge", 

122 "expunge_all", 

123 "flush", 

124 "get", 

125 "get_one", 

126 "get_bind", 

127 "is_modified", 

128 "bulk_save_objects", 

129 "bulk_insert_mappings", 

130 "bulk_update_mappings", 

131 "merge", 

132 "merge_all", 

133 "query", 

134 "refresh", 

135 "rollback", 

136 "scalar", 

137 "scalars", 

138 ], 

139 attributes=[ 

140 "bind", 

141 "dirty", 

142 "deleted", 

143 "new", 

144 "identity_map", 

145 "is_active", 

146 "autoflush", 

147 "no_autoflush", 

148 "info", 

149 ], 

150) 

151class scoped_session(Generic[_S]): 

152 """Provides scoped management of :class:`.Session` objects. 

153 

154 See :ref:`unitofwork_contextual` for a tutorial. 

155 

156 .. note:: 

157 

158 When using :ref:`asyncio_toplevel`, the async-compatible 

159 :class:`_asyncio.async_scoped_session` class should be 

160 used in place of :class:`.scoped_session`. 

161 

162 """ 

163 

164 _support_async: bool = False 

165 

166 session_factory: sessionmaker[_S] 

167 """The `session_factory` provided to `__init__` is stored in this 

168 attribute and may be accessed at a later time. This can be useful when 

169 a new non-scoped :class:`.Session` is needed.""" 

170 

171 registry: ScopedRegistry[_S] 

172 

173 def __init__( 

174 self, 

175 session_factory: sessionmaker[_S], 

176 scopefunc: Optional[Callable[[], Any]] = None, 

177 ): 

178 """Construct a new :class:`.scoped_session`. 

179 

180 :param session_factory: a factory to create new :class:`.Session` 

181 instances. This is usually, but not necessarily, an instance 

182 of :class:`.sessionmaker`. 

183 :param scopefunc: optional function which defines 

184 the current scope. If not passed, the :class:`.scoped_session` 

185 object assumes "thread-local" scope, and will use 

186 a Python ``threading.local()`` in order to maintain the current 

187 :class:`.Session`. If passed, the function should return 

188 a hashable token; this token will be used as the key in a 

189 dictionary in order to store and retrieve the current 

190 :class:`.Session`. 

191 

192 """ 

193 self.session_factory = session_factory 

194 

195 if scopefunc: 

196 self.registry = ScopedRegistry(session_factory, scopefunc) 

197 else: 

198 self.registry = ThreadLocalRegistry(session_factory) 

199 

200 @property 

201 def _proxied(self) -> _S: 

202 return self.registry() 

203 

204 def __call__(self, **kw: Any) -> _S: 

205 r"""Return the current :class:`.Session`, creating it 

206 using the :attr:`.scoped_session.session_factory` if not present. 

207 

208 :param \**kw: Keyword arguments will be passed to the 

209 :attr:`.scoped_session.session_factory` callable, if an existing 

210 :class:`.Session` is not present. If the :class:`.Session` is present 

211 and keyword arguments have been passed, 

212 :exc:`~sqlalchemy.exc.InvalidRequestError` is raised. 

213 

214 """ 

215 if kw: 

216 if self.registry.has(): 

217 raise sa_exc.InvalidRequestError( 

218 "Scoped session is already present; " 

219 "no new arguments may be specified." 

220 ) 

221 else: 

222 sess = self.session_factory(**kw) 

223 self.registry.set(sess) 

224 else: 

225 sess = self.registry() 

226 if not self._support_async and sess._is_asyncio: 

227 warn_deprecated( 

228 "Using `scoped_session` with asyncio is deprecated and " 

229 "will raise an error in a future version. " 

230 "Please use `async_scoped_session` instead.", 

231 "1.4.23", 

232 ) 

233 return sess 

234 

235 def configure(self, **kwargs: Any) -> None: 

236 """reconfigure the :class:`.sessionmaker` used by this 

237 :class:`.scoped_session`. 

238 

239 See :meth:`.sessionmaker.configure`. 

240 

241 """ 

242 

243 if self.registry.has(): 

244 warn( 

245 "At least one scoped session is already present. " 

246 " configure() can not affect sessions that have " 

247 "already been created." 

248 ) 

249 

250 self.session_factory.configure(**kwargs) 

251 

252 def remove(self) -> None: 

253 """Dispose of the current :class:`.Session`, if present. 

254 

255 This will first call :meth:`.Session.close` method 

256 on the current :class:`.Session`, which releases any existing 

257 transactional/connection resources still being held; transactions 

258 specifically are rolled back. The :class:`.Session` is then 

259 discarded. Upon next usage within the same scope, 

260 the :class:`.scoped_session` will produce a new 

261 :class:`.Session` object. 

262 

263 """ 

264 

265 if self.registry.has(): 

266 self.registry().close() 

267 self.registry.clear() 

268 

269 def query_property( 

270 self, query_cls: Optional[Type[Query[_T]]] = None 

271 ) -> QueryPropertyDescriptor: 

272 """return a class property which produces a legacy 

273 :class:`_query.Query` object against the class and the current 

274 :class:`.Session` when called. 

275 

276 .. legacy:: The :meth:`_orm.scoped_session.query_property` accessor 

277 is specific to the legacy :class:`.Query` object and is not 

278 considered to be part of :term:`2.0-style` ORM use. 

279 

280 e.g.:: 

281 

282 from sqlalchemy.orm import QueryPropertyDescriptor 

283 from sqlalchemy.orm import scoped_session 

284 from sqlalchemy.orm import sessionmaker 

285 

286 Session = scoped_session(sessionmaker()) 

287 

288 

289 class MyClass: 

290 query: QueryPropertyDescriptor = Session.query_property() 

291 

292 

293 # after mappers are defined 

294 result = MyClass.query.filter(MyClass.name == "foo").all() 

295 

296 Produces instances of the session's configured query class by 

297 default. To override and use a custom implementation, provide 

298 a ``query_cls`` callable. The callable will be invoked with 

299 the class's mapper as a positional argument and a session 

300 keyword argument. 

301 

302 There is no limit to the number of query properties placed on 

303 a class. 

304 

305 """ 

306 

307 class query: 

308 def __get__(s, instance: Any, owner: Type[_O]) -> Query[_O]: 

309 if query_cls: 

310 # custom query class 

311 return query_cls(owner, session=self.registry()) # type: ignore # noqa: E501 

312 else: 

313 # session's configured query class 

314 return self.registry().query(owner) 

315 

316 return query() 

317 

318 # START PROXY METHODS scoped_session 

319 

320 # code within this block is **programmatically, 

321 # statically generated** by tools/generate_proxy_methods.py 

322 

323 def __contains__(self, instance: object) -> bool: 

324 r"""Return True if the instance is associated with this session. 

325 

326 .. container:: class_bases 

327 

328 Proxied for the :class:`_orm.Session` class on 

329 behalf of the :class:`_orm.scoping.scoped_session` class. 

330 

331 The instance may be pending or persistent within the Session for a 

332 result of True. 

333 

334 

335 """ # noqa: E501 

336 

337 return self._proxied.__contains__(instance) 

338 

339 def __iter__(self) -> Iterator[object]: 

340 r"""Iterate over all pending or persistent instances within this 

341 Session. 

342 

343 .. container:: class_bases 

344 

345 Proxied for the :class:`_orm.Session` class on 

346 behalf of the :class:`_orm.scoping.scoped_session` class. 

347 

348 

349 """ # noqa: E501 

350 

351 return self._proxied.__iter__() 

352 

353 def add(self, instance: object, *, _warn: bool = True) -> None: 

354 r"""Place an object into this :class:`_orm.Session`. 

355 

356 .. container:: class_bases 

357 

358 Proxied for the :class:`_orm.Session` class on 

359 behalf of the :class:`_orm.scoping.scoped_session` class. 

360 

361 Objects that are in the :term:`transient` state when passed to the 

362 :meth:`_orm.Session.add` method will move to the 

363 :term:`pending` state, until the next flush, at which point they 

364 will move to the :term:`persistent` state. 

365 

366 Objects that are in the :term:`detached` state when passed to the 

367 :meth:`_orm.Session.add` method will move to the :term:`persistent` 

368 state directly. 

369 

370 If the transaction used by the :class:`_orm.Session` is rolled back, 

371 objects which were transient when they were passed to 

372 :meth:`_orm.Session.add` will be moved back to the 

373 :term:`transient` state, and will no longer be present within this 

374 :class:`_orm.Session`. 

375 

376 .. seealso:: 

377 

378 :meth:`_orm.Session.add_all` 

379 

380 :ref:`session_adding` - at :ref:`session_basics` 

381 

382 

383 """ # noqa: E501 

384 

385 return self._proxied.add(instance, _warn=_warn) 

386 

387 def add_all(self, instances: Iterable[object]) -> None: 

388 r"""Add the given collection of instances to this :class:`_orm.Session`. 

389 

390 .. container:: class_bases 

391 

392 Proxied for the :class:`_orm.Session` class on 

393 behalf of the :class:`_orm.scoping.scoped_session` class. 

394 

395 See the documentation for :meth:`_orm.Session.add` for a general 

396 behavioral description. 

397 

398 .. seealso:: 

399 

400 :meth:`_orm.Session.add` 

401 

402 :ref:`session_adding` - at :ref:`session_basics` 

403 

404 

405 """ # noqa: E501 

406 

407 return self._proxied.add_all(instances) 

408 

409 def begin(self, nested: bool = False) -> SessionTransaction: 

410 r"""Begin a transaction, or nested transaction, 

411 on this :class:`.Session`, if one is not already begun. 

412 

413 .. container:: class_bases 

414 

415 Proxied for the :class:`_orm.Session` class on 

416 behalf of the :class:`_orm.scoping.scoped_session` class. 

417 

418 The :class:`_orm.Session` object features **autobegin** behavior, 

419 so that normally it is not necessary to call the 

420 :meth:`_orm.Session.begin` 

421 method explicitly. However, it may be used in order to control 

422 the scope of when the transactional state is begun. 

423 

424 When used to begin the outermost transaction, an error is raised 

425 if this :class:`.Session` is already inside of a transaction. 

426 

427 :param nested: if True, begins a SAVEPOINT transaction and is 

428 equivalent to calling :meth:`~.Session.begin_nested`. For 

429 documentation on SAVEPOINT transactions, please see 

430 :ref:`session_begin_nested`. 

431 

432 :return: the :class:`.SessionTransaction` object. Note that 

433 :class:`.SessionTransaction` 

434 acts as a Python context manager, allowing :meth:`.Session.begin` 

435 to be used in a "with" block. See :ref:`session_explicit_begin` for 

436 an example. 

437 

438 .. seealso:: 

439 

440 :ref:`session_autobegin` 

441 

442 :ref:`unitofwork_transaction` 

443 

444 :meth:`.Session.begin_nested` 

445 

446 

447 

448 """ # noqa: E501 

449 

450 return self._proxied.begin(nested=nested) 

451 

452 def begin_nested(self) -> SessionTransaction: 

453 r"""Begin a "nested" transaction on this Session, e.g. SAVEPOINT. 

454 

455 .. container:: class_bases 

456 

457 Proxied for the :class:`_orm.Session` class on 

458 behalf of the :class:`_orm.scoping.scoped_session` class. 

459 

460 The target database(s) and associated drivers must support SQL 

461 SAVEPOINT for this method to function correctly. 

462 

463 For documentation on SAVEPOINT 

464 transactions, please see :ref:`session_begin_nested`. 

465 

466 :return: the :class:`.SessionTransaction` object. Note that 

467 :class:`.SessionTransaction` acts as a context manager, allowing 

468 :meth:`.Session.begin_nested` to be used in a "with" block. 

469 See :ref:`session_begin_nested` for a usage example. 

470 

471 .. seealso:: 

472 

473 :ref:`session_begin_nested` 

474 

475 :ref:`pysqlite_serializable` - special workarounds required 

476 with the SQLite driver in order for SAVEPOINT to work 

477 correctly. For asyncio use cases, see the section 

478 :ref:`aiosqlite_serializable`. 

479 

480 

481 """ # noqa: E501 

482 

483 return self._proxied.begin_nested() 

484 

485 def close(self) -> None: 

486 r"""Close out the transactional resources and ORM objects used by this 

487 :class:`_orm.Session`. 

488 

489 .. container:: class_bases 

490 

491 Proxied for the :class:`_orm.Session` class on 

492 behalf of the :class:`_orm.scoping.scoped_session` class. 

493 

494 This expunges all ORM objects associated with this 

495 :class:`_orm.Session`, ends any transaction in progress and 

496 :term:`releases` any :class:`_engine.Connection` objects which this 

497 :class:`_orm.Session` itself has checked out from associated 

498 :class:`_engine.Engine` objects. The operation then leaves the 

499 :class:`_orm.Session` in a state which it may be used again. 

500 

501 .. tip:: 

502 

503 In the default running mode the :meth:`_orm.Session.close` 

504 method **does not prevent the Session from being used again**. 

505 The :class:`_orm.Session` itself does not actually have a 

506 distinct "closed" state; it merely means 

507 the :class:`_orm.Session` will release all database connections 

508 and ORM objects. 

509 

510 Setting the parameter :paramref:`_orm.Session.close_resets_only` 

511 to ``False`` will instead make the ``close`` final, meaning that 

512 any further action on the session will be forbidden. 

513 

514 .. versionchanged:: 1.4 The :meth:`.Session.close` method does not 

515 immediately create a new :class:`.SessionTransaction` object; 

516 instead, the new :class:`.SessionTransaction` is created only if 

517 the :class:`.Session` is used again for a database operation. 

518 

519 .. seealso:: 

520 

521 :ref:`session_closing` - detail on the semantics of 

522 :meth:`_orm.Session.close` and :meth:`_orm.Session.reset`. 

523 

524 :meth:`_orm.Session.reset` - a similar method that behaves like 

525 ``close()`` with the parameter 

526 :paramref:`_orm.Session.close_resets_only` set to ``True``. 

527 

528 

529 """ # noqa: E501 

530 

531 return self._proxied.close() 

532 

533 def reset(self) -> None: 

534 r"""Close out the transactional resources and ORM objects used by this 

535 :class:`_orm.Session`, resetting the session to its initial state. 

536 

537 .. container:: class_bases 

538 

539 Proxied for the :class:`_orm.Session` class on 

540 behalf of the :class:`_orm.scoping.scoped_session` class. 

541 

542 This method provides for same "reset-only" behavior that the 

543 :meth:`_orm.Session.close` method has provided historically, where the 

544 state of the :class:`_orm.Session` is reset as though the object were 

545 brand new, and ready to be used again. 

546 This method may then be useful for :class:`_orm.Session` objects 

547 which set :paramref:`_orm.Session.close_resets_only` to ``False``, 

548 so that "reset only" behavior is still available. 

549 

550 .. versionadded:: 2.0.22 

551 

552 .. seealso:: 

553 

554 :ref:`session_closing` - detail on the semantics of 

555 :meth:`_orm.Session.close` and :meth:`_orm.Session.reset`. 

556 

557 :meth:`_orm.Session.close` - a similar method will additionally 

558 prevent re-use of the Session when the parameter 

559 :paramref:`_orm.Session.close_resets_only` is set to ``False``. 

560 

561 """ # noqa: E501 

562 

563 return self._proxied.reset() 

564 

565 def commit(self) -> None: 

566 r"""Flush pending changes and commit the current transaction. 

567 

568 .. container:: class_bases 

569 

570 Proxied for the :class:`_orm.Session` class on 

571 behalf of the :class:`_orm.scoping.scoped_session` class. 

572 

573 When the COMMIT operation is complete, all objects are fully 

574 :term:`expired`, erasing their internal contents, which will be 

575 automatically re-loaded when the objects are next accessed. In the 

576 interim, these objects are in an expired state and will not function if 

577 they are :term:`detached` from the :class:`.Session`. Additionally, 

578 this re-load operation is not supported when using asyncio-oriented 

579 APIs. The :paramref:`.Session.expire_on_commit` parameter may be used 

580 to disable this behavior. 

581 

582 When there is no transaction in place for the :class:`.Session`, 

583 indicating that no operations were invoked on this :class:`.Session` 

584 since the previous call to :meth:`.Session.commit`, the method will 

585 begin and commit an internal-only "logical" transaction, that does not 

586 normally affect the database unless pending flush changes were 

587 detected, but will still invoke event handlers and object expiration 

588 rules. 

589 

590 The outermost database transaction is committed unconditionally, 

591 automatically releasing any SAVEPOINTs in effect. 

592 

593 .. seealso:: 

594 

595 :ref:`session_committing` 

596 

597 :ref:`unitofwork_transaction` 

598 

599 :ref:`asyncio_orm_avoid_lazyloads` 

600 

601 

602 """ # noqa: E501 

603 

604 return self._proxied.commit() 

605 

606 def connection( 

607 self, 

608 bind_arguments: Optional[_BindArguments] = None, 

609 execution_options: Optional[CoreExecuteOptionsParameter] = None, 

610 ) -> Connection: 

611 r"""Return a :class:`_engine.Connection` object corresponding to this 

612 :class:`.Session` object's transactional state. 

613 

614 .. container:: class_bases 

615 

616 Proxied for the :class:`_orm.Session` class on 

617 behalf of the :class:`_orm.scoping.scoped_session` class. 

618 

619 Either the :class:`_engine.Connection` corresponding to the current 

620 transaction is returned, or if no transaction is in progress, a new 

621 one is begun and the :class:`_engine.Connection` 

622 returned (note that no 

623 transactional state is established with the DBAPI until the first 

624 SQL statement is emitted). 

625 

626 Ambiguity in multi-bind or unbound :class:`.Session` objects can be 

627 resolved through any of the optional keyword arguments. This 

628 ultimately makes usage of the :meth:`.get_bind` method for resolution. 

629 

630 :param bind_arguments: dictionary of bind arguments. May include 

631 "mapper", "bind", "clause", other custom arguments that are passed 

632 to :meth:`.Session.get_bind`. 

633 

634 :param execution_options: a dictionary of execution options that will 

635 be passed to :meth:`_engine.Connection.execution_options`, **when the 

636 connection is first procured only**. If the connection is already 

637 present within the :class:`.Session`, a warning is emitted and 

638 the arguments are ignored. 

639 

640 .. seealso:: 

641 

642 :ref:`session_transaction_isolation` 

643 

644 

645 """ # noqa: E501 

646 

647 return self._proxied.connection( 

648 bind_arguments=bind_arguments, execution_options=execution_options 

649 ) 

650 

651 def delete(self, instance: object) -> None: 

652 r"""Mark an instance as deleted. 

653 

654 .. container:: class_bases 

655 

656 Proxied for the :class:`_orm.Session` class on 

657 behalf of the :class:`_orm.scoping.scoped_session` class. 

658 

659 The object is assumed to be either :term:`persistent` or 

660 :term:`detached` when passed; after the method is called, the 

661 object will remain in the :term:`persistent` state until the next 

662 flush proceeds. During this time, the object will also be a member 

663 of the :attr:`_orm.Session.deleted` collection. 

664 

665 When the next flush proceeds, the object will move to the 

666 :term:`deleted` state, indicating a ``DELETE`` statement was emitted 

667 for its row within the current transaction. When the transaction 

668 is successfully committed, 

669 the deleted object is moved to the :term:`detached` state and is 

670 no longer present within this :class:`_orm.Session`. 

671 

672 .. seealso:: 

673 

674 :ref:`session_deleting` - at :ref:`session_basics` 

675 

676 :meth:`.Session.delete_all` - multiple instance version 

677 

678 

679 """ # noqa: E501 

680 

681 return self._proxied.delete(instance) 

682 

683 def delete_all(self, instances: Iterable[object]) -> None: 

684 r"""Calls :meth:`.Session.delete` on multiple instances. 

685 

686 .. container:: class_bases 

687 

688 Proxied for the :class:`_orm.Session` class on 

689 behalf of the :class:`_orm.scoping.scoped_session` class. 

690 

691 .. seealso:: 

692 

693 :meth:`.Session.delete` - main documentation on delete 

694 

695 .. versionadded:: 2.1 

696 

697 

698 """ # noqa: E501 

699 

700 return self._proxied.delete_all(instances) 

701 

702 @overload 

703 def execute( 

704 self, 

705 statement: TypedReturnsRows[Unpack[_Ts]], 

706 params: Optional[_CoreAnyExecuteParams] = None, 

707 *, 

708 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, 

709 bind_arguments: Optional[_BindArguments] = None, 

710 _parent_execute_state: Optional[Any] = None, 

711 _add_event: Optional[Any] = None, 

712 ) -> Result[Unpack[_Ts]]: ... 

713 

714 @overload 

715 def execute( 

716 self, 

717 statement: Executable, 

718 params: Optional[_CoreAnyExecuteParams] = None, 

719 *, 

720 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, 

721 bind_arguments: Optional[_BindArguments] = None, 

722 _parent_execute_state: Optional[Any] = None, 

723 _add_event: Optional[Any] = None, 

724 ) -> Result[Unpack[TupleAny]]: ... 

725 

726 def execute( 

727 self, 

728 statement: Executable, 

729 params: Optional[_CoreAnyExecuteParams] = None, 

730 *, 

731 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, 

732 bind_arguments: Optional[_BindArguments] = None, 

733 _parent_execute_state: Optional[Any] = None, 

734 _add_event: Optional[Any] = None, 

735 ) -> Result[Unpack[TupleAny]]: 

736 r"""Execute a SQL expression construct. 

737 

738 .. container:: class_bases 

739 

740 Proxied for the :class:`_orm.Session` class on 

741 behalf of the :class:`_orm.scoping.scoped_session` class. 

742 

743 Returns a :class:`_engine.Result` object representing 

744 results of the statement execution. 

745 

746 E.g.:: 

747 

748 from sqlalchemy import select 

749 

750 result = session.execute(select(User).where(User.id == 5)) 

751 

752 The API contract of :meth:`_orm.Session.execute` is similar to that 

753 of :meth:`_engine.Connection.execute`, the :term:`2.0 style` version 

754 of :class:`_engine.Connection`. 

755 

756 .. versionchanged:: 1.4 the :meth:`_orm.Session.execute` method is 

757 now the primary point of ORM statement execution when using 

758 :term:`2.0 style` ORM usage. 

759 

760 :param statement: 

761 An executable statement (i.e. an :class:`.Executable` expression 

762 such as :func:`_expression.select`). 

763 

764 :param params: 

765 Optional dictionary, or list of dictionaries, containing 

766 bound parameter values. If a single dictionary, single-row 

767 execution occurs; if a list of dictionaries, an 

768 "executemany" will be invoked. The keys in each dictionary 

769 must correspond to parameter names present in the statement. 

770 

771 :param execution_options: optional dictionary of execution options, 

772 which will be associated with the statement execution. This 

773 dictionary can provide a subset of the options that are accepted 

774 by :meth:`_engine.Connection.execution_options`, and may also 

775 provide additional options understood only in an ORM context. 

776 

777 .. seealso:: 

778 

779 :ref:`orm_queryguide_execution_options` - ORM-specific execution 

780 options 

781 

782 :param bind_arguments: dictionary of additional arguments to determine 

783 the bind. May include "mapper", "bind", or other custom arguments. 

784 Contents of this dictionary are passed to the 

785 :meth:`.Session.get_bind` method. 

786 

787 :return: a :class:`_engine.Result` object. 

788 

789 

790 

791 """ # noqa: E501 

792 

793 return self._proxied.execute( 

794 statement, 

795 params=params, 

796 execution_options=execution_options, 

797 bind_arguments=bind_arguments, 

798 _parent_execute_state=_parent_execute_state, 

799 _add_event=_add_event, 

800 ) 

801 

802 def expire( 

803 self, instance: object, attribute_names: Optional[Iterable[str]] = None 

804 ) -> None: 

805 r"""Expire the attributes on an instance. 

806 

807 .. container:: class_bases 

808 

809 Proxied for the :class:`_orm.Session` class on 

810 behalf of the :class:`_orm.scoping.scoped_session` class. 

811 

812 Marks the attributes of an instance as out of date. When an expired 

813 attribute is next accessed, a query will be issued to the 

814 :class:`.Session` object's current transactional context in order to 

815 load all expired attributes for the given instance. Note that 

816 a highly isolated transaction will return the same values as were 

817 previously read in that same transaction, regardless of changes 

818 in database state outside of that transaction. 

819 

820 To expire all objects in the :class:`.Session` simultaneously, 

821 use :meth:`Session.expire_all`. 

822 

823 The :class:`.Session` object's default behavior is to 

824 expire all state whenever the :meth:`Session.rollback` 

825 or :meth:`Session.commit` methods are called, so that new 

826 state can be loaded for the new transaction. For this reason, 

827 calling :meth:`Session.expire` only makes sense for the specific 

828 case that a non-ORM SQL statement was emitted in the current 

829 transaction. 

830 

831 :param instance: The instance to be refreshed. 

832 :param attribute_names: optional list of string attribute names 

833 indicating a subset of attributes to be expired. 

834 

835 .. seealso:: 

836 

837 :ref:`session_expire` - introductory material 

838 

839 :meth:`.Session.expire` 

840 

841 :meth:`.Session.refresh` 

842 

843 :meth:`_orm.Query.populate_existing` 

844 

845 

846 """ # noqa: E501 

847 

848 return self._proxied.expire(instance, attribute_names=attribute_names) 

849 

850 def expire_all(self) -> None: 

851 r"""Expires all persistent instances within this Session. 

852 

853 .. container:: class_bases 

854 

855 Proxied for the :class:`_orm.Session` class on 

856 behalf of the :class:`_orm.scoping.scoped_session` class. 

857 

858 When any attributes on a persistent instance is next accessed, 

859 a query will be issued using the 

860 :class:`.Session` object's current transactional context in order to 

861 load all expired attributes for the given instance. Note that 

862 a highly isolated transaction will return the same values as were 

863 previously read in that same transaction, regardless of changes 

864 in database state outside of that transaction. 

865 

866 To expire individual objects and individual attributes 

867 on those objects, use :meth:`Session.expire`. 

868 

869 The :class:`.Session` object's default behavior is to 

870 expire all state whenever the :meth:`Session.rollback` 

871 or :meth:`Session.commit` methods are called, so that new 

872 state can be loaded for the new transaction. For this reason, 

873 calling :meth:`Session.expire_all` is not usually needed, 

874 assuming the transaction is isolated. 

875 

876 .. seealso:: 

877 

878 :ref:`session_expire` - introductory material 

879 

880 :meth:`.Session.expire` 

881 

882 :meth:`.Session.refresh` 

883 

884 :meth:`_orm.Query.populate_existing` 

885 

886 

887 """ # noqa: E501 

888 

889 return self._proxied.expire_all() 

890 

891 def expunge(self, instance: object) -> None: 

892 r"""Remove the `instance` from this ``Session``. 

893 

894 .. container:: class_bases 

895 

896 Proxied for the :class:`_orm.Session` class on 

897 behalf of the :class:`_orm.scoping.scoped_session` class. 

898 

899 This will free all internal references to the instance. Cascading 

900 will be applied according to the *expunge* cascade rule. 

901 

902 

903 """ # noqa: E501 

904 

905 return self._proxied.expunge(instance) 

906 

907 def expunge_all(self) -> None: 

908 r"""Remove all object instances from this ``Session``. 

909 

910 .. container:: class_bases 

911 

912 Proxied for the :class:`_orm.Session` class on 

913 behalf of the :class:`_orm.scoping.scoped_session` class. 

914 

915 This is equivalent to calling ``expunge(obj)`` on all objects in this 

916 ``Session``. 

917 

918 

919 """ # noqa: E501 

920 

921 return self._proxied.expunge_all() 

922 

923 def flush(self, objects: Optional[Sequence[Any]] = None) -> None: 

924 r"""Flush all the object changes to the database. 

925 

926 .. container:: class_bases 

927 

928 Proxied for the :class:`_orm.Session` class on 

929 behalf of the :class:`_orm.scoping.scoped_session` class. 

930 

931 Writes out all pending object creations, deletions and modifications 

932 to the database as INSERTs, DELETEs, UPDATEs, etc. Operations are 

933 automatically ordered by the Session's unit of work dependency 

934 solver. 

935 

936 Database operations will be issued in the current transactional 

937 context and do not affect the state of the transaction, unless an 

938 error occurs, in which case the entire transaction is rolled back. 

939 You may flush() as often as you like within a transaction to move 

940 changes from Python to the database's transaction buffer. 

941 

942 :param objects: Optional; restricts the flush operation to operate 

943 only on elements that are in the given collection. 

944 

945 This feature is for an extremely narrow set of use cases where 

946 particular objects may need to be operated upon before the 

947 full flush() occurs. It is not intended for general use. 

948 

949 .. deprecated:: 2.1 

950 

951 

952 """ # noqa: E501 

953 

954 return self._proxied.flush(objects=objects) 

955 

956 def get( 

957 self, 

958 entity: _EntityBindKey[_O], 

959 ident: _PKIdentityArgument, 

960 *, 

961 options: Optional[Sequence[ORMOption]] = None, 

962 populate_existing: bool = False, 

963 with_for_update: ForUpdateParameter = None, 

964 identity_token: Optional[Any] = None, 

965 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, 

966 bind_arguments: Optional[_BindArguments] = None, 

967 ) -> Optional[_O]: 

968 r"""Return an instance based on the given primary key identifier, 

969 or ``None`` if not found. 

970 

971 .. container:: class_bases 

972 

973 Proxied for the :class:`_orm.Session` class on 

974 behalf of the :class:`_orm.scoping.scoped_session` class. 

975 

976 E.g.:: 

977 

978 my_user = session.get(User, 5) 

979 

980 some_object = session.get(VersionedFoo, (5, 10)) 

981 

982 some_object = session.get(VersionedFoo, {"id": 5, "version_id": 10}) 

983 

984 .. versionadded:: 1.4 Added :meth:`_orm.Session.get`, which is moved 

985 from the now legacy :meth:`_orm.Query.get` method. 

986 

987 :meth:`_orm.Session.get` is special in that it provides direct 

988 access to the identity map of the :class:`.Session`. 

989 If the given primary key identifier is present 

990 in the local identity map, the object is returned 

991 directly from this collection and no SQL is emitted, 

992 unless the object has been marked fully expired. 

993 If not present, 

994 a SELECT is performed in order to locate the object. 

995 

996 :meth:`_orm.Session.get` also will perform a check if 

997 the object is present in the identity map and 

998 marked as expired - a SELECT 

999 is emitted to refresh the object as well as to 

1000 ensure that the row is still present. 

1001 If not, :class:`~sqlalchemy.orm.exc.ObjectDeletedError` is raised. 

1002 

1003 :param entity: a mapped class or :class:`.Mapper` indicating the 

1004 type of entity to be loaded. 

1005 

1006 :param ident: A scalar, tuple, or dictionary representing the 

1007 primary key. For a composite (e.g. multiple column) primary key, 

1008 a tuple or dictionary should be passed. 

1009 

1010 For a single-column primary key, the scalar calling form is typically 

1011 the most expedient. If the primary key of a row is the value "5", 

1012 the call looks like:: 

1013 

1014 my_object = session.get(SomeClass, 5) 

1015 

1016 The tuple form contains primary key values typically in 

1017 the order in which they correspond to the mapped 

1018 :class:`_schema.Table` 

1019 object's primary key columns, or if the 

1020 :paramref:`_orm.Mapper.primary_key` configuration parameter were 

1021 used, in 

1022 the order used for that parameter. For example, if the primary key 

1023 of a row is represented by the integer 

1024 digits "5, 10" the call would look like:: 

1025 

1026 my_object = session.get(SomeClass, (5, 10)) 

1027 

1028 The dictionary form should include as keys the mapped attribute names 

1029 corresponding to each element of the primary key. If the mapped class 

1030 has the attributes ``id``, ``version_id`` as the attributes which 

1031 store the object's primary key value, the call would look like:: 

1032 

1033 my_object = session.get(SomeClass, {"id": 5, "version_id": 10}) 

1034 

1035 :param options: optional sequence of loader options which will be 

1036 applied to the query, if one is emitted. 

1037 

1038 :param populate_existing: causes the method to unconditionally emit 

1039 a SQL query and refresh the object with the newly loaded data, 

1040 regardless of whether or not the object is already present. 

1041 

1042 :param with_for_update: optional boolean ``True`` indicating FOR UPDATE 

1043 should be used, or may be a dictionary containing flags to 

1044 indicate a more specific set of FOR UPDATE flags for the SELECT; 

1045 flags should match the parameters of 

1046 :meth:`_query.Query.with_for_update`. 

1047 Supersedes the :paramref:`.Session.refresh.lockmode` parameter. 

1048 

1049 :param execution_options: optional dictionary of execution options, 

1050 which will be associated with the query execution if one is emitted. 

1051 This dictionary can provide a subset of the options that are 

1052 accepted by :meth:`_engine.Connection.execution_options`, and may 

1053 also provide additional options understood only in an ORM context. 

1054 

1055 .. versionadded:: 1.4.29 

1056 

1057 .. seealso:: 

1058 

1059 :ref:`orm_queryguide_execution_options` - ORM-specific execution 

1060 options 

1061 

1062 :param bind_arguments: dictionary of additional arguments to determine 

1063 the bind. May include "mapper", "bind", or other custom arguments. 

1064 Contents of this dictionary are passed to the 

1065 :meth:`.Session.get_bind` method. 

1066 

1067 .. versionadded:: 2.0.0rc1 

1068 

1069 :return: The object instance, or ``None``. 

1070 

1071 

1072 """ # noqa: E501 

1073 

1074 return self._proxied.get( 

1075 entity, 

1076 ident, 

1077 options=options, 

1078 populate_existing=populate_existing, 

1079 with_for_update=with_for_update, 

1080 identity_token=identity_token, 

1081 execution_options=execution_options, 

1082 bind_arguments=bind_arguments, 

1083 ) 

1084 

1085 def get_one( 

1086 self, 

1087 entity: _EntityBindKey[_O], 

1088 ident: _PKIdentityArgument, 

1089 *, 

1090 options: Optional[Sequence[ORMOption]] = None, 

1091 populate_existing: bool = False, 

1092 with_for_update: ForUpdateParameter = None, 

1093 identity_token: Optional[Any] = None, 

1094 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, 

1095 bind_arguments: Optional[_BindArguments] = None, 

1096 ) -> _O: 

1097 r"""Return exactly one instance based on the given primary key 

1098 identifier, or raise an exception if not found. 

1099 

1100 .. container:: class_bases 

1101 

1102 Proxied for the :class:`_orm.Session` class on 

1103 behalf of the :class:`_orm.scoping.scoped_session` class. 

1104 

1105 Raises :class:`_exc.NoResultFound` if the query selects no rows. 

1106 

1107 For a detailed documentation of the arguments see the 

1108 method :meth:`.Session.get`. 

1109 

1110 .. versionadded:: 2.0.22 

1111 

1112 :return: The object instance. 

1113 

1114 .. seealso:: 

1115 

1116 :meth:`.Session.get` - equivalent method that instead 

1117 returns ``None`` if no row was found with the provided primary 

1118 key 

1119 

1120 

1121 """ # noqa: E501 

1122 

1123 return self._proxied.get_one( 

1124 entity, 

1125 ident, 

1126 options=options, 

1127 populate_existing=populate_existing, 

1128 with_for_update=with_for_update, 

1129 identity_token=identity_token, 

1130 execution_options=execution_options, 

1131 bind_arguments=bind_arguments, 

1132 ) 

1133 

1134 def get_bind( 

1135 self, 

1136 mapper: Optional[_EntityBindKey[_O]] = None, 

1137 *, 

1138 clause: Optional[ClauseElement] = None, 

1139 bind: Optional[_SessionBind] = None, 

1140 _sa_skip_events: Optional[bool] = None, 

1141 _sa_skip_for_implicit_returning: bool = False, 

1142 **kw: Any, 

1143 ) -> Union[Engine, Connection]: 

1144 r"""Return a "bind" to which this :class:`.Session` is bound. 

1145 

1146 .. container:: class_bases 

1147 

1148 Proxied for the :class:`_orm.Session` class on 

1149 behalf of the :class:`_orm.scoping.scoped_session` class. 

1150 

1151 The "bind" is usually an instance of :class:`_engine.Engine`, 

1152 except in the case where the :class:`.Session` has been 

1153 explicitly bound directly to a :class:`_engine.Connection`. 

1154 

1155 For a multiply-bound or unbound :class:`.Session`, the 

1156 ``mapper`` or ``clause`` arguments are used to determine the 

1157 appropriate bind to return. 

1158 

1159 Note that the "mapper" argument is usually present 

1160 when :meth:`.Session.get_bind` is called via an ORM 

1161 operation such as a :meth:`.Session.query`, each 

1162 individual INSERT/UPDATE/DELETE operation within a 

1163 :meth:`.Session.flush`, call, etc. 

1164 

1165 The order of resolution is: 

1166 

1167 1. if mapper given and :paramref:`.Session.binds` is present, 

1168 locate a bind based first on the mapper in use, then 

1169 on the mapped class in use, then on any base classes that are 

1170 present in the ``__mro__`` of the mapped class, from more specific 

1171 superclasses to more general. 

1172 2. if clause given and ``Session.binds`` is present, 

1173 locate a bind based on :class:`_schema.Table` objects 

1174 found in the given clause present in ``Session.binds``. 

1175 3. if ``Session.binds`` is present, return that. 

1176 4. if clause given, attempt to return a bind 

1177 linked to the :class:`_schema.MetaData` ultimately 

1178 associated with the clause. 

1179 5. if mapper given, attempt to return a bind 

1180 linked to the :class:`_schema.MetaData` ultimately 

1181 associated with the :class:`_schema.Table` or other 

1182 selectable to which the mapper is mapped. 

1183 6. No bind can be found, :exc:`~sqlalchemy.exc.UnboundExecutionError` 

1184 is raised. 

1185 

1186 Note that the :meth:`.Session.get_bind` method can be overridden on 

1187 a user-defined subclass of :class:`.Session` to provide any kind 

1188 of bind resolution scheme. See the example at 

1189 :ref:`session_custom_partitioning`. 

1190 

1191 :param mapper: 

1192 Optional mapped class or corresponding :class:`_orm.Mapper` instance. 

1193 The bind can be derived from a :class:`_orm.Mapper` first by 

1194 consulting the "binds" map associated with this :class:`.Session`, 

1195 and secondly by consulting the :class:`_schema.MetaData` associated 

1196 with the :class:`_schema.Table` to which the :class:`_orm.Mapper` is 

1197 mapped for a bind. 

1198 

1199 :param clause: 

1200 A :class:`_expression.ClauseElement` (i.e. 

1201 :func:`_expression.select`, 

1202 :func:`_expression.text`, 

1203 etc.). If the ``mapper`` argument is not present or could not 

1204 produce a bind, the given expression construct will be searched 

1205 for a bound element, typically a :class:`_schema.Table` 

1206 associated with 

1207 bound :class:`_schema.MetaData`. 

1208 

1209 .. seealso:: 

1210 

1211 :ref:`session_partitioning` 

1212 

1213 :paramref:`.Session.binds` 

1214 

1215 :meth:`.Session.bind_mapper` 

1216 

1217 :meth:`.Session.bind_table` 

1218 

1219 

1220 """ # noqa: E501 

1221 

1222 return self._proxied.get_bind( 

1223 mapper=mapper, 

1224 clause=clause, 

1225 bind=bind, 

1226 _sa_skip_events=_sa_skip_events, 

1227 _sa_skip_for_implicit_returning=_sa_skip_for_implicit_returning, 

1228 **kw, 

1229 ) 

1230 

1231 def is_modified( 

1232 self, instance: object, include_collections: bool = True 

1233 ) -> bool: 

1234 r"""Return ``True`` if the given instance has locally 

1235 modified attributes. 

1236 

1237 .. container:: class_bases 

1238 

1239 Proxied for the :class:`_orm.Session` class on 

1240 behalf of the :class:`_orm.scoping.scoped_session` class. 

1241 

1242 This method retrieves the history for each instrumented 

1243 attribute on the instance and performs a comparison of the current 

1244 value to its previously flushed or committed value, if any. 

1245 

1246 It is in effect a more expensive and accurate 

1247 version of checking for the given instance in the 

1248 :attr:`.Session.dirty` collection; a full test for 

1249 each attribute's net "dirty" status is performed. 

1250 

1251 E.g.:: 

1252 

1253 return session.is_modified(someobject) 

1254 

1255 A few caveats to this method apply: 

1256 

1257 * Instances present in the :attr:`.Session.dirty` collection may 

1258 report ``False`` when tested with this method. This is because 

1259 the object may have received change events via attribute mutation, 

1260 thus placing it in :attr:`.Session.dirty`, but ultimately the state 

1261 is the same as that loaded from the database, resulting in no net 

1262 change here. 

1263 * Scalar attributes may not have recorded the previously set 

1264 value when a new value was applied, if the attribute was not loaded, 

1265 or was expired, at the time the new value was received - in these 

1266 cases, the attribute is assumed to have a change, even if there is 

1267 ultimately no net change against its database value. SQLAlchemy in 

1268 most cases does not need the "old" value when a set event occurs, so 

1269 it skips the expense of a SQL call if the old value isn't present, 

1270 based on the assumption that an UPDATE of the scalar value is 

1271 usually needed, and in those few cases where it isn't, is less 

1272 expensive on average than issuing a defensive SELECT. 

1273 

1274 The "old" value is fetched unconditionally upon set only if the 

1275 attribute container has the ``active_history`` flag set to ``True``. 

1276 This flag is set typically for primary key attributes and scalar 

1277 object references that are not a simple many-to-one. To set this 

1278 flag for any arbitrary mapped column, use the ``active_history`` 

1279 argument with :func:`.column_property`. 

1280 

1281 :param instance: mapped instance to be tested for pending changes. 

1282 :param include_collections: Indicates if multivalued collections 

1283 should be included in the operation. Setting this to ``False`` is a 

1284 way to detect only local-column based properties (i.e. scalar columns 

1285 or many-to-one foreign keys) that would result in an UPDATE for this 

1286 instance upon flush. 

1287 

1288 

1289 """ # noqa: E501 

1290 

1291 return self._proxied.is_modified( 

1292 instance, include_collections=include_collections 

1293 ) 

1294 

1295 def bulk_save_objects( 

1296 self, 

1297 objects: Iterable[object], 

1298 return_defaults: bool = False, 

1299 update_changed_only: bool = True, 

1300 preserve_order: bool = True, 

1301 ) -> None: 

1302 r"""Perform a bulk save of the given list of objects. 

1303 

1304 .. container:: class_bases 

1305 

1306 Proxied for the :class:`_orm.Session` class on 

1307 behalf of the :class:`_orm.scoping.scoped_session` class. 

1308 

1309 .. legacy:: 

1310 

1311 This method is a legacy feature as of the 2.0 series of 

1312 SQLAlchemy. For modern bulk INSERT and UPDATE, see 

1313 the sections :ref:`orm_queryguide_bulk_insert` and 

1314 :ref:`orm_queryguide_bulk_update`. 

1315 

1316 For general INSERT and UPDATE of existing ORM mapped objects, 

1317 prefer standard :term:`unit of work` data management patterns, 

1318 introduced in the :ref:`unified_tutorial` at 

1319 :ref:`tutorial_orm_data_manipulation`. SQLAlchemy 2.0 

1320 now uses :ref:`engine_insertmanyvalues` with modern dialects 

1321 which solves previous issues of bulk INSERT slowness. 

1322 

1323 :param objects: a sequence of mapped object instances. The mapped 

1324 objects are persisted as is, and are **not** associated with the 

1325 :class:`.Session` afterwards. 

1326 

1327 For each object, whether the object is sent as an INSERT or an 

1328 UPDATE is dependent on the same rules used by the :class:`.Session` 

1329 in traditional operation; if the object has the 

1330 :attr:`.InstanceState.key` 

1331 attribute set, then the object is assumed to be "detached" and 

1332 will result in an UPDATE. Otherwise, an INSERT is used. 

1333 

1334 In the case of an UPDATE, statements are grouped based on which 

1335 attributes have changed, and are thus to be the subject of each 

1336 SET clause. If ``update_changed_only`` is False, then all 

1337 attributes present within each object are applied to the UPDATE 

1338 statement, which may help in allowing the statements to be grouped 

1339 together into a larger executemany(), and will also reduce the 

1340 overhead of checking history on attributes. 

1341 

1342 :param return_defaults: when True, rows that are missing values which 

1343 generate defaults, namely integer primary key defaults and sequences, 

1344 will be inserted **one at a time**, so that the primary key value 

1345 is available. In particular this will allow joined-inheritance 

1346 and other multi-table mappings to insert correctly without the need 

1347 to provide primary key values ahead of time; however, 

1348 :paramref:`.Session.bulk_save_objects.return_defaults` **greatly 

1349 reduces the performance gains** of the method overall. It is strongly 

1350 advised to please use the standard :meth:`_orm.Session.add_all` 

1351 approach. 

1352 

1353 :param update_changed_only: when True, UPDATE statements are rendered 

1354 based on those attributes in each state that have logged changes. 

1355 When False, all attributes present are rendered into the SET clause 

1356 with the exception of primary key attributes. 

1357 

1358 :param preserve_order: when True, the order of inserts and updates 

1359 matches exactly the order in which the objects are given. When 

1360 False, common types of objects are grouped into inserts 

1361 and updates, to allow for more batching opportunities. 

1362 

1363 .. seealso:: 

1364 

1365 :doc:`queryguide/dml` 

1366 

1367 :meth:`.Session.bulk_insert_mappings` 

1368 

1369 :meth:`.Session.bulk_update_mappings` 

1370 

1371 

1372 """ # noqa: E501 

1373 

1374 return self._proxied.bulk_save_objects( 

1375 objects, 

1376 return_defaults=return_defaults, 

1377 update_changed_only=update_changed_only, 

1378 preserve_order=preserve_order, 

1379 ) 

1380 

1381 def bulk_insert_mappings( 

1382 self, 

1383 mapper: Mapper[Any], 

1384 mappings: Iterable[Dict[str, Any]], 

1385 return_defaults: bool = False, 

1386 render_nulls: bool = False, 

1387 ) -> None: 

1388 r"""Perform a bulk insert of the given list of mapping dictionaries. 

1389 

1390 .. container:: class_bases 

1391 

1392 Proxied for the :class:`_orm.Session` class on 

1393 behalf of the :class:`_orm.scoping.scoped_session` class. 

1394 

1395 .. legacy:: 

1396 

1397 This method is a legacy feature as of the 2.0 series of 

1398 SQLAlchemy. For modern bulk INSERT and UPDATE, see 

1399 the sections :ref:`orm_queryguide_bulk_insert` and 

1400 :ref:`orm_queryguide_bulk_update`. The 2.0 API shares 

1401 implementation details with this method and adds new features 

1402 as well. 

1403 

1404 :param mapper: a mapped class, or the actual :class:`_orm.Mapper` 

1405 object, 

1406 representing the single kind of object represented within the mapping 

1407 list. 

1408 

1409 :param mappings: a sequence of dictionaries, each one containing the 

1410 state of the mapped row to be inserted, in terms of the attribute 

1411 names on the mapped class. If the mapping refers to multiple tables, 

1412 such as a joined-inheritance mapping, each dictionary must contain all 

1413 keys to be populated into all tables. 

1414 

1415 :param return_defaults: when True, the INSERT process will be altered 

1416 to ensure that newly generated primary key values will be fetched. 

1417 The rationale for this parameter is typically to enable 

1418 :ref:`Joined Table Inheritance <joined_inheritance>` mappings to 

1419 be bulk inserted. 

1420 

1421 .. note:: for backends that don't support RETURNING, the 

1422 :paramref:`_orm.Session.bulk_insert_mappings.return_defaults` 

1423 parameter can significantly decrease performance as INSERT 

1424 statements can no longer be batched. See 

1425 :ref:`engine_insertmanyvalues` 

1426 for background on which backends are affected. 

1427 

1428 :param render_nulls: When True, a value of ``None`` will result 

1429 in a NULL value being included in the INSERT statement, rather 

1430 than the column being omitted from the INSERT. This allows all 

1431 the rows being INSERTed to have the identical set of columns which 

1432 allows the full set of rows to be batched to the DBAPI. Normally, 

1433 each column-set that contains a different combination of NULL values 

1434 than the previous row must omit a different series of columns from 

1435 the rendered INSERT statement, which means it must be emitted as a 

1436 separate statement. By passing this flag, the full set of rows 

1437 are guaranteed to be batchable into one batch; the cost however is 

1438 that server-side defaults which are invoked by an omitted column will 

1439 be skipped, so care must be taken to ensure that these are not 

1440 necessary. 

1441 

1442 .. warning:: 

1443 

1444 When this flag is set, **server side default SQL values will 

1445 not be invoked** for those columns that are inserted as NULL; 

1446 the NULL value will be sent explicitly. Care must be taken 

1447 to ensure that no server-side default functions need to be 

1448 invoked for the operation as a whole. 

1449 

1450 .. seealso:: 

1451 

1452 :doc:`queryguide/dml` 

1453 

1454 :meth:`.Session.bulk_save_objects` 

1455 

1456 :meth:`.Session.bulk_update_mappings` 

1457 

1458 

1459 """ # noqa: E501 

1460 

1461 return self._proxied.bulk_insert_mappings( 

1462 mapper, 

1463 mappings, 

1464 return_defaults=return_defaults, 

1465 render_nulls=render_nulls, 

1466 ) 

1467 

1468 def bulk_update_mappings( 

1469 self, mapper: Mapper[Any], mappings: Iterable[Dict[str, Any]] 

1470 ) -> None: 

1471 r"""Perform a bulk update of the given list of mapping dictionaries. 

1472 

1473 .. container:: class_bases 

1474 

1475 Proxied for the :class:`_orm.Session` class on 

1476 behalf of the :class:`_orm.scoping.scoped_session` class. 

1477 

1478 .. legacy:: 

1479 

1480 This method is a legacy feature as of the 2.0 series of 

1481 SQLAlchemy. For modern bulk INSERT and UPDATE, see 

1482 the sections :ref:`orm_queryguide_bulk_insert` and 

1483 :ref:`orm_queryguide_bulk_update`. The 2.0 API shares 

1484 implementation details with this method and adds new features 

1485 as well. 

1486 

1487 :param mapper: a mapped class, or the actual :class:`_orm.Mapper` 

1488 object, 

1489 representing the single kind of object represented within the mapping 

1490 list. 

1491 

1492 :param mappings: a sequence of dictionaries, each one containing the 

1493 state of the mapped row to be updated, in terms of the attribute names 

1494 on the mapped class. If the mapping refers to multiple tables, such 

1495 as a joined-inheritance mapping, each dictionary may contain keys 

1496 corresponding to all tables. All those keys which are present and 

1497 are not part of the primary key are applied to the SET clause of the 

1498 UPDATE statement; the primary key values, which are required, are 

1499 applied to the WHERE clause. 

1500 

1501 

1502 .. seealso:: 

1503 

1504 :doc:`queryguide/dml` 

1505 

1506 :meth:`.Session.bulk_insert_mappings` 

1507 

1508 :meth:`.Session.bulk_save_objects` 

1509 

1510 

1511 """ # noqa: E501 

1512 

1513 return self._proxied.bulk_update_mappings(mapper, mappings) 

1514 

1515 def merge( 

1516 self, 

1517 instance: _O, 

1518 *, 

1519 load: bool = True, 

1520 options: Optional[Sequence[ORMOption]] = None, 

1521 ) -> _O: 

1522 r"""Copy the state of a given instance into a corresponding instance 

1523 within this :class:`.Session`. 

1524 

1525 .. container:: class_bases 

1526 

1527 Proxied for the :class:`_orm.Session` class on 

1528 behalf of the :class:`_orm.scoping.scoped_session` class. 

1529 

1530 :meth:`.Session.merge` examines the primary key attributes of the 

1531 source instance, and attempts to reconcile it with an instance of the 

1532 same primary key in the session. If not found locally, it attempts 

1533 to load the object from the database based on primary key, and if 

1534 none can be located, creates a new instance. The state of each 

1535 attribute on the source instance is then copied to the target 

1536 instance. The resulting target instance is then returned by the 

1537 method; the original source instance is left unmodified, and 

1538 un-associated with the :class:`.Session` if not already. 

1539 

1540 This operation cascades to associated instances if the association is 

1541 mapped with ``cascade="merge"``. 

1542 

1543 See :ref:`unitofwork_merging` for a detailed discussion of merging. 

1544 

1545 :param instance: Instance to be merged. 

1546 :param load: Boolean, when False, :meth:`.merge` switches into 

1547 a "high performance" mode which causes it to forego emitting history 

1548 events as well as all database access. This flag is used for 

1549 cases such as transferring graphs of objects into a :class:`.Session` 

1550 from a second level cache, or to transfer just-loaded objects 

1551 into the :class:`.Session` owned by a worker thread or process 

1552 without re-querying the database. 

1553 

1554 The ``load=False`` use case adds the caveat that the given 

1555 object has to be in a "clean" state, that is, has no pending changes 

1556 to be flushed - even if the incoming object is detached from any 

1557 :class:`.Session`. This is so that when 

1558 the merge operation populates local attributes and 

1559 cascades to related objects and 

1560 collections, the values can be "stamped" onto the 

1561 target object as is, without generating any history or attribute 

1562 events, and without the need to reconcile the incoming data with 

1563 any existing related objects or collections that might not 

1564 be loaded. The resulting objects from ``load=False`` are always 

1565 produced as "clean", so it is only appropriate that the given objects 

1566 should be "clean" as well, else this suggests a mis-use of the 

1567 method. 

1568 :param options: optional sequence of loader options which will be 

1569 applied to the :meth:`_orm.Session.get` method when the merge 

1570 operation loads the existing version of the object from the database. 

1571 

1572 .. versionadded:: 1.4.24 

1573 

1574 

1575 .. seealso:: 

1576 

1577 :func:`.make_transient_to_detached` - provides for an alternative 

1578 means of "merging" a single object into the :class:`.Session` 

1579 

1580 :meth:`.Session.merge_all` - multiple instance version 

1581 

1582 

1583 """ # noqa: E501 

1584 

1585 return self._proxied.merge(instance, load=load, options=options) 

1586 

1587 def merge_all( 

1588 self, 

1589 instances: Iterable[_O], 

1590 *, 

1591 load: bool = True, 

1592 options: Optional[Sequence[ORMOption]] = None, 

1593 ) -> Sequence[_O]: 

1594 r"""Calls :meth:`.Session.merge` on multiple instances. 

1595 

1596 .. container:: class_bases 

1597 

1598 Proxied for the :class:`_orm.Session` class on 

1599 behalf of the :class:`_orm.scoping.scoped_session` class. 

1600 

1601 .. seealso:: 

1602 

1603 :meth:`.Session.merge` - main documentation on merge 

1604 

1605 .. versionadded:: 2.1 

1606 

1607 

1608 """ # noqa: E501 

1609 

1610 return self._proxied.merge_all(instances, load=load, options=options) 

1611 

1612 @overload 

1613 def query(self, _entity: _EntityType[_O]) -> Query[_O]: ... 

1614 

1615 @overload 

1616 def query( 

1617 self, _colexpr: TypedColumnsClauseRole[_T] 

1618 ) -> RowReturningQuery[_T]: ... 

1619 

1620 # START OVERLOADED FUNCTIONS self.query RowReturningQuery 2-8 

1621 

1622 # code within this block is **programmatically, 

1623 # statically generated** by tools/generate_tuple_map_overloads.py 

1624 

1625 @overload 

1626 def query( 

1627 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], / 

1628 ) -> RowReturningQuery[_T0, _T1]: ... 

1629 

1630 @overload 

1631 def query( 

1632 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], __ent2: _TCCA[_T2], / 

1633 ) -> RowReturningQuery[_T0, _T1, _T2]: ... 

1634 

1635 @overload 

1636 def query( 

1637 self, 

1638 __ent0: _TCCA[_T0], 

1639 __ent1: _TCCA[_T1], 

1640 __ent2: _TCCA[_T2], 

1641 __ent3: _TCCA[_T3], 

1642 /, 

1643 ) -> RowReturningQuery[_T0, _T1, _T2, _T3]: ... 

1644 

1645 @overload 

1646 def query( 

1647 self, 

1648 __ent0: _TCCA[_T0], 

1649 __ent1: _TCCA[_T1], 

1650 __ent2: _TCCA[_T2], 

1651 __ent3: _TCCA[_T3], 

1652 __ent4: _TCCA[_T4], 

1653 /, 

1654 ) -> RowReturningQuery[_T0, _T1, _T2, _T3, _T4]: ... 

1655 

1656 @overload 

1657 def query( 

1658 self, 

1659 __ent0: _TCCA[_T0], 

1660 __ent1: _TCCA[_T1], 

1661 __ent2: _TCCA[_T2], 

1662 __ent3: _TCCA[_T3], 

1663 __ent4: _TCCA[_T4], 

1664 __ent5: _TCCA[_T5], 

1665 /, 

1666 ) -> RowReturningQuery[_T0, _T1, _T2, _T3, _T4, _T5]: ... 

1667 

1668 @overload 

1669 def query( 

1670 self, 

1671 __ent0: _TCCA[_T0], 

1672 __ent1: _TCCA[_T1], 

1673 __ent2: _TCCA[_T2], 

1674 __ent3: _TCCA[_T3], 

1675 __ent4: _TCCA[_T4], 

1676 __ent5: _TCCA[_T5], 

1677 __ent6: _TCCA[_T6], 

1678 /, 

1679 ) -> RowReturningQuery[_T0, _T1, _T2, _T3, _T4, _T5, _T6]: ... 

1680 

1681 @overload 

1682 def query( 

1683 self, 

1684 __ent0: _TCCA[_T0], 

1685 __ent1: _TCCA[_T1], 

1686 __ent2: _TCCA[_T2], 

1687 __ent3: _TCCA[_T3], 

1688 __ent4: _TCCA[_T4], 

1689 __ent5: _TCCA[_T5], 

1690 __ent6: _TCCA[_T6], 

1691 __ent7: _TCCA[_T7], 

1692 /, 

1693 *entities: _ColumnsClauseArgument[Any], 

1694 ) -> RowReturningQuery[ 

1695 _T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, Unpack[TupleAny] 

1696 ]: ... 

1697 

1698 # END OVERLOADED FUNCTIONS self.query 

1699 

1700 @overload 

1701 def query( 

1702 self, *entities: _ColumnsClauseArgument[Any], **kwargs: Any 

1703 ) -> Query[Any]: ... 

1704 

1705 def query( 

1706 self, *entities: _ColumnsClauseArgument[Any], **kwargs: Any 

1707 ) -> Query[Any]: 

1708 r"""Return a new :class:`_query.Query` object corresponding to this 

1709 :class:`_orm.Session`. 

1710 

1711 .. container:: class_bases 

1712 

1713 Proxied for the :class:`_orm.Session` class on 

1714 behalf of the :class:`_orm.scoping.scoped_session` class. 

1715 

1716 Note that the :class:`_query.Query` object is legacy as of 

1717 SQLAlchemy 2.0; the :func:`_sql.select` construct is now used 

1718 to construct ORM queries. 

1719 

1720 .. seealso:: 

1721 

1722 :ref:`unified_tutorial` 

1723 

1724 :ref:`queryguide_toplevel` 

1725 

1726 :ref:`query_api_toplevel` - legacy API doc 

1727 

1728 

1729 """ # noqa: E501 

1730 

1731 return self._proxied.query(*entities, **kwargs) 

1732 

1733 def refresh( 

1734 self, 

1735 instance: object, 

1736 attribute_names: Optional[Iterable[str]] = None, 

1737 with_for_update: ForUpdateParameter = None, 

1738 ) -> None: 

1739 r"""Expire and refresh attributes on the given instance. 

1740 

1741 .. container:: class_bases 

1742 

1743 Proxied for the :class:`_orm.Session` class on 

1744 behalf of the :class:`_orm.scoping.scoped_session` class. 

1745 

1746 The selected attributes will first be expired as they would when using 

1747 :meth:`_orm.Session.expire`; then a SELECT statement will be issued to 

1748 the database to refresh column-oriented attributes with the current 

1749 value available in the current transaction. 

1750 

1751 :func:`_orm.relationship` oriented attributes will also be immediately 

1752 loaded if they were already eagerly loaded on the object, using the 

1753 same eager loading strategy that they were loaded with originally. 

1754 

1755 .. versionadded:: 1.4 - the :meth:`_orm.Session.refresh` method 

1756 can also refresh eagerly loaded attributes. 

1757 

1758 :func:`_orm.relationship` oriented attributes that would normally 

1759 load using the ``select`` (or "lazy") loader strategy will also 

1760 load **if they are named explicitly in the attribute_names 

1761 collection**, emitting a SELECT statement for the attribute using the 

1762 ``immediate`` loader strategy. If lazy-loaded relationships are not 

1763 named in :paramref:`_orm.Session.refresh.attribute_names`, then 

1764 they remain as "lazy loaded" attributes and are not implicitly 

1765 refreshed. 

1766 

1767 .. versionchanged:: 2.0.4 The :meth:`_orm.Session.refresh` method 

1768 will now refresh lazy-loaded :func:`_orm.relationship` oriented 

1769 attributes for those which are named explicitly in the 

1770 :paramref:`_orm.Session.refresh.attribute_names` collection. 

1771 

1772 .. tip:: 

1773 

1774 While the :meth:`_orm.Session.refresh` method is capable of 

1775 refreshing both column and relationship oriented attributes, its 

1776 primary focus is on refreshing of local column-oriented attributes 

1777 on a single instance. For more open ended "refresh" functionality, 

1778 including the ability to refresh the attributes on many objects at 

1779 once while having explicit control over relationship loader 

1780 strategies, use the 

1781 :ref:`populate existing <orm_queryguide_populate_existing>` feature 

1782 instead. 

1783 

1784 Note that a highly isolated transaction will return the same values as 

1785 were previously read in that same transaction, regardless of changes 

1786 in database state outside of that transaction. Refreshing 

1787 attributes usually only makes sense at the start of a transaction 

1788 where database rows have not yet been accessed. 

1789 

1790 :param attribute_names: optional. An iterable collection of 

1791 string attribute names indicating a subset of attributes to 

1792 be refreshed. 

1793 

1794 :param with_for_update: optional boolean ``True`` indicating FOR UPDATE 

1795 should be used, or may be a dictionary containing flags to 

1796 indicate a more specific set of FOR UPDATE flags for the SELECT; 

1797 flags should match the parameters of 

1798 :meth:`_query.Query.with_for_update`. 

1799 Supersedes the :paramref:`.Session.refresh.lockmode` parameter. 

1800 

1801 .. seealso:: 

1802 

1803 :ref:`session_expire` - introductory material 

1804 

1805 :meth:`.Session.expire` 

1806 

1807 :meth:`.Session.expire_all` 

1808 

1809 :ref:`orm_queryguide_populate_existing` - allows any ORM query 

1810 to refresh objects as they would be loaded normally. 

1811 

1812 

1813 """ # noqa: E501 

1814 

1815 return self._proxied.refresh( 

1816 instance, 

1817 attribute_names=attribute_names, 

1818 with_for_update=with_for_update, 

1819 ) 

1820 

1821 def rollback(self) -> None: 

1822 r"""Rollback the current transaction in progress. 

1823 

1824 .. container:: class_bases 

1825 

1826 Proxied for the :class:`_orm.Session` class on 

1827 behalf of the :class:`_orm.scoping.scoped_session` class. 

1828 

1829 If no transaction is in progress, this method is a pass-through. 

1830 

1831 The method always rolls back 

1832 the topmost database transaction, discarding any nested 

1833 transactions that may be in progress. 

1834 

1835 .. seealso:: 

1836 

1837 :ref:`session_rollback` 

1838 

1839 :ref:`unitofwork_transaction` 

1840 

1841 

1842 """ # noqa: E501 

1843 

1844 return self._proxied.rollback() 

1845 

1846 @overload 

1847 def scalar( 

1848 self, 

1849 statement: TypedReturnsRows[_T], 

1850 params: Optional[_CoreSingleExecuteParams] = None, 

1851 *, 

1852 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, 

1853 bind_arguments: Optional[_BindArguments] = None, 

1854 **kw: Any, 

1855 ) -> Optional[_T]: ... 

1856 

1857 @overload 

1858 def scalar( 

1859 self, 

1860 statement: Executable, 

1861 params: Optional[_CoreSingleExecuteParams] = None, 

1862 *, 

1863 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, 

1864 bind_arguments: Optional[_BindArguments] = None, 

1865 **kw: Any, 

1866 ) -> Any: ... 

1867 

1868 def scalar( 

1869 self, 

1870 statement: Executable, 

1871 params: Optional[_CoreSingleExecuteParams] = None, 

1872 *, 

1873 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, 

1874 bind_arguments: Optional[_BindArguments] = None, 

1875 **kw: Any, 

1876 ) -> Any: 

1877 r"""Execute a statement and return a scalar result. 

1878 

1879 .. container:: class_bases 

1880 

1881 Proxied for the :class:`_orm.Session` class on 

1882 behalf of the :class:`_orm.scoping.scoped_session` class. 

1883 

1884 Usage and parameters are the same as that of 

1885 :meth:`_orm.Session.execute`; the return result is a scalar Python 

1886 value. 

1887 

1888 

1889 """ # noqa: E501 

1890 

1891 return self._proxied.scalar( 

1892 statement, 

1893 params=params, 

1894 execution_options=execution_options, 

1895 bind_arguments=bind_arguments, 

1896 **kw, 

1897 ) 

1898 

1899 @overload 

1900 def scalars( 

1901 self, 

1902 statement: TypedReturnsRows[_T], 

1903 params: Optional[_CoreAnyExecuteParams] = None, 

1904 *, 

1905 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, 

1906 bind_arguments: Optional[_BindArguments] = None, 

1907 **kw: Any, 

1908 ) -> ScalarResult[_T]: ... 

1909 

1910 @overload 

1911 def scalars( 

1912 self, 

1913 statement: Executable, 

1914 params: Optional[_CoreAnyExecuteParams] = None, 

1915 *, 

1916 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, 

1917 bind_arguments: Optional[_BindArguments] = None, 

1918 **kw: Any, 

1919 ) -> ScalarResult[Any]: ... 

1920 

1921 def scalars( 

1922 self, 

1923 statement: Executable, 

1924 params: Optional[_CoreAnyExecuteParams] = None, 

1925 *, 

1926 execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT, 

1927 bind_arguments: Optional[_BindArguments] = None, 

1928 **kw: Any, 

1929 ) -> ScalarResult[Any]: 

1930 r"""Execute a statement and return the results as scalars. 

1931 

1932 .. container:: class_bases 

1933 

1934 Proxied for the :class:`_orm.Session` class on 

1935 behalf of the :class:`_orm.scoping.scoped_session` class. 

1936 

1937 Usage and parameters are the same as that of 

1938 :meth:`_orm.Session.execute`; the return result is a 

1939 :class:`_result.ScalarResult` filtering object which 

1940 will return single elements rather than :class:`_row.Row` objects. 

1941 

1942 :return: a :class:`_result.ScalarResult` object 

1943 

1944 .. versionadded:: 1.4.24 Added :meth:`_orm.Session.scalars` 

1945 

1946 .. versionadded:: 1.4.26 Added :meth:`_orm.scoped_session.scalars` 

1947 

1948 .. seealso:: 

1949 

1950 :ref:`orm_queryguide_select_orm_entities` - contrasts the behavior 

1951 of :meth:`_orm.Session.execute` to :meth:`_orm.Session.scalars` 

1952 

1953 

1954 """ # noqa: E501 

1955 

1956 return self._proxied.scalars( 

1957 statement, 

1958 params=params, 

1959 execution_options=execution_options, 

1960 bind_arguments=bind_arguments, 

1961 **kw, 

1962 ) 

1963 

1964 @property 

1965 def bind(self) -> Optional[Union[Engine, Connection]]: 

1966 r"""Proxy for the :attr:`_orm.Session.bind` attribute 

1967 on behalf of the :class:`_orm.scoping.scoped_session` class. 

1968 

1969 """ # noqa: E501 

1970 

1971 return self._proxied.bind 

1972 

1973 @bind.setter 

1974 def bind(self, attr: Optional[Union[Engine, Connection]]) -> None: 

1975 self._proxied.bind = attr 

1976 

1977 @property 

1978 def dirty(self) -> Any: 

1979 r"""The set of all persistent instances considered dirty. 

1980 

1981 .. container:: class_bases 

1982 

1983 Proxied for the :class:`_orm.Session` class 

1984 on behalf of the :class:`_orm.scoping.scoped_session` class. 

1985 

1986 E.g.:: 

1987 

1988 some_mapped_object in session.dirty 

1989 

1990 Instances are considered dirty when they were modified but not 

1991 deleted. 

1992 

1993 Note that this 'dirty' calculation is 'optimistic'; most 

1994 attribute-setting or collection modification operations will 

1995 mark an instance as 'dirty' and place it in this set, even if 

1996 there is no net change to the attribute's value. At flush 

1997 time, the value of each attribute is compared to its 

1998 previously saved value, and if there's no net change, no SQL 

1999 operation will occur (this is a more expensive operation so 

2000 it's only done at flush time). 

2001 

2002 To check if an instance has actionable net changes to its 

2003 attributes, use the :meth:`.Session.is_modified` method. 

2004 

2005 

2006 """ # noqa: E501 

2007 

2008 return self._proxied.dirty 

2009 

2010 @property 

2011 def deleted(self) -> Any: 

2012 r"""The set of all instances marked as 'deleted' within this ``Session`` 

2013 

2014 .. container:: class_bases 

2015 

2016 Proxied for the :class:`_orm.Session` class 

2017 on behalf of the :class:`_orm.scoping.scoped_session` class. 

2018 

2019 """ # noqa: E501 

2020 

2021 return self._proxied.deleted 

2022 

2023 @property 

2024 def new(self) -> Any: 

2025 r"""The set of all instances marked as 'new' within this ``Session``. 

2026 

2027 .. container:: class_bases 

2028 

2029 Proxied for the :class:`_orm.Session` class 

2030 on behalf of the :class:`_orm.scoping.scoped_session` class. 

2031 

2032 """ # noqa: E501 

2033 

2034 return self._proxied.new 

2035 

2036 @property 

2037 def identity_map(self) -> IdentityMap: 

2038 r"""Proxy for the :attr:`_orm.Session.identity_map` attribute 

2039 on behalf of the :class:`_orm.scoping.scoped_session` class. 

2040 

2041 """ # noqa: E501 

2042 

2043 return self._proxied.identity_map 

2044 

2045 @identity_map.setter 

2046 def identity_map(self, attr: IdentityMap) -> None: 

2047 self._proxied.identity_map = attr 

2048 

2049 @property 

2050 def is_active(self) -> Any: 

2051 r"""True if this :class:`.Session` not in "partial rollback" state. 

2052 

2053 .. container:: class_bases 

2054 

2055 Proxied for the :class:`_orm.Session` class 

2056 on behalf of the :class:`_orm.scoping.scoped_session` class. 

2057 

2058 .. versionchanged:: 1.4 The :class:`_orm.Session` no longer begins 

2059 a new transaction immediately, so this attribute will be False 

2060 when the :class:`_orm.Session` is first instantiated. 

2061 

2062 "partial rollback" state typically indicates that the flush process 

2063 of the :class:`_orm.Session` has failed, and that the 

2064 :meth:`_orm.Session.rollback` method must be emitted in order to 

2065 fully roll back the transaction. 

2066 

2067 If this :class:`_orm.Session` is not in a transaction at all, the 

2068 :class:`_orm.Session` will autobegin when it is first used, so in this 

2069 case :attr:`_orm.Session.is_active` will return True. 

2070 

2071 Otherwise, if this :class:`_orm.Session` is within a transaction, 

2072 and that transaction has not been rolled back internally, the 

2073 :attr:`_orm.Session.is_active` will also return True. 

2074 

2075 .. seealso:: 

2076 

2077 :ref:`faq_session_rollback` 

2078 

2079 :meth:`_orm.Session.in_transaction` 

2080 

2081 

2082 """ # noqa: E501 

2083 

2084 return self._proxied.is_active 

2085 

2086 @property 

2087 def autoflush(self) -> bool: 

2088 r"""Proxy for the :attr:`_orm.Session.autoflush` attribute 

2089 on behalf of the :class:`_orm.scoping.scoped_session` class. 

2090 

2091 """ # noqa: E501 

2092 

2093 return self._proxied.autoflush 

2094 

2095 @autoflush.setter 

2096 def autoflush(self, attr: bool) -> None: 

2097 self._proxied.autoflush = attr 

2098 

2099 @property 

2100 def no_autoflush(self) -> Any: 

2101 r"""Return a context manager that disables autoflush. 

2102 

2103 .. container:: class_bases 

2104 

2105 Proxied for the :class:`_orm.Session` class 

2106 on behalf of the :class:`_orm.scoping.scoped_session` class. 

2107 

2108 e.g.:: 

2109 

2110 with session.no_autoflush: 

2111 

2112 some_object = SomeClass() 

2113 session.add(some_object) 

2114 # won't autoflush 

2115 some_object.related_thing = session.query(SomeRelated).first() 

2116 

2117 Operations that proceed within the ``with:`` block 

2118 will not be subject to flushes occurring upon query 

2119 access. This is useful when initializing a series 

2120 of objects which involve existing database queries, 

2121 where the uncompleted object should not yet be flushed. 

2122 

2123 

2124 """ # noqa: E501 

2125 

2126 return self._proxied.no_autoflush 

2127 

2128 @property 

2129 def info(self) -> Any: 

2130 r"""A user-modifiable dictionary. 

2131 

2132 .. container:: class_bases 

2133 

2134 Proxied for the :class:`_orm.Session` class 

2135 on behalf of the :class:`_orm.scoping.scoped_session` class. 

2136 

2137 The initial value of this dictionary can be populated using the 

2138 ``info`` argument to the :class:`.Session` constructor or 

2139 :class:`.sessionmaker` constructor or factory methods. The dictionary 

2140 here is always local to this :class:`.Session` and can be modified 

2141 independently of all other :class:`.Session` objects. 

2142 

2143 

2144 """ # noqa: E501 

2145 

2146 return self._proxied.info 

2147 

2148 @classmethod 

2149 def object_session(cls, instance: object) -> Optional[Session]: 

2150 r"""Return the :class:`.Session` to which an object belongs. 

2151 

2152 .. container:: class_bases 

2153 

2154 Proxied for the :class:`_orm.Session` class on 

2155 behalf of the :class:`_orm.scoping.scoped_session` class. 

2156 

2157 This is an alias of :func:`.object_session`. 

2158 

2159 

2160 """ # noqa: E501 

2161 

2162 return Session.object_session(instance) 

2163 

2164 @classmethod 

2165 def identity_key( 

2166 cls, 

2167 class_: Optional[Type[Any]] = None, 

2168 ident: Union[Any, Tuple[Any, ...]] = None, 

2169 *, 

2170 instance: Optional[Any] = None, 

2171 row: Optional[Union[Row[Unpack[TupleAny]], RowMapping]] = None, 

2172 identity_token: Optional[Any] = None, 

2173 ) -> _IdentityKeyType[Any]: 

2174 r"""Return an identity key. 

2175 

2176 .. container:: class_bases 

2177 

2178 Proxied for the :class:`_orm.Session` class on 

2179 behalf of the :class:`_orm.scoping.scoped_session` class. 

2180 

2181 This is an alias of :func:`.util.identity_key`. 

2182 

2183 

2184 """ # noqa: E501 

2185 

2186 return Session.identity_key( 

2187 class_=class_, 

2188 ident=ident, 

2189 instance=instance, 

2190 row=row, 

2191 identity_token=identity_token, 

2192 ) 

2193 

2194 # END PROXY METHODS scoped_session 

2195 

2196 

2197ScopedSession = scoped_session 

2198"""Old name for backwards compatibility."""