[Python-checkins] cpython: Issue 20691: Add follow_wrapped arg to inspect.signature/from_callable.

yury.selivanov python-checkins at python.org
Wed May 20 20:30:42 CEST 2015


https://hg.python.org/cpython/rev/0c298f1ee3f6
changeset:   96178:0c298f1ee3f6
user:        Yury Selivanov <yselivanov at sprymix.com>
date:        Wed May 20 14:30:08 2015 -0400
summary:
  Issue 20691: Add follow_wrapped arg to inspect.signature/from_callable.

files:
  Doc/library/inspect.rst  |  14 ++++++++++----
  Doc/whatsnew/3.5.rst     |   3 +++
  Lib/inspect.py           |   9 +++++----
  Lib/test/test_inspect.py |  16 ++++++++++++++--
  Misc/NEWS                |   4 ++++
  5 files changed, 36 insertions(+), 10 deletions(-)


diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst
--- a/Doc/library/inspect.rst
+++ b/Doc/library/inspect.rst
@@ -431,7 +431,7 @@
 return annotation.  To retrieve a Signature object, use the :func:`signature`
 function.
 
-.. function:: signature(callable)
+.. function:: signature(callable, \*, follow_wrapped=True)
 
    Return a :class:`Signature` object for the given ``callable``::
 
@@ -456,6 +456,11 @@
    Raises :exc:`ValueError` if no signature can be provided, and
    :exc:`TypeError` if that type of object is not supported.
 
+   .. versionadded:: 3.5
+      ``follow_wrapped`` parameter. Pass ``False`` to get a signature of
+      ``callable`` specifically (``callable.__wrapped__`` will not be used to
+      unwrap decorated callables.)
+
    .. note::
 
       Some callables may not be introspectable in certain implementations of
@@ -528,12 +533,13 @@
          >>> str(new_sig)
          "(a, b) -> 'new return anno'"
 
-   .. classmethod:: Signature.from_callable(obj)
+   .. classmethod:: Signature.from_callable(obj, \*, follow_wrapped=True)
 
        Return a :class:`Signature` (or its subclass) object for a given callable
-       ``obj``. This method simplifies subclassing of :class:`Signature`:
+       ``obj``.  Pass ``follow_wrapped=False`` to get a signature of ``obj``
+       without unwrapping its ``__wrapped__`` chain.
 
-       ::
+       This method simplifies subclassing of :class:`Signature`::
 
          class MySignature(Signature):
              pass
diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst
--- a/Doc/whatsnew/3.5.rst
+++ b/Doc/whatsnew/3.5.rst
@@ -430,6 +430,9 @@
   subclassing of :class:`~inspect.Signature` easier.  (Contributed
   by Yury Selivanov and Eric Snow in :issue:`17373`.)
 
+* New argument ``follow_wrapped`` for :func:`inspect.signature`.
+  (Contributed by Yury Selivanov in :issue:`20691`.)
+
 ipaddress
 ---------
 
diff --git a/Lib/inspect.py b/Lib/inspect.py
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -2664,9 +2664,10 @@
         return _signature_from_builtin(cls, func)
 
     @classmethod
-    def from_callable(cls, obj):
+    def from_callable(cls, obj, *, follow_wrapped=True):
         """Constructs Signature for the given callable object."""
-        return _signature_from_callable(obj, sigcls=cls)
+        return _signature_from_callable(obj, sigcls=cls,
+                                        follow_wrapper_chains=follow_wrapped)
 
     @property
     def parameters(self):
@@ -2915,9 +2916,9 @@
         return rendered
 
 
-def signature(obj):
+def signature(obj, *, follow_wrapped=True):
     """Get a signature object for the passed callable."""
-    return Signature.from_callable(obj)
+    return Signature.from_callable(obj, follow_wrapped=follow_wrapped)
 
 
 def _main():
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -1735,8 +1735,8 @@
 
 class TestSignatureObject(unittest.TestCase):
     @staticmethod
-    def signature(func):
-        sig = inspect.signature(func)
+    def signature(func, **kw):
+        sig = inspect.signature(func, **kw)
         return (tuple((param.name,
                        (... if param.default is param.empty else param.default),
                        (... if param.annotation is param.empty
@@ -1956,6 +1956,11 @@
         self.assertEqual(inspect.signature(func),
                          inspect.signature(decorated_func))
 
+        def wrapper_like(*args, **kwargs) -> int: pass
+        self.assertEqual(inspect.signature(decorated_func,
+                                           follow_wrapped=False),
+                         inspect.signature(wrapper_like))
+
     @cpython_only
     def test_signature_on_builtins_no_signature(self):
         import _testcapi
@@ -2384,6 +2389,13 @@
                            ('b', ..., ..., "positional_or_keyword")),
                           ...))
 
+        self.assertEqual(self.signature(Foo.bar, follow_wrapped=False),
+                         ((('args', ..., ..., "var_positional"),
+                           ('kwargs', ..., ..., "var_keyword")),
+                          ...)) # functools.wraps will copy __annotations__
+                                # from "func" to "wrapper", hence no
+                                # return_annotation
+
         # Test that we handle method wrappers correctly
         def decorator(func):
             @functools.wraps(func)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -176,6 +176,10 @@
 - Issue 24190: Implement inspect.BoundArgument.apply_defaults() method.
   Contributed by Yury Selivanov.
 
+- Issue 20691: Add 'follow_wrapped' argument to
+  inspect.Signature.from_callable() and inspect.signature().
+  Contributed by Yury Selivanov.
+
 Tests
 -----
 

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list