From: Mike Bayer Date: Sat, 19 Jul 2008 19:23:37 +0000 (+0000) Subject: - Some improvements to the _CompileOnAttr mechanism which X-Git-Tag: rel_0_5beta3~28 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d56862cbca1796edafab8845fd1852f6183512f8;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Some improvements to the _CompileOnAttr mechanism which should reduce the probability of "Attribute x was not replaced during compile" warnings. (this generally applies to SQLA hackers, like Elixir devs). --- diff --git a/CHANGES b/CHANGES index 4b3ec2ebe2..1d34eedbea 100644 --- a/CHANGES +++ b/CHANGES @@ -32,6 +32,11 @@ CHANGES present in a list of items to be processed, typically during session.expunge_all() and dependent methods. + - Some improvements to the _CompileOnAttr mechanism which + should reduce the probability of "Attribute x was + not replaced during compile" warnings. (this generally + applies to SQLA hackers, like Elixir devs). + - ext - Class-bound attributes sent as arguments to relation()'s remote_side and foreign_keys parameters diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 588bc359d3..e8bae46a4f 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -355,6 +355,7 @@ class Mapper(object): # re-entrance to compile() occurs rarely, when a class-mapped construct is # used within a ForeignKey, something that is possible # when using the declarative layer + self.__initialize_properties() return _already_compiling = True try: @@ -385,8 +386,8 @@ class Mapper(object): self.__log("__initialize_properties() started") l = [(key, prop) for key, prop in self.__props.iteritems()] for key, prop in l: - self.__log("initialize prop " + key) if not getattr(prop, '_compiled', False): + self.__log("initialize prop " + key) prop.init(key, self) self.__log("__initialize_properties() complete") self.compiled = True diff --git a/test/ext/declarative.py b/test/ext/declarative.py index 0fafc59992..c7bde68020 100644 --- a/test/ext/declarative.py +++ b/test/ext/declarative.py @@ -3,7 +3,7 @@ import testenv; testenv.configure_for_tests() from sqlalchemy.ext import declarative as decl from testlib import sa, testing from testlib.sa import MetaData, Table, Column, Integer, String, ForeignKey, ForeignKeyConstraint -from testlib.sa.orm import relation, create_session +from testlib.sa.orm import relation, create_session, class_mapper from testlib.testing import eq_ from orm._base import ComparableEntity @@ -113,17 +113,26 @@ class DeclarativeTest(testing.TestBase, testing.AssertsExecutionResults): __tablename__ = 'addresses' id = Column(Integer, primary_key=True) email = Column(String(50)) - user_id = Column(Integer) # note no foreign key + user_id = Column(Integer, ForeignKey('users.id')) class User(Base, ComparableEntity): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String(50)) addresses = relation("Address", order_by=Address.email, - foreign_keys=Address.user_id, remote_side=Address.user_id, - primaryjoin=id==Address.user_id, + foreign_keys=Address.user_id, + remote_side=Address.user_id, ) - + + # get the mapper for User. User mapper will compile, + # "addresses" relation will call upon Address.user_id for + # its clause element. Address.user_id is a _CompileOnAttr, + # which then calls class_mapper(Address). But ! We're already + # "in compilation", but class_mapper(Address) needs to initialize + # regardless, or COA's assertion fails + # and things generally go downhill from there. + class_mapper(User) + Base.metadata.create_all() sess = create_session()