summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2013-02-06 17:50:11 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2013-02-06 17:50:11 -0500
commit47858b85ec7139af83c2cd0aed1af8917d88ea3e (patch)
tree412eb0bc2532207c6c111d21dcef69e5d68683ff
parent4ad4e9fccbb263ac2a0e6bf5f84526b2dee19ece (diff)
downloadsqlalchemy-47858b85ec7139af83c2cd0aed1af8917d88ea3e.tar.gz
- add support for pulling in an external requirements file
- start filling in default versions of remaining requirements that are still only in test/
-rw-r--r--lib/sqlalchemy/testing/plugin/noseplugin.py19
-rw-r--r--lib/sqlalchemy/testing/requirements.py55
-rw-r--r--test/requirements.py9
-rw-r--r--test/sql/test_query.py23
4 files changed, 91 insertions, 15 deletions
diff --git a/lib/sqlalchemy/testing/plugin/noseplugin.py b/lib/sqlalchemy/testing/plugin/noseplugin.py
index 81e724bbe..4ce76363e 100644
--- a/lib/sqlalchemy/testing/plugin/noseplugin.py
+++ b/lib/sqlalchemy/testing/plugin/noseplugin.py
@@ -222,13 +222,23 @@ def _reverse_topological(options, file_config):
dependency.set = RandomSet
+def _requirements_opt(options, opt_str, value, parser):
+ _setup_requirements(value)
+
@post
def _requirements(options, file_config):
+
+ requirement_cls = file_config.get('sqla_testing', "requirement_cls")
+ _setup_requirements(requirement_cls)
+
+def _setup_requirements(argument):
from sqlalchemy.testing import config
from sqlalchemy import testing
- requirement_cls = file_config.get('sqla_testing', "requirement_cls")
- modname, clsname = requirement_cls.split(":")
+ if config.requirements is not None:
+ return
+
+ modname, clsname = argument.split(":")
# importlib.import_module() only introduced in 2.7, a little
# late
@@ -236,7 +246,7 @@ def _requirements(options, file_config):
for component in modname.split(".")[1:]:
mod = getattr(mod, component)
req_cls = getattr(mod, clsname)
- config.requirements = testing.requires = req_cls(db, config)
+ config.requirements = testing.requires = req_cls(config)
@post
@@ -290,6 +300,9 @@ class NoseSQLAlchemy(Plugin):
opt("--reversetop", action="store_true", dest="reversetop", default=False,
help="Use a random-ordering set implementation in the ORM (helps "
"reveal dependency issues)")
+ opt("--requirements", action="callback", type="string",
+ callback=_requirements_opt,
+ help="requirements class for testing, overrides setup.cfg")
opt("--with-cdecimal", action="store_true", dest="cdecimal", default=False,
help="Monkeypatch the cdecimal library into Python 'decimal' for all tests")
opt("--unhashable", action="store_true", dest="unhashable", default=False,
diff --git a/lib/sqlalchemy/testing/requirements.py b/lib/sqlalchemy/testing/requirements.py
index e44a333be..7228f38f9 100644
--- a/lib/sqlalchemy/testing/requirements.py
+++ b/lib/sqlalchemy/testing/requirements.py
@@ -8,14 +8,16 @@ to provide specific inclusion/exlusions.
"""
-from . import exclusions
+from . import exclusions, config
class Requirements(object):
- def __init__(self, db, config):
- self.db = db
+ def __init__(self, config):
self.config = config
+ @property
+ def db(self):
+ return config.db
class SuiteRequirements(Requirements):
@@ -62,6 +64,47 @@ class SuiteRequirements(Requirements):
return exclusions.open()
@property
+ def offset(self):
+ """target database can render OFFSET, or an equivalent, in a SELECT."""
+
+ return exclusions.open()
+
+ @property
+ def boolean_col_expressions(self):
+ """Target database must support boolean expressions as columns"""
+
+ return exclusions.closed()
+
+ @property
+ def nullsordering(self):
+ """Target backends that support nulls ordering."""
+
+ return exclusions.closed()
+
+ @property
+ def standalone_binds(self):
+ """target database/driver supports bound parameters as column expressions
+ without being in the context of a typed column.
+
+ """
+ return exclusions.closed()
+
+ @property
+ def intersect(self):
+ """Target database must support INTERSECT or equivalent."""
+ return exclusions.closed()
+
+ @property
+ def except_(self):
+ """Target database must support EXCEPT or equivalent (i.e. MINUS)."""
+ return exclusions.closed()
+
+ @property
+ def window_functions(self):
+ """Target database must support window functions."""
+ return exclusions.closed()
+
+ @property
def autoincrement_insert(self):
"""target platform generates new surrogate integer primary key values
when insert() is executed, excluding the pk column."""
@@ -300,3 +343,9 @@ class SuiteRequirements(Requirements):
)
"""
return exclusions.open()
+
+ @property
+ def mod_operator_as_percent_sign(self):
+ """target database must use a plain percent '%' as the 'modulus'
+ operator."""
+ return exclusions.closed()
diff --git a/test/requirements.py b/test/requirements.py
index e23a54225..525786f72 100644
--- a/test/requirements.py
+++ b/test/requirements.py
@@ -238,6 +238,15 @@ class DefaultRequirements(SuiteRequirements):
return skip_if(exclude('mysql', '<', (4, 1, 1)), 'no subquery support')
@property
+ def mod_operator_as_percent_sign(self):
+ """target database must use a plain percent '%' as the 'modulus'
+ operator."""
+
+ return only_if(
+ ['mysql', 'sqlite', 'postgresql+psycopg2', 'mssql']
+ )
+
+ @property
def intersect(self):
"""Target database must support INTERSECT or equivalent."""
diff --git a/test/sql/test_query.py b/test/sql/test_query.py
index 16b0f79fd..b5f50aeea 100644
--- a/test/sql/test_query.py
+++ b/test/sql/test_query.py
@@ -443,10 +443,7 @@ class QueryTest(fixtures.TestBase):
):
eq_(expr.execute().fetchall(), result)
- @testing.fails_on("firebird", "see dialect.test_firebird:MiscTest.test_percents_in_text")
- @testing.fails_on("oracle", "neither % nor %% are accepted")
- @testing.fails_on("informix", "neither % nor %% are accepted")
- @testing.fails_on("+pg8000", "can't interpret result column from '%%'")
+ @testing.requires.mod_operator_as_percent_sign
@testing.emits_warning('.*now automatically escapes.*')
def test_percents_in_text(self):
for expr, result in (
@@ -534,6 +531,7 @@ class QueryTest(fixtures.TestBase):
a_eq(prep(r"(\:that$other)"), "(:that$other)")
a_eq(prep(r".\:that$ :other."), ".:that$ ?.")
+ @testing.requires.standalone_binds
def test_select_from_bindparam(self):
"""Test result row processing when selecting from a plain bind param."""
@@ -911,15 +909,23 @@ class QueryTest(fixtures.TestBase):
eq_(users.select().execute().fetchall(), [(1, 'john')])
def test_result_as_args(self):
- users.insert().execute([dict(user_id=1, user_name='john'), dict(user_id=2, user_name='ed')])
+ users.insert().execute([
+ dict(user_id=1, user_name='john'),
+ dict(user_id=2, user_name='ed')])
r = users.select().execute()
users2.insert().execute(list(r))
- assert users2.select().execute().fetchall() == [(1, 'john'), (2, 'ed')]
+ eq_(
+ users2.select().order_by(users2.c.user_id).execute().fetchall(),
+ [(1, 'john'), (2, 'ed')]
+ )
users2.delete().execute()
r = users.select().execute()
users2.insert().execute(*list(r))
- assert users2.select().execute().fetchall() == [(1, 'john'), (2, 'ed')]
+ eq_(
+ users2.select().order_by(users2.c.user_id).execute().fetchall(),
+ [(1, 'john'), (2, 'ed')]
+ )
def test_ambiguous_column(self):
users.insert().execute(user_id=1, user_name='john')
@@ -1744,7 +1750,6 @@ class LimitTest(fixtures.TestBase):
self.assert_(r == [(1, 'john'), (2, 'jack'), (3, 'ed')], repr(r))
@testing.requires.offset
- @testing.fails_on('maxdb', 'FIXME: unknown')
def test_select_limit_offset(self):
"""Test the interaction between limit and offset"""
@@ -2369,7 +2374,7 @@ class OperatorTest(fixtures.TestBase):
eq_(
select([flds.c.intcol % 3],
order_by=flds.c.idcol).execute().fetchall(),
- [(2,),(1,)]
+ [(2,), (1,)]
)
@testing.requires.window_functions