diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2012-08-24 18:48:42 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2012-08-24 18:48:42 -0400 |
| commit | 393b29477648e9b2db9597916a0e53602610ac44 (patch) | |
| tree | 533dc7cb74b21cbd6f9ebeab89a6837c9bf30f35 /lib/sqlalchemy | |
| parent | a113c7b3a74f3c1b3128995a20c1760c87695cf3 (diff) | |
| download | sqlalchemy-393b29477648e9b2db9597916a0e53602610ac44.tar.gz | |
- [feature] Added support for .info dictionary argument to
column_property(), relationship(), composite().
All MapperProperty classes have an auto-creating .info
dict available overall.
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/engine/base.py | 10 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/__init__.py | 15 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/descriptor_props.py | 3 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/interfaces.py | 16 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/properties.py | 12 | ||||
| -rw-r--r-- | lib/sqlalchemy/pool.py | 34 | ||||
| -rw-r--r-- | lib/sqlalchemy/schema.py | 26 |
7 files changed, 83 insertions, 33 deletions
diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index bf3131994..2894f2c21 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -253,7 +253,15 @@ class Connection(Connectable): @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 --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py index 2078b2396..f31e8b023 100644 --- a/lib/sqlalchemy/orm/__init__.py +++ b/lib/sqlalchemy/orm/__init__.py @@ -417,6 +417,11 @@ def relationship(argument, secondary=None, **kwargs): 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 @@ def column_property(*cols, **kw): .. 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 @@ def composite(class_, *cols, **kwargs): 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 --git a/lib/sqlalchemy/orm/descriptor_props.py b/lib/sqlalchemy/orm/descriptor_props.py index f4c2e1a90..fdbe44c6c 100644 --- a/lib/sqlalchemy/orm/descriptor_props.py +++ b/lib/sqlalchemy/orm/descriptor_props.py @@ -92,6 +92,9 @@ class CompositeProperty(DescriptorProperty): 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 --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py index f41c5894e..12c38b595 100644 --- a/lib/sqlalchemy/orm/interfaces.py +++ b/lib/sqlalchemy/orm/interfaces.py @@ -126,6 +126,22 @@ class MapperProperty(_InspectionAttr): 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 --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index f52e914f7..ad48234c2 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -63,6 +63,9 @@ class ColumnProperty(StrategizedProperty): :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 @@ class ColumnProperty(StrategizedProperty): 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 @@ class RelationshipProperty(StrategizedProperty): 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 @@ class RelationshipProperty(StrategizedProperty): 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 --git a/lib/sqlalchemy/pool.py b/lib/sqlalchemy/pool.py index 0b3d7d0eb..caef60c2f 100644 --- a/lib/sqlalchemy/pool.py +++ b/lib/sqlalchemy/pool.py @@ -278,13 +278,16 @@ class _ConnectionRecord(object): 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 @@ class _ConnectionFairy(object): """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 @@ class _ConnectionFairy(object): 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 @@ class _ConnectionFairy(object): 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`. + """ try: return self._connection_record.info except AttributeError: - if self.connection is None: - raise exc.InvalidRequestError("This connection is closed") - try: - return self._detached_info - except AttributeError: - self._detached_info = value = {} - return value + raise exc.InvalidRequestError("This connection is closed") def invalidate(self, e=None): """Mark this connection as invalidated. @@ -500,8 +501,7 @@ class _ConnectionFairy(object): self._connection_record.fairy = None self._connection_record.connection = None self._pool._do_return_conn(self._connection_record) - self._detached_info = \ - self._connection_record.info.copy() + self.info = self.info.copy() self._connection_record = None def close(self): diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 4ce27582b..8b46dc250 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -71,6 +71,14 @@ class SchemaItem(events.SchemaEventTarget, visitors.Visitable): @util.memoized_property def info(self): + """Info dictionary associated with the object, allowing user-defined + data to be associated with this :class:`.SchemaItem`. + + The dictionary is automatically generated when first accessed. + It can also be specified in the constructor of some objects, + such as :class:`.Table` and :class:`.Column`. + + """ return {} def _get_table_key(name, schema): @@ -204,8 +212,8 @@ class Table(SchemaItem, expression.TableClause): ``Table`` object. Defaults to ``None`` which indicates all columns should be reflected. - :param info: A dictionary which defaults to ``{}``. A space to store - application specific data. This must be a dictionary. + :param info: Optional data dictionary which will be populated into the + :attr:`.SchemaItem.info` attribute of this object. :param keep_existing: When ``True``, indicates that if this Table is already present in the given :class:`.MetaData`, ignore @@ -408,11 +416,6 @@ class Table(SchemaItem, expression.TableClause): self, include_columns, exclude_columns ) - @util.memoized_property - def info(self): - """Dictionary provided for storage of additional information.""" - return {} - @property def _sorted_constraints(self): """Return the set of constraints as a list, sorted by creation order.""" @@ -797,8 +800,8 @@ class Column(SchemaItem, expression.ColumnClause): contain multiple columns, use the :class:`.Index` construct instead. - :param info: A dictionary which defaults to ``{}``. A space to store - application specific data. This must be a dictionary. + :param info: Optional data dictionary which will be populated into the + :attr:`.SchemaItem.info` attribute of this object. :param nullable: If set to the default of ``True``, indicates the column will be rendered as allowing NULL, else it's rendered as @@ -971,11 +974,6 @@ class Column(SchemaItem, expression.ColumnClause): else: return self.description - @util.memoized_property - def info(self): - """Dictionary provided for storage of additional information.""" - return {} - def references(self, column): """Return True if this Column references the given column via foreign key.""" |
