diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml
index c1c8d59b62..eda0638cbe 100644
--- a/.github/workflows/testing.yml
+++ b/.github/workflows/testing.yml
@@ -17,7 +17,7 @@ jobs:
- uses: actions/setup-python@v5
with:
- python-version: "3.9"
+ python-version: "3.10"
cache: pip
cache-dependency-path: pyproject.toml
@@ -36,7 +36,7 @@ jobs:
shell: bash -l {0} # enables conda/mamba env activation by reading bash profile
strategy:
matrix:
- python-version: ["3.9", "3.10", "3.11"]
+ python-version: ["3.10", "3.11", "3.12"]
steps:
- name: Check out repo
@@ -103,7 +103,7 @@ jobs:
shell: bash -l {0} # enables conda/mamba env activation by reading bash profile
strategy:
matrix:
- python-version: ["3.9", "3.10", "3.11"]
+ python-version: ["3.10", "3.11", "3.12"]
steps:
- name: Check out repo
diff --git a/.github/workflows/update-precommit.yml b/.github/workflows/update-precommit.yml
index 273be7171f..6959999283 100644
--- a/.github/workflows/update-precommit.yml
+++ b/.github/workflows/update-precommit.yml
@@ -15,7 +15,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
- python-version: 3.9
+ python-version: "3.10"
- name: Install pre-commit
run: pip install pre-commit
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 533a6d33db..203672442e 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -3,7 +3,7 @@ default_language_version:
exclude: ^(.github/|tests/test_data/abinit/)
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
- rev: v0.6.1
+ rev: v0.6.7
hooks:
- id: ruff
args: [--fix]
@@ -30,7 +30,7 @@ repos:
- id: rst-directive-colons
- id: rst-inline-touching-normal
- repo: https://github.com/pre-commit/mirrors-mypy
- rev: v1.11.1
+ rev: v1.11.2
hooks:
- id: mypy
files: ^src/
diff --git a/README.md b/README.md
index 4f11ff119e..4b6997bb64 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
[![pypi version](https://img.shields.io/pypi/v/atomate2?color=blue)](https://pypi.org/project/atomate2)
![supported python versions](https://img.shields.io/pypi/pyversions/atomate2)
[![Zenodo](https://img.shields.io/badge/DOI-10.5281/zenodo.10677081-blue?logo=Zenodo&logoColor=white)](https://zenodo.org/records/10677081)
+[![This project supports Python 3.10+](https://img.shields.io/badge/Python-3.10+-blue.svg?logo=python&logoColor=white)](https://python.org/downloads)
[Documentation][docs] | [PyPI][pypi] | [GitHub][github]
@@ -85,7 +86,7 @@ atomate2 workflows can be run using the [FireWorks] software. See the
## Installation
-Atomate2 is a Python 3.8+ library and can be installed using pip. Full installation
+Atomate2 is a Python 3.10+ library and can be installed using pip. Full installation
and configuration instructions are provided in the [installation tutorial][installation].
## Tutorials
diff --git a/docs/conf.py b/docs/conf.py
index 3baba5e939..4ba88b9a01 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -169,7 +169,7 @@
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
- "python": ("https://docs.python.org/3.8", None),
+ "python": ("https://docs.python.org/3.10", None),
"matplotlib": ("https://matplotlib.org/stable/", None),
"networkx": ("https://networkx.org/documentation/stable/", None),
"jobflow": ("https://materialsproject.github.io/jobflow", None),
diff --git a/docs/user/codes/openmm.md b/docs/user/codes/openmm.md
index 59271e4db7..30a4ca651a 100644
--- a/docs/user/codes/openmm.md
+++ b/docs/user/codes/openmm.md
@@ -6,7 +6,7 @@
>>> conda activate atomate2
# installing atomate2
->>> pip install git+https://github.com/orionarcher/atomate2.git
+>>> pip install git+https://github.com/orionarcher/atomate2
# installing classical_md dependencies
>>> conda install -c conda-forge --file .github/classical_md_requirements.txt
@@ -18,7 +18,7 @@ you can clone the repository and install from source.
``` bash
# installing atomate2
->>> git clone https://github.com/orionarcher/atomate2.git
+>>> git clone https://github.com/orionarcher/atomate2
>>> cd atomate2
>>> git branch openff
>>> git checkout openff
@@ -33,7 +33,7 @@ you intend to run on GPU, make sure that the tests are passing for CUDA.
>>> python -m openmm.testInstallation
```
-# Understanding Atomate2 OpenMM
+## Understanding Atomate2 OpenMM
Atomate2 is really just a collection of jobflow workflows relevant to
materials science. In all the workflows, we pass our system of interest
@@ -55,7 +55,6 @@ The first job we need to create generates the `Interchange` object.
To specify the system of interest, we use give it the SMILES strings,
counts, and names (optional) of the molecules we want to include.
-
```python
from atomate2.openff.core import generate_interchange
@@ -73,7 +72,6 @@ out the `create_mol_spec` function in the `atomate2.openff.utils`
module. Under the hood, this is being called on each mol_spec dict.
Meaning the code below is functionally identical to the code above.
-
```python
from atomate2.openff.utils import create_mol_spec
@@ -90,7 +88,6 @@ object, which we can pass to the next stage of the simulation.
NOTE: It's actually mandatory to include partial charges
for PF6- here, the built in partial charge method fails.
-
```python
import numpy as np
from pymatgen.core.structure import Molecule
@@ -205,13 +202,13 @@ Awesome! At this point, we've run a workflow and could start analyzing
our data. Before we get there though, let's go through some of the
other simulation options available.
-# Digging Deeper
+## Digging Deeper
Atomate2 OpenMM supports running a variety of workflows with different
configurations. Below we dig in to some of the more advanced options.
-
### Configuring the Simulation
+
Learn more about the configuration of OpenMM simulations
@@ -228,14 +225,13 @@ once and have it apply to all stages of the simulation. The value inheritance
is as follows: 1) any explicitly set value, 2) the value from the previous
maker, 3) the default value (as shown below).
-
```python
from atomate2.openmm.jobs.base import OPENMM_MAKER_DEFAULTS
print(OPENMM_MAKER_DEFAULTS)
```
-```
+```py
{
"step_size": 0.001,
"temperature": 298,
@@ -339,7 +335,6 @@ Rather than use `jobflow.yaml`, you could also create the stores in
Python and pass the stores to the `run_locally` function. This is a bit
more code, so usually the prior method is preferred.
-
```python
from jobflow import run_locally, JobStore
from maggma.stores import MongoStore, S3Store
@@ -374,6 +369,7 @@ run_locally(
ensure_success=True,
)
```
+
### Running on GPUs
@@ -381,12 +377,10 @@ run_locally(
Learn to accelerate MD simulations with GPUs
-
Running on a GPU is nearly as simple as running on a CPU. The only difference
is that you need to specify the `platform_properties` argument in the
`EnergyMinimizationMaker` with the `DeviceIndex` of the GPU you want to use.
-
```python
production_maker = OpenMMFlowMaker(
name="test_production",
@@ -414,7 +408,6 @@ First you'll need to install mpi4py.
Then you can modify and run the following script to distribute the work across the GPUs.
-
```python
# other imports
@@ -457,15 +450,16 @@ for i in range(4):
# this script will run four times, each with a different rank, thus distributing the work across the four GPUs.
run_locally(flows[rank], ensure_success=True)
```
+
-# Analysis with Emmet
+## Analysis with Emmet
For now, you'll need to make sure you have a particular emmet branch installed.
Later the builders will be integrated into `main`.
```bash
-pip install git+https://github.com/orionarcher/emmet.git@md_builders
+pip install git+https://github.com/orionarcher/emmet@md_builders
```
### Analyzing Local Data
@@ -498,6 +492,7 @@ u = create_universe(
solute = create_solute(u, solute_name="Li", networking_solvents=["PF6"])
```
+
### Setting up builders
@@ -556,6 +551,7 @@ builder.connect()
Here are some more convenient queries.
Here are some more convenient queries we could use!
+
```python
# query jobs from a specific day
april_16 = {"completed_at": {"$regex": "^2024-04-16"}}
@@ -570,6 +566,7 @@ job_uuids = [
]
my_specific_jobs = {"uuid": {"$in": job_uuids}}
```
+
@@ -611,6 +608,7 @@ solute = create_solute(
fallback_radius=3,
)
```
+
### Automated analysis with builders
diff --git a/docs/user/install.md b/docs/user/install.md
index b1d6169dea..5649c27271 100644
--- a/docs/user/install.md
+++ b/docs/user/install.md
@@ -136,8 +136,8 @@ atomate2
## Create a conda environment
```{note}
-Make sure to create a Python 3.8+ environment as recent versions of atomate2 only
-support Python 3.8 and higher.
+Make sure to create a Python 3.10+ environment as recent versions of atomate2 only
+support Python 3.10 and higher.
```
We highly recommend that you organize your installation of the atomate2 and the other
diff --git a/pyproject.toml b/pyproject.toml
index 7312ff6c47..fb4a48ff5d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -19,11 +19,11 @@ classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
- "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.12",
"Topic :: Other/Nonlisted Topic",
"Topic :: Scientific/Engineering",
]
-requires-python = ">=3.9"
+requires-python = ">=3.10"
dependencies = [
"PyYAML",
"click",
@@ -54,21 +54,19 @@ forcefields = [
"calorine<=2.2.1",
"chgnet>=0.2.2",
"mace-torch>=0.3.3",
- "torchdata<=0.7.1", # TODO: remove when issue fixed
"matgl>=1.1.3",
- "quippy-ase>=0.9.14",
+ # quippy-ase support for py3.12 tracked in https://github.com/libAtoms/QUIP/issues/645
+ "quippy-ase>=0.9.14; python_version < '3.12'",
"sevenn>=0.9.3",
+ "torchdata<=0.7.1", # TODO: remove when issue fixed
]
-ase = [
- "ase>=3.23.0",
-]
-ase-ext = [
- "tblite>=0.3.0",
-]
+ase = ["ase>=3.23.0"]
+# tblite py3.12 support tracked in https://github.com/tblite/tblite/issues/198
+ase-ext = ["tblite>=0.3.0; python_version < '3.12'"]
openmm = [
"mdanalysis>=2.7.0",
- "openmm>=8.1.0",
"openmm-mdanalysis-reporter>=0.1.0",
+ "openmm>=8.1.0",
]
docs = [
"FireWorks==2.0.3",
@@ -101,9 +99,12 @@ strict = [
"ijson==3.3.0",
"jobflow==0.1.18",
"lobsterpy==0.4.5",
+ "mdanalysis==2.7.0",
"monty==2024.7.30",
"mp-api==0.42.2",
"numpy",
+ "openmm-mdanalysis-reporter==0.1.0",
+ "openmm==8.1.1",
"phonopy==2.27.0",
"pydantic-settings==2.5.2",
"pydantic==2.9.2",
@@ -111,21 +112,18 @@ strict = [
"pymatgen==2024.6.10",
"python-ulid==2.7.0",
"seekpath==2.1.0",
- "tblite==0.3.0",
+ "tblite==0.3.0; python_version < '3.12'",
"typing-extensions==4.12.2",
- "mdanalysis==2.7.0",
- "openmm==8.1.1",
- "openmm-mdanalysis-reporter==0.1.0",
]
strict-forcefields = [
"calorine==2.2.1",
"chgnet==0.3.8",
"mace-torch>=0.3.3",
- "torchdata==0.7.1", # TODO: remove when issue fixed
"matgl==1.1.3",
- "quippy-ase==0.9.14",
+ "quippy-ase==0.9.14; python_version < '3.12'",
"sevenn==0.9.3.post1",
"torch==2.2.1",
+ "torchdata==0.7.1", # TODO: remove when issue fixed
]
[project.scripts]
@@ -179,7 +177,8 @@ exclude_lines = [
]
[tool.ruff]
-target-version = "py39"
+target-version = "py310"
+output-format = "concise"
[tool.ruff.lint]
select = ["ALL"]
diff --git a/src/atomate2/abinit/sets/base.py b/src/atomate2/abinit/sets/base.py
index e2cf4825c2..00fb05afec 100644
--- a/src/atomate2/abinit/sets/base.py
+++ b/src/atomate2/abinit/sets/base.py
@@ -8,7 +8,7 @@
import os
from dataclasses import dataclass, field
from pathlib import Path
-from typing import TYPE_CHECKING, Any, Callable
+from typing import TYPE_CHECKING, Any
import numpy as np
from abipy.abio.inputs import AbinitInput, MultiDataset
@@ -39,7 +39,7 @@
)
if TYPE_CHECKING:
- from collections.abc import Iterable, Sequence
+ from collections.abc import Callable, Iterable, Sequence
from pymatgen.core.structure import Structure
@@ -394,7 +394,7 @@ def check_format_prev_dirs(
"""Check and format the prev_dirs (restart or dependency)."""
if prev_dirs is None:
return None
- if isinstance(prev_dirs, (str, Path)):
+ if isinstance(prev_dirs, str | Path):
return [str(prev_dirs)]
return [str(prev_dir) for prev_dir in prev_dirs]
diff --git a/src/atomate2/abinit/sets/core.py b/src/atomate2/abinit/sets/core.py
index f75a5adc09..f8d1976cc6 100644
--- a/src/atomate2/abinit/sets/core.py
+++ b/src/atomate2/abinit/sets/core.py
@@ -3,7 +3,7 @@
from __future__ import annotations
from dataclasses import dataclass, field
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
import numpy as np
from abipy.abio.factories import (
@@ -18,6 +18,8 @@
from atomate2.abinit.sets.base import AbinitInputGenerator
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from abipy.abio.inputs import AbinitInput
from pymatgen.core import Structure
from pymatgen.io.abinit import PseudoTable
diff --git a/src/atomate2/abinit/utils/history.py b/src/atomate2/abinit/utils/history.py
index 87888b59c3..4356019f78 100644
--- a/src/atomate2/abinit/utils/history.py
+++ b/src/atomate2/abinit/utils/history.py
@@ -56,7 +56,7 @@ def log_initialization(
self, job: Job | Flow, initialization_info: Any | None = None
) -> None:
"""Log initialization information about the job."""
- details = {"job_class": job.__class__.__name__}
+ details = {"job_class": type(job).__name__}
if initialization_info:
details["initialization_info"] = initialization_info
self.append(JobEvent(JobEvent.INITIALIZED, details=details))
@@ -187,7 +187,7 @@ def get_events_by_types(self, types: list | AbinitEvent) -> list:
types
Single type or list of types.
"""
- types = types if isinstance(types, (list, tuple)) else [types]
+ types = types if isinstance(types, list | tuple) else [types]
return [e for e in self if e.event_type in types]
diff --git a/src/atomate2/aims/utils/bands.py b/src/atomate2/aims/utils/bands.py
index ead5651a26..dd6fe17337 100644
--- a/src/atomate2/aims/utils/bands.py
+++ b/src/atomate2/aims/utils/bands.py
@@ -33,7 +33,7 @@ def prepare_band_input(structure: Structure, density: float = 20) -> list:
points, labels = bp.get_kpoints(line_density=density, coords_are_cartesian=False)
lines_and_labels: list[_SegmentDict] = []
current_segment: _SegmentDict | None = None
- for label_, coords in zip(labels, points):
+ for label_, coords in zip(labels, points, strict=True):
# rename the Gamma point label
label = "G" if label_ in ("GAMMA", "\\Gamma", "Γ") else label_
if label:
diff --git a/src/atomate2/ase/md.py b/src/atomate2/ase/md.py
index dd11652a19..2d2963380a 100644
--- a/src/atomate2/ase/md.py
+++ b/src/atomate2/ase/md.py
@@ -320,7 +320,7 @@ def run_ase(
)
_dyn_mod_path = DynamicsPresets[
- f"{self.ensemble.value}_{self.dynamics.replace('-','_')}"
+ f"{self.ensemble.value}_{self.dynamics.replace('-', '_')}"
].value.split(".")
dynamics = getattr(
import_module(".".join(_dyn_mod_path[:-1])), _dyn_mod_path[-1]
diff --git a/src/atomate2/ase/utils.py b/src/atomate2/ase/utils.py
index 39a2cfc095..1378371eb5 100644
--- a/src/atomate2/ase/utils.py
+++ b/src/atomate2/ase/utils.py
@@ -85,7 +85,7 @@ def __init__(self, atoms: Atoms, store_md_outputs: bool = False) -> None:
self._store_md_outputs = store_md_outputs
if store_md_outputs:
- self._calc_kwargs.update({k: True for k in ("velocities", "temperature")})
+ self._calc_kwargs |= dict(velocities=True, temperature=True)
# `self.{velocities,temperatures}` always initialized,
# but data is only stored / saved to trajectory for MD runs
self.velocities: list[np.ndarray] = []
@@ -361,7 +361,7 @@ def relax(
isinstance(atoms, Atoms) and all(not pbc for pbc in atoms.pbc)
)
- if isinstance(atoms, (Structure, Molecule)):
+ if isinstance(atoms, Structure | Molecule):
atoms = self.ase_adaptor.get_atoms(atoms)
if self.fix_symmetry:
atoms.set_constraint(FixSymmetry(atoms, symprec=self.symprec))
diff --git a/src/atomate2/cli/dev.py b/src/atomate2/cli/dev.py
index de9e0cfa79..d879fdfd91 100644
--- a/src/atomate2/cli/dev.py
+++ b/src/atomate2/cli/dev.py
@@ -325,7 +325,7 @@ def abinit_test_data(test_name: str, test_data_dir: str | None, force: bool) ->
maker_info = loadfn("maker.json")
maker = maker_info["maker"]
- maker_name = maker.__class__.__name__
+ maker_name = type(maker).__name__
# take the module path and exclude the first two elements
# (i.e. "atomate2" and "abinit")
module_path = maker.__module__.split(".")[2:]
@@ -413,6 +413,7 @@ def _fake_dirs(
("indata", "outdata", "tmpdata"),
(indata_files, outdata_files, tmpdata_files),
(indata_fake_files, outdata_fake_files, tmpdata_fake_files),
+ strict=True,
):
_fake_dirdata(
src_dir=src_dir,
diff --git a/src/atomate2/common/flows/magnetism.py b/src/atomate2/common/flows/magnetism.py
index 2f5a15bbd0..5a106192a0 100644
--- a/src/atomate2/common/flows/magnetism.py
+++ b/src/atomate2/common/flows/magnetism.py
@@ -119,15 +119,13 @@ def __post_init__(self) -> None:
"""
if self.relax_maker is None:
warnings.warn(
- (
- "No relax_maker provided, relaxations will be skipped. Please be"
- " sure that this is intended!"
- ),
+ "No relax_maker provided, relaxations will be skipped. Please be"
+ " sure that this is intended!",
stacklevel=2,
)
else:
- static_base_maker_name = self.static_maker.__class__.__mro__[1].__name__
- relax_base_maker_name = self.relax_maker.__class__.__mro__[1].__name__
+ static_base_maker_name = type(self.static_maker).__mro__[1].__name__
+ relax_base_maker_name = type(self.relax_maker).__mro__[1].__name__
if relax_base_maker_name != static_base_maker_name:
warnings.warn(
"The provided static and relax makers do not use the "
diff --git a/src/atomate2/common/jobs/anharmonicity.py b/src/atomate2/common/jobs/anharmonicity.py
index aaf3ef74da..e44aa7f863 100644
--- a/src/atomate2/common/jobs/anharmonicity.py
+++ b/src/atomate2/common/jobs/anharmonicity.py
@@ -441,7 +441,7 @@ def get_sigma_a_per_mode(
).flatten()
anharmonic_vals = [
dft_force - harmonic_force
- for dft_force, harmonic_force in zip(dft_vals, harmonic_vals)
+ for dft_force, harmonic_force in zip(dft_vals, harmonic_vals, strict=True)
]
sigma_a = np.std(anharmonic_vals) / np.std(dft_vals)
mode_sigma_vals.append((mode, sigma_a))
@@ -544,7 +544,9 @@ def get_sigmas(
anharmonic_forces = np.array(
[
dft_force - harmonic_force
- for dft_force, harmonic_force in zip(dft_forces, harmonic_forces)
+ for dft_force, harmonic_force in zip(
+ dft_forces, harmonic_forces, strict=True
+ )
]
)
diff --git a/src/atomate2/common/jobs/defect.py b/src/atomate2/common/jobs/defect.py
index f1a50af1d1..083970fd94 100644
--- a/src/atomate2/common/jobs/defect.py
+++ b/src/atomate2/common/jobs/defect.py
@@ -3,7 +3,7 @@
from __future__ import annotations
import logging
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
import numpy as np
from jobflow import Flow, Response, job
@@ -20,7 +20,7 @@
from atomate2.utils.path import strip_hostname
if TYPE_CHECKING:
- from collections.abc import Iterable
+ from collections.abc import Callable, Iterable
from pathlib import Path
from emmet.core.tasks import TaskDoc
diff --git a/src/atomate2/common/jobs/elastic.py b/src/atomate2/common/jobs/elastic.py
index cd25367cf6..3c3be827a3 100644
--- a/src/atomate2/common/jobs/elastic.py
+++ b/src/atomate2/common/jobs/elastic.py
@@ -78,7 +78,7 @@ def generate_elastic_deformations(
strain_magnitudes = [strain_magnitudes] * len(strain_states) # type: ignore[assignment]
strains = []
- for state, magnitudes in zip(strain_states, strain_magnitudes):
+ for state, magnitudes in zip(strain_states, strain_magnitudes, strict=True):
strains.extend([Strain.from_voigt(m * np.array(state)) for m in magnitudes])
# remove zero strains
diff --git a/src/atomate2/common/jobs/electrode.py b/src/atomate2/common/jobs/electrode.py
index 4ef3a29a02..407632ae7a 100644
--- a/src/atomate2/common/jobs/electrode.py
+++ b/src/atomate2/common/jobs/electrode.py
@@ -3,7 +3,7 @@
from __future__ import annotations
import logging
-from typing import TYPE_CHECKING, Callable, NamedTuple
+from typing import TYPE_CHECKING, NamedTuple
from emmet.core.electrode import InsertionElectrodeDoc
from emmet.core.mpid import MPID
@@ -14,6 +14,7 @@
from ulid import ULID
if TYPE_CHECKING:
+ from collections.abc import Callable
from pathlib import Path
from pymatgen.alchemy import ElementLike
diff --git a/src/atomate2/common/jobs/magnetism.py b/src/atomate2/common/jobs/magnetism.py
index 6243c35270..621c1df1a6 100644
--- a/src/atomate2/common/jobs/magnetism.py
+++ b/src/atomate2/common/jobs/magnetism.py
@@ -111,7 +111,7 @@ def run_ordering_calculations(
"""
jobs = []
num_orderings = len(orderings[0])
- for idx, (struct, origin) in enumerate(zip(*orderings)):
+ for idx, (struct, origin) in enumerate(zip(*orderings, strict=True)):
name = f"{idx + 1}/{num_orderings} ({origin})"
parent_structure = struct.copy()
diff --git a/src/atomate2/common/jobs/qha.py b/src/atomate2/common/jobs/qha.py
index 58cbbf641f..517654040f 100644
--- a/src/atomate2/common/jobs/qha.py
+++ b/src/atomate2/common/jobs/qha.py
@@ -101,7 +101,7 @@ def analyze_free_energy(
heat_capacities.append([])
entropies.append([])
- for _, output in sorted(zip(volume, phonon_outputs)):
+ for _, output in sorted(zip(volume, phonon_outputs, strict=True)):
# check if imaginary modes
if (not output.has_imaginary_modes) or ignore_imaginary_modes:
electronic_energies[itemp].append(output.total_dft_energy)
diff --git a/src/atomate2/common/schemas/defects.py b/src/atomate2/common/schemas/defects.py
index c91912d6bb..0c79a6ad56 100644
--- a/src/atomate2/common/schemas/defects.py
+++ b/src/atomate2/common/schemas/defects.py
@@ -1,9 +1,9 @@
"""General schemas for defect workflow outputs."""
import logging
-from collections.abc import Sequence
+from collections.abc import Callable, Sequence
from itertools import starmap
-from typing import Any, Callable, Optional, Union
+from typing import Any, Optional, Union
import numpy as np
from emmet.core.tasks import TaskDoc
@@ -247,12 +247,14 @@ def get_cs_entry(
entries1 = list(
starmap(
- get_cs_entry, zip(structures1, energies1, static_dirs1, static_uuids1)
+ get_cs_entry,
+ zip(structures1, energies1, static_dirs1, static_uuids1, strict=True),
)
)
entries2 = list(
starmap(
- get_cs_entry, zip(structures2, energies2, static_dirs2, static_uuids2)
+ get_cs_entry,
+ zip(structures2, energies2, static_dirs2, static_uuids2, strict=True),
)
)
@@ -393,7 +395,7 @@ def sort_pos_dist(
d0 = dist(s1, s2)
d_vs_s = []
- for q1, q2, s in zip(d1, d2, list_in):
+ for q1, q2, s in zip(d1, d2, list_in, strict=True):
sign = +1
if q1 < q2 and q2 > d0:
sign = -1
@@ -422,7 +424,7 @@ def get_dQ(ref: Structure, distorted: Structure) -> float: # noqa: N802
np.sum(
[
x[0].distance(x[1]) ** 2 * x[0].specie.atomic_mass
- for x in zip(ref, distorted)
+ for x in zip(ref, distorted, strict=True)
],
),
)
diff --git a/src/atomate2/common/schemas/elastic.py b/src/atomate2/common/schemas/elastic.py
index ddd06ca0db..7f0acabd2f 100644
--- a/src/atomate2/common/schemas/elastic.py
+++ b/src/atomate2/common/schemas/elastic.py
@@ -218,7 +218,9 @@ def from_stresses(
if equilibrium_stress:
eq_stress = -0.1 * Stress(equilibrium_stress)
- pk_stresses = [s.piola_kirchoff_2(d) for s, d in zip(stresses, deformations)]
+ pk_stresses = [
+ s.piola_kirchoff_2(d) for s, d in zip(stresses, deformations, strict=True)
+ ]
if order is None:
order = 2 if len(stresses) < 70 else 3 # TODO: Figure this out better
diff --git a/src/atomate2/common/schemas/gruneisen.py b/src/atomate2/common/schemas/gruneisen.py
index 3b2bdcfadb..b12f9c78a9 100644
--- a/src/atomate2/common/schemas/gruneisen.py
+++ b/src/atomate2/common/schemas/gruneisen.py
@@ -310,7 +310,7 @@ def get_gruneisen_weighted_bandstructure(
)
for (dists_inx, dists), (_, freqs) in zip(
- enumerate(data["distances"]), enumerate(data["frequency"])
+ enumerate(data["distances"]), enumerate(data["frequency"]), strict=True
):
for band_idx in range(gruneisen_band_symline_plotter.n_bands):
ys = [freqs[band_idx][j] * u.factor for j in range(len(dists))]
diff --git a/src/atomate2/common/schemas/qha.py b/src/atomate2/common/schemas/qha.py
index 1efcdb5658..b0257d2142 100644
--- a/src/atomate2/common/schemas/qha.py
+++ b/src/atomate2/common/schemas/qha.py
@@ -42,7 +42,7 @@ class PhononQHADoc(StructureMetadata, extra="allow"): # type: ignore[call-arg]
)
volume_temperature: Optional[list[float]] = Field(
None,
- description="Volumes in Angstrom^3 at temperatures." "Shape: (temperatures, )",
+ description="Volumes in Angstrom^3 at temperatures.Shape: (temperatures, )",
)
gibbs_temperature: Optional[list[float]] = Field(
None,
@@ -51,7 +51,7 @@ class PhononQHADoc(StructureMetadata, extra="allow"): # type: ignore[call-arg]
)
bulk_modulus_temperature: Optional[list[float]] = Field(
None,
- description="Bulk modulus in GPa at temperature." "Shape: (temperatures, )",
+ description="Bulk modulus in GPa at temperature.Shape: (temperatures, )",
)
heat_capacity_p_numerical: Optional[list[float]] = Field(
None,
@@ -60,7 +60,7 @@ class PhononQHADoc(StructureMetadata, extra="allow"): # type: ignore[call-arg]
)
gruneisen_temperature: Optional[list[float]] = Field(
None,
- description="Gruneisen parameters at temperatures." "Shape: (temperatures, )",
+ description="Gruneisen parameters at temperatures.Shape: (temperatures, )",
)
pressure: Optional[float] = Field(
None, description="Pressure in GPA at which Gibb's energy was computed"
@@ -147,33 +147,33 @@ def from_phonon_runs(
# create some plots here
# add kwargs to change the names and file types
qha.plot_helmholtz_volume().savefig(
- f"{kwargs.get('helmholtz_volume_filename','helmholtz_volume')}"
- f".{kwargs.get('plot_type','pdf')}"
+ f"{kwargs.get('helmholtz_volume_filename', 'helmholtz_volume')}"
+ f".{kwargs.get('plot_type', 'pdf')}"
)
qha.plot_volume_temperature().savefig(
- f"{kwargs.get('volume_temperature_plot','volume_temperature')}"
- f".{kwargs.get('plot_type','pdf')}"
+ f"{kwargs.get('volume_temperature_plot', 'volume_temperature')}"
+ f".{kwargs.get('plot_type', 'pdf')}"
)
qha.plot_thermal_expansion().savefig(
- f"{kwargs.get('thermal_expansion_plot','thermal_expansion')}"
- f".{kwargs.get('plot_type','pdf')}"
+ f"{kwargs.get('thermal_expansion_plot', 'thermal_expansion')}"
+ f".{kwargs.get('plot_type', 'pdf')}"
)
qha.plot_gibbs_temperature().savefig(
f"{kwargs.get('gibbs_temperature_plot', 'gibbs_temperature')}"
- f".{kwargs.get('plot_type','pdf')}"
+ f".{kwargs.get('plot_type', 'pdf')}"
)
qha.plot_bulk_modulus_temperature().savefig(
f"{kwargs.get('bulk_modulus_plot', 'bulk_modulus_temperature')}"
- f".{kwargs.get('plot_type','pdf')}"
+ f".{kwargs.get('plot_type', 'pdf')}"
)
qha.plot_heat_capacity_P_numerical().savefig(
f"{kwargs.get('heat_capacity_plot', 'heat_capacity_P_numerical')}"
- f".{kwargs.get('plot_type','pdf')}"
+ f".{kwargs.get('plot_type', 'pdf')}"
)
# qha.plot_heat_capacity_P_polyfit().savefig("heat_capacity_P_polyfit.eps")
qha.plot_gruneisen_temperature().savefig(
f"{kwargs.get('gruneisen_temperature_plot', 'gruneisen_temperature')}"
- f".{kwargs.get('plot_type','pdf')}"
+ f".{kwargs.get('plot_type', 'pdf')}"
)
qha.write_helmholtz_volume(
diff --git a/src/atomate2/common/utils.py b/src/atomate2/common/utils.py
index 4829e0b98c..9110a37f4b 100644
--- a/src/atomate2/common/utils.py
+++ b/src/atomate2/common/utils.py
@@ -34,7 +34,9 @@ def get_transformations(
raise ValueError("Number of transformations and parameters must be the same.")
transformation_objects = []
- for transformation, transformation_params in zip(transformations, params):
+ for transformation, transformation_params in zip(
+ transformations, params, strict=True
+ ):
found = False
for module in (
"advanced_transformations",
diff --git a/src/atomate2/cp2k/jobs/base.py b/src/atomate2/cp2k/jobs/base.py
index 6be8c4d600..40bfe1083b 100644
--- a/src/atomate2/cp2k/jobs/base.py
+++ b/src/atomate2/cp2k/jobs/base.py
@@ -4,7 +4,7 @@
from dataclasses import dataclass, field
from pathlib import Path
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
from jobflow import Maker, Response, job
from monty.serialization import dumpfn
@@ -31,6 +31,8 @@
from atomate2.cp2k.sets.base import Cp2kInputGenerator
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from pymatgen.core import Structure
diff --git a/src/atomate2/forcefields/jobs.py b/src/atomate2/forcefields/jobs.py
index 4c085a41b2..f2307e3a50 100644
--- a/src/atomate2/forcefields/jobs.py
+++ b/src/atomate2/forcefields/jobs.py
@@ -19,8 +19,8 @@
from atomate2.forcefields.utils import ase_calculator, revert_default_dtype
if TYPE_CHECKING:
+ from collections.abc import Callable
from pathlib import Path
- from typing import Callable
from ase.calculators.calculator import Calculator
from pymatgen.core.structure import Structure
diff --git a/src/atomate2/lobster/schemas.py b/src/atomate2/lobster/schemas.py
index 33b435ffbc..ae4352669e 100644
--- a/src/atomate2/lobster/schemas.py
+++ b/src/atomate2/lobster/schemas.py
@@ -373,10 +373,10 @@ def from_directory(
struct = analyse.structure
for _iplot, (ication, labels, cohps) in enumerate(
- zip(seq_ineq_cations, seq_labels_cohps, seq_cohps)
+ zip(seq_ineq_cations, seq_labels_cohps, seq_cohps, strict=True)
):
label_str = f"{struct[ication].specie!s}{ication + 1!s}: "
- for label, cohp in zip(labels, cohps):
+ for label, cohp in zip(labels, cohps, strict=True):
if label is not None:
cba_cohp_plot_data[label_str + label] = cohp
@@ -1176,7 +1176,7 @@ def _replace_inf_values(data: Union[dict[Any, Any], list[Any]]) -> None:
"""
if isinstance(data, dict):
for key, value in data.items():
- if isinstance(value, (dict, list)):
+ if isinstance(value, dict | list):
_replace_inf_values(
value
) # Recursively process nested dictionaries and lists
@@ -1184,7 +1184,7 @@ def _replace_inf_values(data: Union[dict[Any, Any], list[Any]]) -> None:
data[key] = "-Infinity" # Replace -inf with a string representation
elif isinstance(data, list):
for index, item in enumerate(data):
- if isinstance(item, (dict, list)):
+ if isinstance(item, dict | list):
_replace_inf_values(
item
) # Recursively process nested dictionaries and lists
@@ -1280,6 +1280,7 @@ def _get_strong_bonds(
bondlist["list_atom2"],
bondlist["list_icohp"],
bondlist["list_length"],
+ strict=True,
):
bonds.append(f"{a.rstrip('0123456789')}-{b.rstrip('0123456789')}")
icohp_all.append(sum(c.values()))
diff --git a/src/atomate2/openff/core.py b/src/atomate2/openff/core.py
index 9ef7790f3f..97fabd79b2 100644
--- a/src/atomate2/openff/core.py
+++ b/src/atomate2/openff/core.py
@@ -3,7 +3,7 @@
from __future__ import annotations
from pathlib import Path
-from typing import Callable
+from typing import TYPE_CHECKING
import openff.toolkit as tk
from emmet.core.openff import ClassicalMDTaskDocument, MoleculeSpec
@@ -16,6 +16,9 @@
from atomate2.openff.utils import create_mol_spec_list, merge_specs_by_name_and_smiles
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
def openff_job(method: Callable) -> job:
"""Decorate the ``make`` method of ClassicalMD job makers.
diff --git a/src/atomate2/openff/utils.py b/src/atomate2/openff/utils.py
index 92838a971f..78d81dfe67 100644
--- a/src/atomate2/openff/utils.py
+++ b/src/atomate2/openff/utils.py
@@ -190,7 +190,7 @@ def calculate_elyte_composition(
salt_mws = {}
for smile in salts:
mol = tk.Molecule.from_smiles(smile, allow_undefined_stereo=True)
- salt_mws[smile] = sum([masses[atom.atomic_number] for atom in mol.atoms])
+ salt_mws[smile] = sum(masses[atom.atomic_number] for atom in mol.atoms)
# Convert salt mole ratios to mass ratios
salt_mass_ratio = {
@@ -228,12 +228,13 @@ def counts_from_masses(species: dict[str, float], n_mol: int) -> dict[str, float
mol_weights = []
for smile in species:
mol = tk.Molecule.from_smiles(smile, allow_undefined_stereo=True)
- mol_weights.append(sum([masses[atom.atomic_number] for atom in mol.atoms]))
+ mol_weights.append(sum(masses[atom.atomic_number] for atom in mol.atoms))
mol_ratio = np.array(list(species.values())) / np.array(mol_weights)
mol_ratio /= sum(mol_ratio)
return {
- smile: int(np.round(ratio * n_mol)) for smile, ratio in zip(species, mol_ratio)
+ smile: int(np.round(ratio * n_mol))
+ for smile, ratio in zip(species, mol_ratio, strict=True)
}
@@ -258,7 +259,7 @@ def counts_from_box_size(
"""
masses = {el.Z: el.atomic_mass for el in Element}
- na = 6.02214076e23
+ na = 6.02214076e23 # Avogadro's number
volume = (side_length * 1e-7) ** 3 # Convert from nm3 to cm^3
total_mass = volume * density # grams
@@ -266,7 +267,7 @@ def counts_from_box_size(
mol_weights = []
for smile in species:
mol = tk.Molecule.from_smiles(smile, allow_undefined_stereo=True)
- mol_weights.append(sum([masses[atom.atomic_number] for atom in mol.atoms]))
+ mol_weights.append(sum(masses[atom.atomic_number] for atom in mol.atoms))
mean_mw = np.mean(mol_weights)
n_mol = (total_mass / mean_mw) * na
@@ -277,7 +278,7 @@ def counts_from_box_size(
# Convert moles to number of molecules
return {
smile: int(np.round(ratio * n_mol))
- for smile, ratio in zip(species.keys(), mol_ratio)
+ for smile, ratio in zip(species.keys(), mol_ratio, strict=True)
}
diff --git a/src/atomate2/openmm/jobs/base.py b/src/atomate2/openmm/jobs/base.py
index 01ae0bb136..9c190cbafc 100644
--- a/src/atomate2/openmm/jobs/base.py
+++ b/src/atomate2/openmm/jobs/base.py
@@ -9,7 +9,7 @@
from dataclasses import dataclass, field
from datetime import datetime, timezone
from pathlib import Path
-from typing import TYPE_CHECKING, Any, Callable, NoReturn
+from typing import TYPE_CHECKING, Any, NoReturn
from emmet.core.openmm import (
Calculation,
@@ -29,6 +29,8 @@
from atomate2.openmm.utils import increment_name, task_reports
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from openmm.app.simulation import Simulation
@@ -308,7 +310,7 @@ def _add_reporters(
if traj_file_type in ["h5md", "nc", "ncdf"]:
writer_kwargs["velocities"] = report_velocities
writer_kwargs["forces"] = False
- elif report_velocities and traj_file_type not in ["trr"]:
+ elif report_velocities and traj_file_type != "trr":
raise ValueError(
f"File type {traj_file_type} does not support velocities as"
f"of MDAnalysis 2.7.0. Select another file type"
@@ -600,7 +602,7 @@ def _create_task_doc(
),
completed_at=str(datetime.now(tz=timezone.utc)),
task_name=job_name,
- calc_type=self.__class__.__name__,
+ calc_type=type(self).__name__,
)
prev_task = prev_task or OpenMMTaskDocument()
diff --git a/src/atomate2/openmm/jobs/core.py b/src/atomate2/openmm/jobs/core.py
index 821d1953eb..c841818215 100644
--- a/src/atomate2/openmm/jobs/core.py
+++ b/src/atomate2/openmm/jobs/core.py
@@ -196,7 +196,7 @@ def run_openmm(self, sim: Simulation) -> None:
self.starting_temperature, self.temperature, self.temp_steps
)
steps = create_list_summing_to(self.n_steps, self.temp_steps)
- for temp, n_steps in zip(temps, steps):
+ for temp, n_steps in zip(temps, steps, strict=True):
integrator.setTemperature(temp * kelvin)
sim.step(n_steps)
diff --git a/src/atomate2/openmm/jobs/generate.py b/src/atomate2/openmm/jobs/generate.py
index b32ecc542a..a155af20f2 100644
--- a/src/atomate2/openmm/jobs/generate.py
+++ b/src/atomate2/openmm/jobs/generate.py
@@ -138,7 +138,7 @@ def assign_partial_charges(self, mol_or_method: tk.Molecule | str) -> None:
openff_mol.assign_partial_charges(mol_or_method)
mol_or_method = openff_mol
self_mol = self.to_openff_molecule()
- isomorphic, atom_map = get_atom_map(mol_or_method, self_mol)
+ _isomorphic, atom_map = get_atom_map(mol_or_method, self_mol)
mol_charges = mol_or_method.partial_charges[list(atom_map.values())].magnitude
self.partial_charges = mol_charges
@@ -251,10 +251,10 @@ def generate_openmm_interchange(
"The number of molecule specifications and XML files must match."
)
- for mol_spec, xml_mol in zip(mol_specs, xml_mols):
+ for mol_spec, xml_mol in zip(mol_specs, xml_mols, strict=True):
openff_mol = tk.Molecule.from_json(mol_spec.openff_mol)
xml_openff_mol = xml_mol.to_openff_molecule()
- is_isomorphic, atom_map = get_atom_map(openff_mol, xml_openff_mol)
+ is_isomorphic, _atom_map = get_atom_map(openff_mol, xml_openff_mol)
if not is_isomorphic:
raise ValueError(
"The mol_specs and ff_xmls must index identical molecules."
diff --git a/src/atomate2/qchem/jobs/base.py b/src/atomate2/qchem/jobs/base.py
index 4de1d9499e..816771a0f1 100644
--- a/src/atomate2/qchem/jobs/base.py
+++ b/src/atomate2/qchem/jobs/base.py
@@ -5,7 +5,7 @@
import logging
from dataclasses import dataclass, field
from pathlib import Path
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
from emmet.core.qc_tasks import TaskDoc
from jobflow import Maker, Response, job
@@ -18,6 +18,8 @@
from atomate2.qchem.sets.base import QCInputGenerator
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from pymatgen.core.structure import Molecule
logger = logging.getLogger(__name__)
diff --git a/src/atomate2/utils/file_client.py b/src/atomate2/utils/file_client.py
index 0e77aa4c13..47313204d8 100644
--- a/src/atomate2/utils/file_client.py
+++ b/src/atomate2/utils/file_client.py
@@ -11,13 +11,14 @@
from glob import glob
from gzip import GzipFile
from pathlib import Path
-from typing import TYPE_CHECKING, Any, Callable
+from typing import TYPE_CHECKING, Any
import paramiko
from monty.io import zopen
from paramiko import SFTPClient, SSHClient
if TYPE_CHECKING:
+ from collections.abc import Callable
from types import TracebackType
diff --git a/src/atomate2/vasp/jobs/adsorption.py b/src/atomate2/vasp/jobs/adsorption.py
index 328010453d..d1d253cdd0 100644
--- a/src/atomate2/vasp/jobs/adsorption.py
+++ b/src/atomate2/vasp/jobs/adsorption.py
@@ -402,13 +402,13 @@ def adsorption_calculations(
configuration_numbers = []
job_dirs = []
- for i, _ad_structure in enumerate(adslab_structures):
+ for idx in range(len(adslab_structures)):
ads_energy = (
- adslabs_data["static_energy"][i] - molecule_dft_energy - slab_dft_energy
+ adslabs_data["static_energy"][idx] - molecule_dft_energy - slab_dft_energy
)
adsorption_energies.append(ads_energy)
- configuration_numbers.append(i)
- job_dirs.append(adslabs_data["dirs"][i])
+ configuration_numbers.append(idx)
+ job_dirs.append(adslabs_data["dirs"][idx])
# Sort the data by adsorption energy
sorted_indices = sorted(
diff --git a/src/atomate2/vasp/jobs/base.py b/src/atomate2/vasp/jobs/base.py
index c41b16a390..188ed20995 100644
--- a/src/atomate2/vasp/jobs/base.py
+++ b/src/atomate2/vasp/jobs/base.py
@@ -6,7 +6,7 @@
from dataclasses import dataclass, field
from pathlib import Path
from shutil import which
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
from emmet.core.tasks import TaskDoc
from jobflow import Maker, Response, job
@@ -26,6 +26,8 @@
from atomate2.vasp.sets.base import VaspInputGenerator
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from pymatgen.core import Structure
diff --git a/src/atomate2/vasp/jobs/elph.py b/src/atomate2/vasp/jobs/elph.py
index 1cc05fbc4c..76cb9781a0 100644
--- a/src/atomate2/vasp/jobs/elph.py
+++ b/src/atomate2/vasp/jobs/elph.py
@@ -154,7 +154,7 @@ def run_elph_displacements(
"uuids": [],
"dirs": [],
}
- for temp, structure in zip(temperatures, structures):
+ for temp, structure in zip(temperatures, structures, strict=True):
# create the job
elph_job = vasp_maker.make(structure, prev_dir=prev_dir)
elph_job.append_name(f" T={temp}")
diff --git a/tests/common/schemas/test_qha.py b/tests/common/schemas/test_qha.py
index 1552b55240..a3da77eecd 100644
--- a/tests/common/schemas/test_qha.py
+++ b/tests/common/schemas/test_qha.py
@@ -54,7 +54,7 @@ def test_analyze_free_energy(tmp_dir, test_dir):
energies.append(float(e))
phonon_docs = []
- for index, energy, volume in zip(range(-5, 6), energies, volumes):
+ for index, energy, volume in zip(range(-5, 6), energies, volumes, strict=True):
filename = f"{test_dir}/qha/thermal_properties.yaml-{index!s}"
yaml = YAML()
with open(filename) as f:
@@ -131,7 +131,7 @@ def test_analyze_free_energy_small(tmp_dir, test_dir):
energies.append(float(e))
phonon_docs = []
- for index, energy, volume in zip(range(-5, 6), energies, volumes):
+ for index, energy, volume in zip(range(-5, 6), energies, volumes, strict=True):
filename = f"{test_dir}/qha/thermal_properties.yaml-{index!s}"
yaml = YAML()
with open(filename) as f:
diff --git a/tests/forcefields/test_md.py b/tests/forcefields/test_md.py
index f2c5c08cc9..2b11d0686e 100644
--- a/tests/forcefields/test_md.py
+++ b/tests/forcefields/test_md.py
@@ -1,5 +1,6 @@
"""Tests for forcefield MD flows."""
+import sys
from pathlib import Path
import numpy as np
@@ -53,6 +54,11 @@ def test_maker_initialization():
def test_ml_ff_md_maker(
ff_name, si_structure, sr_ti_o3_structure, al2_au_structure, test_dir, clean_dir
):
+ if ff_name == "GAP" and sys.version_info >= (3, 12):
+ pytest.skip(
+ "GAP model not compatible with Python 3.12, waiting on https://github.com/libAtoms/QUIP/issues/645"
+ )
+
n_steps = 5
ref_energies_per_atom = {
diff --git a/tests/qchem/conftest.py b/tests/qchem/conftest.py
index e8ced094f7..80dbdf49d7 100644
--- a/tests/qchem/conftest.py
+++ b/tests/qchem/conftest.py
@@ -3,7 +3,7 @@
import logging
import shutil
from pathlib import Path
-from typing import TYPE_CHECKING, Any, Callable, Final, Literal
+from typing import TYPE_CHECKING, Any, Final, Literal
import pytest
from jobflow import CURRENT_JOB
@@ -17,7 +17,7 @@
from atomate2.qchem.sets.base import QCInputGenerator
if TYPE_CHECKING:
- from collections.abc import Generator, Sequence
+ from collections.abc import Callable, Generator, Sequence
logger = logging.getLogger("atomate2")
diff --git a/tests/qchem/flows/test_core.py b/tests/qchem/flows/test_core.py
index 2fadffcb00..0b05657dc4 100644
--- a/tests/qchem/flows/test_core.py
+++ b/tests/qchem/flows/test_core.py
@@ -46,7 +46,7 @@ def test_frequency_opt_flattening_maker(
mock_qchem, clean_dir, qchem_test_dir, h2o_molecule
):
ref_paths = {
- k: Path(qchem_test_dir) / "ffopt" / f"{k.lower().replace(' ','_')}"
+ k: Path(qchem_test_dir) / "ffopt" / f"{k.lower().replace(' ', '_')}"
for k in ("Geometry Optimization", "Frequency Analysis 1")
}
diff --git a/tests/vasp/conftest.py b/tests/vasp/conftest.py
index 096f769aa8..eb4137eea5 100644
--- a/tests/vasp/conftest.py
+++ b/tests/vasp/conftest.py
@@ -3,7 +3,7 @@
import logging
import shutil
from pathlib import Path
-from typing import TYPE_CHECKING, Any, Callable, Final, Literal
+from typing import TYPE_CHECKING, Any, Final, Literal
import pytest
from jobflow import CURRENT_JOB
@@ -20,7 +20,7 @@
from atomate2.vasp.sets.base import VaspInputGenerator
if TYPE_CHECKING:
- from collections.abc import Generator, Sequence
+ from collections.abc import Callable, Generator, Sequence
logger = logging.getLogger("atomate2")
diff --git a/tests/vasp/flows/test_eos.py b/tests/vasp/flows/test_eos.py
index 2b879b6d65..c0f4d79d46 100644
--- a/tests/vasp/flows/test_eos.py
+++ b/tests/vasp/flows/test_eos.py
@@ -180,5 +180,5 @@ def test_mp_eos_maker(
assert all(
approx(v) == data[k] for k, v in ref_eos_fit[job_type][key].items()
)
- elif isinstance(data, (float, int)):
+ elif isinstance(data, float | int):
assert approx(ref_eos_fit[job_type][key]) == data
diff --git a/tests/vasp/schemas/test_defect.py b/tests/vasp/schemas/test_defect.py
index 61350dd398..cedad2e0c0 100644
--- a/tests/vasp/schemas/test_defect.py
+++ b/tests/vasp/schemas/test_defect.py
@@ -31,11 +31,11 @@ def is_strict_minimum(min_index, arr):
inputs1 = [
(task.output.structure, task.output.energy, sdir)
- for task, sdir in zip(static_tasks1, static_dirs1)
+ for task, sdir in zip(static_tasks1, static_dirs1, strict=True)
]
inputs2 = [
(task.output.structure, task.output.energy, sdir)
- for task, sdir in zip(static_tasks2, static_dirs2)
+ for task, sdir in zip(static_tasks2, static_dirs2, strict=True)
]
input_dict = defaultdict(list)
diff --git a/tests/vasp/sets/test_matpes.py b/tests/vasp/sets/test_matpes.py
index 06ee5fa0eb..f29b31c870 100644
--- a/tests/vasp/sets/test_matpes.py
+++ b/tests/vasp/sets/test_matpes.py
@@ -42,7 +42,7 @@ def test_matpes_sets(set_generator: VaspInputGenerator) -> None:
"vdw",
}
assert matpes_set.potcar_functional == "PBE_64"
- assert isinstance(matpes_set.inherit_incar, (list, tuple))
+ assert isinstance(matpes_set.inherit_incar, list | tuple)
assert set(matpes_set.inherit_incar) == set(MatPESStaticSet.inherit_incar)
assert matpes_set.auto_ismear is False
assert matpes_set.auto_kspacing is False