From bcc570b2157b6a555ff873b3e5653c622105623b Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 8 Feb 2024 05:16:25 -0500 Subject: [PATCH] macOS: Check for display availability when looking for backends --- lib/matplotlib/tests/test_backend_macosx.py | 7 +++++++ lib/matplotlib/tests/test_backend_qt.py | 5 ++--- lib/matplotlib/tests/test_backend_tk.py | 4 ++-- .../tests/test_backends_interactive.py | 7 +++---- lib/matplotlib/tests/test_rcparams.py | 4 +--- meson.build | 4 ++++ src/_c_internal_utils.cpp | 10 ++++++++++ src/_objc_internal_utils.m | 13 +++++++++++++ src/meson.build | 18 ++++++++++++------ 9 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 src/_objc_internal_utils.m diff --git a/lib/matplotlib/tests/test_backend_macosx.py b/lib/matplotlib/tests/test_backend_macosx.py index c460da374c8c..3f1de0ddcc2d 100644 --- a/lib/matplotlib/tests/test_backend_macosx.py +++ b/lib/matplotlib/tests/test_backend_macosx.py @@ -3,6 +3,7 @@ import pytest import matplotlib as mpl +from matplotlib import _c_internal_utils import matplotlib.pyplot as plt try: from matplotlib.backends import _macosx @@ -10,6 +11,12 @@ pytest.skip("These are mac only tests", allow_module_level=True) +pytestmark = [ + pytest.mark.skipif(not _c_internal_utils.display_is_valid(), + reason="Display is unavailable") +] + + @pytest.mark.backend('macosx') def test_cached_renderer(): # Make sure that figures have an associated renderer after diff --git a/lib/matplotlib/tests/test_backend_qt.py b/lib/matplotlib/tests/test_backend_qt.py index f4a7ef6755f2..c04ee926355f 100644 --- a/lib/matplotlib/tests/test_backend_qt.py +++ b/lib/matplotlib/tests/test_backend_qt.py @@ -305,9 +305,8 @@ def _get_testable_qt_backends(): ]: 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" + if not _c_internal_utils.display_is_valid(): + reason = "Display is unavailable" elif missing: reason = "{} cannot be imported".format(", ".join(missing)) elif env["MPLBACKEND"] == 'macosx' and os.environ.get('TF_BUILD'): diff --git a/lib/matplotlib/tests/test_backend_tk.py b/lib/matplotlib/tests/test_backend_tk.py index ee20a94042f7..705666e30343 100644 --- a/lib/matplotlib/tests/test_backend_tk.py +++ b/lib/matplotlib/tests/test_backend_tk.py @@ -35,8 +35,8 @@ def _isolated_tk_test(success_count, func=None): reason="missing tkinter" ) @pytest.mark.skipif( - sys.platform == "linux" and not _c_internal_utils.display_is_valid(), - reason="$DISPLAY and $WAYLAND_DISPLAY are unset" + not _c_internal_utils.display_is_valid(), + reason="Display is unavailable" ) @pytest.mark.xfail( # https://github.com/actions/setup-python/issues/649 ('TF_BUILD' in os.environ or 'GITHUB_ACTION' in os.environ) and diff --git a/lib/matplotlib/tests/test_backends_interactive.py b/lib/matplotlib/tests/test_backends_interactive.py index 2464552d4b98..d8cd14cd223f 100644 --- a/lib/matplotlib/tests/test_backends_interactive.py +++ b/lib/matplotlib/tests/test_backends_interactive.py @@ -55,8 +55,7 @@ def wait_for(self, terminator): @functools.lru_cache def _get_available_interactive_backends(): - _is_linux_and_display_invalid = (sys.platform == "linux" and - not _c_internal_utils.display_is_valid()) + _is_display_invalid = not _c_internal_utils.display_is_valid() envs = [] for deps, env in [ *[([qt_api], @@ -74,8 +73,8 @@ def _get_available_interactive_backends(): ]: reason = None missing = [dep for dep in deps if not importlib.util.find_spec(dep)] - if _is_linux_and_display_invalid: - reason = "$DISPLAY and $WAYLAND_DISPLAY are unset" + if _is_display_invalid: + reason = "Display is unavailable" elif missing: reason = "{} cannot be imported".format(", ".join(missing)) elif env["MPLBACKEND"] == 'macosx' and os.environ.get('TF_BUILD'): diff --git a/lib/matplotlib/tests/test_rcparams.py b/lib/matplotlib/tests/test_rcparams.py index 782c390c9462..3175bf376abc 100644 --- a/lib/matplotlib/tests/test_rcparams.py +++ b/lib/matplotlib/tests/test_rcparams.py @@ -534,9 +534,7 @@ def test_backend_fallback_headless(tmp_path): env=env, check=True, stderr=subprocess.DEVNULL) -@pytest.mark.skipif( - sys.platform == "linux" and not _c_internal_utils.display_is_valid(), - reason="headless") +@pytest.mark.skipif(not _c_internal_utils.display_is_valid(), reason="headless") def test_backend_fallback_headful(tmp_path): pytest.importorskip("tkinter") env = {**os.environ, "MPLBACKEND": "", "MPLCONFIGDIR": str(tmp_path)} diff --git a/meson.build b/meson.build index 41f080b3700e..1afc135bfb34 100644 --- a/meson.build +++ b/meson.build @@ -17,6 +17,10 @@ project( cc = meson.get_compiler('c') cpp = meson.get_compiler('cpp') +# Objective C is needed for the _c_internal_utils and macosx extension. +if host_machine.system() == 'darwin' + add_languages('objc', native: false) +endif # https://mesonbuild.com/Python-module.html py_mod = import('python') diff --git a/src/_c_internal_utils.cpp b/src/_c_internal_utils.cpp index 813aeb6f7d5a..f7e74f80af6e 100644 --- a/src/_c_internal_utils.cpp +++ b/src/_c_internal_utils.cpp @@ -18,6 +18,12 @@ #else #define UNUSED_ON_NON_WINDOWS Py_UNUSED #endif +#ifdef __APPLE__ +// Defined in _objc_internal_utils.m. +extern "C" { +int _macos_display_is_valid(void); +} +#endif namespace py = pybind11; using namespace pybind11::literals; @@ -69,6 +75,8 @@ mpl_display_is_valid(void) } } return false; +#elif defined(__APPLE__) + return _macos_display_is_valid() == 1; #else return true; #endif @@ -180,6 +188,8 @@ PYBIND11_MODULE(_c_internal_utils, m) succeeds, or $WAYLAND_DISPLAY is set and wl_display_connect(NULL) succeeds. + On macOS, returns True if NSScreen::mainScreen is not nil. + On other platforms, always returns True.)"""); m.def( "Win32_GetCurrentProcessExplicitAppUserModelID", diff --git a/src/_objc_internal_utils.m b/src/_objc_internal_utils.m new file mode 100644 index 000000000000..a6271e63b69c --- /dev/null +++ b/src/_objc_internal_utils.m @@ -0,0 +1,13 @@ +#include + +int +_macos_display_is_valid(void) +{ + NSApplicationLoad(); + NSScreen *main = [NSScreen mainScreen]; + if (main != nil) { + return 1; + } else { + return 0; + } +} diff --git a/src/meson.build b/src/meson.build index db064a9c5ca1..b36601736ed9 100644 --- a/src/meson.build +++ b/src/meson.build @@ -69,6 +69,12 @@ else user32 = [] endif +if host_machine.system() == 'darwin' + cocoa = dependency('appleframeworks', modules: 'Cocoa') +else + cocoa = [] +endif + extension_data = { '_backend_agg': { 'subdir': 'matplotlib/backends', @@ -81,10 +87,11 @@ extension_data = { }, '_c_internal_utils': { 'subdir': 'matplotlib', - 'sources': files( - '_c_internal_utils.cpp', - ), - 'dependencies': [pybind11_dep, dl, ole32, shell32, user32], + 'sources': [ + files('_c_internal_utils.cpp'), + (host_machine.system() == 'darwin') ? files('_objc_internal_utils.m') : [], + ], + 'dependencies': [pybind11_dep, dl, ole32, shell32, user32, cocoa], }, 'ft2font': { 'subdir': 'matplotlib', @@ -182,14 +189,13 @@ foreach ext, kwargs : extension_data endforeach if get_option('macosx') and host_machine.system() == 'darwin' - add_languages('objc', native: false) py3.extension_module( '_macosx', subdir: 'matplotlib/backends', sources: files( '_macosx.m', ), - dependencies: dependency('appleframeworks', modules: 'Cocoa'), + dependencies: [cocoa], override_options: ['werror=true'], install: true, ) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy