summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorJason Kirtland <jek@discorporate.us>2007-08-19 17:57:51 +0000
committerJason Kirtland <jek@discorporate.us>2007-08-19 17:57:51 +0000
commitb714ebf49147d7fd1e0161df6861feff51470370 (patch)
tree22e3783994fbd6b53863f3a71a1dc65bc39bee17 /lib/sqlalchemy
parent5a1db6658882efbeba99d5f079cec2fdab1d880b (diff)
downloadsqlalchemy-b714ebf49147d7fd1e0161df6861feff51470370.tar.gz
- Connection.begin() no longer accepts nested=True, a possible source of confusion as two forms of nesting are supported. SAVEPOINT-style nesting logic is now contained soley in begin_nested().
- Docstring love for the engine package. More is needed.
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/engine/__init__.py163
-rw-r--r--lib/sqlalchemy/engine/base.py564
-rw-r--r--lib/sqlalchemy/engine/default.py32
-rw-r--r--lib/sqlalchemy/engine/strategies.py54
-rw-r--r--lib/sqlalchemy/engine/threadlocal.py55
-rw-r--r--lib/sqlalchemy/engine/url.py20
6 files changed, 512 insertions, 376 deletions
diff --git a/lib/sqlalchemy/engine/__init__.py b/lib/sqlalchemy/engine/__init__.py
index 070ff3c3e..ae32b40bb 100644
--- a/lib/sqlalchemy/engine/__init__.py
+++ b/lib/sqlalchemy/engine/__init__.py
@@ -4,45 +4,50 @@
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
-"""defines the basic components used to interface DBAPI modules with
-higher-level statement-construction, connection-management,
-execution and result contexts. The primary "entry point" class into
-this package is the Engine.
-
-The package is represented among several individual modules, including:
-
- base.py
- Defines interface classes and some implementation classes
- which comprise the basic components used to interface between
- a DBAPI, constructed and plain-text statements,
- connections, transactions, and results.
-
- default.py
- Contains default implementations of some of the components
- defined in base.py. All current database dialects use the
- classes in default.py as base classes for their own database-specific
- implementations.
-
- strategies.py
- the mechanics of constructing ``Engine`` objects are represented here.
- Defines the ``EngineStrategy`` class which represents how to go from
- arguments specified to the ``create_engine()`` function, to a fully
- constructed ``Engine``, including initialization of connection pooling,
- dialects, and specific subclasses of ``Engine``.
-
- threadlocal.py
- the ``TLEngine`` class is defined here, which is a subclass of the generic
- ``Engine`` and tracks ``Connection`` and ``Transaction`` objects against
- the identity of the current thread. This allows certain programming patterns
- based around the concept of a "thread-local connection" to be possible. The
- ``TLEngine`` is created by using the "threadlocal" engine strategy in
- conjunction with the ``create_engine()`` function.
-
- url.py
- Defines the ``URL`` class which represents the individual components of a
- string URL passed to ``create_engine()``. Also defines a basic module-loading
- strategy for the dialect specifier within a URL.
-
+"""SQL connections, SQL execution and high-level DB-API interface.
+
+The engine package defines the basic components used to interface
+DB-API modules with higher-level statement construction,
+connection-management, execution and result contexts. The primary
+"entry point" class into this package is the Engine and it's public
+constructor ``create_engine()``.
+
+This package includes:
+
+base.py
+ Defines interface classes and some implementation classes which
+ comprise the basic components used to interface between a DB-API,
+ constructed and plain-text statements, connections, transactions,
+ and results.
+
+default.py
+ Contains default implementations of some of the components defined
+ in base.py. All current database dialects use the classes in
+ default.py as base classes for their own database-specific
+ implementations.
+
+strategies.py
+ The mechanics of constructing ``Engine`` objects are represented
+ here. Defines the ``EngineStrategy`` class which represents how
+ to go from arguments specified to the ``create_engine()``
+ function, to a fully constructed ``Engine``, including
+ initialization of connection pooling, dialects, and specific
+ subclasses of ``Engine``.
+
+threadlocal.py
+ The ``TLEngine`` class is defined here, which is a subclass of
+ the generic ``Engine`` and tracks ``Connection`` and
+ ``Transaction`` objects against the identity of the current
+ thread. This allows certain programming patterns based around
+ the concept of a "thread-local connection" to be possible.
+ The ``TLEngine`` is created by using the "threadlocal" engine
+ strategy in conjunction with the ``create_engine()`` function.
+
+url.py
+ Defines the ``URL`` class which represents the individual
+ components of a string URL passed to ``create_engine()``. Also
+ defines a basic module-loading strategy for the dialect specifier
+ within a URL.
"""
import sqlalchemy.databases
@@ -64,7 +69,7 @@ def engine_descriptors():
arguments
a dictionary describing the name and description of each
- parameter used to connect to this engine's underlying DBAPI.
+ parameter used to connect to this engine's underlying DB-API.
This function is meant for usage in automated configuration tools
that wish to query the user for database and connection
@@ -73,7 +78,8 @@ def engine_descriptors():
result = []
for module in sqlalchemy.databases.__all__:
- module = getattr(__import__('sqlalchemy.databases.%s' % module).databases, module)
+ module = getattr(
+ __import__('sqlalchemy.databases.%s' % module).databases, module)
result.append(module.descriptor())
return result
@@ -86,10 +92,11 @@ def create_engine(*args, **kwargs):
dialect and connection arguments, with additional keyword
arguments sent as options to the dialect and resulting Engine.
- The URL is a string in the form
- ``dialect://user:password@host/dbname[?key=value..]``, where
+ The URL is a string in the form
+ ``dialect://user:password@host/dbname[?key=value..]``, where
``dialect`` is a name such as ``mysql``, ``oracle``, ``postgres``,
- etc. Alternatively, the URL can be an instance of ``sqlalchemy.engine.url.URL``.
+ etc. Alternatively, the URL can be an instance of
+ ``sqlalchemy.engine.url.URL``.
`**kwargs` represents options to be sent to the Engine itself as
well as the components of the Engine, including the Dialect, the
@@ -97,17 +104,17 @@ def create_engine(*args, **kwargs):
follows:
poolclass
- a subclass of ``sqlalchemy.pool.Pool`` which will be used to
+ a subclass of ``sqlalchemy.pool.Pool`` which will be used to
instantiate a connection pool.
-
+
pool
an instance of ``sqlalchemy.pool.DBProxy`` or
``sqlalchemy.pool.Pool`` to be used as the underlying source for
- connections (DBProxy/Pool is described in the previous
- section). This argument supercedes "poolclass".
+ connections (DBProxy/Pool is described in the previous section).
+ This argument supercedes "poolclass".
echo
- Defaults to False: if True, the Engine will log all statements
+ defaults to False: if True, the Engine will log all statements
as well as a repr() of their parameter lists to the engines
logger, which defaults to ``sys.stdout``. A Engine instances'
`echo` data member can be modified at any time to turn logging
@@ -115,38 +122,36 @@ def create_engine(*args, **kwargs):
printed to the standard output as well.
logger
- Defaults to None: a file-like object where logging output can be
+ defaults to None: a file-like object where logging output can be
sent, if `echo` is set to True. This defaults to
``sys.stdout``.
encoding
- Defaults to 'utf-8': the encoding to be used when
+ defaults to 'utf-8': the encoding to be used when
encoding/decoding Unicode strings.
convert_unicode
- Defaults to False: true if unicode conversion should be applied
+ defaults to False: true if unicode conversion should be applied
to all str types.
module
- Defaults to None: this is a
- reference to a DBAPI2 module to be used instead of the engine's
- default module. For Postgres, the default is psycopg2, or
- psycopg1 if 2 cannot be found. For Oracle, its cx_Oracle. For
- mysql, MySQLdb.
+ defaults to None: this is a reference to a DB-API 2.0 module to
+ be used instead of the dialect's default module.
strategy
- allows alternate Engine implementations to take effect.
- Current implementations include ``plain`` and ``threadlocal``.
- The default used by this function is ``plain``.
-
- ``plain`` provides support for a Connection object which can be used
- to execute SQL queries with a specific underlying DBAPI connection.
-
- ``threadlocal`` is similar to ``plain`` except that it adds support
- for a thread-local connection and transaction context, which
- allows a group of engine operations to participate using the same
- underlying connection and transaction without the need for explicitly
- passing a single Connection.
+ allows alternate Engine implementations to take effect. Current
+ implementations include ``plain`` and ``threadlocal``. The
+ default used by this function is ``plain``.
+
+ ``plain`` provides support for a Connection object which can be
+ used to execute SQL queries with a specific underlying DB-API
+ connection.
+
+ ``threadlocal`` is similar to ``plain`` except that it adds
+ support for a thread-local connection and transaction context,
+ which allows a group of engine operations to participate using
+ the same underlying connection and transaction without the need
+ for explicitly passing a single Connection.
"""
strategy = kwargs.pop('strategy', default_strategy)
@@ -155,17 +160,19 @@ def create_engine(*args, **kwargs):
def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
"""Create a new Engine instance using a configuration dictionary.
-
- the dictionary is typically produced from a config file where keys are prefixed,
- such as sqlalchemy.url, sqlalchemy.echo, etc. The 'prefix' argument indicates
- the prefix to be searched for.
-
- A select set of keyword arguments will be "coerced" to their expected type based on
- string values. in a future release, this functionality will be expanded to include
- dialect-specific arguments.
+
+ The dictionary is typically produced from a config file where keys
+ are prefixed, such as sqlalchemy.url, sqlalchemy.echo, etc. The
+ 'prefix' argument indicates the prefix to be searched for.
+
+ A select set of keyword arguments will be "coerced" to their
+ expected type based on string values. in a future release, this
+ functionality will be expanded to include dialect-specific
+ arguments.
"""
- opts = dict([(key[len(prefix):], configuration[key]) for key in configuration if key.startswith(prefix)])
+ opts = dict([(key[len(prefix):], configuration[key])
+ for key in configuration if key.startswith(prefix)])
for opt, type_ in (
('convert_unicode', bool),
('pool_timeout', int),
diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py
index 553c8df84..298264362 100644
--- a/lib/sqlalchemy/engine/base.py
+++ b/lib/sqlalchemy/engine/base.py
@@ -4,9 +4,13 @@
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
-"""defines the basic components used to interface DBAPI modules with
-higher-level statement-construction, connection-management,
-execution and result contexts."""
+
+"""Basic components for SQL execution and interfacing with DB-API..
+
+Defines the basic components used to interface DB-API modules with
+higher-level statement-construction, connection-management, execution
+and result contexts.
+"""
from sqlalchemy import exceptions, schema, util, types, logging
from sqlalchemy.sql import expression, visitors
@@ -14,105 +18,124 @@ import StringIO, sys
class Dialect(object):
- """Define the behavior of a specific database/DBAPI.
+ """Define the behavior of a specific database and DB-API combination.
- Any aspect of metadata definition, SQL query generation, execution,
- result-set handling, or anything else which varies between
- databases is defined under the general category of the Dialect.
- The Dialect acts as a factory for other database-specific object
- implementations including ExecutionContext, Compiled,
- DefaultGenerator, and TypeEngine.
+ Any aspect of metadata definition, SQL query generation,
+ execution, result-set handling, or anything else which varies
+ between databases is defined under the general category of the
+ Dialect. The Dialect acts as a factory for other
+ database-specific object implementations including
+ ExecutionContext, Compiled, DefaultGenerator, and TypeEngine.
All Dialects implement the following attributes:
- positional
- True if the paramstyle for this Dialect is positional
+ positional
+ True if the paramstyle for this Dialect is positional.
- paramstyle
- The paramstyle to be used (some DBAPIs support multiple paramstyles)
+ paramstyle
+ the paramstyle to be used (some DB-APIs support multiple
+ paramstyles).
- convert_unicode
- True if unicode conversion should be applied to all str types
+ convert_unicode
+ True if Unicode conversion should be applied to all ``str``
+ types.
- encoding
- type of encoding to use for unicode, usually defaults to 'utf-8'
+ encoding
+ type of encoding to use for unicode, usually defaults to
+ 'utf-8'.
- schemagenerator
- a [sqlalchemy.schema#SchemaVisitor] class which generates schemas.
+ schemagenerator
+ a [sqlalchemy.schema#SchemaVisitor] class which generates
+ schemas.
- schemadropper
- a [sqlalchemy.schema#SchemaVisitor] class which drops schemas.
+ schemadropper
+ a [sqlalchemy.schema#SchemaVisitor] class which drops schemas.
- defaultrunner
- a [sqlalchemy.schema#SchemaVisitor] class which executes defaults.
+ defaultrunner
+ a [sqlalchemy.schema#SchemaVisitor] class which executes
+ defaults.
- statement_compiler
- a [sqlalchemy.engine.base#Compiled] class used to compile SQL statements
+ statement_compiler
+ a [sqlalchemy.engine.base#Compiled] class used to compile SQL
+ statements
- preparer
- a [sqlalchemy.sql.compiler#IdentifierPreparer] class used to quote
- identifiers.
+ preparer
+ a [sqlalchemy.sql.compiler#IdentifierPreparer] class used to
+ quote identifiers.
"""
def create_connect_args(self, url):
- """Build DBAPI compatible connection arguments.
+ """Build DB-API compatible connection arguments.
- Given a [sqlalchemy.engine.url#URL] object, returns a
- tuple consisting of a `*args`/`**kwargs` suitable to send directly
- to the dbapi's connect function.
+ Given a [sqlalchemy.engine.url#URL] object, returns a tuple
+ consisting of a `*args`/`**kwargs` suitable to send directly
+ to the dbapi's connect function.
"""
raise NotImplementedError()
def dbapi_type_map(self):
- """return a mapping of DBAPI type objects present in this Dialect's DBAPI
- mapped to TypeEngine implementations used by the dialect.
-
- This is used to apply types to result sets based on the DBAPI types
- present in cursor.description; it only takes effect for result sets against
- textual statements where no explicit typemap was present. Constructed SQL statements
- always have type information explicitly embedded.
+ """Returns a DB-API to sqlalchemy.types mapping.
+
+ A mapping of DB-API type objects present in this Dialect's
+ DB-API implmentation mapped to TypeEngine implementations used
+ by the dialect.
+
+ This is used to apply types to result sets based on the DB-API
+ types present in cursor.description; it only takes effect for
+ result sets against textual statements where no explicit
+ typemap was present. Constructed SQL statements always have
+ type information explicitly embedded.
"""
raise NotImplementedError()
def type_descriptor(self, typeobj):
- """Transform the given [sqlalchemy.types#TypeEngine] instance from generic to database-specific.
+ """Transform a generic type to a database-specific type.
+
+ Transforms the given [sqlalchemy.types#TypeEngine] instance
+ from generic to database-specific.
- Subclasses will usually use the [sqlalchemy.types#adapt_type()] method in the types module
- to make this job easy.
+ Subclasses will usually use the
+ [sqlalchemy.types#adapt_type()] method in the types module to
+ make this job easy.
"""
raise NotImplementedError()
def oid_column_name(self, column):
- """Return the oid column name for this dialect, or ``None`` if the dialect can't/won't support OID/ROWID.
+ """Return the oid column name for this Dialect
- The [sqlalchemy.schema#Column] instance which represents OID for the query being
- compiled is passed, so that the dialect can inspect the column
- and its parent selectable to determine if OID/ROWID is not
- selected for a particular selectable (i.e. oracle doesnt
- support ROWID for UNION, GROUP BY, DISTINCT, etc.)
+ May return ``None`` if the dialect can't o won't support
+ OID/ROWID features.
+
+ The [sqlalchemy.schema#Column] instance which represents OID
+ for the query being compiled is passed, so that the dialect
+ can inspect the column and its parent selectable to determine
+ if OID/ROWID is not selected for a particular selectable
+ (i.e. Oracle doesnt support ROWID for UNION, GROUP BY,
+ DISTINCT, etc.)
"""
raise NotImplementedError()
def supports_alter(self):
- """return ``True`` if the database supports ``ALTER TABLE``."""
+ """Return ``True`` if the database supports ``ALTER TABLE``."""
raise NotImplementedError()
def max_identifier_length(self):
"""Return the maximum length of identifier names.
-
- Return ``None`` if no limit."""
-
+
+ Returns ``None`` if no limit.
+ """
+
return None
def supports_unicode_statements(self):
- """indicate whether the DBAPI can receive SQL statements as Python unicode strings"""
-
+ """Indicate whether the DB-API can receive SQL statements as Python unicode strings"""
+
raise NotImplementedError()
-
+
def supports_sane_rowcount(self):
"""Indicate whether the dialect properly implements rowcount for ``UPDATE`` and ``DELETE`` statements.
@@ -131,9 +154,11 @@ class Dialect(object):
def reflecttable(self, connection, table, include_columns=None):
"""Load table description from the database.
- Given a [sqlalchemy.engine#Connection] and a [sqlalchemy.schema#Table] object, reflect its
- columns and properties from the database. If include_columns (a list or set) is specified, limit the autoload
- to the given column names.
+ Given a [sqlalchemy.engine#Connection] and a
+ [sqlalchemy.schema#Table] object, reflect its columns and
+ properties from the database. If include_columns (a list or
+ set) is specified, limit the autoload to the given column
+ names.
"""
raise NotImplementedError()
@@ -141,9 +166,10 @@ class Dialect(object):
def has_table(self, connection, table_name, schema=None):
"""Check the existence of a particular table in the database.
- Given a [sqlalchemy.engine#Connection] object and a string `table_name`, return True
- if the given table (possibly within the specified `schema`)
- exists in the database, False otherwise.
+ Given a [sqlalchemy.engine#Connection] object and a string
+ `table_name`, return True if the given table (possibly within
+ the specified `schema`) exists in the database, False
+ otherwise.
"""
raise NotImplementedError()
@@ -151,9 +177,9 @@ class Dialect(object):
def has_sequence(self, connection, sequence_name):
"""Check the existence of a particular sequence in the database.
- Given a [sqlalchemy.engine#Connection] object and a string `sequence_name`, return
- True if the given sequence exists in the database, False
- otherwise.
+ Given a [sqlalchemy.engine#Connection] object and a string
+ `sequence_name`, return True if the given sequence exists in
+ the database, False otherwise.
"""
raise NotImplementedError()
@@ -165,29 +191,31 @@ class Dialect(object):
def create_execution_context(self, connection, compiled=None, compiled_parameters=None, statement=None, parameters=None):
"""Return a new [sqlalchemy.engine#ExecutionContext] object."""
-
+
raise NotImplementedError()
def do_begin(self, connection):
- """Provide an implementation of *connection.begin()*, given a DBAPI connection."""
+ """Provide an implementation of *connection.begin()*, given a DB-API connection."""
raise NotImplementedError()
def do_rollback(self, connection):
- """Provide an implementation of *connection.rollback()*, given a DBAPI connection."""
+ """Provide an implementation of *connection.rollback()*, given a DB-API connection."""
raise NotImplementedError()
def create_xid(self):
- """create a two-phase transaction ID.
+ """Create a two-phase transaction ID.
- this id will be passed to do_begin_twophase(), do_rollback_twophase(),
- do_commit_twophase(). its format is unspecified."""
+ This id will be passed to do_begin_twophase(),
+ do_rollback_twophase(), do_commit_twophase(). Its format is
+ unspecified.
+ """
raise NotImplementedError()
def do_commit(self, connection):
- """Provide an implementation of *connection.commit()*, given a DBAPI connection."""
+ """Provide an implementation of *connection.commit()*, given a DB-API connection."""
raise NotImplementedError()
@@ -242,8 +270,8 @@ class Dialect(object):
raise NotImplementedError()
def is_disconnect(self, e):
- """Return True if the given DBAPI error indicates an invalid connection"""
-
+ """Return True if the given DB-API error indicates an invalid connection"""
+
raise NotImplementedError()
@@ -251,107 +279,106 @@ class ExecutionContext(object):
"""A messenger object for a Dialect that corresponds to a single execution.
ExecutionContext should have these datamembers:
-
- connection
- Connection object which can be freely used by default value generators
- to execute SQL. This Connection should reference the same underlying
- connection/transactional resources of root_connection.
-
- root_connection
- Connection object which is the source of this ExecutionContext. This
- Connection may have close_with_result=True set, in which case it can
- only be used once.
- dialect
- dialect which created this ExecutionContext.
-
- cursor
- DBAPI cursor procured from the connection
-
- compiled
- if passed to constructor, sqlalchemy.engine.base.Compiled object being executed
-
- statement
- string version of the statement to be executed. Is either
- passed to the constructor, or must be created from the
- sql.Compiled object by the time pre_exec() has completed.
-
- parameters
- bind parameters passed to the execute() method. for
- compiled statements, this is a dictionary or list
- of dictionaries. for textual statements, it should
- be in a format suitable for the dialect's paramstyle
- (i.e. dict or list of dicts for non positional,
- list or list of lists/tuples for positional).
-
- isinsert
- True if the statement is an INSERT
-
- isupdate
- True if the statement is an UPDATE
-
+ connection
+ Connection object which can be freely used by default value
+ generators to execute SQL. This Connection should reference the
+ same underlying connection/transactional resources of
+ root_connection.
+
+ root_connection
+ Connection object which is the source of this ExecutionContext. This
+ Connection may have close_with_result=True set, in which case it can
+ only be used once.
+
+ dialect
+ dialect which created this ExecutionContext.
+
+ cursor
+ DB-API cursor procured from the connection,
+
+ compiled
+ if passed to constructor, sqlalchemy.engine.base.Compiled object
+ being executed,
+
+ statement
+ string version of the statement to be executed. Is either
+ passed to the constructor, or must be created from the
+ sql.Compiled object by the time pre_exec() has completed.
+
+ parameters
+ bind parameters passed to the execute() method. For compiled
+ statements, this is a dictionary or list of dictionaries. For
+ textual statements, it should be in a format suitable for the
+ dialect's paramstyle (i.e. dict or list of dicts for non
+ positional, list or list of lists/tuples for positional).
+
+ isinsert
+ True if the statement is an INSERT.
+
+ isupdate
+ True if the statement is an UPDATE.
+
The Dialect should provide an ExecutionContext via the
create_execution_context() method. The `pre_exec` and `post_exec`
methods will be called for compiled statements.
-
"""
def create_cursor(self):
"""Return a new cursor generated from this ExecutionContext's connection.
-
- Some dialects may wish to change the behavior of connection.cursor(),
- such as postgres which may return a PG "server side" cursor.
+
+ Some dialects may wish to change the behavior of
+ connection.cursor(), such as postgres which may return a PG
+ "server side" cursor.
"""
raise NotImplementedError()
def pre_execution(self):
"""Called before an execution of a compiled statement.
-
- If a compiled statement was passed to this
- ExecutionContext, the `statement` and `parameters` datamembers
- must be initialized after this statement is complete.
+
+ If a compiled statement was passed to this ExecutionContext,
+ the `statement` and `parameters` datamembers must be
+ initialized after this statement is complete.
"""
raise NotImplementedError()
def post_execution(self):
"""Called after the execution of a compiled statement.
-
+
If a compiled statement was passed to this ExecutionContext,
- the `last_insert_ids`, `last_inserted_params`, etc.
- datamembers should be available after this method
- completes.
+ the `last_insert_ids`, `last_inserted_params`, etc.
+ datamembers should be available after this method completes.
"""
raise NotImplementedError()
-
+
def result(self):
- """return a result object corresponding to this ExecutionContext.
-
- Returns a ResultProxy."""
-
+ """Return a result object corresponding to this ExecutionContext.
+
+ Returns a ResultProxy.
+ """
+
raise NotImplementedError()
-
+
def get_rowcount(self):
"""Return the count of rows updated/deleted for an UPDATE/DELETE statement."""
raise NotImplementedError()
def should_autocommit(self):
- """return True if this context's statement should be 'committed' automatically in a non-transactional context"""
+ """Return True if this context's statement should be 'committed' automatically in a non-transactional context"""
raise NotImplementedError()
-
+
def last_inserted_ids(self):
"""Return the list of the primary key values for the last insert statement executed.
This does not apply to straight textual clauses; only to
- ``sql.Insert`` objects compiled against a ``schema.Table`` object.
- The order of
- items in the list is the same as that of the Table's
- 'primary_key' attribute.
-
+ ``sql.Insert`` objects compiled against a ``schema.Table``
+ object. The order of items in the list is the same as that of
+ the Table's 'primary_key' attribute.
"""
raise NotImplementedError()
@@ -498,7 +525,7 @@ class Connectable(object):
dialect = util.NotImplProperty("Dialect which this Connectable is associated with.")
class Connection(Connectable):
- """Represent a single DBAPI connection returned from the underlying connection pool.
+ """Provides high-level functionality for a wrapped DB-API connection.
Provides execution support for string-based SQL statements as well
as ClauseElement, Compiled and DefaultGenerator objects. Provides
@@ -507,7 +534,15 @@ class Connection(Connectable):
The Connection object is **not** threadsafe.
"""
- def __init__(self, engine, connection=None, close_with_result=False, _branch=False):
+ def __init__(self, engine, connection=None, close_with_result=False,
+ _branch=False):
+ """Construct a new Connection.
+
+ Connection objects are typically constructed by an
+ [sqlalchemy.engine#Engine], see the ``connect()`` and
+ ``contextual_connect()`` methods of Engine.
+ """
+
self.__engine = engine
self.__connection = connection or engine.raw_connection()
self.__transaction = None
@@ -525,82 +560,130 @@ class Connection(Connectable):
"""return a new Connection which references this Connection's
engine and connection; but does not have close_with_result enabled,
and also whose close() method does nothing.
-
+
This is used to execute "sub" statements within a single execution,
usually an INSERT statement.
"""
-
+
return Connection(self.__engine, self.__connection, _branch=True)
-
+
engine = property(lambda s:s.__engine, doc="The Engine with which this Connection is associated.")
dialect = property(lambda s:s.__engine.dialect, doc="Dialect used by this Connection.")
- connection = property(_get_connection, doc="The underlying DBAPI connection managed by this Connection.")
+ connection = property(_get_connection, doc="The underlying DB-API connection managed by this Connection.")
should_close_with_result = property(lambda s:s.__close_with_result, doc="Indicates if this Connection should be closed when a corresponding ResultProxy is closed; this is essentially an auto-release mode.")
properties = property(lambda s: s._get_connection().properties,
- doc="A set of per-DBAPI connection properties.")
+ doc="A collection of per-DB-API connection instance properties.")
def connect(self):
- """connect() is implemented to return self so that an incoming Engine or Connection object can be treated similarly."""
+ """Returns self.
+
+ This ``Connectable`` interface method returns self, allowing
+ Connections to be used interchangably with Engines in most
+ situations that require a bind.
+ """
+
return self
def contextual_connect(self, **kwargs):
- """contextual_connect() is implemented to return self so that an incoming Engine or Connection object can be treated similarly."""
+ """Returns self.
+
+ This ``Connectable`` interface method returns self, allowing
+ Connections to be used interchangably with Engines in most
+ situations that require a bind.
+ """
+
return self
def invalidate(self):
- """invalidate the underying DBAPI connection and immediately close this Connection.
-
- The underlying DBAPI connection is literally closed (if possible), and is discarded.
- Its source connection pool will typically create a new connection to replace it, once
- requested.
+ """Invalidate and close the Connection.
+
+ The underlying DB-API connection is literally closed (if
+ possible), and is discarded. Its source connection pool will
+ typically lazilly create a new connection to replace it.
"""
-
+
self.__connection.invalidate()
self.__connection = None
def detach(self):
- """detach the underlying DBAPI connection from its connection pool.
-
- This Connection instance will remain useable. When closed, the
- DBAPI connection will be literally closed and not returned to its pool.
- The pool will typically create a new connection to replace it, once requested.
-
- This method can be used to insulate the rest of an application from a modified
- state on a connection (such as a transaction isolation level or similar).
+ """Detach the underlying DB-API connection from its connection pool.
+
+ This Connection instance will remain useable. When closed,
+ the DB-API connection will be literally closed and not
+ returned to its pool. The pool will typically lazily create a
+ new connection to replace the detached connection.
+
+ This method can be used to insulate the rest of an application
+ from a modified state on a connection (such as a transaction
+ isolation level or similar). Also see
+ [sqlalchemy.interfaces#PoolListener] for a mechanism to modify
+ connection state when connections leave and return to their
+ connection pool.
"""
-
+
self.__connection.detach()
-
- def begin(self, nested=False):
+
+ def begin(self):
+ """Begin a transaction and return a Transaction handle.
+
+ Repeated calls to ``begin`` on the same Connection will create
+ a lightweight, emulated nested transaction. Only the
+ outermost transaction may ``commit``. Calls to ``commit`` on
+ inner transactions are ignored. Any transaction in the
+ hierarchy may ``rollback``, however.
+ """
+
if self.__transaction is None:
self.__transaction = RootTransaction(self)
- elif nested:
- self.__transaction = NestedTransaction(self, self.__transaction)
else:
return Transaction(self, self.__transaction)
return self.__transaction
def begin_nested(self):
- return self.begin(nested=True)
-
+ """Begin a nested transaction and return a Transaction handle.
+
+ Nested transactions require SAVEPOINT support in the
+ underlying database. Any transaction in the hierarchy may
+ ``commit`` and ``rollback``, however the outermost transaction
+ still controls the overall ``commit`` or ``rollback`` of the
+ transaction of a whole.
+ """
+
+ if self.__transaction is None:
+ self.__transaction = RootTransaction(self)
+ else:
+ self.__transaction = NestedTransaction(self, self.__transaction)
+ return self.__transaction
+
def begin_twophase(self, xid=None):
+ """Begin a two-phase or XA transaction and return a Transaction handle.
+
+ xid
+ the two phase transaction id. If not supplied, a random id
+ will be generated.
+ """
+
if self.__transaction is not None:
- raise exceptions.InvalidRequestError("Cannot start a two phase transaction when a transaction is already started.")
+ raise exceptions.InvalidRequestError(
+ "Cannot start a two phase transaction when a transaction "
+ "is already in progress.")
if xid is None:
xid = self.__engine.dialect.create_xid();
self.__transaction = TwoPhaseTransaction(self, xid)
return self.__transaction
-
+
def recover_twophase(self):
return self.__engine.dialect.do_recover_twophase(self)
-
+
def rollback_prepared(self, xid, recover=False):
self.__engine.dialect.do_rollback_twophase(self, xid, recover=recover)
-
+
def commit_prepared(self, xid, recover=False):
self.__engine.dialect.do_commit_twophase(self, xid, recover=recover)
def in_transaction(self):
+ """Return True if a transaction is in progress."""
+
return self.__transaction is not None
def _begin_impl(self):
@@ -636,26 +719,26 @@ class Connection(Connectable):
if self.__connection.is_valid:
self.__engine.dialect.do_savepoint(self, name)
return name
-
+
def _rollback_to_savepoint_impl(self, name, context):
if self.__connection.is_valid:
self.__engine.dialect.do_rollback_to_savepoint(self, name)
self.__transaction = context
-
+
def _release_savepoint_impl(self, name, context):
if self.__connection.is_valid:
self.__engine.dialect.do_release_savepoint(self, name)
self.__transaction = context
-
+
def _begin_twophase_impl(self, xid):
if self.__connection.is_valid:
self.__engine.dialect.do_begin_twophase(self, xid)
-
+
def _prepare_twophase_impl(self, xid):
if self.__connection.is_valid:
assert isinstance(self.__transaction, TwoPhaseTransaction)
self.__engine.dialect.do_prepare_twophase(self, xid)
-
+
def _rollback_twophase_impl(self, xid, is_prepared):
if self.__connection.is_valid:
assert isinstance(self.__transaction, TwoPhaseTransaction)
@@ -669,17 +752,26 @@ class Connection(Connectable):
self.__transaction = None
def _autocommit(self, context):
- """When no Transaction is present, this is called after executions to provide "autocommit" behavior."""
- # TODO: have the dialect determine if autocommit can be set on the connection directly without this
- # extra step
+ """Possibly issue a commit.
+
+ When no Transaction is present, this is called after statement
+ execution to provide "autocommit" behavior. Dialects may
+ inspect the statement to determine if a commit is actually
+ required.
+ """
+
+ # TODO: have the dialect determine if autocommit can be set on
+ # the connection directly without this extra step
if not self.in_transaction() and context.should_autocommit():
self._commit_impl()
def _autorollback(self):
if not self.in_transaction():
self._rollback_impl()
-
+
def close(self):
+ """Close this Connection."""
+
try:
c = self.__connection
except AttributeError:
@@ -690,12 +782,16 @@ class Connection(Connectable):
del self.__connection
def scalar(self, object, *multiparams, **params):
+ """Executes and returns the first column of the first row."""
+
return self.execute(object, *multiparams, **params).scalar()
def statement_compiler(self, statement, parameters, **kwargs):
return self.dialect.statement_compiler(self.dialect, statement, parameters, bind=self, **kwargs)
def execute(self, object, *multiparams, **params):
+ """Executes and returns a ResultProxy."""
+
for c in type(object).__mro__:
if c in Connection.executors:
return Connection.executors[c](self, object, multiparams, params)
@@ -722,7 +818,7 @@ class Connection(Connectable):
def _execute_function(self, func, multiparams, params):
return self._execute_clauseelement(func.select(), multiparams, params)
-
+
def _execute_clauseelement(self, elem, multiparams=None, params=None):
executemany = multiparams is not None and len(multiparams) > 0
if executemany:
@@ -738,15 +834,15 @@ class Connection(Connectable):
params = self.__distill_params(multiparams, params)
context = self.__create_execution_context(compiled=compiled, parameters=params)
-
+
context.pre_execution()
self.__execute_raw(context)
context.post_execution()
return context.result()
-
+
def __create_execution_context(self, **kwargs):
return self.__engine.dialect.create_execution_context(connection=self, **kwargs)
-
+
def __execute_raw(self, context):
if logging.is_info_enabled(self.__engine.logger):
self.__engine.logger.info(context.statement)
@@ -756,7 +852,7 @@ class Connection(Connectable):
else:
self.__execute(context)
self._autocommit(context)
-
+
def __execute(self, context):
if context.parameters is None:
if context.dialect.positional:
@@ -834,10 +930,11 @@ class Transaction(object):
def close(self):
"""close this transaction.
-
- If this transaction is the base transaction in a begin/commit nesting,
- the transaction will rollback(). Otherwise, the method returns.
-
+
+ If this transaction is the base transaction in a begin/commit
+ nesting, the transaction will rollback(). Otherwise, the
+ method returns.
+
This is used to cancel a Transaction without affecting the scope of
an enclosign transaction.
"""
@@ -845,13 +942,13 @@ class Transaction(object):
return
if self._parent is self:
self.rollback()
-
+
def rollback(self):
if not self._parent._is_active:
return
self._is_active = False
self._do_rollback()
-
+
def _do_rollback(self):
self._parent.rollback()
@@ -860,7 +957,7 @@ class Transaction(object):
raise exceptions.InvalidRequestError("This transaction is inactive")
self._is_active = False
self._do_commit()
-
+
def _do_commit(self):
pass
@@ -1084,7 +1181,7 @@ class Engine(Connectable):
return self.run_callable(lambda c: self.dialect.has_table(c, table_name, schema=schema))
def raw_connection(self):
- """Return a DBAPI connection."""
+ """Return a DB-API connection."""
return self.pool.connect()
@@ -1094,7 +1191,7 @@ class Engine(Connectable):
self.logger.info(msg)
class ResultProxy(object):
- """Wraps a DBAPI cursor object to provide easier access to row columns.
+ """Wraps a DB-API cursor object to provide easier access to row columns.
Individual columns may be accessed by their integer position,
case-insensitive column name, or by ``schema.Column``
@@ -1119,7 +1216,7 @@ class ResultProxy(object):
def process(value):
raise exceptions.InvalidRequestError("Ambiguous column name '%s' in result set! try 'use_labels' option on select statement." % colname)
return process
-
+
def __init__(self, context):
"""ResultProxy objects are constructed via the execute() method on SQLEngine."""
self.context = context
@@ -1134,9 +1231,9 @@ class ResultProxy(object):
else:
self._rowcount = context.get_rowcount()
self.close()
-
+
connection = property(lambda self:self.context.root_connection)
-
+
def _get_rowcount(self):
if self._rowcount is not None:
return self._rowcount
@@ -1145,7 +1242,7 @@ class ResultProxy(object):
rowcount = property(_get_rowcount)
lastrowid = property(lambda s:s.cursor.lastrowid)
out_parameters = property(lambda s:s.context.out_parameters)
-
+
def _init_metadata(self):
if hasattr(self, '_ResultProxy__props'):
return
@@ -1201,13 +1298,13 @@ class ResultProxy(object):
return rec
return util.PopulateDict(lookup_key)
-
+
def close(self):
- """Close this ResultProxy, and the underlying DBAPI cursor corresponding to the execution.
+ """Close this ResultProxy, and the underlying DB-API cursor corresponding to the execution.
If this ResultProxy was generated from an implicit execution,
the underlying Connection will also be closed (returns the
- underlying DBAPI connection to the connection pool.)
+ underlying DB-API connection to the connection pool.)
This method is also called automatically when all result rows
are exhausted.
@@ -1217,9 +1314,9 @@ class ResultProxy(object):
self.cursor.close()
if self.connection.should_close_with_result:
self.connection.close()
-
+
keys = property(lambda s:s.__keys)
-
+
def _has_key(self, row, key):
try:
self._key_cache[key]
@@ -1267,7 +1364,6 @@ class ResultProxy(object):
return self.context.lastrow_has_defaults()
-
def supports_sane_rowcount(self):
"""Return ``supports_sane_rowcount()`` from the underlying ExecutionContext.
@@ -1282,7 +1378,7 @@ class ResultProxy(object):
return rec[1](row[rec[2]])
else:
return row[rec[2]]
-
+
def _fetchone_impl(self):
return self.cursor.fetchone()
def _fetchmany_impl(self, size=None):
@@ -1292,16 +1388,16 @@ class ResultProxy(object):
def _row_processor(self):
return RowProxy
-
+
def fetchall(self):
- """Fetch all rows, just like DBAPI ``cursor.fetchall()``."""
+ """Fetch all rows, just like DB-API ``cursor.fetchall()``."""
l = [self._process_row(self, row) for row in self._fetchall_impl()]
self.close()
return l
def fetchmany(self, size=None):
- """Fetch many rows, just like DBAPI ``cursor.fetchmany(size=cursor.arraysize)``."""
+ """Fetch many rows, just like DB-API ``cursor.fetchmany(size=cursor.arraysize)``."""
l = [self._process_row(self, row) for row in self._fetchmany_impl(size)]
if len(l) == 0:
@@ -1309,7 +1405,7 @@ class ResultProxy(object):
return l
def fetchone(self):
- """Fetch one row, just like DBAPI ``cursor.fetchone()``."""
+ """Fetch one row, just like DB-API ``cursor.fetchone()``."""
row = self._fetchone_impl()
if row is not None:
return self._process_row(self, row)
@@ -1329,20 +1425,23 @@ class ResultProxy(object):
self.close()
class BufferedRowResultProxy(ResultProxy):
- """``ResultProxy`` that buffers the contents of a selection of rows before
- ``fetchone()`` is called. This is to allow the results of
- ``cursor.description`` to be available immediately, when interfacing
- with a DBAPI that requires rows to be consumed before this information is
- available (currently psycopg2, when used with server-side cursors).
-
- The pre-fetching behavior fetches only one row initially, and then grows
- its buffer size by a fixed amount with each successive need for additional
- rows up to a size of 100.
+ """A ResultProxy with row buffering behavior.
+
+ ``ResultProxy`` that buffers the contents of a selection of rows
+ before ``fetchone()`` is called. This is to allow the results of
+ ``cursor.description`` to be available immediately, when
+ interfacing with a DB-API that requires rows to be consumed before
+ this information is available (currently psycopg2, when used with
+ server-side cursors).
+
+ The pre-fetching behavior fetches only one row initially, and then
+ grows its buffer size by a fixed amount with each successive need
+ for additional rows up to a size of 100.
"""
def _init_metadata(self):
self.__buffer_rows()
super(BufferedRowResultProxy, self)._init_metadata()
-
+
# this is a "growth chart" for the buffering of rows.
# each successive __buffer_rows call will use the next
# value in the list for the buffer size until the max
@@ -1354,13 +1453,13 @@ class BufferedRowResultProxy(ResultProxy):
20 : 50,
50 : 100
}
-
+
def __buffer_rows(self):
size = getattr(self, '_bufsize', 1)
self.__rowbuffer = self.cursor.fetchmany(size)
#self.context.engine.logger.debug("Buffered %d rows" % size)
self._bufsize = self.size_growth.get(size, size)
-
+
def _fetchone_impl(self):
if self.closed:
return None
@@ -1378,19 +1477,22 @@ class BufferedRowResultProxy(ResultProxy):
break
result.append(row)
return result
-
+
def _fetchall_impl(self):
return self.__rowbuffer + list(self.cursor.fetchall())
class BufferedColumnResultProxy(ResultProxy):
- """``ResultProxy`` that loads all columns into memory each time fetchone() is
- called. If fetchmany() or fetchall() are called, the full grid of results
- is fetched. This is to operate with databases where result rows contain "live"
- results that fall out of scope unless explicitly fetched. Currently this includes
- just cx_Oracle LOB objects, but this behavior is known to exist in other DBAPIs as
- well (Pygresql, currently unsupported).
-
+ """A ResultProxy with column buffering behavior.
+
+ ``ResultProxy`` that loads all columns into memory each time
+ fetchone() is called. If fetchmany() or fetchall() are called,
+ the full grid of results is fetched. This is to operate with
+ databases where result rows contain "live" results that fall out
+ of scope unless explicitly fetched. Currently this includes just
+ cx_Oracle LOB objects, but this behavior is known to exist in
+ other DB-APIs as well (Pygresql, currently unsupported).
"""
+
def _get_col(self, row, key):
rec = self._key_cache[key]
return row[rec[2]]
@@ -1443,7 +1545,7 @@ class RowProxy(object):
def __contains__(self, key):
return self.__parent._has_key(self.__row, key)
-
+
def __iter__(self):
for i in range(0, len(self.__row)):
yield self.__parent._get_col(self.__row, i)
@@ -1531,7 +1633,7 @@ class DefaultRunner(schema.SchemaVisitor):
self.context = context
self.connection = self.context._connection._branch()
dialect = property(lambda self:self.context.dialect)
-
+
def get_column_default(self, column):
if column.default is not None:
return self.traverse_single(column.default)
diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py
index 17986286d..ec8d8d5a7 100644
--- a/lib/sqlalchemy/engine/default.py
+++ b/lib/sqlalchemy/engine/default.py
@@ -4,17 +4,20 @@
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
-"""Provide default implementations of per-dialect sqlalchemy.engine classes"""
+"""Default implementations of per-dialect sqlalchemy.engine classes."""
+
from sqlalchemy import schema, exceptions, util
import re, random
from sqlalchemy.engine import base
from sqlalchemy.sql import compiler, expression
+
AUTOCOMMIT_REGEXP = re.compile(r'\s*(?:UPDATE|INSERT|CREATE|DELETE|DROP|ALTER)',
re.I | re.UNICODE)
SELECT_REGEXP = re.compile(r'\s*SELECT', re.I | re.UNICODE)
+
class DefaultDialect(base.Dialect):
"""Default implementation of Dialect"""
@@ -34,7 +37,7 @@ class DefaultDialect(base.Dialect):
self.identifier_preparer = self.preparer(self)
def dbapi_type_map(self):
- # most DBAPIs have problems with this (such as, psycocpg2 types
+ # most DB-APIs have problems with this (such as, psycocpg2 types
# are unhashable). So far Oracle can return it.
return {}
@@ -53,14 +56,12 @@ class DefaultDialect(base.Dialect):
typeobj = typeobj()
return typeobj
-
def supports_unicode_statements(self):
- """indicate whether the DBAPI can receive SQL statements as Python unicode strings"""
+ """True if DB-API can receive SQL statements as Python Unicode."""
return False
def max_identifier_length(self):
- # TODO: probably raise this and fill out
- # db modules better
+ # TODO: probably raise this and fill out db modules better
return 9999
def supports_alter(self):
@@ -84,7 +85,6 @@ class DefaultDialect(base.Dialect):
autocommit on/off, etc.
"""
- #print "ENGINE ROLLBACK ON ", connection.connection
connection.rollback()
def do_commit(self, connection):
@@ -92,14 +92,13 @@ class DefaultDialect(base.Dialect):
autocommit on/off, etc.
"""
- #print "ENGINE COMMIT ON ", connection.connection
connection.commit()
def create_xid(self):
- """create a two-phase transaction ID.
+ """Create a random two-phase transaction ID.
- this id will be passed to do_begin_twophase(), do_rollback_twophase(),
- do_commit_twophase(). its format is unspecified."""
+ This id will be passed to do_begin_twophase(), do_rollback_twophase(),
+ do_commit_twophase(). Its format is unspecified."""
return "_sa_%032x" % random.randint(0,2**128)
@@ -118,7 +117,6 @@ class DefaultDialect(base.Dialect):
def do_execute(self, cursor, statement, parameters, **kwargs):
cursor.execute(statement, parameters)
-
def is_disconnect(self, e):
return False
@@ -128,7 +126,6 @@ class DefaultDialect(base.Dialect):
paramstyle = property(lambda s:s._paramstyle, _set_paramstyle)
-
def _figure_paramstyle(self, paramstyle=None, default='named'):
if paramstyle is not None:
self._paramstyle = paramstyle
@@ -156,6 +153,7 @@ class DefaultDialect(base.Dialect):
return self._ischema
ischema = property(_get_ischema, doc="""returns an ISchema object for this engine, which allows access to information_schema tables (if supported)""")
+
class DefaultExecutionContext(base.ExecutionContext):
def __init__(self, dialect, connection, compiled=None, statement=None, parameters=None):
self.dialect = dialect
@@ -218,9 +216,9 @@ class DefaultExecutionContext(base.ExecutionContext):
def __convert_compiled_params(self, parameters):
encode = not self.dialect.supports_unicode_statements()
- # the bind params are a CompiledParams object. but all the DBAPI's hate
- # that object (or similar). so convert it to a clean
- # dictionary/list/tuple of dictionary/tuple of list
+ # the bind params are a CompiledParams object. but all the
+ # DB-API's hate that object (or similar). so convert it to a
+ # clean dictionary/list/tuple of dictionary/tuple of list
if parameters is not None:
if self.executemany:
processors = parameters[0].get_processors()
@@ -295,7 +293,7 @@ class DefaultExecutionContext(base.ExecutionContext):
def set_input_sizes(self):
"""Given a cursor and ClauseParameters, call the appropriate
- style of ``setinputsizes()`` on the cursor, using DBAPI types
+ style of ``setinputsizes()`` on the cursor, using DB-API types
from the bind parameter's ``TypeEngine`` objects.
"""
diff --git a/lib/sqlalchemy/engine/strategies.py b/lib/sqlalchemy/engine/strategies.py
index 168a9c4ab..a0a6445fd 100644
--- a/lib/sqlalchemy/engine/strategies.py
+++ b/lib/sqlalchemy/engine/strategies.py
@@ -1,4 +1,4 @@
-"""Define different strategies for creating new instances of sql.Engine.
+"""Strategies for creating new instances of Engine types.
By default there are two, one which is the "thread-local" strategy,
one which is the "plain" strategy.
@@ -15,9 +15,10 @@ from sqlalchemy import pool as poollib
strategies = {}
class EngineStrategy(object):
- """Define a function that receives input arguments and produces an
- instance of sql.Engine, typically an instance
- sqlalchemy.engine.base.Engine or a subclass.
+ """An adaptor that processes input arguements and produces an Engine.
+
+ Provides a ``create`` method that receives input arguments and
+ produces an instance of base.Engine or a subclass.
"""
def __init__(self, name):
@@ -30,11 +31,13 @@ class EngineStrategy(object):
strategies[self.name] = self
def create(self, *args, **kwargs):
- """Given arguments, returns a new sql.Engine instance."""
+ """Given arguments, returns a new Engine instance."""
raise NotImplementedError()
class DefaultEngineStrategy(EngineStrategy):
+ """Base class for built-in stratgies."""
+
def create(self, name_or_url, **kwargs):
# create url.URL object
u = url.make_url(name_or_url)
@@ -54,9 +57,9 @@ class DefaultEngineStrategy(EngineStrategy):
if k in kwargs:
dbapi_args[k] = kwargs.pop(k)
dbapi = dialect_cls.dbapi(**dbapi_args)
-
+
dialect_args['dbapi'] = dbapi
-
+
# create dialect
dialect = dialect_cls(**dialect_args)
@@ -78,9 +81,13 @@ class DefaultEngineStrategy(EngineStrategy):
getattr(dialect_cls, 'poolclass', poollib.QueuePool))
pool_args = {}
- # consume pool arguments from kwargs, translating a few of the arguments
+ # consume pool arguments from kwargs, translating a few of
+ # the arguments
+ translate = {'echo': 'echo_pool',
+ 'timeout': 'pool_timeout',
+ 'recycle': 'pool_recycle'}
for k in util.get_cls_kwargs(poolclass):
- tk = {'echo':'echo_pool', 'timeout':'pool_timeout', 'recycle':'pool_recycle'}.get(k, k)
+ tk = translate.get(k, k)
if tk in kwargs:
pool_args[k] = kwargs.pop(tk)
pool_args['use_threadlocal'] = self.pool_threadlocal()
@@ -100,8 +107,14 @@ class DefaultEngineStrategy(EngineStrategy):
# all kwargs should be consumed
if kwargs:
- raise TypeError("Invalid argument(s) %s sent to create_engine(), using configuration %s/%s/%s. Please check that the keyword arguments are appropriate for this combination of components." % (','.join(["'%s'" % k for k in kwargs]), dialect.__class__.__name__, pool.__class__.__name__, engineclass.__name__))
-
+ raise TypeError(
+ "Invalid argument(s) %s sent to create_engine(), "
+ "using configuration %s/%s/%s. Please check that the "
+ "keyword arguments are appropriate for this combination "
+ "of components." % (','.join(["'%s'" % k for k in kwargs]),
+ dialect.__class__.__name__,
+ pool.__class__.__name__,
+ engineclass.__name__))
return engineclass(pool, dialect, u, **engine_args)
def pool_threadlocal(self):
@@ -111,6 +124,8 @@ class DefaultEngineStrategy(EngineStrategy):
raise NotImplementedError()
class PlainEngineStrategy(DefaultEngineStrategy):
+ """Strategy for configuring a regular Engine."""
+
def __init__(self):
DefaultEngineStrategy.__init__(self, 'plain')
@@ -123,6 +138,8 @@ class PlainEngineStrategy(DefaultEngineStrategy):
PlainEngineStrategy()
class ThreadLocalEngineStrategy(DefaultEngineStrategy):
+ """Strategy for configuring an Engine with thredlocal behavior."""
+
def __init__(self):
DefaultEngineStrategy.__init__(self, 'threadlocal')
@@ -136,11 +153,15 @@ ThreadLocalEngineStrategy()
class MockEngineStrategy(EngineStrategy):
- """Produces a single Connection object which dispatches statement executions
- to a passed-in function"""
+ """Strategy for configuring an Engine-like object with mocked execution.
+
+ Produces a single mock Connectable object which dispatches
+ statement execution to a passed-in function.
+ """
+
def __init__(self):
EngineStrategy.__init__(self, 'mock')
-
+
def create(self, name_or_url, executor, **kwargs):
# create url.URL object
u = url.make_url(name_or_url)
@@ -165,12 +186,13 @@ class MockEngineStrategy(EngineStrategy):
engine = property(lambda s: s)
dialect = property(lambda s:s._dialect)
-
+
def contextual_connect(self, **kwargs):
return self
def compiler(self, statement, parameters, **kwargs):
- return self._dialect.compiler(statement, parameters, engine=self, **kwargs)
+ return self._dialect.compiler(
+ statement, parameters, engine=self, **kwargs)
def create(self, entity, **kwargs):
kwargs['checkfirst'] = False
diff --git a/lib/sqlalchemy/engine/threadlocal.py b/lib/sqlalchemy/engine/threadlocal.py
index 982be3f05..e9843ea2e 100644
--- a/lib/sqlalchemy/engine/threadlocal.py
+++ b/lib/sqlalchemy/engine/threadlocal.py
@@ -1,11 +1,10 @@
from sqlalchemy import util
from sqlalchemy.engine import base
-"""Provide a thread-local transactional wrapper around the root Engine class.
+"""Provides a thread-local transactional wrapper around the root Engine class.
-Multiple calls to engine.connect() will return the same connection for
-the same thread. also provides begin/commit methods on the engine
-itself which correspond to a thread-local transaction.
+Provides begin/commit methods on the engine itself which correspond to
+a thread-local transaction.
"""
class TLSession(object):
@@ -32,10 +31,10 @@ class TLSession(object):
if self.__tcount == 1:
self.__trans._trans.rollback()
self.reset()
-
+
def in_transaction(self):
return self.__tcount > 0
-
+
def prepare(self):
if self.__tcount == 1:
try:
@@ -44,9 +43,11 @@ class TLSession(object):
self.reset()
def begin_twophase(self, xid=None):
- raise NotImplementedError("Two phase transactions not yet implemented for 'threadlocal' strategy")
-
- def _dont_begin_twophase(self, xid=None):
+ raise NotImplementedError(
+ "Two phase transactions not yet implemented for 'threadlocal' "
+ "strategy")
+
+ def _dont_begin_twophase(self, xid=None):
if self.__tcount == 0:
self.__transaction = self.get_connection()
self.__trans = self.__transaction._begin_twophase(xid=xid)
@@ -79,9 +80,11 @@ class TLSession(object):
def is_begun(self):
return self.__tcount > 0
+
class TLConnection(base.Connection):
def __init__(self, session, close_with_result):
- base.Connection.__init__(self, session.engine, close_with_result=close_with_result)
+ base.Connection.__init__(self, session.engine,
+ close_with_result=close_with_result)
self.__session = session
self.__opencount = 1
@@ -92,11 +95,13 @@ class TLConnection(base.Connection):
return self
def _begin(self, **kwargs):
- return TLTransaction(super(TLConnection, self).begin(**kwargs), self.__session)
-
+ return TLTransaction(
+ super(TLConnection, self).begin(**kwargs), self.__session)
+
def _begin_twophase(self, xid=None):
- return TLTransaction(super(TLConnection, self).begin_twophase(xid=xid), self.__session)
-
+ return TLTransaction(
+ super(TLConnection, self).begin_twophase(xid=xid), self.__session)
+
def in_transaction(self):
return self.session.in_transaction()
@@ -116,6 +121,7 @@ class TLConnection(base.Connection):
self.__opencount = 0
base.Connection.close(self)
+
class TLTransaction(base.Transaction):
def __init__(self, trans, session):
self._trans = trans
@@ -129,7 +135,7 @@ class TLTransaction(base.Transaction):
def prepare(self):
self._session.prepare()
-
+
def commit(self):
self._session.commit()
@@ -143,22 +149,19 @@ class TLTransaction(base.Transaction):
class TLEngine(base.Engine):
"""An Engine that includes support for thread-local managed transactions.
- This engine is better suited to be used with threadlocal Pool
- object.
+ The TLEngine relies upon its Pool having "threadlocal" behavior,
+ so that once a connection is checked out for the current thread,
+ you get that same connection repeatedly.
"""
def __init__(self, *args, **kwargs):
- """The TLEngine relies upon the Pool having
- "threadlocal" behavior, so that once a connection is checked out
- for the current thread, you get that same connection
- repeatedly.
- """
+ """Construct a new TLEngine."""
super(TLEngine, self).__init__(*args, **kwargs)
self.context = util.ThreadLocal()
def raw_connection(self):
- """Return a DBAPI connection."""
+ """Return a DB-API connection."""
return self.pool.connect()
@@ -166,7 +169,7 @@ class TLEngine(base.Engine):
"""Return a Connection that is not thread-locally scoped.
This is the equivalent to calling ``connect()`` on a
- ComposedSQLEngine.
+ base.Engine.
"""
return base.Connection(self, self.pool.unique_connection())
@@ -176,7 +179,7 @@ class TLEngine(base.Engine):
self.context.session = TLSession(self)
return self.context.session
- session = property(_session, doc="returns the current thread's TLSession")
+ session = property(_session, doc="Returns the current thread's TLSession")
def contextual_connect(self, **kwargs):
"""Return a TLConnection which is thread-locally scoped."""
@@ -192,3 +195,5 @@ class TLEngine(base.Engine):
def rollback(self):
self.session.rollback()
+ def __repr__(self):
+ return 'TLEngine(%s)' % str(self.url)
diff --git a/lib/sqlalchemy/engine/url.py b/lib/sqlalchemy/engine/url.py
index 31546bae8..1f6f9eff4 100644
--- a/lib/sqlalchemy/engine/url.py
+++ b/lib/sqlalchemy/engine/url.py
@@ -1,4 +1,4 @@
-"""Provide the URL object as well as the make_url parsing function."""
+"""Provides URL facilities for specifying database connections."""
import re, cgi, sys, urllib
from sqlalchemy import exceptions
@@ -7,15 +7,16 @@ from sqlalchemy import exceptions
class URL(object):
"""Represent the components of a URL used to connect to a database.
- This object is suitable to be passed directly to a ``create_engine()``
- call. The fields of the URL are parsed from a string by the
- ``module-level make_url()`` function. the string format of the URL is
- an RFC-1738-style string.
+ This object is suitable to be passed directly to a
+ ``create_engine()`` call. The fields of the URL are parsed from a
+ string by the ``module-level make_url()`` function. the string
+ format of the URL is an RFC-1738-style string.
Attributes on URL include:
drivername
- The name of the database backend. this name will correspond to a module in sqlalchemy/databases
+ the name of the database backend. This name will correspond to
+ a module in sqlalchemy/databases or a third party plug-in.
username
The user name for the connection.
@@ -33,7 +34,8 @@ class URL(object):
The database.
query
- A dictionary containing key/value pairs representing the URL's query string.
+ A dictionary containing key/value pairs representing the URL's
+ query string.
"""
def __init__(self, drivername, username=None, password=None, host=None, port=None, database=None, query=None):
@@ -100,7 +102,7 @@ class URL(object):
raise ImportError('unknown database %r' % self.drivername)
def translate_connect_args(self, names):
- """Translate this URL's attributes into a dictionary of connection arguments.
+ """Translate attributes into a dictionary of connection arguments.
Given a list of argument names corresponding to the URL
attributes (`host`, `database`, `username`, `password`,
@@ -121,7 +123,7 @@ class URL(object):
def make_url(name_or_url):
"""Given a string or unicode instance, produce a new URL instance.
- The given string is parsed according to the rfc1738 spec. If an
+ The given string is parsed according to the RFC 1738 spec. If an
existing URL object is passed, just returns the object.
"""