Skip to content

Commit 2158981

Browse files
authored
Merge pull request OpenMS#8594 from OpenMS/copilot/fix-env-imports-in-tests
Replace env.py import hacks in pyOpenMS tests with pytest fixtures
2 parents 2870d19 + 26c5946 commit 2158981

5 files changed

Lines changed: 150 additions & 12 deletions

File tree

src/pyOpenMS/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ _copy_assets("${PROJECT_SOURCE_DIR}/pyopenms/" "*.sh" ${CMAKE_BINARY_DIR}/pyOpen
188188
_copy_assets("${PROJECT_SOURCE_DIR}/pyopenms/" "*.pyi" ${CMAKE_BINARY_DIR}/pyOpenMS/pyopenms/)
189189
_copy_assets("${PROJECT_SOURCE_DIR}/pyopenms/" "py.typed" ${CMAKE_BINARY_DIR}/pyOpenMS/pyopenms/)
190190
_copy_assets("${PROJECT_SOURCE_DIR}/pyTOPP/" "*.py" ${CMAKE_BINARY_DIR}/pyOpenMS/pyTOPP/)
191+
_copy_assets("${PROJECT_SOURCE_DIR}/tests/" "*.py" ${CMAKE_BINARY_DIR}/pyOpenMS/tests)
191192
_copy_assets("${PROJECT_SOURCE_DIR}/tests/unittests/" "*" ${CMAKE_BINARY_DIR}/pyOpenMS/tests/unittests)
192193
_copy_assets("${PROJECT_SOURCE_DIR}/tests/" "*.mzXML" ${CMAKE_BINARY_DIR}/pyOpenMS/tests)
193194
_copy_assets("${PROJECT_SOURCE_DIR}/tests/memoryleaktests/" "*" ${CMAKE_BINARY_DIR}/pyOpenMS/tests/memoryleaktests)

src/pyOpenMS/README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,24 @@ Build instructions
6161
```
6262
6363
"-R" to restrict to pyopenms* tests. If running out of the OpenMS build tree, this should not be necessary.
64+
65+
**Alternative: Running tests directly with pytest**
66+
67+
For development and debugging, you can run tests directly with pytest:
68+
69+
```bash
70+
cd <build-dir>/pyOpenMS
71+
python -m pytest tests/unittests
72+
python -m pytest tests/integration_tests
73+
```
74+
75+
Tests automatically locate test data files using the `conftest.py` configuration. If test data
76+
is in a non-standard location, set the `OPENMS_TEST_DATA_PATH` environment variable:
77+
78+
```bash
79+
export OPENMS_TEST_DATA_PATH=/path/to/OpenMS/src/tests/topp
80+
python -m pytest tests/
81+
```
6482
6583
6. Install locally (and in-place for live edits [option -e]) into current Python with
6684
@@ -156,3 +174,42 @@ After modifying addon `.pyx` files, force regeneration:
156174
rm OpenMS-build/pyOpenMS/.cpp_extension_generated
157175
cmake --build OpenMS-build --target pyopenms -j4
158176
```
177+
178+
### Writing Tests
179+
180+
Tests are located in `src/pyOpenMS/tests/`:
181+
- `unittests/` - Unit tests for individual components
182+
- `integration_tests/` - Integration tests requiring test data files
183+
- `memoryleaktests/` - Memory leak detection tests
184+
185+
**Accessing test data files:**
186+
187+
Tests automatically find test data through the `openms_test_data_dir` pytest fixture defined in `conftest.py`:
188+
189+
```python
190+
import pytest
191+
import os
192+
193+
class TestMyFeature(unittest.TestCase):
194+
195+
@pytest.fixture(autouse=True)
196+
def setup_test_data(self, openms_test_data_dir):
197+
"""Setup test with test data directory."""
198+
self.test_file = os.path.join(openms_test_data_dir, "my_test_file.mzML")
199+
200+
def test_something(self):
201+
# Use self.test_file here
202+
pass
203+
```
204+
205+
The fixture automatically locates test data using multiple strategies:
206+
1. `OPENMS_TEST_DATA_PATH` environment variable (for custom locations)
207+
2. Relative path from source tree (works in development)
208+
3. CMake-configured env.py (backwards compatibility)
209+
210+
To override test data location:
211+
```bash
212+
export OPENMS_TEST_DATA_PATH=/path/to/OpenMS/src/tests/topp
213+
python -m pytest tests/
214+
```
215+

src/pyOpenMS/tests/conftest.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
"""
2+
Pytest configuration file for pyOpenMS tests.
3+
4+
This file provides fixtures and configuration for test data paths,
5+
replacing the old env.py import pattern.
6+
"""
7+
8+
import os
9+
10+
# Import pytest only if available (needed for fixtures)
11+
try:
12+
import pytest
13+
_HAS_PYTEST = True
14+
except ImportError:
15+
_HAS_PYTEST = False
16+
17+
18+
def _get_test_data_dir():
19+
"""
20+
Get the path to the OpenMS test data directory.
21+
22+
This function tries multiple strategies to find the test data:
23+
1. Check the OPENMS_TEST_DATA_PATH environment variable (for custom locations)
24+
2. Use relative path from this file (works for regular source clones)
25+
3. Try to import env.py if available (for CMake builds, backwards compatibility)
26+
27+
Returns:
28+
str: Path to the test data directory (src/tests/topp)
29+
"""
30+
# Strategy 1: Check environment variable for override
31+
env_path = os.environ.get('OPENMS_TEST_DATA_PATH')
32+
if env_path and os.path.isdir(env_path):
33+
return env_path
34+
35+
# Strategy 2: Use relative path from this conftest.py file
36+
# This works for regular clones where the structure is:
37+
# src/pyOpenMS/tests/conftest.py (this file)
38+
# src/tests/topp/ (test data)
39+
tests_dir = os.path.dirname(os.path.abspath(__file__))
40+
relative_path = os.path.join(tests_dir, '..', '..', '..', 'src', 'tests', 'topp')
41+
relative_path = os.path.normpath(relative_path)
42+
if os.path.isdir(relative_path):
43+
return relative_path
44+
45+
# Strategy 3: Try to import env.py (backwards compatibility for CMake builds)
46+
try:
47+
import env
48+
if hasattr(env, 'PYOPENMS_SRC_DIR'):
49+
env_based_path = os.path.join(env.PYOPENMS_SRC_DIR, "..", "..", "src", "tests", "topp")
50+
env_based_path = os.path.normpath(env_based_path)
51+
if os.path.isdir(env_based_path):
52+
return env_based_path
53+
except ImportError:
54+
pass
55+
56+
# If all strategies fail, raise an error
57+
raise RuntimeError(
58+
"Could not locate OpenMS test data directory. "
59+
"Please set the OPENMS_TEST_DATA_PATH environment variable to point to "
60+
"the 'src/tests/topp' directory, or ensure you're running tests from a "
61+
"complete OpenMS source tree."
62+
)
63+
64+
65+
# Only define pytest fixtures if pytest is available
66+
if _HAS_PYTEST:
67+
@pytest.fixture(scope='session')
68+
def openms_test_data_dir():
69+
"""
70+
Pytest fixture providing the path to the OpenMS test data directory.
71+
72+
Usage in tests:
73+
def test_something(openms_test_data_dir):
74+
data_file = os.path.join(openms_test_data_dir, "test_file.mzML")
75+
76+
Returns:
77+
str: Path to the test data directory
78+
"""
79+
return _get_test_data_dir()
80+

src/pyOpenMS/tests/integration_tests/test_MRMRTNormalizer.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import unittest,os
1+
import unittest
2+
import os
3+
import pytest
24

3-
## UGLY HACK!! This imports the *FILE* env.py that is configured by CMake. Even uglier since there is a module called env!!
4-
import env
55
import pyopenms
66
from collections import defaultdict
77

@@ -28,9 +28,10 @@ def simple_find_best_feature(output, pairs, targeted):
2828
class TestMRMRTNormalizer(unittest.TestCase):
2929
"""Emulates the behavior of OpenSwathMRMRTNormalizer"""
3030

31-
def setUp(self):
32-
# TODO make the tests self-consistent to only use files under the pyOpenMS directory
33-
self.testdirname = os.path.join(env.PYOPENMS_SRC_DIR, "..", "..", "src/tests/topp")
31+
@pytest.fixture(autouse=True)
32+
def setup_test_data(self, openms_test_data_dir):
33+
"""Setup test with test data directory from pytest fixture."""
34+
self.testdirname = openms_test_data_dir
3435
# set up files
3536
self.chromatograms = os.path.join(self.testdirname, "OpenSwathRTNormalizer_1_input.mzML").encode()
3637
self.tramlfile = os.path.join(self.testdirname, "OpenSwathRTNormalizer_1_input.TraML").encode()

src/pyOpenMS/tests/unittests/test_MRMFeatureFinderScoring.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
import unittest
22
import os
3+
import pytest
34

45
import pyopenms
56

6-
## UGLY HACK!! This imports the *FILE* env.py that is configured by CMake. Even uglier since there is a module called env!!
7-
import env
8-
97
eps = 2
108

119
class TestMRMFeatureFinderScoring(unittest.TestCase):
1210

13-
def setUp(self):
11+
@pytest.fixture(autouse=True)
12+
def setup_test_data(self, openms_test_data_dir):
13+
"""Setup test with test data directory from pytest fixture."""
1414
self.dirname = os.path.dirname(os.path.abspath(__file__))
15-
# TODO make the tests self-consistent to only use files under the pyOpenMS directory
16-
self.testdirname = os.path.join(env.PYOPENMS_SRC_DIR, "..", "..", "src/tests/topp")
15+
self.testdirname = openms_test_data_dir
1716
# set up files
1817
self.chromatograms = os.path.join(self.testdirname, "OpenSwathAnalyzer_1_input_chrom.mzML").encode()
1918
self.tramlfile = os.path.join(self.testdirname, "OpenSwathAnalyzer_1_input.TraML").encode()

0 commit comments

Comments
 (0)