]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- adding in requirements
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 7 Feb 2013 00:06:09 +0000 (19:06 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 7 Feb 2013 00:06:09 +0000 (19:06 -0500)
- get test_naturalpks to be more generalized

lib/sqlalchemy/testing/exclusions.py
lib/sqlalchemy/testing/requirements.py
lib/sqlalchemy/testing/suite/test_reflection.py
lib/sqlalchemy/testing/suite/test_types.py
test/engine/test_reflection.py
test/orm/test_naturalpks.py
test/orm/test_query.py
test/requirements.py

index f105c8b6a2267780e202ac9c04eafb6760f28505..2c0679e1d3dfce385f5e408ef91e0b4159024df4 100644 (file)
@@ -84,7 +84,9 @@ def succeeds_if(predicate, reason=None):
 class Predicate(object):
     @classmethod
     def as_predicate(cls, predicate):
-        if isinstance(predicate, Predicate):
+        if isinstance(predicate, skip_if):
+            return predicate.predicate
+        elif isinstance(predicate, Predicate):
             return predicate
         elif isinstance(predicate, list):
             return OrPredicate([cls.as_predicate(pred) for pred in predicate])
index 7228f38f9e132b271eb8a764da5b83378bcc2f5a..e6e21d2cb70b703f167514ec268f4253a8bb154c 100644 (file)
@@ -39,6 +39,27 @@ class SuiteRequirements(Requirements):
 
         return exclusions.open()
 
+    @property
+    def on_update_cascade(self):
+        """"target database must support ON UPDATE..CASCADE behavior in
+        foreign keys."""
+
+        return exclusions.open()
+
+    @property
+    def deferrable_fks(self):
+        return exclusions.closed()
+
+    @property
+    def on_update_or_deferrable_fks(self):
+        # TODO: exclusions should be composable,
+        # somehow only_if([x, y]) isn't working here, negation/conjunctions
+        # getting confused.
+        return exclusions.only_if(
+                    lambda: self.on_update_cascade.enabled or self.deferrable_fks.enabled
+                )
+
+
     @property
     def self_referential_foreign_keys(self):
         """Target database must support self-referential foreign keys."""
@@ -253,6 +274,11 @@ class SuiteRequirements(Requirements):
         """
         return exclusions.open()
 
+    @property
+    def unicode_ddl(self):
+        """Target driver must support some degree of non-ascii symbol names."""
+        return exclusions.closed()
+
     @property
     def datetime(self):
         """target dialect supports representation of Python
@@ -349,3 +375,19 @@ class SuiteRequirements(Requirements):
         """target database must use a plain percent '%' as the 'modulus'
         operator."""
         return exclusions.closed()
+
+    @property
+    def unicode_connections(self):
+        """Target driver must support non-ASCII characters being passed at all."""
+        return exclusions.open()
+
+    @property
+    def skip_mysql_on_windows(self):
+        """Catchall for a large variety of MySQL on Windows failures"""
+        return exclusions.open()
+
+    def _has_mysql_on_windows(self):
+        return False
+
+    def _has_mysql_fully_case_sensitive(self):
+        return False
index 89e233295e1603c7f0676307ce9151ece1af9618..5beed6aad78feae5839f61cbd2876386210c1a04 100644 (file)
@@ -218,6 +218,9 @@ class ComponentReflectionTest(fixtures.TablesTest):
                     ])) > 0, '%s(%s), %s(%s)' % (col.name,
                             col.type, cols[i]['name'], ctype))
 
+                if not col.primary_key:
+                    assert cols[i]['default'] is None
+
     @testing.requires.table_reflection
     def test_get_columns(self):
         self._test_get_columns()
@@ -386,5 +389,32 @@ class ComponentReflectionTest(fixtures.TablesTest):
     def test_get_table_oid_with_schema(self):
         self._test_get_table_oid('users', schema='test_schema')
 
+    @testing.provide_metadata
+    def test_autoincrement_col(self):
+        """test that 'autoincrement' is reflected according to sqla's policy.
+
+        Don't mark this test as unsupported for any backend !
+
+        (technically it fails with MySQL InnoDB since "id" comes before "id2")
+
+        A backend is better off not returning "autoincrement" at all,
+        instead of potentially returning "False" for an auto-incrementing
+        primary key column.
+
+        """
+
+        meta = self.metadata
+        insp = inspect(meta.bind)
+
+        for tname, cname in [
+                ('users', 'user_id'),
+                ('email_addresses', 'address_id'),
+                ('dingalings', 'dingaling_id'),
+            ]:
+            cols = insp.get_columns(tname)
+            id_ = dict((c['name'], c) for c in cols)[cname]
+            assert id_.get('autoincrement', True)
+
+
 
 __all__ = ('ComponentReflectionTest', 'HasTableTest')
