Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 1 addition & 29 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,34 +47,6 @@ jobs:
fail-fast: false
matrix:
include:
- name-suffix: "(Minimum Versions)"
os: ubuntu-22.04
python-version: '3.11'
extra-requirements: '-c requirements/testing/minver.txt'
delete-font-cache: true
# https://github.com/matplotlib/matplotlib/issues/29844
pygobject-ver: '<3.52.0'
- os: ubuntu-22.04
python-version: '3.11'
CFLAGS: "-fno-lto" # Ensure that disabling LTO works.
extra-requirements: '-r requirements/testing/extra.txt'
# https://github.com/matplotlib/matplotlib/issues/29844
pygobject-ver: '<3.52.0'
- name-suffix: "(Extra TeX packages)"
os: ubuntu-22.04
python-version: '3.13'
extra-packages: 'texlive-fonts-extra texlive-lang-cyrillic'
# https://github.com/matplotlib/matplotlib/issues/29844
pygobject-ver: '<3.52.0'
- name-suffix: "Free-threaded"
os: ubuntu-22.04
python-version: '3.13t'
# https://github.com/matplotlib/matplotlib/issues/29844
pygobject-ver: '<3.52.0'
- os: ubuntu-24.04
python-version: '3.12'
- os: ubuntu-24.04
python-version: '3.14'
- os: ubuntu-24.04-arm
python-version: '3.12'
- os: macos-14 # This runner is on M1 (arm64) chips.
Expand Down Expand Up @@ -336,7 +308,7 @@ jobs:
if [[ "${{ matrix.python-version }}" == '3.13t' ]]; then
export PYTHON_GIL=0
fi
pytest -rfEsXR -n auto \
pytest -vrfEsXR -n 2 -m starts_subprocess\
--maxfail=50 --timeout=300 --durations=25 \
--cov-report=xml --cov=lib --log-level=DEBUG --color=yes

Expand Down
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ stages:

echo "##vso[task.setvariable variable=VS_COVERAGE_TOOL]$TOOL"

PYTHONFAULTHANDLER=1 pytest -rfEsXR -n 2 \
PYTHONFAULTHANDLER=1 pytest -vrfEsXR -n 2 \
--maxfail=50 --timeout=300 --durations=25 \
--junitxml=junit/test-results.xml --cov-report=xml --cov=lib

Expand Down
33 changes: 2 additions & 31 deletions lib/matplotlib/dviread.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@
import os
import re
import struct
import subprocess
import sys
from collections import namedtuple
from functools import cache, cached_property, lru_cache, partial, wraps
from functools import cached_property, lru_cache, partial, wraps
from pathlib import Path

import fontTools.agl
Expand Down Expand Up @@ -1244,31 +1243,6 @@ def _parse_enc(path):
raise ValueError(f"Failed to parse {path} as Postscript encoding")


class _LuatexKpsewhich:
@cache # A singleton.
def __new__(cls):
self = object.__new__(cls)
self._proc = self._new_proc()
return self

def _new_proc(self):
return subprocess.Popen(
["luatex", "--luaonly", str(cbook._get_data_path("kpsewhich.lua"))],
# mktexpk logs to stderr; suppress that.
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
# Store generated pk fonts in our own cache.
env={"MT_VARTEXFONTS": str(Path(mpl.get_cachedir(), "vartexfonts")),
**os.environ})

def search(self, filename):
if self._proc.poll() is not None: # Dead, restart it.
self._proc = self._new_proc()
self._proc.stdin.write(os.fsencode(filename) + b"\n")
self._proc.stdin.flush()
out = self._proc.stdout.readline().rstrip()
return None if out == b"nil" else os.fsdecode(out)


