[Sqlalchemy-commits] sqlalchemy: future for with statement
Brought to you by:
zzzeek
From: <co...@sq...> - 2012-08-24 22:49:05
|
details: http://hg.sqlalchemy.org/sqlalchemy/sqlalchemy/rev/5a6d3fdefa0e changeset: 8591:5a6d3fdefa0e user: Mike Bayer <mi...@zz...> date: Fri Aug 24 18:42:28 2012 -0400 description: future for with statement Subject: sqlalchemy: - [feature] Added support for .info dictionary argument to details: http://hg.sqlalchemy.org/sqlalchemy/sqlalchemy/rev/4576c7aaf733 changeset: 8592:4576c7aaf733 user: Mike Bayer <mi...@zz...> date: Fri Aug 24 18:48:42 2012 -0400 description: - [feature] Added support for .info dictionary argument to column_property(), relationship(), composite(). All MapperProperty classes have an auto-creating .info dict available overall. diffstat: CHANGES | 5 +++++ doc/build/core/schema.rst | 25 +++++++++++++------------ lib/sqlalchemy/engine/base.py | 10 +++++++++- lib/sqlalchemy/orm/__init__.py | 15 +++++++++++++++ lib/sqlalchemy/orm/descriptor_props.py | 3 +++ lib/sqlalchemy/orm/interfaces.py | 16 ++++++++++++++++ lib/sqlalchemy/orm/properties.py | 12 +++++++++++- lib/sqlalchemy/pool.py | 34 +++++++++++++++++----------------- lib/sqlalchemy/schema.py | 26 ++++++++++++-------------- test/engine/test_execute.py | 2 ++ test/engine/test_pool.py | 2 +- test/orm/test_mapper.py | 21 +++++++++++++++++++++ 12 files changed, 125 insertions(+), 46 deletions(-) diffs (truncated from 442 to 300 lines): diff -r 89688222ef6a -r 4576c7aaf733 CHANGES --- a/CHANGES Fri Aug 24 16:14:47 2012 -0400 +++ b/CHANGES Fri Aug 24 18:48:42 2012 -0400 @@ -123,6 +123,11 @@ Both features should be avoided, however. [ticket:2372] + - [feature] Added support for .info dictionary argument to + column_property(), relationship(), composite(). + All MapperProperty classes have an auto-creating .info + dict available overall. + - [feature] Adding/removing None from a mapped collection now generates attribute events. Previously, a None append would be ignored in some cases. Related diff -r 89688222ef6a -r 4576c7aaf733 doc/build/core/schema.rst --- a/doc/build/core/schema.rst Fri Aug 24 16:14:47 2012 -0400 +++ b/doc/build/core/schema.rst Fri Aug 24 18:48:42 2012 -0400 @@ -257,8 +257,8 @@ constructs, the ability to alter those constructs, usually via the ALTER statement as well as other database-specific constructs, is outside of the scope of SQLAlchemy itself. While it's easy enough to emit ALTER statements and similar by hand, -such as by passing a string to :meth:`.Connection.execute` or by using the -:class:`.DDL` construct, it's a common practice to automate the maintenance of +such as by passing a string to :meth:`.Connection.execute` or by using the +:class:`.DDL` construct, it's a common practice to automate the maintenance of database schemas in relation to application code using schema migration tools. There are two major migration tools available for SQLAlchemy: @@ -266,12 +266,12 @@ * `Alembic <http://alembic.readthedocs.org>`_ - Written by the author of SQLAlchemy, Alembic features a highly customizable environment and a minimalistic usage pattern, supporting such features as transactional DDL, automatic generation of "candidate" - migrations, an "offline" mode which generates SQL scripts, and support for branch + migrations, an "offline" mode which generates SQL scripts, and support for branch resolution. * `SQLAlchemy-Migrate <http://code.google.com/p/sqlalchemy-migrate/>`_ - The original migration tool for SQLAlchemy, SQLAlchemy-Migrate is widely used and continues - under active development. SQLAlchemy-Migrate includes features such as - SQL script generation, ORM class generation, ORM model comparison, and extensive + under active development. SQLAlchemy-Migrate includes features such as + SQL script generation, ORM class generation, ORM model comparison, and extensive support for SQLite migrations. .. _metadata_binding: @@ -417,6 +417,7 @@ .. autoclass:: SchemaItem :show-inheritance: + :members: .. autoclass:: Table :members: @@ -1092,11 +1093,11 @@ The :class:`.Table` is the SQLAlchemy Core construct that allows one to define table metadata, which among other things can be used by the SQLAlchemy ORM as a target to map a class. The :ref:`Declarative <declarative_toplevel>` -extension allows the :class:`.Table` object to be created automatically, given +extension allows the :class:`.Table` object to be created automatically, given the contents of the table primarily as a mapping of :class:`.Column` objects. To apply table-level constraint objects such as :class:`.ForeignKeyConstraint` -to a table defined using Declarative, use the ``__table_args__`` attribute, +to a table defined using Declarative, use the ``__table_args__`` attribute, described at :ref:`declarative_table_args`. Constraints API @@ -1179,9 +1180,9 @@ CREATE INDEX idx_col34 ON mytable (col3, col4){stop} Note in the example above, the :class:`.Index` construct is created -externally to the table which it corresponds, using :class:`.Column` +externally to the table which it corresponds, using :class:`.Column` objects directly. :class:`.Index` also supports -"inline" definition inside the :class:`.Table`, using string names to +"inline" definition inside the :class:`.Table`, using string names to identify columns:: meta = MetaData() @@ -1308,7 +1309,7 @@ event.listen( users, - "after_create", + "after_create", AddConstraint(constraint) ) event.listen( @@ -1331,11 +1332,11 @@ DROP TABLE users{stop} The real usefulness of the above becomes clearer once we illustrate the :meth:`.DDLEvent.execute_if` -method. This method returns a modified form of the DDL callable which will +method. This method returns a modified form of the DDL callable which will filter on criteria before responding to a received event. It accepts a parameter ``dialect``, which is the string name of a dialect or a tuple of such, which will limit the execution of the item to just those dialects. It also -accepts a ``callable_`` parameter which may reference a Python callable which will +accepts a ``callable_`` parameter which may reference a Python callable which will be invoked upon event reception, returning ``True`` or ``False`` indicating if the event should proceed. diff -r 89688222ef6a -r 4576c7aaf733 lib/sqlalchemy/engine/base.py --- a/lib/sqlalchemy/engine/base.py Fri Aug 24 16:14:47 2012 -0400 +++ b/lib/sqlalchemy/engine/base.py Fri Aug 24 18:48:42 2012 -0400 @@ -253,7 +253,15 @@ @property def info(self): - """A collection of per-DB-API connection instance properties.""" + """Info dictionary associated with the underlying DBAPI connection + referred to by this :class:`.Connection`, allowing user-defined + data to be associated with the connection. + + The data here will follow along with the DBAPI connection including + after it is returned to the connection pool and used again + in subsequent instances of :class:`.Connection`. + + """ return self.connection.info diff -r 89688222ef6a -r 4576c7aaf733 lib/sqlalchemy/orm/__init__.py --- a/lib/sqlalchemy/orm/__init__.py Fri Aug 24 16:14:47 2012 -0400 +++ b/lib/sqlalchemy/orm/__init__.py Fri Aug 24 18:48:42 2012 -0400 @@ -417,6 +417,11 @@ more specific system of describing which columns in a particular ``primaryjoin`` should be considered "foreign". + :param info: Optional data dictionary which will be populated into the + :attr:`.MapperProperty.info` attribute of this object. + + .. versionadded:: 0.8 + :param innerjoin=False: when ``True``, joined eager loads will use an inner join to join against related tables instead of an outer join. The purpose @@ -742,6 +747,11 @@ .. versionadded:: 0.7.3 + :param info: Optional data dictionary which will be populated into the + :attr:`.MapperProperty.info` attribute of this object. + + .. versionadded:: 0.8 + :param extension: an :class:`.AttributeExtension` @@ -794,6 +804,11 @@ optional string that will be applied as the doc on the class-bound descriptor. + :param info: Optional data dictionary which will be populated into the + :attr:`.MapperProperty.info` attribute of this object. + + .. versionadded:: 0.8 + :param extension: an :class:`.AttributeExtension` instance, or list of extensions, which will be prepended to the list of diff -r 89688222ef6a -r 4576c7aaf733 lib/sqlalchemy/orm/descriptor_props.py --- a/lib/sqlalchemy/orm/descriptor_props.py Fri Aug 24 16:14:47 2012 -0400 +++ b/lib/sqlalchemy/orm/descriptor_props.py Fri Aug 24 18:48:42 2012 -0400 @@ -92,6 +92,9 @@ self.group = kwargs.get('group', None) self.comparator_factory = kwargs.pop('comparator_factory', self.__class__.Comparator) + if 'info' in kwargs: + self.info = kwargs.pop('info') + util.set_creation_order(self) self._create_descriptor() diff -r 89688222ef6a -r 4576c7aaf733 lib/sqlalchemy/orm/interfaces.py --- a/lib/sqlalchemy/orm/interfaces.py Fri Aug 24 16:14:47 2012 -0400 +++ b/lib/sqlalchemy/orm/interfaces.py Fri Aug 24 18:48:42 2012 -0400 @@ -126,6 +126,22 @@ def instrument_class(self, mapper): # pragma: no-coverage raise NotImplementedError() + @util.memoized_property + def info(self): + """Info dictionary associated with the object, allowing user-defined + data to be associated with this :class:`.MapperProperty`. + + The dictionary is generated when first accessed. Alternatively, + it can be specified as a constructor argument to the + :func:`.column_property`, :func:`.relationship`, or :func:`.composite` + functions. + + .. versionadded:: 0.8 Added support for .info to all + :class:`.MapperProperty` subclasses. + + """ + return {} + _configure_started = False _configure_finished = False diff -r 89688222ef6a -r 4576c7aaf733 lib/sqlalchemy/orm/properties.py --- a/lib/sqlalchemy/orm/properties.py Fri Aug 24 16:14:47 2012 -0400 +++ b/lib/sqlalchemy/orm/properties.py Fri Aug 24 18:48:42 2012 -0400 @@ -63,6 +63,9 @@ :param extension: + :param info: Optional data dictionary which will be populated into the + :attr:`.info` attribute of this object. + """ self._orig_columns = [expression._labeled(c) for c in columns] self.columns = [expression._labeled(_orm_full_deannotate(c)) @@ -77,6 +80,9 @@ self.active_history = kwargs.pop('active_history', False) self.expire_on_flush = kwargs.pop('expire_on_flush', True) + if 'info' in kwargs: + self.info = kwargs.pop('info') + if 'doc' in kwargs: self.doc = kwargs.pop('doc') else: @@ -243,7 +249,8 @@ cascade_backrefs=True, load_on_pending=False, strategy_class=None, _local_remote_pairs=None, - query_class=None): + query_class=None, + info=None): self.uselist = uselist self.argument = argument @@ -275,6 +282,9 @@ self.comparator = self.comparator_factory(self, None) util.set_creation_order(self) + if info is not None: + self.info = info + if strategy_class: self.strategy_class = strategy_class elif self.lazy == 'dynamic': diff -r 89688222ef6a -r 4576c7aaf733 lib/sqlalchemy/pool.py --- a/lib/sqlalchemy/pool.py Fri Aug 24 16:14:47 2012 -0400 +++ b/lib/sqlalchemy/pool.py Fri Aug 24 18:48:42 2012 -0400 @@ -278,13 +278,16 @@ def __init__(self, pool): self.__pool = pool self.connection = self.__connect() - self.info = {} pool.dispatch.first_connect.\ for_modify(pool.dispatch).\ exec_once(self.connection, self) pool.dispatch.connect(self.connection, self) + @util.memoized_property + def info(self): + return {} + def close(self): if self.connection is not None: self.__pool.logger.debug("Closing connection %r", self.connection) @@ -387,10 +390,6 @@ """Proxies a DB-API connection and provides return-on-dereference support.""" - __slots__ = '_pool', '__counter', 'connection', \ - '_connection_record', '__weakref__', \ - '_detached_info', '_echo' - def __init__(self, pool): self._pool = pool self.__counter = 0 @@ -400,7 +399,8 @@ conn = self.connection = self._connection_record.get_connection() rec.fairy = weakref.ref( self, - lambda ref:_finalize_fairy and _finalize_fairy(conn, rec, pool, ref, _echo) + lambda ref: _finalize_fairy and \ + _finalize_fairy(conn, rec, pool, ref, _echo) ) _refs.add(rec) except: @@ -420,20 +420,21 @@ def is_valid(self): return self.connection is not None - @property + @util.memoized_property def info(self): - """An info collection unique to this DB-API connection.""" + """Info dictionary associated with the underlying DBAPI connection + referred to by this :class:`.ConnectionFairy`, allowing user-defined + data to be associated with the connection. + The data here will follow along with the DBAPI connection including + after it is returned to the connection pool and used again + in subsequent instances of :class:`.ConnectionFairy`. |