Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Officially support Python 3.12 and test in CI #3685

Merged
merged 10 commits into from
May 1, 2024
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
- uses: actions/setup-python@v5
name: Install Python
with:
python-version: "3.11"
python-version: "3.12"

- name: Build sdist
run: |
Expand All @@ -45,7 +45,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-14, windows-latest]
python-version: ["39", "310", "311"]
python-version: ["39", "310", "311", "312"]
runs-on: ${{ matrix.os }}
steps:
- name: Check out repo
Expand All @@ -68,10 +68,10 @@ jobs:
# For pypi trusted publishing
id-token: write
steps:
- name: Set up Python 3.11
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.11
python-version: "3.12"

- name: Get build artifacts
uses: actions/download-artifact@v3
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,16 @@ jobs:
matrix:
# pytest-split automatically distributes work load so parallel jobs finish in similar time
os: [ubuntu-latest, windows-latest]
python-version: ["3.9", "3.11"]
python-version: ["3.9", "3.12"]
split: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# include/exclude is meant to maximize CI coverage of different platforms and python
# versions while minimizing the total number of jobs. We run all pytest splits with the
# oldest supported python version (currently 3.9) on windows (seems most likely to surface
# errors) and with newest version (currently 3.11) on ubuntu (to get complete and speedy
# errors) and with newest version (currently 3.12) on ubuntu (to get complete and speedy
# coverage on unix). We ignore mac-os, which is assumed to be similar to ubuntu.
exclude:
- os: windows-latest
python-version: "3.11"
python-version: "3.12"
- os: ubuntu-latest
python-version: "3.9"

Expand Down
4 changes: 2 additions & 2 deletions dev_scripts/chemenv/get_plane_permutations_optimized.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ def random_permutations_iterator(initial_permutation, n_permutations):
# Definition of the facets
all_planes_point_indices = [algo.plane_points]
if algo.other_plane_points is not None:
all_planes_point_indices.extend(algo.other_plane_points)
all_planes_point_indices += algo.other_plane_points

# Loop on the facets
explicit_permutations_per_plane = []
Expand Down Expand Up @@ -305,7 +305,7 @@ def random_permutations_iterator(initial_permutation, n_permutations):
# Definition of the facets
all_planes_point_indices = [algo.plane_points]
if algo.other_plane_points is not None:
all_planes_point_indices.extend(algo.other_plane_points)
all_planes_point_indices += algo.other_plane_points

# Setup of the permutations to be used for this algorithm

Expand Down
6 changes: 3 additions & 3 deletions dev_scripts/chemenv/plane_multiplicity.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
__date__ = "Feb 20, 2016"

if __name__ == "__main__":
allcg = AllCoordinationGeometries()
all_cg = AllCoordinationGeometries()

cg_symbol = "I:12"
all_plane_points = []
cg = allcg[cg_symbol]
cg = all_cg[cg_symbol]

# I:12
if cg_symbol == "I:12":
Expand All @@ -25,7 +25,7 @@
for edge in edges:
opposite_edge = [opposite_points[edge[0]], opposite_points[edge[1]]]
equiv_plane = list(edge)
equiv_plane.extend(opposite_edge)
equiv_plane += opposite_edge
equiv_plane.sort()
all_plane_points.append(tuple(equiv_plane))
all_plane_points = [tuple(equiv_plane) for equiv_plane in set(all_plane_points)]
Expand Down
2 changes: 1 addition & 1 deletion pymatgen/alchemy/materials.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ def __str__(self) -> str:
for hist in self.history:
hist.pop("input_structure", None)
output.append(str(hist))
output.extend(("\nOther parameters", "------------", str(self.other_parameters)))
output += ("\nOther parameters", "------------", str(self.other_parameters))
return "\n".join(output)

