]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
- move the "legacy names" system into where we create the module proxy.
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 14 Jul 2015 16:42:19 +0000 (12:42 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 14 Jul 2015 16:42:19 +0000 (12:42 -0400)
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.

alembic/operations/base.py
alembic/operations/ops.py
alembic/util/langhelpers.py
tests/test_op.py

index 18710fc7d33bec666da5b163a52943ed34f26e0f..346e03bdd2f2a61ddfb89875a6969ab487a83a04 100644 (file)
@@ -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
 
index 16cccb601da8908137e6401664ada7d469b86364..73ae55f1d9da021ec0353555dfd0663b9ec8cdd4 100644 (file)
@@ -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,
index 904848c014f97fc02b63a4275c25919e42204a6e..21d2bfb3c550c3f45d25d76b6faba44d8075c3ca 100644 (file)
@@ -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 = {}
index 9c14e49181be5d3737ae3b363ad20a5a73929b2e..610c948f9c26ea51030ccb1dde02df4bb88e3c35 100644 (file)
@@ -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)"
         )