summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2015-07-14 12:42:19 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2015-07-14 12:42:19 -0400
commit6f8d0f2e2d119a092bd4c46c42eca2d4737e0d23 (patch)
tree82d5c475d2a239a92583ded424083bb8ea9bdfa6
parenta294f8cc3f2e5fc2cad048bc4ce27c57554e2688 (diff)
downloadalembic-6f8d0f2e2d119a092bd4c46c42eca2d4737e0d23.tar.gz
- move the "legacy names" system into where we create the module proxy.
This is so that we can do a total open ended "*args, **kw" style translation for the vast majority of use cases that are using alembic.op, without impacting docstrings for the Operations class. There is a risk here of impacting an application that is using Operations directly instantitaed while using old names. We may still have to accommodate that somehow.
-rw-r--r--alembic/operations/base.py2
-rw-r--r--alembic/operations/ops.py3
-rw-r--r--alembic/util/langhelpers.py92
-rw-r--r--tests/test_op.py13
4 files changed, 62 insertions, 48 deletions
diff --git a/alembic/operations/base.py b/alembic/operations/base.py
index 18710fc..346e03b 100644
--- a/alembic/operations/base.py
+++ b/alembic/operations/base.py
@@ -130,6 +130,8 @@ class Operations(util.ModuleClsProxy):
"the :class:`.%s` class, via the :meth:`.%s.%s` method." % (
cls.__name__, cls.__name__, name
)
+ if hasattr(fn, '_legacy_translations'):
+ lcl[name]._legacy_translations = fn._legacy_translations
return op_cls
return register
diff --git a/alembic/operations/ops.py b/alembic/operations/ops.py
index 16cccb6..73ae55f 100644
--- a/alembic/operations/ops.py
+++ b/alembic/operations/ops.py
@@ -257,7 +257,8 @@ class CreateUniqueConstraintOp(AddConstraintOp):
@classmethod
@util._with_legacy_names([
('name', 'constraint_name'),
- ('source', 'table_name')
+ ('source', 'table_name'),
+ ('local_cols', 'columns'),
])
def create_unique_constraint(
cls, operations, constraint_name, table_name, columns,
diff --git a/alembic/util/langhelpers.py b/alembic/util/langhelpers.py
index 904848c..21d2bfb 100644
--- a/alembic/util/langhelpers.py
+++ b/alembic/util/langhelpers.py
@@ -101,9 +101,44 @@ class ModuleClsProxy(with_metaclass(_ModuleClsMeta)):
))
globals_['_name_error'] = _name_error
+ translations = getattr(fn, "_legacy_translations", [])
+ if translations:
+ outer_args = inner_args = "*args, **kw"
+ translate_str = "args, kw = _translate(%r, %r, args, kw)" % (
+ tuple(spec),
+ translations
+ )
+
+ def translate(spec, translations, args, kw):
+ return_kw = {}
+ return_args = []
+
+ for oldname, newname in translations:
+ if oldname in kw:
+ return_kw[newname] = kw.pop(oldname)
+ return_kw.update(kw)
+
+ args = list(args)
+ if spec[3]:
+ pos_only = spec[0][:-len(spec[3])]
+ else:
+ pos_only = spec[0]
+ for arg in pos_only:
+ if arg not in return_kw:
+ return_args.append(args.pop(0))
+ return_args.extend(args)
+
+ return return_args, return_kw
+ globals_['_translate'] = translate
+ else:
+ outer_args = args[1:-1]
+ inner_args = apply_kw[1:-1]
+ translate_str = ""
+
func_text = textwrap.dedent("""\
def %(name)s(%(args)s):
%(doc)r
+ %(translate)s
try:
p = _proxy
except NameError:
@@ -112,8 +147,9 @@ class ModuleClsProxy(with_metaclass(_ModuleClsMeta)):
e
""" % {
'name': name,
- 'args': args[1:-1],
- 'apply_kw': apply_kw[1:-1],
+ 'translate': translate_str,
+ 'args': outer_args,
+ 'apply_kw': inner_args,
'doc': fn.__doc__,
})
lcl = {}
@@ -121,6 +157,14 @@ class ModuleClsProxy(with_metaclass(_ModuleClsMeta)):
return lcl[name]
+def _with_legacy_names(translations):
+ def decorate(fn):
+ fn._legacy_translations = translations
+ return fn
+
+ return decorate
+
+
def asbool(value):
return value is not None and \
value.lower() == 'true'
@@ -201,50 +245,6 @@ class immutabledict(dict):
return "immutabledict(%s)" % dict.__repr__(self)
-def _with_legacy_names(translations):
- def decorate(fn):
-
- spec = inspect_getfullargspec(fn)
- metadata = dict(target='target', fn='fn')
- metadata.update(format_argspec_plus(spec, grouped=False))
-
- has_keywords = bool(spec[2])
-
- if not has_keywords:
- metadata['args'] += ", **kw"
- metadata['apply_kw'] += ", **kw"
-
- def go(*arg, **kw):
- names = set(kw).difference(spec[0])
- for oldname, newname in translations:
- if oldname in kw:
- kw[newname] = kw.pop(oldname)
- names.discard(oldname)
-
- warnings.warn(
- "Argument '%s' is now named '%s' for function '%s'" %
- (oldname, newname, fn.__name__))
- if not has_keywords and names:
- raise TypeError("Unknown arguments: %s" % ", ".join(names))
- return fn(*arg, **kw)
-
- code = 'lambda %(args)s: %(target)s(%(apply_kw)s)' % (
- metadata)
- decorated = eval(code, {"target": go})
- decorated.__defaults__ = getattr(fn, '__func__', fn).__defaults__
- update_wrapper(decorated, fn)
- if hasattr(decorated, '__wrapped__'):
- # update_wrapper in py3k applies __wrapped__, which causes
- # inspect.getargspec() to ignore the extra arguments on our
- # wrapper as of Python 3.4. We need this for the
- # "module class proxy" thing though, so just del the __wrapped__
- # for now. See #175 as well as bugs.python.org/issue17482
- del decorated.__wrapped__
- return decorated
-
- return decorate
-
-
class Dispatcher(object):
def __init__(self):
self._registry = {}
diff --git a/tests/test_op.py b/tests/test_op.py
index 9c14e49..610c948 100644
--- a/tests/test_op.py
+++ b/tests/test_op.py
@@ -596,9 +596,20 @@ class OpTest(TestBase):
"ALTER TABLE t1 ADD CONSTRAINT uk_test UNIQUE (foo, bar)"
)
+ def test_add_unique_constraint_legacy_kwarg(self):
+ context = op_fixture()
+ op.create_unique_constraint(
+ name='uk_test',
+ source='t1',
+ local_cols=['foo', 'bar'])
+ context.assert_(
+ "ALTER TABLE t1 ADD CONSTRAINT uk_test UNIQUE (foo, bar)"
+ )
+
def test_add_unique_constraint_schema(self):
context = op_fixture()
- op.create_unique_constraint('uk_test', 't1', ['foo', 'bar'], schema='foo')
+ op.create_unique_constraint(
+ 'uk_test', 't1', ['foo', 'bar'], schema='foo')
context.assert_(
"ALTER TABLE foo.t1 ADD CONSTRAINT uk_test UNIQUE (foo, bar)"
)