Skip to content

Commit 72f6d9d

Browse files
committed
Ensure that pytest is the only strict requirement for running test suite for all installation modes (#738)
* Skip addheader tests if package is not available * Assume that pytest is the only additional testing requirement * Parametrize installation target * Prioritize WIP jobs while debugging * Move omlt to optional requirements * Reorder keras_surrogate imports * Use pytest.importorskip() to check for optional modules sooner * Display skipped tests and CI and docs use exactly the same commands * Add more context to post-installation pytest instructions * Revert "Prioritize WIP jobs while debugging" This reverts commit e1f1892. * Move omlt back to default dependencies in setup.py * Extend CI check to simulate environment after Conda installation * Prioritize WIP jobs while debugging * Track renamed matrix parameter * Reassure pip that we really meant to uninstall * Try to see if -rs flag to pytest causes failure in test_enrtl TestParameters.test_parameters_alpha_symmetry_duplicate * Try to see if the culprit is -W ignore instead * Fix outdated module used for caplog that was causing test to fail * Use module-level pytest.importorskip() * Add remaining individual pytest.skipif() * Fix typo in conditionally imported module name * Revert "Prioritize WIP jobs while debugging" This reverts commit 084a8c2. (cherry picked from commit 90f762a)
1 parent 4ba9b20 commit 72f6d9d

File tree

8 files changed

+70
-35
lines changed

8 files changed

+70
-35
lines changed

Diff for: .github/workflows/integration.yml

+29-9
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ jobs:
193193
cat *errors.txt || echo "No error logs found"
194194
195195
pytest-site-packages:
196-
name: Run tests from site-packages (non-editable) installation
196+
name: Run tests from site-packages (non-editable) installation (${{ matrix.install-mode }})
197197
# NOTE: using ubuntu-latest (20.04) instead of 18.04 results in failures in power_generation/carbon_capture/mea_solvent_system/unit_models/tests/test_column.py
198198
runs-on: ubuntu-18.04
199199
needs: [precheck]
@@ -203,6 +203,21 @@ jobs:
203203
|| needs.precheck.outputs.workflow-trigger == 'not_pr'
204204
|| needs.precheck.outputs.workflow-trigger == 'approved_pr'
205205
)
206+
strategy:
207+
fail-fast: false
208+
matrix:
209+
install-mode:
210+
- pip-default
211+
- pip-optional
212+
- conda-like
213+
include:
214+
- install-mode: pip-default
215+
pip-install-target: '.'
216+
- install-mode: pip-optional
217+
pip-install-target: .[optional]
218+
- install-mode: conda-like
219+
pip-install-target: '.'
220+
dependencies-to-uninstall: omlt
206221
steps:
207222
- uses: actions/checkout@v2
208223
- name: Set up Conda environment
@@ -213,13 +228,18 @@ jobs:
213228
- name: Set up idaes (non-editable installation)
214229
uses: ./.github/actions/setup-idaes
215230
with:
216-
install-target: '.[optional]'
217-
- name: Install test dependencies and run pytest in empty directory
231+
install-target: ${{ matrix.pip-install-target }}
232+
- name: Remove dependencies installable with pip but not with conda
233+
# NOTE some dependencies that are installed by default with pip are not available through conda
234+
# so they're not installed if IDAES is installed with `conda -c conda-forge -c IDAES-PSE idaes-pse`
235+
# to ensure this scenario is handled properly, since we don't have (yet) the conda-build process integrated with the CI,
236+
# we manually remove the "pip-but-not-conda" dependencies after installing with pip
237+
# as an approximation of the enviroment that we'd get from `conda install`
238+
if: matrix.dependencies-to-uninstall
239+
run: |
240+
pip uninstall --yes ${{ matrix.dependencies-to-uninstall }}
241+
- name: Install and run pytest in empty directory
218242
run: |
219243
pushd "$(mktemp -d)"
220-
# TODO this could be an optional [testing] dependency
221-
pip install pytest addheader
222-
# TODO downloading pytest.ini is still needed for the tests to pass
223-
# eventually it will be moved to the root conftest.py so that is installed as Python code
224-
wget https://raw.githubusercontent.com/IDAES/idaes-pse/main/pytest.ini
225-
pytest --pyargs idaes
244+
pip install pytest
245+
pytest --pyargs idaes -W ignore -rs

