@@ -249,6 +249,14 @@ def __set_name__(self, owner, name):
249249 name = name ))
250250
251251
252+ # Used by _copy_docstring_and_deprecators to redecorate pyplot wrappers and
253+ # boilerplate.py to retrieve original signatures. It may seem natural to store
254+ # this information as an attribute on the wrapper, but if the wrapper gets
255+ # itself functools.wraps()ed, then such attributes are silently propagated to
256+ # the outer wrapper, which is not desired.
257+ DECORATORS = {}
258+
259+
252260def rename_parameter (since , old , new , func = None ):
253261 """
254262 Decorator indicating that parameter *old* of *func* is renamed to *new*.
@@ -268,8 +276,10 @@ def rename_parameter(since, old, new, func=None):
268276 def func(good_name): ...
269277 """
270278
279+ decorator = functools .partial (rename_parameter , since , old , new )
280+
271281 if func is None :
272- return functools . partial ( rename_parameter , since , old , new )
282+ return decorator
273283
274284 signature = inspect .signature (func )
275285 assert old not in signature .parameters , (
@@ -294,6 +304,7 @@ def wrapper(*args, **kwargs):
294304 # would both show up in the pyplot function for an Axes method as well and
295305 # pyplot would explicitly pass both arguments to the Axes method.
296306
307+ DECORATORS [wrapper ] = decorator
297308 return wrapper
298309
299310
@@ -330,8 +341,10 @@ def delete_parameter(since, name, func=None, **kwargs):
330341 def func(used_arg, other_arg, unused, more_args): ...
331342 """
332343
344+ decorator = functools .partial (delete_parameter , since , name , ** kwargs )
345+
333346 if func is None :
334- return functools . partial ( delete_parameter , since , name , ** kwargs )
347+ return decorator
335348
336349 signature = inspect .signature (func )
337350 # Name of `**kwargs` parameter of the decorated function, typically
@@ -399,17 +412,24 @@ def wrapper(*inner_args, **inner_kwargs):
399412 ** kwargs )
400413 return func (* inner_args , ** inner_kwargs )
401414
415+ DECORATORS [wrapper ] = decorator
402416 return wrapper
403417
404418
405419def make_keyword_only (since , name , func = None ):
406420 """
407421 Decorator indicating that passing parameter *name* (or any of the following
408422 ones) positionally to *func* is being deprecated.
423+
424+ When used on a method that has a pyplot wrapper, this should be the
425+ outermost decorator, so that :file:`boilerplate.py` can access the original
426+ signature.
409427 """
410428
429+ decorator = functools .partial (make_keyword_only , since , name )
430+
411431 if func is None :
412- return functools . partial ( make_keyword_only , since , name )
432+ return decorator
413433
414434 signature = inspect .signature (func )
415435 POK = inspect .Parameter .POSITIONAL_OR_KEYWORD
@@ -419,26 +439,28 @@ def make_keyword_only(since, name, func=None):
419439 f"Matplotlib internal error: { name !r} must be a positional-or-keyword "
420440 f"parameter for { func .__name__ } ()" )
421441 names = [* signature .parameters ]
422- kwonly = [name for name in names [names .index (name ):]
442+ name_idx = names .index (name )
443+ kwonly = [name for name in names [name_idx :]
423444 if signature .parameters [name ].kind == POK ]
424- func .__signature__ = signature .replace (parameters = [
425- param .replace (kind = KWO ) if param .name in kwonly else param
426- for param in signature .parameters .values ()])
427445
428446 @functools .wraps (func )
429447 def wrapper (* args , ** kwargs ):
430448 # Don't use signature.bind here, as it would fail when stacked with
431449 # rename_parameter and an "old" argument name is passed in
432450 # (signature.bind would fail, but the actual call would succeed).
433- idx = [* func .__signature__ .parameters ].index (name )
434- if len (args ) > idx :
451+ if len (args ) > name_idx :
435452 warn_deprecated (
436453 since , message = "Passing the %(name)s %(obj_type)s "
437454 "positionally is deprecated since Matplotlib %(since)s; the "
438455 "parameter will become keyword-only %(removal)s." ,
439456 name = name , obj_type = f"parameter of { func .__name__ } ()" )
440457 return func (* args , ** kwargs )
441458
459+ # Don't modify *func*'s signature, as boilerplate.py needs it.
460+ wrapper .__signature__ = signature .replace (parameters = [
461+ param .replace (kind = KWO ) if param .name in kwonly else param
462+ for param in signature .parameters .values ()])
463+ DECORATORS [wrapper ] = decorator
442464 return wrapper
443465
444466
0 commit comments