From: Mike Bayer Date: Sat, 30 Jul 2011 15:41:53 +0000 (-0400) Subject: - Added public attribute ".validators" to X-Git-Tag: rel_0_7_2~6 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a45da117889edba7ec0906d3af3fff7d83e5373a;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Added public attribute ".validators" to Mapper, an immutable dictionary view of all attributes that have been decorated with the @validates decorator. [ticket:2240] courtesy Stefano Fontanelli --- diff --git a/CHANGES b/CHANGES index 2c123a9d23..9a39c613e0 100644 --- a/CHANGES +++ b/CHANGES @@ -77,6 +77,12 @@ CHANGES result set. [ticket:2215] Also in 0.6.9. + - Added public attribute ".validators" to + Mapper, an immutable dictionary view of + all attributes that have been decorated + with the @validates decorator. + [ticket:2240] courtesy Stefano Fontanelli + - Fixed subtle bug that caused SQL to blow up if: column_property() against subquery + joinedload + LIMIT + order by the column diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 035b728283..3c3389d797 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -131,7 +131,7 @@ class Mapper(object): polymorphic_on, "polymorphic_on") self._dependency_processors = [] - self._validators = {} + self.validators = util.immutabledict() self.passive_updates = passive_updates self._clause_adapter = None self._requires_row_aliasing = False @@ -428,6 +428,15 @@ class Mapper(object): """ + validators = None + """An immutable dictionary of attributes which have been decorated + using the :func:`~.orm.validates` decorator. + + The dictionary contains string attribute names as keys + mapped to the actual validation method. + + """ + c = None """A synonym for :attr:`~.Mapper.columns`.""" @@ -637,7 +646,9 @@ class Mapper(object): event.listen(manager, 'load', _event_on_load, raw=True) elif hasattr(method, '__sa_validators__'): for name in method.__sa_validators__: - self._validators[name] = method + self.validators = self.validators.union( + {name : method} + ) manager.info[_INSTRUMENTOR] = self diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index 50facbf24a..aacf466d62 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -44,11 +44,11 @@ def _register_attribute(strategy, mapper, useobject, if useobject and prop.single_parent: listen_hooks.append(single_parent_validator) - if prop.key in prop.parent._validators: + if prop.key in prop.parent.validators: listen_hooks.append( lambda desc, prop: mapperutil._validator_events(desc, prop.key, - prop.parent._validators[prop.key]) + prop.parent.validators[prop.key]) ) if useobject: diff --git a/test/orm/test_mapper.py b/test/orm/test_mapper.py index c29a1c5182..4ec3ab0fb5 100644 --- a/test/orm/test_mapper.py +++ b/test/orm/test_mapper.py @@ -1834,7 +1834,6 @@ class ValidatorTest(_fixtures.FixtureTest): sess.expunge_all() eq_(sess.query(User).filter_by(name='ed modified').one(), User(name='ed')) - def test_collection(self): users, addresses, Address = (self.tables.users, self.tables.addresses, @@ -1860,6 +1859,37 @@ class ValidatorTest(_fixtures.FixtureTest): User(name='edward', addresses=[Address(email_address='foo@bar.com')]) ) + def test_validators_dict(self): + users, addresses, Address = (self.tables.users, + self.tables.addresses, + self.classes.Address) + + class User(fixtures.ComparableEntity): + + @validates('name') + def validate_name(self, key, name): + assert name != 'fred' + return name + ' modified' + + @validates('addresses') + def validate_address(self, key, ad): + assert '@' in ad.email_address + return ad + + def simple_function(self, key, value): + return key, value + + u_m = mapper(User, + users, + properties={'addresses':relationship(Address)}) + mapper(Address, addresses) + + eq_( + dict((k, v.__name__) for k, v in u_m.validators.items()), + {'name':'validate_name', + 'addresses':'validate_address'} + ) + class ComparatorFactoryTest(_fixtures.FixtureTest, AssertsCompiledSQL): def test_kwarg_accepted(self): users, Address = self.tables.users, self.classes.Address