Diff for: docs/tutorials/getting_started/index.rst

+12-6
Original file line numberDiff line numberDiff line change
@@ -187,15 +187,21 @@ Powershell Prompt. Regardless of OS and shell, the following steps are the same
187187
Refer to the full :doc:`idaes get-examples command documentation <../../../reference_guides/commands/get_examples>`
188188
for more information.
189189

190-
4. Run tests::
190+
4. To test that the installation was successful, you can run the IDAES test suite.
191+
This is not strictly required, but can offer more confidence that the installation environment is as expected (if the tests pass),
192+
and more insight into possible issues (if any of the tests fail).
193+
The ``pytest`` package is required for running the test suite. After installing it using e.g. ``pip``, run the tests::
191194

192-
pytest --pyargs idaes -W ignore
195+
pip install pytest
196+
pytest --pyargs idaes -W ignore -rs
193197

194-
5. You should see the tests run and all should pass to ensure the installation worked. You
195-
may see some "Error" level log messages, but they are okay, and produced by tests for
198+
5. You should see the tests run and all should pass to ensure the installation worked.
199+
You may see some "Error" level log messages, but they are okay, and produced by tests for
196200
error handling. The number of tests that failed and succeeded is reported at the end of the pytest
197-
output. You can report problems on the |github-issues|
198-
(Please try to be specific about the command and the offending output.)
201+
output.
202+
If the optional ``-rs`` flag is given, the output will also display tests that were skipped because of
203+
e.g. optional dependencies that can be installed separately (see below).
204+
You can report problems on the |github-issues| (Please try to be specific about the command and the offending output.)
199205

200206
**Install IDAES using Conda**
201207

Diff for: idaes/generic_models/properties/core/coolprop/tests/test_coolprop_wrapper.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,16 @@
4141
Constant
4242

4343

44+
CoolProp = pytest.importorskip("CoolProp.CoolProp", reason="CoolProp not installed")
45+
4446
from idaes.generic_models.properties.core.coolprop.coolprop_wrapper import (
4547
CoolPropWrapper,
4648
CoolPropExpressionError,
4749
CoolPropPropertyError)
4850

49-
CoolProp, coolprop_available = attempt_import('CoolProp.CoolProp')
5051
solver = get_solver()
5152

5253

53-
@pytest.mark.skipif(not coolprop_available, reason="CoolProp not installed")
5454
class TestWrapper:
5555
@pytest.mark.unit
5656
def test_load_component(self):
@@ -233,7 +233,6 @@ def test_pressure_sat_unrecognised_form(self):
233233
CoolPropWrapper.pressure_sat_comp.build_parameters(m.TestComp)
234234

235235

236-
@pytest.mark.skipif(not coolprop_available, reason="CoolProp not installed")
237236
class TestCoolPropProperties(object):
238237
@pytest.fixture(scope="class")
239238
def m(self):
@@ -671,7 +670,6 @@ def test_psat(self, m):
671670
m.fs.state[0].pressure_sat_comp["benzene"])
672671

673672

674-
@pytest.mark.skipif(not coolprop_available, reason="CoolProp not installed")
675673
class TestVerifyExcessLiq(object):
676674
@pytest.fixture(scope="class")
677675
def m(self):
@@ -802,7 +800,6 @@ def test_cubic_liquid_entr(self, m):
802800
m.fs.state[0].entr_mol_phase["Liq"] - S0_I)
803801

804802

805-
@pytest.mark.skipif(not coolprop_available, reason="CoolProp not installed")
806803
class TestVerifyExcessVap(object):
807804
@pytest.fixture(scope="class")
808805
def m(self):

Diff for: idaes/generic_models/properties/core/eos/tests/test_enrtl.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ def test_parameters_alpha_symmetry_duplicate(self, caplog):
190190
caplog.set_level(
191191
idaeslog.INFO,
192192
logger=("idaes.generic_models.properties.core."
193-
"generic.generic_property"))
193+
"eos.enrtl_parameters"))
194194

195195
test_config = dict(configuration)
196196
test_config["parameter_data"] = {}

Diff for: idaes/surrogate/keras_surrogate.py

+16-6
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,30 @@
1313
"""
1414
Interface for importing Keras models into IDAES
1515
"""
16-
import numpy as np
16+
from enum import Enum
1717
import json
1818
import os.path
1919

