summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-08-24 18:48:42 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-08-24 18:48:42 -0400
commit393b29477648e9b2db9597916a0e53602610ac44 (patch)
tree533dc7cb74b21cbd6f9ebeab89a6837c9bf30f35 /lib/sqlalchemy
parenta113c7b3a74f3c1b3128995a20c1760c87695cf3 (diff)
downloadsqlalchemy-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.py10
-rw-r--r--lib/sqlalchemy/orm/__init__.py15
-rw-r--r--lib/sqlalchemy/orm/descriptor_props.py3
-rw-r--r--lib/sqlalchemy/orm/interfaces.py16
-rw-r--r--lib/sqlalchemy/orm/properties.py12
-rw-r--r--lib/sqlalchemy/pool.py34
-rw-r--r--lib/sqlalchemy/schema.py26
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."""