diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3064bc20b..394e10047 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -79,8 +79,8 @@ jobs: echo "SDKROOT: ${SDKROOT}" echo "SDKROOT=${SDKROOT}" >> $GITHUB_ENV echo "CONDA_BUILD_SYSROOT=${SDKROOT}" >> $GITHUB_ENV - echo "CFLAGS=-I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include" >> $GITHUB_ENV - echo "LDFLAGS=-L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib" >> $GITHUB_ENV + echo "CFLAGS=-I${SDKROOT}/usr/include" >> $GITHUB_ENV + echo "LDFLAGS=-L${SDKROOT}/usr/lib" >> $GITHUB_ENV - name: Set current date as environment variable run: echo "TODAY=$(date +'%Y.%m.%d')" >> $GITHUB_ENV diff --git a/benchmarks/conftest.py b/benchmarks/conftest.py index 311b28d29..b5bb3c9fc 100644 --- a/benchmarks/conftest.py +++ b/benchmarks/conftest.py @@ -1,6 +1,7 @@ """Config file for pytest. Allow caching for faster test completion. `$ pytest tests/ --use-cache` """ +import pytest def pytest_addoption(parser): @@ -11,3 +12,37 @@ def pytest_generate_tests(metafunc): if metafunc.config.getoption("use_cache"): import pyccl pyccl.Caching.enable() + + +def _isitgr_unusable_reason(): + """Return why isitgr cannot be used (None if it can). An installed + but unloadable isitgr (e.g. an invalid shared library) raises OSError, + not ImportError.""" + try: + import isitgr # noqa: F401 + except (ImportError, OSError) as exc: + return f"isitgr is not usable: {exc!r}" + return None + + +_ISITGR_REASON = _isitgr_unusable_reason() +_USES_ISITGR = {} + + +def _module_uses_isitgr(path): + # The isitgr transfer function is requested inside the tests, not through + # a pytest parameter, so look at the source of the test module. + if path not in _USES_ISITGR: + _USES_ISITGR[path] = "boltzmann_isitgr" in path.read_text( + encoding="utf-8") + return _USES_ISITGR[path] + + +def pytest_collection_modifyitems(config, items): + # Skip the benchmarks that need a working isitgr when it is unavailable. + if _ISITGR_REASON is None: + return + skip = pytest.mark.skip(reason=_ISITGR_REASON) + for item in items: + if _module_uses_isitgr(item.path): + item.add_marker(skip) diff --git a/pyccl/boltzmann.py b/pyccl/boltzmann.py index 7f0e76407..bb337ff75 100644 --- a/pyccl/boltzmann.py +++ b/pyccl/boltzmann.py @@ -4,7 +4,7 @@ try: import isitgr # noqa: F401 -except ModuleNotFoundError: +except (ImportError, OSError): pass # prevent nans from isitgr from . import CCLError, Pk2D, check, lib, sigma8 diff --git a/pyccl/tests/conftest.py b/pyccl/tests/conftest.py index 7e68afe4f..6cdbc2562 100644 --- a/pyccl/tests/conftest.py +++ b/pyccl/tests/conftest.py @@ -1,6 +1,8 @@ """Config file for pytest. Allow caching for faster test completion. `$ pytest tests/ --use-cache` """ +import pytest + from .test_cclobject import all_subclasses, init_decorator import pyccl @@ -15,6 +17,36 @@ def pytest_generate_tests(metafunc): pyccl.Caching.enable() +def _isitgr_unusable_reason(): + """Return why isitgr cannot be used (None if it can). An installed + but unloadable isitgr (e.g. an invalid shared library) raises OSError, + not ImportError.""" + try: + import isitgr # noqa: F401 + except (ImportError, OSError) as exc: + return f"isitgr is not usable: {exc!r}" + return None + + +_ISITGR_REASON = _isitgr_unusable_reason() + + +def pytest_collection_modifyitems(config, items): + # Skip the tests that need a working isitgr when it is unavailable. + if _ISITGR_REASON is None: + return + skip = pytest.mark.skip(reason=_ISITGR_REASON) + for item in items: + callspec = getattr(item, "callspec", None) + if callspec is None: + continue + # Only compare string parameters: other parameters may be arrays, + # for which `==` would not return a single bool. + if any(isinstance(val, str) and val == "boltzmann_isitgr" + for val in callspec.params.values()): + item.add_marker(skip) + + # For testing, we want to make sure that all instances of the subclasses # of `CCLAutoRepr` contain all attributes listed in `__repr_attrs__`. # We run some things post-init for these subclasses, which are triggered diff --git a/pyccl/tests/test_power_mu_sigma_sigma8norm.py b/pyccl/tests/test_power_mu_sigma_sigma8norm.py index 55fb1732d..c73ce211c 100644 --- a/pyccl/tests/test_power_mu_sigma_sigma8norm.py +++ b/pyccl/tests/test_power_mu_sigma_sigma8norm.py @@ -94,3 +94,15 @@ def test_nonlin_camb_MG_error(): # Check that non-linear power spectrum isn't being used with sigma8 with pytest.raises(ValueError): ccl.nonlin_matter_power(ccl_cosmo, k, 1.0) + + +def test_import_survives_broken_isitgr(tmp_path, monkeypatch): + """An installed but unloadable isitgr (e.g. an invalid shared library + raising OSError at import) must not prevent importing pyccl.""" + pkg = tmp_path / "isitgr" + pkg.mkdir() + (pkg / "__init__.py").write_text("raise OSError('invalid shared lib')\n") + monkeypatch.syspath_prepend(str(tmp_path)) + with mock.patch.dict(sys.modules): + sys.modules.pop("isitgr", None) + reload(ccl.boltzmann)