diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-01-19 23:25:43 +0000 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-01-19 23:25:43 +0000 |
commit | 81372486d9a10305f47f76c4455a5e6df02e586c (patch) | |
tree | 84cfd3a599180cb78611a358ae515bfc1078ca6e | |
parent | 40f8aadd582776524d3b98da1f577c2fc95619e7 (diff) | |
download | sqlalchemy-81372486d9a10305f47f76c4455a5e6df02e586c.tar.gz |
lessons learned unpickling from an 0.5 cache
-rw-r--r-- | lib/sqlalchemy/orm/interfaces.py | 2 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/state.py | 11 | ||||
-rw-r--r-- | test/orm/test_pickled.py | 55 |
3 files changed, 65 insertions, 3 deletions
diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py index d8ba9ea96..0077f3e6a 100644 --- a/lib/sqlalchemy/orm/interfaces.py +++ b/lib/sqlalchemy/orm/interfaces.py @@ -700,7 +700,7 @@ def deserialize_path(path): from sqlalchemy.orm import class_mapper p = tuple(chain(*[(class_mapper(cls), key) for cls, key in path])) - if p[-1] is None: + if p and p[-1] is None: p = p[0:-1] return p diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py index 472d2c081..14c677b89 100644 --- a/lib/sqlalchemy/orm/state.py +++ b/lib/sqlalchemy/orm/state.py @@ -155,7 +155,9 @@ class InstanceState(object): "Cannot deserialize object of type %r - no mapper() has" " been configured for this class within the current Python process!" % self.class_) - + elif manager.mapper and not manager.mapper.compiled: + manager.mapper.compile() + self.committed_state = state.get('committed_state', {}) self.pending = state.get('pending', {}) self.parents = state.get('parents', {}) @@ -355,6 +357,13 @@ class InstanceState(object): self._strong_obj = None class MutableAttrInstanceState(InstanceState): + """InstanceState implementation for objects that reference 'mutable' + attributes. + + Has a more involved "cleanup" handler that checks mutable attributes + for changes upon dereference, resurrecting if needed. + + """ def __init__(self, obj, manager): self.mutable_dict = {} InstanceState.__init__(self, obj, manager) diff --git a/test/orm/test_pickled.py b/test/orm/test_pickled.py index 62caa49da..a734ad779 100644 --- a/test/orm/test_pickled.py +++ b/test/orm/test_pickled.py @@ -7,12 +7,14 @@ from sqlalchemy import Integer, String, ForeignKey, exc from sqlalchemy.test.schema import Table, Column from sqlalchemy.orm import mapper, relation, create_session, \ sessionmaker, attributes, interfaces,\ - clear_mappers, exc as orm_exc + clear_mappers, exc as orm_exc,\ + compile_mappers from test.orm import _base, _fixtures User, EmailUser = None, None + class PickleTest(_fixtures.FixtureTest): run_inserts = None @@ -48,6 +50,22 @@ class PickleTest(_fixtures.FixtureTest): orm_exc.UnmappedInstanceError, "Cannot deserialize object of type <class 'test.orm._fixtures.User'> - no mapper()", pickle.loads, u1_pickled) + + @testing.resolve_artifact_names + def test_no_instrumentation(self): + + umapper = mapper(User, users) + u1 = User(name='ed') + u1_pickled = pickle.dumps(u1, -1) + + clear_mappers() + + umapper = mapper(User, users) + + u1 = pickle.loads(u1_pickled) + # this fails unless the InstanceState + # compiles the mapper + eq_(str(u1), "User(name='ed')") @testing.resolve_artifact_names def test_serialize_path(self): @@ -71,6 +89,13 @@ class PickleTest(_fixtures.FixtureTest): p2 ) + # test a blank path + p3 = () + eq_( + interfaces.deserialize_path(interfaces.serialize_path(p3)), + p3 + ) + @testing.resolve_artifact_names def test_class_deferred_cols(self): mapper(User, users, properties={ @@ -254,3 +279,31 @@ class CustomSetupTeardownTest(_fixtures.FixtureTest): attributes.manager_of_class(User).setup_instance(u2) assert attributes.instance_state(u2) +class UnpickleSA05Test(_fixtures.FixtureTest): + """test loading picklestrings from SQLA 0.5.""" + + @testing.resolve_artifact_names + def test_one(self): + mapper(User, users, properties={ + 'addresses':relation(Address, backref="user") + }) + mapper(Address, addresses) + data = \ + '\x80\x02]q\x00(ctest.orm._fixtures\nUser\nq\x01)\x81q\x02}q\x03(U\x12_sa_instance_stateq\x04csqlalchemy.orm.state\nInstanceState\nq\x05)\x81q\x06}q\x07(U\x08instanceq\x08h\x02U\x03keyq\th\x01K\x07\x85q\n\x86q\x0bubU\taddressesq\x0ccsqlalchemy.orm.collections\nInstrumentedList\nq\r)\x81q\x0ectest.orm._fixtures\nAddress\nq\x0f)\x81q\x10}q\x11(U\remail_addressq\x12X\r\x00\x00\x00jack@bean.comq\x13h\x04h\x05)\x81q\x14}q\x15(h\x08h\x10h\th\x0fK\x01\x85q\x16\x86q\x17ubU\x07user_idq\x18K\x07U\x02idq\x19K\x01uba}q\x1aU\x0b_sa_adapterq\x1bcsqlalchemy.orm.collections\nCollectionAdapter\nq\x1c)\x81q\x1d}q\x1e(U\x04dataq\x1fh\x0eU\x0bowner_stateq h\x06U\x03keyq!h\x0cubsbh\x19K\x07U\x04nameq"X\x04\x00\x00\x00jackq#ubh\x01)\x81q$}q%(h\x04h\x05)\x81q&}q\'(h\x08h$h\th\x01K\x08\x85q(\x86q)ubh\x0ch\r)\x81q*(h\x0f)\x81q+}q,(h\x12X\x0b\x00\x00\x00ed@wood.comq-h\x04h\x05)\x81q.}q/(h\x08h+h\th\x0fK\x02\x85q0\x86q1ubh\x18K\x08h\x19K\x02ubh\x0f)\x81q2}q3(h\x12X\x10\x00\x00\x00ed@bettyboop.comq4h\x04h\x05)\x81q5}q6(h\x08h2h\th\x0fK\x03\x85q7\x86q8ubh\x18K\x08h\x19K\x03ubh\x0f)\x81q9}q:(h\x12X\x0b\x00\x00\x00ed@lala.comq;h\x04h\x05)\x81q<}q=(h\x08h9h\th\x0fK\x04\x85q>\x86q?ubh\x18K\x08h\x19K\x04ube}q@h\x1bh\x1c)\x81qA}qB(h\x1fh*h h&h!h\x0cubsbh\x19K\x08h"X\x02\x00\x00\x00edqCubh\x01)\x81qD}qE(h\x04h\x05)\x81qF}qG(h\x08hDh\th\x01K\t\x85qH\x86qIubh\x0ch\r)\x81qJh\x0f)\x81qK}qL(h\x12X\r\x00\x00\x00fred@fred.comqMh\x04h\x05)\x81qN}qO(h\x08hKh\th\x0fK\x05\x85qP\x86qQubh\x18K\th\x19K\x05uba}qRh\x1bh\x1c)\x81qS}qT(h\x1fhJh hFh!h\x0cubsbh\x19K\th"X\x04\x00\x00\x00fredqUubh\x01)\x81qV}qW(h\x04h\x05)\x81qX}qY(h\x08hVh\th\x01K\n\x85qZ\x86q[ubh\x0ch\r)\x81q\\}q]h\x1bh\x1c)\x81q^}q_(h\x1fh\\h hXh!h\x0cubsbh\x19K\nh"X\x05\x00\x00\x00chuckq`ube.' + + sess = create_session() + result = list(sess.query(User).merge_result(pickle.loads(data))) + eq_(result, self.static.user_address_result) + + @testing.resolve_artifact_names + def test_two(self): + mapper(User, users, properties={ + 'addresses':relation(Address, backref="user") + }) + mapper(Address, addresses) + data = \ +'\x80\x02]q\x00(ctest.orm._fixtures\nUser\nq\x01)\x81q\x02}q\x03(U\x12_sa_instance_stateq\x04csqlalchemy.orm.state\nInstanceState\nq\x05)\x81q\x06}q\x07(U\x08instanceq\x08h\x02U\tload_pathq\t]q\nU\x03keyq\x0bh\x01K\x07\x85q\x0c\x86q\rU\x0cload_optionsq\x0ec__builtin__\nset\nq\x0f]q\x10csqlalchemy.orm.strategies\nEagerLazyOption\nq\x11)\x81q\x12}q\x13(U\x06mapperq\x14NU\x04lazyq\x15\x89U\x14propagate_to_loadersq\x16\x88U\x03keyq\x17]q\x18h\x01U\taddressesq\x19\x86q\x1aaU\x07chainedq\x1b\x89uba\x85q\x1cRq\x1dubh\x19csqlalchemy.orm.collections\nInstrumentedList\nq\x1e)\x81q\x1fctest.orm._fixtures\nAddress\nq )\x81q!}q"(U\remail_addressq#X\r\x00\x00\x00jack@bean.comq$h\x04h\x05)\x81q%}q&(h\x08h!h\t]q\'h\x01h\x19\x86q(ah\x0bh K\x01\x85q)\x86q*h\x0eh\x1dubU\x07user_idq+K\x07U\x02idq,K\x01uba}q-U\x0b_sa_adapterq.csqlalchemy.orm.collections\nCollectionAdapter\nq/)\x81q0}q1(U\x04dataq2h\x1fU\x0bowner_stateq3h\x06h\x17h\x19ubsbU\x04nameq4X\x04\x00\x00\x00jackq5h,K\x07ubh\x01)\x81q6}q7(h\x04h\x05)\x81q8}q9(h\x08h6h\t]q:h\x0bh\x01K\x08\x85q;\x86q<h\x0eh\x1dubh\x19h\x1e)\x81q=(h )\x81q>}q?(h#X\x0b\x00\x00\x00ed@wood.comq@h\x04h\x05)\x81qA}qB(h\x08h>h\t]qCh\x01h\x19\x86qDah\x0bh K\x02\x85qE\x86qFh\x0eh\x1dubh+K\x08h,K\x02ubh )\x81qG}qH(h#X\x10\x00\x00\x00ed@bettyboop.comqIh\x04h\x05)\x81qJ}qK(h\x08hGh\t]qLh\x01h\x19\x86qMah\x0bh K\x03\x85qN\x86qOh\x0eh\x1dubh+K\x08h,K\x03ubh )\x81qP}qQ(h#X\x0b\x00\x00\x00ed@lala.comqRh\x04h\x05)\x81qS}qT(h\x08hPh\t]qUh\x01h\x19\x86qVah\x0bh K\x04\x85qW\x86qXh\x0eh\x1dubh+K\x08h,K\x04ube}qYh.h/)\x81qZ}q[(h2h=h3h8h\x17h\x19ubsbh4X\x02\x00\x00\x00edq\\h,K\x08ubh\x01)\x81q]}q^(h\x04h\x05)\x81q_}q`(h\x08h]h\t]qah\x0bh\x01K\t\x85qb\x86qch\x0eh\x1dubh\x19h\x1e)\x81qdh )\x81qe}qf(h#X\r\x00\x00\x00fred@fred.comqgh\x04h\x05)\x81qh}qi(h\x08heh\t]qjh\x01h\x19\x86qkah\x0bh K\x05\x85ql\x86qmh\x0eh\x1dubh+K\th,K\x05uba}qnh.h/)\x81qo}qp(h2hdh3h_h\x17h\x19ubsbh4X\x04\x00\x00\x00fredqqh,K\tubh\x01)\x81qr}qs(h\x04h\x05)\x81qt}qu(h\x08hrh\t]qvh\x0bh\x01K\n\x85qw\x86qxh\x0eh\x1dubh\x19h\x1e)\x81qy}qzh.h/)\x81q{}q|(h2hyh3hth\x17h\x19ubsbh4X\x05\x00\x00\x00chuckq}h,K\nube.' + + sess = create_session() + result = list(sess.query(User).merge_result(pickle.loads(data))) + eq_(result, self.static.user_address_result) |