summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2010-12-05 12:51:24 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2010-12-05 12:51:24 -0500
commit1f9029597caf3d9d9e64e5a326508babfca60ebb (patch)
treed61b888173b7a0a6b6d4f061a3afad734812e1da
parent49145a6940062486a6eec66bfe5c9d95c5f76c7a (diff)
downloadsqlalchemy-1f9029597caf3d9d9e64e5a326508babfca60ebb.tar.gz
- move topological, queue into util
- move function_named into test.lib.util - use @decorator for all decorators in test/
-rw-r--r--lib/sqlalchemy/orm/unitofwork.py3
-rw-r--r--lib/sqlalchemy/pool.py2
-rw-r--r--lib/sqlalchemy/sql/util.py3
-rw-r--r--lib/sqlalchemy/util/__init__.py3
-rw-r--r--lib/sqlalchemy/util/compat.py1
-rw-r--r--lib/sqlalchemy/util/langhelpers.py14
-rw-r--r--lib/sqlalchemy/util/queue.py (renamed from lib/sqlalchemy/queue.py)0
-rw-r--r--lib/sqlalchemy/util/topological.py (renamed from lib/sqlalchemy/topological.py)0
-rw-r--r--test/base/test_dependency.py3
-rw-r--r--test/lib/engines.py57
-rw-r--r--test/lib/profiling.py126
-rw-r--r--test/lib/testing.py412
-rw-r--r--test/lib/util.py21
-rw-r--r--test/orm/_base.py1
-rw-r--r--test/orm/inheritance/test_abc_polymorphic.py2
-rw-r--r--test/orm/inheritance/test_basic.py1
-rw-r--r--test/orm/inheritance/test_magazine.py2
-rw-r--r--test/orm/inheritance/test_polymorph.py2
-rw-r--r--test/orm/inheritance/test_polymorph2.py2
-rw-r--r--test/orm/test_attributes.py4
-rw-r--r--test/orm/test_dynamic.py1
-rw-r--r--test/orm/test_instrumentation.py33
22 files changed, 331 insertions, 362 deletions
diff --git a/lib/sqlalchemy/orm/unitofwork.py b/lib/sqlalchemy/orm/unitofwork.py
index db20acb90..7ee633f3e 100644
--- a/lib/sqlalchemy/orm/unitofwork.py
+++ b/lib/sqlalchemy/orm/unitofwork.py
@@ -12,7 +12,8 @@ organizes them in order of dependency, and executes.
"""
-from sqlalchemy import util, topological
+from sqlalchemy import util
+from sqlalchemy.util import topological
from sqlalchemy.orm import attributes, interfaces
from sqlalchemy.orm import util as mapperutil
from sqlalchemy.orm.util import _state_mapper
diff --git a/lib/sqlalchemy/pool.py b/lib/sqlalchemy/pool.py
index 58b3a39c1..4ae6ec022 100644
--- a/lib/sqlalchemy/pool.py
+++ b/lib/sqlalchemy/pool.py
@@ -20,7 +20,7 @@ SQLAlchemy connection pool.
import weakref, time, threading
from sqlalchemy import exc, log, event, events, interfaces, util
-from sqlalchemy import queue as sqla_queue
+from sqlalchemy.util import queue as sqla_queue
from sqlalchemy.util import threading, pickle, memoized_property
proxies = {}
diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py
index 638549e12..757de37c4 100644
--- a/lib/sqlalchemy/sql/util.py
+++ b/lib/sqlalchemy/sql/util.py
@@ -1,4 +1,5 @@
-from sqlalchemy import exc, schema, topological, util, sql, types as sqltypes
+from sqlalchemy import exc, schema, util, sql, types as sqltypes
+from sqlalchemy.util import topological
from sqlalchemy.sql import expression, operators, visitors
from itertools import chain
diff --git a/lib/sqlalchemy/util/__init__.py b/lib/sqlalchemy/util/__init__.py
index 4aaf41205..aa150874f 100644
--- a/lib/sqlalchemy/util/__init__.py
+++ b/lib/sqlalchemy/util/__init__.py
@@ -20,7 +20,7 @@ from langhelpers import iterate_attributes, class_hierarchy, \
portable_instancemethod, unbound_method_to_callable, \
getargspec_init, format_argspec_init, format_argspec_plus, \
get_func_kwargs, get_cls_kwargs, decorator, as_interface, \
- function_named, memoized_property, memoized_instancemethod, \
+ memoized_property, memoized_instancemethod, \
reset_memoized, group_expirable_memoized_property, importlater, \
monkeypatch_proxied_specials, asbool, bool_or_str, coerce_kw_type,\
duck_type_collection, assert_arg_type, symbol, dictlike_iteritems,\
@@ -29,4 +29,3 @@ from langhelpers import iterate_attributes, class_hierarchy, \
from deprecations import warn_deprecated, warn_pending_deprecation, \
deprecated, pending_deprecation
-
diff --git a/lib/sqlalchemy/util/compat.py b/lib/sqlalchemy/util/compat.py
index 5f00102c1..090f45212 100644
--- a/lib/sqlalchemy/util/compat.py
+++ b/lib/sqlalchemy/util/compat.py
@@ -1,4 +1,5 @@
"""Handle Python version/platform incompatibilities."""
+
import sys
# Py2K
diff --git a/lib/sqlalchemy/util/langhelpers.py b/lib/sqlalchemy/util/langhelpers.py
index 68d9709f8..aac22ba30 100644
--- a/lib/sqlalchemy/util/langhelpers.py
+++ b/lib/sqlalchemy/util/langhelpers.py
@@ -371,20 +371,6 @@ def as_interface(obj, cls=None, methods=None, required=None):
raise TypeError("dictionary does not contain required keys %s" %
', '.join(required - found))
-def function_named(fn, name):
- """Return a function with a given __name__.
-
- Will assign to __name__ and return the original function if possible on
- the Python implementation, otherwise a new function will be constructed.
-
- """
- try:
- fn.__name__ = name
- except TypeError:
- fn = types.FunctionType(fn.func_code, fn.func_globals, name,
- fn.func_defaults, fn.func_closure)
- return fn
-
class memoized_property(object):
"""A read-only @property that is only evaluated once."""
diff --git a/lib/sqlalchemy/queue.py b/lib/sqlalchemy/util/queue.py
index 74435ea38..74435ea38 100644
--- a/lib/sqlalchemy/queue.py
+++ b/lib/sqlalchemy/util/queue.py
diff --git a/lib/sqlalchemy/topological.py b/lib/sqlalchemy/util/topological.py
index 0f4f32461..0f4f32461 100644
--- a/lib/sqlalchemy/topological.py
+++ b/lib/sqlalchemy/util/topological.py
diff --git a/test/base/test_dependency.py b/test/base/test_dependency.py
index 6d4662be5..1853b4d52 100644
--- a/test/base/test_dependency.py
+++ b/test/base/test_dependency.py
@@ -1,10 +1,9 @@
-import sqlalchemy.topological as topological
+from sqlalchemy.util import topological
from test.lib import TestBase
from test.lib.testing import assert_raises, eq_
from test.lib.util import conforms_partial_ordering
from sqlalchemy import exc, util
-
class DependencySortTest(TestBase):
def assert_sort(self, tuples, allitems=None):
diff --git a/test/lib/engines.py b/test/lib/engines.py
index 0f3ccf288..a57795f15 100644
--- a/test/lib/engines.py
+++ b/test/lib/engines.py
@@ -1,7 +1,8 @@
import sys, types, weakref
from collections import deque
from test.bootstrap import config
-from sqlalchemy.util import function_named, callable
+from test.lib.util import decorator
+from sqlalchemy.util import callable
from sqlalchemy import event
import re
import warnings
@@ -44,42 +45,38 @@ 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
+def assert_conns_closed(fn, *args, **kw):
+ try:
+ fn(*args, **kw)
+ finally:
+ testing_reaper.assert_all_closed()
+
+@decorator
+def rollback_open_connections(fn, *args, **kw):
"""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__)
+ try:
+ fn(*args, **kw)
+ finally:
+ testing_reaper.rollback_all()
-def close_first(fn):
+@decorator
+def close_first(fn, *args, **kw):
"""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__)
+
+ testing_reaper.close_all()
+ fn(*args, **kw)
-def close_open_connections(fn):
+@decorator
+def close_open_connections(fn, *args, **kw):
"""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__)
+ try:
+ fn(*args, **kw)
+ finally:
+ testing_reaper.close_all()
def all_dialects(exclude=None):
import sqlalchemy.databases as d
diff --git a/test/lib/profiling.py b/test/lib/profiling.py
index f6c21bde8..eeb3901cb 100644
--- a/test/lib/profiling.py
+++ b/test/lib/profiling.py
@@ -6,7 +6,7 @@ in a more fine-grained way than nose's profiling plugin.
"""
import os, sys
-from test.lib.util import function_named, gc_collect
+from test.lib.util import gc_collect, decorator
from nose import SkipTest
__all__ = 'profiled', 'function_call_count', 'conditional_call_count'
@@ -38,34 +38,33 @@ def profiled(target=None, **target_opts):
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
+
+ @decorator
+ def decorate(fn, *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 decorate
def function_call_count(count=None, versions={}, variance=0.05):
"""Assert a target for a test case's function call count.
@@ -109,35 +108,34 @@ def function_call_count(count=None, versions={}, variance=0.05):
if count is None:
return lambda fn: fn
+
+ @decorator
+ def decorate(fn, *args, **kw):
+ try:
+ filename = "%s.prof" % fn.__name__
- def decorator(fn):
- def counted(*args, **kw):
- try:
- filename = "%s.prof" % fn.__name__
+ elapsed, stat_loader, result = _profile(
+ filename, fn, *args, **kw)
- elapsed, stat_loader, result = _profile(
- filename, fn, *args, **kw)
+ stats = stat_loader()
+ calls = stats.total_calls
- 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))
- 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
+ return result
+ finally:
+ if os.path.exists(filename):
+ os.unlink(filename)
+ return decorate
def conditional_call_count(discriminator, categories):
"""Apply a function call count conditionally at runtime.
@@ -153,17 +151,15 @@ def conditional_call_count(discriminator, categories):
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
+ @decorator
+ def decorate(fn, *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 decorate
def _profile(filename, fn, *args, **kw):
diff --git a/test/lib/testing.py b/test/lib/testing.py
index 8f4838d0a..6a2c62959 100644
--- a/test/lib/testing.py
+++ b/test/lib/testing.py
@@ -10,7 +10,7 @@ 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 sqlalchemy.util import py3k, decorator
from engines import drop_all_tables
from sqlalchemy import exc as sa_exc, util, types as sqltypes, schema, \
@@ -47,44 +47,39 @@ def fails_if(callable_, reason=None):
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)
+ @decorator
+ def decorate(fn, *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:
- 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)
+ raise AssertionError(
+ "Unexpected success for '%s' (condition: %s)" %
+ (fn.__name__, description))
return decorate
-
-def future(fn):
+@decorator
+def future(fn, *args, **kw):
"""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)
+ 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__)
def db_spec(*dbs):
dialects = set([x for x in dbs if '+' not in x])
@@ -110,25 +105,23 @@ def fails_on(dbs, reason):
"""
spec = db_spec(dbs)
-
- def decorate(fn):
- fn_name = fn.__name__
- def maybe(*args, **kw):
- if not spec(config.db):
- return fn(*args, **kw)
+
+ @decorator
+ def decorate(fn, *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:
- 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)
+ raise AssertionError(
+ "Unexpected success for '%s' on DB implementation '%s+%s'" %
+ (fn.__name__, config.db.name, config.db.driver))
return decorate
def fails_on_everything_except(*dbs):
@@ -140,24 +133,22 @@ def fails_on_everything_except(*dbs):
spec = db_spec(*dbs)
- def decorate(fn):
- fn_name = fn.__name__
- def maybe(*args, **kw):
- if spec(config.db):
- return fn(*args, **kw)
+ @decorator
+ def decorate(fn, *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:
- 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)
+ raise AssertionError(
+ "Unexpected success for '%s' on DB implementation '%s+%s'" %
+ (fn.__name__, config.db.name, config.db.driver))
return decorate
def crashes(db, reason):
@@ -169,19 +160,17 @@ def crashes(db, reason):
"""
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)
+ @decorator
+ def decorate(fn, *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 decorate
def _block_unconditionally(db, reason):
@@ -194,37 +183,33 @@ def _block_unconditionally(db, reason):
"""
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)
+ @decorator
+ def decorate(fn, *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 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)
+ @decorator
+ def decorate(fn, *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 decorate
def exclude(db, op, spec, reason):
@@ -241,19 +226,17 @@ def exclude(db, op, spec, reason):
"""
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)
+ @decorator
+ def decorate(fn, *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 decorate
def _should_carp_about_exclusion(reason):
@@ -312,19 +295,17 @@ def skip_if(predicate, reason=None):
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)
+ @decorator
+ def decorate(fn, *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 decorate
def emits_warning(*messages):
@@ -339,26 +320,26 @@ def emits_warning(*messages):
# 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__)
+
+ @decorator
+ def decorate(fn, *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 decorate
def emits_warning_on(db, *warnings):
@@ -370,21 +351,20 @@ def emits_warning_on(db, *warnings):
"""
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)
+ @decorator
+ def decorate(fn, *args, **kw):
+ if isinstance(db, basestring):
+ if not spec(config.db):
+ return fn(*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__)
+ 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 decorate
def assert_warnings(fn, warnings):
@@ -411,32 +391,30 @@ def uses_deprecated(*messages):
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__)
+ @decorator
+ def decorate(fn, *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 decorate
def testing_warn(msg, stacklevel=3):
@@ -569,24 +547,24 @@ def fixture(table, columns, *rows):
for column_values in rows])
table.append_ddl_listener('after-create', onload)
-def provide_metadata(fn):
+@decorator
+def provide_metadata(fn, *args, **kw):
"""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):
+ 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()
+
+@decorator
+def resolve_artifact_names(fn, *args, **kw):
"""Decorator, augment function globals with tables and classes.
Swaps out the function's globals at execution time. The 'global' statement
@@ -601,17 +579,15 @@ def resolve_artifact_names(fn):
# 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)
+ 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, **kw)
class adict(dict):
"""Dict keys available as attributes. Shadows."""
diff --git a/test/lib/util.py b/test/lib/util.py
index e5277f076..b8cc05a81 100644
--- a/test/lib/util.py
+++ b/test/lib/util.py
@@ -1,4 +1,4 @@
-from sqlalchemy.util import jython, function_named, defaultdict
+from sqlalchemy.util import jython, defaultdict, decorator
import gc
import time
@@ -105,3 +105,22 @@ def all_partial_orderings(tuples, elements):
return iter(_all_orderings(elements))
+
+def function_named(fn, name):
+ """Return a function with a given __name__.
+
+ Will assign to __name__ and return the original function if possible on
+ the Python implementation, otherwise a new function will be constructed.
+
+ This function should be phased out as much as possible
+ in favor of @decorator. Tests that "generate" many named tests
+ should be modernized.
+
+ """
+ try:
+ fn.__name__ = name
+ except TypeError:
+ fn = types.FunctionType(fn.func_code, fn.func_globals, name,
+ fn.func_defaults, fn.func_closure)
+ return fn
+
diff --git a/test/orm/_base.py b/test/orm/_base.py
index 4ccc10157..345009d40 100644
--- a/test/orm/_base.py
+++ b/test/orm/_base.py
@@ -6,7 +6,6 @@ import sqlalchemy.exceptions as sa_exc
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 test.lib.entities import BasicEntity, ComparableEntity
Entity = BasicEntity
diff --git a/test/orm/inheritance/test_abc_polymorphic.py b/test/orm/inheritance/test_abc_polymorphic.py
index fb229003b..58569ab9c 100644
--- a/test/orm/inheritance/test_abc_polymorphic.py
+++ b/test/orm/inheritance/test_abc_polymorphic.py
@@ -2,7 +2,7 @@ from sqlalchemy import *
from sqlalchemy import util
from sqlalchemy.orm import *
-from sqlalchemy.util import function_named
+from test.lib.util import function_named
from test.orm import _base, _fixtures
from test.lib.schema import Table, Column
diff --git a/test/orm/inheritance/test_basic.py b/test/orm/inheritance/test_basic.py
index 544aa1abe..d6b9d89f4 100644
--- a/test/orm/inheritance/test_basic.py
+++ b/test/orm/inheritance/test_basic.py
@@ -7,7 +7,6 @@ from sqlalchemy.orm import exc as orm_exc, attributes
from test.lib.assertsql import AllOf, CompiledSQL
from test.lib import testing, engines
-from sqlalchemy.util import function_named
from test.orm import _base, _fixtures
from test.lib.schema import Table, Column
diff --git a/test/orm/inheritance/test_magazine.py b/test/orm/inheritance/test_magazine.py
index 307c54a9c..e38a1ec33 100644
--- a/test/orm/inheritance/test_magazine.py
+++ b/test/orm/inheritance/test_magazine.py
@@ -2,7 +2,7 @@ from sqlalchemy import *
from sqlalchemy.orm import *
from test.lib import testing
-from sqlalchemy.util import function_named
+from test.lib.util import function_named
from test.orm import _base
from test.lib.schema import Table, Column
diff --git a/test/orm/inheritance/test_polymorph.py b/test/orm/inheritance/test_polymorph.py
index 8539baa76..7e31c476b 100644
--- a/test/orm/inheritance/test_polymorph.py
+++ b/test/orm/inheritance/test_polymorph.py
@@ -6,7 +6,7 @@ from sqlalchemy.orm import *
from sqlalchemy.orm import exc as orm_exc
from sqlalchemy import exc as sa_exc
from test.lib import Column, testing
-from sqlalchemy.util import function_named
+from test.lib.util import function_named
from test.orm import _fixtures, _base
class Person(_fixtures.Base):
diff --git a/test/orm/inheritance/test_polymorph2.py b/test/orm/inheritance/test_polymorph2.py
index 030b931a5..2a9341692 100644
--- a/test/orm/inheritance/test_polymorph2.py
+++ b/test/orm/inheritance/test_polymorph2.py
@@ -8,7 +8,7 @@ from sqlalchemy import util
from sqlalchemy.orm import *
from test.lib import TestBase, AssertsExecutionResults, testing
-from sqlalchemy.util import function_named
+from test.lib.util import function_named
from test.orm import _base, _fixtures
from test.lib.testing import eq_
from test.lib.schema import Table, Column
diff --git a/test/orm/test_attributes.py b/test/orm/test_attributes.py
index 395911b64..c0481f96b 100644
--- a/test/orm/test_attributes.py
+++ b/test/orm/test_attributes.py
@@ -7,8 +7,8 @@ from test.lib import *
from test.lib.testing import eq_, ne_, assert_raises
from test.orm import _base
from test.lib.util import gc_collect, all_partial_orderings
-from sqlalchemy.util import cmp, jython
-from sqlalchemy import event, topological
+from sqlalchemy.util import cmp, jython, topological
+from sqlalchemy import event
# global for pickling tests
MyTest = None
diff --git a/test/orm/test_dynamic.py b/test/orm/test_dynamic.py
index c89503278..0958d60dd 100644
--- a/test/orm/test_dynamic.py
+++ b/test/orm/test_dynamic.py
@@ -7,7 +7,6 @@ from test.lib.schema import Table, Column
from sqlalchemy.orm import mapper, relationship, create_session, Query, attributes
from sqlalchemy.orm.dynamic import AppenderMixin
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_instrumentation.py b/test/orm/test_instrumentation.py
index 4b3701350..f7ba025e0 100644
--- a/test/orm/test_instrumentation.py
+++ b/test/orm/test_instrumentation.py
@@ -7,29 +7,26 @@ from sqlalchemy.orm import mapper, relationship, create_session, \
from test.lib.schema import Table
from test.lib.schema import Column
from test.lib.testing import eq_, ne_
-from sqlalchemy.util import function_named
+from test.lib.util import decorator
from test.orm import _base
+@decorator
+def modifies_instrumentation_finders(fn, *args, **kw):
+ pristine = instrumentation.instrumentation_finders[:]
+ try:
+ fn(*args, **kw)
+ finally:
+ del instrumentation.instrumentation_finders[:]
+ instrumentation.instrumentation_finders.extend(pristine)
-def modifies_instrumentation_finders(fn):
- def decorated(*args, **kw):
- pristine = instrumentation.instrumentation_finders[:]
+def with_lookup_strategy(strategy):
+ @decorator
+ def decorate(fn, *args, **kw):
try:
- fn(*args, **kw)
+ instrumentation._install_lookup_strategy(strategy)
+ return fn(*args, **kw)
finally:
- del instrumentation.instrumentation_finders[:]
- instrumentation.instrumentation_finders.extend(pristine)
- return function_named(decorated, fn.func_name)
-
-def with_lookup_strategy(strategy):
- def decorate(fn):
- def wrapped(*args, **kw):
- try:
- instrumentation._install_lookup_strategy(strategy)
- return fn(*args, **kw)
- finally:
- instrumentation._install_lookup_strategy(sa.util.symbol('native'))
- return function_named(wrapped, fn.func_name)
+ instrumentation._install_lookup_strategy(sa.util.symbol('native'))
return decorate