aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2019-05-06 22:40:27 +0300
committerGitHub <noreply@github.com>2019-05-06 22:40:27 +0300
commitd53cf99dca4605ace4b81b1e585616b3e1b74fa6 (patch)
tree0cce690e90a722457d3f472f1a7c4e471182e2bc
parentbpo-36793: Remove unneeded __str__ definitions. (GH-13081) (diff)
downloadcpython-d53cf99dca4605ace4b81b1e585616b3e1b74fa6.tar.gz
cpython-d53cf99dca4605ace4b81b1e585616b3e1b74fa6.tar.bz2
cpython-d53cf99dca4605ace4b81b1e585616b3e1b74fa6.zip
bpo-36542: Allow to overwrite the signature for Python functions. (GH-12705)
-rw-r--r--Lib/bdb.py1
-rwxr-xr-xLib/cProfile.py1
-rw-r--r--Lib/collections/__init__.py2
-rw-r--r--Lib/concurrent/futures/_base.py1
-rw-r--r--Lib/concurrent/futures/process.py1
-rw-r--r--Lib/concurrent/futures/thread.py1
-rw-r--r--Lib/contextlib.py2
-rw-r--r--Lib/curses/__init__.py1
-rw-r--r--Lib/functools.py1
-rw-r--r--Lib/inspect.py9
-rw-r--r--Lib/multiprocessing/managers.py2
-rwxr-xr-xLib/profile.py1
-rw-r--r--Lib/test/test_inspect.py11
-rwxr-xr-xLib/trace.py1
-rw-r--r--Lib/unittest/case.py5
-rw-r--r--Lib/weakref.py1
-rw-r--r--Misc/NEWS.d/next/Library/2019-04-06-12-36-09.bpo-36542.Q0qyYV.rst2
17 files changed, 40 insertions, 3 deletions
diff --git a/Lib/bdb.py b/Lib/bdb.py
index 54aa9843745..69174364c46 100644
--- a/Lib/bdb.py
+++ b/Lib/bdb.py
@@ -649,6 +649,7 @@ class Bdb:
self.quitting = True
sys.settrace(None)
return res
+ runcall.__text_signature__ = '($self, func, /, *args, **kwds)'
def set_trace():
diff --git a/Lib/cProfile.py b/Lib/cProfile.py
index 2e449cc576c..369d02e22e2 100755
--- a/Lib/cProfile.py
+++ b/Lib/cProfile.py
@@ -124,6 +124,7 @@ class Profile(_lsprof.Profiler):
return func(*args, **kw)
finally:
self.disable()
+ runcall.__text_signature__ = '($self, func, /, *args, **kw)'
def __enter__(self):
self.enable()
diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py
index 9657c1cf83b..e6cafb320fa 100644
--- a/Lib/collections/__init__.py
+++ b/Lib/collections/__init__.py
@@ -1018,6 +1018,8 @@ class UserDict(_collections_abc.MutableMapping):
self.update(dict)
if kwargs:
self.update(kwargs)
+ __init__.__text_signature__ = '($self, dict=None, /, **kwargs)'
+
def __len__(self): return len(self.data)
def __getitem__(self, key):
if key in self.data:
diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py
index ea16eef841c..8f155f0ea82 100644
--- a/Lib/concurrent/futures/_base.py
+++ b/Lib/concurrent/futures/_base.py
@@ -567,6 +567,7 @@ class Executor(object):
'got %d' % (len(args)-1))
raise NotImplementedError()
+ submit.__text_signature__ = '($self, fn, /, *args, **kwargs)'
def map(self, fn, *iterables, timeout=None, chunksize=1):
"""Returns an iterator equivalent to map(fn, iter).
diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py
index e6ce278b5d4..21bf4a447f0 100644
--- a/Lib/concurrent/futures/process.py
+++ b/Lib/concurrent/futures/process.py
@@ -630,6 +630,7 @@ class ProcessPoolExecutor(_base.Executor):
self._start_queue_management_thread()
return f
+ submit.__text_signature__ = _base.Executor.submit.__text_signature__
submit.__doc__ = _base.Executor.submit.__doc__
def map(self, fn, *iterables, timeout=None, chunksize=1):
diff --git a/Lib/concurrent/futures/thread.py b/Lib/concurrent/futures/thread.py
index 0a61e3a9ac1..2af31a106dd 100644
--- a/Lib/concurrent/futures/thread.py
+++ b/Lib/concurrent/futures/thread.py
@@ -174,6 +174,7 @@ class ThreadPoolExecutor(_base.Executor):
self._work_queue.put(w)
self._adjust_thread_count()
return f
+ submit.__text_signature__ = _base.Executor.submit.__text_signature__
submit.__doc__ = _base.Executor.submit.__doc__
def _adjust_thread_count(self):
diff --git a/Lib/contextlib.py b/Lib/contextlib.py
index ae498a2b6ef..de989a001c6 100644
--- a/Lib/contextlib.py
+++ b/Lib/contextlib.py
@@ -454,6 +454,7 @@ class _BaseExitStack:
_exit_wrapper.__wrapped__ = callback
self._push_exit_callback(_exit_wrapper)
return callback # Allow use as a decorator
+ callback.__text_signature__ = '($self, callback, /, *args, **kwds)'
def _push_cm_exit(self, cm, cm_exit):
"""Helper to correctly register callbacks to __exit__ methods."""
@@ -615,6 +616,7 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
_exit_wrapper.__wrapped__ = callback
self._push_exit_callback(_exit_wrapper, False)
return callback # Allow use as a decorator
+ push_async_callback.__text_signature__ = '($self, callback, /, *args, **kwds)'
async def aclose(self):
"""Immediately unwind the context stack."""
diff --git a/Lib/curses/__init__.py b/Lib/curses/__init__.py
index 44a19842882..24ff3ca93a8 100644
--- a/Lib/curses/__init__.py
+++ b/Lib/curses/__init__.py
@@ -110,3 +110,4 @@ def wrapper(*args, **kwds):
echo()
nocbreak()
endwin()
+wrapper.__text_signature__ = '(func, /, *args, **kwds)'
diff --git a/Lib/functools.py b/Lib/functools.py
index 1f1874db9b4..28d9f6f75fd 100644
--- a/Lib/functools.py
+++ b/Lib/functools.py
@@ -388,6 +388,7 @@ class partialmethod(object):
self.func = func
self.args = args
self.keywords = keywords
+ __init__.__text_signature__ = '($self, func, /, *args, **keywords)'
def __repr__(self):
args = ", ".join(map(repr, self.args))
diff --git a/Lib/inspect.py b/Lib/inspect.py
index c460309bb5a..6c3027987b3 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -2121,7 +2121,7 @@ def _signature_from_builtin(cls, func, skip_bound_arg=True):
return _signature_fromstr(cls, func, s, skip_bound_arg)
-def _signature_from_function(cls, func):
+def _signature_from_function(cls, func, skip_bound_arg=True):
"""Private helper: constructs Signature for the given python function."""
is_duck_function = False
@@ -2133,6 +2133,10 @@ def _signature_from_function(cls, func):
# of pure function:
raise TypeError('{!r} is not a Python function'.format(func))
+ s = getattr(func, "__text_signature__", None)
+ if s:
+ return _signature_fromstr(cls, func, s, skip_bound_arg)
+
Parameter = cls._parameter_cls
# Parameter information.
@@ -2301,7 +2305,8 @@ def _signature_from_callable(obj, *,
if isfunction(obj) or _signature_is_functionlike(obj):
# If it's a pure Python function, or an object that is duck type
# of a Python function (Cython functions, for instance), then:
- return _signature_from_function(sigcls, obj)
+ return _signature_from_function(sigcls, obj,
+ skip_bound_arg=skip_bound_arg)
if _signature_is_builtin(obj):
return _signature_from_builtin(sigcls, obj,
diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py
index 80c3ddb9154..22abd47fb1f 100644
--- a/Lib/multiprocessing/managers.py
+++ b/Lib/multiprocessing/managers.py
@@ -419,6 +419,7 @@ class Server(object):
self.incref(c, ident)
return ident, tuple(exposed)
+ create.__text_signature__ = '($self, c, typeid, /, *args, **kwds)'
def get_methods(self, c, token):
'''
@@ -1309,6 +1310,7 @@ if HAS_SHMEM:
if hasattr(self.registry[typeid][-1], "_shared_memory_proxy"):
kwargs['shared_memory_context'] = self.shared_memory_context
return Server.create(*args, **kwargs)
+ create.__text_signature__ = '($self, c, typeid, /, *args, **kwargs)'
def shutdown(self, c):
"Call unlink() on all tracked shared memory, terminate the Server."
diff --git a/Lib/profile.py b/Lib/profile.py
index 9a865d3f6f6..1346297c04a 100755
--- a/Lib/profile.py
+++ b/Lib/profile.py
@@ -447,6 +447,7 @@ class Profile:
return func(*args, **kw)
finally:
sys.setprofile(None)
+ runcall.__text_signature__ = '($self, func, /, *args, **kw)'
#******************************************************************
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index 3c825b00e5e..c54cdb23c24 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -3782,6 +3782,17 @@ class TestSignatureDefinitions(unittest.TestCase):
with self.subTest(builtin=name):
self.assertIsNone(obj.__text_signature__)
+ def test_python_function_override_signature(self):
+ def func(*args, **kwargs):
+ pass
+ func.__text_signature__ = '($self, a, b=1, *args, c, d=2, **kwargs)'
+ sig = inspect.signature(func)
+ self.assertIsNotNone(sig)
+ self.assertEqual(str(sig), '(self, /, a, b=1, *args, c, d=2, **kwargs)')
+ func.__text_signature__ = '($self, a, b=1, /, *args, c, d=2, **kwargs)'
+ sig = inspect.signature(func)
+ self.assertEqual(str(sig), '(self, a, b=1, /, *args, c, d=2, **kwargs)')
+
class NTimesUnwrappable:
def __init__(self, n):
diff --git a/Lib/trace.py b/Lib/trace.py
index fd40fbae850..63008a134a8 100755
--- a/Lib/trace.py
+++ b/Lib/trace.py
@@ -476,6 +476,7 @@ class Trace:
if not self.donothing:
sys.settrace(None)
return result
+ runfunc.__text_signature__ = '($self, func, /, *args, **kw)'
def file_module_function_of(self, frame):
code = frame.f_code
diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py
index 8ff2546fc20..8e01c3dc7bb 100644
--- a/Lib/unittest/case.py
+++ b/Lib/unittest/case.py
@@ -102,6 +102,7 @@ def addModuleCleanup(*args, **kwargs):
args = tuple(args)
_module_cleanups.append((function, args, kwargs))
+addModuleCleanup.__text_signature__ = '(function, /, *args, **kwargs)'
def doModuleCleanups():
@@ -498,8 +499,8 @@ class TestCase(object):
args = tuple(args)
self._cleanups.append((function, args, kwargs))
+ addCleanup.__text_signature__ = '($self, function, /, *args, **kwargs)'
- @classmethod
def addClassCleanup(*args, **kwargs):
"""Same as addCleanup, except the cleanup items are called even if
setUpClass fails (unlike tearDownClass)."""
@@ -514,6 +515,8 @@ class TestCase(object):
args = tuple(args)
cls._class_cleanups.append((function, args, kwargs))
+ addClassCleanup.__text_signature__ = '($cls, function, /, *args, **kwargs)'
+ addClassCleanup = classmethod(addClassCleanup)
def setUp(self):
"Hook method for setting up the test fixture before exercising it."
diff --git a/Lib/weakref.py b/Lib/weakref.py
index 285c70792e0..1eeb7b0a0b4 100644
--- a/Lib/weakref.py
+++ b/Lib/weakref.py
@@ -569,6 +569,7 @@ class finalize:
info.index = next(self._index_iter)
self._registry[self] = info
finalize._dirty = True
+ __init__.__text_signature__ = '($self, obj, func, /, *args, **kwargs)'
def __call__(self, _=None):
"""If alive then mark as dead and return func(*args, **kwargs);
diff --git a/Misc/NEWS.d/next/Library/2019-04-06-12-36-09.bpo-36542.Q0qyYV.rst b/Misc/NEWS.d/next/Library/2019-04-06-12-36-09.bpo-36542.Q0qyYV.rst
new file mode 100644
index 00000000000..8374776e61e
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-04-06-12-36-09.bpo-36542.Q0qyYV.rst
@@ -0,0 +1,2 @@
+The signature of Python functions can now be overridden by specifying the
+``__text_signature__`` attribute.