From 47ae63b00558b21be3d2f8fb63304590880a76d0 Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Tue, 29 Apr 2025 16:36:58 -0300 Subject: [PATCH 01/25] Adding a decorator and Refactoring functions --- lib/matplotlib/scale.py | 65 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 44fbe5209c4d..610ac2222806 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -31,6 +31,8 @@ import inspect import textwrap +import warnings +from functools import wraps import numpy as np @@ -103,6 +105,40 @@ def limit_range_for_scale(self, vmin, vmax, minpos): return vmin, vmax +def handle_axis_parameter(init_func): + """ + Allow scale classes to work with or without the `axis` parameter. + + This decorator enables scale constructors to maintain backward + compatibility with older code that passes `axis`, while allowing + future implementations to omit it entirely. + + If the wrapped constructor defines `axis` as its first argument, + the parameter is preserved. Otherwise, it is safely removed from + positional or keyword arguments. + + Parameters + ---------- + init_func : callable + The original __init__ method of a scale class. + + Returns + ------- + callable + A wrapped version of `init_func` that handles the optional `axis`. + """ + @wraps(init_func) + def wrapper(self, *args, **kwargs): + sig = inspect.signature(init_func) + params = list(sig.parameters.values()) + if params and params[1].name == "axis": + return init_func(self, *args, **kwargs) + if args: + args = args[1:] + kwargs.pop("axis", None) + return init_func(self, *args, **kwargs) + return wrapper + class LinearScale(ScaleBase): """ The default linear scale. @@ -110,7 +146,8 @@ class LinearScale(ScaleBase): name = 'linear' - def __init__(self, axis): + @handle_axis_parameter + def __init__(self, axis=None): # This method is present only to prevent inheritance of the base class' # constructor docstring, which would otherwise end up interpolated into # the docstring of Axis.set_scale. @@ -180,6 +217,7 @@ class FuncScale(ScaleBase): name = 'function' + @handle_axis_parameter def __init__(self, axis, functions): """ Parameters @@ -279,7 +317,8 @@ class LogScale(ScaleBase): """ name = 'log' - def __init__(self, axis, *, base=10, subs=None, nonpositive="clip"): + @handle_axis_parameter + def __init__(self, axis=None, *, base=10, subs=None, nonpositive="clip"): """ Parameters ---------- @@ -330,6 +369,7 @@ class FuncScaleLog(LogScale): name = 'functionlog' + @handle_axis_parameter def __init__(self, axis, functions, base=10): """ Parameters @@ -455,7 +495,8 @@ class SymmetricalLogScale(ScaleBase): """ name = 'symlog' - def __init__(self, axis, *, base=10, linthresh=2, subs=None, linscale=1): + @handle_axis_parameter + def __init__(self, axis=None, *, base=10, linthresh=2, subs=None, linscale=1): self._transform = SymmetricalLogTransform(base, linthresh, linscale) self.subs = subs @@ -547,6 +588,7 @@ class AsinhScale(ScaleBase): 1024: (256, 512) } + @handle_axis_parameter def __init__(self, axis, *, linear_width=1.0, base=10, subs='auto', **kwargs): """ @@ -645,7 +687,8 @@ class LogitScale(ScaleBase): """ name = 'logit' - def __init__(self, axis, nonpositive='mask', *, + @handle_axis_parameter + def __init__(self, axis=None, nonpositive='mask', *, one_half=r"\frac{1}{2}", use_overline=False): r""" Parameters @@ -725,7 +768,12 @@ def scale_factory(scale, axis, **kwargs): axis : `~matplotlib.axis.Axis` """ scale_cls = _api.check_getitem(_scale_mapping, scale=scale) - return scale_cls(axis, **kwargs) + try: + return scale_cls(axis, **kwargs) + except TypeError as e: + if 'unexpected keyword argument' in str(e) or 'positional argument' in str(e): + return scale_cls(**kwargs) + raise if scale_factory.__doc__: @@ -742,6 +790,13 @@ def register_scale(scale_class): scale_class : subclass of `ScaleBase` The scale to register. """ + sig = inspect.signature(scale_class.__init__) + if 'axis' in sig.parameters: + warnings.warn( + f"The scale class {scale_class.__name__} still uses the 'axis' parameter in its constructor. " + "Consider refactoring it to remove this dependency.", + DeprecationWarning + ) _scale_mapping[scale_class.name] = scale_class From 5c5ddd26923e37474c9cee0b5b634a888c66e637 Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Tue, 13 May 2025 15:16:10 -0300 Subject: [PATCH 02/25] Fixing Ruff Errors --- lib/matplotlib/scale.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 610ac2222806..5ff6a8144081 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -139,6 +139,7 @@ def wrapper(self, *args, **kwargs): return init_func(self, *args, **kwargs) return wrapper + class LinearScale(ScaleBase): """ The default linear scale. @@ -317,7 +318,7 @@ class LogScale(ScaleBase): """ name = 'log' - @handle_axis_parameter + @handle_axis_parameter def __init__(self, axis=None, *, base=10, subs=None, nonpositive="clip"): """ Parameters @@ -793,8 +794,9 @@ def register_scale(scale_class): sig = inspect.signature(scale_class.__init__) if 'axis' in sig.parameters: warnings.warn( - f"The scale class {scale_class.__name__} still uses the 'axis' parameter in its constructor. " - "Consider refactoring it to remove this dependency.", + f"The scale class {scale_class.__name__} still uses the 'axis' " + "parameter in its constructor. Consider refactoring it to remove " + "this dependency.", DeprecationWarning ) _scale_mapping[scale_class.name] = scale_class From b770f6d37c22e7a1bbead56746e3a6dfb2b293e3 Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Tue, 13 May 2025 15:26:12 -0300 Subject: [PATCH 03/25] Update scale.pyi --- lib/matplotlib/scale.pyi | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/matplotlib/scale.pyi b/lib/matplotlib/scale.pyi index 7fec8e68cc5a..90a48fe7fd7a 100644 --- a/lib/matplotlib/scale.pyi +++ b/lib/matplotlib/scale.pyi @@ -2,7 +2,7 @@ from matplotlib.axis import Axis from matplotlib.transforms import Transform from collections.abc import Callable, Iterable -from typing import Literal +from typing import Literal, Union from numpy.typing import ArrayLike class ScaleBase: @@ -15,6 +15,7 @@ class ScaleBase: class LinearScale(ScaleBase): name: str + def __init__(self: ScaleBase, axis: Union[Axis, None] = None) -> None: ... class FuncTransform(Transform): input_dims: int @@ -56,12 +57,12 @@ class LogScale(ScaleBase): name: str subs: Iterable[int] | None def __init__( - self, - axis: Axis | None, + self: LogScale, + axis: Union[Axis, None] = None, *, - base: float = ..., - subs: Iterable[int] | None = ..., - nonpositive: Literal["clip", "mask"] = ... + base: float = 10, + subs: Union[Iterable[int], None] = None, + nonpositive: Union[Literal['clip'], Literal['mask']] = 'clip' ) -> None: ... @property def base(self) -> float: ... @@ -103,13 +104,13 @@ class SymmetricalLogScale(ScaleBase): name: str subs: Iterable[int] | None def __init__( - self, - axis: Axis | None, + self: SymmetricalLogScale, + axis: Union[Axis, None] = None, *, - base: float = ..., - linthresh: float = ..., - subs: Iterable[int] | None = ..., - linscale: float = ... + base: float = 10, + linthresh: float = 2, + subs: Union[Iterable[int], None] = None, + linscale: float = 1 ) -> None: ... @property def base(self) -> float: ... @@ -164,15 +165,16 @@ class LogisticTransform(Transform): class LogitScale(ScaleBase): name: str def __init__( - self, - axis: Axis | None, - nonpositive: Literal["mask", "clip"] = ..., + self: LogitScale, + axis: Union[Axis, None] = None, + nonpositive: Union[Literal['mask'], Literal['clip']] = 'mask', *, - one_half: str = ..., - use_overline: bool = ... + one_half: str = '\\frac{1}{2}', + use_overline: bool = False ) -> None: ... def get_transform(self) -> LogitTransform: ... def get_scale_names() -> list[str]: ... def scale_factory(scale: str, axis: Axis, **kwargs) -> ScaleBase: ... def register_scale(scale_class: type[ScaleBase]) -> None: ... +def handle_axis_parameter(init_func: Callable[..., None]) -> Callable[..., None]: ... \ No newline at end of file From 16cef9d06964c9c8d76088e80e233a2f1794349d Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Tue, 13 May 2025 15:28:44 -0300 Subject: [PATCH 04/25] Adding new line to the end of scale.pyi --- lib/matplotlib/scale.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/scale.pyi b/lib/matplotlib/scale.pyi index 90a48fe7fd7a..7e13b1c76ce8 100644 --- a/lib/matplotlib/scale.pyi +++ b/lib/matplotlib/scale.pyi @@ -177,4 +177,4 @@ class LogitScale(ScaleBase): def get_scale_names() -> list[str]: ... def scale_factory(scale: str, axis: Axis, **kwargs) -> ScaleBase: ... def register_scale(scale_class: type[ScaleBase]) -> None: ... -def handle_axis_parameter(init_func: Callable[..., None]) -> Callable[..., None]: ... \ No newline at end of file +def handle_axis_parameter(init_func: Callable[..., None]) -> Callable[..., None]: ... From 698c35febf8d46c14c76b2cc7bfec0de36fb31c8 Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Tue, 13 May 2025 16:41:59 -0300 Subject: [PATCH 05/25] Update in docstring --- lib/matplotlib/scale.py | 42 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 5ff6a8144081..c5ba764f8c3f 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -107,37 +107,37 @@ def limit_range_for_scale(self, vmin, vmax, minpos): def handle_axis_parameter(init_func): """ - Allow scale classes to work with or without the `axis` parameter. + Decorator to support scale constructors that optionally accept an axis. - This decorator enables scale constructors to maintain backward - compatibility with older code that passes `axis`, while allowing - future implementations to omit it entirely. - - If the wrapped constructor defines `axis` as its first argument, - the parameter is preserved. Otherwise, it is safely removed from - positional or keyword arguments. + This decorator provides backward compatibility for scale classes that + used to require an *axis* parameter. It allows scale constructors to + function whether or not the *axis* argument is provided. Parameters ---------- init_func : callable - The original __init__ method of a scale class. + The original ``__init__`` method of a scale class. Returns ------- callable - A wrapped version of `init_func` that handles the optional `axis`. + A wrapped version of ``init_func`` that supports the optional *axis* + parameter. + + Notes + ----- + If the constructor defines *axis* explicitly as its first parameter, the + argument is preserved. Otherwise, it is removed from positional and keyword + arguments before calling the constructor. + + Examples + -------- + >>> from matplotlib.scale import ScaleBase + >>> class CustomScale(ScaleBase): + ... @handle_axis_parameter + ... def __init__(self, axis=None, custom_param=1): + ... self.custom_param = custom_param """ - @wraps(init_func) - def wrapper(self, *args, **kwargs): - sig = inspect.signature(init_func) - params = list(sig.parameters.values()) - if params and params[1].name == "axis": - return init_func(self, *args, **kwargs) - if args: - args = args[1:] - kwargs.pop("axis", None) - return init_func(self, *args, **kwargs) - return wrapper class LinearScale(ScaleBase): From 8a0d3c7ae6dc4e127c48d3095e430e24053b126c Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Tue, 13 May 2025 16:47:49 -0300 Subject: [PATCH 06/25] Fixing Handle Function --- lib/matplotlib/scale.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index c5ba764f8c3f..6cb13003ef0c 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -107,28 +107,27 @@ def limit_range_for_scale(self, vmin, vmax, minpos): def handle_axis_parameter(init_func): """ - Decorator to support scale constructors that optionally accept an axis. + Decorator to handle the optional *axis* parameter in scale constructors. - This decorator provides backward compatibility for scale classes that - used to require an *axis* parameter. It allows scale constructors to - function whether or not the *axis* argument is provided. + This decorator ensures backward compatibility for scale classes that + previously required an *axis* parameter. It allows constructors to work + seamlessly with or without the *axis* parameter. Parameters ---------- init_func : callable - The original ``__init__`` method of a scale class. + The original __init__ method of a scale class. Returns ------- callable - A wrapped version of ``init_func`` that supports the optional *axis* - parameter. + A wrapped version of *init_func* that handles the optional *axis*. Notes ----- - If the constructor defines *axis* explicitly as its first parameter, the - argument is preserved. Otherwise, it is removed from positional and keyword - arguments before calling the constructor. + If the wrapped constructor defines *axis* as its first argument, the + parameter is preserved. Otherwise, it is safely removed from positional + or keyword arguments. Examples -------- @@ -138,6 +137,17 @@ def handle_axis_parameter(init_func): ... def __init__(self, axis=None, custom_param=1): ... self.custom_param = custom_param """ + @wraps(init_func) + def wrapper(self, *args, **kwargs): + sig = inspect.signature(init_func) + params = list(sig.parameters.values()) + if params and params[1].name == "axis": + return init_func(self, *args, **kwargs) + if args: + args = args[1:] + kwargs.pop("axis", None) + return init_func(self, *args, **kwargs) + return wrapper class LinearScale(ScaleBase): From 11c9bb8357d61044493680ed5a0cf93644185d8e Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Tue, 20 May 2025 16:16:51 -0300 Subject: [PATCH 07/25] Support optional axis in scales Updated my refactor based on the feedbacks received --- lib/matplotlib/scale.py | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 6cb13003ef0c..5c6c7c5e3863 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -126,8 +126,8 @@ def handle_axis_parameter(init_func): Notes ----- If the wrapped constructor defines *axis* as its first argument, the - parameter is preserved. Otherwise, it is safely removed from positional - or keyword arguments. + parameter is preserved when present. Otherwise, the value `None` is injected + as the first argument. Examples -------- @@ -139,14 +139,12 @@ def handle_axis_parameter(init_func): """ @wraps(init_func) def wrapper(self, *args, **kwargs): - sig = inspect.signature(init_func) - params = list(sig.parameters.values()) - if params and params[1].name == "axis": + # If the first argument is a ScaleBase (axis), pass as is. + if args and isinstance(args[0], ScaleBase): return init_func(self, *args, **kwargs) - if args: - args = args[1:] - kwargs.pop("axis", None) - return init_func(self, *args, **kwargs) + else: + # Inject None as axis parameter + return init_func(self, None, *args, **kwargs) return wrapper @@ -801,14 +799,6 @@ def register_scale(scale_class): scale_class : subclass of `ScaleBase` The scale to register. """ - sig = inspect.signature(scale_class.__init__) - if 'axis' in sig.parameters: - warnings.warn( - f"The scale class {scale_class.__name__} still uses the 'axis' " - "parameter in its constructor. Consider refactoring it to remove " - "this dependency.", - DeprecationWarning - ) _scale_mapping[scale_class.name] = scale_class From 25bdfc2da0d4909d5923f8b68692475e06842622 Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Tue, 20 May 2025 16:21:12 -0300 Subject: [PATCH 08/25] Fixing ruff error --- lib/matplotlib/scale.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 5c6c7c5e3863..d093c518c547 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -31,7 +31,6 @@ import inspect import textwrap -import warnings from functools import wraps import numpy as np From 00214f6a31ed48579c1a5a229af45a71d1a15a0f Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Tue, 20 May 2025 18:34:35 -0300 Subject: [PATCH 09/25] change in parameters and in decorator --- lib/matplotlib/scale.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index d093c518c547..489a2b25aaf5 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -133,16 +133,16 @@ def handle_axis_parameter(init_func): >>> from matplotlib.scale import ScaleBase >>> class CustomScale(ScaleBase): ... @handle_axis_parameter - ... def __init__(self, axis=None, custom_param=1): + ... def __init__(self, axis, custom_param=1): ... self.custom_param = custom_param """ @wraps(init_func) def wrapper(self, *args, **kwargs): - # If the first argument is a ScaleBase (axis), pass as is. - if args and isinstance(args[0], ScaleBase): + if args and isinstance(args[0], mpl.axis.Axis): return init_func(self, *args, **kwargs) else: - # Inject None as axis parameter + # Remove 'axis' from kwargs to avoid double assignment + kwargs.pop('axis', None) return init_func(self, None, *args, **kwargs) return wrapper @@ -155,7 +155,7 @@ class LinearScale(ScaleBase): name = 'linear' @handle_axis_parameter - def __init__(self, axis=None): + def __init__(self, axis): # This method is present only to prevent inheritance of the base class' # constructor docstring, which would otherwise end up interpolated into # the docstring of Axis.set_scale. @@ -326,7 +326,7 @@ class LogScale(ScaleBase): name = 'log' @handle_axis_parameter - def __init__(self, axis=None, *, base=10, subs=None, nonpositive="clip"): + def __init__(self, axis, *, base=10, subs=None, nonpositive="clip"): """ Parameters ---------- @@ -504,7 +504,7 @@ class SymmetricalLogScale(ScaleBase): name = 'symlog' @handle_axis_parameter - def __init__(self, axis=None, *, base=10, linthresh=2, subs=None, linscale=1): + def __init__(self, axis, *, base=10, linthresh=2, subs=None, linscale=1): self._transform = SymmetricalLogTransform(base, linthresh, linscale) self.subs = subs @@ -696,7 +696,7 @@ class LogitScale(ScaleBase): name = 'logit' @handle_axis_parameter - def __init__(self, axis=None, nonpositive='mask', *, + def __init__(self, axis, nonpositive='mask', *, one_half=r"\frac{1}{2}", use_overline=False): r""" Parameters From 4cf2ddeec4f71d87a70a910ff46e8d1ebec5c6f8 Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Tue, 20 May 2025 18:51:04 -0300 Subject: [PATCH 10/25] parameter fix --- lib/matplotlib/scale.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 489a2b25aaf5..3126c2c82095 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -155,7 +155,7 @@ class LinearScale(ScaleBase): name = 'linear' @handle_axis_parameter - def __init__(self, axis): + def __init__(self, axis=None): # This method is present only to prevent inheritance of the base class' # constructor docstring, which would otherwise end up interpolated into # the docstring of Axis.set_scale. @@ -326,7 +326,7 @@ class LogScale(ScaleBase): name = 'log' @handle_axis_parameter - def __init__(self, axis, *, base=10, subs=None, nonpositive="clip"): + def __init__(self, axis=None, *, base=10, subs=None, nonpositive="clip"): """ Parameters ---------- @@ -504,7 +504,7 @@ class SymmetricalLogScale(ScaleBase): name = 'symlog' @handle_axis_parameter - def __init__(self, axis, *, base=10, linthresh=2, subs=None, linscale=1): + def __init__(self, axis=None, *, base=10, linthresh=2, subs=None, linscale=1): self._transform = SymmetricalLogTransform(base, linthresh, linscale) self.subs = subs @@ -597,7 +597,7 @@ class AsinhScale(ScaleBase): } @handle_axis_parameter - def __init__(self, axis, *, linear_width=1.0, + def __init__(self, axis=None, *, linear_width=1.0, base=10, subs='auto', **kwargs): """ Parameters @@ -696,7 +696,7 @@ class LogitScale(ScaleBase): name = 'logit' @handle_axis_parameter - def __init__(self, axis, nonpositive='mask', *, + def __init__(self, axis=None, nonpositive='mask', *, one_half=r"\frac{1}{2}", use_overline=False): r""" Parameters From 2e691c60158e83c8286587aa6cc4767d9ca2f871 Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Tue, 20 May 2025 18:57:14 -0300 Subject: [PATCH 11/25] minor change in pyi --- lib/matplotlib/scale.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/scale.pyi b/lib/matplotlib/scale.pyi index 7e13b1c76ce8..d7f34457ad4f 100644 --- a/lib/matplotlib/scale.pyi +++ b/lib/matplotlib/scale.pyi @@ -139,7 +139,7 @@ class AsinhScale(ScaleBase): auto_tick_multipliers: dict[int, tuple[int, ...]] def __init__( self, - axis: Axis | None, + axis: Union[Axis, None] = None, *, linear_width: float = ..., base: float = ..., From 618054d55f9111b12ed9b866732f1859f18a8f81 Mon Sep 17 00:00:00 2001 From: Vagner Messias <32200525+vagnermcj@users.noreply.github.com> Date: Tue, 27 May 2025 19:17:42 -0300 Subject: [PATCH 12/25] Update lib/matplotlib/scale.py Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- lib/matplotlib/scale.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 3126c2c82095..e0c828220924 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -104,7 +104,7 @@ def limit_range_for_scale(self, vmin, vmax, minpos): return vmin, vmax -def handle_axis_parameter(init_func): +def _make_axis_parameter_optional(init_func): """ Decorator to handle the optional *axis* parameter in scale constructors. From a1002b399079b5d9da58697ed536f5f901fb9e72 Mon Sep 17 00:00:00 2001 From: Vagner Messias <32200525+vagnermcj@users.noreply.github.com> Date: Tue, 27 May 2025 19:17:58 -0300 Subject: [PATCH 13/25] Update lib/matplotlib/scale.py Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- lib/matplotlib/scale.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index e0c828220924..600de44f93fd 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -106,7 +106,7 @@ def limit_range_for_scale(self, vmin, vmax, minpos): def _make_axis_parameter_optional(init_func): """ - Decorator to handle the optional *axis* parameter in scale constructors. + Decorator to allow leaving out the *axis* parameter in scale constructors. This decorator ensures backward compatibility for scale classes that previously required an *axis* parameter. It allows constructors to work From 2ea3468733272338f8976ca95ce8a7bfeed85390 Mon Sep 17 00:00:00 2001 From: Vagner Messias <32200525+vagnermcj@users.noreply.github.com> Date: Tue, 27 May 2025 19:18:06 -0300 Subject: [PATCH 14/25] Update lib/matplotlib/scale.py Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- lib/matplotlib/scale.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 600de44f93fd..8b17604bed03 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -109,8 +109,11 @@ def _make_axis_parameter_optional(init_func): Decorator to allow leaving out the *axis* parameter in scale constructors. This decorator ensures backward compatibility for scale classes that - previously required an *axis* parameter. It allows constructors to work - seamlessly with or without the *axis* parameter. + previously required an *axis* parameter. It allows constructors to be + callerd with or without the *axis* parameter. + + For simplicity, this does not handle the case when *axis* is passed as a keyword. Howver, + scanning GitHub, there's no evidence that that is used anywhere. Parameters ---------- From 0e7dbc5772e3fc400fbe4344948a08fea99fff74 Mon Sep 17 00:00:00 2001 From: Vagner Messias <32200525+vagnermcj@users.noreply.github.com> Date: Tue, 27 May 2025 19:18:41 -0300 Subject: [PATCH 15/25] Update lib/matplotlib/scale.pyi Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- lib/matplotlib/scale.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/scale.pyi b/lib/matplotlib/scale.pyi index d7f34457ad4f..875be95b4236 100644 --- a/lib/matplotlib/scale.pyi +++ b/lib/matplotlib/scale.pyi @@ -58,7 +58,7 @@ class LogScale(ScaleBase): subs: Iterable[int] | None def __init__( self: LogScale, - axis: Union[Axis, None] = None, + axis: Axis | None = ..., *, base: float = 10, subs: Union[Iterable[int], None] = None, From fa15c3a295149edd1b1af718bd34a3b6b5462f4d Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Thu, 29 May 2025 10:25:48 -0300 Subject: [PATCH 16/25] Updating self and axis in pyi --- lib/matplotlib/scale.py | 16 ++++++++-------- lib/matplotlib/scale.pyi | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 8b17604bed03..f02a5e0b886a 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -135,7 +135,7 @@ def _make_axis_parameter_optional(init_func): -------- >>> from matplotlib.scale import ScaleBase >>> class CustomScale(ScaleBase): - ... @handle_axis_parameter + ... @_make_axis_parameter_optional ... def __init__(self, axis, custom_param=1): ... self.custom_param = custom_param """ @@ -157,7 +157,7 @@ class LinearScale(ScaleBase): name = 'linear' - @handle_axis_parameter + @_make_axis_parameter_optional def __init__(self, axis=None): # This method is present only to prevent inheritance of the base class' # constructor docstring, which would otherwise end up interpolated into @@ -228,7 +228,7 @@ class FuncScale(ScaleBase): name = 'function' - @handle_axis_parameter + @_make_axis_parameter_optional def __init__(self, axis, functions): """ Parameters @@ -328,7 +328,7 @@ class LogScale(ScaleBase): """ name = 'log' - @handle_axis_parameter + @_make_axis_parameter_optional def __init__(self, axis=None, *, base=10, subs=None, nonpositive="clip"): """ Parameters @@ -380,7 +380,7 @@ class FuncScaleLog(LogScale): name = 'functionlog' - @handle_axis_parameter + @_make_axis_parameter_optional def __init__(self, axis, functions, base=10): """ Parameters @@ -506,7 +506,7 @@ class SymmetricalLogScale(ScaleBase): """ name = 'symlog' - @handle_axis_parameter + @_make_axis_parameter_optional def __init__(self, axis=None, *, base=10, linthresh=2, subs=None, linscale=1): self._transform = SymmetricalLogTransform(base, linthresh, linscale) self.subs = subs @@ -599,7 +599,7 @@ class AsinhScale(ScaleBase): 1024: (256, 512) } - @handle_axis_parameter + @_make_axis_parameter_optional def __init__(self, axis=None, *, linear_width=1.0, base=10, subs='auto', **kwargs): """ @@ -698,7 +698,7 @@ class LogitScale(ScaleBase): """ name = 'logit' - @handle_axis_parameter + @_make_axis_parameter_optional def __init__(self, axis=None, nonpositive='mask', *, one_half=r"\frac{1}{2}", use_overline=False): r""" diff --git a/lib/matplotlib/scale.pyi b/lib/matplotlib/scale.pyi index 875be95b4236..234ddb8d986d 100644 --- a/lib/matplotlib/scale.pyi +++ b/lib/matplotlib/scale.pyi @@ -104,8 +104,8 @@ class SymmetricalLogScale(ScaleBase): name: str subs: Iterable[int] | None def __init__( - self: SymmetricalLogScale, - axis: Union[Axis, None] = None, + self, + axis: Axis | None = ..., *, base: float = 10, linthresh: float = 2, @@ -139,7 +139,7 @@ class AsinhScale(ScaleBase): auto_tick_multipliers: dict[int, tuple[int, ...]] def __init__( self, - axis: Union[Axis, None] = None, + axis: Axis | None = ..., *, linear_width: float = ..., base: float = ..., @@ -165,8 +165,8 @@ class LogisticTransform(Transform): class LogitScale(ScaleBase): name: str def __init__( - self: LogitScale, - axis: Union[Axis, None] = None, + self, + axis: Axis | None = ..., nonpositive: Union[Literal['mask'], Literal['clip']] = 'mask', *, one_half: str = '\\frac{1}{2}', From d9f57227531ae1df13c471d918d2996e17659086 Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Thu, 29 May 2025 10:53:15 -0300 Subject: [PATCH 17/25] returning scale_factory to default --- lib/matplotlib/scale.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index f02a5e0b886a..e6dc3e7ad03d 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -158,7 +158,7 @@ class LinearScale(ScaleBase): name = 'linear' @_make_axis_parameter_optional - def __init__(self, axis=None): + def __init__(self, axis): # This method is present only to prevent inheritance of the base class' # constructor docstring, which would otherwise end up interpolated into # the docstring of Axis.set_scale. @@ -779,12 +779,7 @@ def scale_factory(scale, axis, **kwargs): axis : `~matplotlib.axis.Axis` """ scale_cls = _api.check_getitem(_scale_mapping, scale=scale) - try: - return scale_cls(axis, **kwargs) - except TypeError as e: - if 'unexpected keyword argument' in str(e) or 'positional argument' in str(e): - return scale_cls(**kwargs) - raise + return scale_cls(axis, **kwargs) if scale_factory.__doc__: From 8aebcc00f8ea4027c97733f7e74831b1cf60a7e2 Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Thu, 29 May 2025 10:56:17 -0300 Subject: [PATCH 18/25] Ruff checks --- lib/matplotlib/scale.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index e6dc3e7ad03d..f38bc0dcf89a 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -111,8 +111,9 @@ def _make_axis_parameter_optional(init_func): This decorator ensures backward compatibility for scale classes that previously required an *axis* parameter. It allows constructors to be callerd with or without the *axis* parameter. - - For simplicity, this does not handle the case when *axis* is passed as a keyword. Howver, + + For simplicity, this does not handle the case when *axis* + is passed as a keyword. Howver, scanning GitHub, there's no evidence that that is used anywhere. Parameters From 6da5188b88fc5b39ca1059294e8dccf050a11350 Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Thu, 29 May 2025 11:00:58 -0300 Subject: [PATCH 19/25] description fix --- lib/matplotlib/scale.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index f38bc0dcf89a..44c0e34065eb 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -113,7 +113,7 @@ def _make_axis_parameter_optional(init_func): callerd with or without the *axis* parameter. For simplicity, this does not handle the case when *axis* - is passed as a keyword. Howver, + is passed as a keyword. However, scanning GitHub, there's no evidence that that is used anywhere. Parameters From 9b7cce441a7c5ebf05c2dcd2907d8636dd115a8b Mon Sep 17 00:00:00 2001 From: Vagner Messias <32200525+vagnermcj@users.noreply.github.com> Date: Fri, 6 Jun 2025 15:03:44 -0300 Subject: [PATCH 20/25] Update lib/matplotlib/scale.pyi Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- lib/matplotlib/scale.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/scale.pyi b/lib/matplotlib/scale.pyi index 234ddb8d986d..e11b3d2f7360 100644 --- a/lib/matplotlib/scale.pyi +++ b/lib/matplotlib/scale.pyi @@ -57,7 +57,7 @@ class LogScale(ScaleBase): name: str subs: Iterable[int] | None def __init__( - self: LogScale, + self, axis: Axis | None = ..., *, base: float = 10, From 9c9101e97aa4a26b02f3cc15588e5cb100712547 Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Fri, 6 Jun 2025 15:08:25 -0300 Subject: [PATCH 21/25] Undoing Unrelated Modifications --- lib/matplotlib/scale.pyi | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/scale.pyi b/lib/matplotlib/scale.pyi index e11b3d2f7360..8cc2e824b12b 100644 --- a/lib/matplotlib/scale.pyi +++ b/lib/matplotlib/scale.pyi @@ -60,9 +60,9 @@ class LogScale(ScaleBase): self, axis: Axis | None = ..., *, - base: float = 10, - subs: Union[Iterable[int], None] = None, - nonpositive: Union[Literal['clip'], Literal['mask']] = 'clip' + base: float = ..., + subs: Iterable[int] | None = ..., + nonpositive: Literal["clip", "mask"] = ... ) -> None: ... @property def base(self) -> float: ... @@ -107,10 +107,10 @@ class SymmetricalLogScale(ScaleBase): self, axis: Axis | None = ..., *, - base: float = 10, - linthresh: float = 2, - subs: Union[Iterable[int], None] = None, - linscale: float = 1 + base: float = ..., + linthresh: float = ..., + subs: Iterable[int] | None = ..., + linscale: float = ... ) -> None: ... @property def base(self) -> float: ... @@ -167,10 +167,10 @@ class LogitScale(ScaleBase): def __init__( self, axis: Axis | None = ..., - nonpositive: Union[Literal['mask'], Literal['clip']] = 'mask', + nonpositive: Literal["mask", "clip"] = ..., *, - one_half: str = '\\frac{1}{2}', - use_overline: bool = False + one_half: str = ..., + use_overline: bool = ... ) -> None: ... def get_transform(self) -> LogitTransform: ... From 5d7303fc303a280cd687aafc6f9df003b28335ab Mon Sep 17 00:00:00 2001 From: Vagner Messias Date: Fri, 6 Jun 2025 15:18:16 -0300 Subject: [PATCH 22/25] fixing mypy tests --- lib/matplotlib/scale.pyi | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/scale.pyi b/lib/matplotlib/scale.pyi index 8cc2e824b12b..53055b92c444 100644 --- a/lib/matplotlib/scale.pyi +++ b/lib/matplotlib/scale.pyi @@ -2,7 +2,7 @@ from matplotlib.axis import Axis from matplotlib.transforms import Transform from collections.abc import Callable, Iterable -from typing import Literal, Union +from typing import Literal from numpy.typing import ArrayLike class ScaleBase: @@ -15,7 +15,10 @@ class ScaleBase: class LinearScale(ScaleBase): name: str - def __init__(self: ScaleBase, axis: Union[Axis, None] = None) -> None: ... + def __init__( + self: ScaleBase, + axis: Axis | None, + ) -> None: ... class FuncTransform(Transform): input_dims: int @@ -177,4 +180,4 @@ class LogitScale(ScaleBase): def get_scale_names() -> list[str]: ... def scale_factory(scale: str, axis: Axis, **kwargs) -> ScaleBase: ... def register_scale(scale_class: type[ScaleBase]) -> None: ... -def handle_axis_parameter(init_func: Callable[..., None]) -> Callable[..., None]: ... +def _make_axis_parameter_optional(init_func: Callable[..., None]) -> Callable[..., None]: ... From dabac62f7472febd823c0137c7c38ebe0d89eb14 Mon Sep 17 00:00:00 2001 From: Vagner Messias <32200525+vagnermcj@users.noreply.github.com> Date: Sat, 7 Jun 2025 19:30:45 -0300 Subject: [PATCH 23/25] Update lib/matplotlib/scale.pyi Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- lib/matplotlib/scale.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/scale.pyi b/lib/matplotlib/scale.pyi index 53055b92c444..ba9f269b8c78 100644 --- a/lib/matplotlib/scale.pyi +++ b/lib/matplotlib/scale.pyi @@ -16,7 +16,7 @@ class ScaleBase: class LinearScale(ScaleBase): name: str def __init__( - self: ScaleBase, + self, axis: Axis | None, ) -> None: ... From 75896a234288d8d9b868aa7ddbc845a16a20d399 Mon Sep 17 00:00:00 2001 From: Vagner Messias <32200525+vagnermcj@users.noreply.github.com> Date: Wed, 25 Jun 2025 22:25:29 -0300 Subject: [PATCH 24/25] keyword-argument suggestion Co-authored-by: Elliott Sales de Andrade --- lib/matplotlib/scale.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 44c0e34065eb..2c7083ac7d82 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -146,8 +146,7 @@ def wrapper(self, *args, **kwargs): return init_func(self, *args, **kwargs) else: # Remove 'axis' from kwargs to avoid double assignment - kwargs.pop('axis', None) - return init_func(self, None, *args, **kwargs) + return init_func(self, kwargs.pop('axis', None), *args, **kwargs) return wrapper From bd8a135f99de2f5df98751e89f3787d4bfe0a6c8 Mon Sep 17 00:00:00 2001 From: Vagner Messias <32200525+vagnermcj@users.noreply.github.com> Date: Thu, 26 Jun 2025 21:41:58 -0300 Subject: [PATCH 25/25] kwargs pop before function call Co-authored-by: Elliott Sales de Andrade --- lib/matplotlib/scale.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 2c7083ac7d82..4517b8946b03 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -146,7 +146,8 @@ def wrapper(self, *args, **kwargs): return init_func(self, *args, **kwargs) else: # Remove 'axis' from kwargs to avoid double assignment - return init_func(self, kwargs.pop('axis', None), *args, **kwargs) + axis = kwargs.pop('axis', None) + return init_func(self, axis, *args, **kwargs) return wrapper