]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- fix pypostgresql typo, [ticket:2185]
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 4 Jul 2011 20:31:58 +0000 (16:31 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 4 Jul 2011 20:31:58 +0000 (16:31 -0400)
- rewrite "getting a session" docs to delineate
all sessionmaker() use cases distinctly
- rewrite "Managing Transactions" doc to spell out
each specific step completely, [ticket:2204]
- add to create_engine() and main "engine" doc
an unambiguous statement that the create_engine()
does not create a connection
- other link fixes
- rewrite "deleting" section so that "deleting from collections"
is separate, well-described, [ticket:2202]
- rephrase "autocommit mode" into its own section, move it down,
put some bold text that you shouldn't be using it.
- simplify the "subtransactions" section and make it local to
"autocommit" since it is utterly unneeded by anybody.
- oracle is not doing 2-phase anytime soon

doc/build/core/engines.rst
doc/build/orm/session.rst
lib/sqlalchemy/dialects/postgresql/pypostgresql.py
lib/sqlalchemy/engine/__init__.py
lib/sqlalchemy/orm/__init__.py
lib/sqlalchemy/orm/scoping.py
lib/sqlalchemy/orm/session.py

index 5fef74faf9784a438618a04070228e301fbf0097..353571526cdb6cf9ec8d77d66b33a720018df7cc 100644 (file)
@@ -24,8 +24,14 @@ Creating an engine is just a matter of issuing a single call,
     from sqlalchemy import create_engine
     engine = create_engine('postgresql://scott:tiger@localhost:5432/mydatabase')
 
-The above engine invokes the ``postgresql`` dialect and a connection pool
-which references ``localhost:5432``.
+The above engine creates a :class:`.Dialect` object tailored towards
+PostgreSQL, as well as a :class:`.Pool` object which will establish a DBAPI
+connection at ``localhost:5432`` when a connection request is first received.
+Note that the :class:`.Engine` and its underlying :class:`.Pool` do **not**
+establish the first actual DBAPI connection until the :meth:`.Engine.connect`
+method is called, or an operation which is dependent on this method such as
+:meth:`.Engine.execute` is invoked. In this way, :class:`.Engine` and
+:class:`.Pool` can be said to have a *lazy initialization* behavior.
 
 The :class:`.Engine`, once created, can either be used directly to interact with the database,
 or can be passed to a :class:`.Session` object to work with the ORM.   This section
index d84c1d11a4148fa04abe02c91433a21c63bc755e..f339d0cbff0fa53e38a2853e9463f9db0e167777 100644 (file)
@@ -62,8 +62,13 @@ The usage of :func:`.sessionmaker` is illustrated below:
 
 .. sourcecode:: python+sql
 
+    from sqlalchemy import create_engine
     from sqlalchemy.orm import sessionmaker
 
+    # an Engine, which the Session will use for connection
+    # resources
+    some_engine = create_engine('postgresql://scott:tiger@localhost/')
+
     # create a configured "Session" class
     Session = sessionmaker(bind=some_engine)
 
@@ -81,16 +86,36 @@ actual :class:`.Session` class, which when instantiated, will
 use the arguments we've given the function, in this case
 to use a particular :class:`.Engine` for connection resources.
 
-When you write your application, place the call to
-:func:`.sessionmaker` somewhere global, and then make your new
-``Session`` class available to the rest of your application.
-
 A typical setup will associate the :func:`.sessionmaker` with an :class:`.Engine`,
 so that each :class:`.Session` generated will use this :class:`.Engine`
 to acquire connection resources.   This association can
-be set up as in the example above, using the ``bind`` argument.   You 
-can also associate a :class:`.Engine` with an existing :func:`.sessionmaker` 
-using the :meth:`.sessionmaker.configure` method::
+be set up as in the example above, using the ``bind`` argument. 
+
+When you write your application, place the result of the
+:func:`.sessionmaker` call at the global level.   The resulting
+``Session`` class, configured for your application, should then
+be used by the rest of the applcation as the source of new :class:`.Session`
+instances.
+
+An extremely common step taken by applications, including virtually
+all web applications, is to further wrap the :func:`.sessionmaker`
+construct in a so-called "contextual" session, provided by the
+:func:`.scoped_session` construct.  This construct places the :func:`.sessionmaker`
+into a **registry** that maintains a single :class:`.Session` per 
+application thread.   Information on using contextual sessions
+is at :ref:`unitofwork_contextual`.
+
+Adding additional configuration to an Existing sessionmaker()
+--------------------------------------------------------------
+
+A common scenario is where the :func:`.sessionmaker` is invoked 
+at module import time, however the generation of one or more :class:`.Engine`
+instances to be associated with the :func:`.sessionmaker` has not yet proceeded.
+For this use case, the :func:`.sessionmaker` construct offers the 
+:meth:`.sessionmaker.configure` method, which will place additional configuration
+directives into an existing :func:`.sessionmaker` that will take place
+when the construct is invoked::
+
 
     from sqlalchemy.orm import sessionmaker
     from sqlalchemy import create_engine
@@ -107,19 +132,31 @@ using the :meth:`.sessionmaker.configure` method::
     # work with the session
     session = Session()
 
-you can also associate individual :class:`.Session` objects with an :class:`.Engine`
-on each invocation::
-
-    session = Session(bind=engine)
-
-...or directly with a :class:`.Connection`::
+Creating Ad-Hoc Session Objects with Alternate Arguments
+---------------------------------------------------------
+
+For the use case where an application needs to create a new :class:`.Session` with
+special arguments that deviate from what is normally used throughout the application, 
+such as a :class:`.Session` that binds to an alternate 
+source of connectivity, or a :class:`.Session` that should 
+have other arguments such as ``expire_on_commit`` established differently from 
+what most of the application wants, specific arguments can be passed to the 
+:func:`.sessionmaker` construct's class itself.  These arguments will override whatever
+configurations have already been placed, such as below, where a new :class:`.Session`
+is constructed against a specific :class:`.Connection`::
+
+    # at the module level, the global sessionmaker,
+    # bound to a specific Engine
+    Session = sessionmaker(bind=engine)
 
+    # later, some unit of code wants to create a 
+    # Session that is bound to a specific Connection
     conn = engine.connect()
     session = Session(bind=conn)
 
-While the rationale for the above example may not be apparent, the typical
-usage is in a test fixture that maintains an external transaction - see
-:ref:`session_external_transaction` below for a full example.
+The typical rationale for the association of a :class:`.Session` with a specific
+:class:`.Connection` is that of a test fixture that maintains an external 
+transaction - see :ref:`session_external_transaction` for an example of this.
 
 Using the Session
 ==================
@@ -541,7 +578,7 @@ is a quick way to check::
 Deleting
 --------
 
-The :func:`~sqlalchemy.orm.session.Session.delete` method places an instance
+The :meth:`~.Session.delete` method places an instance
 into the Session's list of objects to be marked as deleted::
 
     # mark two objects to be deleted
@@ -551,10 +588,16 @@ into the Session's list of objects to be marked as deleted::
     # commit (or flush)
     session.commit()
 
-The big gotcha with :func:`~sqlalchemy.orm.session.Session.delete` is that
-**nothing is removed from collections**. Such as, if a ``User`` has a
-collection of three ``Addresses``, deleting an ``Address`` will not remove it
-from ``user.addresses``::
+Deleting from Collections
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A common confusion that arises regarding :meth:`~.Session.delete` is when
+objects which are members of a collection are being deleted.   While the
+collection member is marked for deletion from the database, this does not
+impact the collection itself in memory until the collection is expired.
+Below, we illustrate that even after an ``Address`` object is marked
+for deletion, it's still present in the collection associated with the
+parent ``User``, even after a flush::
 
     >>> address = user.addresses[1]
     >>> session.delete(address)
@@ -562,7 +605,19 @@ from ``user.addresses``::
     >>> address in user.addresses
     True
 
-The solution is to use proper cascading::
+When the above session is committed, all attributes are expired.  The next
+access of ``user.addresses`` will re-load the collection, revealing the
+desired state::
+
+    >>> session.commit()
+    >>> address in user.addresses
+    False
+
+The usual practice of deleting items within collections is to forego the usage
+of :meth:`~.Session.delete` directly, and instead use cascade behavior to
+automatically invoke the deletion as a result of removing the object from
+the parent collection.  The ``delete-orphan`` cascade accomplishes this,
+as illustrated in the example below::
 
     mapper(User, users_table, properties={
         'addresses':relationship(Address, cascade="all, delete, delete-orphan")
@@ -570,6 +625,12 @@ The solution is to use proper cascading::
     del user.addresses[1]
     session.flush()
 
+Where above, upon removing the ``Address`` object from the ``User.addresses`` 
+collection, the ``delete-orphan`` cascade has the effect of marking the ``Address``
+object for deletion in the same way as passing it to :meth:`~.Session.delete`.
+
+See also :ref:`unitofwork_cascades` for detail on cascades.
+
 Deleting based on Filter Criterion
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -936,74 +997,76 @@ associations to objects which are already persistent in the target session.
 Managing Transactions
 =====================
 
-The :class:`~sqlalchemy.orm.session.Session` manages transactions across all
-engines associated with it. As the :class:`~sqlalchemy.orm.session.Session`
-receives requests to execute SQL statements using a particular
-:class:`~sqlalchemy.engine.base.Engine` or
-:class:`~sqlalchemy.engine.base.Connection`, it adds each individual
-:class:`~sqlalchemy.engine.base.Engine` encountered to its transactional state
-and maintains an open connection for each one (note that a simple application
-normally has just one :class:`~sqlalchemy.engine.base.Engine`). At commit
-time, all unflushed data is flushed, and each individual transaction is
-committed. If the underlying databases support two-phase semantics, this may
-be used by the Session as well if two-phase transactions are enabled.
-
-Normal operation ends the transactional state using the
-:func:`~sqlalchemy.orm.session.Session.rollback` or
-:func:`~sqlalchemy.orm.session.Session.commit` methods. After either is
-called, the :class:`~sqlalchemy.orm.session.Session` starts a new
-transaction::
+A newly constructed :class:`.Session` may be said to be in the "begin" state.
+In this state, the :class:`.Session` has not established any connection or 
+transactional state with any of the :class:`.Engine` objects that may be associated
+with it.
+
+The :class:`.Session` then receives requests to operate upon a database connection.
+Typically, this means it is called upon to execute SQL statements using a particular
+:class:`.Engine`, which may be via :meth:`.Session.query`, :meth:`.Session.execute`,
+or within a flush operation of pending data, which occurs when such state exists
+and :meth:`.Session.commit` or :meth:`.Session.flush` is called.
+
+As these requests are received, each new :class:`.Engine` encountered is associated 
+with an ongoing transactional state maintained by the :class:`.Session`.
+When the first :class:`.Engine` is operated upon, the :class:`.Session` can be said
+to have left the "begin" state and entered "transactional" state.   For each
+:class:`.Engine` encountered, a :class:`.Connection` is associated with it,
+which is acquired via the :meth:`.Engine.contextual_connect` method.  If a
+:class:`.Connection` was directly associated with the :class:`.Session` (see :ref:`session_external_transaction`
+for an example of this), it is 
+added to the transactional state directly.
+
+For each :class:`.Connection`, the :class:`.Session` also maintains a :class:`.Transaction` object, 
+which is acquired by calling :meth:`.Connection.begin` on each :class:`.Connection`,
+or if the :class:`.Session`
+object has been established using the flag ``twophase=True``, a :class:`.TwoPhaseTransaction`
+object acquired via :meth:`.Connection.begin_twophase`.  These transactions are all committed or 
+rolled back corresponding to the invocation of the 
+:meth:`.Session.commit` and :meth:`.Session.rollback` methods.   A commit operation will
+also call the :meth:`.TwoPhaseTransaction.prepare` method on all transactions if applicable.
+
+When the transactional state is completed after a rollback or commit, the :class:`.Session`
+releases all :class:`.Transaction` and :class:`.Connection` resources (which has the effect
+of returning DBAPI connections to the connection pool of each :class:`.Engine`), 
+and goes back to the "begin" state, which
+will again invoke new :class:`.Connection` and :class:`.Transaction` objects as new 
+requests to emit SQL statements are received.
+
+The example below illustrates this lifecycle::
+
+    engine = create_engine("...")
+    Session = sessionmaker(bind=engine)
 
-    Session = sessionmaker()
+    # new session.   no connections are in use.
     session = Session()
     try:
+        # first query.  a Connection is acquired
+        # from the Engine, and a Transaction 
+        # started.
         item1 = session.query(Item).get(1)
-        item2 = session.query(Item).get(2)
-        item1.foo = 'bar'
-        item2.bar = 'foo'
-
-        # commit- will immediately go into 
-        # a new transaction on next use.
-        session.commit()
-    except:
-        # rollback - will immediately go into 
-        # a new transaction on next use.
-        session.rollback()
-
-A session which is configured with ``autocommit=True`` may be placed into a
-transaction using :func:`~sqlalchemy.orm.session.Session.begin`. With an
-``autocommit=True`` session that's been placed into a transaction using
-:func:`~sqlalchemy.orm.session.Session.begin`, the session releases all
-connection resources after a :func:`~sqlalchemy.orm.session.Session.commit` or
-:func:`~sqlalchemy.orm.session.Session.rollback` and remains transaction-less
-(with the exception of flushes) until the next
-:func:`~sqlalchemy.orm.session.Session.begin` call::
 
-    Session = sessionmaker(autocommit=True)
-    session = Session()
-    session.begin()
-    try:
-        item1 = session.query(Item).get(1)
+        # second query.  the same Connection/Transaction
+        # are used.
         item2 = session.query(Item).get(2)
+
+        # pending changes are created.
         item1.foo = 'bar'
         item2.bar = 'foo'
+
+        # commit.  The pending changes above
+        # are flushed via flush(), the Transaction
+        # is committed, the Connection object closed
+        # and discarded, the underlying DBAPI connection
+        # returned to the connection pool.
         session.commit()
     except:
+        # on rollback, the same closure of state
+        # as that of commit proceeds.
         session.rollback()
         raise
 
-The :func:`~sqlalchemy.orm.session.Session.begin` method also returns a
-transactional token which is compatible with the Python 2.6 ``with``
-statement::
-
-    Session = sessionmaker(autocommit=True)
-    session = Session()
-    with session.begin():
-        item1 = session.query(Item).get(1)
-        item2 = session.query(Item).get(2)
-        item1.foo = 'bar'
-        item2.bar = 'foo'
-
 .. _session_begin_nested:
 
 Using SAVEPOINT
@@ -1038,72 +1101,84 @@ session is expired, thus causing all subsequent attribute/instance access to
 reference the full state of the :class:`~sqlalchemy.orm.session.Session` right
 before :func:`~sqlalchemy.orm.session.Session.begin_nested` was called.
 
+Autocommit Mode
+---------------
+
+The example of :class:`.Session` transaction lifecycle illustrated at
+the start of :ref:`unitofwork_transaction` applies to a :class:`.Session` configured in the
+default mode of ``autocommit=False``.   Constructing a :class:`.Session`
+with ``autocommit=True`` produces a :class:`.Session` placed into "autocommit" mode, where each SQL statement
+invoked by a :meth:`.Session.query` or :meth:`.Session.execute` occurs
+using a new connection from the connection pool, discarding it after
+results have been iterated.   The :meth:`.Session.flush` operation
+still occurs within the scope of a single transaction, though this transaction
+is closed out after the :meth:`.Session.flush` operation completes.
+
+"autocommit" mode should **not be considered for general use**.   While
+very old versions of SQLAlchemy standardized on this mode, the modern
+:class:`.Session` benefits highly from being given a clear point of transaction
+demarcation via :meth:`.Session.rollback` and :meth:`.Session.commit`.
+The autoflush action can safely emit SQL to the database as needed without
+implicitly producing permanent effects, the contents of attributes 
+are expired only when a logical series of steps has completed.   If the
+:class:`.Session` were to be used in pure "autocommit" mode without 
+an ongoing transaction, these features should be disabled, that is,
+``autoflush=False, expire_on_commit=False``.
+
+Modern usage of "autocommit" is for framework integrations that need to control
+specifically when the "begin" state occurs.  A session which is configured with 
+``autocommit=True`` may be placed into the "begin" state using the 
+:meth:`.Session.begin` method.
+After the cycle completes upon :meth:`.Session.commit` or :meth:`.Session.rollback`,
+connection and transaction resources are released and the :class:`.Session`
+goes back into "autocommit" mode, until :meth:`.Session.begin` is called again::
+
+    Session = sessionmaker(bind=engine, autocommit=True)
+    session = Session()
+    session.begin()
+    try:
+        item1 = session.query(Item).get(1)
+        item2 = session.query(Item).get(2)
+        item1.foo = 'bar'
+        item2.bar = 'foo'
+        session.commit()
+    except:
+        session.rollback()
+        raise
+
+The :func:`.Session.begin` method also returns a
+transactional token which is compatible with the Python 2.6 ``with``
+statement::
+
+    Session = sessionmaker(bind=engine, autocommit=True)
+    session = Session()
+    with session.begin():
+        item1 = session.query(Item).get(1)
+        item2 = session.query(Item).get(2)
+        item1.foo = 'bar'
+        item2.bar = 'foo'
+
 .. _session_subtransactions:
 
-Using Subtransactions
----------------------
+Using Subtransactions with Autocommit
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-A subtransaction, as offered by the ``subtransactions=True`` flag of :meth:`.Session.begin`,
-is a non-transactional, delimiting construct that
+A subtransaction indicates usage of the :meth:`.Session.begin` method in conjunction with 
+the ``subtransactions=True`` flag.  This produces a a non-transactional, delimiting construct that
 allows nesting of calls to :meth:`~.Session.begin` and :meth:`~.Session.commit`.
 It's purpose is to allow the construction of code that can function within a transaction
 both independently of any external code that starts a transaction,
-as well as within a block that has already demarcated a transaction.  By "non-transactional", we
-mean that no actual transactional dialogue with the database is generated by this flag beyond that of
-a single call to :meth:`~.Session.begin`, regardless of how many times the method
-is called within a transaction.
-
-The subtransaction feature is in fact intrinsic to any call to :meth:`~.Session.flush`, which uses
-it internally to ensure that the series of flush steps are enclosed within a transaction,
-regardless of the setting of ``autocommit`` or the presence of an existing transactional context.
-However, explicit usage of the ``subtransactions=True`` flag is generally only useful with an 
-application that uses the
-:class:`.Session` in "autocommit=True" mode, and calls :meth:`~.Session.begin` explicitly
-in order to demarcate transactions.  For this reason the subtransaction feature is not
-commonly used in an explicit way, except for apps that integrate SQLAlchemy-level transaction control with
-the transaction control of another library or subsystem.  For true, general purpose "nested" 
-transactions, where a rollback affects only a portion of the work which has proceeded, 
-savepoints should be used, documented in :ref:`session_begin_nested`.
-
-The feature is the ORM equivalent to the pattern described at :ref:`connections_nested_transactions`, 
+as well as within a block that has already demarcated a transaction. 
+
+``subtransactions=True`` is generally only useful in conjunction with 
+autocommit, and is equivalent to the pattern described at :ref:`connections_nested_transactions`, 
 where any number of functions can call :meth:`.Connection.begin` and :meth:`.Transaction.commit`
 as though they are the initiator of the transaction, but in fact may be participating
-in an already ongoing transaction.
-
-As is the case with the non-ORM :class:`.Transaction` object,
-calling :meth:`.Session.rollback` rolls back the **entire**
-transaction, which was initiated by the first call to
-:meth:`.Session.begin` (whether this call was explicit by the
-end user, or implicit in an ``autocommit=False`` scenario).
-However, the :class:`.Session` still considers itself to be in a
-"partially rolled back" state until :meth:`.Session.rollback` is
-called explicitly for each call that was made to
-:meth:`.Session.begin`, where "partially rolled back" means that
-no further SQL operations can proceed until each level
-of the transaction has been acounted for, unless the :meth:`~.Session.close` method
-is called which cancels all transactional markers. For a full exposition on 
-the rationale for this,
-please see "`But why isn't the one automatic call to ROLLBACK
-enough ? Why must I ROLLBACK again?
-<http://www.sqlalchemy.org/trac/wiki/FAQ#ButwhyisnttheoneautomaticcalltoROLLBACKenoughWhymustIROLLBACKagain>`_".
-The general theme is that if subtransactions are used as intended, that is, as a means to nest multiple
-begin/commit pairs, the appropriate rollback calls naturally occur in any case, and allow the session's 
-nesting of transactional pairs to function in a simple and predictable way 
-without the need to guess as to what level is active.
-
-An example of ``subtransactions=True`` is nearly identical to
-that of the non-ORM technique. The nesting of transactions, as
-well as the natural presence of "rollback" for all transactions
-should an exception occur, is illustrated::
+in an already ongoing transaction::
 
     # method_a starts a transaction and calls method_b
     def method_a(session):
-        session.begin(subtransactions=True) # open a transaction.  If there was
-                                            # no previous call to begin(), this will
-                                            # begin a real transaction (meaning, a 
-                                            # DBAPI connection is procured, which as
-                                            # per the DBAPI specification is in a transactional
-                                            # state ready to be committed or rolled back)
+        session.begin(subtransactions=True)
         try:
             method_b(session)
             session.commit()  # transaction is committed here
@@ -1111,11 +1186,11 @@ should an exception occur, is illustrated::
             session.rollback() # rolls back the transaction
             raise
 
-    # method_b also starts a transaction
+    # method_b also starts a transaction, but when
+    # called from method_a participates in the ongoing
+    # transaction.
     def method_b(connection):
-        session.begin(subtransactions=True) # open a transaction - this 
-                                            # runs in the context of method_a()'s 
-                                            # transaction
+        session.begin(subtransactions=True)
         try:
             session.add(SomeObject('bat', 'lala'))
             session.commit()  # transaction is not committed yet
@@ -1129,21 +1204,22 @@ should an exception occur, is illustrated::
     method_a(session)
     session.close()
 
-Since the :meth:`.Session.flush` method uses a subtransaction, a failed flush
-will always issue a rollback which then affects the state of the outermost transaction (unless a SAVEPOINT
-is in use).   This forces the need to issue :meth:`~.Session.rollback` for the full operation
-before subsequent SQL operations can proceed.
+Subtransactions are used by the :meth:`.Session.flush` process to ensure that the
+flush operation takes place within a transaction, regardless of autocommit.   When
+autocommit is disabled, it is still useful in that it forces the :class:`.Session`
+into a "pending rollback" state, as a failed flush cannot be resumed in mid-operation,
+where the end user still maintains the "scope" of the transaction overall.
 
 Enabling Two-Phase Commit
 -------------------------
 
-Finally, for MySQL, PostgreSQL, and soon Oracle as well, the session can be
-instructed to use two-phase commit semantics. This will coordinate the
-committing of transactions across databases so that the transaction is either
-committed or rolled back in all databases. You can also
-:func:`~sqlalchemy.orm.session.Session.prepare` the session for interacting
-with transactions not managed by SQLAlchemy. To use two phase transactions set
-the flag ``twophase=True`` on the session::
+For backends which support two-phase operaration (currently MySQL and
+PostgreSQL), the session can be instructed to use two-phase commit semantics.
+This will coordinate the committing of transactions across databases so that
+the transaction is either committed or rolled back in all databases. You can
+also :func:`~sqlalchemy.orm.session.Session.prepare` the session for
+interacting with transactions not managed by SQLAlchemy. To use two phase
+transactions set the flag ``twophase=True`` on the session::
 
     engine1 = create_engine('postgresql://db1')
     engine2 = create_engine('postgresql://db2')
index a137a6240f6d24a0487461e0520e1e958ecc502d..d52e3db6d09479e70e282e970a7c8bdd0d123ffd 100644 (file)
@@ -9,7 +9,7 @@
 Connecting
 ----------
 
-URLs are of the form ``postgresql+pypostgresql://user@password@host:port/dbname[?key=value&key=value...]``.
+URLs are of the form ``postgresql+pypostgresql://user:password@host:port/dbname[?key=value&key=value...]``.
 
 
 """
index 010cc22ddfd008ac5f9bc2a07f4000de7b8cdb75..eab462032b5a9c52337097fb1bf384d852977fb5 100644 (file)
@@ -99,27 +99,38 @@ __all__ = (
 
 default_strategy = 'plain'
 def create_engine(*args, **kwargs):
-    """Create a new Engine instance.
+    """Create a new :class:`.Engine` instance.
 
-    The standard method of specifying the engine is via URL as the
-    first positional argument, to indicate the appropriate database
-    dialect and connection arguments, with additional keyword
-    arguments sent as options to the dialect and resulting Engine.
+    The standard calling form is to send the URL as the 
+    first positional argument, usually a string 
+    that indicates database dialect and connection arguments.
+    Additional keyword arguments may then follow it which
+    establish various options on the resulting :class:`.Engine`
+    and its underlying :class:`.Dialect` and :class:`.Pool`
+    constructs.
 
-    The URL is a string in the form
+    The string form of the URL is
     ``dialect+driver://user:password@host/dbname[?key=value..]``, where
     ``dialect`` is a database name such as ``mysql``, ``oracle``, 
     ``postgresql``, etc., and ``driver`` the name of a DBAPI, such as 
     ``psycopg2``, ``pyodbc``, ``cx_oracle``, etc.  Alternatively, 
     the URL can be an instance of :class:`~sqlalchemy.engine.url.URL`.
 
-    `**kwargs` takes a wide variety of options which are routed 
+    ``**kwargs`` takes a wide variety of options which are routed 
     towards their appropriate components.  Arguments may be 
-    specific to the Engine, the underlying Dialect, as well as the 
-    Pool.  Specific dialects also accept keyword arguments that
+    specific to the :class:`.Engine`, the underlying :class:`.Dialect`, as well as the 
+    :class:`.Pool`.  Specific dialects also accept keyword arguments that
     are unique to that dialect.   Here, we describe the parameters
-    that are common to most ``create_engine()`` usage.
-
+    that are common to most :func:`.create_engine()` usage.
+
+    Once established, the newly resulting :class:`.Engine` will
+    request a connection from the underlying :class:`.Pool` once
+    :meth:`.Engine.connect` is called, or a method which depends on it
+    such as :meth:`.Engine.execute` is invoked.   The :class:`.Pool` in turn
+    will establish the first actual DBAPI connection when this request
+    is received.   The :func:`.create_engine` call itself does **not**
+    establish any actual DBAPI connections directly.
+    
     :param assert_unicode:  Deprecated.  A warning is raised in all cases when a non-Unicode
         object is passed when SQLAlchemy would coerce into an encoding
         (note: but **not** when the DBAPI handles unicode objects natively).
index 854aa8cee5bb7e365f2984b2651606def9ba9f07..d5d2e4e3161e1b32812916c9abf15990ac6d53e7 100644 (file)
@@ -111,18 +111,7 @@ def scoped_session(session_factory, scopefunc=None):
     """Provides thread-local or scoped management of :class:`.Session` objects.
 
     This is a front-end function to
-    :class:`.ScopedSession`.
-
-    :param session_factory: a callable function that produces
-      :class:`.Session` instances, such as :func:`sessionmaker`.
-
-    :param scopefunc: Optional "scope" function which would be
-      passed to the :class:`.ScopedRegistry`.  If None, the
-      :class:`.ThreadLocalRegistry` is used by default.
-
-    :returns: an :class:`.ScopedSession` instance
-
-    Usage::
+    :class:`.ScopedSession`::
 
       Session = scoped_session(sessionmaker(autoflush=True))
 
@@ -137,6 +126,18 @@ def scoped_session(session_factory, scopefunc=None):
       Session.commit()
       Session.close()
 
+    See also: :ref:`unitofwork_contextual`.
+
+    :param session_factory: a callable function that produces
+      :class:`.Session` instances, such as :func:`sessionmaker`.
+
+    :param scopefunc: Optional "scope" function which would be
+      passed to the :class:`.ScopedRegistry`.  If None, the
+      :class:`.ThreadLocalRegistry` is used by default.
+
+    :returns: a :class:`.ScopedSession` instance
+
+
     """
     return ScopedSession(session_factory, scopefunc=scopefunc)
 
index 53e5e5d1fa5bcc4389db4b8d9fc52d4871a09c21..815bda1857d471ed6e3a55fdf6b90a39fcee1818 100644 (file)
@@ -16,16 +16,16 @@ __all__ = ['ScopedSession']
 
 class ScopedSession(object):
     """Provides thread-local management of Sessions.
-
-    Usage::
-
+    
+    Typical invocation is via the :func:`.scoped_session`
+    function::
+    
       Session = scoped_session(sessionmaker())
 
-    ... use Session normally.
-
-    The internal registry is accessible as well,
+    The internal registry is accessible,
     and by default is an instance of :class:`.ThreadLocalRegistry`.
 
+    See also: :ref:`unitofwork_contextual`.
 
     """
 
index ce4d96591ea72c7068e84ab8f6b8f86e8c1ee5fd..0cbad25191acbcff0a8396a80eeace3980788e82 100644 (file)
@@ -31,13 +31,13 @@ __all__ = ['Session', 'SessionTransaction', 'SessionExtension']
 
 def sessionmaker(bind=None, class_=None, autoflush=True, autocommit=False,
                  expire_on_commit=True, **kwargs):
-    """Generate a custom-configured :class:`~sqlalchemy.orm.session.Session` class.
+    """Generate a custom-configured :class:`.Session` class.
 
-    The returned object is a subclass of ``Session``, which, when instantiated
+    The returned object is a subclass of :class:`.Session`, which, when instantiated
     with no arguments, uses the keyword arguments configured here as its
     constructor arguments.
 
-    It is intended that the `sessionmaker()` function be called within the
+    It is intended that the :func:`.sessionmaker()` function be called within the
     global scope of an application, and the returned class be made available
     to the rest of the application as the single class used to instantiate
     sessions.