Skip to content

Commit 7a01f3c

Browse files
DanielYang59janosh
andauthored
Install some optional dependencies in CI (#3786)
* enable `boltztrap2` * Revert "enable `boltztrap2`" This reverts commit 3b1b077. * use explicit encoding * install graphviz * increment boltztrap version to 24.1.1 * fix bader patch * pre-commit auto-fixes * ruff fix * tweak bader test * need confirm: add `wheel` to dev dep * try install BoltzTraP2 with pip * add comment * try move bolt after numpy to fix win, remove wheel * try move boltrap2 to ubuntu only * more description more accurate * install BoltzTraP2 in CI * try to install BoltzTraP2 with uv * remove repeated numpy install in CI tests * update np.exceptions.RankWarning * Revert "update np.exceptions.RankWarning" This reverts commit 4128284. * install setuptool with uv * update BoltzTraP2 * install wheel for building boltztrap2 * try to install boltztrap2 with pip not uv * install cython before boltztrap2 * try to install boltztrap2 with optional * try to manually install bt2 in workflow * manually install bt2 with pip * remove bt2 ver * install bt2 only on ubuntu * skip bt2 for windows * try to fix failing bt2 test * more descriptive skip msg * finish typing of bzt2 * try to install pygraphviz * revert update to | replace for graphs * test.yml join install pymatgen and install dependencies steps * fix TestStructureGraph.test_draw unhashable type list error * skip BoltzTraP2 and matplotlib 3.9.1 --------- Co-authored-by: Janosh Riebesell <[email protected]>
1 parent 99f62d2 commit 7a01f3c

File tree

7 files changed

+63
-46
lines changed

7 files changed

+63
-46
lines changed

.github/workflows/test.yml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ jobs:
3535
resolution: highest
3636
extras: ci,optional
3737
- os: ubuntu-latest
38-
python: '>3.9'
38+
python: ">3.9"
3939
resolution: lowest-direct
4040
extras: ci,optional
4141
- os: macos-latest
42-
python: '3.10'
42+
python: "3.10"
4343
resolution: lowest-direct
4444
extras: ci # test with only required dependencies installed
4545

@@ -70,18 +70,29 @@ jobs:
7070
- name: Install ubuntu-only conda dependencies
7171
if: matrix.config.os == 'ubuntu-latest'
7272
run: |
73-
micromamba install -n pmg -c conda-forge enumlib packmol bader openbabel openff-toolkit --yes
73+
micromamba install -n pmg -c conda-forge enumlib packmol bader openbabel openff-toolkit pygraphviz --yes
7474
7575
- name: Install pymatgen and dependencies
7676
run: |
7777
micromamba activate pmg
78+
7879
# TODO remove temporary fix. added since uv install torch is flaky.
7980
# track https://github.com/astral-sh/uv/issues/1921 for resolution
8081
pip install torch --upgrade
8182
82-
uv pip install numpy cython
83+
uv pip install cython setuptools wheel
84+
8385
uv pip install --editable '.[${{ matrix.config.extras }}]' --resolution=${{ matrix.config.resolution }}
8486
87+
- name: Install optional Ubuntu dependencies
88+
if: matrix.config.os == 'ubuntu-latest'
89+
run: |
90+
micromamba activate pmg
91+
92+
# TODO: uv cannot install BoltzTraP2 (#3786),
93+
# suggesting no NumPy when there is
94+
pip install BoltzTraP2
95+
8596
- name: pytest split ${{ matrix.split }}
8697
run: |
8798
micromamba activate pmg

pyproject.toml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,8 @@ ci = ["pytest-cov>=4", "pytest-split>=0.8", "pytest>=8"]
9595
docs = ["sphinx", "sphinx_rtd_theme"]
9696
optional = [
9797
"ase>=3.23.0",
98-
# TODO restore BoltzTraP2 when install fixed, hopefully following merge of
99-
# https://gitlab.com/sousaw/BoltzTraP2/-/merge_requests/18
100-
# caused CI failure due to ModuleNotFoundError: No module named 'packaging'
101-
# "BoltzTraP2>=22.3.2; platform_system!='Windows'",
98+
# TODO: uv cannot install BoltzTraP2
99+
# "BoltzTraP2>=24.7.2 ; platform_system != 'Windows'",
102100
"chemview>=0.6",
103101
"chgnet>=0.3.8",
104102
"f90nml>=1.1.2",
@@ -107,7 +105,7 @@ optional = [
107105
"jarvis-tools>=2020.7.14",
108106
"matgl>=1.1.1",
109107
# TODO: track https://github.com/matplotlib/matplotlib/issues/28551
110-
"matplotlib>=3.8,<3.9.1",
108+
"matplotlib>=3.8,!=3.9.1",
111109
"netCDF4>=1.6.5",
112110
"phonopy>=2.23",
113111
"seekpath>=2.0.1",

src/pymatgen/analysis/graphs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ def draw_graph_to_file(
933933
d["label"] = f"{d['weight']:.2f} {units}"
934934

935935
# update edge with our new style attributes
936-
g.edges[u, v, k] |= d
936+
g.edges[u, v, k].update(d)
937937

938938
# optionally remove periodic image edges,
939939
# these can be confusing due to periodic boundaries
@@ -2603,7 +2603,7 @@ def draw_graph_to_file(
26032603
d["label"] = f"{d['weight']:.2f} {units}"
26042604

26052605
# update edge with our new style attributes
2606-
g.edges[u, v, k] |= d
2606+
g.edges[u, v, k].update(d)
26072607

26082608
# optionally remove periodic image edges,
26092609
# these can be confusing due to periodic boundaries

src/pymatgen/electronic_structure/boltztrap2.py

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444

4545
if TYPE_CHECKING:
4646
from pathlib import Path
47+
from typing import Literal
4748

4849
from typing_extensions import Self
4950

@@ -961,20 +962,20 @@ def __init__(self, bzt_transP=None, bzt_interp=None) -> None:
961962

962963
def plot_props(
963964
self,
964-
prop_y,
965-
prop_x,
966-
prop_z="temp",
967-
output="avg_eigs",
968-
dop_type="n",
969-
doping=None,
970-
temps=None,
971-
xlim=(-2, 2),
972-
ax: plt.Axes = None,
973-
):
965+
prop_y: str,
966+
prop_x: Literal["mu", "doping", "temp"],
967+
prop_z: Literal["doping", "temp"] = "temp",
968+
output: Literal["avg_eigs", "eigs"] = "avg_eigs",
969+
dop_type: Literal["n", "p"] = "n",
970+
doping: list[float] | None = None,
971+
temps: list[float] | None = None,
972+
xlim: tuple[float, float] = (-2, 2),
973+
ax: plt.Axes | None = None,
974+
) -> plt.Axes | plt.Figure:
974975
"""Plot the transport properties.
975976
976977
Args:
977-
prop_y: property to plot among ("Conductivity","Seebeck","Kappa","Carrier_conc",
978+
prop_y: property to plot among ("Conductivity", "Seebeck", "Kappa", "Carrier_conc",
978979
"Hall_carrier_conc_trace"). Abbreviations are possible, like "S" for "Seebeck"
979980
prop_x: independent variable in the x-axis among ('mu','doping','temp')
980981
prop_z: third variable to plot multiple curves ('doping','temp')
@@ -991,7 +992,9 @@ def plot_props(
991992
ax: figure.axes where to plot. If None, a new figure is produced.
992993
993994
Returns:
994-
plt.Axes: matplotlib Axes object
995+
plt.Axes: matplotlib Axes object if ax provided
996+
OR
997+
plt.Figure: matplotlib Figure object if ax is None
995998
996999
Example:
9971000
bztPlotter.plot_props('S','mu','temp',temps=[600,900,1200]).show()
@@ -1026,15 +1029,15 @@ def plot_props(
10261029
r"$(cm^{-3})$",
10271030
)
10281031

1029-
props_short = [p[: len(prop_y)] for p in props]
1032+
props_short = tuple(p[: len(prop_y)] for p in props)
10301033

10311034
if prop_y not in props_short:
10321035
raise BoltztrapError("prop_y not valid")
10331036

1034-
if prop_x not in ("mu", "doping", "temp"):
1037+
if prop_x not in {"mu", "doping", "temp"}:
10351038
raise BoltztrapError("prop_x not valid")
10361039

1037-
if prop_z not in ("doping", "temp"):
1040+
if prop_z not in {"doping", "temp"}:
10381041
raise BoltztrapError("prop_z not valid")
10391042

10401043
idx_prop = props_short.index(prop_y)
@@ -1048,8 +1051,7 @@ def plot_props(
10481051
else:
10491052
p_array = getattr(self.bzt_transP, f"{props[idx_prop]}_{prop_x}")
10501053

1051-
if ax is None:
1052-
plt.figure(figsize=(10, 8))
1054+
fig = plt.figure(figsize=(10, 8)) if ax is None else None
10531055

10541056
temps_all = self.bzt_transP.temp_r.tolist()
10551057
if temps is None:
@@ -1112,6 +1114,9 @@ def plot_props(
11121114
leg_title = f"{dop_type}-type"
11131115

11141116
elif prop_z == "doping" and prop_x == "temp":
1117+
if doping is None:
1118+
raise ValueError("doping cannot be None when prop_z is doping")
1119+
11151120
for dop in doping:
11161121
dop_idx = doping_all.index(dop)
11171122
prop_out = np.linalg.eigh(p_array[dop_type][:, dop_idx])[0]
@@ -1137,10 +1142,11 @@ def plot_props(
11371142
plt.ylabel(f"{props_lbl[idx_prop]} {props_unit[idx_prop]}", fontsize=30)
11381143
plt.xticks(fontsize=25)
11391144
plt.yticks(fontsize=25)
1140-
plt.legend(title=leg_title if leg_title != "" else "", fontsize=15)
1145+
plt.legend(title=leg_title or "", fontsize=15)
11411146
plt.tight_layout()
11421147
plt.grid()
1143-
return ax
1148+
1149+
return fig if ax is None else ax
11441150

11451151
def plot_bands(self):
11461152
"""Plot a band structure on symmetry line using BSPlotter()."""

tests/command_line/test_bader_caller.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import warnings
44
from shutil import which
5-
from unittest.mock import patch
65

76
import numpy as np
87
import pytest
@@ -60,7 +59,6 @@ def test_init(self):
6059
assert len(analysis.data) == 14
6160

6261
# Test Cube file format parsing
63-
6462
copy_r(TEST_DIR, self.tmp_path)
6563
analysis = BaderAnalysis(cube_filename=f"{TEST_DIR}/elec.cube.gz")
6664
assert len(analysis.data) == 9
@@ -76,17 +74,17 @@ def test_from_path(self):
7674
analysis = BaderAnalysis(chgcar_filename=chgcar_path, chgref_filename=chgref_path)
7775
analysis_from_path = BaderAnalysis.from_path(from_path_dir)
7876

79-
for key in analysis_from_path.summary:
80-
val, val_from_path = analysis.summary[key], analysis_from_path.summary[key]
81-
if isinstance(analysis_from_path.summary[key], (bool, str)):
77+
for key, val_from_path in analysis_from_path.summary.items():
78+
val = analysis.summary[key]
79+
if isinstance(val_from_path, (bool, str)):
8280
assert val == val_from_path, f"{key=}"
8381
elif key == "charge":
8482
assert_allclose(val, val_from_path, atol=1e-5)
8583

8684
def test_bader_analysis_from_path(self):
87-
summary = bader_analysis_from_path(TEST_DIR)
8885
"""
8986
Reference summary dict (with bader 1.0)
87+
9088
summary_ref = {
9189
"magmom": [4.298761, 4.221997, 4.221997, 3.816685, 4.221997, 4.298763, 0.36292, 0.370516, 0.36292,
9290
0.36292, 0.36292, 0.36292, 0.36292, 0.370516],
@@ -102,6 +100,9 @@ def test_bader_analysis_from_path(self):
102100
"reference_used": True,
103101
}
104102
"""
103+
104+
summary = bader_analysis_from_path(TEST_DIR)
105+
105106
assert set(summary) == {
106107
"magmom",
107108
"min_dist",
@@ -131,12 +132,11 @@ def test_atom_parsing(self):
131132
)
132133

133134
def test_missing_file_bader_exe_path(self):
134-
pytest.skip("doesn't reliably raise RuntimeError")
135-
# mock which("bader") to return None so we always fall back to use bader_exe_path
136-
with (
137-
patch("shutil.which", return_value=None),
138-
pytest.raises(
139-
RuntimeError, match="BaderAnalysis requires the executable bader be in the PATH or the full path "
140-
),
141-
):
142-
BaderAnalysis(chgcar_filename=f"{VASP_OUT_DIR}/CHGCAR.Fe3O4.gz", bader_exe_path="")
135+
# Mock which("bader") to return None so we always fall back to use bader_exe_path
136+
with pytest.MonkeyPatch.context() as monkeypatch:
137+
monkeypatch.setenv("PATH", "")
138+
139+
with pytest.raises(
140+
RuntimeError, match="Requires bader or bader.exe to be in the PATH or the absolute path"
141+
):
142+
BaderAnalysis(chgcar_filename=f"{VASP_OUT_DIR}/CHGCAR.Fe3O4.gz")

tests/electronic_structure/test_boltztrap2.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,9 @@ def test_plot(self):
316316
assert self.bztPlotter is not None
317317
fig = self.bztPlotter.plot_props("S", "mu", "temp", temps=[300, 500])
318318
assert fig is not None
319+
319320
fig = self.bztPlotter.plot_bands()
320321
assert fig is not None
322+
321323
fig = self.bztPlotter.plot_dos()
322324
assert fig is not None

tests/ext/test_cod.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
if "CI" in os.environ: # test is slow and flaky, skip in CI. see
1313
# https://github.com/materialsproject/pymatgen/pull/3777#issuecomment-2071217785
14-
pytest.skip(allow_module_level=True)
14+
pytest.skip(allow_module_level=True, reason="Skip COD test in CI")
1515

1616
try:
1717
website_down = requests.get("https://www.crystallography.net", timeout=600).status_code != 200

0 commit comments

Comments
 (0)