summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/engine/interfaces.py2
-rw-r--r--lib/sqlalchemy/engine/result.py25
-rw-r--r--lib/sqlalchemy/event/api.py10
-rw-r--r--lib/sqlalchemy/event/legacy.py14
-rw-r--r--lib/sqlalchemy/orm/__init__.py8
-rw-r--r--lib/sqlalchemy/orm/events.py49
-rw-r--r--lib/sqlalchemy/orm/loading.py20
-rw-r--r--lib/sqlalchemy/orm/session.py61
8 files changed, 141 insertions, 48 deletions
diff --git a/lib/sqlalchemy/engine/interfaces.py b/lib/sqlalchemy/engine/interfaces.py
index f925df6c5..1baef29af 100644
--- a/lib/sqlalchemy/engine/interfaces.py
+++ b/lib/sqlalchemy/engine/interfaces.py
@@ -953,7 +953,7 @@ class CreateEnginePlugin(object):
engine = create_engine(
"mysql+pymysql://scott:tiger@localhost/test?plugin=myplugin")
- Alternatively, the :paramref:`.create_engine.plugins" argument may be
+ Alternatively, the :paramref:`_sa.create_engine.plugins" argument may be
passed as a list to :func:`_sa.create_engine`::
engine = create_engine(
diff --git a/lib/sqlalchemy/engine/result.py b/lib/sqlalchemy/engine/result.py
index db546380e..621cba674 100644
--- a/lib/sqlalchemy/engine/result.py
+++ b/lib/sqlalchemy/engine/result.py
@@ -649,6 +649,11 @@ class Result(InPlaceGenerative):
it will produce a new :class:`_engine.Result` object each time
against its stored set of rows.
+ .. seealso::
+
+ :ref:`do_orm_execute_re_executing` - example usage within the
+ ORM to implement a result-set cache.
+
"""
return FrozenResult(self)
@@ -1173,12 +1178,28 @@ class FrozenResult(object):
frozen = result.freeze()
- r1 = frozen()
- r2 = frozen()
+ unfrozen_result_one = frozen()
+
+ for row in unfrozen_result_one:
+ print(row)
+
+ unfrozen_result_two = frozen()
+ rows = unfrozen_result_two.all()
+
# ... etc
.. versionadded:: 1.4
+ .. seealso::
+
+ .. seealso::
+
+ :ref:`do_orm_execute_re_executing` - example usage within the
+ ORM to implement a result-set cache.
+
+ :func:`_orm.loading.merge_frozen_result` - ORM function to merge
+ a frozen result back into a :class:`_orm.Session`.
+
"""
def __init__(self, result):
diff --git a/lib/sqlalchemy/event/api.py b/lib/sqlalchemy/event/api.py
index 6bd63ceca..b36c448ce 100644
--- a/lib/sqlalchemy/event/api.py
+++ b/lib/sqlalchemy/event/api.py
@@ -61,9 +61,6 @@ def listen(target, identifier, fn, *args, **kw):
event.listen(Mapper, "before_configure", on_config, once=True)
- .. versionadded:: 0.9.4 Added ``once=True`` to :func:`.event.listen`
- and :func:`.event.listens_for`.
-
.. warning:: The ``once`` argument does not imply automatic de-registration
of the listener function after it has been invoked a first time; a
listener entry will remain associated with the target object.
@@ -128,9 +125,6 @@ def listens_for(target, identifier, *args, **kw):
do_config()
- .. versionadded:: 0.9.4 Added ``once=True`` to :func:`.event.listen`
- and :func:`.event.listens_for`.
-
.. warning:: The ``once`` argument does not imply automatic de-registration
of the listener function after it has been invoked a first time; a
listener entry will remain associated with the target object.
@@ -173,8 +167,6 @@ def remove(target, identifier, fn):
propagated to subclasses of ``SomeMappedClass``; the :func:`.remove`
function will revert all of these operations.
- .. versionadded:: 0.9.0
-
.. note::
The :func:`.remove` function cannot be called at the same time
@@ -206,8 +198,6 @@ def remove(target, identifier, fn):
def contains(target, identifier, fn):
"""Return True if the given target/ident/fn is set up to listen.
- .. versionadded:: 0.9.0
-
"""
return _event_key(target, identifier, fn).contains()
diff --git a/lib/sqlalchemy/event/legacy.py b/lib/sqlalchemy/event/legacy.py
index f63c7d101..14115d377 100644
--- a/lib/sqlalchemy/event/legacy.py
+++ b/lib/sqlalchemy/event/legacy.py
@@ -96,8 +96,7 @@ def _standard_listen_example(dispatch_collection, sample_target, fn):
else:
current_since = None
text = (
- "from sqlalchemy import event\n\n"
- "# standard decorator style%(current_since)s\n"
+ "from sqlalchemy import event\n\n\n"
"@event.listens_for(%(sample_target)s, '%(event_name)s')\n"
"def receive_%(event_name)s("
"%(named_event_arguments)s%(has_kw_arguments)s):\n"
@@ -105,17 +104,6 @@ def _standard_listen_example(dispatch_collection, sample_target, fn):
"\n # ... (event handling logic) ...\n"
)
- if len(dispatch_collection.arg_names) > 3:
- text += (
- "\n# named argument style (new in 0.9)\n"
- "@event.listens_for("
- "%(sample_target)s, '%(event_name)s', named=True)\n"
- "def receive_%(event_name)s(**kw):\n"
- " \"listen for the '%(event_name)s' event\"\n"
- "%(example_kw_arg)s\n"
- "\n # ... (event handling logic) ...\n"
- )
-
text %= {
"current_since": " (arguments as of %s)" % current_since
if current_since
diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py
index 458103838..199ae11e5 100644
--- a/lib/sqlalchemy/orm/__init__.py
+++ b/lib/sqlalchemy/orm/__init__.py
@@ -272,6 +272,14 @@ def eagerload(*args, **kwargs):
contains_alias = public_factory(AliasOption, ".orm.contains_alias")
+if True:
+ from .events import AttributeEvents # noqa
+ from .events import MapperEvents # noqa
+ from .events import InstanceEvents # noqa
+ from .events import InstrumentationEvents # noqa
+ from .events import QueryEvents # noqa
+ from .events import SessionEvents # noqa
+
def __go(lcls):
global __all__
diff --git a/lib/sqlalchemy/orm/events.py b/lib/sqlalchemy/orm/events.py
index 217aa76c7..ec907c63e 100644
--- a/lib/sqlalchemy/orm/events.py
+++ b/lib/sqlalchemy/orm/events.py
@@ -1427,7 +1427,27 @@ class SessionEvents(event.Events):
.. seealso::
- :class:`.ORMExecuteState`
+ :ref:`session_execute_events` - top level documentation on how
+ to use :meth:`_orm.SessionEvents.do_orm_execute`
+
+ :class:`.ORMExecuteState` - the object passed to the
+ :meth:`_orm.SessionEvents.do_orm_execute` event which contains
+ all information about the statement to be invoked. It also
+ provides an interface to extend the current statement, options,
+ and parameters as well as an option that allows programmatic
+ invocation of the statement at any point.
+
+ :ref:`examples_session_orm_events` - includes examples of using
+ :meth:`_orm.SessionEvents.do_orm_execute`
+
+ :ref:`examples_caching` - an example of how to integrate
+ Dogpile caching with the ORM :class:`_orm.Session` making use
+ of the :meth:`_orm.SessionEvents.do_orm_execute` event hook.
+
+ :ref:`examples_sharding` - the Horizontal Sharding example /
+ extension relies upon the
+ :meth:`_orm.SessionEvents.do_orm_execute` event hook to invoke a
+ SQL statement on multiple backends and return a merged result.
.. versionadded:: 1.4
@@ -2585,12 +2605,8 @@ class QueryEvents(event.Events):
"""Represent events within the construction of a :class:`_query.Query`
object.
- The events here are intended to be used with an as-yet-unreleased
- inspection system for :class:`_query.Query`. Some very basic operations
- are possible now, however the inspection system is intended to allow
- complex query manipulations to be automated.
-
- .. versionadded:: 1.0.0
+ The :class:`_orm.QueryEvents` hooks are now superseded by the
+ :meth:`_orm.SessionEvents.do_orm_execute` event hook.
"""
@@ -2602,6 +2618,17 @@ class QueryEvents(event.Events):
object before it is composed into a
core :class:`_expression.Select` object.
+ .. deprecated:: 1.4 The :meth:`_orm.QueryEvents.before_compile` event
+ is superseded by the much more capable
+ :meth:`_orm.SessionEvents.do_orm_execute` hook. In version 1.4,
+ the :meth:`_orm.QueryEvents.before_compile` event is **no longer
+ used** for ORM-level attribute loads, such as loads of deferred
+ or expired attributes as well as relationship loaders. See the
+ new examples in :ref:`examples_session_orm_events` which
+ illustrate new ways of intercepting and modifying ORM queries
+ for the most common purpose of adding arbitrary filter criteria.
+
+
This event is intended to allow changes to the query given::
@event.listens_for(Query, "before_compile", retval=True)
@@ -2656,6 +2683,10 @@ class QueryEvents(event.Events):
"""Allow modifications to the :class:`_query.Query` object within
:meth:`_query.Query.update`.
+ .. deprecated:: 1.4 The :meth:`_orm.QueryEvents.before_compile_update`
+ event is superseded by the much more capable
+ :meth:`_orm.SessionEvents.do_orm_execute` hook.
+
Like the :meth:`.QueryEvents.before_compile` event, if the event
is to be used to alter the :class:`_query.Query` object, it should
be configured with ``retval=True``, and the modified
@@ -2702,6 +2733,10 @@ class QueryEvents(event.Events):
"""Allow modifications to the :class:`_query.Query` object within
:meth:`_query.Query.delete`.
+ .. deprecated:: 1.4 The :meth:`_orm.QueryEvents.before_compile_delete`
+ event is superseded by the much more capable
+ :meth:`_orm.SessionEvents.do_orm_execute` hook.
+
Like the :meth:`.QueryEvents.before_compile` event, this event
should be configured with ``retval=True``, and the modified
:class:`_query.Query` object returned, as in ::
diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py
index 601393156..2eb3e1368 100644
--- a/lib/sqlalchemy/orm/loading.py
+++ b/lib/sqlalchemy/orm/loading.py
@@ -141,6 +141,21 @@ def instances(cursor, context):
@util.preload_module("sqlalchemy.orm.context")
def merge_frozen_result(session, statement, frozen_result, load=True):
+ """Merge a :class:`_engine.FrozenResult` back into a :class:`_orm.Session`,
+ returning a new :class:`_engine.Result` object with :term:`persistent`
+ objects.
+
+ See the section :ref:`do_orm_execute_re_executing` for an example.
+
+ .. seealso::
+
+ :ref:`do_orm_execute_re_executing`
+
+ :meth:`_engine.Result.freeze`
+
+ :class:`_engine.FrozenResult`
+
+ """
querycontext = util.preloaded.orm_context
if load:
@@ -184,6 +199,11 @@ def merge_frozen_result(session, statement, frozen_result, load=True):
session.autoflush = autoflush
+@util.deprecated(
+ "2.0",
+ "The :func:`_orm.merge_result` method is superseded by the "
+ ":func:`_orm.merge_frozen_result` function.",
+)
@util.preload_module("sqlalchemy.orm.context")
def merge_result(query, iterator, load=True):
"""Merge a result into this :class:`.Query` object's Session."""
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index e9d4ac2c6..ed1af0a80 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -107,6 +107,10 @@ class ORMExecuteState(util.MemoizedSlots):
.. versionadded:: 1.4
+ .. seealso::
+
+ :ref:`session_execute_events` - top level documentation on how
+ to use :meth:`_orm.SessionEvents.do_orm_execute`
"""
@@ -158,14 +162,24 @@ class ORMExecuteState(util.MemoizedSlots):
bind_arguments=None,
):
"""Execute the statement represented by this
- :class:`.ORMExecuteState`, without re-invoking events.
-
- This method essentially performs a re-entrant execution of the
- current statement for which the :meth:`.SessionEvents.do_orm_execute`
- event is being currently invoked. The use case for this is
- for event handlers that want to override how the ultimate results
- object is returned, such as for schemes that retrieve results from
- an offline cache or which concatenate results from multiple executions.
+ :class:`.ORMExecuteState`, without re-invoking events that have
+ already proceeded.
+
+ This method essentially performs a re-entrant execution of the current
+ statement for which the :meth:`.SessionEvents.do_orm_execute` event is
+ being currently invoked. The use case for this is for event handlers
+ that want to override how the ultimate
+ :class:`_engine.Result` object is returned, such as for schemes that
+ retrieve results from an offline cache or which concatenate results
+ from multiple executions.
+
+ When the :class:`_engine.Result` object is returned by the actual
+ handler function within :meth:`_orm.SessionEvents.do_orm_execute` and
+ is propagated to the calling
+ :meth:`_orm.Session.execute` method, the remainder of the
+ :meth:`_orm.Session.execute` method is preempted and the
+ :class:`_engine.Result` object is returned to the caller of
+ :meth:`_orm.Session.execute` immediately.
:param statement: optional statement to be invoked, in place of the
statement currently represented by :attr:`.ORMExecuteState.statement`.
@@ -970,13 +984,30 @@ class Session(_SessionClassMethods):
transaction will load from the most recent database state.
:param future: if True, use 2.0 style behavior for the
- :meth:`_orm.Session.execute` method. This includes that the
- :class:`_engine.Result` object returned will return new-style
- tuple rows, as well as that Core constructs such as
- :class:`_sql.Select`,
- :class:`_sql.Update` and :class:`_sql.Delete` will be interpreted
- in an ORM context if they are made against ORM entities rather than
- plain :class:`.Table` metadata objects.
+ :meth:`_orm.Session.execute` method. Future mode includes the
+ following behaviors:
+
+ * The :class:`_engine.Result` object returned by the
+ :meth:`_orm.Session.execute` method will return new-style tuple
+ :class:`_engine.Row` objects
+
+ * The :meth:`_orm.Session.execute` method will invoke ORM style
+ queries given objects like :class:`_sql.Select`,
+ :class:`_sql.Update` and :class:`_sql.Delete` against ORM entities
+
+ * The :class:`_orm.Session` will not use "bound" metadata in order
+ to locate an :class:`_engine.Engine`; the engine or engines in use
+ must be specified to the constructor of :class:`_orm.Session` or
+ otherwise be configured against the :class:`_orm.sessionmaker`
+ in use
+
+ * The "subtransactions" feature of :meth:`_orm.Session.begin` is
+ removed in version 2.0 and is disabled when the future flag is
+ set.
+
+ * The behavior of the :paramref:`_orm.relationship.cascade_backrefs`
+ flag on a :func:`_orm.relationship` will always assume
+ "False" behavior.
The "future" flag is also available on a per-execution basis
using the :paramref:`_orm.Session.execute.future` flag.