mirror of
https://github.com/Cantera/cantera.git
synced 2025-02-25 18:55:29 -06:00
[Python] Defer import of h5py until time of use
This avoids potential conflicts between the versions of libhdf5 linked to the Cantera library and h5py, which could occur when a C++ main application made use of the Python ExtensibleRate class.
This commit is contained in:
14
.github/workflows/main.yml
vendored
14
.github/workflows/main.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
run: |
|
||||
python3 -m pip install ruamel.yaml scons==3.1.2 numpy cython pandas pytest \
|
||||
pytest-github-actions-annotate-failures
|
||||
python3 -m pip install h5py || python3 -m pip install --no-binary=h5py h5py
|
||||
python3 -m pip install h5py
|
||||
- name: Build Cantera
|
||||
run: |
|
||||
python3 `which scons` build env_vars=all -j2 debug=n --debug=time \
|
||||
@@ -94,8 +94,7 @@ jobs:
|
||||
run: python3 -m pip install -U pip setuptools wheel
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python3 -m pip install ruamel.yaml scons numpy cython pandas pytest pytest-github-actions-annotate-failures
|
||||
python3 -m pip install --no-binary=h5py h5py
|
||||
python3 -m pip install ruamel.yaml scons numpy cython pandas h5py pytest pytest-github-actions-annotate-failures
|
||||
- name: Build Cantera
|
||||
run: python3 `which scons` build env_vars=all
|
||||
CXX=clang++-12 CC=clang-12 f90_interface=n extra_lib_dirs=/usr/lib/llvm/lib
|
||||
@@ -194,9 +193,8 @@ jobs:
|
||||
run: python3 -m pip install -U pip setuptools wheel
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python3 -m pip install ruamel.yaml scons numpy cython pandas scipy pytest \
|
||||
python3 -m pip install ruamel.yaml scons numpy cython pandas scipy pytest h5py \
|
||||
pytest-github-actions-annotate-failures pytest-cov gcovr
|
||||
python3 -m pip install --no-binary=h5py h5py
|
||||
- name: Setup .NET Core SDK
|
||||
uses: actions/setup-dotnet@v2
|
||||
with:
|
||||
@@ -366,8 +364,7 @@ jobs:
|
||||
run: python3 -m pip install -U pip setuptools wheel
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python3 -m pip install ruamel.yaml scons numpy cython pandas matplotlib scipy
|
||||
python3 -m pip install --no-binary=h5py h5py
|
||||
python3 -m pip install ruamel.yaml scons numpy cython pandas matplotlib scipy h5py
|
||||
- name: Build Cantera
|
||||
# compile with GCC 9.4.0 on ubuntu-20.04 as an alternative to the default
|
||||
# (GCC 7.5.0 is both default and oldest supported version)
|
||||
@@ -619,9 +616,8 @@ jobs:
|
||||
run: python3 -m pip install -U pip setuptools wheel
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python3 -m pip install ruamel.yaml scons numpy cython pandas pytest \
|
||||
python3 -m pip install ruamel.yaml scons numpy cython pandas h5py pytest \
|
||||
pytest-github-actions-annotate-failures
|
||||
python3 -m pip install --no-binary=h5py h5py
|
||||
- name: Setup Intel oneAPI environment
|
||||
run: |
|
||||
source /opt/intel/oneapi/setvars.sh
|
||||
|
||||
@@ -7,17 +7,20 @@ import numpy as np
|
||||
from collections import OrderedDict
|
||||
import csv as _csv
|
||||
|
||||
import pkg_resources
|
||||
|
||||
# avoid explicit dependence of cantera on h5py
|
||||
try:
|
||||
pkg_resources.get_distribution('h5py')
|
||||
except pkg_resources.DistributionNotFound:
|
||||
_h5py = ImportError('Method requires a working h5py installation.')
|
||||
else:
|
||||
import h5py as _h5py
|
||||
def _import_h5py():
|
||||
# avoid explicit dependence of cantera on h5py
|
||||
import pkg_resources # local import to reduce overall import time
|
||||
try:
|
||||
pkg_resources.get_distribution('h5py')
|
||||
except pkg_resources.DistributionNotFound:
|
||||
raise ImportError('Method requires a working h5py installation.')
|
||||
else:
|
||||
import h5py
|
||||
return h5py
|
||||
|
||||
# avoid explicit dependence of cantera on pandas
|
||||
import pkg_resources
|
||||
|
||||
try:
|
||||
pkg_resources.get_distribution('pandas')
|
||||
except pkg_resources.DistributionNotFound:
|
||||
@@ -1311,8 +1314,7 @@ class SolutionArray:
|
||||
requires a working installation of *h5py* (``h5py`` can be installed using
|
||||
pip or conda).
|
||||
"""
|
||||
if isinstance(_h5py, ImportError):
|
||||
raise _h5py
|
||||
h5py = _import_h5py()
|
||||
|
||||
# collect data
|
||||
data = self.collect_data(*args, cols=cols, **kwargs)
|
||||
@@ -1322,7 +1324,7 @@ class SolutionArray:
|
||||
hdf_kwargs = {k: v for k, v in hdf_kwargs.items() if v is not None}
|
||||
|
||||
# save to container file
|
||||
with _h5py.File(filename, mode) as hdf:
|
||||
with h5py.File(filename, mode) as hdf:
|
||||
|
||||
# check existence of tagged item
|
||||
if not group:
|
||||
@@ -1395,10 +1397,9 @@ class SolutionArray:
|
||||
The method imports data using `restore_data` and requires a working
|
||||
installation of *h5py* (``h5py`` can be installed using pip or conda).
|
||||
"""
|
||||
if isinstance(_h5py, ImportError):
|
||||
raise _h5py
|
||||
h5py = _import_h5py()
|
||||
|
||||
with _h5py.File(filename, 'r') as hdf:
|
||||
with h5py.File(filename, 'r') as hdf:
|
||||
|
||||
groups = list(hdf.keys())
|
||||
if not len(groups):
|
||||
@@ -1417,7 +1418,7 @@ class SolutionArray:
|
||||
# identify subgroup
|
||||
if subgroup is not None:
|
||||
sub_names = [key for key, value in root.items()
|
||||
if isinstance(value, _h5py.Group)]
|
||||
if isinstance(value, h5py.Group)]
|
||||
if not len(sub_names):
|
||||
msg = "HDF group '{}' does not contain valid data"
|
||||
raise IOError(msg.format(group))
|
||||
@@ -1454,13 +1455,13 @@ class SolutionArray:
|
||||
self._meta = dict(dgroup.attrs.items())
|
||||
for name, value in dgroup.items():
|
||||
# support one level of recursion
|
||||
if isinstance(value, _h5py.Group):
|
||||
if isinstance(value, h5py.Group):
|
||||
self._meta[name] = dict(value.attrs.items())
|
||||
|
||||
# load data
|
||||
data = OrderedDict()
|
||||
for name, value in dgroup.items():
|
||||
if isinstance(value, _h5py.Group):
|
||||
if isinstance(value, h5py.Group):
|
||||
continue
|
||||
elif value.dtype.type == np.bytes_:
|
||||
data[name] = np.array(value).astype('U')
|
||||
|
||||
@@ -518,10 +518,6 @@ TEST(Reaction, PythonExtensibleRate)
|
||||
#ifndef CT_HAS_PYTHON
|
||||
GTEST_SKIP();
|
||||
#endif
|
||||
#ifdef CT_USE_HDF5
|
||||
// potential mismatch of HDF libraries between h5py and HighFive
|
||||
GTEST_SKIP();
|
||||
#endif
|
||||
auto sol = newSolution("extensible-reactions.yaml");
|
||||
auto R = sol->kinetics()->reaction(0);
|
||||
EXPECT_EQ(R->type(), "square-rate");
|
||||
|
||||
@@ -5,7 +5,14 @@ from collections import OrderedDict
|
||||
import pickle
|
||||
|
||||
import cantera as ct
|
||||
from cantera.composite import _h5py, _pandas
|
||||
|
||||
try:
|
||||
h5py = ct.composite._import_h5py()
|
||||
have_h5py = True
|
||||
except ImportError:
|
||||
have_h5py = False
|
||||
|
||||
from cantera.composite import _pandas
|
||||
from . import utilities
|
||||
|
||||
|
||||
@@ -255,7 +262,7 @@ class TestSolutionArrayIO(utilities.CanteraTest):
|
||||
self.assertEqual(states[0].P, gas.P)
|
||||
self.assertArrayNear(states[0].Y, gas.Y)
|
||||
|
||||
@utilities.unittest.skipIf(isinstance(_h5py, ImportError), "h5py is not installed")
|
||||
@utilities.unittest.skipIf(not have_h5py, "h5py is not installed")
|
||||
def test_import_no_norm_data(self):
|
||||
outfile = self.test_work_path / "solutionarray.h5"
|
||||
# In Python >= 3.8, this can be replaced by the missing_ok argument
|
||||
@@ -336,7 +343,7 @@ class TestSolutionArrayIO(utilities.CanteraTest):
|
||||
with self.assertRaisesRegex(NotImplementedError, 'not supported'):
|
||||
states.to_pandas()
|
||||
|
||||
@utilities.unittest.skipIf(isinstance(_h5py, ImportError), "h5py is not installed")
|
||||
@utilities.unittest.skipIf(not have_h5py, "h5py is not installed")
|
||||
def test_write_hdf(self):
|
||||
outfile = self.test_work_path / "solutionarray.h5"
|
||||
# In Python >= 3.8, this can be replaced by the missing_ok argument
|
||||
@@ -365,7 +372,7 @@ class TestSolutionArrayIO(utilities.CanteraTest):
|
||||
gas = ct.Solution('gri30.yaml', transport_model=None)
|
||||
ct.SolutionArray(gas, 10).write_hdf(outfile)
|
||||
|
||||
with _h5py.File(outfile, 'a') as hdf:
|
||||
with h5py.File(outfile, 'a') as hdf:
|
||||
hdf.create_group('spam')
|
||||
|
||||
c = ct.SolutionArray(self.gas)
|
||||
@@ -382,7 +389,7 @@ class TestSolutionArrayIO(utilities.CanteraTest):
|
||||
c.read_hdf(outfile, group='foo/bar/baz')
|
||||
self.assertArrayNear(states.T, c.T)
|
||||
|
||||
@utilities.unittest.skipIf(isinstance(_h5py, ImportError), "h5py is not installed")
|
||||
@utilities.unittest.skipIf(not have_h5py, "h5py is not installed")
|
||||
def test_write_hdf_str_column(self):
|
||||
outfile = self.test_work_path / "solutionarray.h5"
|
||||
# In Python >= 3.8, this can be replaced by the missing_ok argument
|
||||
@@ -396,7 +403,7 @@ class TestSolutionArrayIO(utilities.CanteraTest):
|
||||
b.read_hdf(outfile)
|
||||
self.assertEqual(list(states.spam), list(b.spam))
|
||||
|
||||
@utilities.unittest.skipIf(isinstance(_h5py, ImportError), "h5py is not installed")
|
||||
@utilities.unittest.skipIf(not have_h5py, "h5py is not installed")
|
||||
def test_write_hdf_multidim_column(self):
|
||||
outfile = self.test_work_path / "solutionarray.h5"
|
||||
# In Python >= 3.8, this can be replaced by the missing_ok argument
|
||||
@@ -571,7 +578,7 @@ class TestRestorePureFluid(utilities.CanteraTest):
|
||||
b.restore_data(data)
|
||||
check(a, b)
|
||||
|
||||
@utilities.unittest.skipIf(isinstance(_h5py, ImportError), "h5py is not installed")
|
||||
@utilities.unittest.skipIf(not have_h5py, "h5py is not installed")
|
||||
def test_import_no_norm_water(self):
|
||||
outfile = self.test_work_path / "solutionarray.h5"
|
||||
# In Python >= 3.8, this can be replaced by the missing_ok argument
|
||||
|
||||
@@ -4,8 +4,6 @@ import numpy as np
|
||||
from .utilities import allow_deprecated
|
||||
import pytest
|
||||
|
||||
from cantera.composite import _h5py
|
||||
|
||||
|
||||
class TestOnedim(utilities.CanteraTest):
|
||||
def test_instantiate(self):
|
||||
|
||||
Reference in New Issue
Block a user