@lru_cache
def find_tex_file(filename):
"""
Expand All @@ -1295,10 +1269,7 @@ def find_tex_file(filename):
if isinstance(filename, bytes):
filename = filename.decode('utf-8', errors='replace')

try:
lk = _LuatexKpsewhich()
except FileNotFoundError:
lk = None # Fallback to directly calling kpsewhich, as below.
lk = None # Fallback to directly calling kpsewhich, as below.

if lk:
path = lk.search(filename)
Expand Down
1 change: 1 addition & 0 deletions lib/matplotlib/testing/_markers.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ def _checkdep_usetex() -> bool:
needs_usetex = pytest.mark.skipif(
not _checkdep_usetex(),
reason="This test needs a TeX installation")
starts_subprocess = pytest.mark.starts_subprocess
3 changes: 3 additions & 0 deletions lib/matplotlib/testing/conftest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import gc
import sys

import pytest
Expand All @@ -18,6 +19,7 @@ def pytest_configure(config):
("markers", "backend: Set alternate Matplotlib backend temporarily."),
("markers", "baseline_images: Compare output against references."),
("markers", "pytz: Tests that require pytz to be installed."),
("markers", "starts_subprocess: Tests that start subprocesses."),
("filterwarnings", "error"),
("filterwarnings",
"ignore:.*The py23 module has been deprecated:DeprecationWarning"),
Expand Down Expand Up @@ -81,6 +83,7 @@ def mpl_test_settings(request):
if backend is not None:
plt.close("all")
matplotlib.use(prev_backend)
gc.collect()


@pytest.fixture
Expand Down
2 changes: 2 additions & 0 deletions lib/matplotlib/tests/test_backend_inline.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import pytest

from matplotlib.testing import subprocess_run_for_testing
from matplotlib.testing._markers import starts_subprocess

nbformat = pytest.importorskip('nbformat')
pytest.importorskip('nbconvert')
pytest.importorskip('ipykernel')
pytest.importorskip('matplotlib_inline')
pytestmark = starts_subprocess


def test_ipynb():
Expand Down
2 changes: 2 additions & 0 deletions lib/matplotlib/tests/test_backend_nbagg.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
from tempfile import TemporaryDirectory

import pytest
from matplotlib.testing._markers import starts_subprocess

from matplotlib.testing import subprocess_run_for_testing

nbformat = pytest.importorskip('nbformat')
pytest.importorskip('nbconvert')
pytest.importorskip('ipykernel')
pytestmark = starts_subprocess

# From https://blog.thedataincubator.com/2016/06/testing-jupyter-notebooks/

Expand Down
2 changes: 0 additions & 2 deletions lib/matplotlib/tests/test_backend_ps.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
import matplotlib.pyplot as plt


# This tests tends to hit a TeX cache lock on AppVeyor.
@pytest.mark.flaky(reruns=3)
@pytest.mark.parametrize('papersize', ['letter', 'figure'])
@pytest.mark.parametrize('orientation', ['portrait', 'landscape'])
@pytest.mark.parametrize('format, use_log, rcParams', [
Expand Down
2 changes: 0 additions & 2 deletions lib/matplotlib/tests/test_backend_tk.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ def legitimate_quit():
@pytest.mark.skipif(platform.python_implementation() != 'CPython',
reason='PyPy does not support Tkinter threading: '
'https://foss.heptapod.net/pypy/pypy/-/issues/1929')
@pytest.mark.flaky(reruns=3)
@_isolated_tk_test(success_count=1)
def test_figuremanager_cleans_own_mainloop():
import tkinter
Expand All @@ -156,7 +155,6 @@ def target():
thread.join()


@pytest.mark.flaky(reruns=3)
@_isolated_tk_test(success_count=0)
def test_never_update():
import tkinter
Expand Down
2 changes: 2 additions & 0 deletions lib/matplotlib/tests/test_backend_webagg.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import pytest

import matplotlib.backends.backend_webagg_core
from matplotlib.testing._markers import starts_subprocess
from matplotlib.testing import subprocess_run_for_testing


@starts_subprocess
@pytest.mark.parametrize("backend", ["webagg", "nbagg"])
def test_webagg_fallback(backend):
pytest.importorskip("tornado")
Expand Down
10 changes: 6 additions & 4 deletions lib/matplotlib/tests/test_backends_interactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
from matplotlib import _c_internal_utils
from matplotlib.backend_tools import ToolToggleBase
from matplotlib.testing import subprocess_run_helper as _run_helper, is_ci_environment
from matplotlib.testing._markers import starts_subprocess


pytestmark = starts_subprocess


class _WaitForStringPopen(subprocess.Popen):
Expand Down Expand Up @@ -240,7 +244,6 @@ def check_alt_backend(alt_backend):

@pytest.mark.parametrize("env", _get_testable_interactive_backends())
@pytest.mark.parametrize("toolbar", ["toolbar2", "toolmanager"])
@pytest.mark.flaky(reruns=_retry_count)
def test_interactive_backend(env, toolbar):
if env["MPLBACKEND"] == "macosx":
if toolbar == "toolmanager":
Expand Down Expand Up @@ -335,7 +338,6 @@ def _test_thread_impl():


@pytest.mark.parametrize("env", _thread_safe_backends)
@pytest.mark.flaky(reruns=_retry_count)
def test_interactive_thread_safety(env):
proc = _run_helper(_test_thread_impl, timeout=_test_timeout, extra_env=env)
assert proc.stdout.count("CloseEvent") == 1
Expand Down Expand Up @@ -622,8 +624,6 @@ def _test_number_of_draws_script():


@pytest.mark.parametrize("env", _blit_backends)
# subprocesses can struggle to get the display, so rerun a few times
@pytest.mark.flaky(reruns=_retry_count)
def test_blitting_events(env):
proc = _run_helper(
_test_number_of_draws_script, timeout=_test_timeout, extra_env=env)
Expand Down Expand Up @@ -725,6 +725,7 @@ def interrupter():
print('SUCCESS', flush=True)


@pytest.mark.skip(reason='eliminate test from enquiries')
@pytest.mark.parametrize("env", _get_testable_interactive_backends())
@pytest.mark.parametrize("target, kwargs", [
('show', {'block': True}),
Expand Down Expand Up @@ -773,6 +774,7 @@ def custom_signal_handler(signum, frame):
print('SUCCESS', flush=True)


@pytest.mark.skip(reason='eliminate test from enquiries')
@pytest.mark.skipif(sys.platform == 'win32',
reason='No other signal available to send on Windows')
@pytest.mark.parametrize("env", _get_testable_interactive_backends())
Expand Down
2 changes: 2 additions & 0 deletions lib/matplotlib/tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import sys
import textwrap

from matplotlib.testing._markers import starts_subprocess
from matplotlib.testing import subprocess_run_for_testing


Expand All @@ -28,6 +29,7 @@ def test_override_builtins():
assert overridden <= ok_to_override


@starts_subprocess
def test_lazy_imports():
source = textwrap.dedent("""
import sys
Expand Down
6 changes: 5 additions & 1 deletion lib/matplotlib/tests/test_determinism.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@
from matplotlib.patches import Circle, PathPatch
from matplotlib.path import Path
from matplotlib.testing import subprocess_run_for_testing
from matplotlib.testing._markers import needs_ghostscript, needs_usetex
from matplotlib.testing._markers import (
needs_ghostscript, needs_usetex, starts_subprocess
)
import matplotlib.testing.compare
from matplotlib.text import TextPath
from matplotlib.transforms import IdentityTransform

