diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-01-21 20:10:23 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-01-21 20:10:23 -0500 |
| commit | 07fb90c6cc14de6d02cf4be592c57d56831f59f7 (patch) | |
| tree | 050ef65db988559c60f7aa40f2d0bfe24947e548 /test/ext | |
| parent | 560fd1d5ed643a1b0f95296f3b840c1963bbe67f (diff) | |
| parent | ee1f4d21037690ad996c5eacf7e1200e92f2fbaa (diff) | |
| download | sqlalchemy-ticket_2501.tar.gz | |
Merge branch 'master' into ticket_2501ticket_2501
Conflicts:
lib/sqlalchemy/orm/mapper.py
Diffstat (limited to 'test/ext')
| -rw-r--r-- | test/ext/declarative/test_basic.py | 157 | ||||
| -rw-r--r-- | test/ext/declarative/test_reflection.py | 132 | ||||
| -rw-r--r-- | test/ext/test_associationproxy.py | 190 | ||||
| -rw-r--r-- | test/ext/test_automap.py | 146 | ||||
| -rw-r--r-- | test/ext/test_compiler.py | 18 | ||||
| -rw-r--r-- | test/ext/test_extendedattr.py | 2 | ||||
| -rw-r--r-- | test/ext/test_mutable.py | 6 | ||||
| -rw-r--r-- | test/ext/test_serializer.py | 51 |
8 files changed, 561 insertions, 141 deletions
diff --git a/test/ext/declarative/test_basic.py b/test/ext/declarative/test_basic.py index 540f1623f..1f14d8164 100644 --- a/test/ext/declarative/test_basic.py +++ b/test/ext/declarative/test_basic.py @@ -4,14 +4,14 @@ from sqlalchemy.testing import eq_, assert_raises, \ from sqlalchemy.ext import declarative as decl from sqlalchemy import exc import sqlalchemy as sa -from sqlalchemy import testing +from sqlalchemy import testing, util from sqlalchemy import MetaData, Integer, String, ForeignKey, \ ForeignKeyConstraint, Index from sqlalchemy.testing.schema import Table, Column from sqlalchemy.orm import relationship, create_session, class_mapper, \ joinedload, configure_mappers, backref, clear_mappers, \ deferred, column_property, composite,\ - Session + Session, properties from sqlalchemy.testing import eq_ from sqlalchemy.util import classproperty, with_metaclass from sqlalchemy.ext.declarative import declared_attr, AbstractConcreteBase, \ @@ -77,6 +77,26 @@ class DeclarativeTest(DeclarativeTestBase): eq_(a1, Address(email='two')) eq_(a1.user, User(name='u1')) + def test_unicode_string_resolve(self): + class User(Base, fixtures.ComparableEntity): + __tablename__ = 'users' + + id = Column('id', Integer, primary_key=True, + test_needs_autoincrement=True) + name = Column('name', String(50)) + addresses = relationship(util.u("Address"), backref="user") + + class Address(Base, fixtures.ComparableEntity): + __tablename__ = 'addresses' + + id = Column(Integer, primary_key=True, + test_needs_autoincrement=True) + email = Column(String(50), key='_email') + user_id = Column('user_id', Integer, ForeignKey('users.id'), + key='_user_id') + + assert User.addresses.property.mapper.class_ is Address + def test_no_table(self): def go(): class User(Base): @@ -123,6 +143,71 @@ class DeclarativeTest(DeclarativeTestBase): assert class_mapper(Bar).get_property('some_data').columns[0] \ is t.c.data + def test_column_named_twice(self): + def go(): + class Foo(Base): + __tablename__ = 'foo' + + id = Column(Integer, primary_key=True) + x = Column('x', Integer) + y = Column('x', Integer) + assert_raises_message( + sa.exc.SAWarning, + "On class 'Foo', Column object 'x' named directly multiple times, " + "only one will be used: x, y", + go + ) + + + def test_column_repeated_under_prop(self): + def go(): + class Foo(Base): + __tablename__ = 'foo' + + id = Column(Integer, primary_key=True) + x = Column('x', Integer) + y = column_property(x) + z = Column('x', Integer) + + assert_raises_message( + sa.exc.SAWarning, + "On class 'Foo', Column object 'x' named directly multiple times, " + "only one will be used: x, y, z", + go + ) + + def test_relationship_level_msg_for_invalid_callable(self): + class A(Base): + __tablename__ = 'a' + id = Column(Integer, primary_key=True) + class B(Base): + __tablename__ = 'b' + id = Column(Integer, primary_key=True) + a_id = Column(Integer, ForeignKey('a.id')) + a = relationship('a') + assert_raises_message( + sa.exc.ArgumentError, + "relationship 'a' expects a class or a mapper " + "argument .received: .*Table", + configure_mappers + ) + + def test_relationship_level_msg_for_invalid_object(self): + class A(Base): + __tablename__ = 'a' + id = Column(Integer, primary_key=True) + class B(Base): + __tablename__ = 'b' + id = Column(Integer, primary_key=True) + a_id = Column(Integer, ForeignKey('a.id')) + a = relationship(A.__table__) + assert_raises_message( + sa.exc.ArgumentError, + "relationship 'a' expects a class or a mapper " + "argument .received: .*Table", + configure_mappers + ) + def test_difficult_class(self): """test no getattr() errors with a customized class""" @@ -202,10 +287,10 @@ class DeclarativeTest(DeclarativeTestBase): user = relationship("User", primaryjoin=user_id == User.id, backref="addresses") - assert mapperlib._new_mappers is True + assert mapperlib.Mapper._new_mappers is True u = User() assert User.addresses - assert mapperlib._new_mappers is False + assert mapperlib.Mapper._new_mappers is False def test_string_dependency_resolution(self): from sqlalchemy.sql import desc @@ -707,6 +792,64 @@ class DeclarativeTest(DeclarativeTestBase): eq_(a1, Address(email='two')) eq_(a1.user, User(name='u1')) + def test_alt_name_attr_subclass_column_inline(self): + # [ticket:2900] + class A(Base): + __tablename__ = 'a' + id = Column('id', Integer, primary_key=True) + data = Column('data') + + class ASub(A): + brap = A.data + assert ASub.brap.property is A.data.property + assert isinstance(ASub.brap.original_property, properties.SynonymProperty) + + def test_alt_name_attr_subclass_relationship_inline(self): + # [ticket:2900] + class A(Base): + __tablename__ = 'a' + id = Column('id', Integer, primary_key=True) + b_id = Column(Integer, ForeignKey('b.id')) + b = relationship("B", backref="as_") + + class B(Base): + __tablename__ = 'b' + id = Column('id', Integer, primary_key=True) + + configure_mappers() + class ASub(A): + brap = A.b + assert ASub.brap.property is A.b.property + assert isinstance(ASub.brap.original_property, properties.SynonymProperty) + ASub(brap=B()) + + def test_alt_name_attr_subclass_column_attrset(self): + # [ticket:2900] + class A(Base): + __tablename__ = 'a' + id = Column('id', Integer, primary_key=True) + data = Column('data') + A.brap = A.data + assert A.brap.property is A.data.property + assert isinstance(A.brap.original_property, properties.SynonymProperty) + + def test_alt_name_attr_subclass_relationship_attrset(self): + # [ticket:2900] + class A(Base): + __tablename__ = 'a' + id = Column('id', Integer, primary_key=True) + b_id = Column(Integer, ForeignKey('b.id')) + b = relationship("B", backref="as_") + A.brap = A.b + class B(Base): + __tablename__ = 'b' + id = Column('id', Integer, primary_key=True) + + assert A.brap.property is A.b.property + assert isinstance(A.brap.original_property, properties.SynonymProperty) + A(brap=B()) + + def test_eager_order_by(self): class Address(Base, fixtures.ComparableEntity): @@ -1276,8 +1419,10 @@ class DeclarativeTest(DeclarativeTestBase): # case sa.orm.configure_mappers() - eq_(str(list(Address.user_id.property.columns[0].foreign_keys)[0]), - "ForeignKey('users.id')") + eq_( + list(Address.user_id.property.columns[0].foreign_keys)[0].column, + User.__table__.c.id + ) Base.metadata.create_all() u1 = User(name='u1', addresses=[Address(email='one'), Address(email='two')]) diff --git a/test/ext/declarative/test_reflection.py b/test/ext/declarative/test_reflection.py index 013439f93..f4bda6995 100644 --- a/test/ext/declarative/test_reflection.py +++ b/test/ext/declarative/test_reflection.py @@ -7,6 +7,8 @@ from sqlalchemy.orm import relationship, create_session, \ clear_mappers, \ Session from sqlalchemy.testing import fixtures +from sqlalchemy.testing.util import gc_collect +from sqlalchemy.ext.declarative.base import _DeferredMapperConfig class DeclarativeReflectionBase(fixtures.TablesTest): __requires__ = 'reflectable_autoincrement', @@ -47,9 +49,8 @@ class DeclarativeReflectionTest(DeclarativeReflectionBase): test_needs_fk=True, ) - def test_basic(self): - meta = MetaData(testing.db) + def test_basic(self): class User(Base, fixtures.ComparableEntity): __tablename__ = 'users' @@ -80,8 +81,6 @@ class DeclarativeReflectionTest(DeclarativeReflectionBase): eq_(a1.user, User(name='u1')) def test_rekey(self): - meta = MetaData(testing.db) - class User(Base, fixtures.ComparableEntity): __tablename__ = 'users' @@ -114,8 +113,6 @@ class DeclarativeReflectionTest(DeclarativeReflectionBase): assert_raises(TypeError, User, name='u3') def test_supplied_fk(self): - meta = MetaData(testing.db) - class IMHandle(Base, fixtures.ComparableEntity): __tablename__ = 'imhandles' @@ -151,9 +148,8 @@ class DeclarativeReflectionTest(DeclarativeReflectionBase): class DeferredReflectBase(DeclarativeReflectionBase): def teardown(self): - super(DeferredReflectBase,self).teardown() - from sqlalchemy.ext.declarative.base import _MapperConfig - _MapperConfig.configs.clear() + super(DeferredReflectBase, self).teardown() + _DeferredMapperConfig._configs.clear() Base = None @@ -275,7 +271,7 @@ class DeferredReflectionTest(DeferredReflectBase): @decl.declared_attr def __mapper_args__(cls): return { - "order_by":cls.__table__.c.name + "order_by": cls.__table__.c.name } decl.DeferredReflection.prepare(testing.db) @@ -297,6 +293,80 @@ class DeferredReflectionTest(DeferredReflectBase): ] ) + @testing.requires.predictable_gc + def test_cls_not_strong_ref(self): + class User(decl.DeferredReflection, fixtures.ComparableEntity, + Base): + __tablename__ = 'users' + class Address(decl.DeferredReflection, fixtures.ComparableEntity, + Base): + __tablename__ = 'addresses' + eq_(len(_DeferredMapperConfig._configs), 2) + del Address + gc_collect() + eq_(len(_DeferredMapperConfig._configs), 1) + decl.DeferredReflection.prepare(testing.db) + assert not _DeferredMapperConfig._configs + +class DeferredSecondaryReflectionTest(DeferredReflectBase): + @classmethod + def define_tables(cls, metadata): + Table('users', metadata, + Column('id', Integer, + primary_key=True, test_needs_autoincrement=True), + Column('name', String(50)), test_needs_fk=True) + + Table('user_items', metadata, + Column('user_id', ForeignKey('users.id'), primary_key=True), + Column('item_id', ForeignKey('items.id'), primary_key=True), + test_needs_fk=True + ) + + Table('items', metadata, + Column('id', Integer, primary_key=True, + test_needs_autoincrement=True), + Column('name', String(50)), + test_needs_fk=True + ) + + def _roundtrip(self): + + User = Base._decl_class_registry['User'] + Item = Base._decl_class_registry['Item'] + + u1 = User(name='u1', items=[Item(name='i1'), Item(name='i2')]) + + sess = Session() + sess.add(u1) + sess.commit() + + eq_(sess.query(User).all(), [User(name='u1', + items=[Item(name='i1'), Item(name='i2')])]) + + def test_string_resolution(self): + class User(decl.DeferredReflection, fixtures.ComparableEntity, Base): + __tablename__ = 'users' + + items = relationship("Item", secondary="user_items") + + class Item(decl.DeferredReflection, fixtures.ComparableEntity, Base): + __tablename__ = 'items' + + decl.DeferredReflection.prepare(testing.db) + self._roundtrip() + + def test_table_resolution(self): + class User(decl.DeferredReflection, fixtures.ComparableEntity, Base): + __tablename__ = 'users' + + items = relationship("Item", secondary=Table("user_items", Base.metadata)) + + class Item(decl.DeferredReflection, fixtures.ComparableEntity, Base): + __tablename__ = 'items' + + decl.DeferredReflection.prepare(testing.db) + self._roundtrip() + class DeferredInhReflectBase(DeferredReflectBase): def _roundtrip(self): Foo = Base._decl_class_registry['Foo'] @@ -338,11 +408,11 @@ class DeferredSingleInhReflectionTest(DeferredInhReflectBase): class Foo(decl.DeferredReflection, fixtures.ComparableEntity, Base): __tablename__ = 'foo' - __mapper_args__ = {"polymorphic_on":"type", - "polymorphic_identity":"foo"} + __mapper_args__ = {"polymorphic_on": "type", + "polymorphic_identity": "foo"} class Bar(Foo): - __mapper_args__ = {"polymorphic_identity":"bar"} + __mapper_args__ = {"polymorphic_identity": "bar"} decl.DeferredReflection.prepare(testing.db) self._roundtrip() @@ -351,11 +421,11 @@ class DeferredSingleInhReflectionTest(DeferredInhReflectBase): class Foo(decl.DeferredReflection, fixtures.ComparableEntity, Base): __tablename__ = 'foo' - __mapper_args__ = {"polymorphic_on":"type", - "polymorphic_identity":"foo"} + __mapper_args__ = {"polymorphic_on": "type", + "polymorphic_identity": "foo"} class Bar(Foo): - __mapper_args__ = {"polymorphic_identity":"bar"} + __mapper_args__ = {"polymorphic_identity": "bar"} bar_data = Column(String(30)) decl.DeferredReflection.prepare(testing.db) @@ -365,12 +435,12 @@ class DeferredSingleInhReflectionTest(DeferredInhReflectBase): class Foo(decl.DeferredReflection, fixtures.ComparableEntity, Base): __tablename__ = 'foo' - __mapper_args__ = {"polymorphic_on":"type", - "polymorphic_identity":"foo"} + __mapper_args__ = {"polymorphic_on": "type", + "polymorphic_identity": "foo"} id = Column(Integer, primary_key=True) class Bar(Foo): - __mapper_args__ = {"polymorphic_identity":"bar"} + __mapper_args__ = {"polymorphic_identity": "bar"} decl.DeferredReflection.prepare(testing.db) self._roundtrip() @@ -395,12 +465,12 @@ class DeferredJoinedInhReflectionTest(DeferredInhReflectBase): class Foo(decl.DeferredReflection, fixtures.ComparableEntity, Base): __tablename__ = 'foo' - __mapper_args__ = {"polymorphic_on":"type", - "polymorphic_identity":"foo"} + __mapper_args__ = {"polymorphic_on": "type", + "polymorphic_identity": "foo"} class Bar(Foo): __tablename__ = 'bar' - __mapper_args__ = {"polymorphic_identity":"bar"} + __mapper_args__ = {"polymorphic_identity": "bar"} decl.DeferredReflection.prepare(testing.db) self._roundtrip() @@ -409,12 +479,12 @@ class DeferredJoinedInhReflectionTest(DeferredInhReflectBase): class Foo(decl.DeferredReflection, fixtures.ComparableEntity, Base): __tablename__ = 'foo' - __mapper_args__ = {"polymorphic_on":"type", - "polymorphic_identity":"foo"} + __mapper_args__ = {"polymorphic_on": "type", + "polymorphic_identity": "foo"} class Bar(Foo): __tablename__ = 'bar' - __mapper_args__ = {"polymorphic_identity":"bar"} + __mapper_args__ = {"polymorphic_identity": "bar"} bar_data = Column(String(30)) decl.DeferredReflection.prepare(testing.db) @@ -424,13 +494,13 @@ class DeferredJoinedInhReflectionTest(DeferredInhReflectBase): class Foo(decl.DeferredReflection, fixtures.ComparableEntity, Base): __tablename__ = 'foo' - __mapper_args__ = {"polymorphic_on":"type", - "polymorphic_identity":"foo"} + __mapper_args__ = {"polymorphic_on": "type", + "polymorphic_identity": "foo"} id = Column(Integer, primary_key=True) class Bar(Foo): __tablename__ = 'bar' - __mapper_args__ = {"polymorphic_identity":"bar"} + __mapper_args__ = {"polymorphic_identity": "bar"} decl.DeferredReflection.prepare(testing.db) self._roundtrip() @@ -439,12 +509,12 @@ class DeferredJoinedInhReflectionTest(DeferredInhReflectBase): class Foo(decl.DeferredReflection, fixtures.ComparableEntity, Base): __tablename__ = 'foo' - __mapper_args__ = {"polymorphic_on":"type", - "polymorphic_identity":"foo"} + __mapper_args__ = {"polymorphic_on": "type", + "polymorphic_identity": "foo"} class Bar(Foo): __tablename__ = 'bar' - __mapper_args__ = {"polymorphic_identity":"bar"} + __mapper_args__ = {"polymorphic_identity": "bar"} id = Column(Integer, ForeignKey('foo.id'), primary_key=True) decl.DeferredReflection.prepare(testing.db) diff --git a/test/ext/test_associationproxy.py b/test/ext/test_associationproxy.py index 4cfb58481..3450eeb2f 100644 --- a/test/ext/test_associationproxy.py +++ b/test/ext/test_associationproxy.py @@ -9,7 +9,6 @@ from sqlalchemy.ext.associationproxy import * from sqlalchemy.ext.associationproxy import _AssociationList from sqlalchemy.testing import assert_raises_message from sqlalchemy.testing.util import gc_collect -from sqlalchemy.sql import not_ from sqlalchemy.testing import fixtures, AssertsCompiledSQL from sqlalchemy import testing from sqlalchemy.testing.schema import Table, Column @@ -139,7 +138,7 @@ class _CollectionOperations(fixtures.TestBase): self.assert_(len(p1._children) == 0) self.assert_(len(p1.children) == 0) - p1.children = ['a','b','c'] + p1.children = ['a', 'b', 'c'] self.assert_(len(p1._children) == 3) self.assert_(len(p1.children) == 3) @@ -324,7 +323,7 @@ class CustomDictTest(DictTest): self.assert_(len(p1._children) == 3) self.assert_(len(p1.children) == 3) - self.assert_(set(p1.children) == set(['d','e','f'])) + self.assert_(set(p1.children) == set(['d', 'e', 'f'])) del ch p1 = self.roundtrip(p1) @@ -407,7 +406,7 @@ class SetTest(_CollectionOperations): self.assert_(len(p1._children) == 0) self.assert_(len(p1.children) == 0) - p1.children = ['a','b','c'] + p1.children = ['a', 'b', 'c'] self.assert_(len(p1._children) == 3) self.assert_(len(p1.children) == 3) @@ -421,13 +420,12 @@ class SetTest(_CollectionOperations): self.assert_('b' in p1.children) self.assert_('d' not in p1.children) - self.assert_(p1.children == set(['a','b','c'])) + self.assert_(p1.children == set(['a', 'b', 'c'])) - try: - p1.children.remove('d') - self.fail() - except KeyError: - pass + assert_raises( + KeyError, + p1.children.remove, "d" + ) self.assert_(len(p1.children) == 3) p1.children.discard('d') @@ -442,9 +440,9 @@ class SetTest(_CollectionOperations): self.assert_(len(p1.children) == 2) self.assert_(popped not in p1.children) - p1.children = ['a','b','c'] + p1.children = ['a', 'b', 'c'] p1 = self.roundtrip(p1) - self.assert_(p1.children == set(['a','b','c'])) + self.assert_(p1.children == set(['a', 'b', 'c'])) p1.children.discard('b') p1 = self.roundtrip(p1) @@ -476,12 +474,12 @@ class SetTest(_CollectionOperations): Parent, Child = self.Parent, self.Child p1 = Parent('P1') - p1.children = ['a','b','c'] - control = set(['a','b','c']) + p1.children = ['a', 'b', 'c'] + control = set(['a', 'b', 'c']) - for other in (set(['a','b','c']), set(['a','b','c','d']), - set(['a']), set(['a','b']), - set(['c','d']), set(['e', 'f', 'g']), + for other in (set(['a', 'b', 'c']), set(['a', 'b', 'c', 'd']), + set(['a']), set(['a', 'b']), + set(['c', 'd']), set(['e', 'f', 'g']), set()): eq_(p1.children.union(other), @@ -499,12 +497,12 @@ class SetTest(_CollectionOperations): eq_(p1.children.issuperset(other), control.issuperset(other)) - self.assert_((p1.children == other) == (control == other)) - self.assert_((p1.children != other) == (control != other)) - self.assert_((p1.children < other) == (control < other)) - self.assert_((p1.children <= other) == (control <= other)) - self.assert_((p1.children > other) == (control > other)) - self.assert_((p1.children >= other) == (control >= other)) + self.assert_((p1.children == other) == (control == other)) + self.assert_((p1.children != other) == (control != other)) + self.assert_((p1.children < other) == (control < other)) + self.assert_((p1.children <= other) == (control <= other)) + self.assert_((p1.children > other) == (control > other)) + self.assert_((p1.children >= other) == (control >= other)) def test_set_mutation(self): Parent, Child = self.Parent, self.Child @@ -513,9 +511,9 @@ class SetTest(_CollectionOperations): for op in ('update', 'intersection_update', 'difference_update', 'symmetric_difference_update'): for base in (['a', 'b', 'c'], []): - for other in (set(['a','b','c']), set(['a','b','c','d']), - set(['a']), set(['a','b']), - set(['c','d']), set(['e', 'f', 'g']), + for other in (set(['a', 'b', 'c']), set(['a', 'b', 'c', 'd']), + set(['a']), set(['a', 'b']), + set(['c', 'd']), set(['e', 'f', 'g']), set()): p = Parent('p') p.children = base[:] @@ -544,9 +542,9 @@ class SetTest(_CollectionOperations): # in-place mutations for op in ('|=', '-=', '&=', '^='): for base in (['a', 'b', 'c'], []): - for other in (set(['a','b','c']), set(['a','b','c','d']), - set(['a']), set(['a','b']), - set(['c','d']), set(['e', 'f', 'g']), + for other in (set(['a', 'b', 'c']), set(['a', 'b', 'c', 'd']), + set(['a']), set(['a', 'b']), + set(['c', 'd']), set(['e', 'f', 'g']), frozenset(['e', 'f', 'g']), set()): p = Parent('p') @@ -599,12 +597,11 @@ class CustomObjectTest(_CollectionOperations): # We didn't provide an alternate _AssociationList implementation # for our ObjectCollection, so indexing will fail. + assert_raises( + TypeError, + p.children.__getitem__, 1 + ) - try: - v = p.children[1] - self.fail() - except TypeError: - pass class ProxyFactoryTest(ListTest): def setup(self): @@ -669,8 +666,9 @@ class ProxyFactoryTest(ListTest): class ScalarTest(fixtures.TestBase): + @testing.provide_metadata def test_scalar_proxy(self): - metadata = MetaData(testing.db) + metadata = self.metadata parents_table = Table('Parent', metadata, Column('id', Integer, primary_key=True, @@ -718,12 +716,8 @@ class ScalarTest(fixtures.TestBase): p = Parent('p') - # No child - try: - v = p.foo - self.fail() - except: - pass + eq_(p.child, None) + eq_(p.foo, None) p.child = Child(foo='a', bar='b', baz='c') @@ -744,19 +738,13 @@ class ScalarTest(fixtures.TestBase): p.child = None - # No child again - try: - v = p.foo - self.fail() - except: - pass + eq_(p.foo, None) # Bogus creator for this scalar type - try: - p.foo = 'zzz' - self.fail() - except TypeError: - pass + assert_raises( + TypeError, + setattr, p, "foo", "zzz" + ) p.bar = 'yyy' @@ -786,6 +774,48 @@ class ScalarTest(fixtures.TestBase): p2 = Parent('p2') p2.bar = 'quux' + @testing.provide_metadata + def test_empty_scalars(self): + metadata = self.metadata + + a = Table('a', metadata, + Column('id', Integer, primary_key=True), + Column('name', String(50)) + ) + a2b = Table('a2b', metadata, + Column('id', Integer, primary_key=True), + Column('id_a', Integer, ForeignKey('a.id')), + Column('id_b', Integer, ForeignKey('b.id')), + Column('name', String(50)) + ) + b = Table('b', metadata, + Column('id', Integer, primary_key=True), + Column('name', String(50)) + ) + class A(object): + a2b_name = association_proxy("a2b_single", "name") + b_single = association_proxy("a2b_single", "b") + + class A2B(object): + pass + + class B(object): + pass + + mapper(A, a, properties=dict( + a2b_single=relationship(A2B, uselist=False) + )) + + mapper(A2B, a2b, properties=dict( + b=relationship(B) + )) + mapper(B, b) + + a1 = A() + assert a1.a2b_name is None + assert a1.b_single is None + + class LazyLoadTest(fixtures.TestBase): def setup(self): @@ -840,7 +870,7 @@ class LazyLoadTest(fixtures.TestBase): collection_class=list)}) p = Parent('p') - p.children = ['a','b','c'] + p.children = ['a', 'b', 'c'] p = self.roundtrip(p) @@ -858,7 +888,7 @@ class LazyLoadTest(fixtures.TestBase): collection_class=list)}) p = Parent('p') - p.children = ['a','b','c'] + p.children = ['a', 'b', 'c'] p = self.roundtrip(p) @@ -1024,7 +1054,7 @@ class ComparatorTest(fixtures.MappedTest, AssertsCompiledSQL): @classmethod def define_tables(cls, metadata): Table('userkeywords', metadata, - Column('keyword_id', Integer,ForeignKey('keywords.id'), primary_key=True), + Column('keyword_id', Integer, ForeignKey('keywords.id'), primary_key=True), Column('user_id', Integer, ForeignKey('users.id')) ) Table('users', metadata, @@ -1094,15 +1124,15 @@ class ComparatorTest(fixtures.MappedTest, AssertsCompiledSQL): cls.classes.Singular) mapper(User, users, properties={ - 'singular':relationship(Singular) + 'singular': relationship(Singular) }) mapper(Keyword, keywords, properties={ - 'user_keyword':relationship(UserKeyword, uselist=False) + 'user_keyword': relationship(UserKeyword, uselist=False) }) mapper(UserKeyword, userkeywords, properties={ - 'user' : relationship(User, backref='user_keywords'), - 'keyword' : relationship(Keyword) + 'user': relationship(User, backref='user_keywords'), + 'keyword': relationship(Keyword) }) mapper(Singular, singular, properties={ 'keywords': relationship(Keyword) @@ -1300,7 +1330,7 @@ class ComparatorTest(fixtures.MappedTest, AssertsCompiledSQL): self.session.query(User).filter(User.singular_value == None), self.session.query(User).filter( or_( - User.singular.has(Singular.value==None), + User.singular.has(Singular.value == None), User.singular == None ) ) @@ -1324,7 +1354,7 @@ class ComparatorTest(fixtures.MappedTest, AssertsCompiledSQL): self._equivalent( self.session.query(User).filter(User.singular_value == "singular4"), self.session.query(User).filter( - User.singular.has(Singular.value=="singular4"), + User.singular.has(Singular.value == "singular4"), ) ) @@ -1343,7 +1373,7 @@ class ComparatorTest(fixtures.MappedTest, AssertsCompiledSQL): # a special case where we provide an empty has() on a # non-object-targeted association proxy. User = self.classes.User - Singular = self.classes.Singular + self.classes.Singular self._equivalent( self.session.query(User).filter(User.singular_value.has()), @@ -1356,7 +1386,7 @@ class ComparatorTest(fixtures.MappedTest, AssertsCompiledSQL): # a special case where we provide an empty has() on a # non-object-targeted association proxy. User = self.classes.User - Singular = self.classes.Singular + self.classes.Singular self._equivalent( self.session.query(User).filter(~User.singular_value.has()), @@ -1368,7 +1398,7 @@ class ComparatorTest(fixtures.MappedTest, AssertsCompiledSQL): def test_has_criterion_nul(self): # but we don't allow that with any criterion... User = self.classes.User - Singular = self.classes.Singular + self.classes.Singular assert_raises_message( exc.ArgumentError, @@ -1380,7 +1410,7 @@ class ComparatorTest(fixtures.MappedTest, AssertsCompiledSQL): def test_has_kwargs_nul(self): # ... or kwargs User = self.classes.User - Singular = self.classes.Singular + self.classes.Singular assert_raises_message( exc.ArgumentError, @@ -1391,32 +1421,32 @@ class ComparatorTest(fixtures.MappedTest, AssertsCompiledSQL): def test_filter_scalar_contains_fails_nul_nul(self): Keyword = self.classes.Keyword - assert_raises(exc.InvalidRequestError, lambda : \ - Keyword.user.contains(self.u)) + assert_raises(exc.InvalidRequestError, + lambda: Keyword.user.contains(self.u)) def test_filter_scalar_any_fails_nul_nul(self): Keyword = self.classes.Keyword - assert_raises(exc.InvalidRequestError, lambda : \ - Keyword.user.any(name='user2')) + assert_raises(exc.InvalidRequestError, + lambda: Keyword.user.any(name='user2')) def test_filter_collection_has_fails_ul_nul(self): User = self.classes.User - assert_raises(exc.InvalidRequestError, lambda : \ - User.keywords.has(keyword='quick')) + assert_raises(exc.InvalidRequestError, + lambda: User.keywords.has(keyword='quick')) def test_filter_collection_eq_fails_ul_nul(self): User = self.classes.User - assert_raises(exc.InvalidRequestError, lambda : \ - User.keywords == self.kw) + assert_raises(exc.InvalidRequestError, + lambda: User.keywords == self.kw) def test_filter_collection_ne_fails_ul_nul(self): User = self.classes.User - assert_raises(exc.InvalidRequestError, lambda : \ - User.keywords != self.kw) + assert_raises(exc.InvalidRequestError, + lambda: User.keywords != self.kw) def test_join_separate_attr(self): User = self.classes.User @@ -1458,7 +1488,7 @@ class DictOfTupleUpdateTest(fixtures.TestBase): b = Table('b', m, Column('id', Integer, primary_key=True), Column('aid', Integer, ForeignKey('a.id'))) mapper(A, a, properties={ - 'orig':relationship(B, collection_class=attribute_mapped_collection('key')) + 'orig': relationship(B, collection_class=attribute_mapped_collection('key')) }) mapper(B, b) self.A = A @@ -1467,22 +1497,22 @@ class DictOfTupleUpdateTest(fixtures.TestBase): def test_update_one_elem_dict(self): a1 = self.A() a1.elements.update({("B", 3): 'elem2'}) - eq_(a1.elements, {("B",3):'elem2'}) + eq_(a1.elements, {("B", 3): 'elem2'}) def test_update_multi_elem_dict(self): a1 = self.A() a1.elements.update({("B", 3): 'elem2', ("C", 4): "elem3"}) - eq_(a1.elements, {("B",3):'elem2', ("C", 4): "elem3"}) + eq_(a1.elements, {("B", 3): 'elem2', ("C", 4): "elem3"}) def test_update_one_elem_list(self): a1 = self.A() a1.elements.update([(("B", 3), 'elem2')]) - eq_(a1.elements, {("B",3):'elem2'}) + eq_(a1.elements, {("B", 3): 'elem2'}) def test_update_multi_elem_list(self): a1 = self.A() a1.elements.update([(("B", 3), 'elem2'), (("C", 4), "elem3")]) - eq_(a1.elements, {("B",3):'elem2', ("C", 4): "elem3"}) + eq_(a1.elements, {("B", 3): 'elem2', ("C", 4): "elem3"}) def test_update_one_elem_varg(self): a1 = self.A() diff --git a/test/ext/test_automap.py b/test/ext/test_automap.py new file mode 100644 index 000000000..9db85879d --- /dev/null +++ b/test/ext/test_automap.py @@ -0,0 +1,146 @@ +from sqlalchemy.testing import fixtures, eq_ +from ..orm._fixtures import FixtureTest +from sqlalchemy.ext.automap import automap_base +from sqlalchemy.orm import relationship, interfaces, backref +from sqlalchemy.ext.automap import generate_relationship +from sqlalchemy.testing.mock import Mock, call + +class AutomapTest(fixtures.MappedTest): + @classmethod + def define_tables(cls, metadata): + FixtureTest.define_tables(metadata) + + def test_relationship_o2m_default(self): + Base = automap_base(metadata=self.metadata) + Base.prepare() + + User = Base.classes.users + Address = Base.classes.addresses + + a1 = Address(email_address='e1') + u1 = User(name='u1', addresses_collection=[a1]) + assert a1.users is u1 + + def test_relationship_explicit_override_o2m(self): + Base = automap_base(metadata=self.metadata) + prop = relationship("addresses", collection_class=set) + class User(Base): + __tablename__ = 'users' + + addresses_collection = prop + + Base.prepare() + assert User.addresses_collection.property is prop + Address = Base.classes.addresses + + a1 = Address(email_address='e1') + u1 = User(name='u1', addresses_collection=set([a1])) + assert a1.user is u1 + + def test_relationship_explicit_override_m2o(self): + Base = automap_base(metadata=self.metadata) + + prop = relationship("users") + class Address(Base): + __tablename__ = 'addresses' + + users = prop + + Base.prepare() + User = Base.classes.users + + assert Address.users.property is prop + a1 = Address(email_address='e1') + u1 = User(name='u1', address_collection=[a1]) + assert a1.users is u1 + + + def test_relationship_self_referential(self): + Base = automap_base(metadata=self.metadata) + Base.prepare() + + Node = Base.classes.nodes + + n1 = Node() + n2 = Node() + n1.nodes_collection.append(n2) + assert n2.nodes is n1 + + def test_naming_schemes(self): + Base = automap_base(metadata=self.metadata) + + def classname_for_table(base, tablename, table): + return str("cls_" + tablename) + + def name_for_scalar_relationship(base, local_cls, referred_cls, constraint): + return "scalar_" + referred_cls.__name__ + + def name_for_collection_relationship(base, local_cls, referred_cls, constraint): + return "coll_" + referred_cls.__name__ + + Base.prepare( + classname_for_table=classname_for_table, + name_for_scalar_relationship=name_for_scalar_relationship, + name_for_collection_relationship=name_for_collection_relationship + ) + + User = Base.classes.cls_users + Address = Base.classes.cls_addresses + + u1 = User() + a1 = Address() + u1.coll_cls_addresses.append(a1) + assert a1.scalar_cls_users is u1 + + def test_relationship_m2m(self): + Base = automap_base(metadata=self.metadata) + + Base.prepare() + + Order, Item = Base.classes.orders, Base.classes['items'] + + o1 = Order() + i1 = Item() + o1.items_collection.append(i1) + assert o1 in i1.orders_collection + + def test_relationship_explicit_override_forwards_m2m(self): + Base = automap_base(metadata=self.metadata) + + class Order(Base): + __tablename__ = 'orders' + + items_collection = relationship("items", + secondary="order_items", + collection_class=set) + Base.prepare() + + Item = Base.classes['items'] + + o1 = Order() + i1 = Item() + o1.items_collection.add(i1) + + # it's 'order_collection' because the class name is + # "Order" ! + assert isinstance(i1.order_collection, list) + assert o1 in i1.order_collection + + def test_relationship_pass_params(self): + Base = automap_base(metadata=self.metadata) + + mock = Mock() + def _gen_relationship(base, direction, return_fn, attrname, + local_cls, referred_cls, **kw): + mock(base, direction, attrname) + return generate_relationship(base, direction, return_fn, + attrname, local_cls, referred_cls, **kw) + + Base.prepare(generate_relationship=_gen_relationship) + assert set(tuple(c[1]) for c in mock.mock_calls).issuperset([ + (Base, interfaces.MANYTOONE, "nodes"), + (Base, interfaces.MANYTOMANY, "keywords_collection"), + (Base, interfaces.MANYTOMANY, "items_collection"), + (Base, interfaces.MANYTOONE, "users"), + (Base, interfaces.ONETOMANY, "addresses_collection"), + ]) diff --git a/test/ext/test_compiler.py b/test/ext/test_compiler.py index c1f8b6258..5ed50442f 100644 --- a/test/ext/test_compiler.py +++ b/test/ext/test_compiler.py @@ -4,7 +4,7 @@ from sqlalchemy.sql.expression import ClauseElement, ColumnClause,\ FunctionElement, Select, \ BindParameter -from sqlalchemy.schema import DDLElement +from sqlalchemy.schema import DDLElement, CreateColumn, CreateTable from sqlalchemy.ext.compiler import compiles, deregister from sqlalchemy import exc from sqlalchemy.sql import table, column, visitors @@ -34,6 +34,22 @@ class UserDefinedTest(fixtures.TestBase, AssertsCompiledSQL): "SELECT >>x<<, >>y<< WHERE >>MYTHINGY!<< = :MYTHINGY!_1" ) + def test_create_column_skip(self): + @compiles(CreateColumn) + def skip_xmin(element, compiler, **kw): + if element.element.name == 'xmin': + return None + else: + return compiler.visit_create_column(element, **kw) + + t = Table('t', MetaData(), Column('a', Integer), + Column('xmin', Integer), + Column('c', Integer)) + + self.assert_compile( + CreateTable(t), + "CREATE TABLE t (a INTEGER, c INTEGER)" + ) def test_types(self): class MyType(TypeEngine): pass diff --git a/test/ext/test_extendedattr.py b/test/ext/test_extendedattr.py index a550ae4d0..7a733696a 100644 --- a/test/ext/test_extendedattr.py +++ b/test/ext/test_extendedattr.py @@ -61,6 +61,8 @@ class MyTypesManager(instrumentation.InstrumentationManager): class MyListLike(list): # add @appender, @remover decorators as needed _sa_iterator = list.__iter__ + _sa_linker = None + _sa_converter = None def _sa_appender(self, item, _sa_initiator=None): if _sa_initiator is not False: self._sa_adapter.fire_append_event(item, _sa_initiator) diff --git a/test/ext/test_mutable.py b/test/ext/test_mutable.py index 25c182f1d..ee1b8075e 100644 --- a/test/ext/test_mutable.py +++ b/test/ext/test_mutable.py @@ -153,9 +153,6 @@ class MutableWithScalarPickleTest(_MutableDictTestBase, fixtures.MappedTest): self._test_non_mutable() class MutableWithScalarJSONTest(_MutableDictTestBase, fixtures.MappedTest): - # json introduced in 2.6 - __skip_if__ = lambda: sys.version_info < (2, 6), - @classmethod def define_tables(cls, metadata): import json @@ -245,9 +242,6 @@ class MutableAssociationScalarPickleTest(_MutableDictTestBase, fixtures.MappedTe ) class MutableAssociationScalarJSONTest(_MutableDictTestBase, fixtures.MappedTest): - # json introduced in 2.6 - __skip_if__ = lambda: sys.version_info < (2, 6), - @classmethod def define_tables(cls, metadata): import json diff --git a/test/ext/test_serializer.py b/test/ext/test_serializer.py index 84fff1304..ffeac55c1 100644 --- a/test/ext/test_serializer.py +++ b/test/ext/test_serializer.py @@ -1,13 +1,15 @@ +# coding: utf-8 from sqlalchemy.ext import serializer from sqlalchemy import testing from sqlalchemy import Integer, String, ForeignKey, select, \ - desc, func, util + desc, func, util, MetaData from sqlalchemy.testing.schema import Table from sqlalchemy.testing.schema import Column from sqlalchemy.orm import relationship, sessionmaker, scoped_session, \ class_mapper, mapper, joinedload, configure_mappers, aliased -from sqlalchemy.testing import eq_ +from sqlalchemy.testing import eq_, AssertsCompiledSQL +from sqlalchemy.util import u, ue from sqlalchemy.testing import fixtures @@ -19,7 +21,7 @@ class Address(fixtures.ComparableEntity): users = addresses = Session = None -class SerializeTest(fixtures.MappedTest): +class SerializeTest(AssertsCompiledSQL, fixtures.MappedTest): run_setup_mappers = 'once' run_inserts = 'once' @@ -77,7 +79,6 @@ class SerializeTest(fixtures.MappedTest): assert serializer.loads(serializer.dumps(User.name, -1), None, None) is User.name - @testing.requires.python26 # crashes in 2.5 def test_expression(self): expr = \ select([users]).select_from(users.join(addresses)).limit(5) @@ -124,19 +125,20 @@ class SerializeTest(fixtures.MappedTest): eq_(q2.all(), [User(name='fred')]) eq_(list(q2.values(User.id, User.name)), [(9, 'fred')]) - @testing.requires.non_broken_pickle - def test_query_three(self): - ua = aliased(User) - q = \ - Session.query(ua).join(ua.addresses).\ - filter(Address.email.like('%fred%')) - q2 = serializer.loads(serializer.dumps(q, -1), users.metadata, - Session) - eq_(q2.all(), [User(name='fred')]) - + # fails too often/randomly + #@testing.requires.non_broken_pickle + #def test_query_three(self): + # ua = aliased(User) + # q = \ + # Session.query(ua).join(ua.addresses).\ + # filter(Address.email.like('%fred%')) + # q2 = serializer.loads(serializer.dumps(q, -1), users.metadata, + # Session) + # eq_(q2.all(), [User(name='fred')]) + # # try to pull out the aliased entity here... - ua_2 = q2._entities[0].entity_zero.entity - eq_(list(q2.values(ua_2.id, ua_2.name)), [(9, 'fred')]) + # ua_2 = q2._entities[0].entity_zero.entity + # eq_(list(q2.values(ua_2.id, ua_2.name)), [(9, 'fred')]) @testing.requires.non_broken_pickle def test_orm_join(self): @@ -149,7 +151,6 @@ class SerializeTest(fixtures.MappedTest): assert j2.right is j.right assert j2._target_adapter._next - @testing.requires.python26 # namedtuple workaround not serializable in 2.5 @testing.exclude('sqlite', '<=', (3, 5, 9), 'id comparison failing on the buildbot') def test_aliases(self): @@ -172,6 +173,22 @@ class SerializeTest(fixtures.MappedTest): x = serializer.loads(ser, users.metadata) eq_(str(r), str(x)) + def test_unicode(self): + m = MetaData() + t = Table(ue('\u6e2c\u8a66'), m, + Column(ue('\u6e2c\u8a66_id'), Integer)) + + expr = select([t]).where(t.c[ue('\u6e2c\u8a66_id')] == 5) + + expr2 = serializer.loads(serializer.dumps(expr, -1), m) + + self.assert_compile( + expr2, + ue('SELECT "\u6e2c\u8a66"."\u6e2c\u8a66_id" FROM "\u6e2c\u8a66" ' + 'WHERE "\u6e2c\u8a66"."\u6e2c\u8a66_id" = :\u6e2c\u8a66_id_1'), + dialect="default" + ) + if __name__ == '__main__': testing.main() |
