diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 282b015fcbf1..ea402d954137 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -84,8 +84,10 @@ jobs:
pyqt6-ver: '!=6.6.0'
# https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-2346
pyside6-ver: '!=6.5.1'
- - os: macos-13 # This runner is on Intel chips.
+ - os: macos-14 # This runner is on M1 (arm64) chips.
python-version: '3.10'
+ # https://github.com/matplotlib/matplotlib/issues/29732
+ pygobject-ver: '<3.52.0'
# https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-2346
pyside6-ver: '!=6.5.1'
- os: macos-14 # This runner is on M1 (arm64) chips.
@@ -94,7 +96,7 @@ jobs:
pygobject-ver: '<3.52.0'
# https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-2346
pyside6-ver: '!=6.5.1'
- - os: macos-14 # This runner is on M1 (arm64) chips.
+ - os: macos-15 # This runner is on M1 (arm64) chips.
python-version: '3.13'
# https://github.com/matplotlib/matplotlib/issues/29732
pygobject-ver: '<3.52.0'
diff --git a/doc/_static/zenodo_cache/16999430.svg b/doc/_static/zenodo_cache/16999430.svg
new file mode 100644
index 000000000000..44c448643e91
--- /dev/null
+++ b/doc/_static/zenodo_cache/16999430.svg
@@ -0,0 +1,35 @@
+
\ No newline at end of file
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 3034a64a3361..95d170a06b00 100644
--- a/doc/install/dependencies.rst
+++ b/doc/install/dependencies.rst
@@ -29,7 +29,7 @@ reference.
* `NumPy `_ (>= 1.23)
* `packaging `_ (>= 20.0)
* `Pillow `_ (>= 8.0)
-* `pyparsing `_ (>= 2.3.1)
+* `pyparsing `_ (>= 3)
.. _optional_dependencies:
@@ -370,7 +370,7 @@ them will be skipped by pytest.
.. _pandas: https://pypi.org/project/pandas/
.. _pikepdf: https://pypi.org/project/pikepdf/
.. _psutil: https://pypi.org/project/psutil/
-.. _pytz: https://fonts.google.com/noto/use#faq
+.. _pytz: https://pypi.org/project/pytz/
.. _pytest-cov: https://pytest-cov.readthedocs.io/en/latest/
.. _pytest-flake8: https://pypi.org/project/pytest-flake8/
.. _pytest-timeout: https://pypi.org/project/pytest-timeout/
diff --git a/doc/project/citing.rst b/doc/project/citing.rst
index 249f568625db..ae2061e7349c 100644
--- a/doc/project/citing.rst
+++ b/doc/project/citing.rst
@@ -32,6 +32,9 @@ By version
.. START OF AUTOGENERATED
+v3.10.6
+ .. image:: ../_static/zenodo_cache/16999430.svg
+ :target: https://doi.org/10.5281/zenodo.16999430
v3.10.5
.. image:: ../_static/zenodo_cache/16644850.svg
:target: https://doi.org/10.5281/zenodo.16644850
diff --git a/doc/users/github_stats.rst b/doc/users/github_stats.rst
index 84c2cc5867fd..c40bedb4cb5b 100644
--- a/doc/users/github_stats.rst
+++ b/doc/users/github_stats.rst
@@ -1,23 +1,23 @@
.. _github-stats:
-GitHub statistics for 3.10.6 (Aug 29, 2025)
+GitHub statistics for 3.10.7 (Oct 08, 2025)
===========================================
-GitHub statistics for 2024/12/14 (tag: v3.10.0) - 2025/08/29
+GitHub statistics for 2024/12/14 (tag: v3.10.0) - 2025/10/08
These lists are automatically generated, and may be incomplete or contain duplicates.
-We closed 4 issues and merged 19 pull requests.
-The full list can be seen `on GitHub `__
+We closed 4 issues and merged 16 pull requests.
+The full list can be seen `on GitHub `__
-The following 31 authors contributed 380 commits.
+The following 32 authors contributed 422 commits.
-* Alan Burlot
+* Aasma Gupta
+* AASMA GUPTA
* Antony Lee
* Christine P. Chai
* David Stansby
* dependabot[bot]
-* Doron Behar
* Elliott Sales de Andrade
* G.D. McBain
* Greg Lucas
@@ -41,39 +41,37 @@ The following 31 authors contributed 380 commits.
* saikarna913
* Scott Shambaugh
* Thomas A Caswell
+* Tim Heap
* Tim Hoffmann
* Trygve Magnus Ræder
GitHub issues and pull requests:
-Pull Requests (19):
+Pull Requests (16):
-* :ghpull:`30487`: Backport PR #30484 on branch v3.10.x (FIX: be more cautious about checking widget size)
-* :ghpull:`30484`: FIX: be more cautious about checking widget size
-* :ghpull:`30481`: Backport PR #30394 on branch v3.10.x (ENH: Gracefully handle python-build-standalone ImportError with Tk)
-* :ghpull:`30477`: Backport PR #30476 on branch v3.10.x (ci: Remove cibuildwheel override for win_arm64/Py3.14)
-* :ghpull:`30394`: ENH: Gracefully handle python-build-standalone ImportError with Tk
-* :ghpull:`30476`: ci: Remove cibuildwheel override for win_arm64/Py3.14
-* :ghpull:`30461`: Backport PR #30451 on branch v3.10.x (doc: factor out quick install tab for reuse)
-* :ghpull:`30448`: Backport PR #30412 on branch v3.10.x ({Check,Radio}Buttons: Improve docs of label_props)
-* :ghpull:`30412`: {Check,Radio}Buttons: Improve docs of label_props
-* :ghpull:`30445`: Backport PR #30444 on branch v3.10.x (Small correction of a typo in the galleries: axis instead of axes)
-* :ghpull:`30444`: Small correction of a typo in the galleries: axis instead of axes
-* :ghpull:`30430`: Backport PR #30426 on branch v3.10.x (Fix a race condition in TexManager.make_dvi.)
-* :ghpull:`30434`: Backport PR #30426: Fix a race condition in TexManager.make_dvi & make_png.
-* :ghpull:`30431`: Use pathlib in texmanager.
-* :ghpull:`30428`: Backport PR #30399 on branch v3.10.x (Qt: Fix HiDPI handling on X11/Windows)
-* :ghpull:`30426`: Fix a race condition in TexManager.make_dvi.
-* :ghpull:`30399`: Qt: Fix HiDPI handling on X11/Windows
-* :ghpull:`30415`: Backport PR #30414 on branch v3.10.x (DOC: update Cartopy url)
-* :ghpull:`30414`: DOC: update Cartopy url
+* :ghpull:`30628`: Backport PR #30626 on branch v3.10.x (MNT: Fix new F401 unused imports warnings)
+* :ghpull:`30626`: MNT: Fix new F401 unused imports warnings
+* :ghpull:`30589`: Backport PR #29745: Use PEP8 style method and function names from
+* :ghpull:`30614`: Backport PR #30612 on branch v3.10.x (MNT: update black pin)
+* :ghpull:`30612`: MNT: update black pin
+* :ghpull:`30572`: Backport PR #30571 on branch v3.10.x (CI: remove macos13)
+* :ghpull:`30571`: CI: remove macos13
+* :ghpull:`30570`: Backport PR #30558 on branch v3.10.x (Fix stubtest with mypy 18)
+* :ghpull:`30558`: Fix stubtest with mypy 18
+* :ghpull:`30540`: Backport PR #30539 on branch v3.10.x (Fix scale_unit/scale_units typo in quiver docs)
+* :ghpull:`30539`: Fix scale_unit/scale_units typo in quiver docs
+* :ghpull:`30518`: Backport PR #30497 on branch v3.10.x (TST: Use a temporary directory for test_save_figure_return)
+* :ghpull:`30497`: TST: Use a temporary directory for test_save_figure_return
+* :ghpull:`30506`: Backport PR #30490 on branch v3.10.x (Fix SVG rendering error in def update_background)
+* :ghpull:`30490`: Fix SVG rendering error in def update_background
+* :ghpull:`30494`: Backport PR #30492 on branch v3.10.x (DOC: pytz link should be from PyPI)
Issues (4):
-* :ghissue:`29618`: [Bug]: FigureCanvasQT is seemingly prematurely freed under certain conditions
-* :ghissue:`30390`: [ENH]: Gracefully handle python-build-standalone ImportError
-* :ghissue:`30420`: [ENH]: Support parallel plotting
-* :ghissue:`30386`: BUG: Qt hi-dpi regression on windows and X11 with mpl 3.10.5
+* :ghissue:`30611`: [MNT]: black version
+* :ghissue:`30551`: [Bug]: Mypy stubtest failure on disjoint_base
+* :ghissue:`30493`: [Bug]: test_save_figure_return seems flaky
+* :ghissue:`30485`: [Bug]: figures with SpanSelector(..., useblit=True) can't be saved to SVG or PDF
Previous GitHub statistics
diff --git a/doc/users/prev_whats_new/github_stats_3.10.6.rst b/doc/users/prev_whats_new/github_stats_3.10.6.rst
new file mode 100644
index 000000000000..fb88af0ae10f
--- /dev/null
+++ b/doc/users/prev_whats_new/github_stats_3.10.6.rst
@@ -0,0 +1,76 @@
+.. _github-stats-3_10_6:
+
+GitHub statistics for 3.10.6 (Aug 29, 2025)
+===========================================
+
+GitHub statistics for 2024/12/14 (tag: v3.10.0) - 2025/08/29
+
+These lists are automatically generated, and may be incomplete or contain duplicates.
+
+We closed 4 issues and merged 19 pull requests.
+The full list can be seen `on GitHub `__
+
+The following 31 authors contributed 380 commits.
+
+* Alan Burlot
+* Antony Lee
+* Christine P. Chai
+* David Stansby
+* dependabot[bot]
+* Doron Behar
+* Elliott Sales de Andrade
+* G.D. McBain
+* Greg Lucas
+* hannah
+* hu-xiaonan
+* Ian Thomas
+* Inês Cachola
+* Jody Klymak
+* Jouni K. Seppänen
+* Khushi_29
+* Kyle Sunden
+* Lumberbot (aka Jack)
+* N R Navaneet
+* Nathan G. Wiseman
+* Oscar Gustafsson
+* Praful Gulani
+* Qian Zhang
+* Raphael Erik Hviding
+* Roman
+* Ruth Comer
+* saikarna913
+* Scott Shambaugh
+* Thomas A Caswell
+* Tim Hoffmann
+* Trygve Magnus Ræder
+
+GitHub issues and pull requests:
+
+Pull Requests (19):
+
+* :ghpull:`30487`: Backport PR #30484 on branch v3.10.x (FIX: be more cautious about checking widget size)
+* :ghpull:`30484`: FIX: be more cautious about checking widget size
+* :ghpull:`30481`: Backport PR #30394 on branch v3.10.x (ENH: Gracefully handle python-build-standalone ImportError with Tk)
+* :ghpull:`30477`: Backport PR #30476 on branch v3.10.x (ci: Remove cibuildwheel override for win_arm64/Py3.14)
+* :ghpull:`30394`: ENH: Gracefully handle python-build-standalone ImportError with Tk
+* :ghpull:`30476`: ci: Remove cibuildwheel override for win_arm64/Py3.14
+* :ghpull:`30461`: Backport PR #30451 on branch v3.10.x (doc: factor out quick install tab for reuse)
+* :ghpull:`30448`: Backport PR #30412 on branch v3.10.x ({Check,Radio}Buttons: Improve docs of label_props)
+* :ghpull:`30412`: {Check,Radio}Buttons: Improve docs of label_props
+* :ghpull:`30445`: Backport PR #30444 on branch v3.10.x (Small correction of a typo in the galleries: axis instead of axes)
+* :ghpull:`30444`: Small correction of a typo in the galleries: axis instead of axes
+* :ghpull:`30430`: Backport PR #30426 on branch v3.10.x (Fix a race condition in TexManager.make_dvi.)
+* :ghpull:`30434`: Backport PR #30426: Fix a race condition in TexManager.make_dvi & make_png.
+* :ghpull:`30431`: Use pathlib in texmanager.
+* :ghpull:`30428`: Backport PR #30399 on branch v3.10.x (Qt: Fix HiDPI handling on X11/Windows)
+* :ghpull:`30426`: Fix a race condition in TexManager.make_dvi.
+* :ghpull:`30399`: Qt: Fix HiDPI handling on X11/Windows
+* :ghpull:`30415`: Backport PR #30414 on branch v3.10.x (DOC: update Cartopy url)
+* :ghpull:`30414`: DOC: update Cartopy url
+
+Issues (4):
+
+* :ghissue:`29618`: [Bug]: FigureCanvasQT is seemingly prematurely freed under certain conditions
+* :ghissue:`30390`: [ENH]: Gracefully handle python-build-standalone ImportError
+* :ghissue:`30420`: [ENH]: Support parallel plotting
+* :ghissue:`30386`: BUG: Qt hi-dpi regression on windows and X11 with mpl 3.10.5
diff --git a/environment.yml b/environment.yml
index d95cab0509ff..2a4f3eff69ea 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
@@ -51,7 +51,7 @@ dependencies:
- sphinxcontrib-video>=0.2.1
- pikepdf
# testing
- - black<24
+ - black<26
- coverage
- flake8>=3.8,<7.2
- flake8-docstrings>=1.4.0
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/lib/matplotlib/backends/backend_webagg.py b/lib/matplotlib/backends/backend_webagg.py
index dfc5747ef77c..e4808e8d0d32 100644
--- a/lib/matplotlib/backends/backend_webagg.py
+++ b/lib/matplotlib/backends/backend_webagg.py
@@ -21,14 +21,12 @@
import threading
try:
- import tornado
+ import tornado.web
+ import tornado.ioloop
+ import tornado.websocket
except ImportError as err:
raise RuntimeError("The WebAgg backend requires Tornado.") from err
-import tornado.web
-import tornado.ioloop
-import tornado.websocket
-
import matplotlib as mpl
from matplotlib.backend_bases import _Backend
from matplotlib._pylab_helpers import Gcf
diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py
index f83a69d8361e..027000c1d78c 100644
--- a/lib/matplotlib/backends/backend_wx.py
+++ b/lib/matplotlib/backends/backend_wx.py
@@ -30,7 +30,7 @@
from matplotlib.transforms import Affine2D
import wx
-import wx.svg
+import wx.svg # noqa: F401
_log = logging.getLogger(__name__)
diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py
index 2dd8e76d98b4..562fc02715ec 100644
--- a/lib/matplotlib/pyplot.py
+++ b/lib/matplotlib/pyplot.py
@@ -54,7 +54,6 @@
from cycler import cycler # noqa: F401
import matplotlib
-import matplotlib.colorbar
import matplotlib.image
from matplotlib import _api
# Re-exported (import x as x) for typing.
@@ -3145,8 +3144,9 @@ def cohere(
NFFT: int = 256,
Fs: float = 2,
Fc: int = 0,
- detrend: Literal["none", "mean", "linear"]
- | Callable[[ArrayLike], ArrayLike] = mlab.detrend_none,
+ detrend: (
+ Literal["none", "mean", "linear"] | Callable[[ArrayLike], ArrayLike]
+ ) = mlab.detrend_none,
window: Callable[[ArrayLike], ArrayLike] | ArrayLike = mlab.window_hanning,
noverlap: int = 0,
pad_to: int | None = None,
@@ -3203,9 +3203,9 @@ def csd(
NFFT: int | None = None,
Fs: float | None = None,
Fc: int | None = None,
- detrend: Literal["none", "mean", "linear"]
- | Callable[[ArrayLike], ArrayLike]
- | None = None,
+ detrend: (
+ Literal["none", "mean", "linear"] | Callable[[ArrayLike], ArrayLike] | None
+ ) = None,
window: Callable[[ArrayLike], ArrayLike] | ArrayLike | None = None,
noverlap: int | None = None,
pad_to: int | None = None,
@@ -3876,9 +3876,9 @@ def psd(
NFFT: int | None = None,
Fs: float | None = None,
Fc: int | None = None,
- detrend: Literal["none", "mean", "linear"]
- | Callable[[ArrayLike], ArrayLike]
- | None = None,
+ detrend: (
+ Literal["none", "mean", "linear"] | Callable[[ArrayLike], ArrayLike] | None
+ ) = None,
window: Callable[[ArrayLike], ArrayLike] | ArrayLike | None = None,
noverlap: int | None = None,
pad_to: int | None = None,
@@ -3986,9 +3986,9 @@ def specgram(
NFFT: int | None = None,
Fs: float | None = None,
Fc: int | None = None,
- detrend: Literal["none", "mean", "linear"]
- | Callable[[ArrayLike], ArrayLike]
- | None = None,
+ detrend: (
+ Literal["none", "mean", "linear"] | Callable[[ArrayLike], ArrayLike] | None
+ ) = None,
window: Callable[[ArrayLike], ArrayLike] | ArrayLike | None = None,
noverlap: int | None = None,
cmap: str | Colormap | None = None,
@@ -4299,10 +4299,9 @@ def violinplot(
showmedians: bool = False,
quantiles: Sequence[float | Sequence[float]] | None = None,
points: int = 100,
- bw_method: Literal["scott", "silverman"]
- | float
- | Callable[[GaussianKDE], float]
- | None = None,
+ bw_method: (
+ Literal["scott", "silverman"] | float | Callable[[GaussianKDE], float] | None
+ ) = None,
side: Literal["both", "low", "high"] = "both",
*,
data=None,
diff --git a/lib/matplotlib/quiver.py b/lib/matplotlib/quiver.py
index e66f1f97b21f..b9963b0e1716 100644
--- a/lib/matplotlib/quiver.py
+++ b/lib/matplotlib/quiver.py
@@ -144,7 +144,7 @@
length in y direction = $\\frac{v}{\\mathrm{scale}} \\mathrm{scale_unit}$
- For example, ``(u, v) = (0.5, 0)`` with ``scale=10, scale_unit="width"`` results
+ For example, ``(u, v) = (0.5, 0)`` with ``scale=10, scale_units="width"`` results
in a horizontal arrow with a length of *0.5 / 10 * "width"*, i.e. 0.05 times the
Axes width.
diff --git a/lib/matplotlib/tests/test_backend_qt.py b/lib/matplotlib/tests/test_backend_qt.py
index 962f5ce94206..1012b16f0212 100644
--- a/lib/matplotlib/tests/test_backend_qt.py
+++ b/lib/matplotlib/tests/test_backend_qt.py
@@ -219,14 +219,15 @@ def test_figureoptions():
@pytest.mark.backend('QtAgg', skip_on_importerror=True)
-def test_save_figure_return():
+def test_save_figure_return(tmp_path):
fig, ax = plt.subplots()
ax.imshow([[1]])
+ expected = tmp_path / "foobar.png"
prop = "matplotlib.backends.qt_compat.QtWidgets.QFileDialog.getSaveFileName"
- with mock.patch(prop, return_value=("foobar.png", None)):
+ with mock.patch(prop, return_value=(str(expected), None)):
fname = fig.canvas.manager.toolbar.save_figure()
- os.remove("foobar.png")
- assert fname == "foobar.png"
+ assert fname == str(expected)
+ assert expected.exists()
with mock.patch(prop, return_value=(None, None)):
fname = fig.canvas.manager.toolbar.save_figure()
assert fname is None
diff --git a/lib/matplotlib/tests/test_pyplot.py b/lib/matplotlib/tests/test_pyplot.py
index 1aaa8dd93ca2..46bd6e456d32 100644
--- a/lib/matplotlib/tests/test_pyplot.py
+++ b/lib/matplotlib/tests/test_pyplot.py
@@ -12,7 +12,7 @@
def test_pyplot_up_to_date(tmp_path):
- pytest.importorskip("black")
+ pytest.importorskip("black", minversion="24.1")
gen_script = Path(mpl.__file__).parents[2] / "tools/boilerplate.py"
if not gen_script.exists():
diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py
index 631ada38027a..6a3c0d684380 100644
--- a/lib/matplotlib/widgets.py
+++ b/lib/matplotlib/widgets.py
@@ -2157,6 +2157,8 @@ def update_background(self, event):
# `release` can call a draw event even when `ignore` is True.
if not self.useblit:
return
+ if self.canvas.is_saving():
+ return # saving does not use blitting
# Make sure that widget artists don't get accidentally included in the
# background, by re-rendering the background if needed (and then
# re-re-rendering the canvas with the visible widget artists).
diff --git a/pyproject.toml b/pyproject.toml
index e6d1abaf530b..25f4ce8d4948 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -38,7 +38,7 @@ dependencies = [
"numpy >= 1.23",
"packaging >= 20.0",
"pillow >= 8",
- "pyparsing >= 2.3.1",
+ "pyparsing >= 3",
"python-dateutil >= 2.7",
]
# Also keep in sync with find_program of meson.build.
diff --git a/requirements/testing/all.txt b/requirements/testing/all.txt
index a41073bdf47e..dd1dbf3f29fd 100644
--- a/requirements/testing/all.txt
+++ b/requirements/testing/all.txt
@@ -1,6 +1,6 @@
# pip requirements for all the CI builds
-black<24
+black<26
certifi
coverage!=6.3
psutil
diff --git a/requirements/testing/minver.txt b/requirements/testing/minver.txt
index d30ebf08f04b..8ecd075fb64b 100644
--- a/requirements/testing/minver.txt
+++ b/requirements/testing/minver.txt
@@ -10,7 +10,7 @@ meson==1.1.0
numpy==1.23.0
packaging==20.0
pillow==8.3.2
-pyparsing==2.3.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..0cef979a34bf 100644
--- a/requirements/testing/mypy.txt
+++ b/requirements/testing/mypy.txt
@@ -20,7 +20,7 @@ fonttools>=4.22.0
kiwisolver>=1.3.1
packaging>=20.0
pillow>=8
-pyparsing>=2.3.1
+pyparsing>=3
python-dateutil>=2.7
setuptools_scm>=7
setuptools>=64
diff --git a/tools/cache_zenodo_svg.py b/tools/cache_zenodo_svg.py
index 59d6fce55162..c6783dd9f19d 100644
--- a/tools/cache_zenodo_svg.py
+++ b/tools/cache_zenodo_svg.py
@@ -63,6 +63,7 @@ def _get_xdg_cache_dir():
if __name__ == "__main__":
data = {
+ "v3.10.6": "16999430",
"v3.10.5": "16644850",
"v3.10.3": "15375714",
"v3.10.1": "14940554",
diff --git a/tools/stubtest.py b/tools/stubtest.py
index b79ab2f40dd0..d73d966de19e 100644
--- a/tools/stubtest.py
+++ b/tools/stubtest.py
@@ -108,6 +108,7 @@ def visit_ClassDef(self, node):
[
"stubtest",
"--mypy-config-file=pyproject.toml",
+ "--ignore-disjoint-bases",
"--allowlist=ci/mypy-stubtest-allowlist.txt",
f"--allowlist={p}",
"matplotlib",