summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2014-08-13 19:45:34 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2014-08-13 19:45:34 -0400
commit7fc08fe89af9760750899346cf81bd74e0d9150f (patch)
treed1a9c485c7795bf33bda15900411aefcec91d193
parentea85c7053dc9532a95fd487628768fdfc1ca5c30 (diff)
downloadsqlalchemy-7fc08fe89af9760750899346cf81bd74e0d9150f.tar.gz
- The ``info`` parameter has been added to the constructor for
:class:`.SynonymProperty` and :class:`.ComparableProperty`. - The ``info`` parameter has been added as a constructor argument to all schema constructs including :class:`.MetaData`, :class:`.Index`, :class:`.ForeignKey`, :class:`.ForeignKeyConstraint`, :class:`.UniqueConstraint`, :class:`.PrimaryKeyConstraint`, :class:`.CheckConstraint`. fixes #2963
-rw-r--r--doc/build/changelog/changelog_10.rst17
-rw-r--r--lib/sqlalchemy/orm/descriptor_props.py19
-rw-r--r--lib/sqlalchemy/sql/schema.py54
-rw-r--r--lib/sqlalchemy/util/langhelpers.py4
-rw-r--r--test/orm/test_mapper.py4
-rw-r--r--test/sql/test_metadata.py65
6 files changed, 152 insertions, 11 deletions
diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst
index c59d7c912..815de72c7 100644
--- a/doc/build/changelog/changelog_10.rst
+++ b/doc/build/changelog/changelog_10.rst
@@ -18,6 +18,23 @@
.. change::
:tags: orm, feature
+ :tickets: 2963
+
+ The ``info`` parameter has been added to the constructor for
+ :class:`.SynonymProperty` and :class:`.ComparableProperty`.
+
+ .. change::
+ :tags: sql, feature
+ :tickets: 2963
+
+ The ``info`` parameter has been added as a constructor argument
+ to all schema constructs including :class:`.MetaData`,
+ :class:`.Index`, :class:`.ForeignKey`, :class:`.ForeignKeyConstraint`,
+ :class:`.UniqueConstraint`, :class:`.PrimaryKeyConstraint`,
+ :class:`.CheckConstraint`.
+
+ .. change::
+ :tags: orm, feature
:tickets: 2971
The :meth:`.InspectionAttr.info` collection is now moved down to
diff --git a/lib/sqlalchemy/orm/descriptor_props.py b/lib/sqlalchemy/orm/descriptor_props.py
index 5ed24b8c0..f0f9a6468 100644
--- a/lib/sqlalchemy/orm/descriptor_props.py
+++ b/lib/sqlalchemy/orm/descriptor_props.py
@@ -496,7 +496,7 @@ class SynonymProperty(DescriptorProperty):
def __init__(self, name, map_column=None,
descriptor=None, comparator_factory=None,
- doc=None):
+ doc=None, info=None):
"""Denote an attribute name as a synonym to a mapped property,
in that the attribute will mirror the value and expression behavior
of another attribute.
@@ -531,6 +531,11 @@ class SynonymProperty(DescriptorProperty):
conjunction with the ``descriptor`` argument in order to link a
user-defined descriptor as a "wrapper" for an existing column.
+ :param info: Optional data dictionary which will be populated into the
+ :attr:`.InspectionAttr.info` attribute of this object.
+
+ .. versionadded:: 1.0.0
+
:param comparator_factory: A subclass of :class:`.PropComparator`
that will provide custom comparison behavior at the SQL expression
level.
@@ -556,6 +561,8 @@ class SynonymProperty(DescriptorProperty):
self.descriptor = descriptor
self.comparator_factory = comparator_factory
self.doc = doc or (descriptor and descriptor.__doc__) or None
+ if info:
+ self.info = info
util.set_creation_order(self)
@@ -608,7 +615,8 @@ class SynonymProperty(DescriptorProperty):
class ComparableProperty(DescriptorProperty):
"""Instruments a Python property for use in query expressions."""
- def __init__(self, comparator_factory, descriptor=None, doc=None):
+ def __init__(
+ self, comparator_factory, descriptor=None, doc=None, info=None):
"""Provides a method of applying a :class:`.PropComparator`
to any Python descriptor attribute.
@@ -670,10 +678,17 @@ class ComparableProperty(DescriptorProperty):
The like-named descriptor will be automatically retrieved from the
mapped class if left blank in a ``properties`` declaration.
+ :param info: Optional data dictionary which will be populated into the
+ :attr:`.InspectionAttr.info` attribute of this object.
+
+ .. versionadded:: 1.0.0
+
"""
self.descriptor = descriptor
self.comparator_factory = comparator_factory
self.doc = doc or (descriptor and descriptor.__doc__) or None
+ if info:
+ self.info = info
util.set_creation_order(self)
def _comparator_factory(self, mapper):
diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py
index 69b3af306..8099dca75 100644
--- a/lib/sqlalchemy/sql/schema.py
+++ b/lib/sqlalchemy/sql/schema.py
@@ -76,7 +76,7 @@ class SchemaItem(SchemaEventTarget, visitors.Visitable):
return []
def __repr__(self):
- return util.generic_repr(self)
+ return util.generic_repr(self, omit_kwarg=['info'])
@property
@util.deprecated('0.9', 'Use ``<obj>.name.quote``')
@@ -1403,6 +1403,7 @@ class ForeignKey(DialectKWArgs, SchemaItem):
def __init__(self, column, _constraint=None, use_alter=False, name=None,
onupdate=None, ondelete=None, deferrable=None,
initially=None, link_to_name=False, match=None,
+ info=None,
**dialect_kw):
"""
Construct a column-level FOREIGN KEY.
@@ -1453,6 +1454,11 @@ class ForeignKey(DialectKWArgs, SchemaItem):
DDL for this constraint. Typical values include SIMPLE, PARTIAL
and FULL.
+ :param info: Optional data dictionary which will be populated into the
+ :attr:`.SchemaItem.info` attribute of this object.
+
+ .. versionadded:: 1.0.0
+
:param \**dialect_kw: Additional keyword arguments are dialect
specific, and passed in the form ``<dialectname>_<argname>``. The
arguments are ultimately handled by a corresponding
@@ -1499,6 +1505,8 @@ class ForeignKey(DialectKWArgs, SchemaItem):
self.initially = initially
self.link_to_name = link_to_name
self.match = match
+ if info:
+ self.info = info
self._unvalidated_dialect_kw = dialect_kw
def __repr__(self):
@@ -2223,7 +2231,7 @@ class Constraint(DialectKWArgs, SchemaItem):
__visit_name__ = 'constraint'
def __init__(self, name=None, deferrable=None, initially=None,
- _create_rule=None,
+ _create_rule=None, info=None,
**dialect_kw):
"""Create a SQL constraint.
@@ -2238,6 +2246,11 @@ class Constraint(DialectKWArgs, SchemaItem):
Optional string. If set, emit INITIALLY <value> when issuing DDL
for this constraint.
+ :param info: Optional data dictionary which will be populated into the
+ :attr:`.SchemaItem.info` attribute of this object.
+
+ .. versionadded:: 1.0.0
+
:param _create_rule:
a callable which is passed the DDLCompiler object during
compilation. Returns True or False to signal inline generation of
@@ -2265,6 +2278,8 @@ class Constraint(DialectKWArgs, SchemaItem):
self.name = name
self.deferrable = deferrable
self.initially = initially
+ if info:
+ self.info = info
self._create_rule = _create_rule
util.set_creation_order(self)
self._validate_dialect_kwargs(dialect_kw)
@@ -2381,7 +2396,7 @@ class CheckConstraint(Constraint):
"""
def __init__(self, sqltext, name=None, deferrable=None,
- initially=None, table=None, _create_rule=None,
+ initially=None, table=None, info=None, _create_rule=None,
_autoattach=True):
"""Construct a CHECK constraint.
@@ -2404,10 +2419,15 @@ class CheckConstraint(Constraint):
Optional string. If set, emit INITIALLY <value> when issuing DDL
for this constraint.
+ :param info: Optional data dictionary which will be populated into the
+ :attr:`.SchemaItem.info` attribute of this object.
+
+ .. versionadded:: 1.0.0
+
"""
super(CheckConstraint, self).\
- __init__(name, deferrable, initially, _create_rule)
+ __init__(name, deferrable, initially, _create_rule, info=info)
self.sqltext = _literal_as_text(sqltext)
if table is not None:
self._set_parent_with_dispatch(table)
@@ -2463,7 +2483,7 @@ class ForeignKeyConstraint(Constraint):
def __init__(self, columns, refcolumns, name=None, onupdate=None,
ondelete=None, deferrable=None, initially=None,
use_alter=False, link_to_name=False, match=None,
- table=None, **dialect_kw):
+ table=None, info=None, **dialect_kw):
"""Construct a composite-capable FOREIGN KEY.
:param columns: A sequence of local column names. The named columns
@@ -2508,6 +2528,11 @@ class ForeignKeyConstraint(Constraint):
DDL for this constraint. Typical values include SIMPLE, PARTIAL
and FULL.
+ :param info: Optional data dictionary which will be populated into the
+ :attr:`.SchemaItem.info` attribute of this object.
+
+ .. versionadded:: 1.0.0
+
:param \**dialect_kw: Additional keyword arguments are dialect
specific, and passed in the form ``<dialectname>_<argname>``. See
the documentation regarding an individual dialect at
@@ -2517,7 +2542,7 @@ class ForeignKeyConstraint(Constraint):
"""
super(ForeignKeyConstraint, self).\
- __init__(name, deferrable, initially, **dialect_kw)
+ __init__(name, deferrable, initially, info=info, **dialect_kw)
self.onupdate = onupdate
self.ondelete = ondelete
@@ -2888,6 +2913,11 @@ class Index(DialectKWArgs, ColumnCollectionMixin, SchemaItem):
the index. Works in the same manner as that of
:paramref:`.Column.quote`.
+ :param info=None: Optional data dictionary which will be populated
+ into the :attr:`.SchemaItem.info` attribute of this object.
+
+ .. versionadded:: 1.0.0
+
:param \**kw: Additional keyword arguments not mentioned above are
dialect specific, and passed in the form
``<dialectname>_<argname>``. See the documentation regarding an
@@ -2910,6 +2940,8 @@ class Index(DialectKWArgs, ColumnCollectionMixin, SchemaItem):
self.expressions = expressions
self.name = quoted_name(name, kw.pop("quote", None))
self.unique = kw.pop('unique', False)
+ if 'info' in kw:
+ self.info = kw.pop('info')
self._validate_dialect_kwargs(kw)
# will call _set_parent() if table-bound column
@@ -3020,7 +3052,8 @@ class MetaData(SchemaItem):
def __init__(self, bind=None, reflect=False, schema=None,
quote_schema=None,
- naming_convention=DEFAULT_NAMING_CONVENTION
+ naming_convention=DEFAULT_NAMING_CONVENTION,
+ info=None
):
"""Create a new MetaData object.
@@ -3046,6 +3079,11 @@ class MetaData(SchemaItem):
:class:`.Sequence`, and other objects which make usage of the
local ``schema`` name.
+ :param info: Optional data dictionary which will be populated into the
+ :attr:`.SchemaItem.info` attribute of this object.
+
+ .. versionadded:: 1.0.0
+
:param naming_convention: a dictionary referring to values which
will establish default naming conventions for :class:`.Constraint`
and :class:`.Index` objects, for those objects which are not given
@@ -3117,6 +3155,8 @@ class MetaData(SchemaItem):
self.tables = util.immutabledict()
self.schema = quoted_name(schema, quote_schema)
self.naming_convention = naming_convention
+ if info:
+ self.info = info
self._schemas = set()
self._sequences = {}
self._fk_memos = collections.defaultdict(list)
diff --git a/lib/sqlalchemy/util/langhelpers.py b/lib/sqlalchemy/util/langhelpers.py
index 8d6fe5a28..828e8f1f3 100644
--- a/lib/sqlalchemy/util/langhelpers.py
+++ b/lib/sqlalchemy/util/langhelpers.py
@@ -435,7 +435,7 @@ def unbound_method_to_callable(func_or_cls):
return func_or_cls
-def generic_repr(obj, additional_kw=(), to_inspect=None):
+def generic_repr(obj, additional_kw=(), to_inspect=None, omit_kwarg=()):
"""Produce a __repr__() based on direct association of the __init__()
specification vs. same-named attributes present.
@@ -484,6 +484,8 @@ def generic_repr(obj, additional_kw=(), to_inspect=None):
output.extend([repr(val) for val in getattr(obj, vargs)])
for arg, defval in kw_args.items():
+ if arg in omit_kwarg:
+ continue
try:
val = getattr(obj, arg, missing)
if val is not missing and val != defval:
diff --git a/test/orm/test_mapper.py b/test/orm/test_mapper.py
index e33c93977..0a9cbfc71 100644
--- a/test/orm/test_mapper.py
+++ b/test/orm/test_mapper.py
@@ -414,7 +414,9 @@ class MapperTest(_fixtures.FixtureTest, AssertsCompiledSQL):
for constructor, args in [
(column_property, (users.c.name,)),
(relationship, (Address,)),
- (composite, (MyComposite, 'id', 'name'))
+ (composite, (MyComposite, 'id', 'name')),
+ (synonym, 'foo'),
+ (comparable_property, 'foo')
]:
obj = constructor(info={"x": "y"}, *args)
eq_(obj.info, {"x": "y"})
diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py
index 3a252c646..ff2755ab1 100644
--- a/test/sql/test_metadata.py
+++ b/test/sql/test_metadata.py
@@ -956,6 +956,71 @@ class ToMetaDataTest(fixtures.TestBase, ComparesTables):
'mytable.myid = othertable.myid')
+class InfoTest(fixtures.TestBase):
+ def test_metadata_info(self):
+ m1 = MetaData()
+ eq_(m1.info, {})
+
+ m1 = MetaData(info={"foo": "bar"})
+ eq_(m1.info, {"foo": "bar"})
+
+ def test_foreignkey_constraint_info(self):
+ fkc = ForeignKeyConstraint(['a'], ['b'], name='bar')
+ eq_(fkc.info, {})
+
+ fkc = ForeignKeyConstraint(
+ ['a'], ['b'], name='bar', info={"foo": "bar"})
+ eq_(fkc.info, {"foo": "bar"})
+
+ def test_foreignkey_info(self):
+ fkc = ForeignKey('a')
+ eq_(fkc.info, {})
+
+ fkc = ForeignKey('a', info={"foo": "bar"})
+ eq_(fkc.info, {"foo": "bar"})
+
+ def test_primarykey_constraint_info(self):
+ pkc = PrimaryKeyConstraint('a', name='x')
+ eq_(pkc.info, {})
+
+ pkc = PrimaryKeyConstraint('a', name='x', info={'foo': 'bar'})
+ eq_(pkc.info, {'foo': 'bar'})
+
+ def test_unique_constraint_info(self):
+ uc = UniqueConstraint('a', name='x')
+ eq_(uc.info, {})
+
+ uc = UniqueConstraint('a', name='x', info={'foo': 'bar'})
+ eq_(uc.info, {'foo': 'bar'})
+
+ def test_check_constraint_info(self):
+ cc = CheckConstraint('foo=bar', name='x')
+ eq_(cc.info, {})
+
+ cc = CheckConstraint('foo=bar', name='x', info={'foo': 'bar'})
+ eq_(cc.info, {'foo': 'bar'})
+
+ def test_index_info(self):
+ ix = Index('x', 'a')
+ eq_(ix.info, {})
+
+ ix = Index('x', 'a', info={'foo': 'bar'})
+ eq_(ix.info, {'foo': 'bar'})
+
+ def test_column_info(self):
+ c = Column('x', Integer)
+ eq_(c.info, {})
+
+ c = Column('x', Integer, info={'foo': 'bar'})
+ eq_(c.info, {'foo': 'bar'})
+
+ def test_table_info(self):
+ t = Table('x', MetaData())
+ eq_(t.info, {})
+
+ t = Table('x', MetaData(), info={'foo': 'bar'})
+ eq_(t.info, {'foo': 'bar'})
+
class TableTest(fixtures.TestBase, AssertsCompiledSQL):
@testing.skip_if('mssql', 'different col format')