20+
import numpy as np
21+
import pandas as pd
22+
2023
from pyomo.common.dependencies import attempt_import
2124
keras, keras_available = attempt_import('tensorflow.keras')
25+
omlt, omlt_available = attempt_import("omlt")
26+
27+
if omlt_available:
28+
from omlt import OmltBlock, OffsetScaling
29+
from omlt.neuralnet import (
30+
FullSpaceContinuousFormulation,
31+
ReducedSpaceContinuousFormulation,
32+
ReLUBigMFormulation,
33+
ReLUComplementarityFormulation,
34+
load_keras_sequential
35+
)
2236

23-
from enum import Enum
24-
import pandas as pd
2537
from idaes.surrogate.base.surrogate_base import SurrogateBase
2638
from idaes.surrogate.sampling.scaling import OffsetScaler
27-
from omlt import OmltBlock, OffsetScaling
28-
from omlt.neuralnet import (FullSpaceContinuousFormulation, ReducedSpaceContinuousFormulation,
29-
ReLUBigMFormulation, ReLUComplementarityFormulation, load_keras_sequential)
39+
3040

3141
class KerasSurrogate(SurrogateBase):
3242
def __init__(self, keras_model, input_labels, output_labels, input_bounds,

Diff for: idaes/surrogate/tests/test_keras_surrogate.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,20 @@
1515
"""
1616
import pytest
1717

18+
pytest.importorskip("tensorflow.keras", reason="tensorflow.keras not available")
19+
pytest.importorskip("omlt", reason="omlt not available")
20+
1821
import os.path
1922
import pandas as pd
2023
from pyomo.common.fileutils import this_file_dir
2124
from pyomo.common.tempfiles import TempfileManager
2225
from pyomo.environ import (ConcreteModel, Var, SolverFactory,
2326
assert_optimal_termination, value,
2427
Objective)
25-
from idaes.surrogate.keras_surrogate import KerasSurrogate, load_keras_json_hd5, keras_available
28+
from idaes.surrogate.keras_surrogate import KerasSurrogate, load_keras_json_hd5
2629
from idaes.surrogate.surrogate_block import SurrogateBlock
2730
from idaes.surrogate.sampling.scaling import OffsetScaler
2831

29-
if not keras_available:
30-
pytestmark = pytest.mark.skip("tensorflow.keras not available")
3132

3233
rtol = 1e-4
3334
atol = 1e-4

Diff for: idaes/tests/test_headers.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
from pathlib import Path
1818
import os
1919
# third-party
20-
from addheader.add import FileFinder, detect_files
2120
import pytest
2221
import yaml
2322

2423

24+
addheader_add = pytest.importorskip("addheader.add", reason="`addheader` package is not available")
25+
26+
2527
@pytest.fixture
2628
def package_root():
2729
"""Determine package root.
@@ -50,8 +52,8 @@ def test_headers(package_root, patterns):
5052
print(f"ERROR: Did not get glob patterns: skipping test")
5153
else:
5254
# modify patterns to match the files that should have headers
53-
ff = FileFinder(package_root, glob_patterns=patterns)
54-
has_header, missing_header = detect_files(ff)
55+
ff = addheader_add.FileFinder(package_root, glob_patterns=patterns)
56+
has_header, missing_header = addheader_add.detect_files(ff)
5557
# ignore empty files (probably should add option in 'detect_files' for this)
5658
nonempty_missing_header = list(filter(lambda p: p.stat().st_size > 0, missing_header))
5759
#
@@ -62,4 +64,3 @@ def test_headers(package_root, patterns):
6264
print(f"Missing headers from files under '{pfx}{os.path.sep}': {file_list}")
6365
# uncomment to require all files to have headers
6466
assert len(nonempty_missing_header) == 0
65-

Diff for: setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def dmf_data_files(root: str = DMF_DATA_ROOT) -> List[Tuple[str, List[str]]]:
109109
"tensorflow", # idaes.surrogate.keras_surrogate
110110
# A Lee 11-Jan-22: no precompiled version of CoolProp available for Pyhton 3.9
111111
"coolprop; python_version < '3.9'" # idaes.generic_models.properties.general.coolprop
112-
]
112+
],
113113
},
114114
package_data={
115115
# If any package contains these files, include them:

0 commit comments

Comments
 (0)