Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9c76bd5

Browse files
committed
Add a make-parameter-positional-only-with-deprecation decorator.
... and use it to make the `block` argument of plt.show() keyword only (with deprecation), with the idea of making the future signature `plt.show(figures=None, *, block=True)`.
1 parent 1a89250 commit 9c76bd5

File tree

7 files changed

+82
-5
lines changed

7 files changed

+82
-5
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
API changes
2+
```````````
3+
4+
Passing the ``block`` argument of ``plt.show`` positionally is deprecated; it
5+
should be passed by keyword.
6+
7+
When using the nbagg backend, ``plt.show`` used to silently accept and ignore
8+
all combinations of positional and keyword arguments. This behavior is
9+
deprecated.

lib/matplotlib/backend_bases.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3216,8 +3216,10 @@ def draw_if_interactive(cls):
32163216
cls.trigger_manager_draw(manager)
32173217

32183218
@classmethod
3219+
@cbook._make_keyword_only("3.1", "block")
32193220
def show(cls, block=None):
3220-
"""Show all figures.
3221+
"""
3222+
Show all figures.
32213223
32223224
`show` blocks by calling `mainloop` if *block* is ``True``, or if it
32233225
is ``None`` and we are neither in IPython's ``%pylab`` mode, nor in

lib/matplotlib/backends/backend_nbagg.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
# Jupyter/IPython 3.x or earlier
1818
from IPython.kernel.comm import Comm
1919

20-
from matplotlib import is_interactive
20+
from matplotlib import cbook, is_interactive
2121
from matplotlib._pylab_helpers import Gcf
2222
from matplotlib.backend_bases import (
2323
_Backend, FigureCanvasBase, NavigationToolbar2)
@@ -242,6 +242,12 @@ def trigger_manager_draw(manager):
242242

243243
@staticmethod
244244
def show(*args, **kwargs):
245+
if args or {*kwargs} - {"block"}:
246+
cbook.warn_deprecated(
247+
"3.1", message="Passing arguments to show(), other than "
248+
"passing 'block' by keyword, is deprecated %(since)s, and "
249+
"support for it will be removed %(removal)s.")
250+
245251
## TODO: something to do when keyword block==False ?
246252
from matplotlib._pylab_helpers import Gcf
247253

lib/matplotlib/backends/backend_template.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def draw_if_interactive():
173173
"""
174174

175175

176-
def show(block=None):
176+
def show(*, block=None):
177177
"""
178178
For image backends - is not required.
179179
For GUI backends - show() is usually the last line of a pyplot script and

lib/matplotlib/cbook/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232

3333
import matplotlib
3434
from .deprecation import (
35-
deprecated, warn_deprecated, _rename_parameter, _delete_parameter,
35+
deprecated, warn_deprecated,
36+
_rename_parameter, _delete_parameter, _make_keyword_only,
3637
_suppress_matplotlib_deprecation_warning,
3738
MatplotlibDeprecationWarning, mplDeprecation)
3839

lib/matplotlib/cbook/deprecation.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,50 @@ def wrapper(*args, **kwargs):
371371
return wrapper
372372

373373

374+
def _make_keyword_only(since, name, func=None):
375+
"""
376+
Decorator indicating that passing parameter *name* (or any of the following
377+
ones) positionally to *func* is being deprecated.
378+
379+
Note that this decorator **cannot** be applied to a function that has a
380+
pyplot-level wrapper, as the wrapper always pass all arguments by keyword.
381+
If it is used, users will see spurious DeprecationWarnings every time they
382+
call the pyplot wrapper.
383+
"""
384+
385+
if func is None:
386+
return functools.partial(_make_keyword_only, since, name)
387+
388+
signature = inspect.signature(func)
389+
POK = inspect.Parameter.POSITIONAL_OR_KEYWORD
390+
KWO = inspect.Parameter.KEYWORD_ONLY
391+
assert (name in signature.parameters
392+
and signature.parameters[name].kind == POK), (
393+
f"Matplotlib internal error: {name!r} must be a positional-or-keyword "
394+
f"parameter for {func.__name__}()")
395+
names = [*signature.parameters]
396+
kwonly = [name for name in names[names.index(name):]
397+
if signature.parameters[name].kind == POK]
398+
func.__signature__ = signature.replace(parameters=[
399+
param.replace(kind=inspect.Parameter.KEYWORD_ONLY)
400+
if param.name in kwonly
401+
else param
402+
for param in signature.parameters.values()])
403+
404+
@functools.wraps(func)
405+
def wrapper(*args, **kwargs):
406+
bound = signature.bind(*args, **kwargs)
407+
if name in bound.arguments and name not in kwargs:
408+
warn_deprecated(
409+
since, message="Passing the %(name)s %(obj_type)s "
410+
"positionally is deprecated since Matplotlib %(since)s; the "
411+
"parameter will become keyword-only %(removal)s.",
412+
name=name, obj_type=f"parameter of {func.__name__}()")
413+
return func(*args, **kwargs)
414+
415+
return wrapper
416+
417+
374418
@contextlib.contextmanager
375419
def _suppress_matplotlib_deprecation_warning():
376420
with warnings.catch_warnings():

lib/matplotlib/tests/test_cbook.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313

1414
import matplotlib.cbook as cbook
1515
import matplotlib.colors as mcolors
16-
from matplotlib.cbook import delete_masked_points as dmp
16+
from matplotlib.cbook import (
17+
MatplotlibDeprecationWarning, delete_masked_points as dmp)
1718

1819

1920
def test_is_hashable():
@@ -545,3 +546,17 @@ def test_safe_first_element_pandas_series(pd):
545546
s = pd.Series(range(5), index=range(10, 15))
546547
actual = cbook.safe_first_element(s)
547548
assert actual == 0
549+
550+
551+
def test_make_keyword_only(recwarn):
552+
@cbook._make_keyword_only("3.0", "arg")
553+
def func(pre, arg, post=None):
554+
pass
555+
556+
func(1, arg=2)
557+
assert len(recwarn) == 0
558+
559+
with pytest.warns(MatplotlibDeprecationWarning):
560+
func(1, 2)
561+
with pytest.warns(MatplotlibDeprecationWarning):
562+
func(1, 2, 3)

0 commit comments

Comments
 (0)