bpo-36542: Allow to overwrite the signature for Python functions. (GH-12705)

diff --git a/Lib/bdb.py b/Lib/bdb.py
index 54aa984..6917436 100644
--- a/Lib/bdb.py
+++ b/Lib/bdb.py
@@ -649,6 +649,7 @@
             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 2e449cc..369d02e 100755
--- a/Lib/cProfile.py
+++ b/Lib/cProfile.py
@@ -124,6 +124,7 @@
             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 9657c1c..e6cafb3 100644
--- a/Lib/collections/__init__.py
+++ b/Lib/collections/__init__.py
@@ -1018,6 +1018,8 @@
             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 ea16eef..8f155f0 100644
--- a/Lib/concurrent/futures/_base.py
+++ b/Lib/concurrent/futures/_base.py
@@ -567,6 +567,7 @@
                             '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 e6ce278..21bf4a4 100644
--- a/Lib/concurrent/futures/process.py
+++ b/Lib/concurrent/futures/process.py
@@ -630,6 +630,7 @@
 
             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 0a61e3a..2af31a1 100644
--- a/Lib/concurrent/futures/thread.py
+++ b/Lib/concurrent/futures/thread.py
@@ -174,6 +174,7 @@
             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 ae498a2..de989a0 100644
--- a/Lib/contextlib.py
+++ b/Lib/contextlib.py
@@ -454,6 +454,7 @@
         _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 @@
         _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 44a1984..24ff3ca 100644
--- a/Lib/curses/__init__.py
+++ b/Lib/curses/__init__.py
@@ -110,3 +110,4 @@
             echo()
             nocbreak()
             endwin()
+wrapper.__text_signature__ = '(func, /, *args, **kwds)'
diff --git a/Lib/functools.py b/Lib/functools.py
index 1f1874d..28d9f6f 100644
--- a/Lib/functools.py
+++ b/Lib/functools.py
@@ -388,6 +388,7 @@
             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 c460309..6c30279 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -2121,7 +2121,7 @@
     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 @@
             # 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 @@
     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 80c3ddb..22abd47 100644
--- a/Lib/multiprocessing/managers.py
+++ b/Lib/multiprocessing/managers.py
@@ -419,6 +419,7 @@
 
         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 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 9a865d3..1346297 100755
--- a/Lib/profile.py
+++ b/Lib/profile.py
@@ -447,6 +447,7 @@
             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 3c825b0..c54cdb2 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -3782,6 +3782,17 @@
             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 fd40fba..63008a1 100755
--- a/Lib/trace.py
+++ b/Lib/trace.py
@@ -476,6 +476,7 @@
             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 8ff2546..8e01c3d 100644
--- a/Lib/unittest/case.py
+++ b/Lib/unittest/case.py
@@ -102,6 +102,7 @@
     args = tuple(args)
 
     _module_cleanups.append((function, args, kwargs))
+addModuleCleanup.__text_signature__ = '(function, /, *args, **kwargs)'
 
 
 def doModuleCleanups():
@@ -498,8 +499,8 @@
         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 @@
         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 285c707..1eeb7b0 100644
--- a/Lib/weakref.py
+++ b/Lib/weakref.py
@@ -569,6 +569,7 @@
         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 0000000..8374776
--- /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.