diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2005-12-24 15:16:50 +0000 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2005-12-24 15:16:50 +0000 |
commit | 648a47c824e5fdffa80547405aa5ffaba1ea5872 (patch) | |
tree | 2182a02c135edb39c6078c8a2bb411140fec225d /lib/sqlalchemy/engine.py | |
parent | 79843330ae315f2572765d5d95158e7f0fe280c2 (diff) | |
download | sqlalchemy-648a47c824e5fdffa80547405aa5ffaba1ea5872.tar.gz |
docstrings
Diffstat (limited to 'lib/sqlalchemy/engine.py')
-rw-r--r-- | lib/sqlalchemy/engine.py | 178 |
1 files changed, 157 insertions, 21 deletions
diff --git a/lib/sqlalchemy/engine.py b/lib/sqlalchemy/engine.py index 1e5ba34d0..d713beebe 100644 --- a/lib/sqlalchemy/engine.py +++ b/lib/sqlalchemy/engine.py @@ -15,8 +15,24 @@ # along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -"""builds upon the schema and sql packages to provide a central object for tying schema -objects and sql constructs to database-specific query compilation and execution""" +"""Defines the SQLEngine class, which serves as the primary "database" object +used throughout the sql construction and object-relational mapper packages. +A SQLEngine is a facade around a single connection pool corresponding to a +particular set of connection parameters, and provides thread-local transactional +methods and statement execution methods for Connection objects. It also provides +a facade around a Cursor object to allow richer column selection for result rows +as well as type conversion operations, known as a ResultProxy. + +A SQLEngine is provided to an application as a subclass that is specific to a particular type +of DBAPI, and is the central switching point for abstracting different kinds of database +behavior into a consistent set of behaviors. It provides a variety of factory methods +to produce everything specific to a certain kind of database, including a Compiler, +schema creation/dropping objects, and TableImpl and ColumnImpl objects to augment the +behavior of table metadata objects. + +The term "database-specific" will be used to describe any object or function that has behavior +corresponding to a particular vendor, such as mysql-specific, sqlite-specific, etc. +""" import sqlalchemy.schema as schema import sqlalchemy.pool @@ -28,13 +44,42 @@ import sqlalchemy.databases __all__ = ['create_engine', 'engine_descriptors'] -def create_engine(name, *args ,**kwargs): - """creates a new SQLEngine instance. +def create_engine(name, opts=None,**kwargs): + """creates a new SQLEngine instance. There are two forms of calling this method. - name - the type of engine to load, i.e. 'sqlite', 'postgres', 'oracle' + In the first, the "name" argument is the type of engine to load, i.e. 'sqlite', 'postgres', + 'oracle', 'mysql'. "opts" is a dictionary of options to be sent to the underlying DBAPI module + to create a connection, usually including a hostname, username, password, etc. - *args, **kwargs - sent directly to the specific engine instance as connect arguments, - options. + In the second, the "name" argument is a URL in the form <enginename>://opt1=val1&opt2=val2. + Where <enginename> is the name as above, and the contents of the option dictionary are + spelled out as a URL encoded string. The "opts" argument is not used. + + In both cases, **kwargs represents options to be sent to the SQLEngine itself. A possibly + partial listing of those options is as follows: + + pool=None : an instance of sqlalchemy.pool.DBProxy to be used as the underlying source + for connections (DBProxy is described in the previous section). If None, a default DBProxy + will be created using the engine's own database module with the given arguments. + + echo=False : if True, the SQLEngine will log all statements as well as a repr() of their + parameter lists to the engines logger, which defaults to sys.stdout. A SQLEngine instances' + "echo" data member can be modified at any time to turn logging on and off. If set to the string + 'debug', result rows will be printed to the standard output as well. + + logger=None : a file-like object where logging output can be sent, if echo is set to True. + This defaults to sys.stdout. + + module=None : used by Oracle and Postgres, 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. + + use_ansi=True : used only by Oracle; when False, the Oracle driver attempts to support a + particular "quirk" of some Oracle databases, that the LEFT OUTER JOIN SQL syntax is not + supported, and the "Oracle join" syntax of using <column1>(+)=<column2> must be used + in order to achieve a LEFT OUTER JOIN. Its advised that the Oracle database be configured to + have full ANSI support instead of using this feature. + """ m = re.match(r'(\w+)://(.*)', name) if m is not None: @@ -48,6 +93,20 @@ def create_engine(name, *args ,**kwargs): return module.engine(*args, **kwargs) def engine_descriptors(): + """provides a listing of all the database implementations supported. this data + is provided as a list of dictionaries, where each dictionary contains the following + key/value pairs: + + name : the name of the engine, suitable for use in the create_engine function + + description: a plain description of the engine. + + arguments : a dictionary describing the name and description of each parameter + used to connect to this engine's underlying DBAPI. + + This function is meant for usage in automated configuration tools that wish to + query the user for database and connection information. + """ result = [] for module in sqlalchemy.databases.__all__: module = getattr(__import__('sqlalchemy.databases.%s' % module).databases, module) @@ -100,11 +159,17 @@ class DefaultRunner(schema.SchemaVisitor): class SQLEngine(schema.SchemaEngine): - """base class for a series of database-specific engines. serves as an abstract factory - for implementation objects as well as database connections, transactions, SQL generators, - etc.""" + """ + The central "database" object used by an application. Subclasses of this object is used + by the schema and SQL construction packages to provide database-specific behaviors, + as well as an execution and thread-local transaction context. + + SQLEngines are constructed via the create_engine() function inside this package. + """ def __init__(self, pool = None, echo = False, logger = None, **params): + """constructs a new SQLEngine. SQLEngines should be constructed via the create_engine() + function which will construct the appropriate subclass of SQLEngine.""" # get a handle on the connection pool via the connect arguments # this insures the SQLEngine instance integrates with the pool referenced # by direct usage of pool.manager(<module>).connect(*args, **params) @@ -142,20 +207,50 @@ class SQLEngine(schema.SchemaEngine): self.positional=True def type_descriptor(self, typeobj): + """provides a database-specific TypeEngine object, given the generic object + which comes from the types module. Subclasses will usually use the adapt_type() + method in the types module to make this job easy.""" if type(typeobj) is type: typeobj = typeobj() return typeobj def schemagenerator(self, proxy, **params): + """returns a schema.SchemaVisitor instance that can generate schemas, when it is + invoked to traverse a set of schema objects. The + "proxy" argument is a callable will execute a given string SQL statement + and a dictionary or list of parameters. + + schemagenerator is called via the create() method. + """ raise NotImplementedError() def schemadropper(self, proxy, **params): + """returns a schema.SchemaVisitor instance that can drop schemas, when it is + invoked to traverse a set of schema objects. The + "proxy" argument is a callable will execute a given string SQL statement + and a dictionary or list of parameters. + + schemagenerator is called via the drop() method. + """ raise NotImplementedError() def defaultrunner(self, proxy): + """Returns a schema.SchemaVisitor instance that can execute the default values on a column. + The base class for this visitor is the DefaultRunner class inside this module. + This visitor will typically only receive schema.DefaultGenerator schema objects. The given + proxy is a callable that takes a string statement and a dictionary of bind parameters + to be executed. For engines that require positional arguments, the dictionary should + be an instance of OrderedDict which returns its bind parameters in the proper order. + + defaultrunner is called within the context of the execute_compiled() method.""" return DefaultRunner(self, proxy) def compiler(self, statement, parameters): + """returns a sql.ClauseVisitor which will produce a string representation of the given + ClauseElement and parameter dictionary. This object is usually a subclass of + ansisql.ANSICompiler. + + compiler is called within the context of the compile() method.""" raise NotImplementedError() def rowid_column_name(self): @@ -163,15 +258,16 @@ class SQLEngine(schema.SchemaEngine): return "oid" def supports_sane_rowcount(self): - """ill give everyone one guess which database warrants this method.""" + """Provided to indicate when MySQL is being used, which does not have standard behavior + for the "rowcount" function on a statement handle. """ return True def create(self, table, **params): - """creates a table given a schema.Table object.""" + """creates a table within this engine's database connection given a schema.Table object.""" table.accept_visitor(self.schemagenerator(self.proxy(), **params)) def drop(self, table, **params): - """drops a table given a schema.Table object.""" + """drops a table within this engine's database connection given a schema.Table object.""" table.accept_visitor(self.schemadropper(self.proxy(), **params)) def compile(self, statement, parameters, **kwargs): @@ -188,19 +284,31 @@ class SQLEngine(schema.SchemaEngine): raise NotImplementedError() def tableimpl(self, table): - """returns a new sql.TableImpl object to correspond to the given Table object.""" + """returns a new sql.TableImpl object to correspond to the given Table object. + A TableImpl provides SQL statement builder operations on a Table metadata object, + and a subclass of this object may be provided by a SQLEngine subclass to provide + database-specific behavior.""" return sql.TableImpl(table) def columnimpl(self, column): - """returns a new sql.ColumnImpl object to correspond to the given Column object.""" + """returns a new sql.ColumnImpl object to correspond to the given Column object. + A ColumnImpl provides SQL statement builder operations on a Column metadata object, + and a subclass of this object may be provided by a SQLEngine subclass to provide + database-specific behavior.""" return sql.ColumnImpl(column) def get_default_schema_name(self): + """returns the currently selected schema in the current connection.""" return None def last_inserted_ids(self): - """returns a thread-local list of the primary keys 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, which are executed via statement.execute(). The order of items in the list is the same as that of the Table's 'primary_key' attribute.""" + """returns a thread-local 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, which are executed via statement.execute(). The order of items in the + list is the same as that of the Table's 'primary_key' attribute. + + In some cases, this method may invoke a query back to the database to retrieve the data, based on + the "lastrowid" value in the cursor.""" raise NotImplementedError() def connect_args(self): @@ -226,6 +334,9 @@ class SQLEngine(schema.SchemaEngine): connection.commit() def proxy(self, **kwargs): + """provides a callable that will execute the given string statement and parameters. + The statement and parameters should be in the format specific to the particular database; + i.e. named or positional.""" return lambda s, p = None: self.execute(s, p, **kwargs) def connection(self): @@ -234,6 +345,10 @@ class SQLEngine(schema.SchemaEngine): def multi_transaction(self, tables, func): """provides a transaction boundary across tables which may be in multiple databases. + If you have three tables, and a function that operates upon them, providing the tables as a + list and the function will result in a begin()/commit() pair invoked for each distinct engine + represented within those tables, and the function executed within the context of that transaction. + any exceptions will result in a rollback(). clearly, this approach only goes so far, such as if database A commits, then database B commits and fails, A is already committed. Any failure conditions have to be raised before anyone @@ -253,6 +368,8 @@ class SQLEngine(schema.SchemaEngine): engine.commit() def transaction(self, func): + """executes the given function within a transaction boundary. this is a shortcut for + explicitly calling begin() and commit() and optionally rollback() when execptions are raised.""" self.begin() try: func() @@ -262,6 +379,11 @@ class SQLEngine(schema.SchemaEngine): self.commit() def begin(self): + """"begins" a transaction on a pooled connection, and stores the connection in a thread-local + context. repeated calls to begin() within the same thread will increment a counter that must be + decreased by corresponding commit() statements before an actual commit occurs. this is to provide + "nested" behavior of transactions so that different functions can all call begin()/commit() and still + call each other.""" if getattr(self.context, 'transaction', None) is None: conn = self.connection() self.do_begin(conn) @@ -271,12 +393,19 @@ class SQLEngine(schema.SchemaEngine): self.context.tcount += 1 def rollback(self): + """rolls back the current thread-local transaction started by begin(). the "begin" counter + is cleared and the transaction ended.""" if self.context.transaction is not None: self.do_rollback(self.context.transaction) self.context.transaction = None self.context.tcount = None def commit(self): + """commits the current thread-local transaction started by begin(). If begin() was called multiple + times, a counter will be decreased for each call to commit(), with the actual commit operation occuring + when the counter reaches zero. this is to provide + "nested" behavior of transactions so that different functions can all call begin()/commit() and still + call each other.""" if self.context.transaction is not None: count = self.context.tcount - 1 self.context.tcount = count @@ -318,9 +447,11 @@ class SQLEngine(schema.SchemaEngine): def pre_exec(self, proxy, compiled, parameters, **kwargs): + """called by execute_compiled before the compiled statement is executed.""" pass def post_exec(self, proxy, compiled, parameters, **kwargs): + """called by execute_compiled after the compiled statement is executed.""" pass def execute_compiled(self, compiled, parameters, connection=None, cursor=None, echo=None, **kwargs): @@ -438,7 +569,7 @@ class SQLEngine(schema.SchemaEngine): except: self.do_rollback(connection) raise - return ResultProxy(cursor, self, typemap = typemap) + return ResultProxy(cursor, self, typemap=typemap) def _execute(self, c, statement, parameters): c.execute(statement, parameters) @@ -457,12 +588,15 @@ class ResultProxy: position, case-insensitive column name, or by schema.Column object. e.g.: row = fetchone() + col1 = row[0] # access via integer position + col2 = row['col2'] # access via name - col3 = row[mytable.c.mycol] # access via Column object. - #the Column's 'label', 'key', and 'name' properties are - # searched in that order. + + col3 = row[mytable.c.mycol] # access via Column object. + ResultProxy also contains a map of TypeEngine objects and will invoke the appropriate + convert_result_value() method before returning columns. """ class AmbiguousColumn(object): def __init__(self, key): @@ -471,6 +605,7 @@ class ResultProxy: raise "Ambiguous column name '%s' in result set! try 'use_labels' option on select statement." % (self.key) def __init__(self, cursor, engine, typemap = None): + """ResultProxy objects are constructed via the execute() method on SQLEngine.""" self.cursor = cursor self.echo = engine.echo=="debug" self.rowcount = engine.context.rowcount @@ -526,6 +661,7 @@ class ResultProxy: class RowProxy: """proxies a single cursor row for a parent ResultProxy.""" def __init__(self, parent, row): + """RowProxy objects are constructed by ResultProxy objects.""" self.parent = parent self.row = row def __iter__(self): |