diff --git a/NaviNIBS/util/pyvista/__init__.py b/NaviNIBS/util/pyvista/__init__.py index be153b2..bdc8ec1 100644 --- a/NaviNIBS/util/pyvista/__init__.py +++ b/NaviNIBS/util/pyvista/__init__.py @@ -20,7 +20,17 @@ def setActorUserTransform(actor: Actor | str, transf: np.ndarray): if False or isMac: from NaviNIBS.util.pyvista.plotting import BackgroundPlotter, PrimaryLayeredPlotter, SecondaryLayeredPlotter DefaultBackgroundPlotter = BackgroundPlotter - RemotePlotterProxy = type('__None') # for callers to easily check if DefaultBackgroundPlotter is RemotePlotterProxy + + class RemotePlotterProxy: + """ + Never-instantiated stand-in so that callers can check + ``isinstance(plotter, RemotePlotterProxy)`` when remote plotting is unavailable. + + (Note: ``type('__None')`` previously used here evaluated to ``str``, making + strings unintentionally satisfy such isinstance checks.) + """ + pass + DefaultPrimaryLayeredPlotter = PrimaryLayeredPlotter DefaultSecondaryLayeredPlotter = SecondaryLayeredPlotter else: diff --git a/tests/test_util/test_pyvistaDefaults.py b/tests/test_util/test_pyvistaDefaults.py new file mode 100644 index 0000000..f74682f --- /dev/null +++ b/tests/test_util/test_pyvistaDefaults.py @@ -0,0 +1,23 @@ +""" +Regression test for the RemotePlotterProxy sentinel used on platforms +where remote plotting is unavailable (currently macOS). +""" + +import platform + +import pytest + +from NaviNIBS.util.pyvista import DefaultBackgroundPlotter, RemotePlotterProxy + + +@pytest.mark.skipif(platform.system() != 'Darwin', + reason='sentinel branch only taken on macOS') +def test_remotePlotterSentinelIsNotStr(): + """ + ``type('__None')`` evaluates to ``str``, so string values would satisfy + ``isinstance(x, RemotePlotterProxy)`` checks; the sentinel must be a + dedicated class. + """ + assert RemotePlotterProxy is not str + assert not isinstance('some string', RemotePlotterProxy) + assert not isinstance(DefaultBackgroundPlotter, RemotePlotterProxy)