summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/sqlalchemy/orm/mapper.py8
-rw-r--r--test/orm/inheritance/concrete.py26
-rw-r--r--test/orm/unitofwork.py20
3 files changed, 47 insertions, 7 deletions
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 99e93df5d..172b99558 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -368,7 +368,7 @@ class Mapper(object):
for mapper in list(_mapper_registry):
if not mapper.compiled:
mapper.__initialize_properties()
-
+
_new_mappers = False
return self
finally:
@@ -526,10 +526,10 @@ class Mapper(object):
# mark these as "read only" properties which are refreshed upon
# INSERT/UPDATE
self._readonly_props = util.Set([
- self._columntoproperty[col] for col in all_cols if
+ self._columntoproperty[col] for col in self._columntoproperty if
not hasattr(col, 'table') or col.table not in self._cols_by_table
])
-
+
# if explicit PK argument sent, add those columns to the primary key mappings
if self.primary_key_argument:
for k in self.primary_key_argument:
@@ -1190,7 +1190,7 @@ class Mapper(object):
# expire readonly attributes
readonly = state.unmodified.intersection([
- p.key for p in chain(*[m._readonly_props for m in mapper.iterate_to_root()])
+ p.key for p in mapper._readonly_props
])
if readonly:
diff --git a/test/orm/inheritance/concrete.py b/test/orm/inheritance/concrete.py
index ffc95ac05..b6d31a715 100644
--- a/test/orm/inheritance/concrete.py
+++ b/test/orm/inheritance/concrete.py
@@ -1,7 +1,9 @@
import testenv; testenv.configure_for_tests()
from sqlalchemy import *
from sqlalchemy.orm import *
+from sqlalchemy.orm import exc as orm_exc
from testlib import *
+from sqlalchemy.orm import attributes
class ConcreteTest(ORMTest):
def define_tables(self, metadata):
@@ -133,16 +135,34 @@ class ConcreteTest(ORMTest):
concrete=True, polymorphic_identity='hacker')
session = create_session()
- session.save(Manager('Tom', 'knows how to manage things'))
- session.save(Engineer('Jerry', 'knows how to program'))
- session.save(Hacker('Kurt', 'Badass', 'knows how to hack'))
+ tom = Manager('Tom', 'knows how to manage things')
+ jerry = Engineer('Jerry', 'knows how to program')
+ hacker = Hacker('Kurt', 'Badass', 'knows how to hack')
+ session.add_all((tom, jerry, hacker))
session.flush()
+
+ # ensure "readonly" on save logic didn't pollute the expired_attributes
+ # collection
+ assert 'nickname' not in attributes.instance_state(jerry).expired_attributes
+ assert 'name' not in attributes.instance_state(jerry).expired_attributes
+ assert 'name' not in attributes.instance_state(hacker).expired_attributes
+ assert 'nickname' not in attributes.instance_state(hacker).expired_attributes
+ def go():
+ self.assertEquals(jerry.name, "Jerry")
+ self.assertEquals(hacker.nickname, "Badass")
+ self.assert_sql_count(testing.db, go, 0)
+
session.clear()
assert set([repr(x) for x in session.query(Employee).all()]) == set(["Engineer Jerry knows how to program", "Manager Tom knows how to manage things", "Hacker Kurt 'Badass' knows how to hack"])
assert set([repr(x) for x in session.query(Manager).all()]) == set(["Manager Tom knows how to manage things"])
assert set([repr(x) for x in session.query(Engineer).all()]) == set(["Engineer Jerry knows how to program", "Hacker Kurt 'Badass' knows how to hack"])
+ # because we are concrete, are intentionally repeating integer ids across
+ # tables, and have told the "Engineer" mapper to load polymorphically,
+ # this cannot work:
+ self.assertRaises(orm_exc.MultipleResultsFound, session.query(Engineer).filter(Engineer.employee_id==1).one)
+
def test_relation(self):
class Employee(object):
def __init__(self, name):
diff --git a/test/orm/unitofwork.py b/test/orm/unitofwork.py
index f0ab709af..371335b07 100644
--- a/test/orm/unitofwork.py
+++ b/test/orm/unitofwork.py
@@ -992,6 +992,11 @@ class ColumnPropertyTest(_base.MappedTest):
Column('a', String(50)),
Column('b', String(50))
)
+
+ Table('subdata', metadata,
+ Column('id', Integer, ForeignKey('data.id'), primary_key=True),
+ Column('c', String(50)),
+ )
def setup_mappers(self):
class Data(_base.BasicEntity):
@@ -1009,6 +1014,21 @@ class ColumnPropertyTest(_base.MappedTest):
m = mapper(Data, data)
m.add_property('aplusb', column_property(data.c.a + literal_column("' '") + data.c.b))
self._test()
+
+ @testing.resolve_artifact_names
+ def test_with_inheritance(self):
+ class SubData(Data):
+ pass
+ mapper(Data, data, properties={
+ 'aplusb':column_property(data.c.a + literal_column("' '") + data.c.b)
+ })
+ mapper(SubData, subdata, inherits=Data)
+
+ sess = create_session()
+ sd1 = SubData(a="hello", b="there", c="hi")
+ sess.add(sd1)
+ sess.flush()
+ self.assertEquals(sd1.aplusb, "hello there")
@testing.resolve_artifact_names
def _test(self):