Skip to content

Commit 4e33c90

Browse files
authored
MAINT: refine installation of core and test dependencies (#131)
Split off optional dependencies (scipy & matplotlib), skip tests when these are not available. Reviewed at #131
1 parent f00b7c7 commit 4e33c90

File tree

5 files changed

+71
-29
lines changed

5 files changed

+71
-29
lines changed

Diff for: .github/workflows/pip.yml

+28-21
Original file line numberDiff line numberDiff line change
@@ -18,37 +18,44 @@ jobs:
1818
python-version: ['3.10', '3.11']
1919
os: [ubuntu-latest]
2020
pytest: ['"pytest<8.0"', pytest]
21-
# pip cache paths
22-
include:
23-
- os: ubuntu-latest
24-
path: ~/.cache/pip
2521

2622
steps:
27-
- uses: actions/checkout@v2
23+
# actions/setup-python@v5 has built-in functionality for caching and restoring dependencies.
24+
- uses: actions/checkout@v4
2825
- name: Set up Python ${{ matrix.python-version }}
29-
uses: actions/setup-python@v2
26+
uses: actions/setup-python@v5
3027
with:
3128
python-version: ${{ matrix.python-version }}
29+
cache: 'pip' # caching pip dependencies
3230

33-
# use pip caching
34-
- uses: actions/cache@v2
35-
with:
36-
path: ${{ matrix.path }}
37-
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
38-
restore-keys: |
39-
${{ runner.os }}-pip-
40-
41-
# Install dependencies
42-
- name: Install
31+
# Install numpy and pytest
32+
- name: Install core dependencies
4333
run: |
44-
python -m pip install numpy scipy matplotlib ${{matrix.pytest}}
34+
python -m pip install --upgrade pip
35+
python -m pip install ${{matrix.pytest}}
4536
python -m pip install -e .
4637
47-
- name: Self-test
38+
# Run self-tests without Scipy and MPL
39+
# Tests that require Scipy and MPL will be skipped
40+
- name: Self-test without SciPy and MPL
41+
run: |
42+
pytest --pyargs scpdt -v
43+
44+
- name: Self-test CLI without SciPy and MPL
45+
run: |
46+
python -m scpdt scpdt/tests/finder_cases.py -vv
47+
48+
# Install Scipy and MPL
49+
- name: Install optional dependencies
50+
run: |
51+
python -m pip install -e '.[test]'
52+
53+
# Tests that require Scipy and MPL can now run
54+
- name: Self-test with SciPy and MPL
4855
run: |
49-
pytest --pyargs scpdt -v -s
56+
pytest --pyargs scpdt -v
5057
51-
- name: Self-test CLI
58+
- name: Self-test CLI with SciPy and MPL
5259
run: |
5360
python -m scpdt scpdt/tests/finder_cases.py -vv
5461
@@ -62,7 +69,7 @@ jobs:
6269
6370
- name: Run testmod a scipy submodule -- Public API onlly
6471
run: |
65-
python -mpip install pooch
72+
python -m pip install pooch
6673
python -c'from scipy import ndimage; from scpdt import testmod; testmod(ndimage, verbose=True, strategy="api")'
6774
6875
- name: Test pytest plugin

Diff for: pyproject.toml

+1-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ dependencies = [
2424
[project.optional-dependencies]
2525
test = [
2626
"scipy",
27-
"matplotlib",
28-
"pytest"
27+
"matplotlib"
2928
]
3029

3130
[project.urls]

Diff for: scpdt/tests/test_pytest_configuration.py

+20-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,32 @@
11
import pytest
2+
3+
try:
4+
import matplotlib.pyplot as plt # noqa
5+
HAVE_MATPLOTLIB = True
6+
except Exception:
7+
HAVE_MATPLOTLIB = False
8+
9+
try:
10+
import scipy # noqa
11+
HAVE_SCIPY = True
12+
except Exception:
13+
HAVE_SCIPY = False
14+
215
from pathlib import PosixPath, Path
316

417
from . import module_cases, failure_cases, failure_cases_2, stopwords_cases, local_file_cases
5-
from scpdt.conftest import dt_config
618

719
# XXX: this is a bit hacky and repetetive. Can rework?
820

921

1022
pytest_plugins = ['pytester']
1123

1224

25+
@pytest.mark.skipif(not HAVE_SCIPY, reason='need scipy')
1326
def test_module_cases(pytester):
1427
"""Test that pytest uses the DTChecker for doctests."""
1528
path_str = module_cases.__file__
16-
python_file = PosixPath(path_str)
29+
python_file = Path(path_str)
1730
result = pytester.inline_run(python_file, "--doctest-modules")
1831
assert result.ret == pytest.ExitCode.OK
1932

@@ -22,23 +35,25 @@ def test_failure_cases(pytester):
2235
file_list = [failure_cases, failure_cases_2]
2336
for file in file_list:
2437
path_str = file.__file__
25-
python_file = PosixPath(path_str)
38+
python_file = Path(path_str)
2639
result = pytester.inline_run(python_file, "--doctest-modules")
2740
assert result.ret == pytest.ExitCode.TESTS_FAILED
2841

2942

43+
@pytest.mark.skipif(not HAVE_MATPLOTLIB, reason='need matplotlib')
3044
def test_stopword_cases(pytester):
3145
"""Test that pytest uses the DTParser for doctests."""
3246
path_str = stopwords_cases.__file__
33-
python_file = PosixPath(path_str)
47+
python_file = Path(path_str)
3448
result = pytester.inline_run(python_file, "--doctest-modules")
3549
assert result.ret == pytest.ExitCode.OK
3650

3751

52+
@pytest.mark.skipif(not HAVE_SCIPY, reason='need scipy')
3853
def test_local_file_cases(pytester):
3954
"""Test that local files are found for use in doctests.
4055
"""
4156
path_str = local_file_cases.__file__
42-
python_file = PosixPath(path_str)
57+
python_file = Path(path_str)
4358
result = pytester.inline_run(python_file, "--doctest-modules")
4459
assert result.ret == pytest.ExitCode.OK

Diff for: scpdt/tests/test_skipmarkers.py

+9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
import doctest
2+
3+
try:
4+
import matplotlib.pyplot as plt # noqa
5+
HAVE_MATPLOTLIB = True
6+
except Exception:
7+
HAVE_MATPLOTLIB = False
8+
29
import pytest
310

411
from ..impl import DTConfig, DTParser, DebugDTRunner
@@ -9,6 +16,7 @@ class TestSyntaxErrors:
916
1017
Either mark it with +SKIP or as pseudocode.
1118
"""
19+
@pytest.mark.skipif(not HAVE_MATPLOTLIB, reason='need matplotlib')
1220
def test_invalid_python(self):
1321
# This string raises
1422
# TypeError("unsupported operand type(s) for +: 'int' and 'tuple'")
@@ -100,6 +108,7 @@ class TestStopwords:
100108
"""If an example contains a stopword, the example still needs to be a valid
101109
python code, but the output is not checked.
102110
"""
111+
@pytest.mark.skipif(not HAVE_MATPLOTLIB, reason='need matplotlib')
103112
def test_bogus_output(self):
104113
# 'plt.xlim(' is a stopword by default in the DTParser. This is because
105114
# it returns a tuple, which we don't want to litter our docstrings with.

Diff for: scpdt/tests/test_testmod.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
import io
22
import doctest
3+
34
from contextlib import redirect_stderr
45

56
import numpy as np
7+
8+
try:
9+
import matplotlib.pyplot as plt
10+
HAVE_MATPLOTLIB = True
11+
except Exception:
12+
HAVE_MATPLOTLIB = False
13+
614
import pytest
715

816
try:
@@ -24,12 +32,14 @@
2432
_VERBOSE = 2
2533

2634

35+
@pytest.mark.skipif(not HAVE_SCIPY, reason='need scipy')
2736
def test_module():
2837
res, _ = _testmod(module, verbose=_VERBOSE)
2938
assert res.failed == 0
3039
assert res.attempted != 0
3140

3241

42+
@pytest.mark.skipif(not HAVE_SCIPY, reason='need scipy')
3343
def test_module_vanilla_dtfinder():
3444
config = DTConfig()
3545
config.stopwords = []
@@ -38,12 +48,14 @@ def test_module_vanilla_dtfinder():
3848
assert res.attempted != 0
3949

4050

51+
@pytest.mark.skipif(not HAVE_MATPLOTLIB, reason='need matplotlib')
4152
def test_stopwords():
4253
res, _ = _testmod(stopwords, verbose=_VERBOSE)
4354
assert res.failed == 0
4455
assert res.attempted != 0
56+
4557

46-
58+
@pytest.mark.skipif(not HAVE_SCIPY, reason='need scipy')
4759
def test_public_obj_discovery():
4860
res, _ = _testmod(module, verbose=_VERBOSE, strategy='api')
4961
assert res.failed == 0

0 commit comments

Comments
 (0)