From c10b324f7232776f5a2f52286a9a1231779bd507 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 29 Mar 2019 19:34:27 +0200 Subject: [PATCH 1/9] Use PEP 570 syntax for positional-only parameters. --- Lib/_collections_abc.py | 29 +++++------- Lib/_py_abc.py | 2 +- Lib/_threading_local.py | 4 +- Lib/argparse.py | 4 +- Lib/bdb.py | 2 +- Lib/cProfile.py | 2 +- Lib/collections/__init__.py | 65 +++++---------------------- Lib/concurrent/futures/_base.py | 2 +- Lib/concurrent/futures/process.py | 2 +- Lib/concurrent/futures/thread.py | 2 +- Lib/contextlib.py | 8 ++-- Lib/curses/__init__.py | 2 +- Lib/dataclasses.py | 9 ++-- Lib/functools.py | 18 ++------ Lib/idlelib/debugger_r.py | 2 +- Lib/idlelib/rpc.py | 2 +- Lib/inspect.py | 12 +++-- Lib/multiprocessing/dummy/__init__.py | 2 +- Lib/multiprocessing/managers.py | 12 ++--- Lib/multiprocessing/pool.py | 2 +- Lib/operator.py | 10 ++--- Lib/optparse.py | 20 ++++----- Lib/profile.py | 2 +- Lib/random.py | 2 +- Lib/string.py | 41 ++++------------- Lib/test/support/script_helper.py | 2 +- Lib/trace.py | 2 +- Lib/typing.py | 2 +- Lib/unittest/case.py | 6 +-- Lib/unittest/mock.py | 28 +++++------- Lib/weakref.py | 35 +++++---------- 31 files changed, 110 insertions(+), 223 deletions(-) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index c363987970b4c6..2b2ddba170e1b1 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -821,30 +821,21 @@ def clear(self): except KeyError: pass - def update(*args, **kwds): + def update(self, other=(), /, **kwds): ''' D.update([E, ]**F) -> None. Update D from mapping/iterable E and F. If E present and has a .keys() method, does: for k in E: D[k] = E[k] If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v In either case, this is followed by: for k, v in F.items(): D[k] = v ''' - if not args: - raise TypeError("descriptor 'update' of 'MutableMapping' object " - "needs an argument") - self, *args = args - if len(args) > 1: - raise TypeError('update expected at most 1 arguments, got %d' % - len(args)) - if args: - other = args[0] - if isinstance(other, Mapping): - for key in other: - self[key] = other[key] - elif hasattr(other, "keys"): - for key in other.keys(): - self[key] = other[key] - else: - for key, value in other: - self[key] = value + if isinstance(other, Mapping): + for key in other: + self[key] = other[key] + elif hasattr(other, "keys"): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value for key, value in kwds.items(): self[key] = value diff --git a/Lib/_py_abc.py b/Lib/_py_abc.py index 3c3aa8e3d61bee..c870ae9048b4f1 100644 --- a/Lib/_py_abc.py +++ b/Lib/_py_abc.py @@ -32,7 +32,7 @@ class ABCMeta(type): # external code. _abc_invalidation_counter = 0 - def __new__(mcls, name, bases, namespace, **kwargs): + def __new__(mcls, name, bases, namespace, /, **kwargs): cls = super().__new__(mcls, name, bases, namespace, **kwargs) # Compute set of abstract method names abstracts = {name diff --git a/Lib/_threading_local.py b/Lib/_threading_local.py index 245bd0ac91b799..b006d76c4e23df 100644 --- a/Lib/_threading_local.py +++ b/Lib/_threading_local.py @@ -56,7 +56,7 @@ >>> class MyLocal(local): ... number = 2 - ... def __init__(self, **kw): + ... def __init__(self, /, **kw): ... self.__dict__.update(kw) ... def squared(self): ... return self.number ** 2 @@ -204,7 +204,7 @@ def _patch(self): class local: __slots__ = '_local__impl', '__dict__' - def __new__(cls, *args, **kw): + def __new__(cls, /, *args, **kw): if (args or kw) and (cls.__init__ is object.__init__): raise TypeError("Initialization arguments are not supported") self = object.__new__(cls) diff --git a/Lib/argparse.py b/Lib/argparse.py index 798766f6c4086a..66a4161495def5 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1220,7 +1220,7 @@ class Namespace(_AttributeHolder): string representation. """ - def __init__(self, **kwargs): + def __init__(self, /, **kwargs): for name in kwargs: setattr(self, name, kwargs[name]) @@ -1297,7 +1297,7 @@ def _registry_get(self, registry_name, value, default=None): # ================================== # Namespace default accessor methods # ================================== - def set_defaults(self, **kwargs): + def set_defaults(self, /, **kwargs): self._defaults.update(kwargs) # if these defaults match any existing arguments, replace diff --git a/Lib/bdb.py b/Lib/bdb.py index ec0f92c06a787c..6fbd0117b90a91 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -618,7 +618,7 @@ def runctx(self, cmd, globals, locals): # This method is more useful to debug a single function call. - def runcall(self, func, *args, **kwds): + def runcall(self, func, /, *args, **kwds): """Debug a single function call. Return the result of the function call. diff --git a/Lib/cProfile.py b/Lib/cProfile.py index 305e79e2804986..4f202038d61260 100755 --- a/Lib/cProfile.py +++ b/Lib/cProfile.py @@ -103,7 +103,7 @@ def runctx(self, cmd, globals, locals): return self # This method is more useful to profile a single function call. - def runcall(self, func, *args, **kw): + def runcall(self, func, /, *args, **kw): self.enable() try: return func(*args, **kw) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index cff75a48d62780..316a18a263a9cf 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -93,16 +93,10 @@ class OrderedDict(dict): # Individual links are kept alive by the hard reference in self.__map. # Those hard references disappear when a key is deleted from an OrderedDict. - def __init__(*args, **kwds): + def __init__(self, other=(), /, **kwds): '''Initialize an ordered dictionary. The signature is the same as regular dictionaries. Keyword argument order is preserved. ''' - if not args: - raise TypeError("descriptor '__init__' of 'OrderedDict' object " - "needs an argument") - self, *args = args - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) try: self.__root except AttributeError: @@ -110,7 +104,7 @@ def __init__(*args, **kwds): self.__root = root = _proxy(self.__hardroot) root.prev = root.next = root self.__map = {} - self.__update(*args, **kwds) + self.__update(other, **kwds) def __setitem__(self, key, value, dict_setitem=dict.__setitem__, proxy=_proxy, Link=_Link): @@ -413,8 +407,8 @@ def _make(cls, iterable): _make.__func__.__doc__ = (f'Make a new {typename} object from a sequence ' 'or iterable') - def _replace(_self, **kwds): - result = _self._make(_map(kwds.pop, field_names, _self)) + def _replace(self, /, **kwds): + result = self._make(_map(kwds.pop, field_names, self)) if kwds: raise ValueError(f'Got unexpected field names: {list(kwds)!r}') return result @@ -543,7 +537,7 @@ class Counter(dict): # http://code.activestate.com/recipes/259174/ # Knuth, TAOCP Vol. II section 4.6.3 - def __init__(*args, **kwds): + def __init__(self, iterable=None, /, **kwds): '''Create a new, empty Counter object. And if given, count elements from an input iterable. Or, initialize the count from another mapping of elements to their counts. @@ -554,14 +548,8 @@ def __init__(*args, **kwds): >>> c = Counter(a=4, b=2) # a new counter from keyword args ''' - if not args: - raise TypeError("descriptor '__init__' of 'Counter' object " - "needs an argument") - self, *args = args - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) super(Counter, self).__init__() - self.update(*args, **kwds) + self.update(iterable, **kwds) def __missing__(self, key): 'The count of elements not in the Counter is zero.' @@ -617,7 +605,7 @@ def fromkeys(cls, iterable, v=None): raise NotImplementedError( 'Counter.fromkeys() is undefined. Use Counter(iterable) instead.') - def update(*args, **kwds): + def update(self, iterable=None, /, **kwds): '''Like dict.update() but add counts instead of replacing them. Source can be an iterable, a dictionary, or another Counter instance. @@ -637,13 +625,6 @@ def update(*args, **kwds): # contexts. Instead, we implement straight-addition. Both the inputs # and outputs are allowed to contain zero and negative counts. - if not args: - raise TypeError("descriptor 'update' of 'Counter' object " - "needs an argument") - self, *args = args - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) - iterable = args[0] if args else None if iterable is not None: if isinstance(iterable, _collections_abc.Mapping): if self: @@ -657,7 +638,7 @@ def update(*args, **kwds): if kwds: self.update(kwds) - def subtract(*args, **kwds): + def subtract(self, iterable=None, /, **kwds): '''Like dict.update() but subtracts counts instead of replacing them. Counts can be reduced below zero. Both the inputs and outputs are allowed to contain zero and negative counts. @@ -673,13 +654,6 @@ def subtract(*args, **kwds): -1 ''' - if not args: - raise TypeError("descriptor 'subtract' of 'Counter' object " - "needs an argument") - self, *args = args - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) - iterable = args[0] if args else None if iterable is not None: self_get = self.get if isinstance(iterable, _collections_abc.Mapping): @@ -997,26 +971,11 @@ def clear(self): class UserDict(_collections_abc.MutableMapping): # Start by filling-out the abstract methods - def __init__(*args, **kwargs): - if not args: - raise TypeError("descriptor '__init__' of 'UserDict' object " - "needs an argument") - self, *args = args - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) - if args: - dict = args[0] - elif 'dict' in kwargs: - dict = kwargs.pop('dict') - import warnings - warnings.warn("Passing 'dict' as keyword argument is deprecated", - DeprecationWarning, stacklevel=2) - else: - dict = None + def __init__(self, dict=None, /, **kwargs): self.data = {} if dict is not None: self.update(dict) - if len(kwargs): + if kwargs: self.update(kwargs) def __len__(self): return len(self.data) def __getitem__(self, key): @@ -1121,7 +1080,7 @@ def copy(self): return self.__class__(self) def count(self, item): return self.data.count(item) def index(self, item, *args): return self.data.index(item, *args) def reverse(self): self.data.reverse() - def sort(self, *args, **kwds): self.data.sort(*args, **kwds) + def sort(self, /, *args, **kwds): self.data.sort(*args, **kwds) def extend(self, other): if isinstance(other, UserList): self.data.extend(other.data) @@ -1221,7 +1180,7 @@ def find(self, sub, start=0, end=_sys.maxsize): if isinstance(sub, UserString): sub = sub.data return self.data.find(sub, start, end) - def format(self, *args, **kwds): + def format(self, /, *args, **kwds): return self.data.format(*args, **kwds) def format_map(self, mapping): return self.data.format_map(mapping) diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py index 8b9dc507138ec6..cbf672dd8f3039 100644 --- a/Lib/concurrent/futures/_base.py +++ b/Lib/concurrent/futures/_base.py @@ -544,7 +544,7 @@ def set_exception(self, exception): class Executor(object): """This is an abstract base class for concrete asynchronous executors.""" - def submit(self, fn, *args, **kwargs): + def submit(self, fn, /, *args, **kwargs): """Submits a callable to be executed with the given arguments. Schedules the callable to be executed as fn(*args, **kwargs) and returns diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 9b85e7f337698e..c8421f03053afa 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -594,7 +594,7 @@ def _adjust_process_count(self): p.start() self._processes[p.pid] = p - def submit(self, fn, *args, **kwargs): + def submit(self, fn, /, *args, **kwargs): with self._shutdown_lock: if self._broken: raise BrokenProcessPool(self._broken) diff --git a/Lib/concurrent/futures/thread.py b/Lib/concurrent/futures/thread.py index 78359711d5d9e4..75e38491bb2064 100644 --- a/Lib/concurrent/futures/thread.py +++ b/Lib/concurrent/futures/thread.py @@ -142,7 +142,7 @@ def __init__(self, max_workers=None, thread_name_prefix='', self._initializer = initializer self._initargs = initargs - def submit(self, fn, *args, **kwargs): + def submit(self, fn, /, *args, **kwargs): with self._shutdown_lock: if self._broken: raise BrokenThreadPool(self._broken) diff --git a/Lib/contextlib.py b/Lib/contextlib.py index c06ec73f489d06..69c272831a55c2 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -377,7 +377,7 @@ def _create_exit_wrapper(cm, cm_exit): return MethodType(cm_exit, cm) @staticmethod - def _create_cb_wrapper(callback, *args, **kwds): + def _create_cb_wrapper(callback, /, *args, **kwds): def _exit_wrapper(exc_type, exc, tb): callback(*args, **kwds) return _exit_wrapper @@ -426,7 +426,7 @@ def enter_context(self, cm): self._push_cm_exit(cm, _exit) return result - def callback(self, callback, *args, **kwds): + def callback(self, callback, /, *args, **kwds): """Registers an arbitrary callback and arguments. Cannot suppress exceptions. @@ -536,7 +536,7 @@ def _create_async_exit_wrapper(cm, cm_exit): return MethodType(cm_exit, cm) @staticmethod - def _create_async_cb_wrapper(callback, *args, **kwds): + def _create_async_cb_wrapper(callback, /, *args, **kwds): async def _exit_wrapper(exc_type, exc, tb): await callback(*args, **kwds) return _exit_wrapper @@ -571,7 +571,7 @@ def push_async_exit(self, exit): self._push_async_cm_exit(exit, exit_method) return exit # Allow use as a decorator - def push_async_callback(self, callback, *args, **kwds): + def push_async_callback(self, callback, /, *args, **kwds): """Registers an arbitrary coroutine function and arguments. Cannot suppress exceptions. diff --git a/Lib/curses/__init__.py b/Lib/curses/__init__.py index 47378741acc255..69270bfcd2b205 100644 --- a/Lib/curses/__init__.py +++ b/Lib/curses/__init__.py @@ -60,7 +60,7 @@ def start_color(): # raises an exception, wrapper() will restore the terminal to a sane state so # you can read the resulting traceback. -def wrapper(func, *args, **kwds): +def wrapper(func, /, *args, **kwds): """Wrapper function that initializes curses and calls another function, restoring normal keyboard/screen behavior on error. The callable object 'func' is then passed the main window 'stdscr' diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 325b822d9f06f1..75113f123b3af1 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -962,10 +962,7 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen): return cls -# _cls should never be specified by keyword, so start it with an -# underscore. The presence of _cls is used to detect if this -# decorator is being called with parameters or not. -def dataclass(_cls=None, *, init=True, repr=True, eq=True, order=False, +def dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False): """Returns the same class as was passed in, with dunder methods added based on the fields defined in the class. @@ -983,12 +980,12 @@ def wrap(cls): return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen) # See if we're being called as @dataclass or @dataclass(). - if _cls is None: + if cls is None: # We're called with parens. return wrap # We're called as @dataclass without parens. - return wrap(_cls) + return wrap(cls) def fields(class_or_instance): diff --git a/Lib/functools.py b/Lib/functools.py index 426653f13f6d1e..2743e997c28986 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -273,15 +273,9 @@ class partial: __slots__ = "func", "args", "keywords", "__dict__", "__weakref__" - def __new__(*args, **keywords): - if not args: - raise TypeError("descriptor '__new__' of partial needs an argument") - if len(args) < 2: - raise TypeError("type 'partial' takes at least one argument") - cls, func, *args = args + def __new__(cls, func, /, *args, **keywords): if not callable(func): raise TypeError("the first argument must be callable") - args = tuple(args) if hasattr(func, "func"): args = func.args + args @@ -295,10 +289,7 @@ def __new__(*args, **keywords): self.keywords = keywords return self - def __call__(*args, **keywords): - if not args: - raise TypeError("descriptor '__call__' of partial needs an argument") - self, *args = args + def __call__(self, /, *args, **keywords): keywords = {**self.keywords, **keywords} return self.func(*self.args, *args, **keywords) @@ -354,7 +345,7 @@ class partialmethod(object): callables as instance methods. """ - def __init__(self, func, *args, **keywords): + def __init__(self, func, /, *args, **keywords): if not callable(func) and not hasattr(func, "__get__"): raise TypeError("{!r} is not callable or a descriptor" .format(func)) @@ -385,8 +376,7 @@ def __repr__(self): keywords=keywords) def _make_unbound_method(self): - def _method(*args, **keywords): - cls_or_self, *args = args + def _method(cls_or_self, /, *args, **keywords): keywords = {**self.keywords, **keywords} return self.func(cls_or_self, *self.args, *args, **keywords) _method.__isabstractmethod__ = self.__isabstractmethod__ diff --git a/Lib/idlelib/debugger_r.py b/Lib/idlelib/debugger_r.py index 0e6dcfbd12c2ab..9dcfc56414c050 100644 --- a/Lib/idlelib/debugger_r.py +++ b/Lib/idlelib/debugger_r.py @@ -299,7 +299,7 @@ def __init__(self, conn, shell, oid): self.conn = conn self.shell = shell - def call(self, methodname, *args, **kwargs): + def call(self, methodname, /, *args, **kwargs): ##print("*** IdbProxy.call %s %s %s" % (methodname, args, kwargs)) value = self.conn.remotecall(self.oid, methodname, args, kwargs) ##print("*** IdbProxy.call %s returns %r" % (methodname, value)) diff --git a/Lib/idlelib/rpc.py b/Lib/idlelib/rpc.py index f035bde4a0a0e2..aa8cbd36c47926 100644 --- a/Lib/idlelib/rpc.py +++ b/Lib/idlelib/rpc.py @@ -603,7 +603,7 @@ def __init__(self, sockio, oid, name): self.oid = oid self.name = name - def __call__(self, *args, **kwargs): + def __call__(self, /, *args, **kwargs): value = self.sockio.remotecall(self.oid, self.name, args, kwargs) return value diff --git a/Lib/inspect.py b/Lib/inspect.py index 8c398bd3534cb6..bfe39a04949542 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1328,14 +1328,12 @@ def _too_many(f_name, args, kwonly, varargs, defcount, given, values): (f_name, sig, "s" if plural else "", given, kwonly_sig, "was" if given == 1 and not kwonly_given else "were")) -def getcallargs(*func_and_positional, **named): +def getcallargs(func, /, *positional, **named): """Get the mapping of arguments to values. A dict is returned, with keys the function argument names (including the names of the * and ** arguments, if any), and values the respective bound values from 'positional' and 'named'.""" - func = func_and_positional[0] - positional = func_and_positional[1:] spec = getfullargspec(func) args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = spec f_name = func.__name__ @@ -3008,19 +3006,19 @@ def _bind(self, args, kwargs, *, partial=False): return self._bound_arguments_cls(self, arguments) - def bind(*args, **kwargs): + def bind(self, /, *args, **kwargs): """Get a BoundArguments object, that maps the passed `args` and `kwargs` to the function's signature. Raises `TypeError` if the passed arguments can not be bound. """ - return args[0]._bind(args[1:], kwargs) + return self._bind(args, kwargs) - def bind_partial(*args, **kwargs): + def bind_partial(self, /, *args, **kwargs): """Get a BoundArguments object, that partially maps the passed `args` and `kwargs` to the function's signature. Raises `TypeError` if the passed arguments can not be bound. """ - return args[0]._bind(args[1:], kwargs, partial=True) + return self._bind(args, kwargs, partial=True) def __reduce__(self): return (type(self), diff --git a/Lib/multiprocessing/dummy/__init__.py b/Lib/multiprocessing/dummy/__init__.py index 403f5e5198e4ed..6a1468609e347b 100644 --- a/Lib/multiprocessing/dummy/__init__.py +++ b/Lib/multiprocessing/dummy/__init__.py @@ -80,7 +80,7 @@ def freeze_support(): # class Namespace(object): - def __init__(self, **kwds): + def __init__(self, /, **kwds): self.__dict__.update(kwds) def __repr__(self): items = list(self.__dict__.items()) diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index 7973012b98d186..c149cdb4f1d633 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -358,7 +358,7 @@ def shutdown(self, c): finally: self.stop_event.set() - def create(self, c, typeid, *args, **kwds): + def create(self, c, typeid, /, *args, **kwds): ''' Create a new shared object and return its id ''' @@ -583,7 +583,7 @@ def _run_server(cls, registry, address, authkey, serializer, writer, util.info('manager serving at %r', server.address) server.serve_forever() - def _create(self, typeid, *args, **kwds): + def _create(self, typeid, /, *args, **kwds): ''' Create a new shared object; return the token and exposed tuple ''' @@ -703,7 +703,7 @@ def register(cls, typeid, callable=None, proxytype=None, exposed=None, ) if create_method: - def temp(self, *args, **kwds): + def temp(self, /, *args, **kwds): util.debug('requesting creation of a shared %r object', typeid) token, exp = self._create(typeid, *args, **kwds) proxy = proxytype( @@ -943,7 +943,7 @@ def MakeProxyType(name, exposed, _cache={}): dic = {} for meth in exposed: - exec('''def %s(self, *args, **kwds): + exec('''def %s(self, /, *args, **kwds): return self._callmethod(%r, args, kwds)''' % (meth, meth), dic) ProxyType = type(name, (BaseProxy,), dic) @@ -982,7 +982,7 @@ def AutoProxy(token, serializer, manager=None, authkey=None, # class Namespace(object): - def __init__(self, **kwds): + def __init__(self, /, **kwds): self.__dict__.update(kwds) def __repr__(self): items = list(self.__dict__.items()) @@ -1261,7 +1261,7 @@ def __init__(self, *args, **kwargs): _SharedMemoryTracker(f"shmm_{self.address}_{getpid()}") util.debug(f"SharedMemoryServer started by pid {getpid()}") - def create(self, c, typeid, *args, **kwargs): + def create(self, c, typeid, /, *args, **kwargs): """Create a new distributed-shared object (not backed by a shared memory block) and return its id to be used in a Proxy Object.""" # Unless set up as a shared proxy, don't make shared_memory_context diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py index 665ca067fa0763..b223d6aa724bb6 100644 --- a/Lib/multiprocessing/pool.py +++ b/Lib/multiprocessing/pool.py @@ -154,7 +154,7 @@ class _PoolCache(dict): notification is done by the use of a queue that is provided when instantiating the cache. """ - def __init__(self, *args, notifier=None, **kwds): + def __init__(self, /, *args, notifier=None, **kwds): self.notifier = notifier super().__init__(*args, **kwds) diff --git a/Lib/operator.py b/Lib/operator.py index 0e2e53efc69a77..fb58851fa6ef67 100644 --- a/Lib/operator.py +++ b/Lib/operator.py @@ -302,15 +302,11 @@ class methodcaller: """ __slots__ = ('_name', '_args', '_kwargs') - def __init__(*args, **kwargs): - if len(args) < 2: - msg = "methodcaller needs at least one argument, the method name" - raise TypeError(msg) - self = args[0] - self._name = args[1] + def __init__(self, name, /, *args, **kwargs): + self._name = name if not isinstance(self._name, str): raise TypeError('method name must be a string') - self._args = args[2:] + self._args = args self._kwargs = kwargs def __call__(self, obj): diff --git a/Lib/optparse.py b/Lib/optparse.py index 1c450c6fcbe3b6..994cf01316d49d 100644 --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -992,14 +992,13 @@ def _check_conflict(self, option): if not (c_option._short_opts or c_option._long_opts): c_option.container.option_list.remove(c_option) - def add_option(self, *args, **kwargs): + def add_option(self, option, /, *args, **kwargs): """add_option(Option) add_option(opt_str, ..., kwarg=val, ...) """ - if isinstance(args[0], str): - option = self.option_class(*args, **kwargs) - elif len(args) == 1 and not kwargs: - option = args[0] + if isinstance(option, str): + option = self.option_class(option, *args, **kwargs) + elif not args and not kwargs: if not isinstance(option, Option): raise TypeError("not an Option instance: %r" % option) else: @@ -1294,7 +1293,7 @@ def set_process_default_values(self, process): def set_default(self, dest, value): self.defaults[dest] = value - def set_defaults(self, **kwargs): + def set_defaults(self, /, **kwargs): self.defaults.update(kwargs) def _get_all_options(self): @@ -1320,12 +1319,11 @@ def get_default_values(self): # -- OptionGroup methods ------------------------------------------- - def add_option_group(self, *args, **kwargs): + def add_option_group(self, group, /, *args, **kwargs): # XXX lots of overlap with OptionContainer.add_option() - if isinstance(args[0], str): - group = OptionGroup(self, *args, **kwargs) - elif len(args) == 1 and not kwargs: - group = args[0] + if isinstance(group, str): + group = OptionGroup(self, group, *args, **kwargs) + elif not args and not kwargs: if not isinstance(group, OptionGroup): raise TypeError("not an OptionGroup instance: %r" % group) if group.parser is not self: diff --git a/Lib/profile.py b/Lib/profile.py index 5df43604acddb2..aad458dc951f41 100755 --- a/Lib/profile.py +++ b/Lib/profile.py @@ -425,7 +425,7 @@ def runctx(self, cmd, globals, locals): return self # This method is more useful to profile a single function call. - def runcall(self, func, *args, **kw): + def runcall(self, func, /, *args, **kw): self.set_cmd(repr(func)) sys.setprofile(self.dispatcher) try: diff --git a/Lib/random.py b/Lib/random.py index 79ef30d7d18d17..cba8a5bfdc3d4d 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -93,7 +93,7 @@ def __init__(self, x=None): self.seed(x) self.gauss_next = None - def __init_subclass__(cls, **kwargs): + def __init_subclass__(cls, /, **kwargs): """Control how subclasses generate random integers. The algorithm a subclass can use depends on the random() and/or diff --git a/Lib/string.py b/Lib/string.py index b9d6f5eb5675f6..b423ff5dc6f69f 100644 --- a/Lib/string.py +++ b/Lib/string.py @@ -52,6 +52,8 @@ def capwords(s, sep=None): import re as _re from collections import ChainMap as _ChainMap +_sentinel_dict = {} + class _TemplateMetaclass(type): pattern = r""" %(delim)s(?: @@ -104,19 +106,11 @@ def _invalid(self, mo): raise ValueError('Invalid placeholder in string: line %d, col %d' % (lineno, colno)) - def substitute(*args, **kws): - if not args: - raise TypeError("descriptor 'substitute' of 'Template' object " - "needs an argument") - self, *args = args # allow the "self" keyword be passed - if len(args) > 1: - raise TypeError('Too many positional arguments') - if not args: + def substitute(self, mapping=_sentinel_dict, /, **kws): + if mapping is _sentinel_dict: mapping = kws elif kws: - mapping = _ChainMap(kws, args[0]) - else: - mapping = args[0] + mapping = _ChainMap(kws, mapping) # Helper function for .sub() def convert(mo): # Check the most common path first. @@ -131,19 +125,11 @@ def convert(mo): self.pattern) return self.pattern.sub(convert, self.template) - def safe_substitute(*args, **kws): - if not args: - raise TypeError("descriptor 'safe_substitute' of 'Template' object " - "needs an argument") - self, *args = args # allow the "self" keyword be passed - if len(args) > 1: - raise TypeError('Too many positional arguments') - if not args: + def safe_substitute(self, mapping=_sentinel_dict, /, **kws): + if mapping is _sentinel_dict: mapping = kws elif kws: - mapping = _ChainMap(kws, args[0]) - else: - mapping = args[0] + mapping = _ChainMap(kws, mapping) # Helper function for .sub() def convert(mo): named = mo.group('named') or mo.group('braced') @@ -173,16 +159,7 @@ def convert(mo): # The field name parser is implemented in _string.formatter_field_name_split class Formatter: - def format(*args, **kwargs): - if not args: - raise TypeError("descriptor 'format' of 'Formatter' object " - "needs an argument") - self, *args = args # allow the "self" keyword be passed - try: - format_string, *args = args # allow the "format_string" keyword be passed - except ValueError: - raise TypeError("format() missing 1 required positional " - "argument: 'format_string'") from None + def format(self, format_string, /, *args, **kwargs): return self.vformat(format_string, args, kwargs) def vformat(self, format_string, args, kwargs): diff --git a/Lib/test/support/script_helper.py b/Lib/test/support/script_helper.py index 27a47f2c4e668c..83519988e39478 100644 --- a/Lib/test/support/script_helper.py +++ b/Lib/test/support/script_helper.py @@ -137,7 +137,7 @@ def run_python_until_end(*args, **env_vars): err = strip_python_stderr(err) return _PythonRunResult(rc, out, err), cmd_line -def _assert_python(expected_success, *args, **env_vars): +def _assert_python(expected_success, /, *args, **env_vars): res, cmd_line = run_python_until_end(*args, **env_vars) if (res.rc and expected_success) or (not res.rc and not expected_success): res.fail(cmd_line) diff --git a/Lib/trace.py b/Lib/trace.py index 3049e4ec683941..bf43c4a40d91c4 100755 --- a/Lib/trace.py +++ b/Lib/trace.py @@ -451,7 +451,7 @@ def runctx(self, cmd, globals=None, locals=None): sys.settrace(None) threading.settrace(None) - def runfunc(self, func, *args, **kw): + def runfunc(self, func, /, *args, **kw): result = None if not self.donothing: sys.settrace(self.globaltrace) diff --git a/Lib/typing.py b/Lib/typing.py index 530d4633fe4c22..ce789a1f684f6a 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -272,7 +272,7 @@ class _Final: __slots__ = ('__weakref__',) - def __init_subclass__(self, *args, **kwds): + def __init_subclass__(self, /, *args, **kwds): if '_root' not in kwds: raise TypeError("Cannot subclass special typing classes") diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py index a157ae8a14bcbe..9dc4031fbb5007 100644 --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -86,7 +86,7 @@ def _id(obj): _module_cleanups = [] -def addModuleCleanup(function, *args, **kwargs): +def addModuleCleanup(function, /, *args, **kwargs): """Same as addCleanup, except the cleanup items are called even if setUpModule fails (unlike tearDownModule).""" _module_cleanups.append((function, args, kwargs)) @@ -463,7 +463,7 @@ def addTypeEqualityFunc(self, typeobj, function): """ self._type_equality_funcs[typeobj] = function - def addCleanup(self, function, *args, **kwargs): + def addCleanup(self, function, /, *args, **kwargs): """Add a function, with arguments, to be called when the test is completed. Functions added are called on a LIFO basis and are called after tearDown on test failure or success. @@ -472,7 +472,7 @@ def addCleanup(self, function, *args, **kwargs): self._cleanups.append((function, args, kwargs)) @classmethod - def addClassCleanup(cls, function, *args, **kwargs): + def addClassCleanup(cls, function, /, *args, **kwargs): """Same as addCleanup, except the cleanup items are called even if setUpClass fails (unlike tearDownClass).""" cls._class_cleanups.append((function, args, kwargs)) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 8684f1dfa5729f..cd94b8497b3643 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -99,7 +99,7 @@ def _check_signature(func, mock, skipfirst, instance=False): if sig is None: return func, sig = sig - def checksig(_mock_self, *args, **kwargs): + def checksig(self, /, *args, **kwargs): sig.bind(*args, **kwargs) _copy_func_details(func, checksig) type(mock)._mock_check_sig = checksig @@ -783,10 +783,9 @@ def _call_matcher(self, _call): else: return _call - def assert_not_called(_mock_self): + def assert_not_called(self): """assert that the mock was never called. """ - self = _mock_self if self.call_count != 0: msg = ("Expected '%s' to not have been called. Called %s times.%s" % (self._mock_name or 'mock', @@ -794,19 +793,17 @@ def assert_not_called(_mock_self): self._calls_repr())) raise AssertionError(msg) - def assert_called(_mock_self): + def assert_called(self): """assert that the mock was called at least once """ - self = _mock_self if self.call_count == 0: msg = ("Expected '%s' to have been called." % self._mock_name or 'mock') raise AssertionError(msg) - def assert_called_once(_mock_self): + def assert_called_once(self): """assert that the mock was called only once. """ - self = _mock_self if not self.call_count == 1: msg = ("Expected '%s' to have been called once. Called %s times.%s" % (self._mock_name or 'mock', @@ -814,12 +811,11 @@ def assert_called_once(_mock_self): self._calls_repr())) raise AssertionError(msg) - def assert_called_with(_mock_self, *args, **kwargs): + def assert_called_with(self, /, *args, **kwargs): """assert that the mock was called with the specified arguments. Raises an AssertionError if the args and keyword args passed in are different to the last call to the mock.""" - self = _mock_self if self.call_args is None: expected = self._format_mock_call_signature(args, kwargs) actual = 'not called.' @@ -837,10 +833,9 @@ def _error_message(): raise AssertionError(_error_message()) from cause - def assert_called_once_with(_mock_self, *args, **kwargs): + def assert_called_once_with(self, /, *args, **kwargs): """assert that the mock was called exactly once and that that call was with the specified arguments.""" - self = _mock_self if not self.call_count == 1: msg = ("Expected '%s' to be called once. Called %s times.%s" % (self._mock_name or 'mock', @@ -978,15 +973,14 @@ def _mock_check_sig(self, *args, **kwargs): pass - def __call__(_mock_self, *args, **kwargs): + def __call__(self, /, *args, **kwargs): # can't use self in-case a function / method we are mocking uses self # in the signature - _mock_self._mock_check_sig(*args, **kwargs) - return _mock_self._mock_call(*args, **kwargs) + self._mock_check_sig(*args, **kwargs) + return self._mock_call(*args, **kwargs) - def _mock_call(_mock_self, *args, **kwargs): - self = _mock_self + def _mock_call(self, /, *args, **kwargs): self.called = True self.call_count += 1 @@ -1773,7 +1767,7 @@ def _patch_stopall(): def _get_method(name, func): "Turns a callable object (like a mock) into a real function" - def method(self, *args, **kw): + def method(self, /, *args, **kw): return func(self, *args, **kw) method.__name__ = name return method diff --git a/Lib/weakref.py b/Lib/weakref.py index 753f07291e20e8..fa7559bb3dbf86 100644 --- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -99,13 +99,7 @@ class WeakValueDictionary(_collections_abc.MutableMapping): # objects are unwrapped on the way out, and we always wrap on the # way in). - def __init__(*args, **kw): - if not args: - raise TypeError("descriptor '__init__' of 'WeakValueDictionary' " - "object needs an argument") - self, *args = args - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) + def __init__(self, other=(), /, **kw): def remove(wr, selfref=ref(self), _atomic_removal=_remove_dead_weakref): self = selfref() if self is not None: @@ -120,7 +114,7 @@ def remove(wr, selfref=ref(self), _atomic_removal=_remove_dead_weakref): self._pending_removals = [] self._iterating = set() self.data = d = {} - self.update(*args, **kw) + self.update(other, **kw) def _commit_removals(self): l = self._pending_removals @@ -287,24 +281,17 @@ def setdefault(self, key, default=None): else: return o - def update(*args, **kwargs): - if not args: - raise TypeError("descriptor 'update' of 'WeakValueDictionary' " - "object needs an argument") - self, *args = args - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) - dict = args[0] if args else None + def update(self, other=None, /, **kwargs): if self._pending_removals: self._commit_removals() d = self.data - if dict is not None: - if not hasattr(dict, "items"): - dict = type({})(dict) - for key, o in dict.items(): + if other is not None: + if not hasattr(other, "items"): + other = dict(other) + for key, o in other.items(): d[key] = KeyedRef(o, self._remove, key) - if len(kwargs): - self.update(kwargs) + for key, o in kwargs.items(): + d[key] = KeyedRef(o, self._remove, key) def valuerefs(self): """Return a list of weak references to the values. @@ -488,7 +475,7 @@ def pop(self, key, *args): def setdefault(self, key, default=None): return self.data.setdefault(ref(key, self._remove),default) - def update(self, dict=None, **kwargs): + def update(self, dict=None, /, **kwargs): d = self.data if dict is not None: if not hasattr(dict, "items"): @@ -527,7 +514,7 @@ class finalize: class _Info: __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index") - def __init__(self, obj, func, *args, **kwargs): + def __init__(self, obj, func, /, *args, **kwargs): if not self._registered_with_atexit: # We may register the exit function more than once because # of a thread race, but that is harmless From e68b9342e01ea2aceb00d37af7fbdd789457f7b7 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 1 Apr 2019 09:37:14 +0300 Subject: [PATCH 2/9] Revert changes in argparse and optparse. --- Lib/argparse.py | 4 ++-- Lib/optparse.py | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index 66a4161495def5..798766f6c4086a 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1220,7 +1220,7 @@ class Namespace(_AttributeHolder): string representation. """ - def __init__(self, /, **kwargs): + def __init__(self, **kwargs): for name in kwargs: setattr(self, name, kwargs[name]) @@ -1297,7 +1297,7 @@ def _registry_get(self, registry_name, value, default=None): # ================================== # Namespace default accessor methods # ================================== - def set_defaults(self, /, **kwargs): + def set_defaults(self, **kwargs): self._defaults.update(kwargs) # if these defaults match any existing arguments, replace diff --git a/Lib/optparse.py b/Lib/optparse.py index 994cf01316d49d..1c450c6fcbe3b6 100644 --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -992,13 +992,14 @@ def _check_conflict(self, option): if not (c_option._short_opts or c_option._long_opts): c_option.container.option_list.remove(c_option) - def add_option(self, option, /, *args, **kwargs): + def add_option(self, *args, **kwargs): """add_option(Option) add_option(opt_str, ..., kwarg=val, ...) """ - if isinstance(option, str): - option = self.option_class(option, *args, **kwargs) - elif not args and not kwargs: + if isinstance(args[0], str): + option = self.option_class(*args, **kwargs) + elif len(args) == 1 and not kwargs: + option = args[0] if not isinstance(option, Option): raise TypeError("not an Option instance: %r" % option) else: @@ -1293,7 +1294,7 @@ def set_process_default_values(self, process): def set_default(self, dest, value): self.defaults[dest] = value - def set_defaults(self, /, **kwargs): + def set_defaults(self, **kwargs): self.defaults.update(kwargs) def _get_all_options(self): @@ -1319,11 +1320,12 @@ def get_default_values(self): # -- OptionGroup methods ------------------------------------------- - def add_option_group(self, group, /, *args, **kwargs): + def add_option_group(self, *args, **kwargs): # XXX lots of overlap with OptionContainer.add_option() - if isinstance(group, str): - group = OptionGroup(self, group, *args, **kwargs) - elif not args and not kwargs: + if isinstance(args[0], str): + group = OptionGroup(self, *args, **kwargs) + elif len(args) == 1 and not kwargs: + group = args[0] if not isinstance(group, OptionGroup): raise TypeError("not an OptionGroup instance: %r" % group) if group.parser is not self: From ba6873969a7acca711190bc6bcda541e3c28d081 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 31 May 2019 10:51:20 +0300 Subject: [PATCH 3/9] Remove unneeded settings of __text_signature__. --- Lib/bdb.py | 1 - Lib/cProfile.py | 1 - Lib/collections/__init__.py | 1 - Lib/concurrent/futures/_base.py | 1 - Lib/concurrent/futures/process.py | 1 - Lib/concurrent/futures/thread.py | 1 - Lib/contextlib.py | 2 -- Lib/curses/__init__.py | 1 - Lib/functools.py | 1 - Lib/multiprocessing/managers.py | 1 - Lib/profile.py | 1 - Lib/trace.py | 1 - Lib/unittest/case.py | 2 -- Lib/weakref.py | 1 - 14 files changed, 16 deletions(-) diff --git a/Lib/bdb.py b/Lib/bdb.py index 1c6490e41b3ccd..6fbd0117b90a91 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -634,7 +634,6 @@ def runcall(self, func, /, *args, **kwds): 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 f0ad1bc22e40b7..4f202038d61260 100755 --- a/Lib/cProfile.py +++ b/Lib/cProfile.py @@ -109,7 +109,6 @@ def runcall(self, func, /, *args, **kw): 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 45b850fc4fd783..2264efe94a7d3c 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -977,7 +977,6 @@ def __init__(self, dict=None, /, **kwargs): 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): diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py index 98ecb2058b2cbf..fd0acec55d0460 100644 --- a/Lib/concurrent/futures/_base.py +++ b/Lib/concurrent/futures/_base.py @@ -557,7 +557,6 @@ def submit(self, fn, /, *args, **kwargs): A Future representing the given call. """ 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 24c77887d7a6f3..cfdcd3ed7ea9df 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -629,7 +629,6 @@ def submit(self, fn, /, *args, **kwargs): 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 e87c0daa0fe84c..75d05a76be3f41 100644 --- a/Lib/concurrent/futures/thread.py +++ b/Lib/concurrent/futures/thread.py @@ -172,7 +172,6 @@ def submit(self, fn, /, *args, **kwargs): 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 2c2e890b3638b2..69c272831a55c2 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -438,7 +438,6 @@ def callback(self, callback, /, *args, **kwds): _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.""" @@ -584,7 +583,6 @@ def push_async_callback(self, callback, /, *args, **kwds): _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 187b94f4304bbd..69270bfcd2b205 100644 --- a/Lib/curses/__init__.py +++ b/Lib/curses/__init__.py @@ -99,4 +99,3 @@ def wrapper(func, /, *args, **kwds): echo() nocbreak() endwin() -wrapper.__text_signature__ = '(func, /, *args, **kwds)' diff --git a/Lib/functools.py b/Lib/functools.py index bea359e9ab72e5..9495fbe56eba39 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -363,7 +363,6 @@ def __init__(self, func, /, *args, **keywords): 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/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index 8e68ae03228808..75b5150f821b1c 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -395,7 +395,6 @@ def create(self, c, typeid, /, *args, **kwds): self.incref(c, ident) return ident, tuple(exposed) - create.__text_signature__ = '($self, c, typeid, /, *args, **kwds)' def get_methods(self, c, token): ''' diff --git a/Lib/profile.py b/Lib/profile.py index 285f5df1912058..aad458dc951f41 100755 --- a/Lib/profile.py +++ b/Lib/profile.py @@ -432,7 +432,6 @@ def runcall(self, func, /, *args, **kw): return func(*args, **kw) finally: sys.setprofile(None) - runcall.__text_signature__ = '($self, func, /, *args, **kw)' #****************************************************************** diff --git a/Lib/trace.py b/Lib/trace.py index 7fa8d74604d00d..bf43c4a40d91c4 100755 --- a/Lib/trace.py +++ b/Lib/trace.py @@ -461,7 +461,6 @@ def runfunc(self, func, /, *args, **kw): 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 50834f5400ba33..8afb84513590f4 100644 --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -90,7 +90,6 @@ def addModuleCleanup(function, /, *args, **kwargs): """Same as addCleanup, except the cleanup items are called even if setUpModule fails (unlike tearDownModule).""" _module_cleanups.append((function, args, kwargs)) -addModuleCleanup.__text_signature__ = '(function, /, *args, **kwargs)' def doModuleCleanups(): @@ -471,7 +470,6 @@ def addCleanup(self, function, /, *args, **kwargs): Cleanup items are called even if setUp fails (unlike tearDown).""" self._cleanups.append((function, args, kwargs)) - addCleanup.__text_signature__ = '($self, function, /, *args, **kwargs)' @classmethod def addClassCleanup(cls, function, /, *args, **kwargs): diff --git a/Lib/weakref.py b/Lib/weakref.py index 5e06c130a3a99a..fa7559bb3dbf86 100644 --- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -530,7 +530,6 @@ def __init__(self, obj, func, /, *args, **kwargs): 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); From 1529d5537b895208b5e259b0c84a6b434e6a41d2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 31 May 2019 17:00:05 +0300 Subject: [PATCH 4/9] Fix tests. --- Lib/test/test_userdict.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_userdict.py b/Lib/test/test_userdict.py index 662c7f641af228..483910aaa4620e 100644 --- a/Lib/test/test_userdict.py +++ b/Lib/test/test_userdict.py @@ -30,8 +30,8 @@ def test_all(self): self.assertEqual(collections.UserDict(one=1, two=2), d2) # item sequence constructor self.assertEqual(collections.UserDict([('one',1), ('two',2)]), d2) - with self.assertWarnsRegex(DeprecationWarning, "'dict'"): - self.assertEqual(collections.UserDict(dict=[('one',1), ('two',2)]), d2) + self.assertEqual(collections.UserDict(dict=[('one',1), ('two',2)]), + {'dict': [('one', 1), ('two', 2)]}) # both together self.assertEqual(collections.UserDict([('one',1), ('two',2)], two=3, three=5), d3) @@ -149,9 +149,8 @@ def test_init(self): [('dict', 42)]) self.assertEqual(list(collections.UserDict({}, dict=None).items()), [('dict', None)]) - with self.assertWarnsRegex(DeprecationWarning, "'dict'"): - self.assertEqual(list(collections.UserDict(dict={'a': 42}).items()), - [('a', 42)]) + self.assertEqual(list(collections.UserDict(dict={'a': 42}).items()), + [('dict', {'a': 42})]) self.assertRaises(TypeError, collections.UserDict, 42) self.assertRaises(TypeError, collections.UserDict, (), ()) self.assertRaises(TypeError, collections.UserDict.__init__) From f12a89cf18c51451f19716eb154eec6048e6d26e Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 31 May 2019 17:21:34 +0300 Subject: [PATCH 5/9] Keep changes that can be applied in 3.8. --- Lib/bdb.py | 18 +++++++++++- Lib/cProfile.py | 18 +++++++++++- Lib/collections/__init__.py | 18 +++++++++++- Lib/concurrent/futures/_base.py | 16 ++++++++++- Lib/concurrent/futures/process.py | 18 +++++++++++- Lib/concurrent/futures/thread.py | 18 +++++++++++- Lib/contextlib.py | 36 +++++++++++++++++++++-- Lib/curses/__init__.py | 14 ++++++++- Lib/functools.py | 19 ++++++++++++- Lib/multiprocessing/managers.py | 44 +++++++++++++++++++++++++++-- Lib/profile.py | 18 +++++++++++- Lib/test/test_concurrent_futures.py | 5 ++-- Lib/test/test_contextlib.py | 4 +-- Lib/test/test_contextlib_async.py | 4 +-- Lib/test/test_functools.py | 4 ++- Lib/test/test_trace.py | 5 ++-- Lib/test/test_userdict.py | 9 +++--- Lib/test/test_weakref.py | 18 +++++++++--- Lib/trace.py | 18 +++++++++++- Lib/unittest/case.py | 34 ++++++++++++++++++++-- Lib/unittest/test/test_runner.py | 5 ++-- Lib/weakref.py | 29 ++++++++++++++++++- 22 files changed, 334 insertions(+), 38 deletions(-) diff --git a/Lib/bdb.py b/Lib/bdb.py index 6fbd0117b90a91..69174364c46aef 100644 --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -618,11 +618,26 @@ def runctx(self, cmd, globals, locals): # This method is more useful to debug a single function call. - def runcall(self, func, /, *args, **kwds): + def runcall(*args, **kwds): """Debug a single function call. Return the result of the function call. """ + if len(args) >= 2: + self, func, *args = args + elif not args: + raise TypeError("descriptor 'runcall' of 'Bdb' object " + "needs an argument") + elif 'func' in kwds: + func = kwds.pop('func') + self, *args = args + import warnings + warnings.warn("Passing 'func' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError('runcall expected at least 1 positional argument, ' + 'got %d' % (len(args)-1)) + self.reset() sys.settrace(self.trace_dispatch) res = None @@ -634,6 +649,7 @@ def runcall(self, func, /, *args, **kwds): 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 4f202038d61260..369d02e22e24aa 100755 --- a/Lib/cProfile.py +++ b/Lib/cProfile.py @@ -103,12 +103,28 @@ def runctx(self, cmd, globals, locals): return self # This method is more useful to profile a single function call. - def runcall(self, func, /, *args, **kw): + def runcall(*args, **kw): + if len(args) >= 2: + self, func, *args = args + elif not args: + raise TypeError("descriptor 'runcall' of 'Profile' object " + "needs an argument") + elif 'func' in kw: + func = kw.pop('func') + self, *args = args + import warnings + warnings.warn("Passing 'func' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError('runcall expected at least 1 positional argument, ' + 'got %d' % (len(args)-1)) + self.enable() try: 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 2264efe94a7d3c..e9999e27d5f535 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -971,12 +971,28 @@ def clear(self): class UserDict(_collections_abc.MutableMapping): # Start by filling-out the abstract methods - def __init__(self, dict=None, /, **kwargs): + def __init__(*args, **kwargs): + if not args: + raise TypeError("descriptor '__init__' of 'UserDict' object " + "needs an argument") + self, *args = args + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + if args: + dict = args[0] + elif 'dict' in kwargs: + dict = kwargs.pop('dict') + import warnings + warnings.warn("Passing 'dict' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + dict = None self.data = {} if dict is not None: 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): diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py index fd0acec55d0460..6001e3bdb81bb3 100644 --- a/Lib/concurrent/futures/_base.py +++ b/Lib/concurrent/futures/_base.py @@ -547,7 +547,7 @@ def set_exception(self, exception): class Executor(object): """This is an abstract base class for concrete asynchronous executors.""" - def submit(self, fn, /, *args, **kwargs): + def submit(*args, **kwargs): """Submits a callable to be executed with the given arguments. Schedules the callable to be executed as fn(*args, **kwargs) and returns @@ -556,7 +556,21 @@ def submit(self, fn, /, *args, **kwargs): Returns: A Future representing the given call. """ + if len(args) >= 2: + pass + elif not args: + raise TypeError("descriptor 'submit' of 'Executor' object " + "needs an argument") + elif 'fn' in kwargs: + import warnings + warnings.warn("Passing 'fn' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError('submit expected at least 1 positional argument, ' + '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 cfdcd3ed7ea9df..dd14eaec907d7b 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -608,7 +608,22 @@ def _adjust_process_count(self): p.start() self._processes[p.pid] = p - def submit(self, fn, /, *args, **kwargs): + def submit(*args, **kwargs): + if len(args) >= 2: + self, fn, *args = args + elif not args: + raise TypeError("descriptor 'submit' of 'ProcessPoolExecutor' object " + "needs an argument") + elif 'fn' in kwargs: + fn = kwargs.pop('fn') + self, *args = args + import warnings + warnings.warn("Passing 'fn' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError('submit expected at least 1 positional argument, ' + 'got %d' % (len(args)-1)) + with self._shutdown_lock: if self._broken: raise BrokenProcessPool(self._broken) @@ -629,6 +644,7 @@ def submit(self, fn, /, *args, **kwargs): 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 75d05a76be3f41..2426e94de91fcb 100644 --- a/Lib/concurrent/futures/thread.py +++ b/Lib/concurrent/futures/thread.py @@ -155,7 +155,22 @@ def __init__(self, max_workers=None, thread_name_prefix='', self._initializer = initializer self._initargs = initargs - def submit(self, fn, /, *args, **kwargs): + def submit(*args, **kwargs): + if len(args) >= 2: + self, fn, *args = args + elif not args: + raise TypeError("descriptor 'submit' of 'ThreadPoolExecutor' object " + "needs an argument") + elif 'fn' in kwargs: + fn = kwargs.pop('fn') + self, *args = args + import warnings + warnings.warn("Passing 'fn' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError('submit expected at least 1 positional argument, ' + 'got %d' % (len(args)-1)) + with self._shutdown_lock: if self._broken: raise BrokenThreadPool(self._broken) @@ -172,6 +187,7 @@ def submit(self, fn, /, *args, **kwargs): 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 69c272831a55c2..94dc2bfed06cd8 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -426,11 +426,26 @@ def enter_context(self, cm): self._push_cm_exit(cm, _exit) return result - def callback(self, callback, /, *args, **kwds): + def callback(*args, **kwds): """Registers an arbitrary callback and arguments. Cannot suppress exceptions. """ + if len(args) >= 2: + self, callback, *args = args + elif not args: + raise TypeError("descriptor 'callback' of '_BaseExitStack' object " + "needs an argument") + elif 'callback' in kwds: + callback = kwds.pop('callback') + self, *args = args + import warnings + warnings.warn("Passing 'callback' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError('callback expected at least 1 positional argument, ' + 'got %d' % (len(args)-1)) + _exit_wrapper = self._create_cb_wrapper(callback, *args, **kwds) # We changed the signature, so using @wraps is not appropriate, but @@ -438,6 +453,7 @@ def callback(self, callback, /, *args, **kwds): _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.""" @@ -571,11 +587,26 @@ def push_async_exit(self, exit): self._push_async_cm_exit(exit, exit_method) return exit # Allow use as a decorator - def push_async_callback(self, callback, /, *args, **kwds): + def push_async_callback(*args, **kwds): """Registers an arbitrary coroutine function and arguments. Cannot suppress exceptions. """ + if len(args) >= 2: + self, callback, *args = args + elif not args: + raise TypeError("descriptor 'push_async_callback' of " + "'AsyncExitStack' object needs an argument") + elif 'callback' in kwds: + callback = kwds.pop('callback') + self, *args = args + import warnings + warnings.warn("Passing 'callback' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError('push_async_callback expected at least 1 ' + 'positional argument, got %d' % (len(args)-1)) + _exit_wrapper = self._create_async_cb_wrapper(callback, *args, **kwds) # We changed the signature, so using @wraps is not appropriate, but @@ -583,6 +614,7 @@ def push_async_callback(self, callback, /, *args, **kwds): _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 69270bfcd2b205..24ff3ca93a8933 100644 --- a/Lib/curses/__init__.py +++ b/Lib/curses/__init__.py @@ -60,7 +60,7 @@ def start_color(): # raises an exception, wrapper() will restore the terminal to a sane state so # you can read the resulting traceback. -def wrapper(func, /, *args, **kwds): +def wrapper(*args, **kwds): """Wrapper function that initializes curses and calls another function, restoring normal keyboard/screen behavior on error. The callable object 'func' is then passed the main window 'stdscr' @@ -68,6 +68,17 @@ def wrapper(func, /, *args, **kwds): wrapper(). """ + if args: + func, *args = args + elif 'func' in kwds: + func = kwds.pop('func') + import warnings + warnings.warn("Passing 'func' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError('wrapper expected at least 1 positional argument, ' + 'got %d' % len(args)) + try: # Initialize curses stdscr = initscr() @@ -99,3 +110,4 @@ def wrapper(func, /, *args, **kwds): echo() nocbreak() endwin() +wrapper.__text_signature__ = '(func, /, *args, **kwds)' diff --git a/Lib/functools.py b/Lib/functools.py index 9495fbe56eba39..64d120182bb07a 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -345,7 +345,23 @@ class partialmethod(object): callables as instance methods. """ - def __init__(self, func, /, *args, **keywords): + def __init__(*args, **keywords): + if len(args) >= 2: + self, func, *args = args + elif not args: + raise TypeError("descriptor '__init__' of partialmethod " + "needs an argument") + elif 'func' in keywords: + func = keywords.pop('func') + self, *args = args + import warnings + warnings.warn("Passing 'func' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError("type 'partialmethod' takes at least one argument, " + "got %d" % (len(args)-1)) + args = tuple(args) + if not callable(func) and not hasattr(func, "__get__"): raise TypeError("{!r} is not callable or a descriptor" .format(func)) @@ -363,6 +379,7 @@ def __init__(self, func, /, *args, **keywords): 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/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index 75b5150f821b1c..7e1818bb099685 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -360,10 +360,36 @@ def shutdown(self, c): finally: self.stop_event.set() - def create(self, c, typeid, /, *args, **kwds): + def create(*args, **kwds): ''' Create a new shared object and return its id ''' + if len(args) >= 3: + self, c, typeid, *args = args + elif not args: + raise TypeError("descriptor 'create' of 'Server' object " + "needs an argument") + else: + if 'typeid' not in kwds: + raise TypeError('create expected at least 2 positional ' + 'arguments, got %d' % (len(args)-1)) + typeid = kwds.pop('typeid') + if len(args) >= 2: + self, c, *args = args + import warnings + warnings.warn("Passing 'typeid' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + if 'c' not in kwds: + raise TypeError('create expected at least 2 positional ' + 'arguments, got %d' % (len(args)-1)) + c = kwds.pop('c') + self, *args = args + import warnings + warnings.warn("Passing 'c' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + args = tuple(args) + with self.mutex: callable, exposed, method_to_typeid, proxytype = \ self.registry[typeid] @@ -395,6 +421,7 @@ def create(self, c, typeid, /, *args, **kwds): self.incref(c, ident) return ident, tuple(exposed) + create.__text_signature__ = '($self, c, typeid, /, *args, **kwds)' def get_methods(self, c, token): ''' @@ -1266,15 +1293,26 @@ def __init__(self, *args, **kwargs): _SharedMemoryTracker(f"shmm_{self.address}_{getpid()}") util.debug(f"SharedMemoryServer started by pid {getpid()}") - def create(self, c, typeid, /, *args, **kwargs): + def create(*args, **kwargs): """Create a new distributed-shared object (not backed by a shared memory block) and return its id to be used in a Proxy Object.""" # Unless set up as a shared proxy, don't make shared_memory_context # a standard part of kwargs. This makes things easier for supplying # simple functions. + if len(args) >= 3: + typeod = args[2] + elif 'typeid' in kwargs: + typeid = kwargs['typeid'] + elif not args: + raise TypeError("descriptor 'create' of 'SharedMemoryServer' " + "object needs an argument") + else: + raise TypeError('create expected at least 2 positional ' + 'arguments, got %d' % (len(args)-1)) if hasattr(self.registry[typeid][-1], "_shared_memory_proxy"): kwargs['shared_memory_context'] = self.shared_memory_context - return Server.create(self, c, typeid, *args, **kwargs) + 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 aad458dc951f41..1346297c04a593 100755 --- a/Lib/profile.py +++ b/Lib/profile.py @@ -425,13 +425,29 @@ def runctx(self, cmd, globals, locals): return self # This method is more useful to profile a single function call. - def runcall(self, func, /, *args, **kw): + def runcall(*args, **kw): + if len(args) >= 2: + self, func, *args = args + elif not args: + raise TypeError("descriptor 'runcall' of 'Profile' object " + "needs an argument") + elif 'func' in kw: + func = kw.pop('func') + self, *args = args + import warnings + warnings.warn("Passing 'func' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError('runcall expected at least 1 positional argument, ' + 'got %d' % (len(args)-1)) + self.set_cmd(repr(func)) sys.setprofile(self.dispatcher) try: return func(*args, **kw) finally: sys.setprofile(None) + runcall.__text_signature__ = '($self, func, /, *args, **kw)' #****************************************************************** diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py index 2497c2b5727528..b27ae719482285 100644 --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -668,8 +668,9 @@ def test_submit_keyword(self): self.assertEqual(16, future.result()) future = self.executor.submit(capture, 1, self=2, fn=3) self.assertEqual(future.result(), ((1,), {'self': 2, 'fn': 3})) - with self.assertRaises(TypeError): - self.executor.submit(fn=capture, arg=1) + with self.assertWarns(DeprecationWarning): + future = self.executor.submit(fn=capture, arg=1) + self.assertEqual(future.result(), ((), {'arg': 1})) with self.assertRaises(TypeError): self.executor.submit(arg=1) diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py index 024f912647295a..188a29d9f9fd77 100644 --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -603,9 +603,9 @@ def _exit(*args, **kwds): stack.callback(arg=1) with self.assertRaises(TypeError): self.exit_stack.callback(arg=2) - with self.assertRaises(TypeError): + with self.assertWarns(DeprecationWarning): stack.callback(callback=_exit, arg=3) - self.assertEqual(result, []) + self.assertEqual(result, [((), {'arg': 3})]) def test_push(self): exc_raised = ZeroDivisionError diff --git a/Lib/test/test_contextlib_async.py b/Lib/test/test_contextlib_async.py index 43fb7fced1bfdb..492b226a0d549b 100644 --- a/Lib/test/test_contextlib_async.py +++ b/Lib/test/test_contextlib_async.py @@ -358,9 +358,9 @@ async def _exit(*args, **kwds): stack.push_async_callback(arg=1) with self.assertRaises(TypeError): self.exit_stack.push_async_callback(arg=2) - with self.assertRaises(TypeError): + with self.assertWarns(DeprecationWarning): stack.push_async_callback(callback=_exit, arg=3) - self.assertEqual(result, []) + self.assertEqual(result, [((), {'arg': 3})]) @_async_test async def test_async_push(self): diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index c300270d49e5ec..8fee1c6afdd450 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -556,9 +556,11 @@ class B(object): with self.assertRaises(TypeError): class B: method = functools.partialmethod() - with self.assertRaises(TypeError): + with self.assertWarns(DeprecationWarning): class B: method = functools.partialmethod(func=capture, a=1) + b = B() + self.assertEqual(b.method(2, x=3), ((b, 2), {'a': 1, 'x': 3})) def test_repr(self): self.assertEqual(repr(vars(self.A)['both']), diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py index d7c324c0d479a4..afe79026766192 100644 --- a/Lib/test/test_trace.py +++ b/Lib/test/test_trace.py @@ -276,8 +276,9 @@ def test_simple_caller(self): def test_arg_errors(self): res = self.tracer.runfunc(traced_capturer, 1, 2, self=3, func=4) self.assertEqual(res, ((1, 2), {'self': 3, 'func': 4})) - with self.assertRaises(TypeError): - self.tracer.runfunc(func=traced_capturer, arg=1) + with self.assertWarns(DeprecationWarning): + res = self.tracer.runfunc(func=traced_capturer, arg=1) + self.assertEqual(res, ((), {'arg': 1})) with self.assertRaises(TypeError): self.tracer.runfunc() diff --git a/Lib/test/test_userdict.py b/Lib/test/test_userdict.py index 483910aaa4620e..662c7f641af228 100644 --- a/Lib/test/test_userdict.py +++ b/Lib/test/test_userdict.py @@ -30,8 +30,8 @@ def test_all(self): self.assertEqual(collections.UserDict(one=1, two=2), d2) # item sequence constructor self.assertEqual(collections.UserDict([('one',1), ('two',2)]), d2) - self.assertEqual(collections.UserDict(dict=[('one',1), ('two',2)]), - {'dict': [('one', 1), ('two', 2)]}) + with self.assertWarnsRegex(DeprecationWarning, "'dict'"): + self.assertEqual(collections.UserDict(dict=[('one',1), ('two',2)]), d2) # both together self.assertEqual(collections.UserDict([('one',1), ('two',2)], two=3, three=5), d3) @@ -149,8 +149,9 @@ def test_init(self): [('dict', 42)]) self.assertEqual(list(collections.UserDict({}, dict=None).items()), [('dict', None)]) - self.assertEqual(list(collections.UserDict(dict={'a': 42}).items()), - [('dict', {'a': 42})]) + with self.assertWarnsRegex(DeprecationWarning, "'dict'"): + self.assertEqual(list(collections.UserDict(dict={'a': 42}).items()), + [('a', 42)]) self.assertRaises(TypeError, collections.UserDict, 42) self.assertRaises(TypeError, collections.UserDict, (), ()) self.assertRaises(TypeError, collections.UserDict.__init__) diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py index ce5bbfccd78789..6f15c03ac5292f 100644 --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -1866,10 +1866,20 @@ def fin(*args, **kwargs): f() self.assertEqual(res, [((1, 2), {'func': 3, 'obj': 4})]) - with self.assertRaises(TypeError): - weakref.finalize(a, func=fin, arg=1) - with self.assertRaises(TypeError): - weakref.finalize(obj=a, func=fin, arg=1) + res = [] + with self.assertWarns(DeprecationWarning): + f = weakref.finalize(a, func=fin, arg=1) + self.assertEqual(f.peek(), (a, fin, (), {'arg': 1})) + f() + self.assertEqual(res, [((), {'arg': 1})]) + + res = [] + with self.assertWarns(DeprecationWarning): + f = weakref.finalize(obj=a, func=fin, arg=1) + self.assertEqual(f.peek(), (a, fin, (), {'arg': 1})) + f() + self.assertEqual(res, [((), {'arg': 1})]) + self.assertRaises(TypeError, weakref.finalize, a) self.assertRaises(TypeError, weakref.finalize) diff --git a/Lib/trace.py b/Lib/trace.py index bf43c4a40d91c4..63008a134a8aec 100755 --- a/Lib/trace.py +++ b/Lib/trace.py @@ -451,7 +451,22 @@ def runctx(self, cmd, globals=None, locals=None): sys.settrace(None) threading.settrace(None) - def runfunc(self, func, /, *args, **kw): + def runfunc(*args, **kw): + if len(args) >= 2: + self, func, *args = args + elif not args: + raise TypeError("descriptor 'runfunc' of 'Trace' object " + "needs an argument") + elif 'func' in kw: + func = kw.pop('func') + self, *args = args + import warnings + warnings.warn("Passing 'func' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError('runfunc expected at least 1 positional argument, ' + 'got %d' % (len(args)-1)) + result = None if not self.donothing: sys.settrace(self.globaltrace) @@ -461,6 +476,7 @@ def runfunc(self, func, /, *args, **kw): 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 8afb84513590f4..cfcc250a58848a 100644 --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -463,19 +463,47 @@ def addTypeEqualityFunc(self, typeobj, function): """ self._type_equality_funcs[typeobj] = function - def addCleanup(self, function, /, *args, **kwargs): + def addCleanup(*args, **kwargs): """Add a function, with arguments, to be called when the test is completed. Functions added are called on a LIFO basis and are called after tearDown on test failure or success. Cleanup items are called even if setUp fails (unlike tearDown).""" + if len(args) >= 2: + self, function, *args = args + elif not args: + raise TypeError("descriptor 'addCleanup' of 'TestCase' object " + "needs an argument") + elif 'function' in kwargs: + function = kwargs.pop('function') + self, *args = args + import warnings + warnings.warn("Passing 'function' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError('addCleanup expected at least 1 positional ' + 'argument, got %d' % (len(args)-1)) + args = tuple(args) + self._cleanups.append((function, args, kwargs)) + addCleanup.__text_signature__ = '($self, function, /, *args, **kwargs)' - @classmethod - def addClassCleanup(cls, function, /, *args, **kwargs): + def addClassCleanup(*args, **kwargs): """Same as addCleanup, except the cleanup items are called even if setUpClass fails (unlike tearDownClass).""" + if len(args) >= 2: + cls, function, *args = args + elif not args: + raise TypeError("descriptor 'addClassCleanup' of 'TestCase' object " + "needs an argument") + else: + raise TypeError('addClassCleanup expected at least 1 positional ' + 'argument, got %d' % (len(args)-1)) + 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/unittest/test/test_runner.py b/Lib/unittest/test/test_runner.py index dd9a1b6d9aeddf..7d36340741f463 100644 --- a/Lib/unittest/test/test_runner.py +++ b/Lib/unittest/test/test_runner.py @@ -592,7 +592,7 @@ def cleanup(*args, **kwargs): class TestableTest(unittest.TestCase): def setUp(self2): self2.addCleanup(cleanup, 1, 2, function=3, self=4) - with self.assertRaises(TypeError): + with self.assertWarns(DeprecationWarning): self2.addCleanup(function=cleanup, arg='hello') def testNothing(self): pass @@ -603,7 +603,8 @@ def testNothing(self): unittest.TestCase.addCleanup(self=TestableTest(), function=cleanup) runTests(TestableTest) self.assertEqual(cleanups, - [((1, 2), {'function': 3, 'self': 4})]) + [((), {'arg': 'hello'}), + ((1, 2), {'function': 3, 'self': 4})]) def test_with_errors_in_addClassCleanup(self): ordering = [] diff --git a/Lib/weakref.py b/Lib/weakref.py index fa7559bb3dbf86..8d71af653b7ec4 100644 --- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -514,7 +514,33 @@ class finalize: class _Info: __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index") - def __init__(self, obj, func, /, *args, **kwargs): + def __init__(*args, **kwargs): + if len(args) >= 3: + self, obj, func, *args = args + elif not args: + raise TypeError("descriptor '__init__' of 'finalize' object " + "needs an argument") + else: + if 'func' not in kwargs: + raise TypeError('finalize expected at least 2 positional ' + 'arguments, got %d' % (len(args)-1)) + func = kwargs.pop('func') + if len(args) >= 2: + self, obj, *args = args + import warnings + warnings.warn("Passing 'func' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + if 'obj' not in kwargs: + raise TypeError('finalize expected at least 2 positional ' + 'arguments, got %d' % (len(args)-1)) + obj = kwargs.pop('obj') + self, *args = args + import warnings + warnings.warn("Passing 'obj' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + args = tuple(args) + if not self._registered_with_atexit: # We may register the exit function more than once because # of a thread race, but that is harmless @@ -530,6 +556,7 @@ def __init__(self, obj, func, /, *args, **kwargs): 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); From c504dc95a63fe4ac7845a80715ed7e02612f46bb Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 1 Jun 2019 09:31:23 +0300 Subject: [PATCH 6/9] Update addClassCleanup and some mock methods. --- Lib/unittest/case.py | 15 ++------------- Lib/unittest/mock.py | 42 +++++++++++++++++++----------------------- 2 files changed, 21 insertions(+), 36 deletions(-) diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py index cfcc250a58848a..b363c635100726 100644 --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -488,22 +488,11 @@ def addCleanup(*args, **kwargs): self._cleanups.append((function, args, kwargs)) addCleanup.__text_signature__ = '($self, function, /, *args, **kwargs)' - def addClassCleanup(*args, **kwargs): + @classmethod + def addClassCleanup(cls, function, /, *args, **kwargs): """Same as addCleanup, except the cleanup items are called even if setUpClass fails (unlike tearDownClass).""" - if len(args) >= 2: - cls, function, *args = args - elif not args: - raise TypeError("descriptor 'addClassCleanup' of 'TestCase' object " - "needs an argument") - else: - raise TypeError('addClassCleanup expected at least 1 positional ' - 'argument, got %d' % (len(args)-1)) - 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/unittest/mock.py b/Lib/unittest/mock.py index 4258dfcb7b1f59..83dc936740bee7 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -243,7 +243,7 @@ def _setup_async_mock(mock): # Mock is not configured yet so the attributes are set # to a function and then the corresponding mock helper function # is called when the helper is accessed similar to _setup_func. - def wrapper(attr, *args, **kwargs): + def wrapper(attr, /, *args, **kwargs): return getattr(mock.mock, attr)(*args, **kwargs) for attribute in ('assert_awaited', @@ -387,7 +387,7 @@ def __next__(self): class Base(object): _mock_return_value = DEFAULT _mock_side_effect = None - def __init__(self, *args, **kwargs): + def __init__(self, /, *args, **kwargs): pass @@ -395,7 +395,7 @@ def __init__(self, *args, **kwargs): class NonCallableMock(Base): """A non-callable version of `Mock`""" - def __new__(cls, *args, **kw): + def __new__(cls, /, *args, **kw): # every instance has its own class # so we can create magic methods on the # class without stomping on other mocks @@ -602,7 +602,7 @@ def reset_mock(self, visited=None,*, return_value=False, side_effect=False): ret.reset_mock(visited) - def configure_mock(self, **kwargs): + def configure_mock(self, /, **kwargs): """Set attributes on the mock through keyword arguments. Attributes plus return values and side effects can be set on child @@ -919,7 +919,7 @@ def assert_has_calls(self, calls, any_order=False): ) from cause - def assert_any_call(self, *args, **kwargs): + def assert_any_call(self, /, *args, **kwargs): """assert the mock has been called with the specified arguments. The assert passes if the mock has *ever* been called, unlike @@ -935,7 +935,7 @@ def assert_any_call(self, *args, **kwargs): ) from cause - def _get_child_mock(self, **kw): + def _get_child_mock(self, /, **kw): """Create the child mocks for attributes and return value. By default child mocks will be the same type as the parent. Subclasses of Mock may want to override this to customize the way @@ -1011,7 +1011,7 @@ def __init__(self, spec=None, side_effect=None, return_value=DEFAULT, self.side_effect = side_effect - def _mock_check_sig(self, *args, **kwargs): + def _mock_check_sig(self, /, *args, **kwargs): # stub method that can be replaced with one with a specific signature pass @@ -1948,7 +1948,7 @@ def _set_return_value(mock, method, name): class MagicMixin(object): - def __init__(self, *args, **kw): + def __init__(self, /, *args, **kw): self._mock_set_magics() # make magic work for kwargs in init _safe_super(MagicMixin, self).__init__(*args, **kw) self._mock_set_magics() # fix magic broken by upper level init @@ -1990,7 +1990,7 @@ def mock_add_spec(self, spec, spec_set=False): class AsyncMagicMixin: - def __init__(self, *args, **kw): + def __init__(self, /, *args, **kw): self._mock_set_async_magics() # make magic work for kwargs in init _safe_super(AsyncMagicMixin, self).__init__(*args, **kw) self._mock_set_async_magics() # fix magic broken by upper level init @@ -2061,7 +2061,7 @@ class AsyncMockMixin(Base): await_args = _delegating_property('await_args') await_args_list = _delegating_property('await_args_list') - def __init__(self, *args, **kwargs): + def __init__(self, /, *args, **kwargs): super().__init__(*args, **kwargs) # asyncio.iscoroutinefunction() checks _is_coroutine property to say if an # object is a coroutine. Without this check it looks to see if it is a @@ -2078,8 +2078,7 @@ def __init__(self, *args, **kwargs): code_mock.co_flags = inspect.CO_COROUTINE self.__dict__['__code__'] = code_mock - async def _mock_call(_mock_self, *args, **kwargs): - self = _mock_self + async def _mock_call(self, /, *args, **kwargs): try: result = super()._mock_call(*args, **kwargs) except (BaseException, StopIteration) as e: @@ -2123,11 +2122,10 @@ def assert_awaited_once(_mock_self): f" Awaited {self.await_count} times.") raise AssertionError(msg) - def assert_awaited_with(_mock_self, *args, **kwargs): + def assert_awaited_with(self, /, *args, **kwargs): """ Assert that the last await was with the specified arguments. """ - self = _mock_self if self.await_args is None: expected = self._format_mock_call_signature(args, kwargs) raise AssertionError(f'Expected await: {expected}\nNot awaited') @@ -2142,23 +2140,21 @@ def _error_message(): cause = expected if isinstance(expected, Exception) else None raise AssertionError(_error_message()) from cause - def assert_awaited_once_with(_mock_self, *args, **kwargs): + def assert_awaited_once_with(self, /, *args, **kwargs): """ Assert that the mock was awaited exactly once and with the specified arguments. """ - self = _mock_self if not self.await_count == 1: msg = (f"Expected {self._mock_name or 'mock'} to have been awaited once." f" Awaited {self.await_count} times.") raise AssertionError(msg) return self.assert_awaited_with(*args, **kwargs) - def assert_any_await(_mock_self, *args, **kwargs): + def assert_any_await(self, /, *args, **kwargs): """ Assert the mock has ever been awaited with the specified arguments. """ - self = _mock_self expected = self._call_matcher((args, kwargs)) actual = [self._call_matcher(c) for c in self.await_args_list] if expected not in actual: @@ -2215,7 +2211,7 @@ def assert_not_awaited(_mock_self): f" Awaited {self.await_count} times.") raise AssertionError(msg) - def reset_mock(self, *args, **kwargs): + def reset_mock(self, /, *args, **kwargs): """ See :func:`.Mock.reset_mock()` """ @@ -2418,7 +2414,7 @@ def __eq__(self, other): __ne__ = object.__ne__ - def __call__(self, *args, **kwargs): + def __call__(self, /, *args, **kwargs): if self._mock_name is None: return _Call(('', args, kwargs), name='()') @@ -2433,10 +2429,10 @@ def __getattr__(self, attr): return _Call(name=name, parent=self, from_kall=False) - def count(self, *args, **kwargs): + def count(self, /, *args, **kwargs): return self.__getattr__('count')(*args, **kwargs) - def index(self, *args, **kwargs): + def index(self, /, *args, **kwargs): return self.__getattr__('index')(*args, **kwargs) def _get_call_arguments(self): @@ -2772,7 +2768,7 @@ class PropertyMock(Mock): Fetching a `PropertyMock` instance from an object calls the mock, with no args. Setting it calls the mock with the value being set. """ - def _get_child_mock(self, **kwargs): + def _get_child_mock(self, /, **kwargs): return MagicMock(**kwargs) def __get__(self, obj, obj_type): From 6b6975739ccb31d7b300615f421fb72942540080 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 1 Jun 2019 10:09:12 +0300 Subject: [PATCH 7/9] Get rid of _mock_self. --- Lib/unittest/mock.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 83dc936740bee7..c2802726d75d9c 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -2103,20 +2103,18 @@ async def proxy(): return await proxy() - def assert_awaited(_mock_self): + def assert_awaited(self): """ Assert that the mock was awaited at least once. """ - self = _mock_self if self.await_count == 0: msg = f"Expected {self._mock_name or 'mock'} to have been awaited." raise AssertionError(msg) - def assert_awaited_once(_mock_self): + def assert_awaited_once(self): """ Assert that the mock was awaited exactly once. """ - self = _mock_self if not self.await_count == 1: msg = (f"Expected {self._mock_name or 'mock'} to have been awaited once." f" Awaited {self.await_count} times.") @@ -2164,7 +2162,7 @@ def assert_any_await(self, /, *args, **kwargs): '%s await not found' % expected_string ) from cause - def assert_has_awaits(_mock_self, calls, any_order=False): + def assert_has_awaits(self, calls, any_order=False): """ Assert the mock has been awaited with the specified calls. The :attr:`await_args_list` list is checked for the awaits. @@ -2176,7 +2174,6 @@ def assert_has_awaits(_mock_self, calls, any_order=False): If `any_order` is True then the awaits can be in any order, but they must all appear in :attr:`await_args_list`. """ - self = _mock_self expected = [self._call_matcher(c) for c in calls] cause = expected if isinstance(expected, Exception) else None all_awaits = _CallList(self._call_matcher(c) for c in self.await_args_list) @@ -2201,11 +2198,10 @@ def assert_has_awaits(_mock_self, calls, any_order=False): '%r not all found in await list' % (tuple(not_found),) ) from cause - def assert_not_awaited(_mock_self): + def assert_not_awaited(self): """ Assert that the mock was never awaited. """ - self = _mock_self if self.await_count != 0: msg = (f"Expected {self._mock_name or 'mock'} to not have been awaited." f" Awaited {self.await_count} times.") From 105c2642a82436640aeb926dd362e3667ad780de Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 1 Jun 2019 10:13:46 +0300 Subject: [PATCH 8/9] Remove a note about deprecation from What's New. --- Doc/whatsnew/3.8.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 98f0c3474f26ed..cc8f2de04449e5 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -941,8 +941,7 @@ Deprecated :meth:`profile.Profile.runcall`, :meth:`cProfile.Profile.runcall`, :meth:`bdb.Bdb.runcall`, :meth:`trace.Trace.runfunc` and :func:`curses.wrapper`. - - *function* in :func:`unittest.addModuleCleanup` and - :meth:`unittest.TestCase.addCleanup`. + - *function* in :meth:`unittest.TestCase.addCleanup`. - *fn* in the :meth:`~concurrent.futures.Executor.submit` method of :class:`concurrent.futures.ThreadPoolExecutor` and :class:`concurrent.futures.ProcessPoolExecutor`. From aa4bdaed138f36a268cc2ec1997438490b7bff69 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 1 Jun 2019 10:38:13 +0300 Subject: [PATCH 9/9] Update the documentation. --- Doc/library/collections.rst | 2 +- Doc/library/contextlib.rst | 2 +- Doc/library/email.headerregistry.rst | 2 +- Doc/library/functools.rst | 4 ++-- Doc/library/inspect.rst | 2 +- Doc/library/operator.rst | 4 ++-- Doc/library/string.rst | 6 +++--- Doc/library/types.rst | 2 +- Doc/library/unittest.mock-examples.rst | 4 ++-- Doc/library/unittest.rst | 4 ++-- Doc/library/weakref.rst | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index ec921d79d0c48b..90a3f4bea9a45b 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -1140,7 +1140,7 @@ variants of :func:`functools.lru_cache`:: class LRU(OrderedDict): 'Limit size, evicting the least recently looked-up key when full' - def __init__(self, maxsize=128, *args, **kwds): + def __init__(self, maxsize=128, /, *args, **kwds): self.maxsize = maxsize super().__init__(*args, **kwds) diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst index 017a87a5648c39..73b24e5f251a94 100644 --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -637,7 +637,7 @@ even further by means of a small helper class:: from contextlib import ExitStack class Callback(ExitStack): - def __init__(self, callback, *args, **kwds): + def __init__(self, callback, /, *args, **kwds): super(Callback, self).__init__() self.callback(callback, *args, **kwds) diff --git a/Doc/library/email.headerregistry.rst b/Doc/library/email.headerregistry.rst index ce283c6b596cf2..c3ce90c2d6d952 100644 --- a/Doc/library/email.headerregistry.rst +++ b/Doc/library/email.headerregistry.rst @@ -107,7 +107,7 @@ headers. method if it wishes to set additional attributes beyond those provided by ``BaseHeader`` itself. Such an ``init`` method should look like this:: - def init(self, *args, **kw): + def init(self, /, *args, **kw): self._myattr = kw.pop('myattr') super().init(*args, **kw) diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index 8b8b1f80a622e7..654a3efa214b05 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -221,7 +221,7 @@ The :mod:`functools` module defines the following functions: Returning NotImplemented from the underlying comparison function for unrecognised types is now supported. -.. function:: partial(func, *args, **keywords) +.. function:: partial(func, /, *args, **keywords) Return a new :ref:`partial object` which when called will behave like *func* called with the positional arguments *args* @@ -230,7 +230,7 @@ The :mod:`functools` module defines the following functions: supplied, they extend and override *keywords*. Roughly equivalent to:: - def partial(func, *args, **keywords): + def partial(func, /, *args, **keywords): def newfunc(*fargs, **fkeywords): newkeywords = {**keywords, **fkeywords} return func(*args, *fargs, **newkeywords) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 1cc503a8e94b6d..2a71201a80b2cb 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -1022,7 +1022,7 @@ Classes and functions metatype is in use, cls will be the first element of the tuple. -.. function:: getcallargs(func, *args, **kwds) +.. function:: getcallargs(func, /, *args, **kwds) Bind the *args* and *kwds* to the argument names of the Python function or method *func*, as if it was called with them. For bound methods, bind also the diff --git a/Doc/library/operator.rst b/Doc/library/operator.rst index 5d0ea7dfdd8928..fa02bde84650e1 100644 --- a/Doc/library/operator.rst +++ b/Doc/library/operator.rst @@ -339,7 +339,7 @@ expect a function argument. [('orange', 1), ('banana', 2), ('apple', 3), ('pear', 5)] -.. function:: methodcaller(name[, args...]) +.. function:: methodcaller(name, /, *args, **kwargs) Return a callable object that calls the method *name* on its operand. If additional arguments and/or keyword arguments are given, they will be given @@ -352,7 +352,7 @@ expect a function argument. Equivalent to:: - def methodcaller(name, *args, **kwargs): + def methodcaller(name, /, *args, **kwargs): def caller(obj): return getattr(obj, name)(*args, **kwargs) return caller diff --git a/Doc/library/string.rst b/Doc/library/string.rst index c2f65224bc8daf..288dde6b3fe4c0 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -88,7 +88,7 @@ implementation as the built-in :meth:`~str.format` method. The :class:`Formatter` class has the following public methods: - .. method:: format(format_string, *args, **kwargs) + .. method:: format(format_string, /, *args, **kwargs) The primary API method. It takes a format string and an arbitrary set of positional and keyword arguments. @@ -720,7 +720,7 @@ these rules. The methods of :class:`Template` are: The constructor takes a single argument which is the template string. - .. method:: substitute(mapping, **kwds) + .. method:: substitute(mapping={}, /, **kwds) Performs the template substitution, returning a new string. *mapping* is any dictionary-like object with keys that match the placeholders in the @@ -729,7 +729,7 @@ these rules. The methods of :class:`Template` are: and there are duplicates, the placeholders from *kwds* take precedence. - .. method:: safe_substitute(mapping, **kwds) + .. method:: safe_substitute(mapping={}, /, **kwds) Like :meth:`substitute`, except that if placeholders are missing from *mapping* and *kwds*, instead of raising a :exc:`KeyError` exception, the diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 07c3a2e7f68276..e629c2935f27f4 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -327,7 +327,7 @@ Additional Utility Classes and Functions The type is roughly equivalent to the following code:: class SimpleNamespace: - def __init__(self, **kwargs): + def __init__(self, /, **kwargs): self.__dict__.update(kwargs) def __repr__(self): diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst index 16690f349822ec..811f0fb1ce9397 100644 --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -848,7 +848,7 @@ Here's an example implementation: >>> from copy import deepcopy >>> class CopyingMock(MagicMock): - ... def __call__(self, *args, **kwargs): + ... def __call__(self, /, *args, **kwargs): ... args = deepcopy(args) ... kwargs = deepcopy(kwargs) ... return super(CopyingMock, self).__call__(*args, **kwargs) @@ -1042,7 +1042,7 @@ that it takes arbitrary keyword arguments (``**kwargs``) which are then passed onto the mock constructor: >>> class Subclass(MagicMock): - ... def _get_child_mock(self, **kwargs): + ... def _get_child_mock(self, /, **kwargs): ... return MagicMock(**kwargs) ... >>> mymock = Subclass() diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 8ad2abd3d89a44..41a56c50bee820 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1448,7 +1448,7 @@ Test cases .. versionadded:: 3.1 - .. classmethod:: addClassCleanup(function, *args, **kwargs) + .. classmethod:: addClassCleanup(function, /, *args, **kwargs) Add a function to be called after :meth:`tearDownClass` to cleanup resources used during the test class. Functions will be called in reverse @@ -2305,7 +2305,7 @@ To add cleanup code that must be run even in the case of an exception, use ``addModuleCleanup``: -.. function:: addModuleCleanup(function, *args, **kwargs) +.. function:: addModuleCleanup(function, /, *args, **kwargs) Add a function to be called after :func:`tearDownModule` to cleanup resources used during the test class. Functions will be called in reverse diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst index 80a908bbd83b0a..a28d71060f3836 100644 --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -396,7 +396,7 @@ the referent is accessed:: import weakref class ExtendedRef(weakref.ref): - def __init__(self, ob, callback=None, **annotations): + def __init__(self, ob, callback=None, /, **annotations): super(ExtendedRef, self).__init__(ob, callback) self.__counter = 0 for k, v in annotations.items():