|
1 | 1 | """Test lazy imports to ensure pandas/matplotlib are not loaded unnecessarily.""" |
2 | 2 | import unittest |
3 | 3 | import sys |
| 4 | +import subprocess |
4 | 5 | import importlib |
5 | 6 |
|
6 | 7 |
|
7 | 8 | class TestLazyImports(unittest.TestCase): |
8 | 9 | """Test that PrometheusConnect can be imported without loading heavy dependencies.""" |
9 | 10 |
|
10 | | - @staticmethod |
11 | | - def _remove_modules(module_names): |
12 | | - """Remove specified modules and their submodules from sys.modules. |
13 | | - |
14 | | - Args: |
15 | | - module_names: List of module names to remove |
16 | | - """ |
17 | | - for module_name in module_names: |
18 | | - modules_to_remove = [ |
19 | | - key for key in sys.modules.keys() |
20 | | - if key == module_name or key.startswith(module_name + '.') |
21 | | - ] |
22 | | - for module in modules_to_remove: |
23 | | - del sys.modules[module] |
24 | | - |
25 | | - @staticmethod |
26 | | - def _is_module_loaded(module_name): |
27 | | - """Check if a module is loaded in sys.modules. |
28 | | - |
29 | | - Args: |
30 | | - module_name: Name of the module to check |
31 | | - |
32 | | - Returns: |
33 | | - bool: True if module is loaded, False otherwise |
34 | | - """ |
35 | | - return any(m == module_name or m.startswith(module_name + '.') for m in sys.modules.keys()) |
36 | | - |
37 | 11 | def test_prometheus_connect_import_without_pandas_matplotlib_numpy(self): |
38 | 12 | """Test that importing PrometheusConnect doesn't load pandas, matplotlib, or numpy.""" |
39 | | - # Remove any previously loaded modules |
40 | | - self._remove_modules(['prometheus_api_client', 'numpy', 'pandas', 'matplotlib']) |
41 | | - |
42 | | - # Import PrometheusConnect |
43 | | - from prometheus_api_client import PrometheusConnect |
| 13 | + # Run in a subprocess to avoid affecting other tests |
| 14 | + code = """ |
| 15 | +import sys |
| 16 | +from prometheus_api_client import PrometheusConnect |
| 17 | +
|
| 18 | +# Check that pandas, matplotlib, and numpy are not loaded |
| 19 | +pandas_loaded = any(m == 'pandas' or m.startswith('pandas.') for m in sys.modules.keys()) |
| 20 | +matplotlib_loaded = any(m == 'matplotlib' or m.startswith('matplotlib.') for m in sys.modules.keys()) |
| 21 | +numpy_loaded = any(m == 'numpy' or m.startswith('numpy.') for m in sys.modules.keys()) |
| 22 | +
|
| 23 | +if pandas_loaded: |
| 24 | + sys.exit(1) |
| 25 | +if matplotlib_loaded: |
| 26 | + sys.exit(2) |
| 27 | +if numpy_loaded: |
| 28 | + sys.exit(3) |
| 29 | +sys.exit(0) |
| 30 | +""" |
| 31 | + result = subprocess.run( |
| 32 | + [sys.executable, '-c', code], |
| 33 | + capture_output=True, |
| 34 | + text=True |
| 35 | + ) |
44 | 36 |
|
45 | | - # Check that pandas, matplotlib, and numpy are not loaded |
46 | | - self.assertFalse(self._is_module_loaded('pandas'), |
47 | | - "pandas should not be loaded when importing PrometheusConnect") |
48 | | - self.assertFalse(self._is_module_loaded('matplotlib'), |
49 | | - "matplotlib should not be loaded when importing PrometheusConnect") |
50 | | - self.assertFalse(self._is_module_loaded('numpy'), |
51 | | - "numpy should not be loaded when importing PrometheusConnect") |
| 37 | + if result.returncode == 1: |
| 38 | + self.fail("pandas should not be loaded when importing PrometheusConnect") |
| 39 | + elif result.returncode == 2: |
| 40 | + self.fail("matplotlib should not be loaded when importing PrometheusConnect") |
| 41 | + elif result.returncode == 3: |
| 42 | + self.fail("numpy should not be loaded when importing PrometheusConnect") |
| 43 | + elif result.returncode != 0: |
| 44 | + self.fail(f"Subprocess failed with code {result.returncode}: {result.stderr}") |
52 | 45 |
|
53 | 46 | def test_prometheus_connect_instantiation_without_numpy(self): |
54 | 47 | """Test that PrometheusConnect can be instantiated without loading numpy.""" |
55 | | - # Remove any previously loaded modules |
56 | | - self._remove_modules(['prometheus_api_client', 'numpy']) |
57 | | - |
58 | | - # Import and instantiate PrometheusConnect |
59 | | - from prometheus_api_client import PrometheusConnect |
60 | | - pc = PrometheusConnect(url='http://test.local:9090') |
| 48 | + # Run in a subprocess to avoid affecting other tests |
| 49 | + code = """ |
| 50 | +import sys |
| 51 | +from prometheus_api_client import PrometheusConnect |
| 52 | +
|
| 53 | +pc = PrometheusConnect(url='http://test.local:9090') |
| 54 | +
|
| 55 | +# Check that numpy is still not loaded after instantiation |
| 56 | +numpy_loaded = any(m == 'numpy' or m.startswith('numpy.') for m in sys.modules.keys()) |
| 57 | +
|
| 58 | +if numpy_loaded: |
| 59 | + sys.exit(1) |
| 60 | +if pc is None: |
| 61 | + sys.exit(2) |
| 62 | +sys.exit(0) |
| 63 | +""" |
| 64 | + result = subprocess.run( |
| 65 | + [sys.executable, '-c', code], |
| 66 | + capture_output=True, |
| 67 | + text=True |
| 68 | + ) |
61 | 69 |
|
62 | | - # Check that numpy is still not loaded after instantiation |
63 | | - self.assertFalse(self._is_module_loaded('numpy'), |
64 | | - "numpy should not be loaded when instantiating PrometheusConnect") |
65 | | - self.assertIsNotNone(pc, "PrometheusConnect should be instantiated successfully") |
| 70 | + if result.returncode == 1: |
| 71 | + self.fail("numpy should not be loaded when instantiating PrometheusConnect") |
| 72 | + elif result.returncode == 2: |
| 73 | + self.fail("PrometheusConnect should be instantiated successfully") |
| 74 | + elif result.returncode != 0: |
| 75 | + self.fail(f"Subprocess failed with code {result.returncode}: {result.stderr}") |
66 | 76 |
|
67 | 77 | def test_metric_import_loads_pandas(self): |
68 | 78 | """Test that importing Metric does load pandas (expected behavior).""" |
69 | | - # Remove any previously loaded modules |
70 | | - self._remove_modules(['prometheus_api_client', 'pandas']) |
71 | | - |
72 | | - # Import Metric |
| 79 | + # This test doesn't remove modules, so it won't cause reload issues |
73 | 80 | from prometheus_api_client import Metric |
74 | 81 |
|
75 | 82 | # Check that pandas is loaded (this is expected for Metric) |
76 | | - self.assertTrue(self._is_module_loaded('pandas'), |
77 | | - "pandas should be loaded when importing Metric") |
| 83 | + pandas_loaded = any(m == 'pandas' or m.startswith('pandas.') for m in sys.modules.keys()) |
| 84 | + self.assertTrue(pandas_loaded, "pandas should be loaded when importing Metric") |
78 | 85 |
|
79 | 86 |
|
80 | 87 | if __name__ == '__main__': |
|
0 commit comments