pytestmark = starts_subprocess


def _save_figure(objects='mhip', fmt="pdf", usetex=False):
mpl.use(fmt)
Expand Down
2 changes: 2 additions & 0 deletions lib/matplotlib/tests/test_font_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
_get_fontconfig_fonts, _normalize_weight)
from matplotlib import cbook, ft2font, pyplot as plt, rc_context, figure as mfigure
from matplotlib.testing import subprocess_run_helper, subprocess_run_for_testing
from matplotlib.testing._markers import starts_subprocess


has_fclist = shutil.which('fc-list') is not None
Expand Down Expand Up @@ -289,6 +290,7 @@ def test_fontcache_thread_safe():
subprocess_run_helper(_test_threading, timeout=10)


@starts_subprocess
def test_lockfilefailure(tmp_path):
# The logic here:
# 1. get a temp directory from pytest
Expand Down
3 changes: 3 additions & 0 deletions lib/matplotlib/tests/test_matplotlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import matplotlib
from matplotlib.testing import subprocess_run_for_testing
from matplotlib.testing._markers import starts_subprocess


@pytest.mark.parametrize('version_str, version_tuple', [
Expand All @@ -19,6 +20,7 @@ def test_parse_to_version_info(version_str, version_tuple):
assert matplotlib._parse_to_version_info(version_str) == version_tuple


@starts_subprocess
@pytest.mark.skipif(sys.platform == "win32",
reason="chmod() doesn't work as is on Windows")
@pytest.mark.skipif(sys.platform != "win32" and os.geteuid() == 0,
Expand All @@ -37,6 +39,7 @@ def test_tmpconfigdir_warning(tmp_path):
os.chmod(tmp_path, mode)


@starts_subprocess
def test_importable_with_no_home(tmp_path):
subprocess_run_for_testing(
[sys.executable, "-c",
Expand Down
3 changes: 3 additions & 0 deletions lib/matplotlib/tests/test_preprocess_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from matplotlib.axes import Axes
from matplotlib.testing import subprocess_run_for_testing
from matplotlib.testing.decorators import check_figures_equal
from matplotlib.testing._markers import starts_subprocess


# Notes on testing the plotting functions itself
# * the individual decorated plotting functions are tested in 'test_axes.py'
Expand Down Expand Up @@ -245,6 +247,7 @@ def funcy(ax, x, y, z, t=None):
funcy.__doc__)


@starts_subprocess
def test_data_parameter_replacement():
"""
Test that the docstring contains the correct *data* parameter stub
Expand Down
3 changes: 3 additions & 0 deletions lib/matplotlib/tests/test_pyplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
from matplotlib.testing import subprocess_run_for_testing
from matplotlib import pyplot as plt

from matplotlib.testing._markers import starts_subprocess


@starts_subprocess
def test_pyplot_up_to_date(tmp_path):
pytest.importorskip("black", minversion="24.1")

Expand Down
4 changes: 4 additions & 0 deletions lib/matplotlib/tests/test_rcparams.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
_validate_linestyle,
_listify_validator)
from matplotlib.testing import subprocess_run_for_testing
from matplotlib.testing._markers import starts_subprocess


def test_rcparams(tmp_path):
Expand Down Expand Up @@ -529,6 +530,7 @@ def test_rcparams_reset_after_fail():
assert mpl.rcParams['text.usetex'] is False


@starts_subprocess
@pytest.mark.skipif(sys.platform != "linux", reason="Linux only")
def test_backend_fallback_headless_invalid_backend(tmp_path):
env = {**os.environ,
Expand All @@ -546,6 +548,7 @@ def test_backend_fallback_headless_invalid_backend(tmp_path):
env=env, check=True, stderr=subprocess.DEVNULL)


@starts_subprocess
@pytest.mark.skipif(sys.platform != "linux", reason="Linux only")
def test_backend_fallback_headless_auto_backend(tmp_path):
# specify a headless mpl environment, but request a graphical (tk) backend
Expand All @@ -568,6 +571,7 @@ def test_backend_fallback_headless_auto_backend(tmp_path):
assert backend.strip().lower() == "agg"


@starts_subprocess
@pytest.mark.skipif(
sys.platform == "linux" and not _c_internal_utils.xdisplay_is_valid(),
reason="headless")
Expand Down
Loading
Loading