Skip to content

Commit 002ffdb

Browse files
committed
fix(tests): use mock.patch.object to avoid plotter module shadowing
1 parent 9f63c78 commit 002ffdb

File tree

1 file changed

+27
-29
lines changed

1 file changed

+27
-29
lines changed

datalab_kernel/tests/unit/test_backend_selection.py

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import contextlib
1515
import os
16+
import sys
1617
from unittest import mock
1718

1819
import pytest
@@ -27,6 +28,11 @@
2728
plotly_available,
2829
resolve_backend,
2930
)
31+
32+
# Grab the *module* from sys.modules because the ``plotter`` attribute on the
33+
# ``datalab_kernel`` package is shadowed by a global variable (``None`` until
34+
# the kernel starts). ``mock.patch.object`` then patches the correct namespace.
35+
_plotter_mod = sys.modules["datalab_kernel.plotter"]
3036
from datalab_kernel.tests.data import make_test_signal
3137
from datalab_kernel.workspace import Workspace
3238

@@ -68,11 +74,11 @@ def test_auto_prefers_plotly(self):
6874
"""Auto-detect prefers plotly when both are available."""
6975
with contextlib.ExitStack() as stack:
7076
stack.enter_context(
71-
mock.patch("datalab_kernel.plotter.plotly_available", return_value=True)
77+
mock.patch.object(_plotter_mod, "plotly_available", return_value=True)
7278
)
7379
stack.enter_context(
74-
mock.patch(
75-
"datalab_kernel.plotter.matplotlib_available", return_value=True
80+
mock.patch.object(
81+
_plotter_mod, "matplotlib_available", return_value=True
7682
)
7783
)
7884
assert resolve_backend(None) == BACKEND_PLOTLY
@@ -81,13 +87,11 @@ def test_auto_falls_back_to_matplotlib(self):
8187
"""Auto-detect falls back to matplotlib when plotly is missing."""
8288
with contextlib.ExitStack() as stack:
8389
stack.enter_context(
84-
mock.patch(
85-
"datalab_kernel.plotter.plotly_available", return_value=False
86-
)
90+
mock.patch.object(_plotter_mod, "plotly_available", return_value=False)
8791
)
8892
stack.enter_context(
89-
mock.patch(
90-
"datalab_kernel.plotter.matplotlib_available", return_value=True
93+
mock.patch.object(
94+
_plotter_mod, "matplotlib_available", return_value=True
9195
)
9296
)
9397
assert resolve_backend(None) == BACKEND_MATPLOTLIB
@@ -96,11 +100,11 @@ def test_auto_plotly_only(self):
96100
"""Auto-detect returns plotly when only plotly is available."""
97101
with contextlib.ExitStack() as stack:
98102
stack.enter_context(
99-
mock.patch("datalab_kernel.plotter.plotly_available", return_value=True)
103+
mock.patch.object(_plotter_mod, "plotly_available", return_value=True)
100104
)
101105
stack.enter_context(
102-
mock.patch(
103-
"datalab_kernel.plotter.matplotlib_available", return_value=False
106+
mock.patch.object(
107+
_plotter_mod, "matplotlib_available", return_value=False
104108
)
105109
)
106110
assert resolve_backend(None) == BACKEND_PLOTLY
@@ -109,13 +113,11 @@ def test_neither_raises(self):
109113
"""ImportError when neither backend is available."""
110114
with contextlib.ExitStack() as stack:
111115
stack.enter_context(
112-
mock.patch(
113-
"datalab_kernel.plotter.plotly_available", return_value=False
114-
)
116+
mock.patch.object(_plotter_mod, "plotly_available", return_value=False)
115117
)
116118
stack.enter_context(
117-
mock.patch(
118-
"datalab_kernel.plotter.matplotlib_available", return_value=False
119+
mock.patch.object(
120+
_plotter_mod, "matplotlib_available", return_value=False
119121
)
120122
)
121123
with pytest.raises(ImportError, match="Neither plotly nor matplotlib"):
@@ -125,13 +127,11 @@ def test_fallback_with_warning(self):
125127
"""Falls back to the other backend with a warning."""
126128
with contextlib.ExitStack() as stack:
127129
stack.enter_context(
128-
mock.patch(
129-
"datalab_kernel.plotter.plotly_available", return_value=False
130-
)
130+
mock.patch.object(_plotter_mod, "plotly_available", return_value=False)
131131
)
132132
stack.enter_context(
133-
mock.patch(
134-
"datalab_kernel.plotter.matplotlib_available", return_value=True
133+
mock.patch.object(
134+
_plotter_mod, "matplotlib_available", return_value=True
135135
)
136136
)
137137
with pytest.warns(UserWarning, match="not installed.*Falling back"):
@@ -142,12 +142,12 @@ def test_fallback_other_direction(self):
142142
"""Falls back to plotly when matplotlib is requested but missing."""
143143
with contextlib.ExitStack() as stack:
144144
stack.enter_context(
145-
mock.patch(
146-
"datalab_kernel.plotter.matplotlib_available", return_value=False
145+
mock.patch.object(
146+
_plotter_mod, "matplotlib_available", return_value=False
147147
)
148148
)
149149
stack.enter_context(
150-
mock.patch("datalab_kernel.plotter.plotly_available", return_value=True)
150+
mock.patch.object(_plotter_mod, "plotly_available", return_value=True)
151151
)
152152
with pytest.warns(UserWarning, match="not installed.*Falling back"):
153153
result = resolve_backend("matplotlib")
@@ -157,13 +157,11 @@ def test_both_missing_with_explicit_raises(self):
157157
"""ImportError when explicit backend and fallback are both missing."""
158158
with contextlib.ExitStack() as stack:
159159
stack.enter_context(
160-
mock.patch(
161-
"datalab_kernel.plotter.plotly_available", return_value=False
162-
)
160+
mock.patch.object(_plotter_mod, "plotly_available", return_value=False)
163161
)
164162
stack.enter_context(
165-
mock.patch(
166-
"datalab_kernel.plotter.matplotlib_available", return_value=False
163+
mock.patch.object(
164+
_plotter_mod, "matplotlib_available", return_value=False
167165
)
168166
)
169167
with pytest.raises(ImportError, match="Neither plotly nor matplotlib"):

0 commit comments

Comments
 (0)