Esempio n. 1
0
def _isolated_tk_test(success_count, func=None):
    """
    A decorator to run *func* in a subprocess and assert that it prints
    "success" *success_count* times and nothing on stderr.

    TkAgg tests seem to have interactions between tests, so isolate each test
    in a subprocess. See GH#18261
    """

    if func is None:
        return functools.partial(_isolated_tk_test, success_count)

    if "MPL_TEST_ESCAPE_HATCH" in os.environ:
        # set in subprocess_run_helper() below
        return func

    @pytest.mark.skipif(
        not importlib.util.find_spec('tkinter'),
        reason="missing tkinter"
    )
    @pytest.mark.skipif(
        sys.platform == "linux" and not _c_internal_utils.display_is_valid(),
        reason="$DISPLAY and $WAYLAND_DISPLAY are unset"
    )
    @pytest.mark.xfail(  # GitHub issue #23094
        sys.platform == 'darwin',
        reason="Tk version mismatch on OSX CI"
    )
    @functools.wraps(func)
    def test_func():
        # even if the package exists, may not actually be importable this can
        # be the case on some CI systems.
        pytest.importorskip('tkinter')
        try:
            proc = subprocess_run_helper(
                func, timeout=_test_timeout, extra_env=dict(
                    MPLBACKEND="TkAgg", MPL_TEST_ESCAPE_HATCH="1"))
        except subprocess.TimeoutExpired:
            pytest.fail("Subprocess timed out")
        except subprocess.CalledProcessError as e:
            pytest.fail("Subprocess failed to test intended behavior\n"
                        + str(e.stderr))
        else:
            # macOS may actually emit irrelevant errors about Accelerated
            # OpenGL vs. software OpenGL, so suppress them.
            # Asserting stderr first (and printing it on failure) should be
            # more helpful for debugging that printing a failed success count.
            assert not [line for line in proc.stderr.splitlines()
                        if "OpenGL" not in line]
            assert proc.stdout.count("success") == success_count

    return test_func
def _get_testable_interactive_backends():
    envs = []
    for deps, env in [
            *[([qt_api], {
                "MPLBACKEND": "qtagg",
                "QT_API": qt_api
            }) for qt_api in ["PyQt6", "PySide6", "PyQt5", "PySide2"]],
            *[([qt_api, "cairocffi"], {
                "MPLBACKEND": "qtcairo",
                "QT_API": qt_api
            }) for qt_api in ["PyQt6", "PySide6", "PyQt5", "PySide2"]],
            *[(["cairo", "gi"], {
                "MPLBACKEND": f"gtk{version}{renderer}"
            }) for version in [3, 4] for renderer in ["agg", "cairo"]],
        (["tkinter"], {
            "MPLBACKEND": "tkagg"
        }),
        (["wx"], {
            "MPLBACKEND": "wx"
        }),
        (["wx"], {
            "MPLBACKEND": "wxagg"
        }),
        (["matplotlib.backends._macosx"], {
            "MPLBACKEND": "macosx"
        }),
    ]:
        reason = None
        missing = [dep for dep in deps if not importlib.util.find_spec(dep)]
        if (sys.platform == "linux"
                and not _c_internal_utils.display_is_valid()):
            reason = "$DISPLAY and $WAYLAND_DISPLAY are unset"
        elif missing:
            reason = "{} cannot be imported".format(", ".join(missing))
        elif env["MPLBACKEND"] == 'macosx' and os.environ.get('TF_BUILD'):
            reason = "macosx backend fails on Azure"
        elif env["MPLBACKEND"].startswith('gtk'):
            import gi
            version = env["MPLBACKEND"][3]
            repo = gi.Repository.get_default()
            if f'{version}.0' not in repo.enumerate_versions('Gtk'):
                reason = "no usable GTK bindings"
        marks = []
        if reason:
            marks.append(
                pytest.mark.skip(reason=f"Skipping {env} because {reason}"))
        elif env["MPLBACKEND"].startswith('wx') and sys.platform == 'darwin':
            # ignore on OSX because that's currently broken (github #16849)
            marks.append(pytest.mark.xfail(reason='github #16849'))
        envs.append(pytest.param(env, marks=marks, id=str(env)))
    return envs
