Skip to content

Commit 9b6e0a2

Browse files
authored
Fix broken tests (#158)
* Fix compatibility issues, drop Python 3.9, and pull Git LFS fiels handling - Removed Python 3.9 from CI due to compatibility issues - Fixed None values for element properties - Added Git LFS pull instructions to GitHub workflows * upadte pytest
1 parent 9cd8ec4 commit 9b6e0a2

5 files changed

Lines changed: 89 additions & 65 deletions

File tree

.github/workflows/pytest.yaml

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,32 +22,18 @@ jobs:
2222

2323
steps:
2424
- uses: "actions/checkout@v4"
25+
# Whether to download Git-LFS files
26+
with:
27+
lfs: true
2528

2629
- name: Setup python for test ${{ matrix.py }}
2730
uses: actions/setup-python@v5
2831
with:
2932
python-version: ${{ matrix.py }}
3033

31-
- name: Install system dependencies for PyTables (Linux/macOS)
32-
run: |
33-
python -m pip install --upgrade pip wheel
34-
pip install numpy==1.26.4
35-
if [[ "$RUNNER_OS" == "Linux" ]]; then
36-
sudo apt-get update
37-
sudo apt-get install -y libhdf5-dev libblosc-dev
38-
elif [[ "$RUNNER_OS" == "macOS" ]]; then
39-
export HOMEBREW_NO_INSTALL_CLEANUP=1
40-
brew update
41-
brew install hdf5 c-blosc
42-
export CPATH="$(brew --prefix hdf5)/include:$(brew --prefix c-blosc)/include:$CPATH"
43-
export LIBRARY_PATH="$(brew --prefix hdf5)/lib:$(brew --prefix c-blosc)/lib:$LIBRARY_PATH"
44-
export HDF5_DIR="$(brew --prefix hdf5)"
45-
fi
46-
47-
4834
- name: Install development version
4935
run: |
50-
pip install -v .
36+
pip install -e .
5137
5238
- name: Install extra test dependencies
5339
run: |
@@ -77,5 +63,3 @@ jobs:
7763
click-to-expand: true
7864
report-title: 'Dev Test Report'
7965
pytest-args: '-m dev'
80-
81-

atomdb/data/elements_data.h5

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
version https://git-lfs.github.com/spec/v1
2-
oid sha256:fde2a5f5db8c0adb8418016ea8b85d5f12af4e2e40a7f07bef7bcfe474ae3e81
2+
oid sha256:af6bc5014271228a3f11c7b64e4dfc5b41a28193c77bd319d59ca8043f2aa4b9
33
size 105117616

atomdb/migration/periodic/elements_data.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import warnings
66
from atomdb.utils import CONVERTOR_TYPES
77

8+
89
# Suppresses NaturalNameWarning warnings from PyTables.
910
warnings.filterwarnings('ignore', category=pt.NaturalNameWarning)
1011

@@ -25,7 +26,7 @@
2526

2627
{
2728
'basic_property': 'symbol',
28-
'table_name': 'symbol',
29+
'table_name': 'elem',
2930
'description': 'Atom Symbol',
3031
'type': 'string',
3132
},

atomdb/species.py

Lines changed: 78 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,19 @@
3838
from numbers import Integral
3939

4040
elements_hdf5_file = files("atomdb.data").joinpath("elements_data.h5")
41-
42-
PROPERTY_NAME_MAP = {
43-
"atmass": "atmass",
44-
"cov_radius": "cov_radius",
45-
"vdw_radius": "vdw_radius",
46-
"at_radius": "at_radius",
47-
"polarizability": "polarizability",
48-
"dispersion_c6": "dispersion_c6",
49-
"elem": "symbol",
50-
"atnum": "atnum",
51-
"name": "name",
52-
}
41+
ELEMENTS_H5FILE = pt.open_file(elements_hdf5_file, mode="r")
42+
43+
PROPERTY_NAME_MAP = [
44+
"atmass",
45+
"cov_radius",
46+
"vdw_radius",
47+
"at_radius",
48+
"polarizability",
49+
"dispersion_c6",
50+
"elem",
51+
"atnum",
52+
"name"
53+
]
5354

5455
__all__ = [
5556
"Species",
@@ -116,6 +117,42 @@ def default_matrix():
116117
# return wrapper
117118

118119

120+
# def scalar(method):
121+
# r"""Expose a SpeciesData field."""
122+
# name = method.__name__
123+
#
124+
# @property
125+
# def wrapper(self):
126+
# print("hi")
127+
#
128+
# # Map the name of the method in the SpeciesData class to the name in the Elements class
129+
# # This dict can be removed if the Elements csv file uses the same names as the SpeciesData class.
130+
# namemap = {
131+
# "cov_radius": "cov_radius",
132+
# "vdw_radius": "vdw_radius",
133+
# "at_radius": "at_radius",
134+
# "polarizability": "pold",
135+
# "dispersion_c6": "c6",
136+
# "atmass": "mass",
137+
# }
138+
#
139+
# if name == "atmass":
140+
# print(f"inside atmass {getattr(Element(self._data.elem), namemap[name])}")
141+
# return getattr(Element(self._data.elem), namemap[name])
142+
# if name in namemap:
143+
# # Only return Element property if neutral, otherwise None
144+
# charge = self._data.atnum - self._data.nelec
145+
# print(f"charge {charge}")
146+
# print(f"inside the other {getattr(Element(self._data.elem), namemap[name])}")
147+
# return getattr(Element(self._data.elem), namemap[name]) if charge == 0 else None
148+
#
149+
# return getattr(self._data, name)
150+
#
151+
# # conserve the docstring of the method
152+
# wrapper.__doc__ = method.__doc__
153+
# return wrapper
154+
155+
119156
def scalar(method):
120157
r"""Expose a SpeciesData field."""
121158
name = method.__name__
@@ -128,39 +165,37 @@ def wrapper(self):
128165

129166
# calculate charge then if charge is not zero (ions) --> return none
130167
charge = self._data.atnum - self._data.nelec
131-
if charge != 0:
168+
if charge != 0 and name not in ["atmass", "elem", "atnum", "name"]:
132169
return None
133170

134-
# open the HDF5 file in read mode
135-
with pt.open_file(elements_hdf5_file, mode="r") as h5file:
136-
# get the element group
137-
element_group = f"/Elements/{self._data.atnum:03d}"
138-
139-
table_name = PROPERTY_NAME_MAP[name]
140-
table_path = f"{element_group}/{table_name}"
141-
142-
# get the table node from the HDF5 file
143-
table = h5file.get_node(table_path)
144-
145-
# Handle basic properties (single row)
146-
if table.nrows == 1:
147-
value = table[0]["value"]
148-
# if the value is an int, return it as an int
149-
if isinstance(value, Integral):
150-
return int(value)
151-
# if the value is a string, decode from bytes
152-
elif isinstance(value, bytes):
153-
return value.decode("utf-8")
154-
else:
155-
# handle properties with multiple sources
156-
result = {}
157-
for row in table:
158-
source = row["source"].decode("utf-8")
159-
value = row["value"]
160-
# exclude none values
161-
if not np.isnan(value):
162-
result[source] = float(value)
163-
return result if result else None
171+
# get the element group
172+
element_group = f"/Elements/{self._data.atnum:03d}"
173+
174+
table_name = name #PROPERTY_NAME_MAP[name]
175+
table_path = f"{element_group}/{table_name}"
176+
177+
# get the table node from the HDF5 file
178+
table = ELEMENTS_H5FILE.get_node(table_path)
179+
180+
# Handle basic properties (single column --> no sources)
181+
if len(table.colnames) == 1 and table.colnames[0] == "value":
182+
value = table[0]["value"]
183+
# if the value is an int, return it as an int
184+
if isinstance(value, Integral):
185+
return int(value)
186+
# if the value is a string, decode from bytes
187+
elif isinstance(value, bytes):
188+
return value.decode("utf-8")
189+
else:
190+
# handle properties with multiple sources
191+
result = {}
192+
for row in table:
193+
source = row["source"].decode("utf-8")
194+
value = row["value"]
195+
# exclude none values
196+
if not np.isnan(value):
197+
result[source] = float(value)
198+
return result if result else None
164199

165200
wrapper.__doc__ = method.__doc__
166201
return wrapper

atomdb/test/test_nist.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
TEST_DATAPATH = files("atomdb.test.data")
1212
TEST_DATAPATH = os.fspath(TEST_DATAPATH._paths[0])
1313

14+
ELEMENTS_HDF5_FILE = files("atomdb.data").joinpath("elements_data.h5")
1415

1516
TEST_CASES_MAKE_PROMOLECULE = [
1617
pytest.param(
@@ -151,6 +152,9 @@ def test_nist_data(case):
151152
"""
152153
Test getting the attributes of the atom for Hydrogen and Carbon.
153154
"""
155+
if not ELEMENTS_HDF5_FILE.exists():
156+
pytest.skip(f"Required data file not found: {ELEMENTS_HDF5_FILE}")
157+
154158
elem = case.get("elem")
155159
charge = case.get("atnum") - case.get("nelec")
156160
mult = case.get("nspin") + 1

0 commit comments

Comments
 (0)