index 8d0500d71d5d41188f252321012e1199abfe697e..5ad26c2f2fb6ee0765959de1876b5eb64227131d 100644 (file)
@@ -4,7 +4,7 @@ from .. import fixtures, config
 from ..assertions import eq_
 from ..config import requirements
 from sqlalchemy import Integer, Unicode, UnicodeText, select
-from sqlalchemy import Date, DateTime, Time, MetaData, String
+from sqlalchemy import Date, DateTime, Time, MetaData, String, Text
 from ..schema import Table, Column
 import datetime
 
@@ -103,6 +103,39 @@ class UnicodeTextTest(_UnicodeFixture, fixtures.TablesTest):
     def test_empty_strings_text(self):
         self._test_empty_strings()
 
+class TextTest(fixtures.TablesTest):
+    @classmethod
+    def define_tables(cls, metadata):
+        Table('text_table', metadata,
+            Column('id', Integer, primary_key=True,
+                        test_needs_autoincrement=True),
+            Column('text_data', Text),
+            )
+
+    def test_text_roundtrip(self):
+        text_table = self.tables.text_table
+
+        config.db.execute(
+            text_table.insert(),
+            {"text_data": 'some text'}
+        )
+        row = config.db.execute(
+                    select([text_table.c.text_data])
+                ).first()
+        eq_(row, ('some text',))
+
+    def test_text_empty_strings(self):
+        text_table = self.tables.text_table
+
+        config.db.execute(
+            text_table.insert(),
+            {"text_data": ''}
+        )
+        row = config.db.execute(
+                    select([text_table.c.text_data])
+                ).first()
+        eq_(row, ('',))
+
 
 class StringTest(fixtures.TestBase):
     @requirements.unbounded_varchar
@@ -212,7 +245,7 @@ class DateHistoricTest(_DateFixture, fixtures.TablesTest):
 
 
 __all__ = ('UnicodeVarcharTest', 'UnicodeTextTest',
-            'DateTest', 'DateTimeTest',
+            'DateTest', 'DateTimeTest', 'TextTest',
             'DateTimeHistoricTest', 'DateTimeCoercedToDateTimeTest',
             'TimeMicrosecondsTest', 'TimeTest', 'DateTimeMicrosecondsTest',
             'DateHistoricTest', 'StringTest')
index 2ff3140a56e38435541d95bec2773fa30483a750..86df929873ae14de62a11da46e6a36a35d77a92f 100644 (file)
@@ -645,8 +645,8 @@ class ReflectionTest(fixtures.TestBase, ComparesTables):
             id INTEGER NOT NULL,
             isbn VARCHAR(50) NOT NULL,
             title VARCHAR(100) NOT NULL,