def _get_testable_interactive_backends():
    try:
        from matplotlib.backends.qt_compat import QtGui  # noqa
        have_qt5 = True
    except ImportError:
        have_qt5 = False

    backends = []
    for deps, backend in [
            (["cairo", "gi"], "gtk3agg"),
            (["cairo", "gi"], "gtk3cairo"),
            (["PyQt5"], "qt5agg"),
            (["PyQt5", "cairocffi"], "qt5cairo"),
            (["PySide2"], "qt5agg"),
            (["PySide2", "cairocffi"], "qt5cairo"),
            (["tkinter"], "tkagg"),
            (["wx"], "wx"),
            (["wx"], "wxagg"),
            (["matplotlib.backends._macosx"], "macosx"),
    ]:
        reason = None
        missing = [dep for dep in deps if not importlib.util.find_spec(dep)]
        if (sys.platform == "linux" and
                not _c_internal_utils.display_is_valid()):
            reason = "$DISPLAY and $WAYLAND_DISPLAY are unset"
        elif missing:
            reason = "{} cannot be imported".format(", ".join(missing))
        elif backend == 'macosx' and os.environ.get('TF_BUILD'):
            reason = "macosx backend fails on Azure"
        elif 'qt5' in backend and not have_qt5:
            reason = "no usable Qt5 bindings"
        if reason:
            backend = pytest.param(
                backend,
                marks=pytest.mark.skip(
                    reason=f"Skipping {backend} because {reason}"))
        elif backend.startswith('wx') and sys.platform == 'darwin':
            # ignore on OSX because that's currently broken (github #16849)
            backend = pytest.param(
                backend,
                marks=pytest.mark.xfail(reason='github #16849'))
        backends.append(backend)
    return backends
Esempio n. 4
0
def _get_testable_qt_backends():
    envs = []
    for deps, env in [([qt_api], {
            "MPLBACKEND": "qtagg",
            "QT_API": qt_api
    }) for qt_api in ["PyQt6", "PySide6", "PyQt5", "PySide2"]]:
        reason = None
        missing = [dep for dep in deps if not importlib.util.find_spec(dep)]
        if (sys.platform == "linux"
                and not _c_internal_utils.display_is_valid()):
            reason = "$DISPLAY and $WAYLAND_DISPLAY are unset"
        elif missing:
            reason = "{} cannot be imported".format(", ".join(missing))
        elif env["MPLBACKEND"] == 'macosx' and os.environ.get('TF_BUILD'):
            reason = "macosx backend fails on Azure"
        marks = []
        if reason:
            marks.append(
                pytest.mark.skip(reason=f"Skipping {env} because {reason}"))
        envs.append(pytest.param(env, marks=marks, id=str(env)))
    return envs
Esempio n. 5
0
        "WAYLAND_DISPLAY": "",
        "MPLBACKEND": "",
        "MPLCONFIGDIR": str(tmpdir)
    }
    with pytest.raises(subprocess.CalledProcessError):
        subprocess.run([
            sys.executable, "-c", "import matplotlib;"
            "matplotlib.use('tkagg');"
            "import matplotlib.pyplot"
        ],
                       env=env,
                       check=True,
                       stderr=subprocess.DEVNULL)


@pytest.mark.skipif(sys.platform == "linux"
                    and not _c_internal_utils.display_is_valid(),
                    reason="headless")
def test_backend_fallback_headful(tmpdir):
    pytest.importorskip("tkinter")
    env = {**os.environ, "MPLBACKEND": "", "MPLCONFIGDIR": str(tmpdir)}
    backend = subprocess.check_output([
        sys.executable, "-c",
        "import matplotlib.pyplot; print(matplotlib.get_backend())"
    ],
                                      env=env,
                                      universal_newlines=True)
    # The actual backend will depend on what's installed, but at least tkagg is
    # present.
    assert backend.strip().lower() != "agg"
Esempio n. 6
0
    env = {**os.environ,
           "DISPLAY": "", "WAYLAND_DISPLAY": "",
           "MPLBACKEND": "", "MPLCONFIGDIR": str(tmpdir)}
    with pytest.raises(subprocess.CalledProcessError):
        subprocess.run(
            [sys.executable, "-c",
             "import matplotlib;"
             "matplotlib.use('tkagg');"
             "import matplotlib.pyplot;"
             "matplotlib.pyplot.plot(42);"
             ],
            env=env, check=True, stderr=subprocess.DEVNULL)


@pytest.mark.skipif(
    sys.platform == "linux" and not _c_internal_utils.display_is_valid(),
    reason="headless")
def test_backend_fallback_headful(tmpdir):
    pytest.importorskip("tkinter")
    env = {**os.environ, "MPLBACKEND": "", "MPLCONFIGDIR": str(tmpdir)}
    backend = subprocess.check_output(
        [sys.executable, "-c",
         "import matplotlib as mpl; "
         "sentinel = mpl.rcsetup._auto_backend_sentinel; "
         # Check that access on another instance does not resolve the sentinel.
         "assert mpl.RcParams({'backend': sentinel})['backend'] == sentinel; "
         "assert dict.__getitem__(mpl.rcParams, 'backend') == sentinel; "
         "import matplotlib.pyplot; "
         "print(matplotlib.get_backend())"],
        env=env, universal_newlines=True)
    # The actual backend will depend on what's installed, but at least tkagg is