From 1abf8565decfb438e958d83f51e359630e06d451 Mon Sep 17 00:00:00 2001 From: Corenthin ZOZOR Date: Thu, 19 Jun 2025 16:00:21 +0200 Subject: [PATCH 01/12] Create tests (cherry picked from commit 608b51fd6321ac07133b8d66a14e15a906e21169) --- lib/matplotlib/tests/test_pyplot.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_pyplot.py b/lib/matplotlib/tests/test_pyplot.py index ab713707bace..193635973733 100644 --- a/lib/matplotlib/tests/test_pyplot.py +++ b/lib/matplotlib/tests/test_pyplot.py @@ -1,4 +1,5 @@ import difflib +import inspect import numpy as np import sys @@ -449,7 +450,6 @@ def figure_hook_example(figure): def test_figure_hook(): - test_rc = { 'figure.hooks': ['matplotlib.tests.test_pyplot:figure_hook_example'] } @@ -484,3 +484,24 @@ def test_matshow(): # Smoke test that matshow does not ask for a new figsize on the existing figure plt.matshow(arr, fignum=fig.number) + + +def assert_signatures_identical(plt_meth, original_meth, remove_self_param=False): + plt_params = inspect.signature(plt_meth).parameters + original_params = inspect.signature(original_meth).parameters + if remove_self_param: + if next(iter(original_params)) not in ["self"]: + raise AssertionError(f"{original_params} is not an instance method") + + original_params = dict(original_params) + del original_params["self"] + + assert plt_params == original_params + + +def test_setloglevel_signature(): + assert_signatures_identical(plt.set_loglevel, mpl.set_loglevel) + + +def test_polar_signature(): + assert_signatures_identical(plt.polar, plt.Axes.plot, True) From 054077fccbebf4bcc99918fec6dce024d862b5c3 Mon Sep 17 00:00:00 2001 From: Corenthin ZOZOR Date: Fri, 20 Jun 2025 19:36:15 +0200 Subject: [PATCH 02/12] Update test_pyplot.py to include type on signature (cherry picked from commit 4ea0ff8e50f3a2460d18694aa1d58e7757c8726a) --- lib/matplotlib/tests/test_pyplot.py | 55 ++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/tests/test_pyplot.py b/lib/matplotlib/tests/test_pyplot.py index 193635973733..8bfc1951f4bb 100644 --- a/lib/matplotlib/tests/test_pyplot.py +++ b/lib/matplotlib/tests/test_pyplot.py @@ -1,3 +1,4 @@ +import ast import difflib import inspect @@ -487,16 +488,60 @@ def test_matshow(): def assert_signatures_identical(plt_meth, original_meth, remove_self_param=False): - plt_params = inspect.signature(plt_meth).parameters - original_params = inspect.signature(original_meth).parameters + def get_src(meth): + meth_src = Path(inspect.getfile(meth)) + meth_stub = meth_src.with_suffix(".pyi") + return meth_stub if meth_stub.exists() else meth_src + + def tree_loop(tree, name, class_): + for item in tree.body: + if class_ and isinstance(item, ast.ClassDef) and item.name == class_: + return tree_loop(item, name, None) + + if isinstance(item, ast.FunctionDef) and item.name == name: + return item + + raise ValueError(f"Cannot find {class_}.{name} in ast") + + def get_signature(meth): + qualname = meth.__qualname__ + class_ = None if "." not in qualname else qualname.split(".")[-2] + path = get_src(meth) + tree = ast.parse(path.read_text()) + node = tree_loop(tree, meth.__name__, class_) + + params = dict(inspect.signature(meth).parameters) + args = node.args + for param in (*args.posonlyargs, *args.args, args.vararg, *args.kwonlyargs, args.kwarg): + if param is None: + continue + if param.annotation is None: + continue + annotation = ast.unparse(param.annotation) + params[param.arg] = params[param.arg].replace(annotation=annotation) + + if node.returns is not None: + return inspect.Signature( + params.values(), + return_annotation=ast.unparse(node.returns) + ) + else: + return inspect.Signature(params.values()) + + plt_sig = get_signature(plt_meth) + original_sig = get_signature(original_meth) + + assert plt_sig.return_annotation == original_sig.return_annotation + + original_params = original_sig.parameters if remove_self_param: if next(iter(original_params)) not in ["self"]: - raise AssertionError(f"{original_params} is not an instance method") + raise ValueError(f"{original_sig} is not an instance method") - original_params = dict(original_params) + original_params = original_params.copy() del original_params["self"] - assert plt_params == original_params + assert plt_sig.parameters == original_params def test_setloglevel_signature(): From 9011d53c33ef855d399167ee90b2da0b3d95c1ef Mon Sep 17 00:00:00 2001 From: Corenthin ZOZOR Date: Thu, 19 Jun 2025 16:09:35 +0200 Subject: [PATCH 03/12] Update polar and set_loglevel signature on pyplot.py (cherry picked from commit 41b701b41858cb2868485ca9f5747db4cd1f6d4a) --- lib/matplotlib/pyplot.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index cf5c9b4b739f..3df35566361c 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -338,8 +338,8 @@ def uninstall_repl_displayhook() -> None: # Ensure this appears in the pyplot docs. @_copy_docstring_and_deprecators(matplotlib.set_loglevel) -def set_loglevel(*args, **kwargs) -> None: - return matplotlib.set_loglevel(*args, **kwargs) +def set_loglevel(level) -> None: + return matplotlib.set_loglevel(level) @_copy_docstring_and_deprecators(Artist.findobj) @@ -2690,7 +2690,13 @@ def matshow(A: ArrayLike, fignum: None | int = None, **kwargs) -> AxesImage: return im -def polar(*args, **kwargs) -> list[Line2D]: +def polar( + *args, + scalex=True, + scaley=True, + data=None, + **kwargs +) -> list[Line2D]: """ Make a polar plot. From 6ef70ac421310ad2628150bb831c9c426189551c Mon Sep 17 00:00:00 2001 From: Corenthin ZOZOR Date: Thu, 19 Jun 2025 16:21:59 +0200 Subject: [PATCH 04/12] Update savefig signature on pyplot.py (cherry picked from commit b863ba298abe37c08c92f1ac1afc41f985d0bbff) --- lib/matplotlib/pyplot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 3df35566361c..01fde9f8f077 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -50,7 +50,7 @@ import sys import threading import time -from typing import TYPE_CHECKING, cast, overload +from typing import IO, TYPE_CHECKING, cast, overload from cycler import cycler # noqa: F401 import matplotlib @@ -1251,11 +1251,11 @@ def draw() -> None: @_copy_docstring_and_deprecators(Figure.savefig) -def savefig(*args, **kwargs) -> None: +def savefig(fname: str | os.PathLike | IO, **kwargs) -> None: fig = gcf() # savefig default implementation has no return, so mypy is unhappy # presumably this is here because subclasses can return? - res = fig.savefig(*args, **kwargs) # type: ignore[func-returns-value] + res = fig.savefig(fname, **kwargs) # type: ignore[func-returns-value] fig.canvas.draw_idle() # Need this if 'transparent=True', to reset colors. return res From 8ee42ff9de44ba03298ab85592c4a04ee5554e96 Mon Sep 17 00:00:00 2001 From: Corenthin ZOZOR Date: Fri, 20 Jun 2025 19:44:25 +0200 Subject: [PATCH 05/12] Add type hint on polar and set_loglevel on pyplot.py. Correct polar content (cherry picked from commit 92dc04501bab539586cac48a3266891c75a4cb7c) --- lib/matplotlib/pyplot.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 01fde9f8f077..f1ce4ff6deb8 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -338,7 +338,7 @@ def uninstall_repl_displayhook() -> None: # Ensure this appears in the pyplot docs. @_copy_docstring_and_deprecators(matplotlib.set_loglevel) -def set_loglevel(level) -> None: +def set_loglevel(level: str) -> None: return matplotlib.set_loglevel(level) @@ -2691,9 +2691,9 @@ def matshow(A: ArrayLike, fignum: None | int = None, **kwargs) -> AxesImage: def polar( - *args, - scalex=True, - scaley=True, + *args: float | ArrayLike | str, + scalex: bool = True, + scaley: bool = True, data=None, **kwargs ) -> list[Line2D]: @@ -2730,7 +2730,13 @@ def polar( ) else: ax = axes(projection="polar") - return ax.plot(*args, **kwargs) + return ax.plot( + *args, + scalex=scalex, + scaley=scaley, + data=data, + **kwargs + ) # If rcParams['backend_fallback'] is true, and an interactive backend is From 2c9a9eda59ee465f79edcb2cb554a943ae348a82 Mon Sep 17 00:00:00 2001 From: Corenthin ZOZOR Date: Fri, 20 Jun 2025 21:12:24 +0200 Subject: [PATCH 06/12] Format with ruff (cherry picked from commit 64e7921b0b3f56c88c1f449a4f2081e862289279) --- lib/matplotlib/tests/test_pyplot.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_pyplot.py b/lib/matplotlib/tests/test_pyplot.py index 8bfc1951f4bb..80b4bfd3f9c3 100644 --- a/lib/matplotlib/tests/test_pyplot.py +++ b/lib/matplotlib/tests/test_pyplot.py @@ -451,6 +451,7 @@ def figure_hook_example(figure): def test_figure_hook(): + test_rc = { 'figure.hooks': ['matplotlib.tests.test_pyplot:figure_hook_example'] } @@ -512,7 +513,14 @@ def get_signature(meth): params = dict(inspect.signature(meth).parameters) args = node.args - for param in (*args.posonlyargs, *args.args, args.vararg, *args.kwonlyargs, args.kwarg): + allargs = ( + *args.posonlyargs, + *args.args, + args.vararg, + *args.kwonlyargs, + args.kwarg + ) + for param in allargs: if param is None: continue if param.annotation is None: From 26e71d7b820fc360fbe23f9cbe4978899291b8b2 Mon Sep 17 00:00:00 2001 From: ZPyrolink <38cz74@gmail.com> Date: Tue, 24 Jun 2025 20:46:46 +0200 Subject: [PATCH 07/12] Revert polar on pyplot.py and remove corresponding test --- lib/matplotlib/pyplot.py | 16 ++-------------- lib/matplotlib/tests/test_pyplot.py | 4 ---- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index f1ce4ff6deb8..8da666499702 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -2690,13 +2690,7 @@ def matshow(A: ArrayLike, fignum: None | int = None, **kwargs) -> AxesImage: return im -def polar( - *args: float | ArrayLike | str, - scalex: bool = True, - scaley: bool = True, - data=None, - **kwargs -) -> list[Line2D]: +def polar(*args, **kwargs) -> list[Line2D]: """ Make a polar plot. @@ -2730,13 +2724,7 @@ def polar( ) else: ax = axes(projection="polar") - return ax.plot( - *args, - scalex=scalex, - scaley=scaley, - data=data, - **kwargs - ) + return ax.plot(*args, **kwargs) # If rcParams['backend_fallback'] is true, and an interactive backend is diff --git a/lib/matplotlib/tests/test_pyplot.py b/lib/matplotlib/tests/test_pyplot.py index 80b4bfd3f9c3..72bfd8f6034f 100644 --- a/lib/matplotlib/tests/test_pyplot.py +++ b/lib/matplotlib/tests/test_pyplot.py @@ -554,7 +554,3 @@ def get_signature(meth): def test_setloglevel_signature(): assert_signatures_identical(plt.set_loglevel, mpl.set_loglevel) - - -def test_polar_signature(): - assert_signatures_identical(plt.polar, plt.Axes.plot, True) From 53cc026d463591f624a3dc779f8f83676880d69f Mon Sep 17 00:00:00 2001 From: ZPyrolink <73246085+ZPyrolink@users.noreply.github.com> Date: Thu, 26 Jun 2025 20:19:43 +0200 Subject: [PATCH 08/12] Remove extra work when stub file doesn't exists Co-authored-by: Elliott Sales de Andrade --- lib/matplotlib/tests/test_pyplot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_pyplot.py b/lib/matplotlib/tests/test_pyplot.py index 72bfd8f6034f..a424f017524c 100644 --- a/lib/matplotlib/tests/test_pyplot.py +++ b/lib/matplotlib/tests/test_pyplot.py @@ -536,7 +536,7 @@ def get_signature(meth): else: return inspect.Signature(params.values()) - plt_sig = get_signature(plt_meth) + plt_sig = inspect.signature(plt_meth) original_sig = get_signature(original_meth) assert plt_sig.return_annotation == original_sig.return_annotation From 31d4418dcb867f7682dde1de20407ab68942607c Mon Sep 17 00:00:00 2001 From: ZPyrolink <38cz74@gmail.com> Date: Fri, 27 Jun 2025 15:52:05 +0200 Subject: [PATCH 09/12] Replace assert_signatures_identical (check return_annotation and full parameters) with assert_same_signature (only check len(parameters), names and kinds) --- lib/matplotlib/tests/test_pyplot.py | 76 ++++++----------------------- 1 file changed, 15 insertions(+), 61 deletions(-) diff --git a/lib/matplotlib/tests/test_pyplot.py b/lib/matplotlib/tests/test_pyplot.py index a424f017524c..51b37637791d 100644 --- a/lib/matplotlib/tests/test_pyplot.py +++ b/lib/matplotlib/tests/test_pyplot.py @@ -488,69 +488,23 @@ def test_matshow(): plt.matshow(arr, fignum=fig.number) -def assert_signatures_identical(plt_meth, original_meth, remove_self_param=False): - def get_src(meth): - meth_src = Path(inspect.getfile(meth)) - meth_stub = meth_src.with_suffix(".pyi") - return meth_stub if meth_stub.exists() else meth_src - - def tree_loop(tree, name, class_): - for item in tree.body: - if class_ and isinstance(item, ast.ClassDef) and item.name == class_: - return tree_loop(item, name, None) - - if isinstance(item, ast.FunctionDef) and item.name == name: - return item - - raise ValueError(f"Cannot find {class_}.{name} in ast") - - def get_signature(meth): - qualname = meth.__qualname__ - class_ = None if "." not in qualname else qualname.split(".")[-2] - path = get_src(meth) - tree = ast.parse(path.read_text()) - node = tree_loop(tree, meth.__name__, class_) - - params = dict(inspect.signature(meth).parameters) - args = node.args - allargs = ( - *args.posonlyargs, - *args.args, - args.vararg, - *args.kwonlyargs, - args.kwarg - ) - for param in allargs: - if param is None: - continue - if param.annotation is None: - continue - annotation = ast.unparse(param.annotation) - params[param.arg] = params[param.arg].replace(annotation=annotation) - - if node.returns is not None: - return inspect.Signature( - params.values(), - return_annotation=ast.unparse(node.returns) - ) - else: - return inspect.Signature(params.values()) - - plt_sig = inspect.signature(plt_meth) - original_sig = get_signature(original_meth) - - assert plt_sig.return_annotation == original_sig.return_annotation - - original_params = original_sig.parameters - if remove_self_param: - if next(iter(original_params)) not in ["self"]: - raise ValueError(f"{original_sig} is not an instance method") +def assert_same_signature(meth, original_meth): + """ + Assert that the arguments of plt_meth and original_meth have the same names. - original_params = original_params.copy() - del original_params["self"] + :param meth: The method to check. + :param original_meth: The original method to compare against. + """ + params = inspect.signature(meth).parameters + original_params = inspect.signature(original_meth).parameters - assert plt_sig.parameters == original_params + assert len(params) == len(original_params) + assert all([ + params[p].name == original_params[p].name and + params[p].kind == original_params[p].kind + for p in params + ]) def test_setloglevel_signature(): - assert_signatures_identical(plt.set_loglevel, mpl.set_loglevel) + assert_same_signature(plt.set_loglevel, mpl.set_loglevel) From cbc8d602f48792d4b3e056ff4882aec5b1cd0077 Mon Sep 17 00:00:00 2001 From: ZPyrolink <38cz74@gmail.com> Date: Fri, 27 Jun 2025 15:58:43 +0200 Subject: [PATCH 10/12] Remove unused import --- lib/matplotlib/tests/test_pyplot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/matplotlib/tests/test_pyplot.py b/lib/matplotlib/tests/test_pyplot.py index 51b37637791d..75f29153eb24 100644 --- a/lib/matplotlib/tests/test_pyplot.py +++ b/lib/matplotlib/tests/test_pyplot.py @@ -1,4 +1,3 @@ -import ast import difflib import inspect From 083d25db42cd1771a5176a1a77e3e3d21a458471 Mon Sep 17 00:00:00 2001 From: ZPyrolink <73246085+ZPyrolink@users.noreply.github.com> Date: Fri, 27 Jun 2025 21:21:36 +0200 Subject: [PATCH 11/12] Renaming assert_signature arguments --- lib/matplotlib/tests/test_pyplot.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/tests/test_pyplot.py b/lib/matplotlib/tests/test_pyplot.py index 75f29153eb24..18e8528fce32 100644 --- a/lib/matplotlib/tests/test_pyplot.py +++ b/lib/matplotlib/tests/test_pyplot.py @@ -487,20 +487,20 @@ def test_matshow(): plt.matshow(arr, fignum=fig.number) -def assert_same_signature(meth, original_meth): +def assert_same_signature(func1, func2): """ - Assert that the arguments of plt_meth and original_meth have the same names. + Assert that `func1` and `func2` have the same arguments, i.e. same parameter count, names and kinds. - :param meth: The method to check. - :param original_meth: The original method to compare against. + :param func1: First function to check + :param func2: Second function to check """ - params = inspect.signature(meth).parameters - original_params = inspect.signature(original_meth).parameters + params1 = inspect.signature(func1).parameters + params2 = inspect.signature(func2).parameters - assert len(params) == len(original_params) + assert len(params1) == len(params2) assert all([ - params[p].name == original_params[p].name and - params[p].kind == original_params[p].kind + params1[p].name == params2[p].name and + params1[p].kind == params2[p].kind for p in params ]) From 9d40b99a79040902d094feb0f1cc13a5c8827a6e Mon Sep 17 00:00:00 2001 From: ZPyrolink <38cz74@gmail.com> Date: Sat, 28 Jun 2025 00:10:20 +0200 Subject: [PATCH 12/12] Correct typo and ruff error --- lib/matplotlib/tests/test_pyplot.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/tests/test_pyplot.py b/lib/matplotlib/tests/test_pyplot.py index 18e8528fce32..55f7c33cb52e 100644 --- a/lib/matplotlib/tests/test_pyplot.py +++ b/lib/matplotlib/tests/test_pyplot.py @@ -489,7 +489,8 @@ def test_matshow(): def assert_same_signature(func1, func2): """ - Assert that `func1` and `func2` have the same arguments, i.e. same parameter count, names and kinds. + Assert that `func1` and `func2` have the same arguments, + i.e. same parameter count, names and kinds. :param func1: First function to check :param func2: Second function to check @@ -501,7 +502,7 @@ def assert_same_signature(func1, func2): assert all([ params1[p].name == params2[p].name and params1[p].kind == params2[p].kind - for p in params + for p in params1 ]) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy