From 93b08a52fedb6ae50ade5862fa087c8cc03de6e6 Mon Sep 17 00:00:00 2001 From: David Stansby Date: Thu, 10 Apr 2025 08:40:57 +0200 Subject: [PATCH 1/3] Backport PR #29745: Use PEP8 style method and function names from pyparsing * Bump minimum pyparsing version * Use PEP8 method names from pyparsing * Add api note * Clean up pyparsing<3 code * Remove unused import * Clean up pyparsing import * Sort imports (cherry picked from commit d55bddedbb0636b44804a1b2aab4fbc91dccd08b) --- .../next_api_changes/development/29745-DS.rst | 4 ++ doc/install/dependencies.rst | 4 +- environment.yml | 2 +- lib/matplotlib/_fontconfig_pattern.py | 8 +-- lib/matplotlib/_mathtext.py | 50 ++++++++----------- pyproject.toml | 4 +- requirements/testing/minver.txt | 4 +- requirements/testing/mypy.txt | 4 +- 8 files changed, 39 insertions(+), 41 deletions(-) create mode 100644 doc/api/next_api_changes/development/29745-DS.rst diff --git a/doc/api/next_api_changes/development/29745-DS.rst b/doc/api/next_api_changes/development/29745-DS.rst new file mode 100644 index 000000000000..7d9b1c2b143b --- /dev/null +++ b/doc/api/next_api_changes/development/29745-DS.rst @@ -0,0 +1,4 @@ +New minimum version of pyparsing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The minimum required version of ``pyparsing`` has been updated from 2.3.1 to 3.0.0. diff --git a/doc/install/dependencies.rst b/doc/install/dependencies.rst index c97dcdd64444..a6ef0f08ff5c 100644 --- a/doc/install/dependencies.rst +++ b/doc/install/dependencies.rst @@ -28,8 +28,8 @@ reference. * `kiwisolver `_ (>= 1.3.1) * `NumPy `_ (>= 1.23) * `packaging `_ (>= 20.0) -* `Pillow `_ (>= 8.0) -* `pyparsing `_ (>= 2.3.1) +* `Pillow `_ (>= 9.0) +* `pyparsing `_ (>= 3) .. _optional_dependencies: diff --git a/environment.yml b/environment.yml index d95cab0509ff..8b6cca1f6108 100644 --- a/environment.yml +++ b/environment.yml @@ -22,7 +22,7 @@ dependencies: - pillow>=8 - pkg-config - pygobject - - pyparsing>=2.3.1 + - pyparsing>=3 - pyqt - python>=3.10 - python-dateutil>=2.1 diff --git a/lib/matplotlib/_fontconfig_pattern.py b/lib/matplotlib/_fontconfig_pattern.py index a1341c633243..48bb2956bd7e 100644 --- a/lib/matplotlib/_fontconfig_pattern.py +++ b/lib/matplotlib/_fontconfig_pattern.py @@ -13,7 +13,7 @@ import re from pyparsing import ( - Group, Optional, ParseException, Regex, StringEnd, Suppress, ZeroOrMore, oneOf) + Group, Optional, ParseException, Regex, StringEnd, Suppress, ZeroOrMore, one_of) _family_punc = r'\\\-:,' @@ -61,7 +61,7 @@ def comma_separated(elem): size = Regex(r"([0-9]+\.?[0-9]*|\.[0-9]+)") name = Regex(r"[a-z]+") value = Regex(fr"([^{_value_punc}]|(\\[{_value_punc}]))*") - prop = Group((name + Suppress("=") + comma_separated(value)) | oneOf(_CONSTANTS)) + prop = Group((name + Suppress("=") + comma_separated(value)) | one_of(_CONSTANTS)) return ( Optional(comma_separated(family)("families")) + Optional("-" + comma_separated(size)("sizes")) @@ -82,11 +82,11 @@ def parse_fontconfig_pattern(pattern): """ parser = _make_fontconfig_parser() try: - parse = parser.parseString(pattern) + parse = parser.parse_string(pattern) except ParseException as err: # explain becomes a plain method on pyparsing 3 (err.explain(0)). raise ValueError("\n" + ParseException.explain(err, 0)) from None - parser.resetCache() + parser.reset_cache() props = {} if "families" in parse: props["family"] = [*map(_family_unescape, parse["families"])] diff --git a/lib/matplotlib/_mathtext.py b/lib/matplotlib/_mathtext.py index 9e20ea3da9b7..cf35dc1de7db 100644 --- a/lib/matplotlib/_mathtext.py +++ b/lib/matplotlib/_mathtext.py @@ -19,10 +19,10 @@ import numpy as np from pyparsing import ( - Empty, Forward, Literal, NotAny, oneOf, OneOrMore, Optional, + Empty, Forward, Literal, Group, NotAny, OneOrMore, Optional, ParseBaseException, ParseException, ParseExpression, ParseFatalException, ParserElement, ParseResults, QuotedString, Regex, StringEnd, ZeroOrMore, - pyparsing_common, Group) + pyparsing_common, nested_expr, one_of) import matplotlib as mpl from . import cbook @@ -31,18 +31,12 @@ from .font_manager import FontProperties, findfont, get_font from .ft2font import FT2Font, FT2Image, Kerning, LoadFlags -from packaging.version import parse as parse_version -from pyparsing import __version__ as pyparsing_version -if parse_version(pyparsing_version).major < 3: - from pyparsing import nestedExpr as nested_expr -else: - from pyparsing import nested_expr if T.TYPE_CHECKING: from collections.abc import Iterable from .ft2font import Glyph -ParserElement.enablePackrat() +ParserElement.enable_packrat() _log = logging.getLogger("matplotlib.mathtext") @@ -1745,7 +1739,7 @@ def Error(msg: str) -> ParserElement: def raise_error(s: str, loc: int, toks: ParseResults) -> T.Any: raise ParseFatalException(s, loc, msg) - return Empty().setParseAction(raise_error) + return Empty().set_parse_action(raise_error) class ParserState: @@ -1981,10 +1975,10 @@ def set_names_and_parse_actions() -> None: # token, placeable, and auto_delim are forward references which # are left without names to ensure useful error messages if key not in ("token", "placeable", "auto_delim"): - val.setName(key) + val.set_name(key) # Set actions if hasattr(self, key): - val.setParseAction(getattr(self, key)) + val.set_parse_action(getattr(self, key)) # Root definitions. @@ -2007,9 +2001,9 @@ def csnames(group: str, names: Iterable[str]) -> Regex: ) p.float_literal = Regex(r"[-+]?([0-9]+\.?[0-9]*|\.[0-9]+)") - p.space = oneOf(self._space_widths)("space") + p.space = one_of(self._space_widths)("space") - p.style_literal = oneOf( + p.style_literal = one_of( [str(e.value) for e in self._MathStyle])("style_literal") p.symbol = Regex( @@ -2017,14 +2011,14 @@ def csnames(group: str, names: Iterable[str]) -> Regex: r"|\\[%${}\[\]_|]" + r"|\\(?:{})(?![A-Za-z])".format( "|".join(map(re.escape, tex2uni))) - )("sym").leaveWhitespace() + )("sym").leave_whitespace() p.unknown_symbol = Regex(r"\\[A-Za-z]+")("name") p.font = csnames("font", self._fontnames) - p.start_group = Optional(r"\math" + oneOf(self._fontnames)("font")) + "{" + p.start_group = Optional(r"\math" + one_of(self._fontnames)("font")) + "{" p.end_group = Literal("}") - p.delim = oneOf(self._delims) + p.delim = one_of(self._delims) # Mutually recursive definitions. (Minimizing the number of Forward # elements is important for speed.) @@ -2085,7 +2079,7 @@ def csnames(group: str, names: Iterable[str]) -> Regex: r"\underset", p.optional_group("annotation") + p.optional_group("body")) - p.text = cmd(r"\text", QuotedString('{', '\\', endQuoteChar="}")) + p.text = cmd(r"\text", QuotedString('{', '\\', end_quote_char="}")) p.substack = cmd(r"\substack", nested_expr(opener="{", closer="}", @@ -2094,7 +2088,7 @@ def csnames(group: str, names: Iterable[str]) -> Regex: p.subsuper = ( (Optional(p.placeable)("nucleus") - + OneOrMore(oneOf(["_", "^"]) - p.placeable)("subsuper") + + OneOrMore(one_of(["_", "^"]) - p.placeable)("subsuper") + Regex("'*")("apostrophes")) | Regex("'+")("apostrophes") | (p.named_placeable("nucleus") + Regex("'*")("apostrophes")) @@ -2143,8 +2137,8 @@ def csnames(group: str, names: Iterable[str]) -> Regex: # Leaf definitions. p.math = OneOrMore(p.token) - p.math_string = QuotedString('$', '\\', unquoteResults=False) - p.non_math = Regex(r"(?:(?:\\[$])|[^$])*").leaveWhitespace() + p.math_string = QuotedString('$', '\\', unquote_results=False) + p.non_math = Regex(r"(?:(?:\\[$])|[^$])*").leave_whitespace() p.main = ( p.non_math + ZeroOrMore(p.math_string + p.non_math) + StringEnd() ) @@ -2167,7 +2161,7 @@ def parse(self, s: str, fonts_object: Fonts, fontsize: float, dpi: float) -> Hli ParserState(fonts_object, 'default', 'rm', fontsize, dpi)] self._em_width_cache: dict[tuple[str, float, float], float] = {} try: - result = self._expression.parseString(s) + result = self._expression.parse_string(s) except ParseBaseException as err: # explain becomes a plain method on pyparsing 3 (err.explain(0)). raise ValueError("\n" + ParseException.explain(err, 0)) from None @@ -2175,7 +2169,7 @@ def parse(self, s: str, fonts_object: Fonts, fontsize: float, dpi: float) -> Hli self._in_subscript_or_superscript = False # prevent operator spacing from leaking into a new expression self._em_width_cache = {} - ParserElement.resetCache() + ParserElement.reset_cache() return T.cast(Hlist, result[0]) # Known return type from main. def get_state(self) -> ParserState: @@ -2191,13 +2185,13 @@ def push_state(self) -> None: self._state_stack.append(self.get_state().copy()) def main(self, toks: ParseResults) -> list[Hlist]: - return [Hlist(toks.asList())] + return [Hlist(toks.as_list())] def math_string(self, toks: ParseResults) -> ParseResults: - return self._math_expression.parseString(toks[0][1:-1], parseAll=True) + return self._math_expression.parse_string(toks[0][1:-1], parse_all=True) def math(self, toks: ParseResults) -> T.Any: - hlist = Hlist(toks.asList()) + hlist = Hlist(toks.as_list()) self.pop_state() return [hlist] @@ -2210,7 +2204,7 @@ def non_math(self, toks: ParseResults) -> T.Any: self.get_state().font = mpl.rcParams['mathtext.default'] return [hlist] - float_literal = staticmethod(pyparsing_common.convertToFloat) + float_literal = staticmethod(pyparsing_common.convert_to_float) def text(self, toks: ParseResults) -> T.Any: self.push_state() @@ -2809,7 +2803,7 @@ def auto_delim(self, toks: ParseResults) -> T.Any: return self._auto_sized_delimiter( toks["left"], # if "mid" in toks ... can be removed when requiring pyparsing 3. - toks["mid"].asList() if "mid" in toks else [], + toks["mid"].as_list() if "mid" in toks else [], toks["right"]) def boldsymbol(self, toks: ParseResults) -> T.Any: diff --git a/pyproject.toml b/pyproject.toml index e6d1abaf530b..8396fdb59845 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,8 +37,8 @@ dependencies = [ "kiwisolver >= 1.3.1", "numpy >= 1.23", "packaging >= 20.0", - "pillow >= 8", - "pyparsing >= 2.3.1", + "pillow >= 9", + "pyparsing >= 3", "python-dateutil >= 2.7", ] # Also keep in sync with find_program of meson.build. diff --git a/requirements/testing/minver.txt b/requirements/testing/minver.txt index d30ebf08f04b..5f9a52afcee9 100644 --- a/requirements/testing/minver.txt +++ b/requirements/testing/minver.txt @@ -9,8 +9,8 @@ meson-python==0.13.1 meson==1.1.0 numpy==1.23.0 packaging==20.0 -pillow==8.3.2 -pyparsing==2.3.1 +pillow==9.0.1 +pyparsing==3.0.0 pytest==7.0.0 python-dateutil==2.7 diff --git a/requirements/testing/mypy.txt b/requirements/testing/mypy.txt index aa20581ee69b..343517263f40 100644 --- a/requirements/testing/mypy.txt +++ b/requirements/testing/mypy.txt @@ -19,8 +19,8 @@ cycler>=0.10 fonttools>=4.22.0 kiwisolver>=1.3.1 packaging>=20.0 -pillow>=8 -pyparsing>=2.3.1 +pillow>=9 +pyparsing>=3 python-dateutil>=2.7 setuptools_scm>=7 setuptools>=64 From 2bff898d4726f9f1489500b549484b2cfc9bb686 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Tue, 30 Sep 2025 07:05:12 +0200 Subject: [PATCH 2/3] Remove erroneous pillow bump Co-authored-by: Thomas A Caswell --- doc/install/dependencies.rst | 2 +- requirements/testing/minver.txt | 2 +- requirements/testing/mypy.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/install/dependencies.rst b/doc/install/dependencies.rst index a6ef0f08ff5c..95d170a06b00 100644 --- a/doc/install/dependencies.rst +++ b/doc/install/dependencies.rst @@ -28,7 +28,7 @@ reference. * `kiwisolver `_ (>= 1.3.1) * `NumPy `_ (>= 1.23) * `packaging `_ (>= 20.0) -* `Pillow `_ (>= 9.0) +* `Pillow `_ (>= 8.0) * `pyparsing `_ (>= 3) diff --git a/requirements/testing/minver.txt b/requirements/testing/minver.txt index 5f9a52afcee9..8ecd075fb64b 100644 --- a/requirements/testing/minver.txt +++ b/requirements/testing/minver.txt @@ -9,7 +9,7 @@ meson-python==0.13.1 meson==1.1.0 numpy==1.23.0 packaging==20.0 -pillow==9.0.1 +pillow==8.3.2 pyparsing==3.0.0 pytest==7.0.0 python-dateutil==2.7 diff --git a/requirements/testing/mypy.txt b/requirements/testing/mypy.txt index 343517263f40..0cef979a34bf 100644 --- a/requirements/testing/mypy.txt +++ b/requirements/testing/mypy.txt @@ -19,7 +19,7 @@ cycler>=0.10 fonttools>=4.22.0 kiwisolver>=1.3.1 packaging>=20.0 -pillow>=9 +pillow>=8 pyparsing>=3 python-dateutil>=2.7 setuptools_scm>=7 From b4b943d4001737d506071b07c2f97782ac3bb116 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Tue, 30 Sep 2025 17:18:31 +0200 Subject: [PATCH 3/3] Update pyproject.toml Co-authored-by: Elliott Sales de Andrade --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 8396fdb59845..25f4ce8d4948 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ dependencies = [ "kiwisolver >= 1.3.1", "numpy >= 1.23", "packaging >= 20.0", - "pillow >= 9", + "pillow >= 8", "pyparsing >= 3", "python-dateutil >= 2.7", ]