summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2014-03-02 14:49:24 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2014-03-02 14:49:24 -0500
commitffbc58333306c098c9c71ea28482975803467d8c (patch)
treef3fcb9451f050f0fdaf9f0b277ce8020cb258f63
parente932c263d54bb86451e8e4c63e459388654c860b (diff)
downloadsqlalchemy-ffbc58333306c098c9c71ea28482975803467d8c.tar.gz
- cleanup, solidify Config
-rw-r--r--lib/sqlalchemy/testing/__init__.py3
-rw-r--r--lib/sqlalchemy/testing/config.py54
-rw-r--r--lib/sqlalchemy/testing/exclusions.py1
-rw-r--r--lib/sqlalchemy/testing/plugin/noseplugin.py60
-rw-r--r--lib/sqlalchemy/testing/schema.py6
-rw-r--r--test/engine/test_reflection.py2
-rw-r--r--test/requirements.py20
7 files changed, 92 insertions, 54 deletions
diff --git a/lib/sqlalchemy/testing/__init__.py b/lib/sqlalchemy/testing/__init__.py
index 61e0f5429..954906432 100644
--- a/lib/sqlalchemy/testing/__init__.py
+++ b/lib/sqlalchemy/testing/__init__.py
@@ -26,6 +26,7 @@ from .util import run_as_contextmanager, rowset, fail, provide_metadata, adict
crashes = skip
-from .config import db, requirements as requires
+from .config import db
+from .config import requirements as requires
from . import mock \ No newline at end of file
diff --git a/lib/sqlalchemy/testing/config.py b/lib/sqlalchemy/testing/config.py
index c25355396..d75f6b545 100644
--- a/lib/sqlalchemy/testing/config.py
+++ b/lib/sqlalchemy/testing/config.py
@@ -4,12 +4,66 @@
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
+import collections
+
requirements = None
db = None
+db_url = None
dbs = {}
db_opts = None
_current = None
file_config = None
+class Config(object):
+ def __init__(self, db, db_opts, options, file_config):
+ self.db = db
+ self.db_opts = db_opts
+ self.options = options
+ self.file_config = file_config
+
+ _stack = collections.deque()
+
+ @classmethod
+ def register(cls, db, db_opts, options, file_config, namespace):
+ """add a config as one of the global configs.
+
+ If there are no configs set up yet, this config also
+ gets set as the "_current".
+ """
+ cfg = Config(db, db_opts, options, file_config)
+
+ global _current
+ if not _current:
+ cls.set_as_current(cfg, namespace)
+ dbs[cfg.db.name] = cfg
+ dbs[(cfg.db.name, cfg.db.dialect)] = cfg
+ dbs[cfg.db] = cfg
+
+ @classmethod
+ def set_as_current(cls, config, namespace):
+ global db, _current, db_url
+ _current = config
+ db_url = config.db.url
+ namespace.db = db = config.db
+
+ @classmethod
+ def push_engine(cls, db, namespace):
+ assert _current, "Can't push without a default Config set up"
+ cls.push(
+ Config(db, _current.db_opts, _current.options, _current.file_config),
+ namespace
+ )
+
+ @classmethod
+ def push(cls, config, namespace):
+ cls._stack.append(_current)
+ cls.set_as_current(config, namespace)
+
+ @classmethod
+ def reset(cls, namespace):
+ if cls._stack:
+ cls.set_as_current(cls._stack[0], namespace)
+ cls._stack.clear()
+
def _unique_configs():
return set(dbs.values()) \ No newline at end of file
diff --git a/lib/sqlalchemy/testing/exclusions.py b/lib/sqlalchemy/testing/exclusions.py
index c517f9049..2c642a3e8 100644
--- a/lib/sqlalchemy/testing/exclusions.py
+++ b/lib/sqlalchemy/testing/exclusions.py
@@ -348,6 +348,7 @@ def exclude(db, op, spec, reason=None):
def against(config, *queries):
+ assert queries, "no queries sent!"
return OrPredicate([
Predicate.as_predicate(query)
for query in queries
diff --git a/lib/sqlalchemy/testing/plugin/noseplugin.py b/lib/sqlalchemy/testing/plugin/noseplugin.py
index 153d227a7..ed822ffc4 100644
--- a/lib/sqlalchemy/testing/plugin/noseplugin.py
+++ b/lib/sqlalchemy/testing/plugin/noseplugin.py
@@ -20,6 +20,7 @@ from __future__ import absolute_import
import os
import sys
+import re
py3k = sys.version_info >= (3, 0)
if py3k:
@@ -48,16 +49,8 @@ file_config = None
logging = None
db_opts = {}
options = None
-_existing_config_obj = None
-class Config(object):
- def __init__(self, db, db_opts, options, file_config):
- self.db = db
- self.db_opts = db_opts
- self.options = options
- self.file_config = file_config
-
def _log(option, opt_str, value, parser):
global logging
if not logging:
@@ -119,13 +112,14 @@ def _engine_uri(options, file_config):
db_urls = []
if options.db:
- for db in options.db:
- if db not in file_config.options('db'):
- raise RuntimeError(
- "Unknown URI specifier '%s'. Specify --dbs for known uris."
- % db)
- else:
- db_urls.append(file_config.get('db', db))
+ for db_token in options.db:
+ for db in re.split(r'[,\s]+', db_token):
+ if db not in file_config.options('db'):
+ raise RuntimeError(
+ "Unknown URI specifier '%s'. Specify --dbs for known uris."
+ % db)
+ else:
+ db_urls.append(file_config.get('db', db))
if not db_urls:
db_urls.append(file_config.get('db', 'default'))
@@ -133,13 +127,7 @@ def _engine_uri(options, file_config):
for db_url in db_urls:
eng = engines.testing_engine(db_url, db_opts)
eng.connect().close()
- config_obj = Config(eng, db_opts, options, file_config)
- if not config.db:
- config.db = testing.db = eng
- config._current = config_obj
- config.dbs[eng.name] = config_obj
- config.dbs[(eng.name, eng.dialect)] = config_obj
- config.dbs[eng] = config_obj
+ config.Config.register(eng, db_opts, options, file_config, testing)
config.db_opts = db_opts
@@ -385,7 +373,9 @@ class NoseSQLAlchemy(Plugin):
for db_spec, op, spec in getattr(cls, '__excluded_on__', ()):
for config_obj in list(all_configs):
- if exclusions.skip_if(exclusions.SpecPredicate(db_spec, op, spec)).predicate(config_obj):
+ if exclusions.skip_if(
+ exclusions.SpecPredicate(db_spec, op, spec)
+ ).predicate(config_obj):
all_configs.remove(config_obj)
@@ -393,7 +383,9 @@ class NoseSQLAlchemy(Plugin):
raise SkipTest(
"'%s' unsupported on DB implementation %s%s" % (
cls.__name__,
- ", ".join("'%s' = %s" % (config_obj.db.name, config_obj.db.dialect.server_version_info)
+ ", ".join("'%s' = %s" % (
+ config_obj.db.name,
+ config_obj.db.dialect.server_version_info)
for config_obj in config._unique_configs()
),
", ".join(reasons)
@@ -420,29 +412,15 @@ class NoseSQLAlchemy(Plugin):
warnings.resetwarnings()
def _setup_config(self, config_obj, ctx):
- ctx.__use_config__ = config_obj
+ config._current.push(config_obj, testing)
def _setup_engine(self, ctx):
if getattr(ctx, '__engine_options__', None):
eng = engines.testing_engine(options=ctx.__engine_options__)
- config_obj = Config(eng, db_opts, options, file_config)
- elif getattr(ctx, '__use_config__', None):
- config_obj = ctx.__use_config__
- else:
- config_obj = None
-
- if config_obj:
- global _existing_config_obj
- _existing_config_obj = config._current
- config._current = config_obj
- config.db = testing.db = config_obj.db
+ config._current.push_engine(eng)
def _restore_engine(self, ctx):
- global _existing_config_obj
- if _existing_config_obj is not None:
- config.db = testing.db = _existing_config_obj.db
- config._current = _existing_config_obj
- _existing_config_obj = None
+ config._current.reset(testing)
def startContext(self, ctx):
if not isinstance(ctx, type) \
diff --git a/lib/sqlalchemy/testing/schema.py b/lib/sqlalchemy/testing/schema.py
index 605ca86b8..4766af180 100644
--- a/lib/sqlalchemy/testing/schema.py
+++ b/lib/sqlalchemy/testing/schema.py
@@ -21,7 +21,7 @@ def Table(*args, **kw):
kw.update(table_options)
- if exclusions.against('mysql'):
+ if exclusions.against(config._current, 'mysql'):
if 'mysql_engine' not in kw and 'mysql_type' not in kw:
if 'test_needs_fk' in test_opts or 'test_needs_acid' in test_opts:
kw['mysql_engine'] = 'InnoDB'
@@ -30,7 +30,7 @@ def Table(*args, **kw):
# Apply some default cascading rules for self-referential foreign keys.
# MySQL InnoDB has some issues around seleting self-refs too.
- if exclusions.against('firebird'):
+ if exclusions.against(config._current, 'firebird'):
table_name = args[0]
unpack = (config.db.dialect.
identifier_preparer.unformat_identifiers)
@@ -78,7 +78,7 @@ def Column(*args, **kw):
# hardcoded rule for firebird, oracle; this should
# be moved out
- if exclusions.against(config, 'firebird', 'oracle'):
+ if exclusions.against(config._current, 'firebird', 'oracle'):
def add_seq(c, tbl):
c._init_items(
schema.Sequence(_truncate_name(
diff --git a/test/engine/test_reflection.py b/test/engine/test_reflection.py
index 8a1d7b70e..45ca934ce 100644
--- a/test/engine/test_reflection.py
+++ b/test/engine/test_reflection.py
@@ -1152,7 +1152,7 @@ class UnicodeReflectionTest(fixtures.TestBase):
names = no_multibyte_period
# mysql can't handle casing usually
elif testing.against("mysql") and \
- not testing.requires._has_mysql_fully_case_sensitive():
+ not testing.requires.mysql_fully_case_sensitive.enabled:
names = no_multibyte_period.union(no_case_sensitivity)
# mssql + pyodbc + freetds can't compare multibyte names to
# information_schema.tables.table_name
diff --git a/test/requirements.py b/test/requirements.py
index 6f6945818..4d8433003 100644
--- a/test/requirements.py
+++ b/test/requirements.py
@@ -403,7 +403,7 @@ class DefaultRequirements(SuiteRequirements):
@property
def sane_rowcount(self):
return skip_if(
- lambda: not self.db.dialect.supports_sane_rowcount,
+ lambda config: not config.db.dialect.supports_sane_rowcount,
"driver doesn't support 'sane' rowcount"
)
@@ -443,7 +443,7 @@ class DefaultRequirements(SuiteRequirements):
@property
def sane_multi_rowcount(self):
return skip_if(
- lambda: not self.db.dialect.supports_sane_multi_rowcount,
+ lambda config: not config.db.dialect.supports_sane_multi_rowcount,
"driver doesn't support 'sane' multi row count"
)
@@ -698,7 +698,7 @@ class DefaultRequirements(SuiteRequirements):
as not present.
"""
- return skip_if(lambda: self.config.options.low_connections)
+ return skip_if(lambda config: config.options.low_connections)
@property
def skip_mysql_on_windows(self):
@@ -715,8 +715,8 @@ class DefaultRequirements(SuiteRequirements):
"""
return skip_if(
- lambda: util.py3k and
- self.config.options.enable_plugin_coverage,
+ lambda config: util.py3k and
+ config.options.enable_plugin_coverage,
"Stability issues with coverage + py3k"
)
@@ -740,11 +740,15 @@ class DefaultRequirements(SuiteRequirements):
except ImportError:
return False
+ @property
+ def mysql_fully_case_sensitive(self):
+ return only_if(self._has_mysql_fully_case_sensitive)
+
def _has_mysql_on_windows(self, config):
- return against(config.db, 'mysql') and \
- self.db.dialect._detect_casing(self.db) == 1
+ return against(config, 'mysql') and \
+ config.db.dialect._detect_casing(config.db) == 1
def _has_mysql_fully_case_sensitive(self, config):
- return against(config.db, 'mysql') and \
+ return against(config, 'mysql') and \
config.db.dialect._detect_casing(config.db) == 0