From e1402efb198f96090833a9b561cdba8dee937f70 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Mon, 15 Nov 2010 19:37:50 -0500 Subject: - move sqlalchemy.test to test.lib --- lib/sqlalchemy/test/__init__.py | 27 - lib/sqlalchemy/test/assertsql.py | 295 ---------- lib/sqlalchemy/test/engines.py | 305 ---------- lib/sqlalchemy/test/entities.py | 83 --- lib/sqlalchemy/test/orm.py | 111 ---- lib/sqlalchemy/test/pickleable.py | 75 --- lib/sqlalchemy/test/profiling.py | 221 ------- lib/sqlalchemy/test/requires.py | 318 ---------- lib/sqlalchemy/test/schema.py | 79 --- lib/sqlalchemy/test/testing.py | 797 -------------------------- lib/sqlalchemy/test/util.py | 76 --- sqla_nose.py | 4 +- test/aaa_profiling/test_compiler.py | 2 +- test/aaa_profiling/test_memusage.py | 8 +- test/aaa_profiling/test_orm.py | 6 +- test/aaa_profiling/test_pool.py | 2 +- test/aaa_profiling/test_resultset.py | 2 +- test/aaa_profiling/test_zoomark.py | 2 +- test/aaa_profiling/test_zoomark_orm.py | 2 +- test/base/test_dependency.py | 4 +- test/base/test_except.py | 2 +- test/base/test_utils.py | 8 +- test/bootstrap/config.py | 8 +- test/bootstrap/noseplugin.py | 2 +- test/dialect/test_access.py | 2 +- test/dialect/test_firebird.py | 4 +- test/dialect/test_informix.py | 2 +- test/dialect/test_maxdb.py | 4 +- test/dialect/test_mssql.py | 6 +- test/dialect/test_mxodbc.py | 4 +- test/dialect/test_mysql.py | 8 +- test/dialect/test_oracle.py | 8 +- test/dialect/test_postgresql.py | 10 +- test/dialect/test_sqlite.py | 4 +- test/dialect/test_sybase.py | 2 +- test/engine/_base.py | 4 +- test/engine/test_bind.py | 8 +- test/engine/test_ddlevents.py | 10 +- test/engine/test_execute.py | 6 +- test/engine/test_metadata.py | 12 +- test/engine/test_parseconnect.py | 4 +- test/engine/test_pool.py | 6 +- test/engine/test_reconnect.py | 8 +- test/engine/test_reflection.py | 6 +- test/engine/test_transaction.py | 8 +- test/ex/test_examples.py | 2 +- test/ext/test_associationproxy.py | 6 +- test/ext/test_compiler.py | 2 +- test/ext/test_declarative.py | 8 +- test/ext/test_horizontal_shard.py | 4 +- test/ext/test_orderinglist.py | 4 +- test/ext/test_serializer.py | 8 +- test/ext/test_sqlsoup.py | 2 +- test/lib/__init__.py | 27 + test/lib/assertsql.py | 295 ++++++++++ test/lib/engines.py | 305 ++++++++++ test/lib/entities.py | 83 +++ test/lib/orm.py | 111 ++++ test/lib/pickleable.py | 75 +++ test/lib/profiling.py | 221 +++++++ test/lib/requires.py | 318 ++++++++++ test/lib/schema.py | 79 +++ test/lib/testing.py | 797 ++++++++++++++++++++++++++ test/lib/util.py | 76 +++ test/orm/_base.py | 8 +- test/orm/_fixtures.py | 6 +- test/orm/inheritance/test_abc_inheritance.py | 4 +- test/orm/inheritance/test_abc_polymorphic.py | 2 +- test/orm/inheritance/test_basic.py | 6 +- test/orm/inheritance/test_concrete.py | 10 +- test/orm/inheritance/test_magazine.py | 4 +- test/orm/inheritance/test_manytomany.py | 4 +- test/orm/inheritance/test_poly_linked_list.py | 4 +- test/orm/inheritance/test_polymorph.py | 4 +- test/orm/inheritance/test_polymorph2.py | 8 +- test/orm/inheritance/test_productspec.py | 4 +- test/orm/inheritance/test_query.py | 8 +- test/orm/inheritance/test_selects.py | 2 +- test/orm/inheritance/test_single.py | 6 +- test/orm/test_association.py | 6 +- test/orm/test_assorted_eager.py | 6 +- test/orm/test_attributes.py | 6 +- test/orm/test_backref_mutations.py | 10 +- test/orm/test_bind.py | 8 +- test/orm/test_cascade.py | 8 +- test/orm/test_collection.py | 8 +- test/orm/test_compile.py | 2 +- test/orm/test_cycles.py | 8 +- test/orm/test_defaults.py | 6 +- test/orm/test_deprecations.py | 6 +- test/orm/test_dynamic.py | 8 +- test/orm/test_eager_relations.py | 10 +- test/orm/test_evaluator.py | 8 +- test/orm/test_expire.py | 10 +- test/orm/test_extendedattr.py | 4 +- test/orm/test_generative.py | 10 +- test/orm/test_immediate_load.py | 4 +- test/orm/test_instrumentation.py | 8 +- test/orm/test_lazy_relations.py | 10 +- test/orm/test_lazytest1.py | 6 +- test/orm/test_load_on_fks.py | 6 +- test/orm/test_manytomany.py | 8 +- test/orm/test_mapper.py | 10 +- test/orm/test_merge.py | 8 +- test/orm/test_naturalpks.py | 10 +- test/orm/test_onetoone.py | 4 +- test/orm/test_pickled.py | 8 +- test/orm/test_query.py | 6 +- test/orm/test_relationships.py | 8 +- test/orm/test_scoping.py | 8 +- test/orm/test_selectable.py | 8 +- test/orm/test_session.py | 10 +- test/orm/test_subquery_relations.py | 10 +- test/orm/test_transaction.py | 6 +- test/orm/test_unitofwork.py | 12 +- test/orm/test_unitofworkv2.py | 8 +- test/orm/test_utils.py | 6 +- test/orm/test_versioning.py | 6 +- test/perf/insertspeed.py | 2 +- test/perf/large_flush.py | 2 +- test/perf/masscreate2.py | 2 +- test/perf/masseagerload.py | 2 +- test/perf/massload.py | 2 +- test/perf/masssave.py | 2 +- test/perf/objselectspeed.py | 4 +- test/perf/objupdatespeed.py | 4 +- test/perf/ormsession.py | 4 +- test/perf/poolload.py | 2 +- test/perf/sessions.py | 4 +- test/perf/wsgi.py | 2 +- test/sql/test_case_statement.py | 4 +- test/sql/test_columns.py | 4 +- test/sql/test_compiler.py | 4 +- test/sql/test_constraints.py | 10 +- test/sql/test_defaults.py | 8 +- test/sql/test_functions.py | 10 +- test/sql/test_generative.py | 4 +- test/sql/test_labels.py | 4 +- test/sql/test_query.py | 8 +- test/sql/test_quote.py | 2 +- test/sql/test_returning.py | 6 +- test/sql/test_rowcount.py | 2 +- test/sql/test_selectable.py | 4 +- test/sql/test_types.py | 12 +- test/sql/test_unicode.py | 4 +- test/zblog/tables.py | 2 +- test/zblog/test_zblog.py | 2 +- 147 files changed, 2742 insertions(+), 2742 deletions(-) delete mode 100644 lib/sqlalchemy/test/__init__.py delete mode 100644 lib/sqlalchemy/test/assertsql.py delete mode 100644 lib/sqlalchemy/test/engines.py delete mode 100644 lib/sqlalchemy/test/entities.py delete mode 100644 lib/sqlalchemy/test/orm.py delete mode 100644 lib/sqlalchemy/test/pickleable.py delete mode 100644 lib/sqlalchemy/test/profiling.py delete mode 100644 lib/sqlalchemy/test/requires.py delete mode 100644 lib/sqlalchemy/test/schema.py delete mode 100644 lib/sqlalchemy/test/testing.py delete mode 100644 lib/sqlalchemy/test/util.py create mode 100644 test/lib/__init__.py create mode 100644 test/lib/assertsql.py create mode 100644 test/lib/engines.py create mode 100644 test/lib/entities.py create mode 100644 test/lib/orm.py create mode 100644 test/lib/pickleable.py create mode 100644 test/lib/profiling.py create mode 100644 test/lib/requires.py create mode 100644 test/lib/schema.py create mode 100644 test/lib/testing.py create mode 100644 test/lib/util.py diff --git a/lib/sqlalchemy/test/__init__.py b/lib/sqlalchemy/test/__init__.py deleted file mode 100644 index e82b3ac91..000000000 --- a/lib/sqlalchemy/test/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -"""Testing environment and utilities. - -This package contains base classes and routines used by -the unit tests. Tests are based on Nose and bootstrapped -by noseplugin.NoseSQLAlchemy. - -""" - -from test.bootstrap import config -from sqlalchemy.test import testing, engines, requires, profiling, pickleable -from sqlalchemy.test.schema import Column, Table -from sqlalchemy.test.testing import \ - AssertsCompiledSQL, \ - AssertsExecutionResults, \ - ComparesTables, \ - TestBase, \ - rowset - - -__all__ = ('testing', - 'Column', 'Table', - 'rowset', - 'TestBase', 'AssertsExecutionResults', - 'AssertsCompiledSQL', 'ComparesTables', - 'engines', 'profiling', 'pickleable') - - diff --git a/lib/sqlalchemy/test/assertsql.py b/lib/sqlalchemy/test/assertsql.py deleted file mode 100644 index a044f9d02..000000000 --- a/lib/sqlalchemy/test/assertsql.py +++ /dev/null @@ -1,295 +0,0 @@ - -from sqlalchemy.interfaces import ConnectionProxy -from sqlalchemy.engine.default import DefaultDialect -from sqlalchemy.engine.base import Connection -from sqlalchemy import util -import re - -class AssertRule(object): - def process_execute(self, clauseelement, *multiparams, **params): - pass - - def process_cursor_execute(self, statement, parameters, context, executemany): - pass - - def is_consumed(self): - """Return True if this rule has been consumed, False if not. - - Should raise an AssertionError if this rule's condition has definitely failed. - - """ - raise NotImplementedError() - - def rule_passed(self): - """Return True if the last test of this rule passed, False if failed, None if no test was applied.""" - - raise NotImplementedError() - - def consume_final(self): - """Return True if this rule has been consumed. - - Should raise an AssertionError if this rule's condition has not been consumed or has failed. - - """ - - if self._result is None: - assert False, "Rule has not been consumed" - - return self.is_consumed() - -class SQLMatchRule(AssertRule): - def __init__(self): - self._result = None - self._errmsg = "" - - def rule_passed(self): - return self._result - - def is_consumed(self): - if self._result is None: - return False - - assert self._result, self._errmsg - - return True - -class ExactSQL(SQLMatchRule): - def __init__(self, sql, params=None): - SQLMatchRule.__init__(self) - self.sql = sql - self.params = params - - def process_cursor_execute(self, statement, parameters, context, executemany): - if not context: - return - - _received_statement = _process_engine_statement(context.unicode_statement, context) - _received_parameters = context.compiled_parameters - - # TODO: remove this step once all unit tests - # are migrated, as ExactSQL should really be *exact* SQL - sql = _process_assertion_statement(self.sql, context) - - equivalent = _received_statement == sql - if self.params: - if util.callable(self.params): - params = self.params(context) - else: - params = self.params - - if not isinstance(params, list): - params = [params] - equivalent = equivalent and params == context.compiled_parameters - else: - params = {} - - - self._result = equivalent - if not self._result: - self._errmsg = "Testing for exact statement %r exact params %r, " \ - "received %r with params %r" % (sql, params, _received_statement, _received_parameters) - - -class RegexSQL(SQLMatchRule): - def __init__(self, regex, params=None): - SQLMatchRule.__init__(self) - self.regex = re.compile(regex) - self.orig_regex = regex - self.params = params - - def process_cursor_execute(self, statement, parameters, context, executemany): - if not context: - return - - _received_statement = _process_engine_statement(context.unicode_statement, context) - _received_parameters = context.compiled_parameters - - equivalent = bool(self.regex.match(_received_statement)) - if self.params: - if util.callable(self.params): - params = self.params(context) - else: - params = self.params - - if not isinstance(params, list): - params = [params] - - # do a positive compare only - for param, received in zip(params, _received_parameters): - for k, v in param.iteritems(): - if k not in received or received[k] != v: - equivalent = False - break - else: - params = {} - - self._result = equivalent - if not self._result: - self._errmsg = "Testing for regex %r partial params %r, "\ - "received %r with params %r" % (self.orig_regex, params, _received_statement, _received_parameters) - -class CompiledSQL(SQLMatchRule): - def __init__(self, statement, params): - SQLMatchRule.__init__(self) - self.statement = statement - self.params = params - - def process_cursor_execute(self, statement, parameters, context, executemany): - if not context: - return - - _received_parameters = list(context.compiled_parameters) - - # recompile from the context, using the default dialect - compiled = context.compiled.statement.\ - compile(dialect=DefaultDialect(), column_keys=context.compiled.column_keys) - - _received_statement = re.sub(r'\n', '', str(compiled)) - - equivalent = self.statement == _received_statement - if self.params: - if util.callable(self.params): - params = self.params(context) - else: - params = self.params - - if not isinstance(params, list): - params = [params] - - all_params = list(params) - all_received = list(_received_parameters) - while params: - param = dict(params.pop(0)) - for k, v in context.compiled.params.iteritems(): - param.setdefault(k, v) - - if param not in _received_parameters: - equivalent = False - break - else: - _received_parameters.remove(param) - if _received_parameters: - equivalent = False - else: - params = {} - - self._result = equivalent - if not self._result: - self._errmsg = "Testing for compiled statement %r partial params %r, " \ - "received %r with params %r" % \ - (self.statement, all_params, _received_statement, all_received) - #print self._errmsg - - -class CountStatements(AssertRule): - def __init__(self, count): - self.count = count - self._statement_count = 0 - - def process_execute(self, clauseelement, *multiparams, **params): - self._statement_count += 1 - - def process_cursor_execute(self, statement, parameters, context, executemany): - pass - - def is_consumed(self): - return False - - def consume_final(self): - assert self.count == self._statement_count, "desired statement count %d does not match %d" % (self.count, self._statement_count) - return True - -class AllOf(AssertRule): - def __init__(self, *rules): - self.rules = set(rules) - - def process_execute(self, clauseelement, *multiparams, **params): - for rule in self.rules: - rule.process_execute(clauseelement, *multiparams, **params) - - def process_cursor_execute(self, statement, parameters, context, executemany): - for rule in self.rules: - rule.process_cursor_execute(statement, parameters, context, executemany) - - def is_consumed(self): - if not self.rules: - return True - - for rule in list(self.rules): - if rule.rule_passed(): # a rule passed, move on - self.rules.remove(rule) - return len(self.rules) == 0 - - assert False, "No assertion rules were satisfied for statement" - - def consume_final(self): - return len(self.rules) == 0 - -def _process_engine_statement(query, context): - if util.jython: - # oracle+zxjdbc passes a PyStatement when returning into - query = unicode(query) - if context.engine.name == 'mssql' and query.endswith('; select scope_identity()'): - query = query[:-25] - - query = re.sub(r'\n', '', query) - - return query - -def _process_assertion_statement(query, context): - paramstyle = context.dialect.paramstyle - if paramstyle == 'named': - pass - elif paramstyle =='pyformat': - query = re.sub(r':([\w_]+)', r"%(\1)s", query) - else: - # positional params - repl = None - if paramstyle=='qmark': - repl = "?" - elif paramstyle=='format': - repl = r"%s" - elif paramstyle=='numeric': - repl = None - query = re.sub(r':([\w_]+)', repl, query) - - return query - -class SQLAssert(ConnectionProxy): - rules = None - - def add_rules(self, rules): - self.rules = list(rules) - - def statement_complete(self): - for rule in self.rules: - if not rule.consume_final(): - assert False, "All statements are complete, but pending assertion rules remain" - - def clear_rules(self): - del self.rules - - def execute(self, conn, execute, clauseelement, *multiparams, **params): - result = execute(clauseelement, *multiparams, **params) - - if self.rules is not None: - if not self.rules: - assert False, "All rules have been exhausted, but further statements remain" - rule = self.rules[0] - rule.process_execute(clauseelement, *multiparams, **params) - if rule.is_consumed(): - self.rules.pop(0) - - return result - - def cursor_execute(self, execute, cursor, statement, parameters, context, executemany): - result = execute(cursor, statement, parameters, context) - - if self.rules: - rule = self.rules[0] - rule.process_cursor_execute(statement, parameters, context, executemany) - - return result - -asserter = SQLAssert() - diff --git a/lib/sqlalchemy/test/engines.py b/lib/sqlalchemy/test/engines.py deleted file mode 100644 index d18b8c8cf..000000000 --- a/lib/sqlalchemy/test/engines.py +++ /dev/null @@ -1,305 +0,0 @@ -import sys, types, weakref -from collections import deque -from test.bootstrap import config -from sqlalchemy.util import function_named, callable -import re -import warnings - -class ConnectionKiller(object): - def __init__(self): - self.proxy_refs = weakref.WeakKeyDictionary() - - def checkout(self, dbapi_con, con_record, con_proxy): - self.proxy_refs[con_proxy] = True - - def _apply_all(self, methods): - # must copy keys atomically - for rec in self.proxy_refs.keys(): - if rec is not None and rec.is_valid: - try: - for name in methods: - if callable(name): - name(rec) - else: - getattr(rec, name)() - except (SystemExit, KeyboardInterrupt): - raise - except Exception, e: - warnings.warn("testing_reaper couldn't close connection: %s" % e) - - def rollback_all(self): - self._apply_all(('rollback',)) - - def close_all(self): - self._apply_all(('rollback', 'close')) - - def assert_all_closed(self): - for rec in self.proxy_refs: - if rec.is_valid: - assert False - -testing_reaper = ConnectionKiller() - -def drop_all_tables(metadata): - testing_reaper.close_all() - metadata.drop_all() - -def assert_conns_closed(fn): - def decorated(*args, **kw): - try: - fn(*args, **kw) - finally: - testing_reaper.assert_all_closed() - return function_named(decorated, fn.__name__) - -def rollback_open_connections(fn): - """Decorator that rolls back all open connections after fn execution.""" - - def decorated(*args, **kw): - try: - fn(*args, **kw) - finally: - testing_reaper.rollback_all() - return function_named(decorated, fn.__name__) - -def close_first(fn): - """Decorator that closes all connections before fn execution.""" - def decorated(*args, **kw): - testing_reaper.close_all() - fn(*args, **kw) - return function_named(decorated, fn.__name__) - - -def close_open_connections(fn): - """Decorator that closes all connections after fn execution.""" - - def decorated(*args, **kw): - try: - fn(*args, **kw) - finally: - testing_reaper.close_all() - return function_named(decorated, fn.__name__) - -def all_dialects(exclude=None): - import sqlalchemy.databases as d - for name in d.__all__: - # TEMPORARY - if exclude and name in exclude: - continue - mod = getattr(d, name, None) - if not mod: - mod = getattr(__import__('sqlalchemy.databases.%s' % name).databases, name) - yield mod.dialect() - -class ReconnectFixture(object): - def __init__(self, dbapi): - self.dbapi = dbapi - self.connections = [] - - def __getattr__(self, key): - return getattr(self.dbapi, key) - - def connect(self, *args, **kwargs): - conn = self.dbapi.connect(*args, **kwargs) - self.connections.append(conn) - return conn - - def shutdown(self): - # TODO: this doesn't cover all cases - # as nicely as we'd like, namely MySQLdb. - # would need to implement R. Brewer's - # proxy server idea to get better - # coverage. - for c in list(self.connections): - c.close() - self.connections = [] - -def reconnecting_engine(url=None, options=None): - url = url or config.db_url - dbapi = config.db.dialect.dbapi - if not options: - options = {} - options['module'] = ReconnectFixture(dbapi) - engine = testing_engine(url, options) - engine.test_shutdown = engine.dialect.dbapi.shutdown - return engine - -def testing_engine(url=None, options=None): - """Produce an engine configured by --options with optional overrides.""" - - from sqlalchemy import create_engine - from sqlalchemy.test.assertsql import asserter - - url = url or config.db_url - options = options or config.db_opts - - options.setdefault('proxy', asserter) - - listeners = options.setdefault('listeners', []) - listeners.append(testing_reaper) - - engine = create_engine(url, **options) - - # may want to call this, results - # in first-connect initializers - #engine.connect() - - return engine - -def utf8_engine(url=None, options=None): - """Hook for dialects or drivers that don't handle utf8 by default.""" - - from sqlalchemy.engine import url as engine_url - - if config.db.driver == 'mysqldb': - dbapi_ver = config.db.dialect.dbapi.version_info - if (dbapi_ver < (1, 2, 1) or - dbapi_ver in ((1, 2, 1, 'gamma', 1), (1, 2, 1, 'gamma', 2), - (1, 2, 1, 'gamma', 3), (1, 2, 1, 'gamma', 5))): - raise RuntimeError('Character set support unavailable with this ' - 'driver version: %s' % repr(dbapi_ver)) - else: - url = url or config.db_url - url = engine_url.make_url(url) - url.query['charset'] = 'utf8' - url.query['use_unicode'] = '0' - url = str(url) - - return testing_engine(url, options) - -def mock_engine(dialect_name=None): - """Provides a mocking engine based on the current testing.db. - - This is normally used to test DDL generation flow as emitted - by an Engine. - - It should not be used in other cases, as assert_compile() and - assert_sql_execution() are much better choices with fewer - moving parts. - - """ - - from sqlalchemy import create_engine - - if not dialect_name: - dialect_name = config.db.name - - buffer = [] - def executor(sql, *a, **kw): - buffer.append(sql) - def assert_sql(stmts): - recv = [re.sub(r'[\n\t]', '', str(s)) for s in buffer] - assert recv == stmts, recv - - engine = create_engine(dialect_name + '://', - strategy='mock', executor=executor) - assert not hasattr(engine, 'mock') - engine.mock = buffer - engine.assert_sql = assert_sql - return engine - -class ReplayableSession(object): - """A simple record/playback tool. - - This is *not* a mock testing class. It only records a session for later - playback and makes no assertions on call consistency whatsoever. It's - unlikely to be suitable for anything other than DB-API recording. - - """ - - Callable = object() - NoAttribute = object() - Natives = set([getattr(types, t) - for t in dir(types) if not t.startswith('_')]). \ - difference([getattr(types, t) - # Py3K - #for t in ('FunctionType', 'BuiltinFunctionType', - # 'MethodType', 'BuiltinMethodType', - # 'LambdaType', )]) - - # Py2K - for t in ('FunctionType', 'BuiltinFunctionType', - 'MethodType', 'BuiltinMethodType', - 'LambdaType', 'UnboundMethodType',)]) - # end Py2K - def __init__(self): - self.buffer = deque() - - def recorder(self, base): - return self.Recorder(self.buffer, base) - - def player(self): - return self.Player(self.buffer) - - class Recorder(object): - def __init__(self, buffer, subject): - self._buffer = buffer - self._subject = subject - - def __call__(self, *args, **kw): - subject, buffer = [object.__getattribute__(self, x) - for x in ('_subject', '_buffer')] - - result = subject(*args, **kw) - if type(result) not in ReplayableSession.Natives: - buffer.append(ReplayableSession.Callable) - return type(self)(buffer, result) - else: - buffer.append(result) - return result - - @property - def _sqla_unwrap(self): - return self._subject - - def __getattribute__(self, key): - try: - return object.__getattribute__(self, key) - except AttributeError: - pass - - subject, buffer = [object.__getattribute__(self, x) - for x in ('_subject', '_buffer')] - try: - result = type(subject).__getattribute__(subject, key) - except AttributeError: - buffer.append(ReplayableSession.NoAttribute) - raise - else: - if type(result) not in ReplayableSession.Natives: - buffer.append(ReplayableSession.Callable) - return type(self)(buffer, result) - else: - buffer.append(result) - return result - - class Player(object): - def __init__(self, buffer): - self._buffer = buffer - - def __call__(self, *args, **kw): - buffer = object.__getattribute__(self, '_buffer') - result = buffer.popleft() - if result is ReplayableSession.Callable: - return self - else: - return result - - @property - def _sqla_unwrap(self): - return None - - def __getattribute__(self, key): - try: - return object.__getattribute__(self, key) - except AttributeError: - pass - buffer = object.__getattribute__(self, '_buffer') - result = buffer.popleft() - if result is ReplayableSession.Callable: - return self - elif result is ReplayableSession.NoAttribute: - raise AttributeError(key) - else: - return result - diff --git a/lib/sqlalchemy/test/entities.py b/lib/sqlalchemy/test/entities.py deleted file mode 100644 index 0ec677eea..000000000 --- a/lib/sqlalchemy/test/entities.py +++ /dev/null @@ -1,83 +0,0 @@ -import sqlalchemy as sa -from sqlalchemy import exc as sa_exc - -_repr_stack = set() -class BasicEntity(object): - def __init__(self, **kw): - for key, value in kw.iteritems(): - setattr(self, key, value) - - def __repr__(self): - if id(self) in _repr_stack: - return object.__repr__(self) - _repr_stack.add(id(self)) - try: - return "%s(%s)" % ( - (self.__class__.__name__), - ', '.join(["%s=%r" % (key, getattr(self, key)) - for key in sorted(self.__dict__.keys()) - if not key.startswith('_')])) - finally: - _repr_stack.remove(id(self)) - -_recursion_stack = set() -class ComparableEntity(BasicEntity): - def __hash__(self): - return hash(self.__class__) - - def __ne__(self, other): - return not self.__eq__(other) - - def __eq__(self, other): - """'Deep, sparse compare. - - Deeply compare two entities, following the non-None attributes of the - non-persisted object, if possible. - - """ - if other is self: - return True - elif not self.__class__ == other.__class__: - return False - - if id(self) in _recursion_stack: - return True - _recursion_stack.add(id(self)) - - try: - # pick the entity thats not SA persisted as the source - try: - self_key = sa.orm.attributes.instance_state(self).key - except sa.orm.exc.NO_STATE: - self_key = None - - if other is None: - a = self - b = other - elif self_key is not None: - a = other - b = self - else: - a = self - b = other - - for attr in a.__dict__.keys(): - if attr.startswith('_'): - continue - value = getattr(a, attr) - - try: - # handle lazy loader errors - battr = getattr(b, attr) - except (AttributeError, sa_exc.UnboundExecutionError): - return False - - if hasattr(value, '__iter__'): - if list(value) != list(battr): - return False - else: - if value is not None and value != battr: - return False - return True - finally: - _recursion_stack.remove(id(self)) diff --git a/lib/sqlalchemy/test/orm.py b/lib/sqlalchemy/test/orm.py deleted file mode 100644 index 7ec13c555..000000000 --- a/lib/sqlalchemy/test/orm.py +++ /dev/null @@ -1,111 +0,0 @@ -import inspect, re -import config, testing -from sqlalchemy import orm - -__all__ = 'mapper', - - -_whitespace = re.compile(r'^(\s+)') - -def _find_pragma(lines, current): - m = _whitespace.match(lines[current]) - basis = m and m.group() or '' - - for line in reversed(lines[0:current]): - if 'testlib.pragma' in line: - return line - m = _whitespace.match(line) - indent = m and m.group() or '' - - # simplistic detection: - - # >> # testlib.pragma foo - # >> center_line() - if indent == basis: - break - # >> # testlib.pragma foo - # >> if fleem: - # >> center_line() - if line.endswith(':'): - break - return None - -def _make_blocker(method_name, fallback): - """Creates tripwired variant of a method, raising when called. - - To excempt an invocation from blockage, there are two options. - - 1) add a pragma in a comment:: - - # testlib.pragma exempt:methodname - offending_line() - - 2) add a magic cookie to the function's namespace:: - __sa_baremethodname_exempt__ = True - ... - offending_line() - another_offending_lines() - - The second is useful for testing and development. - """ - - if method_name.startswith('__') and method_name.endswith('__'): - frame_marker = '__sa_%s_exempt__' % method_name[2:-2] - else: - frame_marker = '__sa_%s_exempt__' % method_name - pragma_marker = 'exempt:' + method_name - - def method(self, *args, **kw): - frame_r = None - try: - frame = inspect.stack()[1][0] - frame_r = inspect.getframeinfo(frame, 9) - - module = frame.f_globals.get('__name__', '') - - type_ = type(self) - - pragma = _find_pragma(*frame_r[3:5]) - - exempt = ( - (not module.startswith('sqlalchemy')) or - (pragma and pragma_marker in pragma) or - (frame_marker in frame.f_locals) or - ('self' in frame.f_locals and - getattr(frame.f_locals['self'], frame_marker, False))) - - if exempt: - supermeth = getattr(super(type_, self), method_name, None) - if (supermeth is None or - getattr(supermeth, 'im_func', None) is method): - return fallback(self, *args, **kw) - else: - return supermeth(*args, **kw) - else: - raise AssertionError( - "%s.%s called in %s, line %s in %s" % ( - type_.__name__, method_name, module, frame_r[1], frame_r[2])) - finally: - del frame - method.__name__ = method_name - return method - -def mapper(type_, *args, **kw): - forbidden = [ - ('__hash__', 'unhashable', lambda s: id(s)), - ('__eq__', 'noncomparable', lambda s, o: s is o), - ('__ne__', 'noncomparable', lambda s, o: s is not o), - ('__cmp__', 'noncomparable', lambda s, o: object.__cmp__(s, o)), - ('__le__', 'noncomparable', lambda s, o: object.__le__(s, o)), - ('__lt__', 'noncomparable', lambda s, o: object.__lt__(s, o)), - ('__ge__', 'noncomparable', lambda s, o: object.__ge__(s, o)), - ('__gt__', 'noncomparable', lambda s, o: object.__gt__(s, o)), - ('__nonzero__', 'truthless', lambda s: 1), ] - - if isinstance(type_, type) and type_.__bases__ == (object,): - for method_name, option, fallback in forbidden: - if (getattr(config.options, option, False) and - method_name not in type_.__dict__): - setattr(type_, method_name, _make_blocker(method_name, fallback)) - - return orm.mapper(type_, *args, **kw) diff --git a/lib/sqlalchemy/test/pickleable.py b/lib/sqlalchemy/test/pickleable.py deleted file mode 100644 index 9794e424d..000000000 --- a/lib/sqlalchemy/test/pickleable.py +++ /dev/null @@ -1,75 +0,0 @@ -""" - -some objects used for pickle tests, declared in their own module so that they -are easily pickleable. - -""" - - -class Foo(object): - def __init__(self, moredata): - self.data = 'im data' - self.stuff = 'im stuff' - self.moredata = moredata - __hash__ = object.__hash__ - def __eq__(self, other): - return other.data == self.data and other.stuff == self.stuff and other.moredata==self.moredata - - -class Bar(object): - def __init__(self, x, y): - self.x = x - self.y = y - __hash__ = object.__hash__ - def __eq__(self, other): - return other.__class__ is self.__class__ and other.x==self.x and other.y==self.y - def __str__(self): - return "Bar(%d, %d)" % (self.x, self.y) - -class OldSchool: - def __init__(self, x, y): - self.x = x - self.y = y - def __eq__(self, other): - return other.__class__ is self.__class__ and other.x==self.x and other.y==self.y - -class OldSchoolWithoutCompare: - def __init__(self, x, y): - self.x = x - self.y = y - -class BarWithoutCompare(object): - def __init__(self, x, y): - self.x = x - self.y = y - def __str__(self): - return "Bar(%d, %d)" % (self.x, self.y) - - -class NotComparable(object): - def __init__(self, data): - self.data = data - - def __hash__(self): - return id(self) - - def __eq__(self, other): - return NotImplemented - - def __ne__(self, other): - return NotImplemented - - -class BrokenComparable(object): - def __init__(self, data): - self.data = data - - def __hash__(self): - return id(self) - - def __eq__(self, other): - raise NotImplementedError - - def __ne__(self, other): - raise NotImplementedError - diff --git a/lib/sqlalchemy/test/profiling.py b/lib/sqlalchemy/test/profiling.py deleted file mode 100644 index 6f839897d..000000000 --- a/lib/sqlalchemy/test/profiling.py +++ /dev/null @@ -1,221 +0,0 @@ -"""Profiling support for unit and performance tests. - -These are special purpose profiling methods which operate -in a more fine-grained way than nose's profiling plugin. - -""" - -import os, sys -from sqlalchemy.test.util import function_named, gc_collect -from nose import SkipTest - -__all__ = 'profiled', 'function_call_count', 'conditional_call_count' - -all_targets = set() -profile_config = { 'targets': set(), - 'report': True, - 'sort': ('time', 'calls'), - 'limit': None } -profiler = None - -def profiled(target=None, **target_opts): - """Optional function profiling. - - @profiled('label') - or - @profiled('label', report=True, sort=('calls',), limit=20) - - Enables profiling for a function when 'label' is targetted for - profiling. Report options can be supplied, and override the global - configuration and command-line options. - """ - - # manual or automatic namespacing by module would remove conflict issues - if target is None: - target = 'anonymous_target' - elif target in all_targets: - print "Warning: redefining profile target '%s'" % target - all_targets.add(target) - - filename = "%s.prof" % target - - def decorator(fn): - def profiled(*args, **kw): - if (target not in profile_config['targets'] and - not target_opts.get('always', None)): - return fn(*args, **kw) - - elapsed, load_stats, result = _profile( - filename, fn, *args, **kw) - - report = target_opts.get('report', profile_config['report']) - if report: - sort_ = target_opts.get('sort', profile_config['sort']) - limit = target_opts.get('limit', profile_config['limit']) - print "Profile report for target '%s' (%s)" % ( - target, filename) - - stats = load_stats() - stats.sort_stats(*sort_) - if limit: - stats.print_stats(limit) - else: - stats.print_stats() - #stats.print_callers() - os.unlink(filename) - return result - return function_named(profiled, fn.__name__) - return decorator - -def function_call_count(count=None, versions={}, variance=0.05): - """Assert a target for a test case's function call count. - - count - Optional, general target function call count. - - versions - Optional, a dictionary of Python version strings to counts, - for example:: - - { '2.5.1': 110, - '2.5': 100, - '2.4': 150 } - - The best match for the current running python will be used. - If none match, 'count' will be used as the fallback. - - variance - An +/- deviation percentage, defaults to 5%. - """ - - # this could easily dump the profile report if --verbose is in effect - - version_info = list(sys.version_info) - py_version = '.'.join([str(v) for v in sys.version_info]) - try: - from sqlalchemy.cprocessors import to_float - cextension = True - except ImportError: - cextension = False - - while version_info: - version = '.'.join([str(v) for v in version_info]) - if cextension: - version += "+cextension" - if version in versions: - count = versions[version] - break - version_info.pop() - - if count is None: - return lambda fn: fn - - def decorator(fn): - def counted(*args, **kw): - try: - filename = "%s.prof" % fn.__name__ - - elapsed, stat_loader, result = _profile( - filename, fn, *args, **kw) - - stats = stat_loader() - calls = stats.total_calls - - stats.sort_stats('calls', 'cumulative') - stats.print_stats() - #stats.print_callers() - deviance = int(count * variance) - if (calls < (count - deviance) or - calls > (count + deviance)): - raise AssertionError( - "Function call count %s not within %s%% " - "of expected %s. (Python version %s)" % ( - calls, (variance * 100), count, py_version)) - - return result - finally: - if os.path.exists(filename): - os.unlink(filename) - return function_named(counted, fn.__name__) - return decorator - -def conditional_call_count(discriminator, categories): - """Apply a function call count conditionally at runtime. - - Takes two arguments, a callable that returns a key value, and a dict - mapping key values to a tuple of arguments to function_call_count. - - The callable is not evaluated until the decorated function is actually - invoked. If the `discriminator` returns a key not present in the - `categories` dictionary, no call count assertion is applied. - - Useful for integration tests, where running a named test in isolation may - have a function count penalty not seen in the full suite, due to lazy - initialization in the DB-API, SA, etc. - """ - - def decorator(fn): - def at_runtime(*args, **kw): - criteria = categories.get(discriminator(), None) - if criteria is None: - return fn(*args, **kw) - - rewrapped = function_call_count(*criteria)(fn) - return rewrapped(*args, **kw) - return function_named(at_runtime, fn.__name__) - return decorator - - -def _profile(filename, fn, *args, **kw): - global profiler - if not profiler: - if sys.version_info > (2, 5): - try: - import cProfile - profiler = 'cProfile' - except ImportError: - pass - if not profiler: - try: - import hotshot - profiler = 'hotshot' - except ImportError: - profiler = 'skip' - - if profiler == 'skip': - raise SkipTest('Profiling not supported on this platform') - elif profiler == 'cProfile': - return _profile_cProfile(filename, fn, *args, **kw) - else: - return _profile_hotshot(filename, fn, *args, **kw) - -def _profile_cProfile(filename, fn, *args, **kw): - import cProfile, gc, pstats, time - - load_stats = lambda: pstats.Stats(filename) - gc_collect() - - began = time.time() - cProfile.runctx('result = fn(*args, **kw)', globals(), locals(), - filename=filename) - ended = time.time() - - return ended - began, load_stats, locals()['result'] - -def _profile_hotshot(filename, fn, *args, **kw): - import gc, hotshot, hotshot.stats, time - load_stats = lambda: hotshot.stats.load(filename) - - gc_collect() - prof = hotshot.Profile(filename) - began = time.time() - prof.start() - try: - result = fn(*args, **kw) - finally: - prof.stop() - ended = time.time() - prof.close() - - return ended - began, load_stats, result - diff --git a/lib/sqlalchemy/test/requires.py b/lib/sqlalchemy/test/requires.py deleted file mode 100644 index d29b7abc2..000000000 --- a/lib/sqlalchemy/test/requires.py +++ /dev/null @@ -1,318 +0,0 @@ -"""Global database feature support policy. - -Provides decorators to mark tests requiring specific feature support from the -target database. - -""" - -from testing import \ - _block_unconditionally as no_support, \ - _chain_decorators_on, \ - exclude, \ - emits_warning_on,\ - skip_if,\ - fails_on,\ - fails_on_everything_except - -import testing -import sys - -def deferrable_constraints(fn): - """Target database must support derferable constraints.""" - return _chain_decorators_on( - fn, - no_support('firebird', 'not supported by database'), - no_support('mysql', 'not supported by database'), - no_support('mssql', 'not supported by database'), - ) - -def foreign_keys(fn): - """Target database must support foreign keys.""" - return _chain_decorators_on( - fn, - no_support('sqlite', 'not supported by database'), - ) - - -def unbounded_varchar(fn): - """Target database must support VARCHAR with no length""" - return _chain_decorators_on( - fn, - no_support('firebird', 'not supported by database'), - no_support('oracle', 'not supported by database'), - no_support('mysql', 'not supported by database'), - ) - -def boolean_col_expressions(fn): - """Target database must support boolean expressions as columns""" - return _chain_decorators_on( - fn, - no_support('firebird', 'not supported by database'), - no_support('oracle', 'not supported by database'), - no_support('mssql', 'not supported by database'), - no_support('sybase', 'not supported by database'), - no_support('maxdb', 'FIXME: verify not supported by database'), - no_support('informix', 'not supported by database'), - ) - -def identity(fn): - """Target database must support GENERATED AS IDENTITY or a facsimile. - - Includes GENERATED AS IDENTITY, AUTOINCREMENT, AUTO_INCREMENT, or other - column DDL feature that fills in a DB-generated identifier at INSERT-time - without requiring pre-execution of a SEQUENCE or other artifact. - - """ - return _chain_decorators_on( - fn, - no_support('firebird', 'not supported by database'), - no_support('oracle', 'not supported by database'), - no_support('postgresql', 'not supported by database'), - no_support('sybase', 'not supported by database'), - ) - -def independent_cursors(fn): - """Target must support simultaneous, independent database cursors on a single connection.""" - - return _chain_decorators_on( - fn, - no_support('mssql+pyodbc', 'no driver support'), - no_support('mssql+mxodbc', 'no driver support'), - ) - -def independent_connections(fn): - """Target must support simultaneous, independent database connections.""" - - # This is also true of some configurations of UnixODBC and probably win32 - # ODBC as well. - return _chain_decorators_on( - fn, - no_support('sqlite', 'no driver support'), - exclude('mssql', '<', (9, 0, 0), - 'SQL Server 2005+ is required for independent connections'), - ) - -def row_triggers(fn): - """Target must support standard statement-running EACH ROW triggers.""" - return _chain_decorators_on( - fn, - # no access to same table - no_support('mysql', 'requires SUPER priv'), - exclude('mysql', '<', (5, 0, 10), 'not supported by database'), - - # huh? TODO: implement triggers for PG tests, remove this - no_support('postgresql', 'PG triggers need to be implemented for tests'), - ) - -def correlated_outer_joins(fn): - """Target must support an outer join to a subquery which correlates to the parent.""" - - return _chain_decorators_on( - fn, - no_support('oracle', 'Raises "ORA-01799: a column may not be outer-joined to a subquery"') - ) - -def savepoints(fn): - """Target database must support savepoints.""" - return _chain_decorators_on( - fn, - emits_warning_on('mssql', 'Savepoint support in mssql is experimental and may lead to data loss.'), - no_support('access', 'not supported by database'), - no_support('sqlite', 'not supported by database'), - no_support('sybase', 'FIXME: guessing, needs confirmation'), - exclude('mysql', '<', (5, 0, 3), 'not supported by database'), - exclude('informix', '<', (11, 55, 'xC3'), 'not supported by database'), - ) - -def denormalized_names(fn): - """Target database must have 'denormalized', i.e. UPPERCASE as case insensitive names.""" - - return skip_if( - lambda: not testing.db.dialect.requires_name_normalize, - "Backend does not require denomralized names." - )(fn) - -def schemas(fn): - """Target database must support external schemas, and have one named 'test_schema'.""" - - return _chain_decorators_on( - fn, - no_support('sqlite', 'no schema support'), - no_support('firebird', 'no schema support') - ) - -def sequences(fn): - """Target database must support SEQUENCEs.""" - return _chain_decorators_on( - fn, - no_support('access', 'no SEQUENCE support'), - no_support('mssql', 'no SEQUENCE support'), - no_support('mysql', 'no SEQUENCE support'), - no_support('sqlite', 'no SEQUENCE support'), - no_support('sybase', 'no SEQUENCE support'), - no_support('informix', 'no SEQUENCE support'), - ) - -def update_nowait(fn): - """Target database must support SELECT...FOR UPDATE NOWAIT""" - return _chain_decorators_on( - fn, - no_support('access', 'no FOR UPDATE NOWAIT support'), - no_support('firebird', 'no FOR UPDATE NOWAIT support'), - no_support('mssql', 'no FOR UPDATE NOWAIT support'), - no_support('mysql', 'no FOR UPDATE NOWAIT support'), - no_support('sqlite', 'no FOR UPDATE NOWAIT support'), - no_support('sybase', 'no FOR UPDATE NOWAIT support'), - ) - -def subqueries(fn): - """Target database must support subqueries.""" - return _chain_decorators_on( - fn, - exclude('mysql', '<', (4, 1, 1), 'no subquery support'), - ) - -def intersect(fn): - """Target database must support INTERSECT or equivlaent.""" - return _chain_decorators_on( - fn, - fails_on('firebird', 'no support for INTERSECT'), - fails_on('mysql', 'no support for INTERSECT'), - fails_on('sybase', 'no support for INTERSECT'), - fails_on('informix', 'no support for INTERSECT'), - ) - -def except_(fn): - """Target database must support EXCEPT or equivlaent (i.e. MINUS).""" - return _chain_decorators_on( - fn, - fails_on('firebird', 'no support for EXCEPT'), - fails_on('mysql', 'no support for EXCEPT'), - fails_on('sybase', 'no support for EXCEPT'), - fails_on('informix', 'no support for EXCEPT'), - ) - -def offset(fn): - """Target database must support some method of adding OFFSET or equivalent to a result set.""" - return _chain_decorators_on( - fn, - fails_on('sybase', 'no support for OFFSET or equivalent'), - ) - -def returning(fn): - return _chain_decorators_on( - fn, - no_support('access', 'not supported by database'), - no_support('sqlite', 'not supported by database'), - no_support('mysql', 'not supported by database'), - no_support('maxdb', 'not supported by database'), - no_support('sybase', 'not supported by database'), - no_support('informix', 'not supported by database'), - ) - -def two_phase_transactions(fn): - """Target database must support two-phase transactions.""" - return _chain_decorators_on( - fn, - no_support('access', 'not supported by database'), - no_support('firebird', 'no SA implementation'), - no_support('maxdb', 'not supported by database'), - no_support('mssql', 'FIXME: guessing, needs confirmation'), - no_support('oracle', 'no SA implementation'), - no_support('sqlite', 'not supported by database'), - no_support('sybase', 'FIXME: guessing, needs confirmation'), - no_support('postgresql+zxjdbc', 'FIXME: JDBC driver confuses the transaction state, may ' - 'need separate XA implementation'), - exclude('mysql', '<', (5, 0, 3), 'not supported by database'), - ) - -def unicode_connections(fn): - """Target driver must support some encoding of Unicode across the wire.""" - # TODO: expand to exclude MySQLdb versions w/ broken unicode - return _chain_decorators_on( - fn, - exclude('mysql', '<', (4, 1, 1), 'no unicode connection support'), - ) - -def unicode_ddl(fn): - """Target driver must support some encoding of Unicode across the wire.""" - # TODO: expand to exclude MySQLdb versions w/ broken unicode - return _chain_decorators_on( - fn, - no_support('maxdb', 'database support flakey'), - no_support('oracle', 'FIXME: no support in database?'), - no_support('sybase', 'FIXME: guessing, needs confirmation'), - no_support('mssql+pymssql', 'no FreeTDS support'), - exclude('mysql', '<', (4, 1, 1), 'no unicode connection support'), - ) - -def sane_rowcount(fn): - return _chain_decorators_on( - fn, - skip_if(lambda: not testing.db.dialect.supports_sane_rowcount) - ) - -def cextensions(fn): - return _chain_decorators_on( - fn, - skip_if(lambda: not _has_cextensions(), "C extensions not installed") - ) - -def dbapi_lastrowid(fn): - return _chain_decorators_on( - fn, - fails_on_everything_except('mysql+mysqldb', 'mysql+oursql', 'sqlite+pysqlite') - ) - -def sane_multi_rowcount(fn): - return _chain_decorators_on( - fn, - skip_if(lambda: not testing.db.dialect.supports_sane_multi_rowcount) - ) - -def reflects_pk_names(fn): - """Target driver reflects the name of primary key constraints.""" - return _chain_decorators_on( - fn, - fails_on_everything_except('postgresql', 'oracle') - ) - -def python2(fn): - return _chain_decorators_on( - fn, - skip_if( - lambda: sys.version_info >= (3,), - "Python version 2.xx is required." - ) - ) - -def python26(fn): - return _chain_decorators_on( - fn, - skip_if( - lambda: sys.version_info < (2, 6), - "Python version 2.6 or greater is required" - ) - ) - -def _has_cextensions(): - try: - from sqlalchemy import cresultproxy, cprocessors - return True - except ImportError: - return False - -def _has_sqlite(): - from sqlalchemy import create_engine - try: - e = create_engine('sqlite://') - return True - except ImportError: - return False - -def sqlite(fn): - return _chain_decorators_on( - fn, - skip_if(lambda: not _has_sqlite()) - ) - diff --git a/lib/sqlalchemy/test/schema.py b/lib/sqlalchemy/test/schema.py deleted file mode 100644 index d33d75e2c..000000000 --- a/lib/sqlalchemy/test/schema.py +++ /dev/null @@ -1,79 +0,0 @@ -"""Enhanced versions of schema.Table and schema.Column which establish -desired state for different backends. -""" - -from sqlalchemy.test import testing -from sqlalchemy import schema - -__all__ = 'Table', 'Column', - -table_options = {} - -def Table(*args, **kw): - """A schema.Table wrapper/hook for dialect-specific tweaks.""" - - test_opts = dict([(k,kw.pop(k)) for k in kw.keys() - if k.startswith('test_')]) - - kw.update(table_options) - - if testing.against('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' - - # Apply some default cascading rules for self-referential foreign keys. - # MySQL InnoDB has some issues around seleting self-refs too. - if testing.against('firebird'): - table_name = args[0] - unpack = (testing.config.db.dialect. - identifier_preparer.unformat_identifiers) - - # Only going after ForeignKeys in Columns. May need to - # expand to ForeignKeyConstraint too. - fks = [fk - for col in args if isinstance(col, schema.Column) - for fk in col.foreign_keys] - - for fk in fks: - # root around in raw spec - ref = fk._colspec - if isinstance(ref, schema.Column): - name = ref.table.name - else: - # take just the table name: on FB there cannot be - # a schema, so the first element is always the - # table name, possibly followed by the field name - name = unpack(ref)[0] - if name == table_name: - if fk.ondelete is None: - fk.ondelete = 'CASCADE' - if fk.onupdate is None: - fk.onupdate = 'CASCADE' - - return schema.Table(*args, **kw) - - -def Column(*args, **kw): - """A schema.Column wrapper/hook for dialect-specific tweaks.""" - - test_opts = dict([(k,kw.pop(k)) for k in kw.keys() - if k.startswith('test_')]) - - col = schema.Column(*args, **kw) - if 'test_needs_autoincrement' in test_opts and \ - kw.get('primary_key', False) and \ - testing.against('firebird', 'oracle'): - def add_seq(tbl, c): - c._init_items( - schema.Sequence(_truncate_name(testing.db.dialect, tbl.name + '_' + c.name + '_seq'), optional=True) - ) - col._on_table_attach(add_seq) - return col - -def _truncate_name(dialect, name): - if len(name) > dialect.max_identifier_length: - return name[0:max(dialect.max_identifier_length - 6, 0)] + "_" + hex(hash(name) % 64)[2:] - else: - return name - diff --git a/lib/sqlalchemy/test/testing.py b/lib/sqlalchemy/test/testing.py deleted file mode 100644 index 46723baa0..000000000 --- a/lib/sqlalchemy/test/testing.py +++ /dev/null @@ -1,797 +0,0 @@ -"""TestCase and TestSuite artifacts and testing decorators.""" - -import itertools -import operator -import re -import sys -import types -import warnings -from cStringIO import StringIO - -from test.bootstrap import config -from sqlalchemy.test import assertsql, util as testutil -from sqlalchemy.util import function_named, py3k -from engines import drop_all_tables - -from sqlalchemy import exc as sa_exc, util, types as sqltypes, schema, pool, orm -from sqlalchemy.engine import default -from nose import SkipTest - - -_ops = { '<': operator.lt, - '>': operator.gt, - '==': operator.eq, - '!=': operator.ne, - '<=': operator.le, - '>=': operator.ge, - 'in': operator.contains, - 'between': lambda val, pair: val >= pair[0] and val <= pair[1], - } - -# sugar ('testing.db'); set here by config() at runtime -db = None - -# more sugar, installed by __init__ -requires = None - -def fails_if(callable_, reason=None): - """Mark a test as expected to fail if callable_ returns True. - - If the callable returns false, the test is run and reported as normal. - However if the callable returns true, the test is expected to fail and the - unit test logic is inverted: if the test fails, a success is reported. If - the test succeeds, a failure is reported. - """ - - docstring = getattr(callable_, '__doc__', None) or callable_.__name__ - description = docstring.split('\n')[0] - - def decorate(fn): - fn_name = fn.__name__ - def maybe(*args, **kw): - if not callable_(): - return fn(*args, **kw) - else: - try: - fn(*args, **kw) - except Exception, ex: - print ("'%s' failed as expected (condition: %s): %s " % ( - fn_name, description, str(ex))) - return True - else: - raise AssertionError( - "Unexpected success for '%s' (condition: %s)" % - (fn_name, description)) - return function_named(maybe, fn_name) - return decorate - - -def future(fn): - """Mark a test as expected to unconditionally fail. - - Takes no arguments, omit parens when using as a decorator. - """ - - fn_name = fn.__name__ - def decorated(*args, **kw): - try: - fn(*args, **kw) - except Exception, ex: - print ("Future test '%s' failed as expected: %s " % ( - fn_name, str(ex))) - return True - else: - raise AssertionError( - "Unexpected success for future test '%s'" % fn_name) - return function_named(decorated, fn_name) - -def db_spec(*dbs): - dialects = set([x for x in dbs if '+' not in x]) - drivers = set([x[1:] for x in dbs if x.startswith('+')]) - specs = set([tuple(x.split('+')) for x in dbs if '+' in x and x not in drivers]) - - def check(engine): - return engine.name in dialects or \ - engine.driver in drivers or \ - (engine.name, engine.driver) in specs - - return check - - -def fails_on(dbs, reason): - """Mark a test as expected to fail on the specified database - implementation. - - Unlike ``crashes``, tests marked as ``fails_on`` will be run - for the named databases. The test is expected to fail and the unit test - logic is inverted: if the test fails, a success is reported. If the test - succeeds, a failure is reported. - """ - - spec = db_spec(dbs) - - def decorate(fn): - fn_name = fn.__name__ - def maybe(*args, **kw): - if not spec(config.db): - return fn(*args, **kw) - else: - try: - fn(*args, **kw) - except Exception, ex: - print ("'%s' failed as expected on DB implementation " - "'%s+%s': %s" % ( - fn_name, config.db.name, config.db.driver, reason)) - return True - else: - raise AssertionError( - "Unexpected success for '%s' on DB implementation '%s+%s'" % - (fn_name, config.db.name, config.db.driver)) - return function_named(maybe, fn_name) - return decorate - -def fails_on_everything_except(*dbs): - """Mark a test as expected to fail on most database implementations. - - Like ``fails_on``, except failure is the expected outcome on all - databases except those listed. - """ - - spec = db_spec(*dbs) - - def decorate(fn): - fn_name = fn.__name__ - def maybe(*args, **kw): - if spec(config.db): - return fn(*args, **kw) - else: - try: - fn(*args, **kw) - except Exception, ex: - print ("'%s' failed as expected on DB implementation " - "'%s+%s': %s" % ( - fn_name, config.db.name, config.db.driver, str(ex))) - return True - else: - raise AssertionError( - "Unexpected success for '%s' on DB implementation '%s+%s'" % - (fn_name, config.db.name, config.db.driver)) - return function_named(maybe, fn_name) - return decorate - -def crashes(db, reason): - """Mark a test as unsupported by a database implementation. - - ``crashes`` tests will be skipped unconditionally. Use for feature tests - that cause deadlocks or other fatal problems. - - """ - carp = _should_carp_about_exclusion(reason) - spec = db_spec(db) - def decorate(fn): - fn_name = fn.__name__ - def maybe(*args, **kw): - if spec(config.db): - msg = "'%s' unsupported on DB implementation '%s+%s': %s" % ( - fn_name, config.db.name, config.db.driver, reason) - print msg - if carp: - print >> sys.stderr, msg - return True - else: - return fn(*args, **kw) - return function_named(maybe, fn_name) - return decorate - -def _block_unconditionally(db, reason): - """Mark a test as unsupported by a database implementation. - - Will never run the test against any version of the given database, ever, - no matter what. Use when your assumptions are infallible; past, present - and future. - - """ - carp = _should_carp_about_exclusion(reason) - spec = db_spec(db) - def decorate(fn): - fn_name = fn.__name__ - def maybe(*args, **kw): - if spec(config.db): - msg = "'%s' unsupported on DB implementation '%s+%s': %s" % ( - fn_name, config.db.name, config.db.driver, reason) - print msg - if carp: - print >> sys.stderr, msg - return True - else: - return fn(*args, **kw) - return function_named(maybe, fn_name) - return decorate - -def only_on(dbs, reason): - carp = _should_carp_about_exclusion(reason) - spec = db_spec(*util.to_list(dbs)) - def decorate(fn): - fn_name = fn.__name__ - def maybe(*args, **kw): - if spec(config.db): - return fn(*args, **kw) - else: - msg = "'%s' unsupported on DB implementation '%s+%s': %s" % ( - fn_name, config.db.name, config.db.driver, reason) - print msg - if carp: - print >> sys.stderr, msg - return True - return function_named(maybe, fn_name) - return decorate - -def exclude(db, op, spec, reason): - """Mark a test as unsupported by specific database server versions. - - Stackable, both with other excludes and other decorators. Examples:: - - # Not supported by mydb versions less than 1, 0 - @exclude('mydb', '<', (1,0)) - # Other operators work too - @exclude('bigdb', '==', (9,0,9)) - @exclude('yikesdb', 'in', ((0, 3, 'alpha2'), (0, 3, 'alpha3'))) - - """ - carp = _should_carp_about_exclusion(reason) - - def decorate(fn): - fn_name = fn.__name__ - def maybe(*args, **kw): - if _is_excluded(db, op, spec): - msg = "'%s' unsupported on DB %s version '%s': %s" % ( - fn_name, config.db.name, _server_version(), reason) - print msg - if carp: - print >> sys.stderr, msg - return True - else: - return fn(*args, **kw) - return function_named(maybe, fn_name) - return decorate - -def _should_carp_about_exclusion(reason): - """Guard against forgotten exclusions.""" - assert reason - for _ in ('todo', 'fixme', 'xxx'): - if _ in reason.lower(): - return True - else: - if len(reason) < 4: - return True - -def _is_excluded(db, op, spec): - """Return True if the configured db matches an exclusion specification. - - db: - A dialect name - op: - An operator or stringified operator, such as '==' - spec: - A value that will be compared to the dialect's server_version_info - using the supplied operator. - - Examples:: - # Not supported by mydb versions less than 1, 0 - _is_excluded('mydb', '<', (1,0)) - # Other operators work too - _is_excluded('bigdb', '==', (9,0,9)) - _is_excluded('yikesdb', 'in', ((0, 3, 'alpha2'), (0, 3, 'alpha3'))) - """ - - vendor_spec = db_spec(db) - - if not vendor_spec(config.db): - return False - - version = _server_version() - - oper = hasattr(op, '__call__') and op or _ops[op] - return oper(version, spec) - -def _server_version(bind=None): - """Return a server_version_info tuple.""" - - if bind is None: - bind = config.db - - # force metadata to be retrieved - conn = bind.connect() - version = getattr(bind.dialect, 'server_version_info', ()) - conn.close() - return version - -def skip_if(predicate, reason=None): - """Skip a test if predicate is true.""" - reason = reason or predicate.__name__ - carp = _should_carp_about_exclusion(reason) - - def decorate(fn): - fn_name = fn.__name__ - def maybe(*args, **kw): - if predicate(): - msg = "'%s' skipped on DB %s version '%s': %s" % ( - fn_name, config.db.name, _server_version(), reason) - print msg - if carp: - print >> sys.stderr, msg - return True - else: - return fn(*args, **kw) - return function_named(maybe, fn_name) - return decorate - -def emits_warning(*messages): - """Mark a test as emitting a warning. - - With no arguments, squelches all SAWarning failures. Or pass one or more - strings; these will be matched to the root of the warning description by - warnings.filterwarnings(). - """ - - # TODO: it would be nice to assert that a named warning was - # emitted. should work with some monkeypatching of warnings, - # and may work on non-CPython if they keep to the spirit of - # warnings.showwarning's docstring. - # - update: jython looks ok, it uses cpython's module - def decorate(fn): - def safe(*args, **kw): - # todo: should probably be strict about this, too - filters = [dict(action='ignore', - category=sa_exc.SAPendingDeprecationWarning)] - if not messages: - filters.append(dict(action='ignore', - category=sa_exc.SAWarning)) - else: - filters.extend(dict(action='ignore', - message=message, - category=sa_exc.SAWarning) - for message in messages) - for f in filters: - warnings.filterwarnings(**f) - try: - return fn(*args, **kw) - finally: - resetwarnings() - return function_named(safe, fn.__name__) - return decorate - -def emits_warning_on(db, *warnings): - """Mark a test as emitting a warning on a specific dialect. - - With no arguments, squelches all SAWarning failures. Or pass one or more - strings; these will be matched to the root of the warning description by - warnings.filterwarnings(). - """ - spec = db_spec(db) - - def decorate(fn): - def maybe(*args, **kw): - if isinstance(db, basestring): - if not spec(config.db): - return fn(*args, **kw) - else: - wrapped = emits_warning(*warnings)(fn) - return wrapped(*args, **kw) - else: - if not _is_excluded(*db): - return fn(*args, **kw) - else: - wrapped = emits_warning(*warnings)(fn) - return wrapped(*args, **kw) - return function_named(maybe, fn.__name__) - return decorate - -def uses_deprecated(*messages): - """Mark a test as immune from fatal deprecation warnings. - - With no arguments, squelches all SADeprecationWarning failures. - Or pass one or more strings; these will be matched to the root - of the warning description by warnings.filterwarnings(). - - As a special case, you may pass a function name prefixed with // - and it will be re-written as needed to match the standard warning - verbiage emitted by the sqlalchemy.util.deprecated decorator. - """ - - - def decorate(fn): - def safe(*args, **kw): - # todo: should probably be strict about this, too - filters = [dict(action='ignore', - category=sa_exc.SAPendingDeprecationWarning)] - if not messages: - filters.append(dict(action='ignore', - category=sa_exc.SADeprecationWarning)) - else: - filters.extend( - [dict(action='ignore', - message=message, - category=sa_exc.SADeprecationWarning) - for message in - [ (m.startswith('//') and - ('Call to deprecated function ' + m[2:]) or m) - for m in messages] ]) - - for f in filters: - warnings.filterwarnings(**f) - try: - return fn(*args, **kw) - finally: - resetwarnings() - return function_named(safe, fn.__name__) - return decorate - -def resetwarnings(): - """Reset warning behavior to testing defaults.""" - - warnings.filterwarnings('ignore', - category=sa_exc.SAPendingDeprecationWarning) - warnings.filterwarnings('error', category=sa_exc.SADeprecationWarning) - warnings.filterwarnings('error', category=sa_exc.SAWarning) - -# warnings.simplefilter('error') - - -def global_cleanup_assertions(): - """Check things that have to be finalized at the end of a test suite. - - Hardcoded at the moment, a modular system can be built here - to support things like PG prepared transactions, tables all - dropped, etc. - - """ - - testutil.lazy_gc() - assert not pool._refs - - - -def against(*queries): - """Boolean predicate, compares to testing database configuration. - - Given one or more dialect names, returns True if one is the configured - database engine. - - Also supports comparison to database version when provided with one or - more 3-tuples of dialect name, operator, and version specification:: - - testing.against('mysql', 'postgresql') - testing.against(('mysql', '>=', (5, 0, 0)) - """ - - for query in queries: - if isinstance(query, basestring): - if db_spec(query)(config.db): - return True - else: - name, op, spec = query - if not db_spec(name)(config.db): - continue - - have = _server_version() - - oper = hasattr(op, '__call__') and op or _ops[op] - if oper(have, spec): - return True - return False - -def _chain_decorators_on(fn, *decorators): - """Apply a series of decorators to fn, returning a decorated function.""" - for decorator in reversed(decorators): - fn = decorator(fn) - return fn - -def rowset(results): - """Converts the results of sql execution into a plain set of column tuples. - - Useful for asserting the results of an unordered query. - """ - - return set([tuple(row) for row in results]) - - -def eq_(a, b, msg=None): - """Assert a == b, with repr messaging on failure.""" - assert a == b, msg or "%r != %r" % (a, b) - -def ne_(a, b, msg=None): - """Assert a != b, with repr messaging on failure.""" - assert a != b, msg or "%r == %r" % (a, b) - -def is_(a, b, msg=None): - """Assert a is b, with repr messaging on failure.""" - assert a is b, msg or "%r is not %r" % (a, b) - -def is_not_(a, b, msg=None): - """Assert a is not b, with repr messaging on failure.""" - assert a is not b, msg or "%r is %r" % (a, b) - -def startswith_(a, fragment, msg=None): - """Assert a.startswith(fragment), with repr messaging on failure.""" - assert a.startswith(fragment), msg or "%r does not start with %r" % ( - a, fragment) - -def assert_raises(except_cls, callable_, *args, **kw): - try: - callable_(*args, **kw) - success = False - except except_cls, e: - success = True - - # assert outside the block so it works for AssertionError too ! - assert success, "Callable did not raise an exception" - -def assert_raises_message(except_cls, msg, callable_, *args, **kwargs): - try: - callable_(*args, **kwargs) - assert False, "Callable did not raise an exception" - except except_cls, e: - assert re.search(msg, str(e)), "%r !~ %s" % (msg, e) - print str(e) - -def fail(msg): - assert False, msg - -def fixture(table, columns, *rows): - """Insert data into table after creation.""" - def onload(event, schema_item, connection): - insert = table.insert() - column_names = [col.key for col in columns] - connection.execute(insert, [dict(zip(column_names, column_values)) - for column_values in rows]) - table.append_ddl_listener('after-create', onload) - -def provide_metadata(fn): - """Provides a bound MetaData object for a single test, - drops it afterwards.""" - def maybe(*args, **kw): - metadata = schema.MetaData(db) - context = dict(fn.func_globals) - context['metadata'] = metadata - # jython bug #1034 - rebound = types.FunctionType( - fn.func_code, context, fn.func_name, fn.func_defaults, - fn.func_closure) - try: - return rebound(*args, **kw) - finally: - metadata.drop_all() - return function_named(maybe, fn.__name__) - -def resolve_artifact_names(fn): - """Decorator, augment function globals with tables and classes. - - Swaps out the function's globals at execution time. The 'global' statement - will not work as expected inside a decorated function. - - """ - # This could be automatically applied to framework and test_ methods in - # the MappedTest-derived test suites but... *some* explicitness for this - # magic is probably good. Especially as 'global' won't work- these - # rebound functions aren't regular Python.. - # - # Also: it's lame that CPython accepts a dict-subclass for globals, but - # only calls dict methods. That would allow 'global' to pass through to - # the func_globals. - def resolved(*args, **kwargs): - self = args[0] - context = dict(fn.func_globals) - for source in self._artifact_registries: - context.update(getattr(self, source)) - # jython bug #1034 - rebound = types.FunctionType( - fn.func_code, context, fn.func_name, fn.func_defaults, - fn.func_closure) - return rebound(*args, **kwargs) - return function_named(resolved, fn.func_name) - -class adict(dict): - """Dict keys available as attributes. Shadows.""" - def __getattribute__(self, key): - try: - return self[key] - except KeyError: - return dict.__getattribute__(self, key) - - def get_all(self, *keys): - return tuple([self[key] for key in keys]) - - -class TestBase(object): - # A sequence of database names to always run, regardless of the - # constraints below. - __whitelist__ = () - - # A sequence of requirement names matching testing.requires decorators - __requires__ = () - - # A sequence of dialect names to exclude from the test class. - __unsupported_on__ = () - - # If present, test class is only runnable for the *single* specified - # dialect. If you need multiple, use __unsupported_on__ and invert. - __only_on__ = None - - # A sequence of no-arg callables. If any are True, the entire testcase is - # skipped. - __skip_if__ = None - - _artifact_registries = () - - def assert_(self, val, msg=None): - assert val, msg - -class AssertsCompiledSQL(object): - def assert_compile(self, clause, result, params=None, checkparams=None, dialect=None, use_default_dialect=False): - if use_default_dialect: - dialect = default.DefaultDialect() - - if dialect is None: - dialect = getattr(self, '__dialect__', None) - - kw = {} - if params is not None: - kw['column_keys'] = params.keys() - - if isinstance(clause, orm.Query): - context = clause._compile_context() - context.statement.use_labels = True - clause = context.statement - - c = clause.compile(dialect=dialect, **kw) - - param_str = repr(getattr(c, 'params', {})) - # Py3K - #param_str = param_str.encode('utf-8').decode('ascii', 'ignore') - - print "\nSQL String:\n" + str(c) + param_str - - cc = re.sub(r'[\n\t]', '', str(c)) - - eq_(cc, result, "%r != %r on dialect %r" % (cc, result, dialect)) - - if checkparams is not None: - eq_(c.construct_params(params), checkparams) - -class ComparesTables(object): - def assert_tables_equal(self, table, reflected_table, strict_types=False): - assert len(table.c) == len(reflected_table.c) - for c, reflected_c in zip(table.c, reflected_table.c): - eq_(c.name, reflected_c.name) - assert reflected_c is reflected_table.c[c.name] - eq_(c.primary_key, reflected_c.primary_key) - eq_(c.nullable, reflected_c.nullable) - - if strict_types: - assert type(reflected_c.type) is type(c.type), \ - "Type '%s' doesn't correspond to type '%s'" % (reflected_c.type, c.type) - else: - self.assert_types_base(reflected_c, c) - - if isinstance(c.type, sqltypes.String): - eq_(c.type.length, reflected_c.type.length) - - eq_(set([f.column.name for f in c.foreign_keys]), set([f.column.name for f in reflected_c.foreign_keys])) - if c.server_default: - assert isinstance(reflected_c.server_default, - schema.FetchedValue) - - assert len(table.primary_key) == len(reflected_table.primary_key) - for c in table.primary_key: - assert reflected_table.primary_key.columns[c.name] is not None - - def assert_types_base(self, c1, c2): - assert c1.type._compare_type_affinity(c2.type),\ - "On column %r, type '%s' doesn't correspond to type '%s'" % \ - (c1.name, c1.type, c2.type) - -class AssertsExecutionResults(object): - def assert_result(self, result, class_, *objects): - result = list(result) - print repr(result) - self.assert_list(result, class_, objects) - - def assert_list(self, result, class_, list): - self.assert_(len(result) == len(list), - "result list is not the same size as test list, " + - "for class " + class_.__name__) - for i in range(0, len(list)): - self.assert_row(class_, result[i], list[i]) - - def assert_row(self, class_, rowobj, desc): - self.assert_(rowobj.__class__ is class_, - "item class is not " + repr(class_)) - for key, value in desc.iteritems(): - if isinstance(value, tuple): - if isinstance(value[1], list): - self.assert_list(getattr(rowobj, key), value[0], value[1]) - else: - self.assert_row(value[0], getattr(rowobj, key), value[1]) - else: - self.assert_(getattr(rowobj, key) == value, - "attribute %s value %s does not match %s" % ( - key, getattr(rowobj, key), value)) - - def assert_unordered_result(self, result, cls, *expected): - """As assert_result, but the order of objects is not considered. - - The algorithm is very expensive but not a big deal for the small - numbers of rows that the test suite manipulates. - """ - - class frozendict(dict): - def __hash__(self): - return id(self) - - found = util.IdentitySet(result) - expected = set([frozendict(e) for e in expected]) - - for wrong in itertools.ifilterfalse(lambda o: type(o) == cls, found): - fail('Unexpected type "%s", expected "%s"' % ( - type(wrong).__name__, cls.__name__)) - - if len(found) != len(expected): - fail('Unexpected object count "%s", expected "%s"' % ( - len(found), len(expected))) - - NOVALUE = object() - def _compare_item(obj, spec): - for key, value in spec.iteritems(): - if isinstance(value, tuple): - try: - self.assert_unordered_result( - getattr(obj, key), value[0], *value[1]) - except AssertionError: - return False - else: - if getattr(obj, key, NOVALUE) != value: - return False - return True - - for expected_item in expected: - for found_item in found: - if _compare_item(found_item, expected_item): - found.remove(found_item) - break - else: - fail( - "Expected %s instance with attributes %s not found." % ( - cls.__name__, repr(expected_item))) - return True - - def assert_sql_execution(self, db, callable_, *rules): - assertsql.asserter.add_rules(rules) - try: - callable_() - assertsql.asserter.statement_complete() - finally: - assertsql.asserter.clear_rules() - - def assert_sql(self, db, callable_, list_, with_sequences=None): - if with_sequences is not None and config.db.name in ('firebird', 'oracle', 'postgresql'): - rules = with_sequences - else: - rules = list_ - - newrules = [] - for rule in rules: - if isinstance(rule, dict): - newrule = assertsql.AllOf(*[ - assertsql.ExactSQL(k, v) for k, v in rule.iteritems() - ]) - else: - newrule = assertsql.ExactSQL(*rule) - newrules.append(newrule) - - self.assert_sql_execution(db, callable_, *newrules) - - def assert_sql_count(self, db, callable_, count): - self.assert_sql_execution(db, callable_, assertsql.CountStatements(count)) - - diff --git a/lib/sqlalchemy/test/util.py b/lib/sqlalchemy/test/util.py deleted file mode 100644 index f2b6b49ea..000000000 --- a/lib/sqlalchemy/test/util.py +++ /dev/null @@ -1,76 +0,0 @@ -from sqlalchemy.util import jython, function_named - -import gc -import time -import random - -if jython: - def gc_collect(*args): - """aggressive gc.collect for tests.""" - gc.collect() - time.sleep(0.1) - gc.collect() - gc.collect() - return 0 - - # "lazy" gc, for VM's that don't GC on refcount == 0 - lazy_gc = gc_collect - -else: - # assume CPython - straight gc.collect, lazy_gc() is a pass - gc_collect = gc.collect - def lazy_gc(): - pass - -def picklers(): - picklers = set() - # Py2K - try: - import cPickle - picklers.add(cPickle) - except ImportError: - pass - # end Py2K - import pickle - picklers.add(pickle) - - # yes, this thing needs this much testing - for pickle in picklers: - for protocol in -1, 0, 1, 2: - yield pickle.loads, lambda d:pickle.dumps(d, protocol) - - -def round_decimal(value, prec): - if isinstance(value, float): - return round(value, prec) - - import decimal - - # can also use shift() here but that is 2.6 only - return (value * decimal.Decimal("1" + "0" * prec)).to_integral(decimal.ROUND_FLOOR) / \ - pow(10, prec) - -class RandomSet(set): - def __iter__(self): - l = list(set.__iter__(self)) - random.shuffle(l) - return iter(l) - - def pop(self): - index = random.randint(0, len(self) - 1) - item = list(set.__iter__(self))[index] - self.remove(item) - return item - - def union(self, other): - return RandomSet(set.union(self, other)) - - def difference(self, other): - return RandomSet(set.difference(self, other)) - - def intersection(self, other): - return RandomSet(set.intersection(self, other)) - - def copy(self): - return RandomSet(self) - \ No newline at end of file diff --git a/sqla_nose.py b/sqla_nose.py index 6482958cb..e6f60e476 100755 --- a/sqla_nose.py +++ b/sqla_nose.py @@ -2,8 +2,8 @@ """ nose runner script. -This script is a front-end to "nosetests" which doesn't -require that SQLA's testing plugin be installed via setuptools. +This script is a front-end to "nosetests" which +installs SQLAlchemy's testing plugin into the local environment. """ import sys diff --git a/test/aaa_profiling/test_compiler.py b/test/aaa_profiling/test_compiler.py index bc589c0b2..a7422b49e 100644 --- a/test/aaa_profiling/test_compiler.py +++ b/test/aaa_profiling/test_compiler.py @@ -1,5 +1,5 @@ from sqlalchemy import * -from sqlalchemy.test import * +from test.lib import * class CompileTest(TestBase, AssertsExecutionResults): diff --git a/test/aaa_profiling/test_memusage.py b/test/aaa_profiling/test_memusage.py index 5fa40a997..4b443780a 100644 --- a/test/aaa_profiling/test_memusage.py +++ b/test/aaa_profiling/test_memusage.py @@ -1,17 +1,17 @@ -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from sqlalchemy.orm import mapper, relationship, create_session, \ clear_mappers, sessionmaker, class_mapper from sqlalchemy.orm.mapper import _mapper_registry from sqlalchemy.orm.session import _sessions from sqlalchemy.util import jython import operator -from sqlalchemy.test import testing, engines +from test.lib import testing, engines from sqlalchemy import MetaData, Integer, String, ForeignKey, \ PickleType, create_engine, Unicode -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column import sqlalchemy as sa from sqlalchemy.sql import column -from sqlalchemy.test.util import gc_collect +from test.lib.util import gc_collect import gc import weakref from test.orm import _base diff --git a/test/aaa_profiling/test_orm.py b/test/aaa_profiling/test_orm.py index f2b876837..1b39f6edb 100644 --- a/test/aaa_profiling/test_orm.py +++ b/test/aaa_profiling/test_orm.py @@ -1,11 +1,11 @@ -from sqlalchemy.test.testing import eq_, assert_raises, \ +from test.lib.testing import eq_, assert_raises, \ assert_raises_message from sqlalchemy import exc as sa_exc, util, Integer, String, ForeignKey from sqlalchemy.orm import exc as orm_exc, mapper, relationship, \ sessionmaker -from sqlalchemy.test import testing, profiling +from test.lib import testing, profiling from test.orm import _base -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column class MergeTest(_base.MappedTest): diff --git a/test/aaa_profiling/test_pool.py b/test/aaa_profiling/test_pool.py index bc3c12d57..a63a643ce 100644 --- a/test/aaa_profiling/test_pool.py +++ b/test/aaa_profiling/test_pool.py @@ -1,5 +1,5 @@ from sqlalchemy import * -from sqlalchemy.test import * +from test.lib import * from sqlalchemy.pool import QueuePool diff --git a/test/aaa_profiling/test_resultset.py b/test/aaa_profiling/test_resultset.py index bd9d3ae50..9904267dc 100644 --- a/test/aaa_profiling/test_resultset.py +++ b/test/aaa_profiling/test_resultset.py @@ -1,5 +1,5 @@ from sqlalchemy import * -from sqlalchemy.test import * +from test.lib import * NUM_FIELDS = 10 NUM_RECORDS = 1000 diff --git a/test/aaa_profiling/test_zoomark.py b/test/aaa_profiling/test_zoomark.py index dc990e983..ec489beb1 100644 --- a/test/aaa_profiling/test_zoomark.py +++ b/test/aaa_profiling/test_zoomark.py @@ -7,7 +7,7 @@ import datetime import sys import time from sqlalchemy import * -from sqlalchemy.test import * +from test.lib import * ITERATIONS = 1 dbapi_session = engines.ReplayableSession() metadata = None diff --git a/test/aaa_profiling/test_zoomark_orm.py b/test/aaa_profiling/test_zoomark_orm.py index 623ec67ba..11285f972 100644 --- a/test/aaa_profiling/test_zoomark_orm.py +++ b/test/aaa_profiling/test_zoomark_orm.py @@ -8,7 +8,7 @@ import sys import time from sqlalchemy import * from sqlalchemy.orm import * -from sqlalchemy.test import * +from test.lib import * ITERATIONS = 1 dbapi_session = engines.ReplayableSession() metadata = None diff --git a/test/base/test_dependency.py b/test/base/test_dependency.py index 9fddfc47f..9f6344de7 100644 --- a/test/base/test_dependency.py +++ b/test/base/test_dependency.py @@ -1,6 +1,6 @@ import sqlalchemy.topological as topological -from sqlalchemy.test import TestBase -from sqlalchemy.test.testing import assert_raises, eq_ +from test.lib import TestBase +from test.lib.testing import assert_raises, eq_ from sqlalchemy import exc, util diff --git a/test/base/test_except.py b/test/base/test_except.py index 78a534e67..f02ca988b 100644 --- a/test/base/test_except.py +++ b/test/base/test_except.py @@ -2,7 +2,7 @@ from sqlalchemy import exc as sa_exceptions -from sqlalchemy.test import TestBase +from test.lib import TestBase # Py3K #StandardError = BaseException diff --git a/test/base/test_utils.py b/test/base/test_utils.py index d083a8458..4f02d3811 100644 --- a/test/base/test_utils.py +++ b/test/base/test_utils.py @@ -1,9 +1,9 @@ -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message import copy, threading from sqlalchemy import util, sql, exc -from sqlalchemy.test import TestBase -from sqlalchemy.test.testing import eq_, is_, ne_ -from sqlalchemy.test.util import gc_collect, picklers +from test.lib import TestBase +from test.lib.testing import eq_, is_, ne_ +from test.lib.util import gc_collect, picklers from sqlalchemy.util import classproperty diff --git a/test/bootstrap/config.py b/test/bootstrap/config.py index 7d528a04b..ef37e4f20 100644 --- a/test/bootstrap/config.py +++ b/test/bootstrap/config.py @@ -123,14 +123,14 @@ def _engine_pool(options, file_config): post_configure['engine_pool'] = _engine_pool def _create_testing_engine(options, file_config): - from sqlalchemy.test import engines, testing + from test.lib import engines, testing global db db = engines.testing_engine(db_url, db_opts) testing.db = db post_configure['create_engine'] = _create_testing_engine def _prep_testing_database(options, file_config): - from sqlalchemy.test import engines + from test.lib import engines from sqlalchemy import schema # also create alt schemas etc. here? @@ -152,7 +152,7 @@ def _prep_testing_database(options, file_config): post_configure['prep_db'] = _prep_testing_database def _set_table_options(options, file_config): - from sqlalchemy.test import schema + from test.lib import schema table_options = schema.table_options for spec in options.tableopts: @@ -167,7 +167,7 @@ def _reverse_topological(options, file_config): if options.reversetop: from sqlalchemy.orm import unitofwork, session, mapper, dependency from sqlalchemy import topological - from sqlalchemy.test.util import RandomSet + from test.lib.util import RandomSet topological.set = unitofwork.set = session.set = mapper.set = dependency.set = RandomSet post_configure['topological'] = _reverse_topological diff --git a/test/bootstrap/noseplugin.py b/test/bootstrap/noseplugin.py index f010641f6..1be8be522 100644 --- a/test/bootstrap/noseplugin.py +++ b/test/bootstrap/noseplugin.py @@ -79,7 +79,7 @@ class NoseSQLAlchemy(Plugin): def begin(self): global testing, requires, util - from sqlalchemy.test import testing, requires + from test.lib import testing, requires from sqlalchemy import util testing.db = db diff --git a/test/dialect/test_access.py b/test/dialect/test_access.py index 0ea8d9a61..bd0d7c22a 100644 --- a/test/dialect/test_access.py +++ b/test/dialect/test_access.py @@ -1,7 +1,7 @@ from sqlalchemy import * from sqlalchemy import sql from sqlalchemy.databases import access -from sqlalchemy.test import * +from test.lib import * class CompileTest(TestBase, AssertsCompiledSQL): diff --git a/test/dialect/test_firebird.py b/test/dialect/test_firebird.py index 41a50e6a3..814c267b5 100644 --- a/test/dialect/test_firebird.py +++ b/test/dialect/test_firebird.py @@ -1,9 +1,9 @@ -from sqlalchemy.test.testing import eq_, assert_raises +from test.lib.testing import eq_, assert_raises from sqlalchemy import * from sqlalchemy.databases import firebird from sqlalchemy.exc import ProgrammingError from sqlalchemy.sql import table, column -from sqlalchemy.test import * +from test.lib import * class DomainReflectionTest(TestBase, AssertsExecutionResults): diff --git a/test/dialect/test_informix.py b/test/dialect/test_informix.py index ceec587d9..ea74dcbe4 100644 --- a/test/dialect/test_informix.py +++ b/test/dialect/test_informix.py @@ -1,6 +1,6 @@ from sqlalchemy import * from sqlalchemy.databases import informix -from sqlalchemy.test import * +from test.lib import * class CompileTest(TestBase, AssertsCompiledSQL): diff --git a/test/dialect/test_maxdb.py b/test/dialect/test_maxdb.py index 4df049030..7d43d594b 100644 --- a/test/dialect/test_maxdb.py +++ b/test/dialect/test_maxdb.py @@ -1,12 +1,12 @@ """MaxDB-specific tests.""" -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ import StringIO, sys from sqlalchemy import * from sqlalchemy import exc, sql from decimal import Decimal from sqlalchemy.databases import maxdb -from sqlalchemy.test import * +from test.lib import * # TODO diff --git a/test/dialect/test_mssql.py b/test/dialect/test_mssql.py index e766a8301..26c53298c 100644 --- a/test/dialect/test_mssql.py +++ b/test/dialect/test_mssql.py @@ -1,5 +1,5 @@ # -*- encoding: utf-8 -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ import datetime import os import re @@ -11,8 +11,8 @@ from sqlalchemy.sql import table, column from sqlalchemy.databases import mssql from sqlalchemy.dialects.mssql import pyodbc, mxodbc, pymssql from sqlalchemy.engine import url -from sqlalchemy.test import * -from sqlalchemy.test.testing import eq_, emits_warning_on, \ +from test.lib import * +from test.lib.testing import eq_, emits_warning_on, \ assert_raises_message class CompileTest(TestBase, AssertsCompiledSQL): diff --git a/test/dialect/test_mxodbc.py b/test/dialect/test_mxodbc.py index f574177dd..36cfc9b08 100644 --- a/test/dialect/test_mxodbc.py +++ b/test/dialect/test_mxodbc.py @@ -1,6 +1,6 @@ from sqlalchemy import * -from sqlalchemy.test.testing import eq_, TestBase -from sqlalchemy.test import engines +from test.lib.testing import eq_, TestBase +from test.lib import engines # TODO: we should probably build mock bases for # these to share with test_reconnect, test_parseconnect diff --git a/test/dialect/test_mysql.py b/test/dialect/test_mysql.py index 78e1b9ab0..02e317b02 100644 --- a/test/dialect/test_mysql.py +++ b/test/dialect/test_mysql.py @@ -1,6 +1,6 @@ # coding: utf-8 -from sqlalchemy.test.testing import eq_, assert_raises +from test.lib.testing import eq_, assert_raises # Py2K import sets @@ -9,9 +9,9 @@ import sets from sqlalchemy import * from sqlalchemy import sql, exc, schema, types as sqltypes from sqlalchemy.dialects.mysql import base as mysql -from sqlalchemy.test.testing import eq_ -from sqlalchemy.test import * -from sqlalchemy.test.engines import utf8_engine +from test.lib.testing import eq_ +from test.lib import * +from test.lib.engines import utf8_engine import datetime class TypesTest(TestBase, AssertsExecutionResults, AssertsCompiledSQL): diff --git a/test/dialect/test_oracle.py b/test/dialect/test_oracle.py index 04b9d3274..e1275dbfc 100644 --- a/test/dialect/test_oracle.py +++ b/test/dialect/test_oracle.py @@ -1,12 +1,12 @@ # coding: utf-8 -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from sqlalchemy import * from sqlalchemy import types as sqltypes, exc from sqlalchemy.sql import table, column -from sqlalchemy.test import * -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message -from sqlalchemy.test.engines import testing_engine +from test.lib import * +from test.lib.testing import eq_, assert_raises, assert_raises_message +from test.lib.engines import testing_engine from sqlalchemy.dialects.oracle import cx_oracle, base as oracle from sqlalchemy.engine import default from sqlalchemy.util import jython diff --git a/test/dialect/test_postgresql.py b/test/dialect/test_postgresql.py index e20274aef..3bc22f2a3 100644 --- a/test/dialect/test_postgresql.py +++ b/test/dialect/test_postgresql.py @@ -1,6 +1,6 @@ # coding: utf-8 -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message -from sqlalchemy.test import engines +from test.lib.testing import eq_, assert_raises, assert_raises_message +from test.lib import engines import datetime import decimal from sqlalchemy import * @@ -8,10 +8,10 @@ from sqlalchemy.orm import * from sqlalchemy import exc, schema, types from sqlalchemy.dialects.postgresql import base as postgresql from sqlalchemy.engine.strategies import MockEngineStrategy -from sqlalchemy.test import * -from sqlalchemy.test.util import round_decimal +from test.lib import * +from test.lib.util import round_decimal from sqlalchemy.sql import table, column -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from test.engine._base import TablesTest import logging diff --git a/test/dialect/test_sqlite.py b/test/dialect/test_sqlite.py index 19ec260d3..90036147b 100644 --- a/test/dialect/test_sqlite.py +++ b/test/dialect/test_sqlite.py @@ -1,13 +1,13 @@ """SQLite-specific tests.""" -from sqlalchemy.test.testing import eq_, assert_raises, \ +from test.lib.testing import eq_, assert_raises, \ assert_raises_message import datetime from sqlalchemy import * from sqlalchemy import exc, sql, schema from sqlalchemy.dialects.sqlite import base as sqlite, \ pysqlite as pysqlite_dialect -from sqlalchemy.test import * +from test.lib import * class TestTypes(TestBase, AssertsExecutionResults): diff --git a/test/dialect/test_sybase.py b/test/dialect/test_sybase.py index 37de91d1c..54e4f32e1 100644 --- a/test/dialect/test_sybase.py +++ b/test/dialect/test_sybase.py @@ -1,7 +1,7 @@ from sqlalchemy import * from sqlalchemy import sql from sqlalchemy.databases import sybase -from sqlalchemy.test import * +from test.lib import * class CompileTest(TestBase, AssertsCompiledSQL): diff --git a/test/engine/_base.py b/test/engine/_base.py index ec91243d2..773fa2fea 100644 --- a/test/engine/_base.py +++ b/test/engine/_base.py @@ -1,6 +1,6 @@ import sqlalchemy as sa -from sqlalchemy.test import testing -from sqlalchemy.test.testing import adict +from test.lib import testing +from test.lib.testing import adict class TablesTest(testing.TestBase): diff --git a/test/engine/test_bind.py b/test/engine/test_bind.py index dfcc5e172..855c3611e 100644 --- a/test/engine/test_bind.py +++ b/test/engine/test_bind.py @@ -1,14 +1,14 @@ """tests the "bind" attribute/argument across schema and SQL, including the deprecated versions of these arguments""" -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from sqlalchemy import engine, exc from sqlalchemy import MetaData, ThreadLocalMetaData from sqlalchemy import Integer, text -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column +from test.lib.schema import Table +from test.lib.schema import Column import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing class BindTest(testing.TestBase): diff --git a/test/engine/test_ddlevents.py b/test/engine/test_ddlevents.py index ccbbfd82d..cc4f8b0e4 100644 --- a/test/engine/test_ddlevents.py +++ b/test/engine/test_ddlevents.py @@ -1,13 +1,13 @@ -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message from sqlalchemy.schema import DDL, CheckConstraint, AddConstraint, \ DropConstraint from sqlalchemy import create_engine from sqlalchemy import MetaData, Integer, String -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column +from test.lib.schema import Table +from test.lib.schema import Column import sqlalchemy as tsa -from sqlalchemy.test import TestBase, testing, engines -from sqlalchemy.test.testing import AssertsCompiledSQL +from test.lib import TestBase, testing, engines +from test.lib.testing import AssertsCompiledSQL from nose import SkipTest class DDLEventTest(TestBase): diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py index 116b8fc22..9b63945fb 100644 --- a/test/engine/test_execute.py +++ b/test/engine/test_execute.py @@ -1,11 +1,11 @@ -from sqlalchemy.test.testing import eq_, assert_raises +from test.lib.testing import eq_, assert_raises import re from sqlalchemy.interfaces import ConnectionProxy from sqlalchemy import MetaData, Integer, String, INT, VARCHAR, func, \ bindparam, select -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column import sqlalchemy as tsa -from sqlalchemy.test import TestBase, testing, engines +from test.lib import TestBase, testing, engines import logging from sqlalchemy.dialects.oracle.zxjdbc import ReturningParam diff --git a/test/engine/test_metadata.py b/test/engine/test_metadata.py index b2250c808..daead42de 100644 --- a/test/engine/test_metadata.py +++ b/test/engine/test_metadata.py @@ -1,17 +1,17 @@ -from sqlalchemy.test.testing import assert_raises -from sqlalchemy.test.testing import assert_raises_message -from sqlalchemy.test.testing import emits_warning +from test.lib.testing import assert_raises +from test.lib.testing import assert_raises_message +from test.lib.testing import emits_warning import pickle from sqlalchemy import Integer, String, UniqueConstraint, \ CheckConstraint, ForeignKey, MetaData, Sequence, \ ForeignKeyConstraint, ColumnDefault, Index -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy import schema, exc import sqlalchemy as tsa -from sqlalchemy.test import TestBase, ComparesTables, \ +from test.lib import TestBase, ComparesTables, \ AssertsCompiledSQL, testing, engines -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ class MetaDataTest(TestBase, ComparesTables): def test_metadata_connect(self): diff --git a/test/engine/test_parseconnect.py b/test/engine/test_parseconnect.py index 78b75ad2f..7000549e7 100644 --- a/test/engine/test_parseconnect.py +++ b/test/engine/test_parseconnect.py @@ -1,11 +1,11 @@ -from sqlalchemy.test.testing import assert_raises, assert_raises_message, eq_ +from test.lib.testing import assert_raises, assert_raises_message, eq_ import ConfigParser import StringIO import sqlalchemy.engine.url as url from sqlalchemy import create_engine, engine_from_config from sqlalchemy.engine import _coerce_config import sqlalchemy as tsa -from sqlalchemy.test import TestBase +from test.lib import TestBase class ParseConnectTest(TestBase): diff --git a/test/engine/test_pool.py b/test/engine/test_pool.py index 9db65d2ab..a278b563a 100644 --- a/test/engine/test_pool.py +++ b/test/engine/test_pool.py @@ -1,9 +1,9 @@ import threading, time from sqlalchemy import pool, interfaces, create_engine, select import sqlalchemy as tsa -from sqlalchemy.test import TestBase, testing -from sqlalchemy.test.util import gc_collect, lazy_gc -from sqlalchemy.test.testing import eq_ +from test.lib import TestBase, testing +from test.lib.util import gc_collect, lazy_gc +from test.lib.testing import eq_ mcid = 1 class MockDBAPI(object): diff --git a/test/engine/test_reconnect.py b/test/engine/test_reconnect.py index e26413957..7130b6b4f 100644 --- a/test/engine/test_reconnect.py +++ b/test/engine/test_reconnect.py @@ -1,11 +1,11 @@ -from sqlalchemy.test.testing import eq_, assert_raises +from test.lib.testing import eq_, assert_raises import time import weakref from sqlalchemy import select, MetaData, Integer, String, pool -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column import sqlalchemy as tsa -from sqlalchemy.test import TestBase, testing, engines -from sqlalchemy.test.util import gc_collect +from test.lib import TestBase, testing, engines +from test.lib.util import gc_collect from sqlalchemy import exc class MockDisconnect(Exception): diff --git a/test/engine/test_reflection.py b/test/engine/test_reflection.py index d0d6e31e1..cd1138985 100644 --- a/test/engine/test_reflection.py +++ b/test/engine/test_reflection.py @@ -1,12 +1,12 @@ -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message +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 from sqlalchemy.engine.reflection import Inspector from sqlalchemy import MetaData -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column import sqlalchemy as sa -from sqlalchemy.test import TestBase, ComparesTables, \ +from test.lib import TestBase, ComparesTables, \ testing, engines, AssertsCompiledSQL create_inspector = Inspector.from_engine diff --git a/test/engine/test_transaction.py b/test/engine/test_transaction.py index f09c67164..c21fc9642 100644 --- a/test/engine/test_transaction.py +++ b/test/engine/test_transaction.py @@ -1,13 +1,13 @@ -from sqlalchemy.test.testing import eq_, assert_raises, \ +from test.lib.testing import eq_, assert_raises, \ assert_raises_message import sys import time import threading from sqlalchemy import create_engine, MetaData, INT, VARCHAR, Sequence, \ select, Integer, String, func, text, exc -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column -from sqlalchemy.test import TestBase, testing +from test.lib.schema import Table +from test.lib.schema import Column +from test.lib import TestBase, testing users, metadata = None, None diff --git a/test/ex/test_examples.py b/test/ex/test_examples.py index 9c68f1825..311eab041 100644 --- a/test/ex/test_examples.py +++ b/test/ex/test_examples.py @@ -1,4 +1,4 @@ -from sqlalchemy.test import * +from test.lib import * import os import re diff --git a/test/ext/test_associationproxy.py b/test/ext/test_associationproxy.py index d22e45796..fb2f60ff1 100644 --- a/test/ext/test_associationproxy.py +++ b/test/ext/test_associationproxy.py @@ -1,4 +1,4 @@ -from sqlalchemy.test.testing import eq_, assert_raises +from test.lib.testing import eq_, assert_raises import copy import pickle @@ -7,8 +7,8 @@ from sqlalchemy.orm import * from sqlalchemy.orm.collections import collection from sqlalchemy.ext.associationproxy import * from sqlalchemy.ext.associationproxy import _AssociationList -from sqlalchemy.test import * -from sqlalchemy.test.util import gc_collect +from test.lib import * +from test.lib.util import gc_collect from sqlalchemy.sql import not_ from test.orm import _base diff --git a/test/ext/test_compiler.py b/test/ext/test_compiler.py index 3ed84fe61..31b893b48 100644 --- a/test/ext/test_compiler.py +++ b/test/ext/test_compiler.py @@ -5,7 +5,7 @@ from sqlalchemy.sql.expression import ClauseElement, ColumnClause,\ from sqlalchemy.schema import DDLElement from sqlalchemy.ext.compiler import compiles from sqlalchemy.sql import table, column -from sqlalchemy.test import * +from test.lib import * class UserDefinedTest(TestBase, AssertsCompiledSQL): diff --git a/test/ext/test_declarative.py b/test/ext/test_declarative.py index 72e2edf30..89e8e9108 100644 --- a/test/ext/test_declarative.py +++ b/test/ext/test_declarative.py @@ -1,17 +1,17 @@ -from sqlalchemy.test.testing import eq_, assert_raises, \ +from test.lib.testing import eq_, assert_raises, \ assert_raises_message from sqlalchemy.ext import declarative as decl from sqlalchemy import exc import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import MetaData, Integer, String, ForeignKey, \ ForeignKeyConstraint, asc, Index -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import relationship, create_session, class_mapper, \ joinedload, compile_mappers, backref, clear_mappers, \ polymorphic_union, deferred, column_property -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from sqlalchemy.util import classproperty from test.orm._base import ComparableEntity, MappedTest from sqlalchemy.ext.declarative import declared_attr diff --git a/test/ext/test_horizontal_shard.py b/test/ext/test_horizontal_shard.py index 66583fb0d..bbd4ed2e7 100644 --- a/test/ext/test_horizontal_shard.py +++ b/test/ext/test_horizontal_shard.py @@ -4,8 +4,8 @@ from sqlalchemy import sql from sqlalchemy.orm import * from sqlalchemy.ext.horizontal_shard import ShardedSession from sqlalchemy.sql import operators -from sqlalchemy.test import * -from sqlalchemy.test.testing import eq_ +from test.lib import * +from test.lib.testing import eq_ from nose import SkipTest # TODO: ShardTest can be turned into a base for further subclasses diff --git a/test/ext/test_orderinglist.py b/test/ext/test_orderinglist.py index 559aefd1d..f7f8f7fa7 100644 --- a/test/ext/test_orderinglist.py +++ b/test/ext/test_orderinglist.py @@ -1,8 +1,8 @@ from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.orderinglist import * -from sqlalchemy.test.testing import eq_ -from sqlalchemy.test import * +from test.lib.testing import eq_ +from test.lib import * metadata = None diff --git a/test/ext/test_serializer.py b/test/ext/test_serializer.py index 45f55e1c9..09a6504a3 100644 --- a/test/ext/test_serializer.py +++ b/test/ext/test_serializer.py @@ -2,14 +2,14 @@ from sqlalchemy.ext import serializer from sqlalchemy import exc import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import MetaData, Integer, String, ForeignKey, select, \ desc, func, util -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column +from test.lib.schema import Table +from test.lib.schema import Column from sqlalchemy.orm import relationship, sessionmaker, scoped_session, \ class_mapper, mapper, joinedload, compile_mappers, aliased -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from test.orm._base import ComparableEntity, MappedTest diff --git a/test/ext/test_sqlsoup.py b/test/ext/test_sqlsoup.py index 7fe8ab178..f0ac6cbed 100644 --- a/test/ext/test_sqlsoup.py +++ b/test/ext/test_sqlsoup.py @@ -1,5 +1,5 @@ from sqlalchemy.ext import sqlsoup -from sqlalchemy.test.testing import TestBase, eq_, assert_raises +from test.lib.testing import TestBase, eq_, assert_raises from sqlalchemy import create_engine, or_, desc, select, func, exc, \ Table, util from sqlalchemy.orm import scoped_session, sessionmaker diff --git a/test/lib/__init__.py b/test/lib/__init__.py new file mode 100644 index 000000000..452848aff --- /dev/null +++ b/test/lib/__init__.py @@ -0,0 +1,27 @@ +"""Testing environment and utilities. + +This package contains base classes and routines used by +the unit tests. Tests are based on Nose and bootstrapped +by noseplugin.NoseSQLAlchemy. + +""" + +from test.bootstrap import config +from test.lib import testing, engines, requires, profiling, pickleable +from test.lib.schema import Column, Table +from test.lib.testing import \ + AssertsCompiledSQL, \ + AssertsExecutionResults, \ + ComparesTables, \ + TestBase, \ + rowset + + +__all__ = ('testing', + 'Column', 'Table', + 'rowset', + 'TestBase', 'AssertsExecutionResults', + 'AssertsCompiledSQL', 'ComparesTables', + 'engines', 'profiling', 'pickleable') + + diff --git a/test/lib/assertsql.py b/test/lib/assertsql.py new file mode 100644 index 000000000..a044f9d02 --- /dev/null +++ b/test/lib/assertsql.py @@ -0,0 +1,295 @@ + +from sqlalchemy.interfaces import ConnectionProxy +from sqlalchemy.engine.default import DefaultDialect +from sqlalchemy.engine.base import Connection +from sqlalchemy import util +import re + +class AssertRule(object): + def process_execute(self, clauseelement, *multiparams, **params): + pass + + def process_cursor_execute(self, statement, parameters, context, executemany): + pass + + def is_consumed(self): + """Return True if this rule has been consumed, False if not. + + Should raise an AssertionError if this rule's condition has definitely failed. + + """ + raise NotImplementedError() + + def rule_passed(self): + """Return True if the last test of this rule passed, False if failed, None if no test was applied.""" + + raise NotImplementedError() + + def consume_final(self): + """Return True if this rule has been consumed. + + Should raise an AssertionError if this rule's condition has not been consumed or has failed. + + """ + + if self._result is None: + assert False, "Rule has not been consumed" + + return self.is_consumed() + +class SQLMatchRule(AssertRule): + def __init__(self): + self._result = None + self._errmsg = "" + + def rule_passed(self): + return self._result + + def is_consumed(self): + if self._result is None: + return False + + assert self._result, self._errmsg + + return True + +class ExactSQL(SQLMatchRule): + def __init__(self, sql, params=None): + SQLMatchRule.__init__(self) + self.sql = sql + self.params = params + + def process_cursor_execute(self, statement, parameters, context, executemany): + if not context: + return + + _received_statement = _process_engine_statement(context.unicode_statement, context) + _received_parameters = context.compiled_parameters + + # TODO: remove this step once all unit tests + # are migrated, as ExactSQL should really be *exact* SQL + sql = _process_assertion_statement(self.sql, context) + + equivalent = _received_statement == sql + if self.params: + if util.callable(self.params): + params = self.params(context) + else: + params = self.params + + if not isinstance(params, list): + params = [params] + equivalent = equivalent and params == context.compiled_parameters + else: + params = {} + + + self._result = equivalent + if not self._result: + self._errmsg = "Testing for exact statement %r exact params %r, " \ + "received %r with params %r" % (sql, params, _received_statement, _received_parameters) + + +class RegexSQL(SQLMatchRule): + def __init__(self, regex, params=None): + SQLMatchRule.__init__(self) + self.regex = re.compile(regex) + self.orig_regex = regex + self.params = params + + def process_cursor_execute(self, statement, parameters, context, executemany): + if not context: + return + + _received_statement = _process_engine_statement(context.unicode_statement, context) + _received_parameters = context.compiled_parameters + + equivalent = bool(self.regex.match(_received_statement)) + if self.params: + if util.callable(self.params): + params = self.params(context) + else: + params = self.params + + if not isinstance(params, list): + params = [params] + + # do a positive compare only + for param, received in zip(params, _received_parameters): + for k, v in param.iteritems(): + if k not in received or received[k] != v: + equivalent = False + break + else: + params = {} + + self._result = equivalent + if not self._result: + self._errmsg = "Testing for regex %r partial params %r, "\ + "received %r with params %r" % (self.orig_regex, params, _received_statement, _received_parameters) + +class CompiledSQL(SQLMatchRule): + def __init__(self, statement, params): + SQLMatchRule.__init__(self) + self.statement = statement + self.params = params + + def process_cursor_execute(self, statement, parameters, context, executemany): + if not context: + return + + _received_parameters = list(context.compiled_parameters) + + # recompile from the context, using the default dialect + compiled = context.compiled.statement.\ + compile(dialect=DefaultDialect(), column_keys=context.compiled.column_keys) + + _received_statement = re.sub(r'\n', '', str(compiled)) + + equivalent = self.statement == _received_statement + if self.params: + if util.callable(self.params): + params = self.params(context) + else: + params = self.params + + if not isinstance(params, list): + params = [params] + + all_params = list(params) + all_received = list(_received_parameters) + while params: + param = dict(params.pop(0)) + for k, v in context.compiled.params.iteritems(): + param.setdefault(k, v) + + if param not in _received_parameters: + equivalent = False + break + else: + _received_parameters.remove(param) + if _received_parameters: + equivalent = False + else: + params = {} + + self._result = equivalent + if not self._result: + self._errmsg = "Testing for compiled statement %r partial params %r, " \ + "received %r with params %r" % \ + (self.statement, all_params, _received_statement, all_received) + #print self._errmsg + + +class CountStatements(AssertRule): + def __init__(self, count): + self.count = count + self._statement_count = 0 + + def process_execute(self, clauseelement, *multiparams, **params): + self._statement_count += 1 + + def process_cursor_execute(self, statement, parameters, context, executemany): + pass + + def is_consumed(self): + return False + + def consume_final(self): + assert self.count == self._statement_count, "desired statement count %d does not match %d" % (self.count, self._statement_count) + return True + +class AllOf(AssertRule): + def __init__(self, *rules): + self.rules = set(rules) + + def process_execute(self, clauseelement, *multiparams, **params): + for rule in self.rules: + rule.process_execute(clauseelement, *multiparams, **params) + + def process_cursor_execute(self, statement, parameters, context, executemany): + for rule in self.rules: + rule.process_cursor_execute(statement, parameters, context, executemany) + + def is_consumed(self): + if not self.rules: + return True + + for rule in list(self.rules): + if rule.rule_passed(): # a rule passed, move on + self.rules.remove(rule) + return len(self.rules) == 0 + + assert False, "No assertion rules were satisfied for statement" + + def consume_final(self): + return len(self.rules) == 0 + +def _process_engine_statement(query, context): + if util.jython: + # oracle+zxjdbc passes a PyStatement when returning into + query = unicode(query) + if context.engine.name == 'mssql' and query.endswith('; select scope_identity()'): + query = query[:-25] + + query = re.sub(r'\n', '', query) + + return query + +def _process_assertion_statement(query, context): + paramstyle = context.dialect.paramstyle + if paramstyle == 'named': + pass + elif paramstyle =='pyformat': + query = re.sub(r':([\w_]+)', r"%(\1)s", query) + else: + # positional params + repl = None + if paramstyle=='qmark': + repl = "?" + elif paramstyle=='format': + repl = r"%s" + elif paramstyle=='numeric': + repl = None + query = re.sub(r':([\w_]+)', repl, query) + + return query + +class SQLAssert(ConnectionProxy): + rules = None + + def add_rules(self, rules): + self.rules = list(rules) + + def statement_complete(self): + for rule in self.rules: + if not rule.consume_final(): + assert False, "All statements are complete, but pending assertion rules remain" + + def clear_rules(self): + del self.rules + + def execute(self, conn, execute, clauseelement, *multiparams, **params): + result = execute(clauseelement, *multiparams, **params) + + if self.rules is not None: + if not self.rules: + assert False, "All rules have been exhausted, but further statements remain" + rule = self.rules[0] + rule.process_execute(clauseelement, *multiparams, **params) + if rule.is_consumed(): + self.rules.pop(0) + + return result + + def cursor_execute(self, execute, cursor, statement, parameters, context, executemany): + result = execute(cursor, statement, parameters, context) + + if self.rules: + rule = self.rules[0] + rule.process_cursor_execute(statement, parameters, context, executemany) + + return result + +asserter = SQLAssert() + diff --git a/test/lib/engines.py b/test/lib/engines.py new file mode 100644 index 000000000..61c5fb8fc --- /dev/null +++ b/test/lib/engines.py @@ -0,0 +1,305 @@ +import sys, types, weakref +from collections import deque +from test.bootstrap import config +from sqlalchemy.util import function_named, callable +import re +import warnings + +class ConnectionKiller(object): + def __init__(self): + self.proxy_refs = weakref.WeakKeyDictionary() + + def checkout(self, dbapi_con, con_record, con_proxy): + self.proxy_refs[con_proxy] = True + + def _apply_all(self, methods): + # must copy keys atomically + for rec in self.proxy_refs.keys(): + if rec is not None and rec.is_valid: + try: + for name in methods: + if callable(name): + name(rec) + else: + getattr(rec, name)() + except (SystemExit, KeyboardInterrupt): + raise + except Exception, e: + warnings.warn("testing_reaper couldn't close connection: %s" % e) + + def rollback_all(self): + self._apply_all(('rollback',)) + + def close_all(self): + self._apply_all(('rollback', 'close')) + + def assert_all_closed(self): + for rec in self.proxy_refs: + if rec.is_valid: + assert False + +testing_reaper = ConnectionKiller() + +def drop_all_tables(metadata): + testing_reaper.close_all() + metadata.drop_all() + +def assert_conns_closed(fn): + def decorated(*args, **kw): + try: + fn(*args, **kw) + finally: + testing_reaper.assert_all_closed() + return function_named(decorated, fn.__name__) + +def rollback_open_connections(fn): + """Decorator that rolls back all open connections after fn execution.""" + + def decorated(*args, **kw): + try: + fn(*args, **kw) + finally: + testing_reaper.rollback_all() + return function_named(decorated, fn.__name__) + +def close_first(fn): + """Decorator that closes all connections before fn execution.""" + def decorated(*args, **kw): + testing_reaper.close_all() + fn(*args, **kw) + return function_named(decorated, fn.__name__) + + +def close_open_connections(fn): + """Decorator that closes all connections after fn execution.""" + + def decorated(*args, **kw): + try: + fn(*args, **kw) + finally: + testing_reaper.close_all() + return function_named(decorated, fn.__name__) + +def all_dialects(exclude=None): + import sqlalchemy.databases as d + for name in d.__all__: + # TEMPORARY + if exclude and name in exclude: + continue + mod = getattr(d, name, None) + if not mod: + mod = getattr(__import__('sqlalchemy.databases.%s' % name).databases, name) + yield mod.dialect() + +class ReconnectFixture(object): + def __init__(self, dbapi): + self.dbapi = dbapi + self.connections = [] + + def __getattr__(self, key): + return getattr(self.dbapi, key) + + def connect(self, *args, **kwargs): + conn = self.dbapi.connect(*args, **kwargs) + self.connections.append(conn) + return conn + + def shutdown(self): + # TODO: this doesn't cover all cases + # as nicely as we'd like, namely MySQLdb. + # would need to implement R. Brewer's + # proxy server idea to get better + # coverage. + for c in list(self.connections): + c.close() + self.connections = [] + +def reconnecting_engine(url=None, options=None): + url = url or config.db_url + dbapi = config.db.dialect.dbapi + if not options: + options = {} + options['module'] = ReconnectFixture(dbapi) + engine = testing_engine(url, options) + engine.test_shutdown = engine.dialect.dbapi.shutdown + return engine + +def testing_engine(url=None, options=None): + """Produce an engine configured by --options with optional overrides.""" + + from sqlalchemy import create_engine + from test.lib.assertsql import asserter + + url = url or config.db_url + options = options or config.db_opts + + options.setdefault('proxy', asserter) + + listeners = options.setdefault('listeners', []) + listeners.append(testing_reaper) + + engine = create_engine(url, **options) + + # may want to call this, results + # in first-connect initializers + #engine.connect() + + return engine + +def utf8_engine(url=None, options=None): + """Hook for dialects or drivers that don't handle utf8 by default.""" + + from sqlalchemy.engine import url as engine_url + + if config.db.driver == 'mysqldb': + dbapi_ver = config.db.dialect.dbapi.version_info + if (dbapi_ver < (1, 2, 1) or + dbapi_ver in ((1, 2, 1, 'gamma', 1), (1, 2, 1, 'gamma', 2), + (1, 2, 1, 'gamma', 3), (1, 2, 1, 'gamma', 5))): + raise RuntimeError('Character set support unavailable with this ' + 'driver version: %s' % repr(dbapi_ver)) + else: + url = url or config.db_url + url = engine_url.make_url(url) + url.query['charset'] = 'utf8' + url.query['use_unicode'] = '0' + url = str(url) + + return testing_engine(url, options) + +def mock_engine(dialect_name=None): + """Provides a mocking engine based on the current testing.db. + + This is normally used to test DDL generation flow as emitted + by an Engine. + + It should not be used in other cases, as assert_compile() and + assert_sql_execution() are much better choices with fewer + moving parts. + + """ + + from sqlalchemy import create_engine + + if not dialect_name: + dialect_name = config.db.name + + buffer = [] + def executor(sql, *a, **kw): + buffer.append(sql) + def assert_sql(stmts): + recv = [re.sub(r'[\n\t]', '', str(s)) for s in buffer] + assert recv == stmts, recv + + engine = create_engine(dialect_name + '://', + strategy='mock', executor=executor) + assert not hasattr(engine, 'mock') + engine.mock = buffer + engine.assert_sql = assert_sql + return engine + +class ReplayableSession(object): + """A simple record/playback tool. + + This is *not* a mock testing class. It only records a session for later + playback and makes no assertions on call consistency whatsoever. It's + unlikely to be suitable for anything other than DB-API recording. + + """ + + Callable = object() + NoAttribute = object() + Natives = set([getattr(types, t) + for t in dir(types) if not t.startswith('_')]). \ + difference([getattr(types, t) + # Py3K + #for t in ('FunctionType', 'BuiltinFunctionType', + # 'MethodType', 'BuiltinMethodType', + # 'LambdaType', )]) + + # Py2K + for t in ('FunctionType', 'BuiltinFunctionType', + 'MethodType', 'BuiltinMethodType', + 'LambdaType', 'UnboundMethodType',)]) + # end Py2K + def __init__(self): + self.buffer = deque() + + def recorder(self, base): + return self.Recorder(self.buffer, base) + + def player(self): + return self.Player(self.buffer) + + class Recorder(object): + def __init__(self, buffer, subject): + self._buffer = buffer + self._subject = subject + + def __call__(self, *args, **kw): + subject, buffer = [object.__getattribute__(self, x) + for x in ('_subject', '_buffer')] + + result = subject(*args, **kw) + if type(result) not in ReplayableSession.Natives: + buffer.append(ReplayableSession.Callable) + return type(self)(buffer, result) + else: + buffer.append(result) + return result + + @property + def _sqla_unwrap(self): + return self._subject + + def __getattribute__(self, key): + try: + return object.__getattribute__(self, key) + except AttributeError: + pass + + subject, buffer = [object.__getattribute__(self, x) + for x in ('_subject', '_buffer')] + try: + result = type(subject).__getattribute__(subject, key) + except AttributeError: + buffer.append(ReplayableSession.NoAttribute) + raise + else: + if type(result) not in ReplayableSession.Natives: + buffer.append(ReplayableSession.Callable) + return type(self)(buffer, result) + else: + buffer.append(result) + return result + + class Player(object): + def __init__(self, buffer): + self._buffer = buffer + + def __call__(self, *args, **kw): + buffer = object.__getattribute__(self, '_buffer') + result = buffer.popleft() + if result is ReplayableSession.Callable: + return self + else: + return result + + @property + def _sqla_unwrap(self): + return None + + def __getattribute__(self, key): + try: + return object.__getattribute__(self, key) + except AttributeError: + pass + buffer = object.__getattribute__(self, '_buffer') + result = buffer.popleft() + if result is ReplayableSession.Callable: + return self + elif result is ReplayableSession.NoAttribute: + raise AttributeError(key) + else: + return result + diff --git a/test/lib/entities.py b/test/lib/entities.py new file mode 100644 index 000000000..0ec677eea --- /dev/null +++ b/test/lib/entities.py @@ -0,0 +1,83 @@ +import sqlalchemy as sa +from sqlalchemy import exc as sa_exc + +_repr_stack = set() +class BasicEntity(object): + def __init__(self, **kw): + for key, value in kw.iteritems(): + setattr(self, key, value) + + def __repr__(self): + if id(self) in _repr_stack: + return object.__repr__(self) + _repr_stack.add(id(self)) + try: + return "%s(%s)" % ( + (self.__class__.__name__), + ', '.join(["%s=%r" % (key, getattr(self, key)) + for key in sorted(self.__dict__.keys()) + if not key.startswith('_')])) + finally: + _repr_stack.remove(id(self)) + +_recursion_stack = set() +class ComparableEntity(BasicEntity): + def __hash__(self): + return hash(self.__class__) + + def __ne__(self, other): + return not self.__eq__(other) + + def __eq__(self, other): + """'Deep, sparse compare. + + Deeply compare two entities, following the non-None attributes of the + non-persisted object, if possible. + + """ + if other is self: + return True + elif not self.__class__ == other.__class__: + return False + + if id(self) in _recursion_stack: + return True + _recursion_stack.add(id(self)) + + try: + # pick the entity thats not SA persisted as the source + try: + self_key = sa.orm.attributes.instance_state(self).key + except sa.orm.exc.NO_STATE: + self_key = None + + if other is None: + a = self + b = other + elif self_key is not None: + a = other + b = self + else: + a = self + b = other + + for attr in a.__dict__.keys(): + if attr.startswith('_'): + continue + value = getattr(a, attr) + + try: + # handle lazy loader errors + battr = getattr(b, attr) + except (AttributeError, sa_exc.UnboundExecutionError): + return False + + if hasattr(value, '__iter__'): + if list(value) != list(battr): + return False + else: + if value is not None and value != battr: + return False + return True + finally: + _recursion_stack.remove(id(self)) diff --git a/test/lib/orm.py b/test/lib/orm.py new file mode 100644 index 000000000..7ec13c555 --- /dev/null +++ b/test/lib/orm.py @@ -0,0 +1,111 @@ +import inspect, re +import config, testing +from sqlalchemy import orm + +__all__ = 'mapper', + + +_whitespace = re.compile(r'^(\s+)') + +def _find_pragma(lines, current): + m = _whitespace.match(lines[current]) + basis = m and m.group() or '' + + for line in reversed(lines[0:current]): + if 'testlib.pragma' in line: + return line + m = _whitespace.match(line) + indent = m and m.group() or '' + + # simplistic detection: + + # >> # testlib.pragma foo + # >> center_line() + if indent == basis: + break + # >> # testlib.pragma foo + # >> if fleem: + # >> center_line() + if line.endswith(':'): + break + return None + +def _make_blocker(method_name, fallback): + """Creates tripwired variant of a method, raising when called. + + To excempt an invocation from blockage, there are two options. + + 1) add a pragma in a comment:: + + # testlib.pragma exempt:methodname + offending_line() + + 2) add a magic cookie to the function's namespace:: + __sa_baremethodname_exempt__ = True + ... + offending_line() + another_offending_lines() + + The second is useful for testing and development. + """ + + if method_name.startswith('__') and method_name.endswith('__'): + frame_marker = '__sa_%s_exempt__' % method_name[2:-2] + else: + frame_marker = '__sa_%s_exempt__' % method_name + pragma_marker = 'exempt:' + method_name + + def method(self, *args, **kw): + frame_r = None + try: + frame = inspect.stack()[1][0] + frame_r = inspect.getframeinfo(frame, 9) + + module = frame.f_globals.get('__name__', '') + + type_ = type(self) + + pragma = _find_pragma(*frame_r[3:5]) + + exempt = ( + (not module.startswith('sqlalchemy')) or + (pragma and pragma_marker in pragma) or + (frame_marker in frame.f_locals) or + ('self' in frame.f_locals and + getattr(frame.f_locals['self'], frame_marker, False))) + + if exempt: + supermeth = getattr(super(type_, self), method_name, None) + if (supermeth is None or + getattr(supermeth, 'im_func', None) is method): + return fallback(self, *args, **kw) + else: + return supermeth(*args, **kw) + else: + raise AssertionError( + "%s.%s called in %s, line %s in %s" % ( + type_.__name__, method_name, module, frame_r[1], frame_r[2])) + finally: + del frame + method.__name__ = method_name + return method + +def mapper(type_, *args, **kw): + forbidden = [ + ('__hash__', 'unhashable', lambda s: id(s)), + ('__eq__', 'noncomparable', lambda s, o: s is o), + ('__ne__', 'noncomparable', lambda s, o: s is not o), + ('__cmp__', 'noncomparable', lambda s, o: object.__cmp__(s, o)), + ('__le__', 'noncomparable', lambda s, o: object.__le__(s, o)), + ('__lt__', 'noncomparable', lambda s, o: object.__lt__(s, o)), + ('__ge__', 'noncomparable', lambda s, o: object.__ge__(s, o)), + ('__gt__', 'noncomparable', lambda s, o: object.__gt__(s, o)), + ('__nonzero__', 'truthless', lambda s: 1), ] + + if isinstance(type_, type) and type_.__bases__ == (object,): + for method_name, option, fallback in forbidden: + if (getattr(config.options, option, False) and + method_name not in type_.__dict__): + setattr(type_, method_name, _make_blocker(method_name, fallback)) + + return orm.mapper(type_, *args, **kw) diff --git a/test/lib/pickleable.py b/test/lib/pickleable.py new file mode 100644 index 000000000..9794e424d --- /dev/null +++ b/test/lib/pickleable.py @@ -0,0 +1,75 @@ +""" + +some objects used for pickle tests, declared in their own module so that they +are easily pickleable. + +""" + + +class Foo(object): + def __init__(self, moredata): + self.data = 'im data' + self.stuff = 'im stuff' + self.moredata = moredata + __hash__ = object.__hash__ + def __eq__(self, other): + return other.data == self.data and other.stuff == self.stuff and other.moredata==self.moredata + + +class Bar(object): + def __init__(self, x, y): + self.x = x + self.y = y + __hash__ = object.__hash__ + def __eq__(self, other): + return other.__class__ is self.__class__ and other.x==self.x and other.y==self.y + def __str__(self): + return "Bar(%d, %d)" % (self.x, self.y) + +class OldSchool: + def __init__(self, x, y): + self.x = x + self.y = y + def __eq__(self, other): + return other.__class__ is self.__class__ and other.x==self.x and other.y==self.y + +class OldSchoolWithoutCompare: + def __init__(self, x, y): + self.x = x + self.y = y + +class BarWithoutCompare(object): + def __init__(self, x, y): + self.x = x + self.y = y + def __str__(self): + return "Bar(%d, %d)" % (self.x, self.y) + + +class NotComparable(object): + def __init__(self, data): + self.data = data + + def __hash__(self): + return id(self) + + def __eq__(self, other): + return NotImplemented + + def __ne__(self, other): + return NotImplemented + + +class BrokenComparable(object): + def __init__(self, data): + self.data = data + + def __hash__(self): + return id(self) + + def __eq__(self, other): + raise NotImplementedError + + def __ne__(self, other): + raise NotImplementedError + diff --git a/test/lib/profiling.py b/test/lib/profiling.py new file mode 100644 index 000000000..f6c21bde8 --- /dev/null +++ b/test/lib/profiling.py @@ -0,0 +1,221 @@ +"""Profiling support for unit and performance tests. + +These are special purpose profiling methods which operate +in a more fine-grained way than nose's profiling plugin. + +""" + +import os, sys +from test.lib.util import function_named, gc_collect +from nose import SkipTest + +__all__ = 'profiled', 'function_call_count', 'conditional_call_count' + +all_targets = set() +profile_config = { 'targets': set(), + 'report': True, + 'sort': ('time', 'calls'), + 'limit': None } +profiler = None + +def profiled(target=None, **target_opts): + """Optional function profiling. + + @profiled('label') + or + @profiled('label', report=True, sort=('calls',), limit=20) + + Enables profiling for a function when 'label' is targetted for + profiling. Report options can be supplied, and override the global + configuration and command-line options. + """ + + # manual or automatic namespacing by module would remove conflict issues + if target is None: + target = 'anonymous_target' + elif target in all_targets: + print "Warning: redefining profile target '%s'" % target + all_targets.add(target) + + filename = "%s.prof" % target + + def decorator(fn): + def profiled(*args, **kw): + if (target not in profile_config['targets'] and + not target_opts.get('always', None)): + return fn(*args, **kw) + + elapsed, load_stats, result = _profile( + filename, fn, *args, **kw) + + report = target_opts.get('report', profile_config['report']) + if report: + sort_ = target_opts.get('sort', profile_config['sort']) + limit = target_opts.get('limit', profile_config['limit']) + print "Profile report for target '%s' (%s)" % ( + target, filename) + + stats = load_stats() + stats.sort_stats(*sort_) + if limit: + stats.print_stats(limit) + else: + stats.print_stats() + #stats.print_callers() + os.unlink(filename) + return result + return function_named(profiled, fn.__name__) + return decorator + +def function_call_count(count=None, versions={}, variance=0.05): + """Assert a target for a test case's function call count. + + count + Optional, general target function call count. + + versions + Optional, a dictionary of Python version strings to counts, + for example:: + + { '2.5.1': 110, + '2.5': 100, + '2.4': 150 } + + The best match for the current running python will be used. + If none match, 'count' will be used as the fallback. + + variance + An +/- deviation percentage, defaults to 5%. + """ + + # this could easily dump the profile report if --verbose is in effect + + version_info = list(sys.version_info) + py_version = '.'.join([str(v) for v in sys.version_info]) + try: + from sqlalchemy.cprocessors import to_float + cextension = True + except ImportError: + cextension = False + + while version_info: + version = '.'.join([str(v) for v in version_info]) + if cextension: + version += "+cextension" + if version in versions: + count = versions[version] + break + version_info.pop() + + if count is None: + return lambda fn: fn + + def decorator(fn): + def counted(*args, **kw): + try: + filename = "%s.prof" % fn.__name__ + + elapsed, stat_loader, result = _profile( + filename, fn, *args, **kw) + + stats = stat_loader() + calls = stats.total_calls + + stats.sort_stats('calls', 'cumulative') + stats.print_stats() + #stats.print_callers() + deviance = int(count * variance) + if (calls < (count - deviance) or + calls > (count + deviance)): + raise AssertionError( + "Function call count %s not within %s%% " + "of expected %s. (Python version %s)" % ( + calls, (variance * 100), count, py_version)) + + return result + finally: + if os.path.exists(filename): + os.unlink(filename) + return function_named(counted, fn.__name__) + return decorator + +def conditional_call_count(discriminator, categories): + """Apply a function call count conditionally at runtime. + + Takes two arguments, a callable that returns a key value, and a dict + mapping key values to a tuple of arguments to function_call_count. + + The callable is not evaluated until the decorated function is actually + invoked. If the `discriminator` returns a key not present in the + `categories` dictionary, no call count assertion is applied. + + Useful for integration tests, where running a named test in isolation may + have a function count penalty not seen in the full suite, due to lazy + initialization in the DB-API, SA, etc. + """ + + def decorator(fn): + def at_runtime(*args, **kw): + criteria = categories.get(discriminator(), None) + if criteria is None: + return fn(*args, **kw) + + rewrapped = function_call_count(*criteria)(fn) + return rewrapped(*args, **kw) + return function_named(at_runtime, fn.__name__) + return decorator + + +def _profile(filename, fn, *args, **kw): + global profiler + if not profiler: + if sys.version_info > (2, 5): + try: + import cProfile + profiler = 'cProfile' + except ImportError: + pass + if not profiler: + try: + import hotshot + profiler = 'hotshot' + except ImportError: + profiler = 'skip' + + if profiler == 'skip': + raise SkipTest('Profiling not supported on this platform') + elif profiler == 'cProfile': + return _profile_cProfile(filename, fn, *args, **kw) + else: + return _profile_hotshot(filename, fn, *args, **kw) + +def _profile_cProfile(filename, fn, *args, **kw): + import cProfile, gc, pstats, time + + load_stats = lambda: pstats.Stats(filename) + gc_collect() + + began = time.time() + cProfile.runctx('result = fn(*args, **kw)', globals(), locals(), + filename=filename) + ended = time.time() + + return ended - began, load_stats, locals()['result'] + +def _profile_hotshot(filename, fn, *args, **kw): + import gc, hotshot, hotshot.stats, time + load_stats = lambda: hotshot.stats.load(filename) + + gc_collect() + prof = hotshot.Profile(filename) + began = time.time() + prof.start() + try: + result = fn(*args, **kw) + finally: + prof.stop() + ended = time.time() + prof.close() + + return ended - began, load_stats, result + diff --git a/test/lib/requires.py b/test/lib/requires.py new file mode 100644 index 000000000..d29b7abc2 --- /dev/null +++ b/test/lib/requires.py @@ -0,0 +1,318 @@ +"""Global database feature support policy. + +Provides decorators to mark tests requiring specific feature support from the +target database. + +""" + +from testing import \ + _block_unconditionally as no_support, \ + _chain_decorators_on, \ + exclude, \ + emits_warning_on,\ + skip_if,\ + fails_on,\ + fails_on_everything_except + +import testing +import sys + +def deferrable_constraints(fn): + """Target database must support derferable constraints.""" + return _chain_decorators_on( + fn, + no_support('firebird', 'not supported by database'), + no_support('mysql', 'not supported by database'), + no_support('mssql', 'not supported by database'), + ) + +def foreign_keys(fn): + """Target database must support foreign keys.""" + return _chain_decorators_on( + fn, + no_support('sqlite', 'not supported by database'), + ) + + +def unbounded_varchar(fn): + """Target database must support VARCHAR with no length""" + return _chain_decorators_on( + fn, + no_support('firebird', 'not supported by database'), + no_support('oracle', 'not supported by database'), + no_support('mysql', 'not supported by database'), + ) + +def boolean_col_expressions(fn): + """Target database must support boolean expressions as columns""" + return _chain_decorators_on( + fn, + no_support('firebird', 'not supported by database'), + no_support('oracle', 'not supported by database'), + no_support('mssql', 'not supported by database'), + no_support('sybase', 'not supported by database'), + no_support('maxdb', 'FIXME: verify not supported by database'), + no_support('informix', 'not supported by database'), + ) + +def identity(fn): + """Target database must support GENERATED AS IDENTITY or a facsimile. + + Includes GENERATED AS IDENTITY, AUTOINCREMENT, AUTO_INCREMENT, or other + column DDL feature that fills in a DB-generated identifier at INSERT-time + without requiring pre-execution of a SEQUENCE or other artifact. + + """ + return _chain_decorators_on( + fn, + no_support('firebird', 'not supported by database'), + no_support('oracle', 'not supported by database'), + no_support('postgresql', 'not supported by database'), + no_support('sybase', 'not supported by database'), + ) + +def independent_cursors(fn): + """Target must support simultaneous, independent database cursors on a single connection.""" + + return _chain_decorators_on( + fn, + no_support('mssql+pyodbc', 'no driver support'), + no_support('mssql+mxodbc', 'no driver support'), + ) + +def independent_connections(fn): + """Target must support simultaneous, independent database connections.""" + + # This is also true of some configurations of UnixODBC and probably win32 + # ODBC as well. + return _chain_decorators_on( + fn, + no_support('sqlite', 'no driver support'), + exclude('mssql', '<', (9, 0, 0), + 'SQL Server 2005+ is required for independent connections'), + ) + +def row_triggers(fn): + """Target must support standard statement-running EACH ROW triggers.""" + return _chain_decorators_on( + fn, + # no access to same table + no_support('mysql', 'requires SUPER priv'), + exclude('mysql', '<', (5, 0, 10), 'not supported by database'), + + # huh? TODO: implement triggers for PG tests, remove this + no_support('postgresql', 'PG triggers need to be implemented for tests'), + ) + +def correlated_outer_joins(fn): + """Target must support an outer join to a subquery which correlates to the parent.""" + + return _chain_decorators_on( + fn, + no_support('oracle', 'Raises "ORA-01799: a column may not be outer-joined to a subquery"') + ) + +def savepoints(fn): + """Target database must support savepoints.""" + return _chain_decorators_on( + fn, + emits_warning_on('mssql', 'Savepoint support in mssql is experimental and may lead to data loss.'), + no_support('access', 'not supported by database'), + no_support('sqlite', 'not supported by database'), + no_support('sybase', 'FIXME: guessing, needs confirmation'), + exclude('mysql', '<', (5, 0, 3), 'not supported by database'), + exclude('informix', '<', (11, 55, 'xC3'), 'not supported by database'), + ) + +def denormalized_names(fn): + """Target database must have 'denormalized', i.e. UPPERCASE as case insensitive names.""" + + return skip_if( + lambda: not testing.db.dialect.requires_name_normalize, + "Backend does not require denomralized names." + )(fn) + +def schemas(fn): + """Target database must support external schemas, and have one named 'test_schema'.""" + + return _chain_decorators_on( + fn, + no_support('sqlite', 'no schema support'), + no_support('firebird', 'no schema support') + ) + +def sequences(fn): + """Target database must support SEQUENCEs.""" + return _chain_decorators_on( + fn, + no_support('access', 'no SEQUENCE support'), + no_support('mssql', 'no SEQUENCE support'), + no_support('mysql', 'no SEQUENCE support'), + no_support('sqlite', 'no SEQUENCE support'), + no_support('sybase', 'no SEQUENCE support'), + no_support('informix', 'no SEQUENCE support'), + ) + +def update_nowait(fn): + """Target database must support SELECT...FOR UPDATE NOWAIT""" + return _chain_decorators_on( + fn, + no_support('access', 'no FOR UPDATE NOWAIT support'), + no_support('firebird', 'no FOR UPDATE NOWAIT support'), + no_support('mssql', 'no FOR UPDATE NOWAIT support'), + no_support('mysql', 'no FOR UPDATE NOWAIT support'), + no_support('sqlite', 'no FOR UPDATE NOWAIT support'), + no_support('sybase', 'no FOR UPDATE NOWAIT support'), + ) + +def subqueries(fn): + """Target database must support subqueries.""" + return _chain_decorators_on( + fn, + exclude('mysql', '<', (4, 1, 1), 'no subquery support'), + ) + +def intersect(fn): + """Target database must support INTERSECT or equivlaent.""" + return _chain_decorators_on( + fn, + fails_on('firebird', 'no support for INTERSECT'), + fails_on('mysql', 'no support for INTERSECT'), + fails_on('sybase', 'no support for INTERSECT'), + fails_on('informix', 'no support for INTERSECT'), + ) + +def except_(fn): + """Target database must support EXCEPT or equivlaent (i.e. MINUS).""" + return _chain_decorators_on( + fn, + fails_on('firebird', 'no support for EXCEPT'), + fails_on('mysql', 'no support for EXCEPT'), + fails_on('sybase', 'no support for EXCEPT'), + fails_on('informix', 'no support for EXCEPT'), + ) + +def offset(fn): + """Target database must support some method of adding OFFSET or equivalent to a result set.""" + return _chain_decorators_on( + fn, + fails_on('sybase', 'no support for OFFSET or equivalent'), + ) + +def returning(fn): + return _chain_decorators_on( + fn, + no_support('access', 'not supported by database'), + no_support('sqlite', 'not supported by database'), + no_support('mysql', 'not supported by database'), + no_support('maxdb', 'not supported by database'), + no_support('sybase', 'not supported by database'), + no_support('informix', 'not supported by database'), + ) + +def two_phase_transactions(fn): + """Target database must support two-phase transactions.""" + return _chain_decorators_on( + fn, + no_support('access', 'not supported by database'), + no_support('firebird', 'no SA implementation'), + no_support('maxdb', 'not supported by database'), + no_support('mssql', 'FIXME: guessing, needs confirmation'), + no_support('oracle', 'no SA implementation'), + no_support('sqlite', 'not supported by database'), + no_support('sybase', 'FIXME: guessing, needs confirmation'), + no_support('postgresql+zxjdbc', 'FIXME: JDBC driver confuses the transaction state, may ' + 'need separate XA implementation'), + exclude('mysql', '<', (5, 0, 3), 'not supported by database'), + ) + +def unicode_connections(fn): + """Target driver must support some encoding of Unicode across the wire.""" + # TODO: expand to exclude MySQLdb versions w/ broken unicode + return _chain_decorators_on( + fn, + exclude('mysql', '<', (4, 1, 1), 'no unicode connection support'), + ) + +def unicode_ddl(fn): + """Target driver must support some encoding of Unicode across the wire.""" + # TODO: expand to exclude MySQLdb versions w/ broken unicode + return _chain_decorators_on( + fn, + no_support('maxdb', 'database support flakey'), + no_support('oracle', 'FIXME: no support in database?'), + no_support('sybase', 'FIXME: guessing, needs confirmation'), + no_support('mssql+pymssql', 'no FreeTDS support'), + exclude('mysql', '<', (4, 1, 1), 'no unicode connection support'), + ) + +def sane_rowcount(fn): + return _chain_decorators_on( + fn, + skip_if(lambda: not testing.db.dialect.supports_sane_rowcount) + ) + +def cextensions(fn): + return _chain_decorators_on( + fn, + skip_if(lambda: not _has_cextensions(), "C extensions not installed") + ) + +def dbapi_lastrowid(fn): + return _chain_decorators_on( + fn, + fails_on_everything_except('mysql+mysqldb', 'mysql+oursql', 'sqlite+pysqlite') + ) + +def sane_multi_rowcount(fn): + return _chain_decorators_on( + fn, + skip_if(lambda: not testing.db.dialect.supports_sane_multi_rowcount) + ) + +def reflects_pk_names(fn): + """Target driver reflects the name of primary key constraints.""" + return _chain_decorators_on( + fn, + fails_on_everything_except('postgresql', 'oracle') + ) + +def python2(fn): + return _chain_decorators_on( + fn, + skip_if( + lambda: sys.version_info >= (3,), + "Python version 2.xx is required." + ) + ) + +def python26(fn): + return _chain_decorators_on( + fn, + skip_if( + lambda: sys.version_info < (2, 6), + "Python version 2.6 or greater is required" + ) + ) + +def _has_cextensions(): + try: + from sqlalchemy import cresultproxy, cprocessors + return True + except ImportError: + return False + +def _has_sqlite(): + from sqlalchemy import create_engine + try: + e = create_engine('sqlite://') + return True + except ImportError: + return False + +def sqlite(fn): + return _chain_decorators_on( + fn, + skip_if(lambda: not _has_sqlite()) + ) + diff --git a/test/lib/schema.py b/test/lib/schema.py new file mode 100644 index 000000000..614e5863e --- /dev/null +++ b/test/lib/schema.py @@ -0,0 +1,79 @@ +"""Enhanced versions of schema.Table and schema.Column which establish +desired state for different backends. +""" + +from test.lib import testing +from sqlalchemy import schema + +__all__ = 'Table', 'Column', + +table_options = {} + +def Table(*args, **kw): + """A schema.Table wrapper/hook for dialect-specific tweaks.""" + + test_opts = dict([(k,kw.pop(k)) for k in kw.keys() + if k.startswith('test_')]) + + kw.update(table_options) + + if testing.against('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' + + # Apply some default cascading rules for self-referential foreign keys. + # MySQL InnoDB has some issues around seleting self-refs too. + if testing.against('firebird'): + table_name = args[0] + unpack = (testing.config.db.dialect. + identifier_preparer.unformat_identifiers) + + # Only going after ForeignKeys in Columns. May need to + # expand to ForeignKeyConstraint too. + fks = [fk + for col in args if isinstance(col, schema.Column) + for fk in col.foreign_keys] + + for fk in fks: + # root around in raw spec + ref = fk._colspec + if isinstance(ref, schema.Column): + name = ref.table.name + else: + # take just the table name: on FB there cannot be + # a schema, so the first element is always the + # table name, possibly followed by the field name + name = unpack(ref)[0] + if name == table_name: + if fk.ondelete is None: + fk.ondelete = 'CASCADE' + if fk.onupdate is None: + fk.onupdate = 'CASCADE' + + return schema.Table(*args, **kw) + + +def Column(*args, **kw): + """A schema.Column wrapper/hook for dialect-specific tweaks.""" + + test_opts = dict([(k,kw.pop(k)) for k in kw.keys() + if k.startswith('test_')]) + + col = schema.Column(*args, **kw) + if 'test_needs_autoincrement' in test_opts and \ + kw.get('primary_key', False) and \ + testing.against('firebird', 'oracle'): + def add_seq(tbl, c): + c._init_items( + schema.Sequence(_truncate_name(testing.db.dialect, tbl.name + '_' + c.name + '_seq'), optional=True) + ) + col._on_table_attach(add_seq) + return col + +def _truncate_name(dialect, name): + if len(name) > dialect.max_identifier_length: + return name[0:max(dialect.max_identifier_length - 6, 0)] + "_" + hex(hash(name) % 64)[2:] + else: + return name + diff --git a/test/lib/testing.py b/test/lib/testing.py new file mode 100644 index 000000000..da2a3dfd3 --- /dev/null +++ b/test/lib/testing.py @@ -0,0 +1,797 @@ +"""TestCase and TestSuite artifacts and testing decorators.""" + +import itertools +import operator +import re +import sys +import types +import warnings +from cStringIO import StringIO + +from test.bootstrap import config +from test.lib import assertsql, util as testutil +from sqlalchemy.util import function_named, py3k +from engines import drop_all_tables + +from sqlalchemy import exc as sa_exc, util, types as sqltypes, schema, pool, orm +from sqlalchemy.engine import default +from nose import SkipTest + + +_ops = { '<': operator.lt, + '>': operator.gt, + '==': operator.eq, + '!=': operator.ne, + '<=': operator.le, + '>=': operator.ge, + 'in': operator.contains, + 'between': lambda val, pair: val >= pair[0] and val <= pair[1], + } + +# sugar ('testing.db'); set here by config() at runtime +db = None + +# more sugar, installed by __init__ +requires = None + +def fails_if(callable_, reason=None): + """Mark a test as expected to fail if callable_ returns True. + + If the callable returns false, the test is run and reported as normal. + However if the callable returns true, the test is expected to fail and the + unit test logic is inverted: if the test fails, a success is reported. If + the test succeeds, a failure is reported. + """ + + docstring = getattr(callable_, '__doc__', None) or callable_.__name__ + description = docstring.split('\n')[0] + + def decorate(fn): + fn_name = fn.__name__ + def maybe(*args, **kw): + if not callable_(): + return fn(*args, **kw) + else: + try: + fn(*args, **kw) + except Exception, ex: + print ("'%s' failed as expected (condition: %s): %s " % ( + fn_name, description, str(ex))) + return True + else: + raise AssertionError( + "Unexpected success for '%s' (condition: %s)" % + (fn_name, description)) + return function_named(maybe, fn_name) + return decorate + + +def future(fn): + """Mark a test as expected to unconditionally fail. + + Takes no arguments, omit parens when using as a decorator. + """ + + fn_name = fn.__name__ + def decorated(*args, **kw): + try: + fn(*args, **kw) + except Exception, ex: + print ("Future test '%s' failed as expected: %s " % ( + fn_name, str(ex))) + return True + else: + raise AssertionError( + "Unexpected success for future test '%s'" % fn_name) + return function_named(decorated, fn_name) + +def db_spec(*dbs): + dialects = set([x for x in dbs if '+' not in x]) + drivers = set([x[1:] for x in dbs if x.startswith('+')]) + specs = set([tuple(x.split('+')) for x in dbs if '+' in x and x not in drivers]) + + def check(engine): + return engine.name in dialects or \ + engine.driver in drivers or \ + (engine.name, engine.driver) in specs + + return check + + +def fails_on(dbs, reason): + """Mark a test as expected to fail on the specified database + implementation. + + Unlike ``crashes``, tests marked as ``fails_on`` will be run + for the named databases. The test is expected to fail and the unit test + logic is inverted: if the test fails, a success is reported. If the test + succeeds, a failure is reported. + """ + + spec = db_spec(dbs) + + def decorate(fn): + fn_name = fn.__name__ + def maybe(*args, **kw): + if not spec(config.db): + return fn(*args, **kw) + else: + try: + fn(*args, **kw) + except Exception, ex: + print ("'%s' failed as expected on DB implementation " + "'%s+%s': %s" % ( + fn_name, config.db.name, config.db.driver, reason)) + return True + else: + raise AssertionError( + "Unexpected success for '%s' on DB implementation '%s+%s'" % + (fn_name, config.db.name, config.db.driver)) + return function_named(maybe, fn_name) + return decorate + +def fails_on_everything_except(*dbs): + """Mark a test as expected to fail on most database implementations. + + Like ``fails_on``, except failure is the expected outcome on all + databases except those listed. + """ + + spec = db_spec(*dbs) + + def decorate(fn): + fn_name = fn.__name__ + def maybe(*args, **kw): + if spec(config.db): + return fn(*args, **kw) + else: + try: + fn(*args, **kw) + except Exception, ex: + print ("'%s' failed as expected on DB implementation " + "'%s+%s': %s" % ( + fn_name, config.db.name, config.db.driver, str(ex))) + return True + else: + raise AssertionError( + "Unexpected success for '%s' on DB implementation '%s+%s'" % + (fn_name, config.db.name, config.db.driver)) + return function_named(maybe, fn_name) + return decorate + +def crashes(db, reason): + """Mark a test as unsupported by a database implementation. + + ``crashes`` tests will be skipped unconditionally. Use for feature tests + that cause deadlocks or other fatal problems. + + """ + carp = _should_carp_about_exclusion(reason) + spec = db_spec(db) + def decorate(fn): + fn_name = fn.__name__ + def maybe(*args, **kw): + if spec(config.db): + msg = "'%s' unsupported on DB implementation '%s+%s': %s" % ( + fn_name, config.db.name, config.db.driver, reason) + print msg + if carp: + print >> sys.stderr, msg + return True + else: + return fn(*args, **kw) + return function_named(maybe, fn_name) + return decorate + +def _block_unconditionally(db, reason): + """Mark a test as unsupported by a database implementation. + + Will never run the test against any version of the given database, ever, + no matter what. Use when your assumptions are infallible; past, present + and future. + + """ + carp = _should_carp_about_exclusion(reason) + spec = db_spec(db) + def decorate(fn): + fn_name = fn.__name__ + def maybe(*args, **kw): + if spec(config.db): + msg = "'%s' unsupported on DB implementation '%s+%s': %s" % ( + fn_name, config.db.name, config.db.driver, reason) + print msg + if carp: + print >> sys.stderr, msg + return True + else: + return fn(*args, **kw) + return function_named(maybe, fn_name) + return decorate + +def only_on(dbs, reason): + carp = _should_carp_about_exclusion(reason) + spec = db_spec(*util.to_list(dbs)) + def decorate(fn): + fn_name = fn.__name__ + def maybe(*args, **kw): + if spec(config.db): + return fn(*args, **kw) + else: + msg = "'%s' unsupported on DB implementation '%s+%s': %s" % ( + fn_name, config.db.name, config.db.driver, reason) + print msg + if carp: + print >> sys.stderr, msg + return True + return function_named(maybe, fn_name) + return decorate + +def exclude(db, op, spec, reason): + """Mark a test as unsupported by specific database server versions. + + Stackable, both with other excludes and other decorators. Examples:: + + # Not supported by mydb versions less than 1, 0 + @exclude('mydb', '<', (1,0)) + # Other operators work too + @exclude('bigdb', '==', (9,0,9)) + @exclude('yikesdb', 'in', ((0, 3, 'alpha2'), (0, 3, 'alpha3'))) + + """ + carp = _should_carp_about_exclusion(reason) + + def decorate(fn): + fn_name = fn.__name__ + def maybe(*args, **kw): + if _is_excluded(db, op, spec): + msg = "'%s' unsupported on DB %s version '%s': %s" % ( + fn_name, config.db.name, _server_version(), reason) + print msg + if carp: + print >> sys.stderr, msg + return True + else: + return fn(*args, **kw) + return function_named(maybe, fn_name) + return decorate + +def _should_carp_about_exclusion(reason): + """Guard against forgotten exclusions.""" + assert reason + for _ in ('todo', 'fixme', 'xxx'): + if _ in reason.lower(): + return True + else: + if len(reason) < 4: + return True + +def _is_excluded(db, op, spec): + """Return True if the configured db matches an exclusion specification. + + db: + A dialect name + op: + An operator or stringified operator, such as '==' + spec: + A value that will be compared to the dialect's server_version_info + using the supplied operator. + + Examples:: + # Not supported by mydb versions less than 1, 0 + _is_excluded('mydb', '<', (1,0)) + # Other operators work too + _is_excluded('bigdb', '==', (9,0,9)) + _is_excluded('yikesdb', 'in', ((0, 3, 'alpha2'), (0, 3, 'alpha3'))) + """ + + vendor_spec = db_spec(db) + + if not vendor_spec(config.db): + return False + + version = _server_version() + + oper = hasattr(op, '__call__') and op or _ops[op] + return oper(version, spec) + +def _server_version(bind=None): + """Return a server_version_info tuple.""" + + if bind is None: + bind = config.db + + # force metadata to be retrieved + conn = bind.connect() + version = getattr(bind.dialect, 'server_version_info', ()) + conn.close() + return version + +def skip_if(predicate, reason=None): + """Skip a test if predicate is true.""" + reason = reason or predicate.__name__ + carp = _should_carp_about_exclusion(reason) + + def decorate(fn): + fn_name = fn.__name__ + def maybe(*args, **kw): + if predicate(): + msg = "'%s' skipped on DB %s version '%s': %s" % ( + fn_name, config.db.name, _server_version(), reason) + print msg + if carp: + print >> sys.stderr, msg + return True + else: + return fn(*args, **kw) + return function_named(maybe, fn_name) + return decorate + +def emits_warning(*messages): + """Mark a test as emitting a warning. + + With no arguments, squelches all SAWarning failures. Or pass one or more + strings; these will be matched to the root of the warning description by + warnings.filterwarnings(). + """ + + # TODO: it would be nice to assert that a named warning was + # emitted. should work with some monkeypatching of warnings, + # and may work on non-CPython if they keep to the spirit of + # warnings.showwarning's docstring. + # - update: jython looks ok, it uses cpython's module + def decorate(fn): + def safe(*args, **kw): + # todo: should probably be strict about this, too + filters = [dict(action='ignore', + category=sa_exc.SAPendingDeprecationWarning)] + if not messages: + filters.append(dict(action='ignore', + category=sa_exc.SAWarning)) + else: + filters.extend(dict(action='ignore', + message=message, + category=sa_exc.SAWarning) + for message in messages) + for f in filters: + warnings.filterwarnings(**f) + try: + return fn(*args, **kw) + finally: + resetwarnings() + return function_named(safe, fn.__name__) + return decorate + +def emits_warning_on(db, *warnings): + """Mark a test as emitting a warning on a specific dialect. + + With no arguments, squelches all SAWarning failures. Or pass one or more + strings; these will be matched to the root of the warning description by + warnings.filterwarnings(). + """ + spec = db_spec(db) + + def decorate(fn): + def maybe(*args, **kw): + if isinstance(db, basestring): + if not spec(config.db): + return fn(*args, **kw) + else: + wrapped = emits_warning(*warnings)(fn) + return wrapped(*args, **kw) + else: + if not _is_excluded(*db): + return fn(*args, **kw) + else: + wrapped = emits_warning(*warnings)(fn) + return wrapped(*args, **kw) + return function_named(maybe, fn.__name__) + return decorate + +def uses_deprecated(*messages): + """Mark a test as immune from fatal deprecation warnings. + + With no arguments, squelches all SADeprecationWarning failures. + Or pass one or more strings; these will be matched to the root + of the warning description by warnings.filterwarnings(). + + As a special case, you may pass a function name prefixed with // + and it will be re-written as needed to match the standard warning + verbiage emitted by the sqlalchemy.util.deprecated decorator. + """ + + + def decorate(fn): + def safe(*args, **kw): + # todo: should probably be strict about this, too + filters = [dict(action='ignore', + category=sa_exc.SAPendingDeprecationWarning)] + if not messages: + filters.append(dict(action='ignore', + category=sa_exc.SADeprecationWarning)) + else: + filters.extend( + [dict(action='ignore', + message=message, + category=sa_exc.SADeprecationWarning) + for message in + [ (m.startswith('//') and + ('Call to deprecated function ' + m[2:]) or m) + for m in messages] ]) + + for f in filters: + warnings.filterwarnings(**f) + try: + return fn(*args, **kw) + finally: + resetwarnings() + return function_named(safe, fn.__name__) + return decorate + +def resetwarnings(): + """Reset warning behavior to testing defaults.""" + + warnings.filterwarnings('ignore', + category=sa_exc.SAPendingDeprecationWarning) + warnings.filterwarnings('error', category=sa_exc.SADeprecationWarning) + warnings.filterwarnings('error', category=sa_exc.SAWarning) + +# warnings.simplefilter('error') + + +def global_cleanup_assertions(): + """Check things that have to be finalized at the end of a test suite. + + Hardcoded at the moment, a modular system can be built here + to support things like PG prepared transactions, tables all + dropped, etc. + + """ + + testutil.lazy_gc() + assert not pool._refs + + + +def against(*queries): + """Boolean predicate, compares to testing database configuration. + + Given one or more dialect names, returns True if one is the configured + database engine. + + Also supports comparison to database version when provided with one or + more 3-tuples of dialect name, operator, and version specification:: + + testing.against('mysql', 'postgresql') + testing.against(('mysql', '>=', (5, 0, 0)) + """ + + for query in queries: + if isinstance(query, basestring): + if db_spec(query)(config.db): + return True + else: + name, op, spec = query + if not db_spec(name)(config.db): + continue + + have = _server_version() + + oper = hasattr(op, '__call__') and op or _ops[op] + if oper(have, spec): + return True + return False + +def _chain_decorators_on(fn, *decorators): + """Apply a series of decorators to fn, returning a decorated function.""" + for decorator in reversed(decorators): + fn = decorator(fn) + return fn + +def rowset(results): + """Converts the results of sql execution into a plain set of column tuples. + + Useful for asserting the results of an unordered query. + """ + + return set([tuple(row) for row in results]) + + +def eq_(a, b, msg=None): + """Assert a == b, with repr messaging on failure.""" + assert a == b, msg or "%r != %r" % (a, b) + +def ne_(a, b, msg=None): + """Assert a != b, with repr messaging on failure.""" + assert a != b, msg or "%r == %r" % (a, b) + +def is_(a, b, msg=None): + """Assert a is b, with repr messaging on failure.""" + assert a is b, msg or "%r is not %r" % (a, b) + +def is_not_(a, b, msg=None): + """Assert a is not b, with repr messaging on failure.""" + assert a is not b, msg or "%r is %r" % (a, b) + +def startswith_(a, fragment, msg=None): + """Assert a.startswith(fragment), with repr messaging on failure.""" + assert a.startswith(fragment), msg or "%r does not start with %r" % ( + a, fragment) + +def assert_raises(except_cls, callable_, *args, **kw): + try: + callable_(*args, **kw) + success = False + except except_cls, e: + success = True + + # assert outside the block so it works for AssertionError too ! + assert success, "Callable did not raise an exception" + +def assert_raises_message(except_cls, msg, callable_, *args, **kwargs): + try: + callable_(*args, **kwargs) + assert False, "Callable did not raise an exception" + except except_cls, e: + assert re.search(msg, str(e)), "%r !~ %s" % (msg, e) + print str(e) + +def fail(msg): + assert False, msg + +def fixture(table, columns, *rows): + """Insert data into table after creation.""" + def onload(event, schema_item, connection): + insert = table.insert() + column_names = [col.key for col in columns] + connection.execute(insert, [dict(zip(column_names, column_values)) + for column_values in rows]) + table.append_ddl_listener('after-create', onload) + +def provide_metadata(fn): + """Provides a bound MetaData object for a single test, + drops it afterwards.""" + def maybe(*args, **kw): + metadata = schema.MetaData(db) + context = dict(fn.func_globals) + context['metadata'] = metadata + # jython bug #1034 + rebound = types.FunctionType( + fn.func_code, context, fn.func_name, fn.func_defaults, + fn.func_closure) + try: + return rebound(*args, **kw) + finally: + metadata.drop_all() + return function_named(maybe, fn.__name__) + +def resolve_artifact_names(fn): + """Decorator, augment function globals with tables and classes. + + Swaps out the function's globals at execution time. The 'global' statement + will not work as expected inside a decorated function. + + """ + # This could be automatically applied to framework and test_ methods in + # the MappedTest-derived test suites but... *some* explicitness for this + # magic is probably good. Especially as 'global' won't work- these + # rebound functions aren't regular Python.. + # + # Also: it's lame that CPython accepts a dict-subclass for globals, but + # only calls dict methods. That would allow 'global' to pass through to + # the func_globals. + def resolved(*args, **kwargs): + self = args[0] + context = dict(fn.func_globals) + for source in self._artifact_registries: + context.update(getattr(self, source)) + # jython bug #1034 + rebound = types.FunctionType( + fn.func_code, context, fn.func_name, fn.func_defaults, + fn.func_closure) + return rebound(*args, **kwargs) + return function_named(resolved, fn.func_name) + +class adict(dict): + """Dict keys available as attributes. Shadows.""" + def __getattribute__(self, key): + try: + return self[key] + except KeyError: + return dict.__getattribute__(self, key) + + def get_all(self, *keys): + return tuple([self[key] for key in keys]) + + +class TestBase(object): + # A sequence of database names to always run, regardless of the + # constraints below. + __whitelist__ = () + + # A sequence of requirement names matching testing.requires decorators + __requires__ = () + + # A sequence of dialect names to exclude from the test class. + __unsupported_on__ = () + + # If present, test class is only runnable for the *single* specified + # dialect. If you need multiple, use __unsupported_on__ and invert. + __only_on__ = None + + # A sequence of no-arg callables. If any are True, the entire testcase is + # skipped. + __skip_if__ = None + + _artifact_registries = () + + def assert_(self, val, msg=None): + assert val, msg + +class AssertsCompiledSQL(object): + def assert_compile(self, clause, result, params=None, checkparams=None, dialect=None, use_default_dialect=False): + if use_default_dialect: + dialect = default.DefaultDialect() + + if dialect is None: + dialect = getattr(self, '__dialect__', None) + + kw = {} + if params is not None: + kw['column_keys'] = params.keys() + + if isinstance(clause, orm.Query): + context = clause._compile_context() + context.statement.use_labels = True + clause = context.statement + + c = clause.compile(dialect=dialect, **kw) + + param_str = repr(getattr(c, 'params', {})) + # Py3K + #param_str = param_str.encode('utf-8').decode('ascii', 'ignore') + + print "\nSQL String:\n" + str(c) + param_str + + cc = re.sub(r'[\n\t]', '', str(c)) + + eq_(cc, result, "%r != %r on dialect %r" % (cc, result, dialect)) + + if checkparams is not None: + eq_(c.construct_params(params), checkparams) + +class ComparesTables(object): + def assert_tables_equal(self, table, reflected_table, strict_types=False): + assert len(table.c) == len(reflected_table.c) + for c, reflected_c in zip(table.c, reflected_table.c): + eq_(c.name, reflected_c.name) + assert reflected_c is reflected_table.c[c.name] + eq_(c.primary_key, reflected_c.primary_key) + eq_(c.nullable, reflected_c.nullable) + + if strict_types: + assert type(reflected_c.type) is type(c.type), \ + "Type '%s' doesn't correspond to type '%s'" % (reflected_c.type, c.type) + else: + self.assert_types_base(reflected_c, c) + + if isinstance(c.type, sqltypes.String): + eq_(c.type.length, reflected_c.type.length) + + eq_(set([f.column.name for f in c.foreign_keys]), set([f.column.name for f in reflected_c.foreign_keys])) + if c.server_default: + assert isinstance(reflected_c.server_default, + schema.FetchedValue) + + assert len(table.primary_key) == len(reflected_table.primary_key) + for c in table.primary_key: + assert reflected_table.primary_key.columns[c.name] is not None + + def assert_types_base(self, c1, c2): + assert c1.type._compare_type_affinity(c2.type),\ + "On column %r, type '%s' doesn't correspond to type '%s'" % \ + (c1.name, c1.type, c2.type) + +class AssertsExecutionResults(object): + def assert_result(self, result, class_, *objects): + result = list(result) + print repr(result) + self.assert_list(result, class_, objects) + + def assert_list(self, result, class_, list): + self.assert_(len(result) == len(list), + "result list is not the same size as test list, " + + "for class " + class_.__name__) + for i in range(0, len(list)): + self.assert_row(class_, result[i], list[i]) + + def assert_row(self, class_, rowobj, desc): + self.assert_(rowobj.__class__ is class_, + "item class is not " + repr(class_)) + for key, value in desc.iteritems(): + if isinstance(value, tuple): + if isinstance(value[1], list): + self.assert_list(getattr(rowobj, key), value[0], value[1]) + else: + self.assert_row(value[0], getattr(rowobj, key), value[1]) + else: + self.assert_(getattr(rowobj, key) == value, + "attribute %s value %s does not match %s" % ( + key, getattr(rowobj, key), value)) + + def assert_unordered_result(self, result, cls, *expected): + """As assert_result, but the order of objects is not considered. + + The algorithm is very expensive but not a big deal for the small + numbers of rows that the test suite manipulates. + """ + + class frozendict(dict): + def __hash__(self): + return id(self) + + found = util.IdentitySet(result) + expected = set([frozendict(e) for e in expected]) + + for wrong in itertools.ifilterfalse(lambda o: type(o) == cls, found): + fail('Unexpected type "%s", expected "%s"' % ( + type(wrong).__name__, cls.__name__)) + + if len(found) != len(expected): + fail('Unexpected object count "%s", expected "%s"' % ( + len(found), len(expected))) + + NOVALUE = object() + def _compare_item(obj, spec): + for key, value in spec.iteritems(): + if isinstance(value, tuple): + try: + self.assert_unordered_result( + getattr(obj, key), value[0], *value[1]) + except AssertionError: + return False + else: + if getattr(obj, key, NOVALUE) != value: + return False + return True + + for expected_item in expected: + for found_item in found: + if _compare_item(found_item, expected_item): + found.remove(found_item) + break + else: + fail( + "Expected %s instance with attributes %s not found." % ( + cls.__name__, repr(expected_item))) + return True + + def assert_sql_execution(self, db, callable_, *rules): + assertsql.asserter.add_rules(rules) + try: + callable_() + assertsql.asserter.statement_complete() + finally: + assertsql.asserter.clear_rules() + + def assert_sql(self, db, callable_, list_, with_sequences=None): + if with_sequences is not None and config.db.name in ('firebird', 'oracle', 'postgresql'): + rules = with_sequences + else: + rules = list_ + + newrules = [] + for rule in rules: + if isinstance(rule, dict): + newrule = assertsql.AllOf(*[ + assertsql.ExactSQL(k, v) for k, v in rule.iteritems() + ]) + else: + newrule = assertsql.ExactSQL(*rule) + newrules.append(newrule) + + self.assert_sql_execution(db, callable_, *newrules) + + def assert_sql_count(self, db, callable_, count): + self.assert_sql_execution(db, callable_, assertsql.CountStatements(count)) + + diff --git a/test/lib/util.py b/test/lib/util.py new file mode 100644 index 000000000..f2b6b49ea --- /dev/null +++ b/test/lib/util.py @@ -0,0 +1,76 @@ +from sqlalchemy.util import jython, function_named + +import gc +import time +import random + +if jython: + def gc_collect(*args): + """aggressive gc.collect for tests.""" + gc.collect() + time.sleep(0.1) + gc.collect() + gc.collect() + return 0 + + # "lazy" gc, for VM's that don't GC on refcount == 0 + lazy_gc = gc_collect + +else: + # assume CPython - straight gc.collect, lazy_gc() is a pass + gc_collect = gc.collect + def lazy_gc(): + pass + +def picklers(): + picklers = set() + # Py2K + try: + import cPickle + picklers.add(cPickle) + except ImportError: + pass + # end Py2K + import pickle + picklers.add(pickle) + + # yes, this thing needs this much testing + for pickle in picklers: + for protocol in -1, 0, 1, 2: + yield pickle.loads, lambda d:pickle.dumps(d, protocol) + + +def round_decimal(value, prec): + if isinstance(value, float): + return round(value, prec) + + import decimal + + # can also use shift() here but that is 2.6 only + return (value * decimal.Decimal("1" + "0" * prec)).to_integral(decimal.ROUND_FLOOR) / \ + pow(10, prec) + +class RandomSet(set): + def __iter__(self): + l = list(set.__iter__(self)) + random.shuffle(l) + return iter(l) + + def pop(self): + index = random.randint(0, len(self) - 1) + item = list(set.__iter__(self))[index] + self.remove(item) + return item + + def union(self, other): + return RandomSet(set.union(self, other)) + + def difference(self, other): + return RandomSet(set.difference(self, other)) + + def intersection(self, other): + return RandomSet(set.intersection(self, other)) + + def copy(self): + return RandomSet(self) + \ No newline at end of file diff --git a/test/orm/_base.py b/test/orm/_base.py index 4d0031f5a..4ccc10157 100644 --- a/test/orm/_base.py +++ b/test/orm/_base.py @@ -3,11 +3,11 @@ import sys import types import sqlalchemy as sa import sqlalchemy.exceptions as sa_exc -from sqlalchemy.test import config, testing -from sqlalchemy.test.testing import resolve_artifact_names, adict -from sqlalchemy.test.engines import drop_all_tables +from test.lib import config, testing +from test.lib.testing import resolve_artifact_names, adict +from test.lib.engines import drop_all_tables from sqlalchemy.util import function_named -from sqlalchemy.test.entities import BasicEntity, ComparableEntity +from test.lib.entities import BasicEntity, ComparableEntity Entity = BasicEntity diff --git a/test/orm/_fixtures.py b/test/orm/_fixtures.py index a8df63b4a..8f128c287 100644 --- a/test/orm/_fixtures.py +++ b/test/orm/_fixtures.py @@ -1,8 +1,8 @@ from sqlalchemy import MetaData, Integer, String, ForeignKey -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column +from test.lib.schema import Table +from test.lib.schema import Column from sqlalchemy.orm import attributes -from sqlalchemy.test.testing import fixture +from test.lib.testing import fixture from test.orm import _base __all__ = () diff --git a/test/orm/inheritance/test_abc_inheritance.py b/test/orm/inheritance/test_abc_inheritance.py index edbd476ec..08ab28a08 100644 --- a/test/orm/inheritance/test_abc_inheritance.py +++ b/test/orm/inheritance/test_abc_inheritance.py @@ -2,8 +2,8 @@ from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.orm.interfaces import ONETOMANY, MANYTOONE -from sqlalchemy.test import testing -from sqlalchemy.test.schema import Table, Column +from test.lib import testing +from test.lib.schema import Table, Column from test.orm import _base diff --git a/test/orm/inheritance/test_abc_polymorphic.py b/test/orm/inheritance/test_abc_polymorphic.py index 2dab59bb2..fb229003b 100644 --- a/test/orm/inheritance/test_abc_polymorphic.py +++ b/test/orm/inheritance/test_abc_polymorphic.py @@ -4,7 +4,7 @@ from sqlalchemy.orm import * from sqlalchemy.util import function_named from test.orm import _base, _fixtures -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column class ABCTest(_base.MappedTest): @classmethod diff --git a/test/orm/inheritance/test_basic.py b/test/orm/inheritance/test_basic.py index c6dec16b7..9d3155655 100644 --- a/test/orm/inheritance/test_basic.py +++ b/test/orm/inheritance/test_basic.py @@ -1,14 +1,14 @@ import warnings -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message +from test.lib.testing import eq_, assert_raises, assert_raises_message from sqlalchemy import * from sqlalchemy import exc as sa_exc, util from sqlalchemy.orm import * from sqlalchemy.orm import exc as orm_exc -from sqlalchemy.test import testing, engines +from test.lib import testing, engines from sqlalchemy.util import function_named from test.orm import _base, _fixtures -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column class O2MTest(_base.MappedTest): """deals with inheritance and one-to-many relationships""" diff --git a/test/orm/inheritance/test_concrete.py b/test/orm/inheritance/test_concrete.py index a2d79284c..43ba36ace 100644 --- a/test/orm/inheritance/test_concrete.py +++ b/test/orm/inheritance/test_concrete.py @@ -1,15 +1,15 @@ -from sqlalchemy.test.testing import eq_, assert_raises, \ +from test.lib.testing import eq_, assert_raises, \ assert_raises_message from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.orm import exc as orm_exc -from sqlalchemy.test import * +from test.lib import * import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from test.orm import _base from sqlalchemy.orm import attributes -from sqlalchemy.test.testing import eq_ -from sqlalchemy.test.schema import Table, Column +from test.lib.testing import eq_ +from test.lib.schema import Table, Column class Employee(object): diff --git a/test/orm/inheritance/test_magazine.py b/test/orm/inheritance/test_magazine.py index 125a5629c..307c54a9c 100644 --- a/test/orm/inheritance/test_magazine.py +++ b/test/orm/inheritance/test_magazine.py @@ -1,10 +1,10 @@ from sqlalchemy import * from sqlalchemy.orm import * -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy.util import function_named from test.orm import _base -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column class BaseObject(object): def __init__(self, *args, **kwargs): diff --git a/test/orm/inheritance/test_manytomany.py b/test/orm/inheritance/test_manytomany.py index 8390e2a1b..f5e3e63a1 100644 --- a/test/orm/inheritance/test_manytomany.py +++ b/test/orm/inheritance/test_manytomany.py @@ -1,8 +1,8 @@ -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from sqlalchemy import * from sqlalchemy.orm import * -from sqlalchemy.test import testing +from test.lib import testing from test.orm import _base diff --git a/test/orm/inheritance/test_poly_linked_list.py b/test/orm/inheritance/test_poly_linked_list.py index e16c95555..046cf4b34 100644 --- a/test/orm/inheritance/test_poly_linked_list.py +++ b/test/orm/inheritance/test_poly_linked_list.py @@ -2,8 +2,8 @@ from sqlalchemy import * from sqlalchemy.orm import * from test.orm import _base -from sqlalchemy.test import testing -from sqlalchemy.test.schema import Table, Column +from test.lib import testing +from test.lib.schema import Table, Column class PolymorphicCircularTest(_base.MappedTest): diff --git a/test/orm/inheritance/test_polymorph.py b/test/orm/inheritance/test_polymorph.py index eed2395d7..8eeeeec50 100644 --- a/test/orm/inheritance/test_polymorph.py +++ b/test/orm/inheritance/test_polymorph.py @@ -1,10 +1,10 @@ """tests basic polymorphic mapper loading/saving, minimal relationships""" -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message +from test.lib.testing import eq_, assert_raises, assert_raises_message from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.orm import exc as orm_exc -from sqlalchemy.test import Column, testing +from test.lib import Column, testing from sqlalchemy.util import function_named from test.orm import _fixtures, _base diff --git a/test/orm/inheritance/test_polymorph2.py b/test/orm/inheritance/test_polymorph2.py index 9852e8b09..030b931a5 100644 --- a/test/orm/inheritance/test_polymorph2.py +++ b/test/orm/inheritance/test_polymorph2.py @@ -2,16 +2,16 @@ inheritance setups for which we maintain compatibility. """ -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from sqlalchemy import * from sqlalchemy import util from sqlalchemy.orm import * -from sqlalchemy.test import TestBase, AssertsExecutionResults, testing +from test.lib import TestBase, AssertsExecutionResults, testing from sqlalchemy.util import function_named from test.orm import _base, _fixtures -from sqlalchemy.test.testing import eq_ -from sqlalchemy.test.schema import Table, Column +from test.lib.testing import eq_ +from test.lib.schema import Table, Column class AttrSettable(object): def __init__(self, **kwargs): diff --git a/test/orm/inheritance/test_productspec.py b/test/orm/inheritance/test_productspec.py index dc81d9245..a1ecf2562 100644 --- a/test/orm/inheritance/test_productspec.py +++ b/test/orm/inheritance/test_productspec.py @@ -2,9 +2,9 @@ from datetime import datetime from sqlalchemy import * from sqlalchemy.orm import * -from sqlalchemy.test import testing +from test.lib import testing from test.orm import _base -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column class InheritTest(_base.MappedTest): """tests some various inheritance round trips involving a particular set of polymorphic inheritance relationships""" diff --git a/test/orm/inheritance/test_query.py b/test/orm/inheritance/test_query.py index 9e944ca6f..e7d4d618a 100644 --- a/test/orm/inheritance/test_query.py +++ b/test/orm/inheritance/test_query.py @@ -1,4 +1,4 @@ -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message +from test.lib.testing import eq_, assert_raises, assert_raises_message from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.orm import interfaces @@ -6,10 +6,10 @@ from sqlalchemy import exc as sa_exc from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.engine import default -from sqlalchemy.test import AssertsCompiledSQL, testing +from test.lib import AssertsCompiledSQL, testing from test.orm import _base, _fixtures -from sqlalchemy.test.testing import eq_ -from sqlalchemy.test.schema import Table, Column +from test.lib.testing import eq_ +from test.lib.schema import Table, Column class Company(_fixtures.Base): pass diff --git a/test/orm/inheritance/test_selects.py b/test/orm/inheritance/test_selects.py index 7c9920f6f..5a7389386 100644 --- a/test/orm/inheritance/test_selects.py +++ b/test/orm/inheritance/test_selects.py @@ -1,7 +1,7 @@ from sqlalchemy import * from sqlalchemy.orm import * -from sqlalchemy.test import testing +from test.lib import testing from test.orm._fixtures import Base from test.orm._base import MappedTest diff --git a/test/orm/inheritance/test_single.py b/test/orm/inheritance/test_single.py index 2efde2b32..a65851a5f 100644 --- a/test/orm/inheritance/test_single.py +++ b/test/orm/inheritance/test_single.py @@ -1,11 +1,11 @@ -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from sqlalchemy import * from sqlalchemy.orm import * -from sqlalchemy.test import testing +from test.lib import testing from test.orm import _fixtures from test.orm._base import MappedTest, ComparableEntity -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column class SingleInheritanceTest(testing.AssertsCompiledSQL, MappedTest): diff --git a/test/orm/test_association.py b/test/orm/test_association.py index c9b1584bb..e681099c5 100644 --- a/test/orm/test_association.py +++ b/test/orm/test_association.py @@ -1,10 +1,10 @@ -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import Integer, String, ForeignKey -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, relationship, create_session from test.orm import _base -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ class AssociationTest(_base.MappedTest): diff --git a/test/orm/test_assorted_eager.py b/test/orm/test_assorted_eager.py index 0e389b74b..050e39d82 100644 --- a/test/orm/test_assorted_eager.py +++ b/test/orm/test_assorted_eager.py @@ -6,11 +6,11 @@ Derived from mailing list-reported problems and trac tickets. import datetime import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import Integer, String, ForeignKey -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, relationship, backref, create_session -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from test.orm import _base diff --git a/test/orm/test_attributes.py b/test/orm/test_attributes.py index 742e9d874..cedfccd5b 100644 --- a/test/orm/test_attributes.py +++ b/test/orm/test_attributes.py @@ -3,10 +3,10 @@ import sqlalchemy.orm.attributes as attributes from sqlalchemy.orm.collections import collection from sqlalchemy.orm.interfaces import AttributeExtension from sqlalchemy import exc as sa_exc -from sqlalchemy.test import * -from sqlalchemy.test.testing import eq_, ne_, assert_raises +from test.lib import * +from test.lib.testing import eq_, ne_, assert_raises from test.orm import _base -from sqlalchemy.test.util import gc_collect +from test.lib.util import gc_collect from sqlalchemy.util import cmp, jython # global for pickling tests diff --git a/test/orm/test_backref_mutations.py b/test/orm/test_backref_mutations.py index 13b44e1bb..53337c204 100644 --- a/test/orm/test_backref_mutations.py +++ b/test/orm/test_backref_mutations.py @@ -9,14 +9,14 @@ UPDATE in the database. """ -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message from sqlalchemy import Integer, String, ForeignKey, Sequence, exc as sa_exc -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column +from test.lib.schema import Table +from test.lib.schema import Column from sqlalchemy.orm import mapper, relationship, create_session, class_mapper, backref, sessionmaker from sqlalchemy.orm import attributes, exc as orm_exc -from sqlalchemy.test import testing -from sqlalchemy.test.testing import eq_ +from test.lib import testing +from test.lib.testing import eq_ from test.orm import _base, _fixtures class O2MCollectionTest(_fixtures.FixtureTest): diff --git a/test/orm/test_bind.py b/test/orm/test_bind.py index 9b1c20b60..bab9be428 100644 --- a/test/orm/test_bind.py +++ b/test/orm/test_bind.py @@ -1,10 +1,10 @@ -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message from sqlalchemy import MetaData, Integer -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column +from test.lib.schema import Table +from test.lib.schema import Column from sqlalchemy.orm import mapper, create_session import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from test.orm import _base diff --git a/test/orm/test_cascade.py b/test/orm/test_cascade.py index 75b9e22ec..27f231b06 100644 --- a/test/orm/test_cascade.py +++ b/test/orm/test_cascade.py @@ -1,13 +1,13 @@ -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message from sqlalchemy import Integer, String, ForeignKey, Sequence, \ exc as sa_exc -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, relationship, create_session, \ sessionmaker, class_mapper, backref, Session from sqlalchemy.orm import attributes, exc as orm_exc -from sqlalchemy.test import testing -from sqlalchemy.test.testing import eq_ +from test.lib import testing +from test.lib.testing import eq_ from test.orm import _base, _fixtures diff --git a/test/orm/test_collection.py b/test/orm/test_collection.py index 730605a76..1e92d4155 100644 --- a/test/orm/test_collection.py +++ b/test/orm/test_collection.py @@ -1,4 +1,4 @@ -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ import sys from operator import and_ @@ -6,13 +6,13 @@ import sqlalchemy.orm.collections as collections from sqlalchemy.orm.collections import collection import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import Integer, String, ForeignKey, text -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy import util, exc as sa_exc from sqlalchemy.orm import create_session, mapper, relationship, attributes from test.orm import _base -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message +from test.lib.testing import eq_, assert_raises, assert_raises_message class Canary(sa.orm.interfaces.AttributeExtension): def __init__(self): diff --git a/test/orm/test_compile.py b/test/orm/test_compile.py index 101e4143a..a4fd280a2 100644 --- a/test/orm/test_compile.py +++ b/test/orm/test_compile.py @@ -1,7 +1,7 @@ from sqlalchemy import * from sqlalchemy import exc as sa_exc from sqlalchemy.orm import * -from sqlalchemy.test import * +from test.lib import * from test.orm import _base diff --git a/test/orm/test_cycles.py b/test/orm/test_cycles.py index 26765244a..e5e657933 100644 --- a/test/orm/test_cycles.py +++ b/test/orm/test_cycles.py @@ -5,13 +5,13 @@ T1<->T2, with o2m or m2o between them, and a third T3 with o2m/m2o to one/both T1/T2. """ -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import Integer, String, ForeignKey -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, relationship, backref, \ create_session, sessionmaker -from sqlalchemy.test.testing import eq_ -from sqlalchemy.test.assertsql import RegexSQL, ExactSQL, CompiledSQL, AllOf +from test.lib.testing import eq_ +from test.lib.assertsql import RegexSQL, ExactSQL, CompiledSQL, AllOf from test.orm import _base diff --git a/test/orm/test_defaults.py b/test/orm/test_defaults.py index 9be8e6e56..8e0b68918 100644 --- a/test/orm/test_defaults.py +++ b/test/orm/test_defaults.py @@ -1,11 +1,11 @@ import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import Integer, String, ForeignKey -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, relationship, create_session from test.orm import _base -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ class TriggerDefaultsTest(_base.MappedTest): diff --git a/test/orm/test_deprecations.py b/test/orm/test_deprecations.py index 76c59d029..2565105a6 100644 --- a/test/orm/test_deprecations.py +++ b/test/orm/test_deprecations.py @@ -5,10 +5,10 @@ modern (i.e. not deprecated) alternative to them. The tests snippets here can be migrated directly to the wiki, docs, etc. """ -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import Integer, String, ForeignKey, func -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column +from test.lib.schema import Table +from test.lib.schema import Column from sqlalchemy.orm import mapper, relationship, relation, create_session, sessionmaker from test.orm import _base diff --git a/test/orm/test_dynamic.py b/test/orm/test_dynamic.py index c06f6918a..c89503278 100644 --- a/test/orm/test_dynamic.py +++ b/test/orm/test_dynamic.py @@ -1,12 +1,12 @@ -from sqlalchemy.test.testing import eq_, ne_ +from test.lib.testing import eq_, ne_ import operator from sqlalchemy.orm import dynamic_loader, backref -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import Integer, String, ForeignKey, desc, select, func -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, relationship, create_session, Query, attributes from sqlalchemy.orm.dynamic import AppenderMixin -from sqlalchemy.test.testing import eq_, AssertsCompiledSQL, assert_raises_message +from test.lib.testing import eq_, AssertsCompiledSQL, assert_raises_message from sqlalchemy.util import function_named from test.orm import _base, _fixtures diff --git a/test/orm/test_eager_relations.py b/test/orm/test_eager_relations.py index b70ad0973..aad69b140 100644 --- a/test/orm/test_eager_relations.py +++ b/test/orm/test_eager_relations.py @@ -1,18 +1,18 @@ """tests of joined-eager loaded attributes""" -from sqlalchemy.test.testing import eq_, is_, is_not_ +from test.lib.testing import eq_, is_, is_not_ import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy.orm import joinedload, deferred, undefer, \ joinedload_all, backref from sqlalchemy import Integer, String, Date, ForeignKey, and_, select, \ func -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, relationship, create_session, \ lazyload, aliased -from sqlalchemy.test.testing import eq_, assert_raises, \ +from test.lib.testing import eq_, assert_raises, \ assert_raises_message -from sqlalchemy.test.assertsql import CompiledSQL +from test.lib.assertsql import CompiledSQL from test.orm import _base, _fixtures from sqlalchemy.util import OrderedDict as odict import datetime diff --git a/test/orm/test_evaluator.py b/test/orm/test_evaluator.py index af6a3f89e..26f9f49c3 100644 --- a/test/orm/test_evaluator.py +++ b/test/orm/test_evaluator.py @@ -1,11 +1,11 @@ """Evluating SQL expressions on ORM objects""" import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import String, Integer, select -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column +from test.lib.schema import Table +from test.lib.schema import Column from sqlalchemy.orm import mapper, create_session -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from test.orm import _base from sqlalchemy import and_, or_, not_ diff --git a/test/orm/test_expire.py b/test/orm/test_expire.py index c8bdf1719..93a3e198b 100644 --- a/test/orm/test_expire.py +++ b/test/orm/test_expire.py @@ -1,12 +1,12 @@ """Attribute/instance expiration, deferral of attributes, etc.""" -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message -from sqlalchemy.test.util import gc_collect +from test.lib.testing import eq_, assert_raises, assert_raises_message +from test.lib.util import gc_collect import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import Integer, String, ForeignKey, exc as sa_exc -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column +from test.lib.schema import Table +from test.lib.schema import Column from sqlalchemy.orm import mapper, relationship, create_session, \ attributes, deferred, exc as orm_exc, defer, undefer,\ strategies, state, lazyload, backref diff --git a/test/orm/test_extendedattr.py b/test/orm/test_extendedattr.py index 4374b9ecb..83839e77b 100644 --- a/test/orm/test_extendedattr.py +++ b/test/orm/test_extendedattr.py @@ -1,4 +1,4 @@ -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message +from test.lib.testing import eq_, assert_raises, assert_raises_message import pickle from sqlalchemy import util import sqlalchemy.orm.attributes as attributes @@ -6,7 +6,7 @@ from sqlalchemy.orm.collections import collection from sqlalchemy.orm.attributes import set_attribute, get_attribute, del_attribute, is_instrumented from sqlalchemy.orm import clear_mappers from sqlalchemy.orm import InstrumentationManager -from sqlalchemy.test import * +from test.lib import * from test.orm import _base class MyTypesManager(InstrumentationManager): diff --git a/test/orm/test_generative.py b/test/orm/test_generative.py index 31b7be8cc..440dc9554 100644 --- a/test/orm/test_generative.py +++ b/test/orm/test_generative.py @@ -1,11 +1,11 @@ -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import Integer, String, ForeignKey, MetaData, func -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column +from test.lib.schema import Table +from test.lib.schema import Column from sqlalchemy.orm import mapper, relationship, create_session -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from test.orm import _base, _fixtures diff --git a/test/orm/test_immediate_load.py b/test/orm/test_immediate_load.py index f85208bff..66794ad4b 100644 --- a/test/orm/test_immediate_load.py +++ b/test/orm/test_immediate_load.py @@ -1,8 +1,8 @@ """basic tests of lazy loaded attributes""" -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy.orm import mapper, relationship, create_session, immediateload -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from test.orm import _fixtures diff --git a/test/orm/test_instrumentation.py b/test/orm/test_instrumentation.py index b0c965470..0495ae20b 100644 --- a/test/orm/test_instrumentation.py +++ b/test/orm/test_instrumentation.py @@ -1,11 +1,11 @@ -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message import sqlalchemy as sa from sqlalchemy import MetaData, Integer, ForeignKey, util -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column +from test.lib.schema import Table +from test.lib.schema import Column from sqlalchemy.orm import mapper, relationship, create_session, attributes, class_mapper, clear_mappers -from sqlalchemy.test.testing import eq_, ne_ +from test.lib.testing import eq_, ne_ from sqlalchemy.util import function_named from test.orm import _base diff --git a/test/orm/test_lazy_relations.py b/test/orm/test_lazy_relations.py index f6147a3eb..1bf7eecaf 100644 --- a/test/orm/test_lazy_relations.py +++ b/test/orm/test_lazy_relations.py @@ -1,17 +1,17 @@ """basic tests of lazy loaded attributes""" -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message import datetime from sqlalchemy import exc as sa_exc from sqlalchemy.orm import attributes, exc as orm_exc import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import Integer, String, ForeignKey, SmallInteger from sqlalchemy.types import TypeDecorator -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column +from test.lib.schema import Table +from test.lib.schema import Column from sqlalchemy.orm import mapper, relationship, create_session -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from test.orm import _base, _fixtures diff --git a/test/orm/test_lazytest1.py b/test/orm/test_lazytest1.py index 3a96f430b..15f56e618 100644 --- a/test/orm/test_lazytest1.py +++ b/test/orm/test_lazytest1.py @@ -1,8 +1,8 @@ import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import Integer, String, ForeignKey -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column +from test.lib.schema import Table +from test.lib.schema import Column from sqlalchemy.orm import mapper, relationship, create_session from test.orm import _base diff --git a/test/orm/test_load_on_fks.py b/test/orm/test_load_on_fks.py index 8e4f53b0d..3e7ddb8c2 100644 --- a/test/orm/test_load_on_fks.py +++ b/test/orm/test_load_on_fks.py @@ -2,11 +2,11 @@ from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.test.testing import TestBase, eq_, AssertsExecutionResults, assert_raises -from sqlalchemy.test import testing +from test.lib.testing import TestBase, eq_, AssertsExecutionResults, assert_raises +from test.lib import testing from sqlalchemy.orm.attributes import instance_state from sqlalchemy.orm.exc import FlushError -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column engine = testing.db diff --git a/test/orm/test_manytomany.py b/test/orm/test_manytomany.py index 1b5c5f7ac..e8660ac6a 100644 --- a/test/orm/test_manytomany.py +++ b/test/orm/test_manytomany.py @@ -1,10 +1,10 @@ -from sqlalchemy.test.testing import assert_raises, \ +from test.lib.testing import assert_raises, \ assert_raises_message, eq_ import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import Integer, String, ForeignKey -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column +from test.lib.schema import Table +from test.lib.schema import Column from sqlalchemy.orm import mapper, relationship, create_session, \ exc as orm_exc, sessionmaker from test.orm import _base diff --git a/test/orm/test_mapper.py b/test/orm/test_mapper.py index f041c8896..f60d5a871 100644 --- a/test/orm/test_mapper.py +++ b/test/orm/test_mapper.py @@ -1,16 +1,16 @@ """General mapper operations with an emphasis on selecting/loading.""" -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message import sqlalchemy as sa -from sqlalchemy.test import testing, pickleable +from test.lib import testing, pickleable from sqlalchemy import MetaData, Integer, String, ForeignKey, func, util -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.engine import default from sqlalchemy.orm import mapper, relationship, backref, create_session, class_mapper, compile_mappers, reconstructor, validates, aliased from sqlalchemy.orm import defer, deferred, synonym, attributes, column_property, composite, relationship, dynamic_loader, comparable_property,AttributeExtension -from sqlalchemy.test.testing import eq_, AssertsCompiledSQL +from test.lib.testing import eq_, AssertsCompiledSQL from test.orm import _base, _fixtures -from sqlalchemy.test.assertsql import AllOf, CompiledSQL +from test.lib.assertsql import AllOf, CompiledSQL class MapperTest(_fixtures.FixtureTest): diff --git a/test/orm/test_merge.py b/test/orm/test_merge.py index d63d7e086..47c4f0963 100644 --- a/test/orm/test_merge.py +++ b/test/orm/test_merge.py @@ -1,16 +1,16 @@ -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message import sqlalchemy as sa from sqlalchemy import Integer, PickleType, String import operator -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy.util import OrderedSet from sqlalchemy.orm import mapper, relationship, create_session, PropComparator, \ synonym, comparable_property, sessionmaker, attributes from sqlalchemy.orm.collections import attribute_mapped_collection from sqlalchemy.orm.interfaces import MapperOption -from sqlalchemy.test.testing import eq_, ne_ +from test.lib.testing import eq_, ne_ from test.orm import _base, _fixtures -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column class MergeTest(_fixtures.FixtureTest): """Session.merge() functionality""" diff --git a/test/orm/test_naturalpks.py b/test/orm/test_naturalpks.py index ca88251d7..f9ce7b3ca 100644 --- a/test/orm/test_naturalpks.py +++ b/test/orm/test_naturalpks.py @@ -2,15 +2,15 @@ Primary key changing capabilities and passive/non-passive cascading updates. """ -from sqlalchemy.test.testing import eq_, ne_, \ +from test.lib.testing import eq_, ne_, \ assert_raises, assert_raises_message import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import Integer, String, ForeignKey, Unicode -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, relationship, create_session, backref, Session from sqlalchemy.orm.session import make_transient -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from test.orm import _base, _fixtures class NaturalPKTest(_base.MappedTest): @@ -862,7 +862,7 @@ class CascadeToFKPKTest(_base.MappedTest, testing.AssertsCompiledSQL): sess.add(u2) sess.add(a2) - from sqlalchemy.test.assertsql import CompiledSQL + from test.lib.assertsql import CompiledSQL # test that the primary key columns of addresses are not # being updated as well, since this is a row switch. diff --git a/test/orm/test_onetoone.py b/test/orm/test_onetoone.py index 4e3cade9b..7097a266e 100644 --- a/test/orm/test_onetoone.py +++ b/test/orm/test_onetoone.py @@ -1,7 +1,7 @@ import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import Integer, String, ForeignKey -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, relationship, create_session from test.orm import _base diff --git a/test/orm/test_pickled.py b/test/orm/test_pickled.py index 5b87b2b85..7119b8753 100644 --- a/test/orm/test_pickled.py +++ b/test/orm/test_pickled.py @@ -1,10 +1,10 @@ -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ import pickle import sqlalchemy as sa -from sqlalchemy.test import testing -from sqlalchemy.test.testing import assert_raises_message +from test.lib import testing +from test.lib.testing import assert_raises_message from sqlalchemy import Integer, String, ForeignKey, exc, MetaData -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, relationship, create_session, \ sessionmaker, attributes, interfaces,\ clear_mappers, exc as orm_exc,\ diff --git a/test/orm/test_query.py b/test/orm/test_query.py index d96fa7384..758df6ee6 100644 --- a/test/orm/test_query.py +++ b/test/orm/test_query.py @@ -1,4 +1,4 @@ -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message +from test.lib.testing import eq_, assert_raises, assert_raises_message import operator from sqlalchemy import * from sqlalchemy import exc as sa_exc, util @@ -7,10 +7,10 @@ from sqlalchemy.engine import default from sqlalchemy.orm import * from sqlalchemy.orm import attributes -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ import sqlalchemy as sa -from sqlalchemy.test import testing, AssertsCompiledSQL, Column, engines +from test.lib import testing, AssertsCompiledSQL, Column, engines from test.orm import _fixtures from test.orm._fixtures import keywords, addresses, Base, \ diff --git a/test/orm/test_relationships.py b/test/orm/test_relationships.py index 187c9e534..eadf17b39 100644 --- a/test/orm/test_relationships.py +++ b/test/orm/test_relationships.py @@ -1,12 +1,12 @@ -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message import datetime import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import Integer, String, ForeignKey, MetaData, and_ -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, relationship, relation, \ backref, create_session, compile_mappers, clear_mappers, sessionmaker -from sqlalchemy.test.testing import eq_, startswith_ +from test.lib.testing import eq_, startswith_ from test.orm import _base, _fixtures diff --git a/test/orm/test_scoping.py b/test/orm/test_scoping.py index 1682e0f7e..899dac1b0 100644 --- a/test/orm/test_scoping.py +++ b/test/orm/test_scoping.py @@ -1,11 +1,11 @@ -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy.orm import scoped_session from sqlalchemy import Integer, String, ForeignKey -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, relationship, query -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from test.orm import _base diff --git a/test/orm/test_selectable.py b/test/orm/test_selectable.py index e46d8bbc8..30278b5bc 100644 --- a/test/orm/test_selectable.py +++ b/test/orm/test_selectable.py @@ -1,11 +1,11 @@ """Generic mapping to Select statements""" -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message import sqlalchemy as sa -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy import String, Integer, select -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, create_session -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from test.orm import _base diff --git a/test/orm/test_session.py b/test/orm/test_session.py index 6ac42a6b3..51e59d809 100644 --- a/test/orm/test_session.py +++ b/test/orm/test_session.py @@ -1,18 +1,18 @@ -from sqlalchemy.test.testing import eq_, assert_raises, \ +from test.lib.testing import eq_, assert_raises, \ assert_raises_message -from sqlalchemy.test.util import gc_collect +from test.lib.util import gc_collect import inspect import pickle from sqlalchemy.orm import create_session, sessionmaker, attributes, \ make_transient, Session from sqlalchemy.orm.attributes import instance_state import sqlalchemy as sa -from sqlalchemy.test import engines, testing, config +from test.lib import engines, testing, config from sqlalchemy import Integer, String, Sequence -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, relationship, backref, joinedload, \ exc as orm_exc, object_session -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from test.engine import _base as engine_base from test.orm import _base, _fixtures diff --git a/test/orm/test_subquery_relations.py b/test/orm/test_subquery_relations.py index 5eba68e13..2aadf26d4 100644 --- a/test/orm/test_subquery_relations.py +++ b/test/orm/test_subquery_relations.py @@ -1,13 +1,13 @@ -from sqlalchemy.test.testing import eq_, is_, is_not_ -from sqlalchemy.test import testing -from sqlalchemy.test.schema import Table, Column +from test.lib.testing import eq_, is_, is_not_ +from test.lib import testing +from test.lib.schema import Table, Column from sqlalchemy import Integer, String, ForeignKey, bindparam from sqlalchemy.orm import backref, subqueryload, subqueryload_all, \ mapper, relationship, clear_mappers, create_session, lazyload, \ aliased, joinedload, deferred, undefer, eagerload_all -from sqlalchemy.test.testing import eq_, assert_raises, \ +from test.lib.testing import eq_, assert_raises, \ assert_raises_message -from sqlalchemy.test.assertsql import CompiledSQL +from test.lib.assertsql import CompiledSQL from test.orm import _base, _fixtures import sqlalchemy as sa diff --git a/test/orm/test_transaction.py b/test/orm/test_transaction.py index 2617f12f0..7f0ada49f 100644 --- a/test/orm/test_transaction.py +++ b/test/orm/test_transaction.py @@ -1,12 +1,12 @@ -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message +from test.lib.testing import eq_, assert_raises, assert_raises_message from sqlalchemy import * from sqlalchemy.orm import attributes from sqlalchemy import exc as sa_exc from sqlalchemy.orm import exc as orm_exc from sqlalchemy.orm import * -from sqlalchemy.test.util import gc_collect -from sqlalchemy.test import testing +from test.lib.util import gc_collect +from test.lib import testing from test.orm import _base from test.orm._fixtures import FixtureTest, User, Address, users, addresses diff --git a/test/orm/test_unitofwork.py b/test/orm/test_unitofwork.py index 52a93a122..f228fb7d9 100644 --- a/test/orm/test_unitofwork.py +++ b/test/orm/test_unitofwork.py @@ -1,22 +1,22 @@ # coding: utf-8 """Tests unitofwork operations.""" -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message +from test.lib.testing import eq_, assert_raises, assert_raises_message import datetime import operator from sqlalchemy.orm import mapper as orm_mapper import sqlalchemy as sa -from sqlalchemy.test import engines, testing, pickleable +from test.lib import engines, testing, pickleable from sqlalchemy import Integer, String, ForeignKey, literal_column -from sqlalchemy.test.schema import Table -from sqlalchemy.test.schema import Column +from test.lib.schema import Table +from test.lib.schema import Column from sqlalchemy.orm import mapper, relationship, create_session, \ column_property, attributes, Session, reconstructor, object_session -from sqlalchemy.test.testing import eq_, ne_ +from test.lib.testing import eq_, ne_ from test.orm import _base, _fixtures from test.engine import _base as engine_base -from sqlalchemy.test.assertsql import AllOf, CompiledSQL +from test.lib.assertsql import AllOf, CompiledSQL import gc class UnitOfWorkTest(object): diff --git a/test/orm/test_unitofworkv2.py b/test/orm/test_unitofworkv2.py index d91799305..73a884e0c 100644 --- a/test/orm/test_unitofworkv2.py +++ b/test/orm/test_unitofworkv2.py @@ -1,11 +1,11 @@ -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message -from sqlalchemy.test import testing -from sqlalchemy.test.schema import Table, Column +from test.lib.testing import eq_, assert_raises, assert_raises_message +from test.lib import testing +from test.lib.schema import Table, Column from sqlalchemy import Integer, String, ForeignKey, func from test.orm import _fixtures, _base from sqlalchemy.orm import mapper, relationship, backref, \ create_session, unitofwork, attributes -from sqlalchemy.test.assertsql import AllOf, CompiledSQL +from test.lib.assertsql import AllOf, CompiledSQL from test.orm._fixtures import keywords, addresses, Base, Keyword, \ Dingaling, item_keywords, dingalings, User, items,\ diff --git a/test/orm/test_utils.py b/test/orm/test_utils.py index 8635ad212..89861c78d 100644 --- a/test/orm/test_utils.py +++ b/test/orm/test_utils.py @@ -1,4 +1,4 @@ -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message from sqlalchemy.orm import interfaces, util from sqlalchemy import Column from sqlalchemy import Integer @@ -8,10 +8,10 @@ from sqlalchemy.orm import aliased from sqlalchemy.orm import mapper, create_session -from sqlalchemy.test import TestBase, testing +from test.lib import TestBase, testing from test.orm import _fixtures -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ class ExtensionCarrierTest(TestBase): diff --git a/test/orm/test_versioning.py b/test/orm/test_versioning.py index 6cb2bb9e2..75f7fbb6e 100644 --- a/test/orm/test_versioning.py +++ b/test/orm/test_versioning.py @@ -1,9 +1,9 @@ import sqlalchemy as sa -from sqlalchemy.test import engines, testing +from test.lib import engines, testing from sqlalchemy import Integer, String, ForeignKey, literal_column, orm, exc -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, relationship, create_session, column_property, sessionmaker -from sqlalchemy.test.testing import eq_, ne_, assert_raises, assert_raises_message +from test.lib.testing import eq_, ne_, assert_raises, assert_raises_message from test.orm import _base, _fixtures from test.engine import _base as engine_base diff --git a/test/perf/insertspeed.py b/test/perf/insertspeed.py index 0491e9f95..3ae1ccbde 100644 --- a/test/perf/insertspeed.py +++ b/test/perf/insertspeed.py @@ -2,7 +2,7 @@ import testenv; testenv.simple_setup() import sys, time from sqlalchemy import * from sqlalchemy.orm import * -from sqlalchemy.test import profiling +from test.lib import profiling db = create_engine('sqlite://') metadata = MetaData(db) diff --git a/test/perf/large_flush.py b/test/perf/large_flush.py index 431a28944..b23de080c 100644 --- a/test/perf/large_flush.py +++ b/test/perf/large_flush.py @@ -3,7 +3,7 @@ from sqlalchemy import create_engine, MetaData, orm from sqlalchemy import Column, ForeignKey from sqlalchemy import Integer, String from sqlalchemy.orm import mapper -from sqlalchemy.test import profiling +from test.lib import profiling class Object(object): pass diff --git a/test/perf/masscreate2.py b/test/perf/masscreate2.py index e525fcf99..6ad2194cd 100644 --- a/test/perf/masscreate2.py +++ b/test/perf/masscreate2.py @@ -3,7 +3,7 @@ import testenv; testenv.simple_setup() import random, string from sqlalchemy.orm import attributes -from sqlalchemy.test.util import gc_collect +from test.lib.util import gc_collect # with this test, run top. make sure the Python process doenst grow in size arbitrarily. diff --git a/test/perf/masseagerload.py b/test/perf/masseagerload.py index 2ed8d2803..6e6d86d54 100644 --- a/test/perf/masseagerload.py +++ b/test/perf/masseagerload.py @@ -1,6 +1,6 @@ from sqlalchemy import * from sqlalchemy.orm import * -from sqlalchemy.test import profiling +from test.lib import profiling NUM = 500 DIVISOR = 50 diff --git a/test/perf/massload.py b/test/perf/massload.py index f6cde3adf..06cfae786 100644 --- a/test/perf/massload.py +++ b/test/perf/massload.py @@ -2,7 +2,7 @@ import time #import sqlalchemy.orm.attributes as attributes from sqlalchemy import * from sqlalchemy.orm import * -from sqlalchemy.test import * +from test.lib import * """ diff --git a/test/perf/masssave.py b/test/perf/masssave.py index 41acd12cc..3c1547d38 100644 --- a/test/perf/masssave.py +++ b/test/perf/masssave.py @@ -2,7 +2,7 @@ import gc import types from sqlalchemy import * from sqlalchemy.orm import * -from sqlalchemy.test import * +from test.lib import * NUM = 2500 diff --git a/test/perf/objselectspeed.py b/test/perf/objselectspeed.py index 816643680..126c9c707 100644 --- a/test/perf/objselectspeed.py +++ b/test/perf/objselectspeed.py @@ -1,8 +1,8 @@ import time, resource from sqlalchemy import * from sqlalchemy.orm import * -from sqlalchemy.test.util import gc_collect -from sqlalchemy.test import profiling +from test.lib.util import gc_collect +from test.lib import profiling db = create_engine('sqlite://') metadata = MetaData(db) diff --git a/test/perf/objupdatespeed.py b/test/perf/objupdatespeed.py index fad22189a..078d95fa3 100644 --- a/test/perf/objupdatespeed.py +++ b/test/perf/objupdatespeed.py @@ -1,8 +1,8 @@ import time, resource from sqlalchemy import * from sqlalchemy.orm import * -from sqlalchemy.test import * -from sqlalchemy.test.util import gc_collect +from test.lib import * +from test.lib.util import gc_collect NUM = 100 diff --git a/test/perf/ormsession.py b/test/perf/ormsession.py index 0b01fc5a3..aff265ff1 100644 --- a/test/perf/ormsession.py +++ b/test/perf/ormsession.py @@ -3,8 +3,8 @@ from datetime import datetime from sqlalchemy import * from sqlalchemy.orm import * -from sqlalchemy.test import * -from sqlalchemy.test.profiling import profiled +from test.lib import * +from test.lib.profiling import profiled class Item(object): def __repr__(self): diff --git a/test/perf/poolload.py b/test/perf/poolload.py index 62c66fbae..345720f0c 100644 --- a/test/perf/poolload.py +++ b/test/perf/poolload.py @@ -2,7 +2,7 @@ import thread, time from sqlalchemy import * import sqlalchemy.pool as pool -from sqlalchemy.test import testing +from test.lib import testing db = create_engine(testing.db.url, pool_timeout=30, echo_pool=True) metadata = MetaData(db) diff --git a/test/perf/sessions.py b/test/perf/sessions.py index 4210732d6..2fe4f758f 100644 --- a/test/perf/sessions.py +++ b/test/perf/sessions.py @@ -1,8 +1,8 @@ from sqlalchemy import * from sqlalchemy.orm import * -from sqlalchemy.test.compat import gc_collect -from sqlalchemy.test import TestBase, AssertsExecutionResults, profiling, testing +from test.lib.compat import gc_collect +from test.lib import TestBase, AssertsExecutionResults, profiling, testing from test.orm import _fixtures # in this test we are specifically looking for time spent in the attributes.InstanceState.__cleanup() method. diff --git a/test/perf/wsgi.py b/test/perf/wsgi.py index 549c92ade..27aa4a8c8 100644 --- a/test/perf/wsgi.py +++ b/test/perf/wsgi.py @@ -4,7 +4,7 @@ from sqlalchemy import * from sqlalchemy.orm import * import thread -from sqlalchemy.test import * +from test.lib import * port = 8000 diff --git a/test/sql/test_case_statement.py b/test/sql/test_case_statement.py index 1a106ee5e..7bc3ab31f 100644 --- a/test/sql/test_case_statement.py +++ b/test/sql/test_case_statement.py @@ -1,7 +1,7 @@ -from sqlalchemy.test.testing import assert_raises, assert_raises_message, eq_ +from test.lib.testing import assert_raises, assert_raises_message, eq_ import sys from sqlalchemy import * -from sqlalchemy.test import * +from test.lib import * from sqlalchemy import util, exc from sqlalchemy.sql import table, column diff --git a/test/sql/test_columns.py b/test/sql/test_columns.py index 3cbb01943..95933b41b 100644 --- a/test/sql/test_columns.py +++ b/test/sql/test_columns.py @@ -1,7 +1,7 @@ -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message from sqlalchemy import * from sqlalchemy import exc, sql -from sqlalchemy.test import * +from test.lib import * from sqlalchemy import Table, Column # don't use testlib's wrappers diff --git a/test/sql/test_compiler.py b/test/sql/test_compiler.py index 338a5491e..788feb84d 100644 --- a/test/sql/test_compiler.py +++ b/test/sql/test_compiler.py @@ -1,4 +1,4 @@ -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message +from test.lib.testing import eq_, assert_raises, assert_raises_message import datetime, re, operator from sqlalchemy import * from sqlalchemy import exc, sql, util @@ -6,7 +6,7 @@ from sqlalchemy.sql import table, column, label, compiler from sqlalchemy.sql.expression import ClauseList from sqlalchemy.engine import default from sqlalchemy.databases import * -from sqlalchemy.test import * +from test.lib import * table1 = table('mytable', column('myid', Integer), diff --git a/test/sql/test_constraints.py b/test/sql/test_constraints.py index 69f29a9bd..56c5c6205 100644 --- a/test/sql/test_constraints.py +++ b/test/sql/test_constraints.py @@ -1,11 +1,11 @@ -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message from sqlalchemy import * from sqlalchemy import exc, schema -from sqlalchemy.test import * -from sqlalchemy.test import config, engines +from test.lib import * +from test.lib import config, engines from sqlalchemy.engine import ddl -from sqlalchemy.test.testing import eq_ -from sqlalchemy.test.assertsql import AllOf, RegexSQL, ExactSQL, CompiledSQL +from test.lib.testing import eq_ +from test.lib.assertsql import AllOf, RegexSQL, ExactSQL, CompiledSQL from sqlalchemy.dialects.postgresql import base as postgresql class ConstraintTest(TestBase, AssertsExecutionResults, AssertsCompiledSQL): diff --git a/test/sql/test_defaults.py b/test/sql/test_defaults.py index f49e4d0d3..7ec43f8d2 100644 --- a/test/sql/test_defaults.py +++ b/test/sql/test_defaults.py @@ -1,13 +1,13 @@ -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message +from test.lib.testing import eq_, assert_raises, assert_raises_message import datetime from sqlalchemy import Sequence, Column, func from sqlalchemy.schema import CreateSequence, DropSequence from sqlalchemy.sql import select, text import sqlalchemy as sa -from sqlalchemy.test import testing, engines +from test.lib import testing, engines from sqlalchemy import MetaData, Integer, String, ForeignKey, Boolean, exc -from sqlalchemy.test.schema import Table -from sqlalchemy.test.testing import eq_ +from test.lib.schema import Table +from test.lib.testing import eq_ from test.sql import _base diff --git a/test/sql/test_functions.py b/test/sql/test_functions.py index c9bb8348c..396eaaf9b 100644 --- a/test/sql/test_functions.py +++ b/test/sql/test_functions.py @@ -1,17 +1,17 @@ -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ import datetime from sqlalchemy import * from sqlalchemy.sql import table, column from sqlalchemy import databases, sql, util from sqlalchemy.sql.compiler import BIND_TEMPLATES from sqlalchemy.engine import default -from sqlalchemy.test.engines import all_dialects +from test.lib.engines import all_dialects from sqlalchemy import types as sqltypes -from sqlalchemy.test import * +from test.lib import * from sqlalchemy.sql.functions import GenericFunction -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from decimal import Decimal as _python_Decimal -from sqlalchemy.test import testing +from test.lib import testing from sqlalchemy.databases import * diff --git a/test/sql/test_generative.py b/test/sql/test_generative.py index 5457c7a79..5454a0f09 100644 --- a/test/sql/test_generative.py +++ b/test/sql/test_generative.py @@ -1,11 +1,11 @@ from sqlalchemy import * from sqlalchemy.sql import table, column, ClauseElement from sqlalchemy.sql.expression import _clone, _from_objects -from sqlalchemy.test import * +from test.lib import * from sqlalchemy.sql.visitors import * from sqlalchemy import util from sqlalchemy.sql import util as sql_util -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ class TraversalTest(TestBase, AssertsExecutionResults): """test ClauseVisitor's traversal, particularly its ability to copy and modify diff --git a/test/sql/test_labels.py b/test/sql/test_labels.py index f67ba9855..0f84c30a0 100644 --- a/test/sql/test_labels.py +++ b/test/sql/test_labels.py @@ -1,7 +1,7 @@ -from sqlalchemy.test.testing import assert_raises, assert_raises_message +from test.lib.testing import assert_raises, assert_raises_message from sqlalchemy import * from sqlalchemy import exc as exceptions -from sqlalchemy.test import * +from test.lib import * from sqlalchemy.engine import default IDENT_LENGTH = 29 diff --git a/test/sql/test_query.py b/test/sql/test_query.py index 410ff73a6..f59b34076 100644 --- a/test/sql/test_query.py +++ b/test/sql/test_query.py @@ -1,11 +1,11 @@ -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ import datetime from sqlalchemy import * from sqlalchemy import exc, sql, util from sqlalchemy.engine import default, base -from sqlalchemy.test import * -from sqlalchemy.test.testing import eq_, assert_raises_message, assert_raises -from sqlalchemy.test.schema import Table, Column +from test.lib import * +from test.lib.testing import eq_, assert_raises_message, assert_raises +from test.lib.schema import Table, Column class QueryTest(TestBase): diff --git a/test/sql/test_quote.py b/test/sql/test_quote.py index 81a68ec74..8f27a7b3c 100644 --- a/test/sql/test_quote.py +++ b/test/sql/test_quote.py @@ -1,7 +1,7 @@ from sqlalchemy import * from sqlalchemy import sql, schema from sqlalchemy.sql import compiler -from sqlalchemy.test import * +from test.lib import * class QuoteTest(TestBase, AssertsCompiledSQL): @classmethod diff --git a/test/sql/test_returning.py b/test/sql/test_returning.py index 332f4eef5..632a739f1 100644 --- a/test/sql/test_returning.py +++ b/test/sql/test_returning.py @@ -1,7 +1,7 @@ -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ from sqlalchemy import * -from sqlalchemy.test import * -from sqlalchemy.test.schema import Table, Column +from test.lib import * +from test.lib.schema import Table, Column from sqlalchemy.types import TypeDecorator class ReturningTest(TestBase, AssertsExecutionResults): diff --git a/test/sql/test_rowcount.py b/test/sql/test_rowcount.py index ccd0d8f5e..ed40f2801 100644 --- a/test/sql/test_rowcount.py +++ b/test/sql/test_rowcount.py @@ -1,5 +1,5 @@ from sqlalchemy import * -from sqlalchemy.test import * +from test.lib import * class FoundRowsTest(TestBase, AssertsExecutionResults): diff --git a/test/sql/test_selectable.py b/test/sql/test_selectable.py index 5bebbe05f..77acf896b 100644 --- a/test/sql/test_selectable.py +++ b/test/sql/test_selectable.py @@ -1,9 +1,9 @@ """Test various algorithmic properties of selectables.""" -from sqlalchemy.test.testing import eq_, assert_raises, \ +from test.lib.testing import eq_, assert_raises, \ assert_raises_message from sqlalchemy import * -from sqlalchemy.test import * +from test.lib import * from sqlalchemy.sql import util as sql_util, visitors from sqlalchemy import exc from sqlalchemy.sql import table, column, null diff --git a/test/sql/test_types.py b/test/sql/test_types.py index 993843891..bfadca7c9 100644 --- a/test/sql/test_types.py +++ b/test/sql/test_types.py @@ -1,18 +1,18 @@ # coding: utf-8 -from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message +from test.lib.testing import eq_, assert_raises, assert_raises_message import decimal import datetime, os, re from sqlalchemy import * from sqlalchemy import exc, types, util, schema from sqlalchemy.sql import operators, column, table -from sqlalchemy.test.testing import eq_ +from test.lib.testing import eq_ import sqlalchemy.engine.url as url from sqlalchemy.databases import * -from sqlalchemy.test.schema import Table, Column -from sqlalchemy.test import * -from sqlalchemy.test.util import picklers +from test.lib.schema import Table, Column +from test.lib import * +from test.lib.util import picklers from decimal import Decimal -from sqlalchemy.test.util import round_decimal +from test.lib.util import round_decimal class AdaptTest(TestBase): diff --git a/test/sql/test_unicode.py b/test/sql/test_unicode.py index a116d34cb..2eda4ffa8 100644 --- a/test/sql/test_unicode.py +++ b/test/sql/test_unicode.py @@ -2,8 +2,8 @@ """verrrrry basic unicode column name testing""" from sqlalchemy import * -from sqlalchemy.test import * -from sqlalchemy.test.engines import utf8_engine +from test.lib import * +from test.lib.engines import utf8_engine from sqlalchemy.sql import column class UnicodeSchemaTest(TestBase): diff --git a/test/zblog/tables.py b/test/zblog/tables.py index 4907259e1..3326c28fb 100644 --- a/test/zblog/tables.py +++ b/test/zblog/tables.py @@ -1,7 +1,7 @@ """application table metadata objects are described here.""" from sqlalchemy import * -from sqlalchemy.test.schema import Table, Column +from test.lib.schema import Table, Column metadata = MetaData() diff --git a/test/zblog/test_zblog.py b/test/zblog/test_zblog.py index 8103cde8b..ec6402a6e 100644 --- a/test/zblog/test_zblog.py +++ b/test/zblog/test_zblog.py @@ -1,6 +1,6 @@ from sqlalchemy import * from sqlalchemy.orm import * -from sqlalchemy.test import * +from test.lib import * from test.zblog import mappers, tables from test.zblog.user import * from test.zblog.blog import * -- cgit v1.2.1