From ec34a500ab7a1a20029ef45fe64890e423719446 Mon Sep 17 00:00:00 2001 From: lvr44 <86169515+EricRLeao1311@users.noreply.github.com> Date: Mon, 16 Oct 2023 19:38:22 -0300 Subject: [PATCH 1/9] deduplicate hatch validate I replaced the deprecated warning from _validate_hatch_pattern() function in hatch.py with the validate_hatch() warn from rcsetup.py. I also make validate_hatch() warn from rcsetup.py use the _validate_hatch_pattern() function. This removed the deprecated warning from the hatch validation code and made it the canonical validator for all hatch patterns. --- lib/matplotlib/hatch.py | 24 +++++------ lib/matplotlib/rcsetup.py | 85 +++++++-------------------------------- 2 files changed, 25 insertions(+), 84 deletions(-) diff --git a/lib/matplotlib/hatch.py b/lib/matplotlib/hatch.py index 9ec88776cfd3..b3e4ffadd158 100644 --- a/lib/matplotlib/hatch.py +++ b/lib/matplotlib/hatch.py @@ -179,21 +179,17 @@ def __init__(self, hatch, density): ] -def _validate_hatch_pattern(hatch): - valid_hatch_patterns = set(r'-+|/\xXoO.*') - if hatch is not None: - invalids = set(hatch).difference(valid_hatch_patterns) - if invalids: - valid = ''.join(sorted(valid_hatch_patterns)) +def _validate_hatch_pattern(hatch): + valid_hatch_patterns = set(r'-+|/\xXoO.*') + if hatch is not None: + invalids = set(hatch).difference(valid_hatch_patterns) + if invalids: + valid = ''.join(sorted(valid_hatch_patterns)) invalids = ''.join(sorted(invalids)) - _api.warn_deprecated( - '3.4', - removal='3.9', # one release after custom hatches (#20690) - message=f'hatch must consist of a string of "{valid}" or ' - 'None, but found the following invalid values ' - f'"{invalids}". Passing invalid values is deprecated ' - 'since %(since)s and will become an error %(removal)s.' - ) + message = f"""Unknown hatch symbol(s): {invalids}. + Hatch must consist of a string of {valid}""" + raise ValueError(message) + raise ValueError("Hatch pattern must be a string") def get_path(hatchpattern, density=6): diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index fa18677f5895..e3bacea50b4a 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -22,6 +22,7 @@ import numpy as np +from hatch import _validate_hatch_pattern from matplotlib import _api, cbook from matplotlib.cbook import ls_mapper from matplotlib.colors import Colormap, is_color_like @@ -179,7 +180,7 @@ def _make_type_validator(cls, *, allow_none=False): def validator(s): if (allow_none and - (s is None or cbook._str_lower_equal(s, "none"))): + (s is None or isinstance(s, str) and s.lower() == "none")): return None if cls is str and not isinstance(s, str): raise ValueError(f'Could not convert {s!r} to str') @@ -438,19 +439,6 @@ def validate_ps_distiller(s): return ValidateInStrings('ps.usedistiller', ['ghostscript', 'xpdf'])(s) -def _validate_papersize(s): - # Re-inline this validator when the 'auto' deprecation expires. - s = ValidateInStrings("ps.papersize", - ["figure", "auto", "letter", "legal", "ledger", - *[f"{ab}{i}" for ab in "ab" for i in range(11)]], - ignorecase=True)(s) - if s == "auto": - _api.warn_deprecated("3.8", name="ps.papersize='auto'", - addendum="Pass an explicit paper type, figure, or omit " - "the *ps.papersize* rcParam entirely.") - return s - - # A validator dedicated to the named line styles, based on the items in # ls_mapper, and a list of possible strings read from Line2D.set_linestyle _validate_named_linestyle = ValidateInStrings( @@ -589,7 +577,7 @@ def _validate_int_greaterequal0(s): raise RuntimeError(f'Value must be >=0; got {s}') -def validate_hatch(s): +def _validate_hatch_pattern(s): r""" Validate a hatch pattern. A hatch pattern string can have any sequence of the following @@ -604,7 +592,7 @@ def validate_hatch(s): return s -validate_hatchlist = _listify_validator(validate_hatch) +validate_hatchlist = _listify_validator(_validate_hatch_pattern) validate_dashlist = _listify_validator(validate_floatlist) @@ -615,7 +603,7 @@ def _validate_minor_tick_ndivs(n): two major ticks. """ - if cbook._str_lower_equal(n, 'auto'): + if isinstance(n, str) and n.lower() == 'auto': return n try: n = _validate_int_greaterequal0(n) @@ -751,51 +739,6 @@ def visit_Attribute(self, node): self.generic_visit(node) -# A validator dedicated to the named legend loc -_validate_named_legend_loc = ValidateInStrings( - 'legend.loc', - [ - "best", - "upper right", "upper left", "lower left", "lower right", "right", - "center left", "center right", "lower center", "upper center", - "center"], - ignorecase=True) - - -def _validate_legend_loc(loc): - """ - Confirm that loc is a type which rc.Params["legend.loc"] supports. - - .. versionadded:: 3.8 - - Parameters - ---------- - loc : str | int | (float, float) | str((float, float)) - The location of the legend. - - Returns - ------- - loc : str | int | (float, float) or raise ValueError exception - The location of the legend. - """ - if isinstance(loc, str): - try: - return _validate_named_legend_loc(loc) - except ValueError: - pass - try: - loc = ast.literal_eval(loc) - except (SyntaxError, ValueError): - pass - if isinstance(loc, int): - if 0 <= loc <= 10: - return loc - if isinstance(loc, tuple): - if len(loc) == 2 and all(isinstance(e, Real) for e in loc): - return loc - raise ValueError(f"{loc} is not a valid legend location.") - - def validate_cycler(s): """Return a Cycler object from a string repr or the object itself.""" if isinstance(s, str): @@ -1094,10 +1037,8 @@ def _convert_validator_spec(key, conv): "axes.ymargin": _validate_greaterthan_minushalf, # margin added to yaxis "axes.zmargin": _validate_greaterthan_minushalf, # margin added to zaxis - "polaraxes.grid": validate_bool, # display polar grid or not - "axes3d.grid": validate_bool, # display 3d grid - "axes3d.automargin": validate_bool, # automatically add margin when - # manually setting 3D axis limits + "polaraxes.grid": validate_bool, # display polar grid or not + "axes3d.grid": validate_bool, # display 3d grid "axes3d.xaxis.panecolor": validate_color, # 3d background pane "axes3d.yaxis.panecolor": validate_color, # 3d background pane @@ -1122,7 +1063,11 @@ def _convert_validator_spec(key, conv): # legend properties "legend.fancybox": validate_bool, - "legend.loc": _validate_legend_loc, + "legend.loc": _ignorecase([ + "best", + "upper right", "upper left", "lower left", "lower right", "right", + "center left", "center right", "lower center", "upper center", + "center"]), # the number of points in the legend line "legend.numpoints": validate_int, @@ -1134,7 +1079,6 @@ def _convert_validator_spec(key, conv): "legend.labelcolor": _validate_color_or_linecolor, # the relative size of legend markers vs. original "legend.markerscale": validate_float, - # using dict in rcParams not yet supported, so make sure it is bool "legend.shadow": validate_bool, # whether or not to draw a frame around legend "legend.frameon": validate_bool, @@ -1229,7 +1173,6 @@ def _convert_validator_spec(key, conv): "figure.autolayout": validate_bool, "figure.max_open_warning": validate_int, "figure.raise_window": validate_bool, - "macosx.window_mode": ["system", "tab", "window"], "figure.subplot.left": validate_float, "figure.subplot.right": validate_float, @@ -1262,7 +1205,9 @@ def _convert_validator_spec(key, conv): "tk.window_focus": validate_bool, # Maintain shell focus for TkAgg # Set the papersize/type - "ps.papersize": _validate_papersize, + "ps.papersize": _ignorecase(["auto", "letter", "legal", "ledger", + *[f"{ab}{i}" + for ab in "ab" for i in range(11)]]), "ps.useafm": validate_bool, # use ghostscript or xpdf to distill ps output "ps.usedistiller": validate_ps_distiller, From 69b248b9f3ac68eb5c30f452228db510b1080d6f Mon Sep 17 00:00:00 2001 From: lvr44 <86169515+EricRLeao1311@users.noreply.github.com> Date: Mon, 16 Oct 2023 20:05:29 -0300 Subject: [PATCH 2/9] deduplicate hatch validate I replaced the deprecated warning from _validate_hatch_pattern() function in hatch.py with the validate_hatch() warn from rcsetup.py. I also make validate_hatch() warn from rcsetup.py use the _validate_hatch_pattern() function. This removed the deprecated warning from the hatch validation code and made it the canonical validator for all hatch patterns. --- lib/matplotlib/hatch.py | 16 ++++++++-------- lib/matplotlib/rcsetup.py | 15 ++------------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/lib/matplotlib/hatch.py b/lib/matplotlib/hatch.py index b3e4ffadd158..a8af1a3ea56d 100644 --- a/lib/matplotlib/hatch.py +++ b/lib/matplotlib/hatch.py @@ -2,7 +2,6 @@ import numpy as np -from matplotlib import _api from matplotlib.path import Path @@ -179,16 +178,17 @@ def __init__(self, hatch, density): ] -def _validate_hatch_pattern(hatch): - valid_hatch_patterns = set(r'-+|/\xXoO.*') - if hatch is not None: - invalids = set(hatch).difference(valid_hatch_patterns) - if invalids: - valid = ''.join(sorted(valid_hatch_patterns)) +def _validate_hatch_pattern(hatch): + valid_hatch_patterns = set(r'-+|/\xXoO.*') + if hatch is not None: + invalids = set(hatch).difference(valid_hatch_patterns) + if invalids: + valid = ''.join(sorted(valid_hatch_patterns)) invalids = ''.join(sorted(invalids)) - message = f"""Unknown hatch symbol(s): {invalids}. + message = f"""Unknown hatch symbol(s): {invalids}. Hatch must consist of a string of {valid}""" raise ValueError(message) + else: raise ValueError("Hatch pattern must be a string") diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index e3bacea50b4a..fae56e3bf983 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -577,19 +577,8 @@ def _validate_int_greaterequal0(s): raise RuntimeError(f'Value must be >=0; got {s}') -def _validate_hatch_pattern(s): - r""" - Validate a hatch pattern. - A hatch pattern string can have any sequence of the following - characters: ``\ / | - + * . x o O``. - """ - if not isinstance(s, str): - raise ValueError("Hatch pattern must be a string") - _api.check_isinstance(str, hatch_pattern=s) - unknown = set(s) - {'\\', '/', '|', '-', '+', '*', '.', 'x', 'o', 'O'} - if unknown: - raise ValueError("Unknown hatch symbol(s): %s" % list(unknown)) - return s +def validate_hatch(hatch): + _validate_hatch_pattern(hatch) validate_hatchlist = _listify_validator(_validate_hatch_pattern) From 29fd872cfde5e9fb6d2046b79b8e87fb9ede0a76 Mon Sep 17 00:00:00 2001 From: Eric Leao <86169515+EricRLeao1311@users.noreply.github.com> Date: Wed, 18 Oct 2023 07:43:41 -0300 Subject: [PATCH 3/9] returning the deleted functions --- lib/matplotlib/hatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/hatch.py b/lib/matplotlib/hatch.py index a8af1a3ea56d..5e1589faf31b 100644 --- a/lib/matplotlib/hatch.py +++ b/lib/matplotlib/hatch.py @@ -186,7 +186,7 @@ def _validate_hatch_pattern(hatch): valid = ''.join(sorted(valid_hatch_patterns)) invalids = ''.join(sorted(invalids)) message = f"""Unknown hatch symbol(s): {invalids}. - Hatch must consist of a string of {valid}""" + Hatch must consist of a string of {valid}""" raise ValueError(message) else: raise ValueError("Hatch pattern must be a string") From 30a4fc4136fb27a4ad4a7556becda73f541a5974 Mon Sep 17 00:00:00 2001 From: Eric Leao <86169515+EricRLeao1311@users.noreply.github.com> Date: Wed, 18 Oct 2023 07:48:14 -0300 Subject: [PATCH 4/9] returning the deleted functions and refactoring validate_hatch --- lib/matplotlib/rcsetup.py | 87 ++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 16 deletions(-) diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index fae56e3bf983..2f6c51b2d0b1 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -22,7 +22,7 @@ import numpy as np -from hatch import _validate_hatch_pattern +from matplotlib.hatch import _validate_hatch_pattern from matplotlib import _api, cbook from matplotlib.cbook import ls_mapper from matplotlib.colors import Colormap, is_color_like @@ -180,7 +180,7 @@ def _make_type_validator(cls, *, allow_none=False): def validator(s): if (allow_none and - (s is None or isinstance(s, str) and s.lower() == "none")): + (s is None or cbook._str_lower_equal(s, "none"))): return None if cls is str and not isinstance(s, str): raise ValueError(f'Could not convert {s!r} to str') @@ -439,6 +439,19 @@ def validate_ps_distiller(s): return ValidateInStrings('ps.usedistiller', ['ghostscript', 'xpdf'])(s) +def _validate_papersize(s): + # Re-inline this validator when the 'auto' deprecation expires. + s = ValidateInStrings("ps.papersize", + ["figure", "auto", "letter", "legal", "ledger", + *[f"{ab}{i}" for ab in "ab" for i in range(11)]], + ignorecase=True)(s) + if s == "auto": + _api.warn_deprecated("3.8", name="ps.papersize='auto'", + addendum="Pass an explicit paper type, figure, or omit " + "the *ps.papersize* rcParam entirely.") + return s + + # A validator dedicated to the named line styles, based on the items in # ls_mapper, and a list of possible strings read from Line2D.set_linestyle _validate_named_linestyle = ValidateInStrings( @@ -577,11 +590,10 @@ def _validate_int_greaterequal0(s): raise RuntimeError(f'Value must be >=0; got {s}') -def validate_hatch(hatch): - _validate_hatch_pattern(hatch) +validate_hatch = _validate_hatch_pattern -validate_hatchlist = _listify_validator(_validate_hatch_pattern) +validate_hatchlist = _listify_validator(validate_hatch) validate_dashlist = _listify_validator(validate_floatlist) @@ -592,7 +604,7 @@ def _validate_minor_tick_ndivs(n): two major ticks. """ - if isinstance(n, str) and n.lower() == 'auto': + if cbook._str_lower_equal(n, 'auto'): return n try: n = _validate_int_greaterequal0(n) @@ -728,6 +740,51 @@ def visit_Attribute(self, node): self.generic_visit(node) +# A validator dedicated to the named legend loc +_validate_named_legend_loc = ValidateInStrings( + 'legend.loc', + [ + "best", + "upper right", "upper left", "lower left", "lower right", "right", + "center left", "center right", "lower center", "upper center", + "center"], + ignorecase=True) + + +def _validate_legend_loc(loc): + """ + Confirm that loc is a type which rc.Params["legend.loc"] supports. + + .. versionadded:: 3.8 + + Parameters + ---------- + loc : str | int | (float, float) | str((float, float)) + The location of the legend. + + Returns + ------- + loc : str | int | (float, float) or raise ValueError exception + The location of the legend. + """ + if isinstance(loc, str): + try: + return _validate_named_legend_loc(loc) + except ValueError: + pass + try: + loc = ast.literal_eval(loc) + except (SyntaxError, ValueError): + pass + if isinstance(loc, int): + if 0 <= loc <= 10: + return loc + if isinstance(loc, tuple): + if len(loc) == 2 and all(isinstance(e, Real) for e in loc): + return loc + raise ValueError(f"{loc} is not a valid legend location.") + + def validate_cycler(s): """Return a Cycler object from a string repr or the object itself.""" if isinstance(s, str): @@ -1026,8 +1083,10 @@ def _convert_validator_spec(key, conv): "axes.ymargin": _validate_greaterthan_minushalf, # margin added to yaxis "axes.zmargin": _validate_greaterthan_minushalf, # margin added to zaxis - "polaraxes.grid": validate_bool, # display polar grid or not - "axes3d.grid": validate_bool, # display 3d grid + "polaraxes.grid": validate_bool, # display polar grid or not + "axes3d.grid": validate_bool, # display 3d grid + "axes3d.automargin": validate_bool, # automatically add margin when + # manually setting 3D axis limits "axes3d.xaxis.panecolor": validate_color, # 3d background pane "axes3d.yaxis.panecolor": validate_color, # 3d background pane @@ -1052,11 +1111,7 @@ def _convert_validator_spec(key, conv): # legend properties "legend.fancybox": validate_bool, - "legend.loc": _ignorecase([ - "best", - "upper right", "upper left", "lower left", "lower right", "right", - "center left", "center right", "lower center", "upper center", - "center"]), + "legend.loc": _validate_legend_loc, # the number of points in the legend line "legend.numpoints": validate_int, @@ -1068,6 +1123,7 @@ def _convert_validator_spec(key, conv): "legend.labelcolor": _validate_color_or_linecolor, # the relative size of legend markers vs. original "legend.markerscale": validate_float, + # using dict in rcParams not yet supported, so make sure it is bool "legend.shadow": validate_bool, # whether or not to draw a frame around legend "legend.frameon": validate_bool, @@ -1162,6 +1218,7 @@ def _convert_validator_spec(key, conv): "figure.autolayout": validate_bool, "figure.max_open_warning": validate_int, "figure.raise_window": validate_bool, + "macosx.window_mode": ["system", "tab", "window"], "figure.subplot.left": validate_float, "figure.subplot.right": validate_float, @@ -1194,9 +1251,7 @@ def _convert_validator_spec(key, conv): "tk.window_focus": validate_bool, # Maintain shell focus for TkAgg # Set the papersize/type - "ps.papersize": _ignorecase(["auto", "letter", "legal", "ledger", - *[f"{ab}{i}" - for ab in "ab" for i in range(11)]]), + "ps.papersize": _validate_papersize, "ps.useafm": validate_bool, # use ghostscript or xpdf to distill ps output "ps.usedistiller": validate_ps_distiller, From 862d58106cfd648c8ae0f8a01cf474801466085f Mon Sep 17 00:00:00 2001 From: Eric Leao <86169515+EricRLeao1311@users.noreply.github.com> Date: Wed, 18 Oct 2023 13:50:06 -0300 Subject: [PATCH 5/9] allowing None and adding return --- lib/matplotlib/hatch.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/matplotlib/hatch.py b/lib/matplotlib/hatch.py index 5e1589faf31b..81367008d3f8 100644 --- a/lib/matplotlib/hatch.py +++ b/lib/matplotlib/hatch.py @@ -188,8 +188,7 @@ def _validate_hatch_pattern(hatch): message = f"""Unknown hatch symbol(s): {invalids}. Hatch must consist of a string of {valid}""" raise ValueError(message) - else: - raise ValueError("Hatch pattern must be a string") + return hatch def get_path(hatchpattern, density=6): From 39eaaedd1a73f5b1907ea554fc78dc0edf1b0db6 Mon Sep 17 00:00:00 2001 From: Eric Leao <86169515+EricRLeao1311@users.noreply.github.com> Date: Wed, 18 Oct 2023 15:42:23 -0300 Subject: [PATCH 6/9] raising error when hatch is not string --- lib/matplotlib/hatch.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matplotlib/hatch.py b/lib/matplotlib/hatch.py index 81367008d3f8..095b179b9cea 100644 --- a/lib/matplotlib/hatch.py +++ b/lib/matplotlib/hatch.py @@ -181,6 +181,8 @@ def __init__(self, hatch, density): def _validate_hatch_pattern(hatch): valid_hatch_patterns = set(r'-+|/\xXoO.*') if hatch is not None: + if not isinstance(hatch, str): + raise ValueError("Hatch pattern must be a string") invalids = set(hatch).difference(valid_hatch_patterns) if invalids: valid = ''.join(sorted(valid_hatch_patterns)) From a1097f995abb42656a4ae8171e57c6c4a9a803e8 Mon Sep 17 00:00:00 2001 From: Eric Leao <86169515+EricRLeao1311@users.noreply.github.com> Date: Wed, 18 Oct 2023 18:16:05 -0300 Subject: [PATCH 7/9] removing 'X' from valid hatch due to test failure --- lib/matplotlib/hatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/hatch.py b/lib/matplotlib/hatch.py index 095b179b9cea..6c16f37e0f80 100644 --- a/lib/matplotlib/hatch.py +++ b/lib/matplotlib/hatch.py @@ -179,7 +179,7 @@ def __init__(self, hatch, density): def _validate_hatch_pattern(hatch): - valid_hatch_patterns = set(r'-+|/\xXoO.*') + valid_hatch_patterns = set(r'-+|/\\xoO.*') if hatch is not None: if not isinstance(hatch, str): raise ValueError("Hatch pattern must be a string") From 400ce9d0c134925328689312775e590c20b5780e Mon Sep 17 00:00:00 2001 From: Eric Leao <86169515+EricRLeao1311@users.noreply.github.com> Date: Mon, 13 Nov 2023 13:11:34 -0300 Subject: [PATCH 8/9] Addding 'X' as valid hatch --- lib/matplotlib/hatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/hatch.py b/lib/matplotlib/hatch.py index 6c16f37e0f80..992df2d90bb7 100644 --- a/lib/matplotlib/hatch.py +++ b/lib/matplotlib/hatch.py @@ -179,7 +179,7 @@ def __init__(self, hatch, density): def _validate_hatch_pattern(hatch): - valid_hatch_patterns = set(r'-+|/\\xoO.*') + valid_hatch_patterns = set(r'-+|/\\xXoO.*') if hatch is not None: if not isinstance(hatch, str): raise ValueError("Hatch pattern must be a string") From b44c281ccb2e52c611d46344079a620c98e37c4b Mon Sep 17 00:00:00 2001 From: Eric Leao <86169515+EricRLeao1311@users.noreply.github.com> Date: Tue, 14 Nov 2023 12:17:49 -0300 Subject: [PATCH 9/9] Changing test to accept X as hatch --- lib/matplotlib/tests/test_rcparams.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/tests/test_rcparams.py b/lib/matplotlib/tests/test_rcparams.py index 65cd823f13a9..4635c6b5f44e 100644 --- a/lib/matplotlib/tests/test_rcparams.py +++ b/lib/matplotlib/tests/test_rcparams.py @@ -311,10 +311,9 @@ def generate_validator_testcases(valid): }, {'validator': validate_hatch, 'success': (('--|', '--|'), ('\\oO', '\\oO'), - ('/+*/.x', '/+*/.x'), ('', '')), + ('/+*/.xX', '/+*/.xX'), ('', '')), 'fail': (('--_', ValueError), - (8, ValueError), - ('X', ValueError)), + (8, ValueError),), }, {'validator': validate_colorlist, 'success': (('r,g,b', ['r', 'g', 'b']),