diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2012-04-23 12:03:54 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2012-04-23 12:03:54 -0400 |
| commit | 54017d9de202ed67072a352ce2f6dbfd74bf48f3 (patch) | |
| tree | a632045bd8a5e7d5932d69d5f436bc27f1b9788d /test | |
| parent | 8f35f7a803c67f4ab0620686592a021a24e4b331 (diff) | |
| parent | f7bb3b17e6df09caa56c20c722364fc52edf7afc (diff) | |
| download | sqlalchemy-54017d9de202ed67072a352ce2f6dbfd74bf48f3.tar.gz | |
merge patch for [ticket:2208]. This still needs documentation.
Diffstat (limited to 'test')
| -rw-r--r-- | test/base/test_inspect.py | 62 | ||||
| -rw-r--r-- | test/engine/test_reflection.py | 29 | ||||
| -rw-r--r-- | test/orm/_fixtures.py | 45 | ||||
| -rw-r--r-- | test/orm/test_backref_mutations.py | 4 | ||||
| -rw-r--r-- | test/orm/test_inspect.py | 290 | ||||
| -rw-r--r-- | test/orm/test_mapper.py | 8 | ||||
| -rw-r--r-- | test/orm/test_query.py | 40 | ||||
| -rw-r--r-- | test/orm/test_session.py | 2 |
8 files changed, 413 insertions, 67 deletions
diff --git a/test/base/test_inspect.py b/test/base/test_inspect.py new file mode 100644 index 000000000..b95b7d8c5 --- /dev/null +++ b/test/base/test_inspect.py @@ -0,0 +1,62 @@ +"""test the inspection registry system.""" + +from test.lib.testing import eq_, assert_raises +from sqlalchemy import exc, util +from sqlalchemy import inspection, inspect +from test.lib import fixtures + +class TestFixture(object): + pass + +class TestEvents(fixtures.TestBase): + """Test class- and instance-level event registration.""" + + def tearDown(self): + for type_ in list(inspection._registrars): + if issubclass(type_, TestFixture): + del inspection._registrars[type_] + + def test_def_insp(self): + class SomeFoo(TestFixture): + pass + + @inspection._inspects(SomeFoo) + def insp_somefoo(subject): + return {"insp":subject} + + somefoo = SomeFoo() + insp = inspect(somefoo) + assert insp["insp"] is somefoo + + def test_class_insp(self): + class SomeFoo(TestFixture): + pass + + @inspection._inspects(SomeFoo) + class SomeFooInspect(object): + def __init__(self, target): + self.target = target + + somefoo = SomeFoo() + insp = inspect(somefoo) + assert isinstance(insp, SomeFooInspect) + assert insp.target is somefoo + + def test_hierarchy_insp(self): + class SomeFoo(TestFixture): + pass + + class SomeSubFoo(SomeFoo): + pass + + @inspection._inspects(SomeFoo) + def insp_somefoo(subject): + return 1 + + @inspection._inspects(SomeSubFoo) + def insp_somesubfoo(subject): + return 2 + + somefoo = SomeFoo() + eq_(inspect(SomeFoo()), 1) + eq_(inspect(SomeSubFoo()), 2) diff --git a/test/engine/test_reflection.py b/test/engine/test_reflection.py index f385a0fa2..e59849d98 100644 --- a/test/engine/test_reflection.py +++ b/test/engine/test_reflection.py @@ -1,8 +1,7 @@ from test.lib.testing import eq_, assert_raises, assert_raises_message import StringIO, unicodedata from sqlalchemy import types as sql_types -from sqlalchemy import schema, events, event -from sqlalchemy.engine.reflection import Inspector +from sqlalchemy import schema, events, event, inspect from sqlalchemy import MetaData, Integer, String from test.lib.schema import Table, Column import sqlalchemy as sa @@ -10,8 +9,6 @@ from test.lib import ComparesTables, \ testing, engines, AssertsCompiledSQL from test.lib import fixtures -create_inspector = Inspector.from_engine - metadata, users = None, None class ReflectionTest(fixtures.TestBase, ComparesTables): @@ -773,7 +770,7 @@ class ReflectionTest(fixtures.TestBase, ComparesTables): def test_inspector_conn_closing(self): m1 = MetaData() c = testing.db.connect() - i = Inspector.from_engine(testing.db) + i = inspect(testing.db) assert not c.closed @testing.provide_metadata @@ -1050,7 +1047,7 @@ class UnicodeReflectionTest(fixtures.TestBase): @testing.requires.unicode_connections def test_get_names(self): - inspector = Inspector.from_engine(self.bind) + inspector = inspect(self.bind) names = dict( (tname, (cname, ixname)) for tname, cname, ixname in self.names ) @@ -1362,18 +1359,18 @@ class ComponentReflectionTest(fixtures.TestBase): @testing.requires.schemas def test_get_schema_names(self): - insp = Inspector(testing.db) + insp = inspect(testing.db) self.assert_('test_schema' in insp.get_schema_names()) def test_dialect_initialize(self): engine = engines.testing_engine() assert not hasattr(engine.dialect, 'default_schema_name') - insp = Inspector(engine) + insp = inspect(engine) assert hasattr(engine.dialect, 'default_schema_name') def test_get_default_schema_name(self): - insp = Inspector(testing.db) + insp = inspect(testing.db) eq_(insp.default_schema_name, testing.db.dialect.default_schema_name) @testing.provide_metadata @@ -1384,7 +1381,7 @@ class ComponentReflectionTest(fixtures.TestBase): meta.create_all() _create_views(meta.bind, schema) try: - insp = Inspector(meta.bind) + insp = inspect(meta.bind) if table_type == 'view': table_names = insp.get_view_names(schema) table_names.sort() @@ -1428,7 +1425,7 @@ class ComponentReflectionTest(fixtures.TestBase): _create_views(meta.bind, schema) table_names = ['users_v', 'email_addresses_v'] try: - insp = Inspector(meta.bind) + insp = inspect(meta.bind) for table_name, table in zip(table_names, (users, addresses)): schema_name = schema @@ -1490,7 +1487,7 @@ class ComponentReflectionTest(fixtures.TestBase): meta = self.metadata users, addresses, dingalings = createTables(meta, schema) meta.create_all() - insp = Inspector(meta.bind) + insp = inspect(meta.bind) users_pkeys = insp.get_primary_keys(users.name, schema=schema) eq_(users_pkeys, ['user_id']) @@ -1517,7 +1514,7 @@ class ComponentReflectionTest(fixtures.TestBase): meta = self.metadata users, addresses, dingalings = createTables(meta, schema) meta.create_all() - insp = Inspector(meta.bind) + insp = inspect(meta.bind) expected_schema = schema # users users_fkeys = insp.get_foreign_keys(users.name, @@ -1561,7 +1558,7 @@ class ComponentReflectionTest(fixtures.TestBase): createIndexes(meta.bind, schema) # The database may decide to create indexes for foreign keys, etc. # so there may be more indexes than expected. - insp = Inspector(meta.bind) + insp = inspect(meta.bind) indexes = insp.get_indexes('users', schema=schema) expected_indexes = [ {'unique': False, @@ -1590,7 +1587,7 @@ class ComponentReflectionTest(fixtures.TestBase): view_name1 = 'users_v' view_name2 = 'email_addresses_v' try: - insp = Inspector(meta.bind) + insp = inspect(meta.bind) v1 = insp.get_view_definition(view_name1, schema=schema) self.assert_(v1) v2 = insp.get_view_definition(view_name2, schema=schema) @@ -1613,7 +1610,7 @@ class ComponentReflectionTest(fixtures.TestBase): meta = self.metadata users, addresses, dingalings = createTables(meta, schema) meta.create_all() - insp = create_inspector(meta.bind) + insp = inspect(meta.bind) oid = insp.get_table_oid(table_name, schema) self.assert_(isinstance(oid, (int, long))) diff --git a/test/orm/_fixtures.py b/test/orm/_fixtures.py index 5def54e3a..7431a3a83 100644 --- a/test/orm/_fixtures.py +++ b/test/orm/_fixtures.py @@ -2,7 +2,8 @@ from sqlalchemy import MetaData, Integer, String, ForeignKey from sqlalchemy import util from test.lib.schema import Table from test.lib.schema import Column -from sqlalchemy.orm import attributes +from sqlalchemy.orm import attributes, mapper, relationship, \ + backref, configure_mappers from test.lib import fixtures __all__ = () @@ -49,6 +50,48 @@ class FixtureTest(fixtures.MappedTest): pass @classmethod + def _setup_stock_mapping(cls): + Node, composite_pk_table, users, Keyword, items, Dingaling, \ + order_items, item_keywords, Item, User, dingalings, \ + Address, keywords, CompositePk, nodes, Order, orders, \ + addresses = cls.classes.Node, \ + cls.tables.composite_pk_table, cls.tables.users, \ + cls.classes.Keyword, cls.tables.items, \ + cls.classes.Dingaling, cls.tables.order_items, \ + cls.tables.item_keywords, cls.classes.Item, \ + cls.classes.User, cls.tables.dingalings, \ + cls.classes.Address, cls.tables.keywords, \ + cls.classes.CompositePk, cls.tables.nodes, \ + cls.classes.Order, cls.tables.orders, cls.tables.addresses + + mapper(User, users, properties={ + 'addresses':relationship(Address, backref='user', order_by=addresses.c.id), + 'orders':relationship(Order, backref='user', order_by=orders.c.id), # o2m, m2o + }) + mapper(Address, addresses, properties={ + 'dingaling':relationship(Dingaling, uselist=False, backref="address") #o2o + }) + mapper(Dingaling, dingalings) + mapper(Order, orders, properties={ + 'items':relationship(Item, secondary=order_items, order_by=items.c.id), #m2m + 'address':relationship(Address), # m2o + }) + mapper(Item, items, properties={ + 'keywords':relationship(Keyword, secondary=item_keywords) #m2m + }) + mapper(Keyword, keywords) + + mapper(Node, nodes, properties={ + 'children':relationship(Node, + backref=backref('parent', remote_side=[nodes.c.id]) + ) + }) + + mapper(CompositePk, composite_pk_table) + + configure_mappers() + + @classmethod def define_tables(cls, metadata): Table('users', metadata, Column('id', Integer, primary_key=True, test_needs_autoincrement=True), diff --git a/test/orm/test_backref_mutations.py b/test/orm/test_backref_mutations.py index c633cb8ee..b3214984f 100644 --- a/test/orm/test_backref_mutations.py +++ b/test/orm/test_backref_mutations.py @@ -551,7 +551,7 @@ class M2MCollectionMoveTest(_fixtures.FixtureTest): # list is still here. eq_( set(attributes.instance_state(i1). - pending['keywords'].added_items), + _pending_mutations['keywords'].added_items), set([k2]) ) # because autoflush is off, k2 is still @@ -564,7 +564,7 @@ class M2MCollectionMoveTest(_fixtures.FixtureTest): # the pending collection was removed assert 'keywords' not in attributes.\ instance_state(i1).\ - pending + _pending_mutations def test_duplicate_adds(self): Item, Keyword = (self.classes.Item, self.classes.Keyword) diff --git a/test/orm/test_inspect.py b/test/orm/test_inspect.py new file mode 100644 index 000000000..9973c31c2 --- /dev/null +++ b/test/orm/test_inspect.py @@ -0,0 +1,290 @@ +"""test the inspection registry system.""" + +from test.lib.testing import eq_, assert_raises, is_ +from sqlalchemy import exc, util +from sqlalchemy import inspect +from test.orm import _fixtures +from sqlalchemy.orm import class_mapper, synonym, Session +from sqlalchemy.orm.attributes import instance_state, NO_VALUE +from test.lib import testing + +class TestORMInspection(_fixtures.FixtureTest): + @classmethod + def setup_mappers(cls): + cls._setup_stock_mapping() + inspect(cls.classes.User).add_property( + "name_syn",synonym("name") + ) + + def test_class_mapper(self): + User = self.classes.User + + assert inspect(User) is class_mapper(User) + + def test_instance_state(self): + User = self.classes.User + u1 = User() + + assert inspect(u1) is instance_state(u1) + + def test_column_collection_iterate(self): + User = self.classes.User + user_table = self.tables.users + insp = inspect(User) + eq_( + list(insp.columns), + [user_table.c.id, user_table.c.name] + ) + is_( + insp.columns.id, user_table.c.id + ) + + def test_primary_key(self): + User = self.classes.User + user_table = self.tables.users + insp = inspect(User) + eq_(insp.primary_key, + (user_table.c.id,) + ) + + def test_local_table(self): + User = self.classes.User + user_table = self.tables.users + insp = inspect(User) + is_(insp.local_table, user_table) + + def test_property(self): + User = self.classes.User + user_table = self.tables.users + insp = inspect(User) + is_(insp.attr.id, class_mapper(User).get_property('id')) + + def test_col_property(self): + User = self.classes.User + user_table = self.tables.users + insp = inspect(User) + id_prop = insp.attr.id + + eq_(id_prop.columns, [user_table.c.id]) + is_(id_prop.expression, user_table.c.id) + + assert not hasattr(id_prop, 'mapper') + + def test_attr_keys(self): + User = self.classes.User + insp = inspect(User) + eq_( + set(insp.attr.keys()), + set(['addresses', 'orders', 'id', 'name', 'name_syn']) + ) + + def test_col_filter(self): + User = self.classes.User + insp = inspect(User) + eq_( + list(insp.column_attrs), + [insp.get_property('id'), insp.get_property('name')] + ) + eq_( + insp.column_attrs.keys(), + ['id', 'name'] + ) + is_( + insp.column_attrs.id, + User.id.property + ) + + def test_synonym_filter(self): + User = self.classes.User + syn = inspect(User).synonyms + + eq_( + list(syn.keys()), ['name_syn'] + ) + is_(syn.name_syn, User.name_syn.original_property) + eq_(dict(syn), { + "name_syn":User.name_syn.original_property + }) + + def test_relationship_filter(self): + User = self.classes.User + rel = inspect(User).relationships + + eq_( + rel.addresses, + User.addresses.property + ) + eq_( + set(rel.keys()), + set(['orders', 'addresses']) + ) + + def test_insp_prop(self): + User = self.classes.User + prop = inspect(User.addresses) + is_(prop, User.addresses.property) + + def test_rel_accessors(self): + User = self.classes.User + Address = self.classes.Address + prop = inspect(User.addresses) + is_(prop.parent, class_mapper(User)) + is_(prop.mapper, class_mapper(Address)) + + assert not hasattr(prop, 'columns') + assert not hasattr(prop, 'expression') + + def test_instance_state(self): + User = self.classes.User + u1 = User() + insp = inspect(u1) + is_(insp, instance_state(u1)) + + def test_instance_state_attr(self): + User = self.classes.User + u1 = User(name='ed') + insp = inspect(u1) + + eq_( + set(insp.attr.keys()), + set(['id', 'name', 'name_syn', 'addresses', 'orders']) + ) + eq_( + insp.attr.name.value, + 'ed' + ) + eq_( + insp.attr.name.loaded_value, + 'ed' + ) + + def test_instance_state_attr_passive_value_scalar(self): + User = self.classes.User + u1 = User(name='ed') + insp = inspect(u1) + # value was not set, NO_VALUE + eq_( + insp.attr.id.loaded_value, + NO_VALUE + ) + # regular accessor sets it + eq_( + insp.attr.id.value, + None + ) + # now the None is there + eq_( + insp.attr.id.loaded_value, + None + ) + + def test_instance_state_attr_passive_value_collection(self): + User = self.classes.User + u1 = User(name='ed') + insp = inspect(u1) + # value was not set, NO_VALUE + eq_( + insp.attr.addresses.loaded_value, + NO_VALUE + ) + # regular accessor sets it + eq_( + insp.attr.addresses.value, + [] + ) + # now the None is there + eq_( + insp.attr.addresses.loaded_value, + [] + ) + + def test_instance_state_attr_hist(self): + User = self.classes.User + u1 = User(name='ed') + insp = inspect(u1) + hist = insp.attr.addresses.history + eq_( + hist.unchanged, None + ) + u1.addresses + hist = insp.attr.addresses.history + eq_( + hist.unchanged, [] + ) + + def test_instance_state_ident_transient(self): + User = self.classes.User + u1 = User(name='ed') + insp = inspect(u1) + is_(insp.identity, None) + + def test_instance_state_ident_persistent(self): + User = self.classes.User + u1 = User(name='ed') + s = Session(testing.db) + s.add(u1) + s.flush() + insp = inspect(u1) + eq_(insp.identity, (u1.id,)) + is_(s.query(User).get(insp.identity), u1) + + def test_identity_key(self): + User = self.classes.User + u1 = User(name='ed') + s = Session(testing.db) + s.add(u1) + s.flush() + insp = inspect(u1) + eq_( + insp.identity_key, + (User, (11, )) + ) + + def test_persistence_states(self): + User = self.classes.User + u1 = User(name='ed') + insp = inspect(u1) + + eq_( + (insp.transient, insp.pending, + insp.persistent, insp.detached), + (True, False, False, False) + ) + s = Session(testing.db) + s.add(u1) + + eq_( + (insp.transient, insp.pending, + insp.persistent, insp.detached), + (False, True, False, False) + ) + + s.flush() + eq_( + (insp.transient, insp.pending, + insp.persistent, insp.detached), + (False, False, True, False) + ) + s.expunge(u1) + eq_( + (insp.transient, insp.pending, + insp.persistent, insp.detached), + (False, False, False, True) + ) + + def test_session_accessor(self): + User = self.classes.User + u1 = User(name='ed') + insp = inspect(u1) + + is_(insp.session, None) + s = Session() + s.add(u1) + is_(insp.session, s) + + def test_object_accessor(self): + User = self.classes.User + u1 = User(name='ed') + insp = inspect(u1) + is_(insp.object, u1) + diff --git a/test/orm/test_mapper.py b/test/orm/test_mapper.py index 4478e5d80..78a1c29a4 100644 --- a/test/orm/test_mapper.py +++ b/test/orm/test_mapper.py @@ -87,14 +87,6 @@ class MapperTest(_fixtures.FixtureTest, AssertsCompiledSQL): - def test_prop_accessor(self): - users, User = self.tables.users, self.classes.User - - mapper(User, users) - assert_raises(NotImplementedError, - getattr, sa.orm.class_mapper(User), 'properties') - - def test_friendly_attribute_str_on_uncompiled_boom(self): User, users = self.classes.User, self.tables.users diff --git a/test/orm/test_query.py b/test/orm/test_query.py index 1b57299f0..6e945aa72 100644 --- a/test/orm/test_query.py +++ b/test/orm/test_query.py @@ -29,45 +29,7 @@ class QueryTest(_fixtures.FixtureTest): @classmethod def setup_mappers(cls): - Node, composite_pk_table, users, Keyword, items, Dingaling, \ - order_items, item_keywords, Item, User, dingalings, \ - Address, keywords, CompositePk, nodes, Order, orders, \ - addresses = cls.classes.Node, \ - cls.tables.composite_pk_table, cls.tables.users, \ - cls.classes.Keyword, cls.tables.items, \ - cls.classes.Dingaling, cls.tables.order_items, \ - cls.tables.item_keywords, cls.classes.Item, \ - cls.classes.User, cls.tables.dingalings, \ - cls.classes.Address, cls.tables.keywords, \ - cls.classes.CompositePk, cls.tables.nodes, \ - cls.classes.Order, cls.tables.orders, cls.tables.addresses - - mapper(User, users, properties={ - 'addresses':relationship(Address, backref='user', order_by=addresses.c.id), - 'orders':relationship(Order, backref='user', order_by=orders.c.id), # o2m, m2o - }) - mapper(Address, addresses, properties={ - 'dingaling':relationship(Dingaling, uselist=False, backref="address") #o2o - }) - mapper(Dingaling, dingalings) - mapper(Order, orders, properties={ - 'items':relationship(Item, secondary=order_items, order_by=items.c.id), #m2m - 'address':relationship(Address), # m2o - }) - mapper(Item, items, properties={ - 'keywords':relationship(Keyword, secondary=item_keywords) #m2m - }) - mapper(Keyword, keywords) - - mapper(Node, nodes, properties={ - 'children':relationship(Node, - backref=backref('parent', remote_side=[nodes.c.id]) - ) - }) - - mapper(CompositePk, composite_pk_table) - - configure_mappers() + cls._setup_stock_mapping() class MiscTest(QueryTest): run_create_tables = None diff --git a/test/orm/test_session.py b/test/orm/test_session.py index 79852c7a4..a82606b2b 100644 --- a/test/orm/test_session.py +++ b/test/orm/test_session.py @@ -1158,7 +1158,7 @@ class DisposedStates(fixtures.MappedTest): for obj in objs: state = attributes.instance_state(obj) sess.identity_map.discard(state) - state.dispose() + state._dispose() def _test_session(self, **kwargs): global sess |