def set_parameter(self, key: str, value: Any) -> TransformedStructure:
Expand Down
16 changes: 8 additions & 8 deletions pymatgen/alchemy/transmuters.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ def append_transformation(self, transformation, extend_collection=False, clear_r
for x in self.transformed_structures:
new = x.append_transformation(transformation, extend_collection, clear_redo=clear_redo)
if new is not None:
new_structures.extend(new)
self.transformed_structures.extend(new_structures)
new_structures += new
self.transformed_structures += new_structures

def extend_transformations(self, transformations):
"""Extends a sequence of transformations to the TransformedStructure.
Expand All @@ -142,7 +142,7 @@ def extend_transformations(self, transformations):
for trafo in transformations:
self.append_transformation(trafo)

def apply_filter(self, structure_filter):
def apply_filter(self, structure_filter: Callable):
"""Applies a structure_filter to the list of TransformedStructures
in the transmuter.

Expand Down Expand Up @@ -196,11 +196,11 @@ def append_transformed_structures(self, trafo_structs_or_transmuter):
transmuter.
"""
if isinstance(trafo_structs_or_transmuter, self.__class__):
self.transformed_structures.extend(trafo_structs_or_transmuter.transformed_structures)
self.transformed_structures += trafo_structs_or_transmuter.transformed_structures
else:
for ts in trafo_structs_or_transmuter:
assert isinstance(ts, TransformedStructure)
self.transformed_structures.extend(trafo_structs_or_transmuter)
self.transformed_structures += trafo_structs_or_transmuter

@classmethod
def from_structures(cls, structures, transformations=None, extend_collection=0) -> Self:
Expand Down Expand Up @@ -373,7 +373,7 @@ def _apply_transformation(inputs):
"""
ts, transformation, extend_collection, clear_redo = inputs
new = ts.append_transformation(transformation, extend_collection, clear_redo=clear_redo)
o = [ts]
out = [ts]
if new:
o.extend(new)
return o
out += new
return out
18 changes: 7 additions & 11 deletions pymatgen/io/vasp/outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1480,7 +1480,7 @@ def _parse_calculation(self, elem):
return istep

@staticmethod
def _parse_dos(elem):
def _parse_dos(elem) -> tuple[Dos, Dos, list[dict]]:
efermi = float(elem.find("i").text)
energies = None
tdensities = {}
Expand All @@ -1500,22 +1500,18 @@ def _parse_dos(elem):
orbs.pop(0)
lm = any("x" in s for s in orbs)
for s in partial.find("array").find("set").findall("set"):
pdos = defaultdict(dict)
pdos: dict[Orbital | OrbitalType, dict[Spin, np.ndarray]] = defaultdict(dict)

for ss in s.findall("set"):
spin = Spin.up if ss.attrib["comment"] == "spin 1" else Spin.down
data = np.array(_parse_vasp_array(ss))
_nrow, ncol = data.shape
for j in range(1, ncol):
orb = Orbital(j - 1) if lm else OrbitalType(j - 1)
pdos[orb][spin] = data[:, j]
_n_row, n_col = data.shape
for col_idx in range(1, n_col):
orb = Orbital(col_idx - 1) if lm else OrbitalType(col_idx - 1)
pdos[orb][spin] = data[:, col_idx] # type: ignore[index]
pdoss.append(pdos)
elem.clear()
return (
Dos(efermi, energies, tdensities),
Dos(efermi, energies, idensities),
pdoss,
)
return Dos(efermi, energies, tdensities), Dos(efermi, energies, idensities), pdoss

@staticmethod
def _parse_eigen(elem):
Expand Down
11 changes: 7 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@
],
extras_require={
"ase": ["ase>=3.3"],
"tblite": ["tblite[ase]>=0.3.0"],
# don't depend on tblite above 3.11 since unsupported https://github.com/tblite/tblite/issues/175
"tblite": ["tblite[ase]>=0.3.0; python_version<'3.12'"],
"vis": ["vtk>=6.0.0"],
"abinit": ["netcdf4"],
"relaxation": ["matgl", "chgnet"],
"relaxation": ["matgl", "chgnet>=0.3.0"],
"electronic_structure": ["fdint>=2.0.2"],
"dev": [
"mypy",
Expand All @@ -74,7 +75,7 @@
# caused CI failure due to ModuleNotFoundError: No module named 'packaging'
# "BoltzTraP2>=22.3.2; platform_system!='Windows'",
"chemview>=0.6",
"chgnet",
"chgnet>=0.3.0",
"f90nml>=1.1.2",
"galore>=0.6.1",
"h5py>=3.8.0",
Expand All @@ -83,7 +84,8 @@
"netCDF4>=1.5.8",
"phonopy>=2.4.2",
"seekpath>=1.9.4",
"tblite[ase]>=0.3.0; platform_system=='Linux'",
# don't depend on tblite above 3.11 since unsupported https://github.com/tblite/tblite/issues/175
"tblite[ase]>=0.3.0; platform_system=='Linux' and python_version<'3.12'",
# "hiphive>=0.6",
# "openbabel>=3.1.1; platform_system=='Linux'",
],
Expand Down Expand Up @@ -159,6 +161,7 @@
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3",
"Topic :: Scientific/Engineering :: Chemistry",
"Topic :: Scientific/Engineering :: Information Analysis",
Expand Down
22 changes: 11 additions & 11 deletions tests/io/vasp/test_outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from pymatgen.electronic_structure.bandstructure import BandStructureSymmLine
from pymatgen.electronic_structure.core import Magmom, Orbital, OrbitalType, Spin
from pymatgen.entries.compatibility import MaterialsProjectCompatibility
from pymatgen.io.vasp.inputs import Kpoints, Poscar, Potcar
from pymatgen.io.vasp.inputs import Incar, Kpoints, Poscar, Potcar
from pymatgen.io.vasp.outputs import (
WSWQ,
BSVasprun,
Expand Down Expand Up @@ -251,8 +251,8 @@ def test_standard(self):
assert len(trajectory) == len(vasp_run.ionic_steps)
assert "forces" in trajectory[0].site_properties

for i, step in enumerate(vasp_run.ionic_steps):
assert vasp_run.structures[i] == step["structure"]
for idx, step in enumerate(vasp_run.ionic_steps):
assert vasp_run.structures[idx] == step["structure"]

assert all(
vasp_run.structures[idx] == vasp_run.ionic_steps[idx]["structure"]
Expand All @@ -263,27 +263,27 @@ def test_standard(self):

assert vasp_run.atomic_symbols == ["Li"] + 4 * ["Fe"] + 4 * ["P"] + 16 * ["O"]
assert vasp_run.final_structure.reduced_formula == "LiFe4(PO4)4"
assert vasp_run.incar is not None, "Incar cannot be read"
assert vasp_run.kpoints is not None, "Kpoints cannot be read"
assert vasp_run.eigenvalues is not None, "Eigenvalues cannot be read"
assert isinstance(vasp_run.incar, Incar), f"{vasp_run.incar=}"
assert isinstance(vasp_run.kpoints, Kpoints), f"{vasp_run.kpoints=}"
assert isinstance(vasp_run.eigenvalues, Eigenval), f"{vasp_run.eigenvalues=}"
assert vasp_run.final_energy == approx(-269.38319884, abs=1e-7)
assert vasp_run.tdos.get_gap() == approx(2.0589, abs=1e-4)
expected = (2.539, 4.0906, 1.5516, False)
assert vasp_run.eigenvalue_band_properties == approx(expected)
assert not vasp_run.is_hubbard
assert vasp_run.is_hubbard is False
assert vasp_run.potcar_symbols == [
"PAW_PBE Li 17Jan2003",
"PAW_PBE Fe 06Sep2000",
"PAW_PBE Fe 06Sep2000",
"PAW_PBE P 17Jan2003",
"PAW_PBE O 08Apr2002",
]
assert vasp_run.kpoints is not None, "Kpoints cannot be read"
assert vasp_run.actual_kpoints is not None, "Actual kpoints cannot be read"
assert vasp_run.actual_kpoints_weights is not None, "Actual kpoints weights cannot be read"
assert isinstance(vasp_run.kpoints, Kpoints), f"{vasp_run.kpoints=}"
assert isinstance(vasp_run.actual_kpoints, list), f"{vasp_run.actual_kpoints=}"
assert isinstance(vasp_run.actual_kpoints_weights, list), f"{vasp_run.actual_kpoints_weights=}"
for atom_doses in vasp_run.pdos:
for orbital_dos in atom_doses:
assert orbital_dos is not None, "Partial Dos cannot be read"
assert isinstance(orbital_dos, Orbital), f"{orbital_dos=}"

# test skipping ionic steps.
vasprun_skip = Vasprun(filepath, 3, parse_potcar_file=False)
Expand Down
Loading