diff options
| -rw-r--r-- | doc/build/changelog/changelog_11.rst | 11 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 5 | ||||
| -rw-r--r-- | test/orm/test_validators.py | 39 |
3 files changed, 54 insertions, 1 deletions
diff --git a/doc/build/changelog/changelog_11.rst b/doc/build/changelog/changelog_11.rst index e08976f15..ba967f976 100644 --- a/doc/build/changelog/changelog_11.rst +++ b/doc/build/changelog/changelog_11.rst @@ -22,6 +22,17 @@ :version: 1.1.0 .. change:: + :tags: bug, orm + :tickets: 3776 + + An exception is raised when two ``@validates`` decorators on a mapping + make use of the same name. Only one validator of a certain name + at a time is supported, there's no mechanism to chain these together, + as the order of the validators at the level of function decorator + can't be made deterministic. + + + .. change:: :tags: bug, mysql :tickets: 3766 diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index b76a6f727..e8aa08541 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -1204,6 +1204,11 @@ class Mapper(InspectionAttr): elif hasattr(method, '__sa_validators__'): validation_opts = method.__sa_validation_opts__ for name in method.__sa_validators__: + if name in self.validators: + raise sa_exc.InvalidRequestError( + "A validation function for mapped " + "attribute %r on mapper %s already exists." % + (name, self)) self.validators = self.validators.union( {name: (method, validation_opts)} ) diff --git a/test/orm/test_validators.py b/test/orm/test_validators.py index 417554f46..e59bb580a 100644 --- a/test/orm/test_validators.py +++ b/test/orm/test_validators.py @@ -1,7 +1,9 @@ from test.orm import _fixtures -from sqlalchemy.testing import fixtures, assert_raises, eq_, ne_ +from sqlalchemy.testing import fixtures, assert_raises, eq_, ne_, \ + assert_raises_message from sqlalchemy.orm import mapper, Session, validates, relationship from sqlalchemy.testing.mock import Mock, call +from sqlalchemy import exc class ValidatorTest(_fixtures.FixtureTest): @@ -145,6 +147,41 @@ class ValidatorTest(_fixtures.FixtureTest): ] ) + def test_validator_multi_warning(self): + users = self.tables.users + + class Foo(object): + @validates("name") + def validate_one(self, key, value): + pass + + @validates("name") + def validate_two(self, key, value): + pass + + assert_raises_message( + exc.InvalidRequestError, + "A validation function for mapped attribute " + "'name' on mapper Mapper|Foo|users already exists", + mapper, Foo, users + ) + + class Bar(object): + @validates("id") + def validate_three(self, key, value): + return value + 10 + + @validates("id", "name") + def validate_four(self, key, value): + return value + "foo" + + assert_raises_message( + exc.InvalidRequestError, + "A validation function for mapped attribute " + "'name' on mapper Mapper|Bar|users already exists", + mapper, Bar, users + ) + def test_validator_wo_backrefs_wo_removes(self): self._test_validator_backrefs(False, False) |
