diff options
-rw-r--r-- | CHANGES | 11 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 15 | ||||
-rw-r--r-- | test/ext/declarative.py | 24 | ||||
-rw-r--r-- | test/orm/mapper.py | 18 |
4 files changed, 60 insertions, 8 deletions
@@ -5,6 +5,9 @@ CHANGES 0.4.5 ===== - orm + - added a more aggressive check for "uncompiled mappers", + helps particularly with declarative layer [ticket:995] + - Added comparable_property(), adds query Comparator behavior to regular, unmanaged Python properties @@ -79,8 +82,6 @@ CHANGES stickier behavior than before which is why it's off by default. - - - extensions - The "synonym" function is now directly usable with "declarative". Pass in the decorated property using the @@ -94,7 +95,11 @@ CHANGES - Declarative also gained @synonym_for(...) and @comparable_using(...), front-ends for synonym and comparable_property. - + + - Improvements to mapper compilation when using declarative; + already-compiled mappers will still trigger compiles of + other uncompiled mappers when used [ticket:995] + - Declarative will complete setup for Columns lacking names, allows a more DRY syntax. diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 3a6ea21cf..7e24c27c2 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -23,6 +23,7 @@ from sqlalchemy.orm.interfaces import MapperProperty, EXT_CONTINUE, PropComparat __all__ = ['Mapper', 'class_mapper', 'object_mapper', '_mapper_registry'] _mapper_registry = weakref.WeakKeyDictionary() +__new_mappers = False # a list of MapperExtensions that will be installed in all mappers by default global_extensions = [] @@ -93,7 +94,7 @@ class Mapper(object): # we make, theres workarounds but it starts to get really crazy (its crazy enough # the SQL that gets generated) so just require an alias raise exceptions.ArgumentError("Mapping against a Select object requires that it has a name. Use an alias to give it a name, i.e. s = select(...).alias('myselect')") - + self.class_ = class_ self.entity_name = entity_name self.primary_key_argument = primary_key @@ -164,7 +165,8 @@ class Mapper(object): self._compile_properties() self._compile_pks() self._compile_selectable() - + global __new_mappers + __new_mappers = True self.__log("constructed") def __log(self, msg): @@ -224,13 +226,15 @@ class Mapper(object): def compile(self): """Compile this mapper into its final internal format. """ - - if self.__props_init: + + global __new_mappers + if self.__props_init and not __new_mappers: return self _COMPILE_MUTEX.acquire() try: + # double-check inside mutex - if self.__props_init: + if self.__props_init and not __new_mappers: return self # initialize properties on all mappers @@ -238,6 +242,7 @@ class Mapper(object): if not mapper.__props_init: mapper.__initialize_properties() + __new_mappers = False return self finally: _COMPILE_MUTEX.release() diff --git a/test/ext/declarative.py b/test/ext/declarative.py index 6b6b90ea0..5da2dded5 100644 --- a/test/ext/declarative.py +++ b/test/ext/declarative.py @@ -56,6 +56,30 @@ class DeclarativeTest(TestBase, AssertsExecutionResults): a1 = sess.query(Address).filter(Address.email=='two').one() self.assertEquals(a1, Address(email='two')) self.assertEquals(a1.user, User(name='u1')) + + def test_recompile_on_othermapper(self): + """declarative version of the same test in mappers.py""" + + from sqlalchemy.orm import mapperlib + + class User(Base): + __tablename__ = 'users' + + id = Column('id', Integer, primary_key=True) + name = Column('name', String(50)) + + class Address(Base): + __tablename__ = 'addresses' + + id = Column('id', Integer, primary_key=True) + email = Column('email', String(50)) + user_id = Column('user_id', Integer, ForeignKey('users.id')) + user = relation("User", primaryjoin=user_id==User.id, backref="addresses") + + assert mapperlib._Mapper__new_mappers is True + u = User() + assert User.addresses + assert mapperlib._Mapper__new_mappers is False def test_nice_dependency_error(self): class User(Base): diff --git a/test/orm/mapper.py b/test/orm/mapper.py index 1228c6c77..aa27c4c81 100644 --- a/test/orm/mapper.py +++ b/test/orm/mapper.py @@ -73,7 +73,25 @@ class MapperTest(MapperSuperTest): assert False except exceptions.ArgumentError, e: assert "could not assemble any primary key columns for mapped table 'foo'" in str(e) + + def test_recompile_on_othermapper(self): + """test the global '__new_mappers' flag such that a compile + trigger on an already-compiled mapper still triggers a check against all mappers.""" + from sqlalchemy.orm import mapperlib + + mapper(User, users) + compile_mappers() + assert mapperlib._Mapper__new_mappers is False + + m = mapper(Address, addresses, properties={'user':relation(User, backref="addresses")}) + + assert m._Mapper__props_init is False + assert mapperlib._Mapper__new_mappers is True + u = User() + assert User.addresses + assert mapperlib._Mapper__new_mappers is False + def test_compileonsession(self): m = mapper(User, users) session = create_session() |