-            series INTEGER,
-            series_id INTEGER,
+            series INTEGER NOT NULL,
+            series_id INTEGER NOT NULL,
             UNIQUE(series, series_id),
             PRIMARY KEY(id, isbn)
         )""")
@@ -1060,7 +1060,7 @@ class UnicodeReflectionTest(fixtures.TestBase):
         # are really limited unless you're on PG or SQLite
 
         # forget about it on these backends
-        if testing.against('sybase', 'maxdb', 'oracle'):
+        if not testing.requires.unicode_ddl.enabled:
             names = no_multibyte_period
         # mysql can't handle casing usually
         elif testing.against("mysql") and \
index 9ad54fd10c1051235b6f0ce2f7717f46c32f4c45..d30cdc598948539c46816d5559d99941050e038e 100644 (file)
@@ -15,17 +15,23 @@ from sqlalchemy.testing import eq_
 from sqlalchemy.testing import fixtures
 from test.orm import _fixtures
 
+def _backend_specific_fk_args():
+    if testing.requires.deferrable_fks.enabled:
+        fk_args = dict(deferrable=True, initially='deferred')
+    elif not testing.requires.on_update_cascade.enabled:
+        fk_args = dict()
+    else:
+        fk_args = dict(onupdate='cascade')
+    return fk_args
+
 class NaturalPKTest(fixtures.MappedTest):
     # MySQL 5.5 on Windows crashes (the entire server, not the client)
     # if you screw around with ON UPDATE CASCADE type of stuff.
-    __requires__ = 'skip_mysql_on_windows',
+    __requires__ = 'skip_mysql_on_windows', 'on_update_or_deferrable_fks'
 
     @classmethod
     def define_tables(cls, metadata):
-        if testing.against('oracle'):
-            fk_args = dict(deferrable=True, initially='deferred')
-        else:
-            fk_args = dict(onupdate='cascade')
+        fk_args = _backend_specific_fk_args()
 
         users = Table('users', metadata,
             Column('username', String(50), primary_key=True),
@@ -128,8 +134,7 @@ class NaturalPKTest(fixtures.MappedTest):
         assert sess.query(User).get('ed').fullname == 'jack'
 
 
-    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
-    @testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
+    @testing.requires.on_update_cascade
     def test_onetomany_passive(self):
         self._test_onetomany(True)
 
@@ -190,8 +195,7 @@ class NaturalPKTest(fixtures.MappedTest):
         u1 = sess.query(User).get('fred')
         eq_(User(username='fred', fullname='jack'), u1)
 
-    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
-    @testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
+    @testing.requires.on_update_cascade
     def test_manytoone_passive(self):
         self._test_manytoone(True)
 
@@ -276,8 +280,7 @@ class NaturalPKTest(fixtures.MappedTest):
                 sess.query(Address).all())
 
 
-    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
-    @testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
+    @testing.requires.on_update_cascade
     def test_onetoone_passive(self):
         self._test_onetoone(True)
 
@@ -323,8 +326,7 @@ class NaturalPKTest(fixtures.MappedTest):
         sess.expunge_all()
         eq_([Address(username='ed')], sess.query(Address).all())
 
-    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
-    @testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
+    @testing.requires.on_update_cascade
     def test_bidirectional_passive(self):
         self._test_bidirectional(True)
 
@@ -339,7 +341,7 @@ class NaturalPKTest(fixtures.MappedTest):
 
         mapper(User, users)
         mapper(Address, addresses, properties={
-            'user':relationship(User, passive_updates=passive_updates,
+            'user': relationship(User, passive_updates=passive_updates,
                             backref='addresses')})
 
         sess = create_session()
@@ -382,8 +384,7 @@ class NaturalPKTest(fixtures.MappedTest):
                         sess.query(Address).all())
 
 
-    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
-    @testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
+    @testing.requires.on_update_cascade
     def test_manytomany_passive(self):
         self._test_manytomany(True)
 
@@ -549,14 +550,13 @@ class ReversePKsTest(fixtures.MappedTest):
 class SelfReferentialTest(fixtures.MappedTest):
     # mssql, mysql don't allow
     # ON UPDATE on self-referential keys
-    __unsupported_on__ = ('mssql','mysql')
+    __unsupported_on__ = ('mssql', 'mysql')
+
+    __requires__ = 'on_update_or_deferrable_fks',
 
     @classmethod
     def define_tables(cls, metadata):
-        if testing.against('oracle'):
-            fk_args = dict(deferrable=True, initially='deferred')
-        else:
-            fk_args = dict(onupdate='cascade')
+        fk_args = _backend_specific_fk_args()
 
         Table('nodes', metadata,
               Column('name', String(50), primary_key=True),
@@ -622,8 +622,7 @@ class SelfReferentialTest(fixtures.MappedTest):
              for n in sess.query(Node).filter(
                  Node.name.in_(['n11', 'n12', 'n13']))])
 
-    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
-    @testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
+    @testing.requires.on_update_cascade
     def test_many_to_one_passive(self):
         self._test_many_to_one(True)
 
@@ -657,14 +656,11 @@ class SelfReferentialTest(fixtures.MappedTest):
 
 
 class NonPKCascadeTest(fixtures.MappedTest):
-    __requires__ = 'skip_mysql_on_windows',
+    __requires__ = 'skip_mysql_on_windows', 'on_update_or_deferrable_fks'
 
     @classmethod
     def define_tables(cls, metadata):
-        if testing.against('oracle'):
-            fk_args = dict(deferrable=True, initially='deferred')
-        else:
-            fk_args = dict(onupdate='cascade')
+        fk_args = _backend_specific_fk_args()
 
         Table('users', metadata,
             Column('id', Integer, primary_key=True,
@@ -689,8 +685,7 @@ class NonPKCascadeTest(fixtures.MappedTest):
         class Address(cls.Comparable):
             pass
 
-    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
-    @testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
+    @testing.requires.on_update_cascade
     def test_onetomany_passive(self):
         self._test_onetomany(True)
 
@@ -770,10 +765,7 @@ class CascadeToFKPKTest(fixtures.MappedTest, testing.AssertsCompiledSQL):
 
     @classmethod
     def define_tables(cls, metadata):
-        if testing.against('oracle'):
-            fk_args = dict(deferrable=True, initially='deferred')
-        else:
-            fk_args = dict(onupdate='cascade')
+        fk_args = _backend_specific_fk_args()
 
         Table('users', metadata,
             Column('username', String(50), primary_key=True),
@@ -796,8 +788,7 @@ class CascadeToFKPKTest(fixtures.MappedTest, testing.AssertsCompiledSQL):
         class Address(cls.Comparable):
             pass
 
-    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
-    @testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
+    @testing.requires.on_update_cascade
     def test_onetomany_passive(self):
         self._test_onetomany(True)
 
@@ -875,9 +866,7 @@ class CascadeToFKPKTest(fixtures.MappedTest, testing.AssertsCompiledSQL):
         u2.addresses.append(a1)
         sess.flush()
 
-    @testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE '
-                                'but requires referential integrity')
-    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
+    @testing.requires.on_update_cascade
     def test_change_m2o_passive(self):
         self._test_change_m2o(True)
 
@@ -1030,10 +1019,7 @@ class JoinedInheritanceTest(fixtures.MappedTest):
 
     @classmethod
     def define_tables(cls, metadata):
-        if testing.against('oracle'):
-            fk_args = dict(deferrable=True, initially='deferred')
-        else:
-            fk_args = dict(onupdate='cascade')
+        fk_args = _backend_specific_fk_args()
 
         Table('person', metadata,
             Column('name', String(50), primary_key=True),
@@ -1066,8 +1052,7 @@ class JoinedInheritanceTest(fixtures.MappedTest):
         class Manager(Person):
             pass
 
-    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
-    @testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
+    @testing.requires.on_update_cascade
     def test_pk_passive(self):
         self._test_pk(True)
 
@@ -1076,8 +1061,7 @@ class JoinedInheritanceTest(fixtures.MappedTest):
     def test_pk_nonpassive(self):
         self._test_pk(False)
 
-    @testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
-    @testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
+    @testing.requires.on_update_cascade
     def test_fk_passive(self):
         self._test_fk(True)
 
index 9aad19579d1c998d8102f75d41919a95540fe3e5..05a13c3c15d2c6557c4e400ba80c336fc092beae 100644 (file)
@@ -1099,20 +1099,27 @@ class FilterTest(QueryTest, AssertsCompiledSQL):
     def test_basic(self):
         User = self.classes.User
 
-        assert [User(id=7), User(id=8), User(id=9),User(id=10)] == create_session().query(User).all()
+        users = create_session().query(User).all()
+        eq_(
+            [User(id=7), User(id=8), User(id=9),User(id=10)],
+            users
+        )
 
-    @testing.fails_on('maxdb', 'FIXME: unknown')
-    def test_limit(self):
+    @testing.requires.offset
+    def test_limit_offset(self):
         User = self.classes.User
 
-        assert [User(id=8), User(id=9)] == create_session().query(User).order_by(User.id).limit(2).offset(1).all()
+        sess = create_session()
+
+        assert [User(id=8), User(id=9)] == sess.query(User).order_by(User.id).limit(2).offset(1).all()
+
+        assert [User(id=8), User(id=9)] == list(sess.query(User).order_by(User.id)[1:3])
 
-        assert [User(id=8), User(id=9)] == list(create_session().query(User).order_by(User.id)[1:3])
+        assert User(id=8) == sess.query(User).order_by(User.id)[1]
 
-        assert User(id=8) == create_session().query(User).order_by(User.id)[1]
+        assert [] == sess.query(User).order_by(User.id)[3:3]
+        assert [] == sess.query(User).order_by(User.id)[0:0]
 
-        assert [] == create_session().query(User).order_by(User.id)[3:3]
-        assert [] == create_session().query(User).order_by(User.id)[0:0]
 
     @testing.requires.boolean_col_expressions
     def test_exists(self):
index 525786f72a668c791c5fb27d0065bc163fec12be..8dde55d6af5806d2ff98fb03cfbafff93802644e 100644 (file)
@@ -51,6 +51,23 @@ class DefaultRequirements(SuiteRequirements):
                 no_support('sqlite', 'not supported by database')
             )
 
+    @property
+    def on_update_cascade(self):
+        """target database must support ON UPDATE..CASCADE behavior in
+        foreign keys."""
+
+        return skip_if(
+                    ['sqlite', 'oracle'],
+                    'target backend does not support ON UPDATE CASCADE'
+                )
+
+    @property
+    def deferrable_fks(self):
+        """target database must support deferrable fks"""
+
+        return only_on(['oracle'])
+
+
     @property
     def unbounded_varchar(self):
         """Target database must support VARCHAR with no length"""
@@ -316,6 +333,7 @@ class DefaultRequirements(SuiteRequirements):
 
     @property
     def unicode_data(self):
+        """target drive must support unicode data stored in columns."""
         return skip_if([
             no_support("sybase", "no unicode driver support")
             ])
@@ -330,7 +348,7 @@ class DefaultRequirements(SuiteRequirements):
 
     @property
     def unicode_ddl(self):
-        """Target driver must support some encoding of Unicode across the wire."""
+        """Target driver must support some degree of non-ascii symbol names."""
         # TODO: expand to exclude MySQLdb versions w/ broken unicode
         return skip_if([
             no_support('maxdb', 'database support flakey'),