]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- convert wrap_callable() to a general purpose update_wrapper-like
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 29 Oct 2015 18:25:58 +0000 (14:25 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 29 Oct 2015 18:28:00 +0000 (14:28 -0400)
function; the caller still passes in the "wrapper"
- move tests for wrap_callable() to be generic util tests
- changelog for pullreq github:204

doc/build/changelog/changelog_11.rst
lib/sqlalchemy/sql/schema.py
lib/sqlalchemy/util/langhelpers.py
test/base/test_utils.py
test/sql/test_defaults.py

index e37fd1a69299a413b44a626f45ea9a6861ca3ec3..e296be0e2e301bd02b427a4769f502461fe1abdb 100644 (file)
 .. changelog::
     :version: 1.1.0b1
 
+    .. change::
+        :tags: enhancement, schema
+        :pullreq: github:204
+
+        The default generation functions passed to :class:`.Column` objects
+        are now run through "update_wrapper", or an equivalent function
+        if a callable non-function is passed, so that introspection tools
+        preserve the name and docstring of the wrapped function.  Pull
+        request courtesy hsum.
+
     .. change::
         :tags: change, mssql
         :tickets: 3434
index 0c433d16e4c3e4feaa9a3723fa5f8513c65fe0ad..a88203e848349243b14292394ff42743c65003a0 100644 (file)
@@ -1981,13 +1981,13 @@ class ColumnDefault(DefaultGenerator):
         try:
             argspec = util.get_callable_argspec(fn, no_self=True)
         except TypeError:
-            return util.wrap_callable(fn)
+            return util.wrap_callable(lambda ctx: fn(), fn)
 
         defaulted = argspec[3] is not None and len(argspec[3]) or 0
         positionals = len(argspec[0]) - defaulted
 
         if positionals == 0:
-            return util.wrap_callable(fn)
+            return util.wrap_callable(lambda ctx: fn(), fn)
 
         elif positionals == 1:
             return fn
index 9f259aea3a0488027a4dac504cca451854e221a7..e9d4e09bc202aabfe7d519516c81a351d3b7271f 100644 (file)
@@ -1378,28 +1378,24 @@ class EnsureKWArgType(type):
         return update_wrapper(wrap, fn)
 
 
-def wrap_callable(fn):
-    """Wrap callable and set __name__, __doc__, and __module__.
+def wrap_callable(wrapper, fn):
+    """Augment functools.update_wrapper() to work with objects with
+    a ``__call__()`` method.
 
     :param fn:
       object with __call__ method
+
     """
     if hasattr(fn, '__name__'):
-        _f = update_wrapper(lambda ctx: fn(), fn)
-        _f.__doc__ = _f.__doc__ or fn.__name__
-        return _f
+        return update_wrapper(wrapper, fn)
     else:
-        _f = lambda ctx: fn()
+        _f = wrapper
         _f.__name__ = fn.__class__.__name__
         _f.__module__ = fn.__module__
 
         if hasattr(fn.__call__, '__doc__') and fn.__call__.__doc__:
-            _f.__doc__ = fn.__call__.__doc__ 
-        elif hasattr(fn.__class__, '__doc__') and fn.__class__.__doc__:
-            _f.__doc__ = fn.__class__.__doc__
+            _f.__doc__ = fn.__call__.__doc__
         elif fn.__doc__:
             _f.__doc__ = fn.__doc__
-        else:
-            _f.__doc__ = fn.__class__.__name__
 
         return _f
index 8074de53ed38e241d9f7910ff7c579f834b1e194..c1027ec8ea230bc68c0e0a6f551b4c50728b0d01 100644 (file)
@@ -313,6 +313,75 @@ class MemoizedAttrTest(fixtures.TestBase):
         eq_(canary.mock_calls, [mock.call.attr(), mock.call.method()])
 
 
+class WrapCallableTest(fixtures.TestBase):
+    def test_wrapping_update_wrapper_fn(self):
+        def my_fancy_default():
+            """run the fancy default"""
+            return 10
+
+        c = util.wrap_callable(lambda: my_fancy_default, my_fancy_default)
+
+        eq_(c.__name__, "my_fancy_default")
+        eq_(c.__doc__, "run the fancy default")
+
+    def test_wrapping_update_wrapper_fn_nodocstring(self):
+        def my_fancy_default():
+            return 10
+
+        c = util.wrap_callable(lambda: my_fancy_default, my_fancy_default)
+        eq_(c.__name__, "my_fancy_default")
+        eq_(c.__doc__, None)
+
+    def test_wrapping_update_wrapper_cls(self):
+        class MyFancyDefault(object):
+            """a fancy default"""
+
+            def __call__(self):
+                """run the fancy default"""
+                return 10
+
+        def_ = MyFancyDefault()
+        c = util.wrap_callable(lambda: def_(), def_)
+
+        eq_(c.__name__, "MyFancyDefault")
+        eq_(c.__doc__, "run the fancy default")
+
+    def test_wrapping_update_wrapper_cls_noclsdocstring(self):
+        class MyFancyDefault(object):
+
+            def __call__(self):
+                """run the fancy default"""
+                return 10
+
+        def_ = MyFancyDefault()
+        c = util.wrap_callable(lambda: def_(), def_)
+        eq_(c.__name__, "MyFancyDefault")
+        eq_(c.__doc__, "run the fancy default")
+
+    def test_wrapping_update_wrapper_cls_nomethdocstring(self):
+        class MyFancyDefault(object):
+            """a fancy default"""
+
+            def __call__(self):
+                return 10
+
+        def_ = MyFancyDefault()
+        c = util.wrap_callable(lambda: def_(), def_)
+        eq_(c.__name__, "MyFancyDefault")
+        eq_(c.__doc__, "a fancy default")
+
+    def test_wrapping_update_wrapper_cls_noclsdocstring_nomethdocstring(self):
+        class MyFancyDefault(object):
+
+            def __call__(self):
+                return 10
+
+        def_ = MyFancyDefault()
+        c = util.wrap_callable(lambda: def_(), def_)
+        eq_(c.__name__, "MyFancyDefault")
+        eq_(c.__doc__, None)
+
+
 class ToListTest(fixtures.TestBase):
     def test_from_string(self):
         eq_(
index e2250e8346acb1cdceb777f5beb63196f2064d36..88679e20828b56d8640ad86914946793b67ba212 100644 (file)
@@ -301,66 +301,6 @@ class DefaultTest(fixtures.TestBase):
             c = sa.ColumnDefault(fn)
             c.arg("context")
 
-    def test_wrapping_update_wrapper_fn(self):
-        def my_fancy_default():
-            """run the fancy default"""
-            return 10
-
-        c = sa.ColumnDefault(my_fancy_default)
-        eq_(c.arg.__name__, "my_fancy_default")
-        eq_(c.arg.__doc__, "run the fancy default")
-
-    def test_wrapping_update_wrapper_fn_nodocstring(self):
-        def my_fancy_default():
-            return 10
-
-        c = sa.ColumnDefault(my_fancy_default)
-        eq_(c.arg.__name__, "my_fancy_default")
-        eq_(c.arg.__doc__, "my_fancy_default")
-
-    def test_wrapping_update_wrapper_cls(self):
-        class MyFancyDefault(object):
-            """a fancy default"""
-
-            def __call__(self):
-                """run the fancy default"""
-                return 10
-
-        c = sa.ColumnDefault(MyFancyDefault())
-        eq_(c.arg.__name__, "MyFancyDefault")
-        eq_(c.arg.__doc__, "run the fancy default")
-
-    def test_wrapping_update_wrapper_cls_noclassdocstring(self):
-        class MyFancyDefault(object):
-
-            def __call__(self):
-                """run the fancy default"""
-                return 10
-
-        c = sa.ColumnDefault(MyFancyDefault())
-        eq_(c.arg.__name__, "MyFancyDefault")
-        eq_(c.arg.__doc__, "run the fancy default")
-
-    def test_wrapping_update_wrapper_cls_nomethoddocstring(self):
-        class MyFancyDefault(object):
-            """a fancy default"""
-
-            def __call__(self):
-                return 10
-
-        c = sa.ColumnDefault(MyFancyDefault())
-        eq_(c.arg.__name__, "MyFancyDefault")
-        eq_(c.arg.__doc__, "a fancy default")
-
-    def test_wrapping_update_wrapper_cls_noclassdocstring_nomethoddocstring(self):
-        class MyFancyDefault(object):
-
-            def __call__(self):
-                return 10
-
-        c = sa.ColumnDefault(MyFancyDefault())
-        eq_(c.arg.__name__, "MyFancyDefault")
-        eq_(c.arg.__doc__, "MyFancyDefault")
 
     @testing.fails_on('firebird', 'Data type unknown')
     def test_standalone(self):