bpo-36542: Allow to overwrite the signature for Python functions. (GH-12705)
This commit is contained in:
parent
96aeaec647
commit
d53cf99dca
|
@ -649,6 +649,7 @@ class Bdb:
|
||||||
self.quitting = True
|
self.quitting = True
|
||||||
sys.settrace(None)
|
sys.settrace(None)
|
||||||
return res
|
return res
|
||||||
|
runcall.__text_signature__ = '($self, func, /, *args, **kwds)'
|
||||||
|
|
||||||
|
|
||||||
def set_trace():
|
def set_trace():
|
||||||
|
|
|
@ -124,6 +124,7 @@ class Profile(_lsprof.Profiler):
|
||||||
return func(*args, **kw)
|
return func(*args, **kw)
|
||||||
finally:
|
finally:
|
||||||
self.disable()
|
self.disable()
|
||||||
|
runcall.__text_signature__ = '($self, func, /, *args, **kw)'
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.enable()
|
self.enable()
|
||||||
|
|
|
@ -1018,6 +1018,8 @@ class UserDict(_collections_abc.MutableMapping):
|
||||||
self.update(dict)
|
self.update(dict)
|
||||||
if kwargs:
|
if kwargs:
|
||||||
self.update(kwargs)
|
self.update(kwargs)
|
||||||
|
__init__.__text_signature__ = '($self, dict=None, /, **kwargs)'
|
||||||
|
|
||||||
def __len__(self): return len(self.data)
|
def __len__(self): return len(self.data)
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
if key in self.data:
|
if key in self.data:
|
||||||
|
|
|
@ -567,6 +567,7 @@ class Executor(object):
|
||||||
'got %d' % (len(args)-1))
|
'got %d' % (len(args)-1))
|
||||||
|
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
submit.__text_signature__ = '($self, fn, /, *args, **kwargs)'
|
||||||
|
|
||||||
def map(self, fn, *iterables, timeout=None, chunksize=1):
|
def map(self, fn, *iterables, timeout=None, chunksize=1):
|
||||||
"""Returns an iterator equivalent to map(fn, iter).
|
"""Returns an iterator equivalent to map(fn, iter).
|
||||||
|
|
|
@ -630,6 +630,7 @@ class ProcessPoolExecutor(_base.Executor):
|
||||||
|
|
||||||
self._start_queue_management_thread()
|
self._start_queue_management_thread()
|
||||||
return f
|
return f
|
||||||
|
submit.__text_signature__ = _base.Executor.submit.__text_signature__
|
||||||
submit.__doc__ = _base.Executor.submit.__doc__
|
submit.__doc__ = _base.Executor.submit.__doc__
|
||||||
|
|
||||||
def map(self, fn, *iterables, timeout=None, chunksize=1):
|
def map(self, fn, *iterables, timeout=None, chunksize=1):
|
||||||
|
|
|
@ -174,6 +174,7 @@ class ThreadPoolExecutor(_base.Executor):
|
||||||
self._work_queue.put(w)
|
self._work_queue.put(w)
|
||||||
self._adjust_thread_count()
|
self._adjust_thread_count()
|
||||||
return f
|
return f
|
||||||
|
submit.__text_signature__ = _base.Executor.submit.__text_signature__
|
||||||
submit.__doc__ = _base.Executor.submit.__doc__
|
submit.__doc__ = _base.Executor.submit.__doc__
|
||||||
|
|
||||||
def _adjust_thread_count(self):
|
def _adjust_thread_count(self):
|
||||||
|
|
|
@ -454,6 +454,7 @@ class _BaseExitStack:
|
||||||
_exit_wrapper.__wrapped__ = callback
|
_exit_wrapper.__wrapped__ = callback
|
||||||
self._push_exit_callback(_exit_wrapper)
|
self._push_exit_callback(_exit_wrapper)
|
||||||
return callback # Allow use as a decorator
|
return callback # Allow use as a decorator
|
||||||
|
callback.__text_signature__ = '($self, callback, /, *args, **kwds)'
|
||||||
|
|
||||||
def _push_cm_exit(self, cm, cm_exit):
|
def _push_cm_exit(self, cm, cm_exit):
|
||||||
"""Helper to correctly register callbacks to __exit__ methods."""
|
"""Helper to correctly register callbacks to __exit__ methods."""
|
||||||
|
@ -615,6 +616,7 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
|
||||||
_exit_wrapper.__wrapped__ = callback
|
_exit_wrapper.__wrapped__ = callback
|
||||||
self._push_exit_callback(_exit_wrapper, False)
|
self._push_exit_callback(_exit_wrapper, False)
|
||||||
return callback # Allow use as a decorator
|
return callback # Allow use as a decorator
|
||||||
|
push_async_callback.__text_signature__ = '($self, callback, /, *args, **kwds)'
|
||||||
|
|
||||||
async def aclose(self):
|
async def aclose(self):
|
||||||
"""Immediately unwind the context stack."""
|
"""Immediately unwind the context stack."""
|
||||||
|
|
|
@ -110,3 +110,4 @@ def wrapper(*args, **kwds):
|
||||||
echo()
|
echo()
|
||||||
nocbreak()
|
nocbreak()
|
||||||
endwin()
|
endwin()
|
||||||
|
wrapper.__text_signature__ = '(func, /, *args, **kwds)'
|
||||||
|
|
|
@ -388,6 +388,7 @@ class partialmethod(object):
|
||||||
self.func = func
|
self.func = func
|
||||||
self.args = args
|
self.args = args
|
||||||
self.keywords = keywords
|
self.keywords = keywords
|
||||||
|
__init__.__text_signature__ = '($self, func, /, *args, **keywords)'
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
args = ", ".join(map(repr, self.args))
|
args = ", ".join(map(repr, self.args))
|
||||||
|
|
|
@ -2121,7 +2121,7 @@ def _signature_from_builtin(cls, func, skip_bound_arg=True):
|
||||||
return _signature_fromstr(cls, func, s, skip_bound_arg)
|
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."""
|
"""Private helper: constructs Signature for the given python function."""
|
||||||
|
|
||||||
is_duck_function = False
|
is_duck_function = False
|
||||||
|
@ -2133,6 +2133,10 @@ def _signature_from_function(cls, func):
|
||||||
# of pure function:
|
# of pure function:
|
||||||
raise TypeError('{!r} is not a Python function'.format(func))
|
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 = cls._parameter_cls
|
||||||
|
|
||||||
# Parameter information.
|
# Parameter information.
|
||||||
|
@ -2301,7 +2305,8 @@ def _signature_from_callable(obj, *,
|
||||||
if isfunction(obj) or _signature_is_functionlike(obj):
|
if isfunction(obj) or _signature_is_functionlike(obj):
|
||||||
# If it's a pure Python function, or an object that is duck type
|
# If it's a pure Python function, or an object that is duck type
|
||||||
# of a Python function (Cython functions, for instance), then:
|
# 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):
|
if _signature_is_builtin(obj):
|
||||||
return _signature_from_builtin(sigcls, obj,
|
return _signature_from_builtin(sigcls, obj,
|
||||||
|
|
|
@ -419,6 +419,7 @@ class Server(object):
|
||||||
|
|
||||||
self.incref(c, ident)
|
self.incref(c, ident)
|
||||||
return ident, tuple(exposed)
|
return ident, tuple(exposed)
|
||||||
|
create.__text_signature__ = '($self, c, typeid, /, *args, **kwds)'
|
||||||
|
|
||||||
def get_methods(self, c, token):
|
def get_methods(self, c, token):
|
||||||
'''
|
'''
|
||||||
|
@ -1309,6 +1310,7 @@ if HAS_SHMEM:
|
||||||
if hasattr(self.registry[typeid][-1], "_shared_memory_proxy"):
|
if hasattr(self.registry[typeid][-1], "_shared_memory_proxy"):
|
||||||
kwargs['shared_memory_context'] = self.shared_memory_context
|
kwargs['shared_memory_context'] = self.shared_memory_context
|
||||||
return Server.create(*args, **kwargs)
|
return Server.create(*args, **kwargs)
|
||||||
|
create.__text_signature__ = '($self, c, typeid, /, *args, **kwargs)'
|
||||||
|
|
||||||
def shutdown(self, c):
|
def shutdown(self, c):
|
||||||
"Call unlink() on all tracked shared memory, terminate the Server."
|
"Call unlink() on all tracked shared memory, terminate the Server."
|
||||||
|
|
|
@ -447,6 +447,7 @@ class Profile:
|
||||||
return func(*args, **kw)
|
return func(*args, **kw)
|
||||||
finally:
|
finally:
|
||||||
sys.setprofile(None)
|
sys.setprofile(None)
|
||||||
|
runcall.__text_signature__ = '($self, func, /, *args, **kw)'
|
||||||
|
|
||||||
|
|
||||||
#******************************************************************
|
#******************************************************************
|
||||||
|
|
|
@ -3782,6 +3782,17 @@ class TestSignatureDefinitions(unittest.TestCase):
|
||||||
with self.subTest(builtin=name):
|
with self.subTest(builtin=name):
|
||||||
self.assertIsNone(obj.__text_signature__)
|
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:
|
class NTimesUnwrappable:
|
||||||
def __init__(self, n):
|
def __init__(self, n):
|
||||||
|
|
|
@ -476,6 +476,7 @@ class Trace:
|
||||||
if not self.donothing:
|
if not self.donothing:
|
||||||
sys.settrace(None)
|
sys.settrace(None)
|
||||||
return result
|
return result
|
||||||
|
runfunc.__text_signature__ = '($self, func, /, *args, **kw)'
|
||||||
|
|
||||||
def file_module_function_of(self, frame):
|
def file_module_function_of(self, frame):
|
||||||
code = frame.f_code
|
code = frame.f_code
|
||||||
|
|
|
@ -102,6 +102,7 @@ def addModuleCleanup(*args, **kwargs):
|
||||||
args = tuple(args)
|
args = tuple(args)
|
||||||
|
|
||||||
_module_cleanups.append((function, args, kwargs))
|
_module_cleanups.append((function, args, kwargs))
|
||||||
|
addModuleCleanup.__text_signature__ = '(function, /, *args, **kwargs)'
|
||||||
|
|
||||||
|
|
||||||
def doModuleCleanups():
|
def doModuleCleanups():
|
||||||
|
@ -498,8 +499,8 @@ class TestCase(object):
|
||||||
args = tuple(args)
|
args = tuple(args)
|
||||||
|
|
||||||
self._cleanups.append((function, args, kwargs))
|
self._cleanups.append((function, args, kwargs))
|
||||||
|
addCleanup.__text_signature__ = '($self, function, /, *args, **kwargs)'
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def addClassCleanup(*args, **kwargs):
|
def addClassCleanup(*args, **kwargs):
|
||||||
"""Same as addCleanup, except the cleanup items are called even if
|
"""Same as addCleanup, except the cleanup items are called even if
|
||||||
setUpClass fails (unlike tearDownClass)."""
|
setUpClass fails (unlike tearDownClass)."""
|
||||||
|
@ -514,6 +515,8 @@ class TestCase(object):
|
||||||
args = tuple(args)
|
args = tuple(args)
|
||||||
|
|
||||||
cls._class_cleanups.append((function, args, kwargs))
|
cls._class_cleanups.append((function, args, kwargs))
|
||||||
|
addClassCleanup.__text_signature__ = '($cls, function, /, *args, **kwargs)'
|
||||||
|
addClassCleanup = classmethod(addClassCleanup)
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"Hook method for setting up the test fixture before exercising it."
|
"Hook method for setting up the test fixture before exercising it."
|
||||||
|
|
|
@ -569,6 +569,7 @@ class finalize:
|
||||||
info.index = next(self._index_iter)
|
info.index = next(self._index_iter)
|
||||||
self._registry[self] = info
|
self._registry[self] = info
|
||||||
finalize._dirty = True
|
finalize._dirty = True
|
||||||
|
__init__.__text_signature__ = '($self, obj, func, /, *args, **kwargs)'
|
||||||
|
|
||||||
def __call__(self, _=None):
|
def __call__(self, _=None):
|
||||||
"""If alive then mark as dead and return func(*args, **kwargs);
|
"""If alive then mark as dead and return func(*args, **kwargs);
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
The signature of Python functions can now be overridden by specifying the
|
||||||
|
``__text_signature__`` attribute.
|
Loading…
Reference in New Issue