From 9c636d612ce7260075b1ca14aa321bd129543f62 Mon Sep 17 00:00:00 2001 From: Max Gallant Date: Mon, 16 Jun 2025 09:41:16 -0700 Subject: [PATCH 1/9] Add oszicar to discoverable files --- emmet-core/emmet/core/vasp/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/emmet-core/emmet/core/vasp/utils.py b/emmet-core/emmet/core/vasp/utils.py index e4ca72c2a3..ba82bfd51d 100644 --- a/emmet-core/emmet/core/vasp/utils.py +++ b/emmet-core/emmet/core/vasp/utils.py @@ -181,6 +181,7 @@ def discover_and_sort_vasp_files( "vasprun", "contcar", "outcar", + "oszicar" ): if k in f: by_type[f"{k}_file"].append(_f) From ee99a3ecffcee20c44254579397aec6b3d230365 Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Mon, 16 Jun 2025 10:14:31 -0700 Subject: [PATCH 2/9] exception handling for DOS parsing --- emmet-core/emmet/core/tasks.py | 8 ++-- emmet-core/emmet/core/vasp/calculation.py | 52 ++++++++++++----------- emmet-core/emmet/core/vasp/utils.py | 7 +-- 3 files changed, 32 insertions(+), 35 deletions(-) diff --git a/emmet-core/emmet/core/tasks.py b/emmet-core/emmet/core/tasks.py index 84c3fee53a..f2c19dd868 100644 --- a/emmet-core/emmet/core/tasks.py +++ b/emmet-core/emmet/core/tasks.py @@ -1144,8 +1144,7 @@ def _find_vasp_files( def _update_task_files(tpath) -> None: for category, files in discover_and_sort_vasp_files(tpath).items(): for f in files: - f = f.name - tasks = sorted([t for t in task_names if t in f]) + tasks = sorted([t for t in task_names if t in f.name]) task = "standard" if len(tasks) == 0 else tasks[0] if task not in task_files: task_files[task] = {} @@ -1154,11 +1153,10 @@ def _update_task_files(tpath) -> None: ) and category not in task_files[task]: task_files[task][category] = [] - abs_f = Path(base_path) / f if is_list_like: - task_files[task][category].append(abs_f) # type: ignore[union-attr] + task_files[task][category].append(f.path.absolute()) # type: ignore[union-attr] else: - task_files[task][category] = abs_f + task_files[task][category] = f.path.absolute() _update_task_files(base_path) diff --git a/emmet-core/emmet/core/vasp/calculation.py b/emmet-core/emmet/core/vasp/calculation.py index ec5312f619..713d20f4a4 100644 --- a/emmet-core/emmet/core/vasp/calculation.py +++ b/emmet-core/emmet/core/vasp/calculation.py @@ -1087,35 +1087,39 @@ def _get_band_props( A dictionary of element and orbital-projected DOS properties. """ dosprop_dict: dict[str, dict[str, dict[str, float]]] = {} + if not complete_dos.pdos: + # It's possible to have a CompleteDos object with only structure info and no projected DOS info + return dosprop_dict + for el in structure.composition.elements: el_name = str(el.name) dosprop_dict[el_name] = {} for orb_type in [ - OrbitalType.s, - OrbitalType.p, - OrbitalType.d, + OrbitalType(x) for x in range(OrbitalType[el.block].value + 1) ]: - orb_name = str(orb_type) # NB this is the same as orb_type.name - if ( - (el.block == "s" and orb_name in ["p", "d", "f"]) - or (el.block == "p" and orb_name in ["d", "f"]) - or (el.block == "d" and orb_name == "f") - ): + try: + dosprop_dict[el_name][str(orb_type)] = { + "filling": complete_dos.get_band_filling( + band=orb_type, elements=[el] + ), + "center": complete_dos.get_band_center( + band=orb_type, elements=[el] + ), + "bandwidth": complete_dos.get_band_width( + band=orb_type, elements=[el] + ), + "skewness": complete_dos.get_band_skewness( + band=orb_type, elements=[el] + ), + "kurtosis": complete_dos.get_band_kurtosis( + band=orb_type, elements=[el] + ), + "upper_edge": complete_dos.get_upper_band_edge( + band=orb_type, elements=[el] + ), + } + except KeyError: + # No projected DOS available for that particular element + orbital character continue - dosprops = { - "filling": complete_dos.get_band_filling(band=orb_type, elements=[el]), - "center": complete_dos.get_band_center(band=orb_type, elements=[el]), - "bandwidth": complete_dos.get_band_width(band=orb_type, elements=[el]), - "skewness": complete_dos.get_band_skewness( - band=orb_type, elements=[el] - ), - "kurtosis": complete_dos.get_band_kurtosis( - band=orb_type, elements=[el] - ), - "upper_edge": complete_dos.get_upper_band_edge( - band=orb_type, elements=[el] - ), - } - dosprop_dict[el_name][orb_name] = dosprops return dosprop_dict diff --git a/emmet-core/emmet/core/vasp/utils.py b/emmet-core/emmet/core/vasp/utils.py index ba82bfd51d..5afb41e0a2 100644 --- a/emmet-core/emmet/core/vasp/utils.py +++ b/emmet-core/emmet/core/vasp/utils.py @@ -177,12 +177,7 @@ def discover_and_sort_vasp_files( by_type: dict[str, list[FileMetadata]] = defaultdict(list) for _f in discover_vasp_files(target_dir): f = _f.name.lower() - for k in ( - "vasprun", - "contcar", - "outcar", - "oszicar" - ): + for k in ("vasprun", "contcar", "outcar", "oszicar"): if k in f: by_type[f"{k}_file"].append(_f) break From 89761cb562d5f510cc2c448e3f9a136be80d49f1 Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Mon, 16 Jun 2025 14:53:14 -0700 Subject: [PATCH 3/9] pep-0585 --- .../emmet/builders/abinit/phonon.py | 6 +++++- .../emmet/builders/abinit/sound_velocity.py | 6 +++++- .../builders/materials/absorption_spectrum.py | 6 +++++- .../builders/materials/corrected_entries.py | 6 +++++- .../emmet/builders/materials/dielectric.py | 6 +++++- .../emmet/builders/materials/elasticity.py | 7 ++++++- .../emmet/builders/materials/electrodes.py | 7 ++++++- .../emmet/builders/materials/magnetism.py | 6 +++++- .../emmet/builders/materials/optimade.py | 6 +++++- .../emmet/builders/materials/provenance.py | 6 +++++- .../emmet/builders/materials/thermo.py | 8 +++++-- .../matscholar/missing_compositions.py | 6 +++++- .../emmet/builders/molecules/atomic.py | 6 +++++- .../emmet/builders/molecules/bonds.py | 6 +++++- .../emmet/builders/molecules/electric.py | 6 +++++- .../emmet/builders/molecules/metal_binding.py | 5 ++++- .../emmet/builders/molecules/orbitals.py | 5 ++++- .../emmet/builders/molecules/redox.py | 7 ++++++- .../emmet/builders/molecules/summary.py | 8 ++++++- .../emmet/builders/molecules/thermo.py | 7 ++++++- .../emmet/builders/molecules/trajectory.py | 6 +++++- .../emmet/builders/molecules/vibration.py | 5 ++++- .../emmet/builders/qchem/molecules.py | 17 +++++++++------ emmet-builders/emmet/builders/utils.py | 10 ++++++--- .../emmet/builders/vasp/materials.py | 6 +++++- emmet-core/emmet/core/_general_store.py | 7 +++---- emmet-core/emmet/core/base.py | 7 +------ emmet-core/emmet/core/electronic_structure.py | 12 +++++------ emmet-core/emmet/core/material.py | 18 ++++++++-------- emmet-core/emmet/core/material_property.py | 10 +++++---- .../emmet/core/mobility/migrationgraph.py | 2 +- emmet-core/emmet/core/molecules/bonds.py | 5 ++++- .../emmet/core/molecules/metal_binding.py | 16 +++++++++----- .../emmet/core/molecules/molecule_property.py | 17 ++++++++------- emmet-core/emmet/core/molecules/orbitals.py | 7 ++++++- emmet-core/emmet/core/molecules/redox.py | 12 +++++------ emmet-core/emmet/core/molecules/summary.py | 11 +++++----- emmet-core/emmet/core/mpid.py | 6 +++++- emmet-core/emmet/core/openff/solvation.py | 5 ++++- emmet-core/emmet/core/qc_tasks.py | 13 +++++++----- .../emmet/core/qchem/calc_types/utils.py | 5 ++++- emmet-core/emmet/core/qchem/molecule.py | 3 ++- emmet-core/emmet/core/qchem/task.py | 8 +++++-- emmet-core/emmet/core/settings.py | 8 +++---- emmet-core/emmet/core/structure.py | 21 +++++++++++-------- emmet-core/emmet/core/structure_group.py | 5 ++++- emmet-core/emmet/core/stubs.py | 10 ++++++--- emmet-core/emmet/core/summary.py | 9 +++++--- emmet-core/emmet/core/symmetry.py | 7 ++++++- emmet-core/emmet/core/utils.py | 5 +++-- emmet-core/emmet/core/vasp/material.py | 2 +- 51 files changed, 277 insertions(+), 124 deletions(-) diff --git a/emmet-builders/emmet/builders/abinit/phonon.py b/emmet-builders/emmet/builders/abinit/phonon.py index 8affceb890..cb9d6cb494 100644 --- a/emmet-builders/emmet/builders/abinit/phonon.py +++ b/emmet-builders/emmet/builders/abinit/phonon.py @@ -1,7 +1,6 @@ import os import tempfile from math import ceil -from typing import Iterator import numpy as np from abipy.abio.inputs import AnaddbInput @@ -36,6 +35,11 @@ from emmet.core.polar import BornEffectiveCharges, DielectricDoc, IRDielectric from emmet.core.utils import jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterator + SETTINGS = EmmetBuildSettings() diff --git a/emmet-builders/emmet/builders/abinit/sound_velocity.py b/emmet-builders/emmet/builders/abinit/sound_velocity.py index 9bf292a3c4..dee1b2350f 100644 --- a/emmet-builders/emmet/builders/abinit/sound_velocity.py +++ b/emmet-builders/emmet/builders/abinit/sound_velocity.py @@ -1,7 +1,6 @@ import tempfile import traceback from math import ceil -from typing import Iterator from abipy.dfpt.ddb import DdbFile from abipy.dfpt.vsound import SoundVelocity as AbiSoundVelocity @@ -13,6 +12,11 @@ from emmet.core.phonon import SoundVelocity from emmet.core.utils import jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterator + class SoundVelocityBuilder(Builder): def __init__( diff --git a/emmet-builders/emmet/builders/materials/absorption_spectrum.py b/emmet-builders/emmet/builders/materials/absorption_spectrum.py index b2927a451c..0fea459945 100644 --- a/emmet-builders/emmet/builders/materials/absorption_spectrum.py +++ b/emmet-builders/emmet/builders/materials/absorption_spectrum.py @@ -1,5 +1,4 @@ from math import ceil -from typing import Iterator import numpy as np from maggma.builders import Builder @@ -10,6 +9,11 @@ from emmet.core.absorption import AbsorptionDoc from emmet.core.utils import jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterator + class AbsorptionBuilder(Builder): def __init__( diff --git a/emmet-builders/emmet/builders/materials/corrected_entries.py b/emmet-builders/emmet/builders/materials/corrected_entries.py index 1dd1cb53d5..320c43ef5d 100644 --- a/emmet-builders/emmet/builders/materials/corrected_entries.py +++ b/emmet-builders/emmet/builders/materials/corrected_entries.py @@ -4,7 +4,6 @@ from datetime import datetime from itertools import chain from math import ceil -from typing import Iterable, Iterator from maggma.core import Builder, Store from maggma.utils import grouper @@ -16,6 +15,11 @@ from emmet.core.thermo import ThermoType from emmet.core.utils import jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + class CorrectedEntriesBuilder(Builder): def __init__( diff --git a/emmet-builders/emmet/builders/materials/dielectric.py b/emmet-builders/emmet/builders/materials/dielectric.py index 4346dc662a..c4d0add2d7 100644 --- a/emmet-builders/emmet/builders/materials/dielectric.py +++ b/emmet-builders/emmet/builders/materials/dielectric.py @@ -1,5 +1,4 @@ from math import ceil -from typing import Iterator import numpy as np from maggma.builders import Builder @@ -10,6 +9,11 @@ from emmet.core.polar import DielectricDoc from emmet.core.utils import jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterator + class DielectricBuilder(Builder): def __init__( diff --git a/emmet-builders/emmet/builders/materials/elasticity.py b/emmet-builders/emmet/builders/materials/elasticity.py index 98be5dc589..38461505c4 100644 --- a/emmet-builders/emmet/builders/materials/elasticity.py +++ b/emmet-builders/emmet/builders/materials/elasticity.py @@ -18,7 +18,6 @@ """ from datetime import datetime -from typing import Any, Generator import numpy as np from maggma.core import Builder, Store @@ -33,6 +32,12 @@ from emmet.core.utils import jsanitize from emmet.core.vasp.calc_types import CalcType +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Generator + from typing import Any + class ElasticityBuilder(Builder): def __init__( diff --git a/emmet-builders/emmet/builders/materials/electrodes.py b/emmet-builders/emmet/builders/materials/electrodes.py index 67b5e0d9a5..aadfc6dfcd 100644 --- a/emmet-builders/emmet/builders/materials/electrodes.py +++ b/emmet-builders/emmet/builders/materials/electrodes.py @@ -4,7 +4,6 @@ from functools import lru_cache from itertools import chain from math import ceil -from typing import Any, Iterator from maggma.builders import Builder from maggma.stores import MongoStore @@ -18,6 +17,12 @@ from emmet.core.structure_group import StructureGroupDoc, _get_id_lexi from emmet.core.utils import jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from typing import Any + from collections.abc import Iterator + def s_hash(el): return el.data["comp_delith"] diff --git a/emmet-builders/emmet/builders/materials/magnetism.py b/emmet-builders/emmet/builders/materials/magnetism.py index 883bd92c4f..f9e51949c5 100644 --- a/emmet-builders/emmet/builders/materials/magnetism.py +++ b/emmet-builders/emmet/builders/materials/magnetism.py @@ -1,5 +1,4 @@ from math import ceil -from typing import Iterator from maggma.builders import Builder from maggma.stores import Store @@ -9,6 +8,11 @@ from emmet.core.magnetism import MagnetismDoc from emmet.core.utils import jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterator + __author__ = "Shyam Dwaraknath , Matthew Horton " diff --git a/emmet-builders/emmet/builders/materials/optimade.py b/emmet-builders/emmet/builders/materials/optimade.py index 4d1f1857ca..9d6b11fed3 100644 --- a/emmet-builders/emmet/builders/materials/optimade.py +++ b/emmet-builders/emmet/builders/materials/optimade.py @@ -1,5 +1,4 @@ from math import ceil -from typing import Iterator from maggma.builders import Builder from maggma.core import Store @@ -9,6 +8,11 @@ from emmet.core.optimade import OptimadeMaterialsDoc from emmet.core.utils import jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterator + class OptimadeMaterialsBuilder(Builder): def __init__( diff --git a/emmet-builders/emmet/builders/materials/provenance.py b/emmet-builders/emmet/builders/materials/provenance.py index c7c43e8597..09eb07707c 100644 --- a/emmet-builders/emmet/builders/materials/provenance.py +++ b/emmet-builders/emmet/builders/materials/provenance.py @@ -1,7 +1,6 @@ from collections import defaultdict from datetime import datetime from math import ceil -from typing import Iterable from maggma.core import Builder, Store from maggma.utils import grouper @@ -12,6 +11,11 @@ from emmet.core.provenance import ProvenanceDoc, SNLDict from emmet.core.utils import get_sg, jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterable + class ProvenanceBuilder(Builder): def __init__( diff --git a/emmet-builders/emmet/builders/materials/thermo.py b/emmet-builders/emmet/builders/materials/thermo.py index 07b36de4c9..48e2c2421c 100644 --- a/emmet-builders/emmet/builders/materials/thermo.py +++ b/emmet-builders/emmet/builders/materials/thermo.py @@ -2,7 +2,6 @@ from datetime import datetime from itertools import chain from math import ceil -from typing import Iterator, Set from maggma.core import Builder, Store from maggma.stores import S3Store @@ -15,6 +14,11 @@ from emmet.core.thermo import PhaseDiagramDoc, ThermoDoc from emmet.core.utils import jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterator + class ThermoBuilder(Builder): def __init__( @@ -49,7 +53,7 @@ def __init__( self.phase_diagram = phase_diagram self.num_phase_diagram_eles = num_phase_diagram_eles self.chunk_size = chunk_size - self._completed_tasks: Set[str] = set() + self._completed_tasks: set[str] = set() if self.thermo.key != "thermo_id": warnings.warn( diff --git a/emmet-builders/emmet/builders/matscholar/missing_compositions.py b/emmet-builders/emmet/builders/matscholar/missing_compositions.py index 0d92097813..5bbc32adb5 100644 --- a/emmet-builders/emmet/builders/matscholar/missing_compositions.py +++ b/emmet-builders/emmet/builders/matscholar/missing_compositions.py @@ -1,13 +1,17 @@ import itertools from itertools import combinations from math import ceil -from typing import Iterator from maggma.core import Builder from maggma.stores import MongoStore, MongoURIStore, S3Store from maggma.utils import grouper from pymatgen.core import Composition, Element +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterator + class MissingCompositionsBuilder(Builder): """ diff --git a/emmet-builders/emmet/builders/molecules/atomic.py b/emmet-builders/emmet/builders/molecules/atomic.py index 28a9006f25..a11ed8cca5 100644 --- a/emmet-builders/emmet/builders/molecules/atomic.py +++ b/emmet-builders/emmet/builders/molecules/atomic.py @@ -2,7 +2,6 @@ from datetime import datetime from itertools import chain from math import ceil -from typing import Iterable, Iterator from maggma.builders import Builder from maggma.core import Store @@ -19,6 +18,11 @@ from emmet.core.qchem.task import TaskDocument from emmet.core.utils import jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + __author__ = "Evan Spotte-Smith" SETTINGS = EmmetBuildSettings() diff --git a/emmet-builders/emmet/builders/molecules/bonds.py b/emmet-builders/emmet/builders/molecules/bonds.py index ac4ad3d713..8b19d56f05 100644 --- a/emmet-builders/emmet/builders/molecules/bonds.py +++ b/emmet-builders/emmet/builders/molecules/bonds.py @@ -2,7 +2,6 @@ from datetime import datetime from itertools import chain from math import ceil -from typing import Iterable, Iterator from maggma.builders import Builder from maggma.core import Store @@ -14,6 +13,11 @@ from emmet.core.qchem.task import TaskDocument from emmet.core.utils import jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + __author__ = "Evan Spotte-Smith" SETTINGS = EmmetBuildSettings() diff --git a/emmet-builders/emmet/builders/molecules/electric.py b/emmet-builders/emmet/builders/molecules/electric.py index 5b577b378b..20ca4ee977 100644 --- a/emmet-builders/emmet/builders/molecules/electric.py +++ b/emmet-builders/emmet/builders/molecules/electric.py @@ -2,7 +2,6 @@ from datetime import datetime from itertools import chain from math import ceil -from typing import Iterable, Iterator from maggma.builders import Builder from maggma.core import Store @@ -14,6 +13,11 @@ from emmet.core.qchem.task import TaskDocument from emmet.core.utils import jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + __author__ = "Evan Spotte-Smith" SETTINGS = EmmetBuildSettings() diff --git a/emmet-builders/emmet/builders/molecules/metal_binding.py b/emmet-builders/emmet/builders/molecules/metal_binding.py index 58cfb6966b..4b789b4918 100644 --- a/emmet-builders/emmet/builders/molecules/metal_binding.py +++ b/emmet-builders/emmet/builders/molecules/metal_binding.py @@ -2,7 +2,7 @@ from datetime import datetime from itertools import chain from math import ceil -from typing import Iterable, Iterator +from typing import TYPE_CHECKING from maggma.builders import Builder from maggma.core import Store @@ -18,6 +18,9 @@ from emmet.core.qchem.molecule import MoleculeDoc from emmet.core.utils import jsanitize +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + __author__ = "Evan Spotte-Smith" SETTINGS = EmmetBuildSettings() diff --git a/emmet-builders/emmet/builders/molecules/orbitals.py b/emmet-builders/emmet/builders/molecules/orbitals.py index ccc7a3e78a..91fd0251ed 100644 --- a/emmet-builders/emmet/builders/molecules/orbitals.py +++ b/emmet-builders/emmet/builders/molecules/orbitals.py @@ -2,7 +2,7 @@ from datetime import datetime from itertools import chain from math import ceil -from typing import Iterable, Iterator +from typing import TYPE_CHECKING from maggma.builders import Builder from maggma.core import Store @@ -14,6 +14,9 @@ from emmet.core.qchem.task import TaskDocument from emmet.core.utils import jsanitize +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + __author__ = "Evan Spotte-Smith" SETTINGS = EmmetBuildSettings() diff --git a/emmet-builders/emmet/builders/molecules/redox.py b/emmet-builders/emmet/builders/molecules/redox.py index 6d6806f3f7..02ae1e5ac1 100644 --- a/emmet-builders/emmet/builders/molecules/redox.py +++ b/emmet-builders/emmet/builders/molecules/redox.py @@ -3,7 +3,6 @@ from datetime import datetime from itertools import chain, groupby from math import ceil -from typing import Any, Iterable, Iterator from maggma.builders import Builder from maggma.core import Store @@ -17,6 +16,12 @@ from emmet.core.qchem.task import TaskDocument from emmet.core.utils import confirm_molecule, get_graph_hash, jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + from typing import Any + __author__ = "Evan Spotte-Smith" SETTINGS = EmmetBuildSettings() diff --git a/emmet-builders/emmet/builders/molecules/summary.py b/emmet-builders/emmet/builders/molecules/summary.py index 0facfdfbec..840f2e8d96 100644 --- a/emmet-builders/emmet/builders/molecules/summary.py +++ b/emmet-builders/emmet/builders/molecules/summary.py @@ -1,7 +1,6 @@ from datetime import datetime from itertools import chain from math import ceil -from typing import Any, Iterable, Iterator from maggma.builders import Builder from maggma.core import Store @@ -11,6 +10,13 @@ from emmet.core.molecules.summary import MoleculeSummaryDoc from emmet.core.utils import jsanitize + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + from typing import Any + # from monty.serialization import loadfn, dumpfn diff --git a/emmet-builders/emmet/builders/molecules/thermo.py b/emmet-builders/emmet/builders/molecules/thermo.py index 2d93c79d4b..b55df2d698 100644 --- a/emmet-builders/emmet/builders/molecules/thermo.py +++ b/emmet-builders/emmet/builders/molecules/thermo.py @@ -2,7 +2,6 @@ from datetime import datetime from itertools import chain from math import ceil -from typing import Iterable, Iterator from maggma.builders import Builder from maggma.core import Store @@ -17,6 +16,12 @@ from emmet.core.qchem.task import TaskDocument from emmet.core.utils import jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + + __author__ = "Evan Spotte-Smith" SETTINGS = EmmetBuildSettings() diff --git a/emmet-builders/emmet/builders/molecules/trajectory.py b/emmet-builders/emmet/builders/molecules/trajectory.py index 7c89ebdb44..cf44a98e11 100644 --- a/emmet-builders/emmet/builders/molecules/trajectory.py +++ b/emmet-builders/emmet/builders/molecules/trajectory.py @@ -2,7 +2,6 @@ from datetime import datetime from itertools import chain from math import ceil -from typing import Iterable, Iterator from maggma.builders import Builder from maggma.core import Store @@ -14,6 +13,11 @@ from emmet.core.qchem.task import TaskDocument from emmet.core.utils import jsanitize +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + __author__ = "Evan Spotte-Smith" SETTINGS = EmmetBuildSettings() diff --git a/emmet-builders/emmet/builders/molecules/vibration.py b/emmet-builders/emmet/builders/molecules/vibration.py index 6a45b8c356..89054c2cb0 100644 --- a/emmet-builders/emmet/builders/molecules/vibration.py +++ b/emmet-builders/emmet/builders/molecules/vibration.py @@ -2,7 +2,7 @@ from datetime import datetime from itertools import chain from math import ceil -from typing import Iterable, Iterator +from typing import TYPE_CHECKING from maggma.builders import Builder from maggma.core import Store @@ -14,6 +14,9 @@ from emmet.core.qchem.task import TaskDocument from emmet.core.utils import jsanitize +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + __author__ = "Evan Spotte-Smith" SETTINGS = EmmetBuildSettings() diff --git a/emmet-builders/emmet/builders/qchem/molecules.py b/emmet-builders/emmet/builders/qchem/molecules.py index 7dcc1a9cab..c749c2ab87 100644 --- a/emmet-builders/emmet/builders/qchem/molecules.py +++ b/emmet-builders/emmet/builders/qchem/molecules.py @@ -1,7 +1,6 @@ from datetime import datetime from itertools import chain, groupby from math import ceil -from typing import Any, Iterable, Iterator, Set import networkx as nx from maggma.builders import Builder @@ -19,6 +18,12 @@ from emmet.core.qchem.task import TaskDocument from emmet.core.utils import get_molecule_id, group_molecules, jsanitize, make_mol_graph +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + from typing import Any + __author__ = "Evan Spotte-Smith " @@ -554,11 +559,11 @@ def process_item(self, items: list[dict]) -> list[dict]: levels_of_theory = dict() solvents = dict() lot_solvents = dict() - unique_calc_types: Set[str | CalcType] = set() - unique_task_types: Set[str | TaskType] = set() - unique_levels_of_theory: Set[str | LevelOfTheory] = set() - unique_solvents: Set[str] = set() - unique_lot_solvents: Set[str] = set() + unique_calc_types: set[str | CalcType] = set() + unique_task_types: set[str | TaskType] = set() + unique_levels_of_theory: set[str | LevelOfTheory] = set() + unique_solvents: set[str] = set() + unique_lot_solvents: set[str] = set() origins = list() entries = list() best_entries: dict[str, Any] = dict() diff --git a/emmet-builders/emmet/builders/utils.py b/emmet-builders/emmet/builders/utils.py index fff1e718e9..d1d139735c 100644 --- a/emmet-builders/emmet/builders/utils.py +++ b/emmet-builders/emmet/builders/utils.py @@ -7,7 +7,6 @@ from io import BytesIO from itertools import chain, combinations from pathlib import Path -from typing import Any, Literal, Set import orjson from botocore.exceptions import ClientError @@ -18,8 +17,13 @@ from emmet.builders.settings import EmmetBuildSettings +from typing import TYPE_CHECKING -def maximal_spanning_non_intersecting_subsets(sets) -> Set[Set]: +if TYPE_CHECKING: + from typing import Any, Literal + + +def maximal_spanning_non_intersecting_subsets(sets) -> set[set[Any]]: """ Finds the maximal spanning non intersecting subsets of a group of sets This is usefull for parsing out the sandboxes and figuring out how to group @@ -47,7 +51,7 @@ def maximal_spanning_non_intersecting_subsets(sets) -> Set[Set]: return set(to_return_subsets) -def chemsys_permutations(chemsys) -> Set: +def chemsys_permutations(chemsys) -> set[str]: # Function to get all relevant chemical subsystems # e.g. for Li-Mn-O returns Li, Li-Mn, Li-Mn-O, Li-O, Mn, Mn-O, O elements = chemsys.split("-") diff --git a/emmet-builders/emmet/builders/vasp/materials.py b/emmet-builders/emmet/builders/vasp/materials.py index 712866a922..9da37b74d2 100644 --- a/emmet-builders/emmet/builders/vasp/materials.py +++ b/emmet-builders/emmet/builders/vasp/materials.py @@ -1,7 +1,6 @@ from datetime import datetime from itertools import chain from math import ceil -from typing import Iterable, Iterator from maggma.builders import Builder from maggma.stores import Store @@ -13,6 +12,11 @@ from emmet.core.vasp.calc_types import TaskType from emmet.core.vasp.material import MaterialsDoc +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + __author__ = "Shyam Dwaraknath " SETTINGS = EmmetBuildSettings() diff --git a/emmet-core/emmet/core/_general_store.py b/emmet-core/emmet/core/_general_store.py index bb665425d7..52e1b22753 100644 --- a/emmet-core/emmet/core/_general_store.py +++ b/emmet-core/emmet/core/_general_store.py @@ -1,11 +1,10 @@ +from __future__ import annotations + from pydantic import BaseModel, Field from emmet.core.utils import utcnow -try: - from typing import Literal # type: ignore -except ImportError: - from typing_extensions import Literal # type: ignore +from typing import Literal from datetime import datetime diff --git a/emmet-core/emmet/core/base.py b/emmet-core/emmet/core/base.py index 3f9519d994..bfbcbdc4dd 100644 --- a/emmet-core/emmet/core/base.py +++ b/emmet-core/emmet/core/base.py @@ -1,10 +1,7 @@ -# mypy: ignore-errors - """Base emmet model to add default metadata.""" from datetime import datetime -from typing import Literal, TypeVar - +from typing import Literal from pydantic import BaseModel, Field, field_validator from pymatgen.core import __version__ as pmg_version @@ -12,8 +9,6 @@ from emmet.core.common import convert_datetime from emmet.core.utils import utcnow -T = TypeVar("T", bound="EmmetBaseModel") - class EmmetMeta(BaseModel): """Default emmet metadata.""" diff --git a/emmet-core/emmet/core/electronic_structure.py b/emmet-core/emmet/core/electronic_structure.py index 1dd8d494d0..dc7f9d5213 100644 --- a/emmet-core/emmet/core/electronic_structure.py +++ b/emmet-core/emmet/core/electronic_structure.py @@ -6,7 +6,7 @@ from datetime import datetime from enum import Enum from math import isnan -from typing import Type, TypeVar +from typing import TYPE_CHECKING import numpy as np from pydantic import BaseModel, Field, field_validator @@ -29,6 +29,9 @@ from emmet.core.settings import EmmetSettings from emmet.core.utils import utcnow +if TYPE_CHECKING: + from typing_extensions import Self + SETTINGS = EmmetSettings() @@ -190,9 +193,6 @@ class DosData(BaseModel): ) -T = TypeVar("T", bound="ElectronicStructureDoc") - - class ElectronicStructureDoc(PropertyDoc, ElectronicStructureSummary): """ Definition for a core Electronic Structure Document @@ -210,7 +210,7 @@ class ElectronicStructureDoc(PropertyDoc, ElectronicStructureSummary): @classmethod def from_bsdos( # type: ignore[override] - cls: Type[T], + cls, dos: dict[MPID, CompleteDos], is_gap_direct: bool, is_metal: bool, @@ -221,7 +221,7 @@ def from_bsdos( # type: ignore[override] hinuma: dict[MPID, BandStructureSymmLine] | None = None, latimer_munro: dict[MPID, BandStructureSymmLine] | None = None, **kwargs, - ) -> T: + ) -> Self: """ Builds a electronic structure document using band structure and density of states data. diff --git a/emmet-core/emmet/core/material.py b/emmet-core/emmet/core/material.py index ca5b3fe4a3..f32a66d88f 100644 --- a/emmet-core/emmet/core/material.py +++ b/emmet-core/emmet/core/material.py @@ -2,8 +2,9 @@ from __future__ import annotations +from collections.abc import Mapping from datetime import datetime -from typing import Mapping, Type, TypeVar +from typing import TYPE_CHECKING from pydantic import BaseModel, Field, field_validator from pymatgen.core import Structure @@ -15,6 +16,9 @@ from emmet.core.utils import utcnow from emmet.core.vasp.validation import DeprecationMessage +if TYPE_CHECKING: + from typing_extensions import Self + class PropertyOrigin(BaseModel): """ @@ -36,10 +40,6 @@ def handle_datetime(cls, v): return convert_datetime(cls, v) -T = TypeVar("T", bound="MaterialsDoc") -S = TypeVar("S", bound="CoreMoleculeDoc") - - class MaterialsDoc(StructureMetadata): """ Definition for a core Materials Document @@ -103,8 +103,8 @@ class MaterialsDoc(StructureMetadata): @classmethod def from_structure( - cls: Type[T], structure: Structure, material_id: MPID | None = None, **kwargs - ) -> T: # type: ignore[override] + cls, structure: Structure, material_id: MPID | None = None, **kwargs + ) -> Self: # type: ignore[override] """ Builds a materials document using the minimal amount of information """ @@ -187,8 +187,8 @@ class CoreMoleculeDoc(MoleculeMetadata): @classmethod def from_molecule( - cls: Type[S], molecule: Molecule, molecule_id: MPculeID, **kwargs - ) -> S: # type: ignore[override] + cls, molecule: Molecule, molecule_id: MPculeID, **kwargs + ) -> Self: # type: ignore[override] """ Builds a molecule document using the minimal amount of information """ diff --git a/emmet-core/emmet/core/material_property.py b/emmet-core/emmet/core/material_property.py index 6b6190de9d..18a6700702 100644 --- a/emmet-core/emmet/core/material_property.py +++ b/emmet-core/emmet/core/material_property.py @@ -2,8 +2,9 @@ from __future__ import annotations +from collections.abc import Sequence from datetime import datetime -from typing import Sequence, Type, TypeVar +from typing import TYPE_CHECKING from pydantic import Field, field_validator from pymatgen.core import Structure @@ -15,7 +16,8 @@ from emmet.core.utils import utcnow from emmet.core.vasp.validation import DeprecationMessage -S = TypeVar("S", bound="PropertyDoc") +if TYPE_CHECKING: + from typing_extensions import Self class PropertyDoc(StructureMetadata): @@ -62,11 +64,11 @@ def handle_datetime(cls, v): @classmethod def from_structure( # type: ignore[override] - cls: Type[S], + cls, meta_structure: Structure, material_id: MPID | None = None, **kwargs, - ) -> S: + ) -> Self: """ Builds a materials document using the minimal amount of information """ diff --git a/emmet-core/emmet/core/mobility/migrationgraph.py b/emmet-core/emmet/core/mobility/migrationgraph.py index 3ffb01296d..f4d55d4048 100644 --- a/emmet-core/emmet/core/mobility/migrationgraph.py +++ b/emmet-core/emmet/core/mobility/migrationgraph.py @@ -1,7 +1,7 @@ from __future__ import annotations from datetime import datetime -from typing import Sequence +from collections.abc import Sequence import numpy as np from pydantic import Field diff --git a/emmet-core/emmet/core/molecules/bonds.py b/emmet-core/emmet/core/molecules/bonds.py index 9db5b59332..2ed137191d 100644 --- a/emmet-core/emmet/core/molecules/bonds.py +++ b/emmet-core/emmet/core/molecules/bonds.py @@ -1,6 +1,6 @@ import copy from hashlib import blake2b -from typing import Any +from typing import TYPE_CHECKING import networkx as nx from pydantic import Field @@ -13,6 +13,9 @@ from emmet.core.qchem.task import TaskDocument from emmet.core.utils import make_mol_graph +if TYPE_CHECKING: + from typing import Any + __author__ = "Evan Spotte-Smith " diff --git a/emmet-core/emmet/core/molecules/metal_binding.py b/emmet-core/emmet/core/molecules/metal_binding.py index 2a5d84e595..bc4c742dde 100644 --- a/emmet-core/emmet/core/molecules/metal_binding.py +++ b/emmet-core/emmet/core/molecules/metal_binding.py @@ -1,5 +1,10 @@ +# mypy: ignore-errors + +from __future__ import annotations + +from typing import TYPE_CHECKING + from hashlib import blake2b -from typing import Type, TypeVar from pydantic import BaseModel, Field from pymatgen.core.periodic_table import Element, Species @@ -12,12 +17,13 @@ from emmet.core.mpid import MPculeID from emmet.core.qchem.molecule import MoleculeDoc +if TYPE_CHECKING: + from typing_extensions import Self + __author__ = "Evan Spotte-Smith " METAL_BINDING_METHODS = ["nbo", "mulliken-OB-mee"] -T = TypeVar("T", bound="MetalBindingDoc") - class MetalBindingData(BaseModel): """ @@ -187,7 +193,7 @@ class MetalBindingDoc(PropertyDoc): @classmethod def from_docs( - cls: Type[T], + cls: Self, method: str, metal_indices: list[int], base_molecule_doc: MoleculeDoc, @@ -198,7 +204,7 @@ def from_docs( metal_thermo: dict[int, MoleculeThermoDoc], nometal_thermo: dict[int, MoleculeThermoDoc], **kwargs, - ): # type: ignore[override] + ) -> Self: # type: ignore[override] """ Construct a document describing the binding energy of a metal atom or ion to a molecule from MoleculeThermoDocs (for thermochemistry), PartialChargesDocs diff --git a/emmet-core/emmet/core/molecules/molecule_property.py b/emmet-core/emmet/core/molecules/molecule_property.py index 5745b5476b..e6dd9fd19a 100644 --- a/emmet-core/emmet/core/molecules/molecule_property.py +++ b/emmet-core/emmet/core/molecules/molecule_property.py @@ -1,9 +1,12 @@ """Core definition of a Materials Document""" +# mypy: ignore-errors + from __future__ import annotations +from collections.abc import Sequence from datetime import datetime -from typing import Sequence, Type, TypeVar +from typing import TYPE_CHECKING from pydantic import Field from pymatgen.core.structure import Molecule @@ -14,10 +17,10 @@ from emmet.core.structure import MoleculeMetadata from emmet.core.utils import utcnow -__author__ = "Evan Spotte-Smith " - +if TYPE_CHECKING: + from typing_extensions import Self -S = TypeVar("S", bound="PropertyDoc") +__author__ = "Evan Spotte-Smith " class PropertyDoc(MoleculeMetadata): @@ -80,12 +83,12 @@ class PropertyDoc(MoleculeMetadata): @classmethod def from_molecule( # type: ignore[override] - cls: Type[S], + cls: Self, meta_molecule: Molecule, property_id: str, molecule_id: MPculeID, **kwargs, - ) -> S: + ) -> Self: """ Builds a molecule document using the minimal amount of information """ @@ -95,4 +98,4 @@ def from_molecule( # type: ignore[override] property_id=property_id, molecule_id=molecule_id, **kwargs, - ) # type: ignore + ) diff --git a/emmet-core/emmet/core/molecules/orbitals.py b/emmet-core/emmet/core/molecules/orbitals.py index ee71ff5c88..8a03b83a41 100644 --- a/emmet-core/emmet/core/molecules/orbitals.py +++ b/emmet-core/emmet/core/molecules/orbitals.py @@ -1,6 +1,8 @@ +from __future__ import annotations + import re from hashlib import blake2b -from typing import Any +from typing import TYPE_CHECKING from monty.json import MSONable from pydantic import Field @@ -10,6 +12,9 @@ from emmet.core.mpid import MPculeID from emmet.core.qchem.task import TaskDocument +if TYPE_CHECKING: + from typing import Any + __author__ = "Evan Spotte-Smith " diff --git a/emmet-core/emmet/core/molecules/redox.py b/emmet-core/emmet/core/molecules/redox.py index 815712f800..0eed6b7d77 100644 --- a/emmet-core/emmet/core/molecules/redox.py +++ b/emmet-core/emmet/core/molecules/redox.py @@ -1,5 +1,5 @@ from hashlib import blake2b -from typing import Any, Type, TypeVar +from typing import TYPE_CHECKING from pydantic import Field @@ -10,15 +10,15 @@ from emmet.core.qchem.molecule import MoleculeDoc from emmet.core.qchem.task import TaskDocument +if TYPE_CHECKING: + from typing import Any + __author__ = "Evan Spotte-Smith " reference_potential = 4.44 -T = TypeVar("T", bound="RedoxDoc") - - class RedoxDoc(PropertyDoc): """ Molecular properties related to reduction and oxidation, including @@ -94,7 +94,7 @@ class RedoxDoc(PropertyDoc): ) @classmethod - def _g_or_e(cls: Type[T], entry: dict[str, Any]) -> float: + def _g_or_e(cls, entry: dict[str, Any]) -> float: """ Single atoms may not have free energies like more complex molecules do. This function returns the free energy of a TaskDocument entry if @@ -117,7 +117,7 @@ def _g_or_e(cls: Type[T], entry: dict[str, Any]) -> float: @classmethod def from_docs( - cls: Type[T], + cls, base_molecule_doc: MoleculeDoc, base_thermo_doc: MoleculeThermoDoc, red_doc: MoleculeThermoDoc | None = None, diff --git a/emmet-core/emmet/core/molecules/summary.py b/emmet-core/emmet/core/molecules/summary.py index 6a76e55cd9..674de76c9e 100644 --- a/emmet-core/emmet/core/molecules/summary.py +++ b/emmet-core/emmet/core/molecules/summary.py @@ -1,6 +1,6 @@ from enum import Enum from hashlib import blake2b -from typing import Any, TypeVar +from typing import TYPE_CHECKING from pydantic import BaseModel, Field from pymatgen.core.structure import Molecule @@ -10,10 +10,11 @@ from emmet.core.mpid import MPID, MPculeID from emmet.core.qchem.calc_types import CalcType, LevelOfTheory, TaskType -__author__ = "Evan Spotte-Smith " - +if TYPE_CHECKING: + from typing import Any + from typing_extensions import Self -T = TypeVar("T", bound="MoleculeSummaryDoc") +__author__ = "Evan Spotte-Smith " class HasProps(Enum): @@ -477,7 +478,7 @@ class MoleculeSummaryDoc(PropertyDoc): ) @classmethod - def from_docs(cls, molecule_id: MPculeID, docs: dict[str, Any]): + def from_docs(cls, molecule_id: MPculeID, docs: dict[str, Any]) -> Self: """Converts a bunch of property docs into a SummaryDoc""" doc = _copy_from_docs(**docs) diff --git a/emmet-core/emmet/core/mpid.py b/emmet-core/emmet/core/mpid.py index ee74a2b57a..94ba786246 100644 --- a/emmet-core/emmet/core/mpid.py +++ b/emmet-core/emmet/core/mpid.py @@ -2,12 +2,16 @@ from __future__ import annotations import re -from typing import Any, Callable +from typing import TYPE_CHECKING from pydantic import GetJsonSchemaHandler from pydantic.json_schema import JsonSchemaValue from pydantic_core import CoreSchema, core_schema +if TYPE_CHECKING: + from collections.abc import Callable + from typing import Any + # matches "mp-1234" or "1234" followed by and optional "-(Alphanumeric)" mpid_regex = re.compile(r"^([A-Za-z]*-)?(\d+)(-[A-Za-z0-9]+)*$") mpculeid_regex = re.compile( diff --git a/emmet-core/emmet/core/openff/solvation.py b/emmet-core/emmet/core/openff/solvation.py index 9df9bdcdc1..9506857916 100644 --- a/emmet-core/emmet/core/openff/solvation.py +++ b/emmet-core/emmet/core/openff/solvation.py @@ -1,11 +1,14 @@ from io import StringIO -from typing import Any +from typing import TYPE_CHECKING import pandas as pd from pydantic import BaseModel, Field, PlainSerializer, PlainValidator, WithJsonSchema from solvation_analysis.solute import Solute from typing_extensions import Annotated +if TYPE_CHECKING: + from typing import Any + def data_frame_validater(o: Any) -> pd.DataFrame: if isinstance(o, pd.DataFrame): diff --git a/emmet-core/emmet/core/qc_tasks.py b/emmet-core/emmet/core/qc_tasks.py index e9db29d84c..125a0f9ca1 100644 --- a/emmet-core/emmet/core/qc_tasks.py +++ b/emmet-core/emmet/core/qc_tasks.py @@ -1,11 +1,12 @@ +"""Core definition of a Q-Chem Task Document""" + # mypy: ignore-errors -"""Core definition of a Q-Chem Task Document""" import logging import re from collections import OrderedDict from pathlib import Path -from typing import Any, Type, TypeVar +from typing import Any, TYPE_CHECKING from custodian.qchem.jobs import QCJob from monty.serialization import loadfn @@ -18,12 +19,14 @@ from emmet.core.qchem.task import QChemStatus from emmet.core.structure import MoleculeMetadata +if TYPE_CHECKING: + from typing_extensions import Self + __author__ = ( "Evan Spotte-Smith , Rishabh D. Guha " ) logger = logging.getLogger(__name__) -_T = TypeVar("_T", bound="TaskDoc") # _DERIVATIVE_FILES = ("GRAD", "HESS") @@ -283,13 +286,13 @@ class TaskDoc(MoleculeMetadata): @classmethod def from_directory( - cls: Type[_T], + cls, dir_name: Path | str, validate_lot: bool = True, store_additional_json: bool = True, additional_fields: dict[str, Any] = None, **qchem_calculation_kwargs, - ) -> _T: + ) -> Self: """ Create a task document from a directory containing QChem files. diff --git a/emmet-core/emmet/core/qchem/calc_types/utils.py b/emmet-core/emmet/core/qchem/calc_types/utils.py index 8fa78bc683..aac1270ad4 100644 --- a/emmet-core/emmet/core/qchem/calc_types/utils.py +++ b/emmet-core/emmet/core/qchem/calc_types/utils.py @@ -1,10 +1,13 @@ """Utilities to determine level of theory, task type, and calculation type for Q-Chem calculations""" -from typing import Any +from typing import TYPE_CHECKING from emmet.core.qchem.calc_types import CalcType, LevelOfTheory, TaskType from emmet.core.qchem.calc_types.calc_types import BASIS_SETS, FUNCTIONALS +if TYPE_CHECKING: + from typing import Any + __author__ = "Evan Spotte-Smith " # TODO : better string translation diff --git a/emmet-core/emmet/core/qchem/molecule.py b/emmet-core/emmet/core/qchem/molecule.py index 959bdd5205..941618a376 100644 --- a/emmet-core/emmet/core/qchem/molecule.py +++ b/emmet-core/emmet/core/qchem/molecule.py @@ -1,6 +1,7 @@ """Core definition of a Molecule Document""" -from typing import Any, Mapping +from collections.abc import Mapping +from typing import Any from pydantic import Field from pymatgen.analysis.molecule_matcher import MoleculeMatcher diff --git a/emmet-core/emmet/core/qchem/task.py b/emmet-core/emmet/core/qchem/task.py index f5cce2778e..67ad4e8a70 100644 --- a/emmet-core/emmet/core/qchem/task.py +++ b/emmet-core/emmet/core/qchem/task.py @@ -1,7 +1,8 @@ +"""Core definition of a Q-Chem Task Document""" + # mypy: ignore-errors -"""Core definition of a Q-Chem Task Document""" -from typing import Any, Callable +from typing import Any, TYPE_CHECKING from pydantic import BaseModel, Field from pymatgen.core.structure import Molecule @@ -20,6 +21,9 @@ from emmet.core.task import BaseTaskDocument from emmet.core.utils import ValueEnum +if TYPE_CHECKING: + from collections.abc import Callable + __author__ = "Evan Spotte-Smith " diff --git a/emmet-core/emmet/core/settings.py b/emmet-core/emmet/core/settings.py index ba0dcec1fd..00196c7b63 100644 --- a/emmet-core/emmet/core/settings.py +++ b/emmet-core/emmet/core/settings.py @@ -4,7 +4,7 @@ import json from pathlib import Path -from typing import TYPE_CHECKING, Type, TypeVar +from typing import TYPE_CHECKING import requests # type: ignore[import-untyped] from monty.json import MontyDecoder @@ -13,13 +13,11 @@ if TYPE_CHECKING: from typing import Any + from typing_extensions import Self DEFAULT_CONFIG_FILE_PATH = str(Path.home().joinpath(".emmet.json")) -S = TypeVar("S", bound="EmmetSettings") - - class EmmetSettings(BaseSettings): """ Settings for the emmet- packages @@ -196,7 +194,7 @@ def load_default_settings(cls, values: Any) -> Any: return new_values @classmethod - def autoload(cls: Type[S], settings: None | dict | S) -> S: + def autoload(cls, settings: None | dict | Self) -> Self: if settings is None: return cls(**{}) elif isinstance(settings, dict): diff --git a/emmet-core/emmet/core/structure.py b/emmet-core/emmet/core/structure.py index e669ac3635..c0ec82171d 100644 --- a/emmet-core/emmet/core/structure.py +++ b/emmet-core/emmet/core/structure.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Type, TypeVar +from typing import TYPE_CHECKING, TypeVar from pydantic import Field from pymatgen.core.composition import Composition @@ -13,6 +13,9 @@ from emmet.core.symmetry import PointGroupData, SymmetryData from emmet.core.utils import get_graph_hash +if TYPE_CHECKING: + from typing_extensions import Self + T = TypeVar("T", bound="StructureMetadata") S = TypeVar("S", bound="MoleculeMetadata") @@ -78,11 +81,11 @@ class StructureMetadata(EmmetBaseModel): @classmethod def from_composition( - cls: Type[T], + cls, composition: Composition, fields: list[str] | None = None, **kwargs, - ) -> T: + ) -> Self: fields = ( [ "elements", @@ -114,11 +117,11 @@ def from_composition( @classmethod def from_structure( - cls: Type[T], + cls, meta_structure: Structure, fields: list[str] | None = None, **kwargs, - ) -> T: + ) -> Self: fields = ( [ "nsites", @@ -222,11 +225,11 @@ class MoleculeMetadata(EmmetBaseModel): @classmethod def from_composition( - cls: Type[S], + cls, comp: Composition, fields: list[str] | None = None, **kwargs, - ) -> S: + ) -> Self: """ Create a MoleculeMetadata model from a composition. @@ -275,11 +278,11 @@ def from_composition( @classmethod def from_molecule( - cls: Type[S], + cls, meta_molecule: Molecule, fields: list[str] | None = None, **kwargs, - ) -> S: + ) -> Self: fields = ( [ "charge", diff --git a/emmet-core/emmet/core/structure_group.py b/emmet-core/emmet/core/structure_group.py index fd441a520a..5829ecacf2 100644 --- a/emmet-core/emmet/core/structure_group.py +++ b/emmet-core/emmet/core/structure_group.py @@ -2,7 +2,7 @@ import operator from datetime import datetime from itertools import groupby -from typing import Iterable +from typing import TYPE_CHECKING from pydantic import BaseModel, Field, field_validator from pymatgen.analysis.structure_matcher import ElementComparator, StructureMatcher @@ -14,6 +14,9 @@ from emmet.core.mpid import MPID from emmet.core.utils import utcnow +if TYPE_CHECKING: + from collections.abc import Iterable + logger = logging.getLogger(__name__) diff --git a/emmet-core/emmet/core/stubs.py b/emmet-core/emmet/core/stubs.py index 8c60d7e435..6a231553e9 100644 --- a/emmet-core/emmet/core/stubs.py +++ b/emmet-core/emmet/core/stubs.py @@ -1,14 +1,18 @@ -# mypy: ignore-errors # isort: off +# mypy: ignore-errors + """ This module stubs some pymatgen classes that implement custom behavior outside the standard MSONable model """ - +from typing import TYPE_CHECKING import pymatgen.core.composition from pydantic import RootModel from pymatgen.core.periodic_table import Element +if TYPE_CHECKING: + from typing import Any + """ The stub names are kept in sync with the actual classes so they show up correctly in the JSON Schema. They are imported here @@ -27,7 +31,7 @@ def get_validators(cls): yield validate_composition -def validate_composition(cls, v): +def validate_composition(cls, v: Any) -> pymatgen.core.composition.Composition: if isinstance(v, pymatgen.core.structure.Composition): return v return pymatgen.core.composition.Composition(**v) diff --git a/emmet-core/emmet/core/summary.py b/emmet-core/emmet/core/summary.py index e2b5df8d68..02864868a2 100644 --- a/emmet-core/emmet/core/summary.py +++ b/emmet-core/emmet/core/summary.py @@ -1,5 +1,5 @@ from enum import Enum -from typing import TypeVar +from typing import TYPE_CHECKING from pydantic import BaseModel, Field from pymatgen.core.periodic_table import Element @@ -11,7 +11,8 @@ from emmet.core.thermo import DecompositionProduct from emmet.core.xas import Edge, Type -T = TypeVar("T", bound="SummaryDoc") +if TYPE_CHECKING: + from typing_extensions import Self class HasProps(Enum): @@ -423,7 +424,9 @@ class SummaryDoc(PropertyDoc): ) @classmethod - def from_docs(cls, material_id: MPID | None = None, **docs: dict[str, dict]): + def from_docs( + cls, material_id: MPID | None = None, **docs: dict[str, dict] + ) -> Self: """Converts a bunch of summary docs into a SummaryDoc""" doc = _copy_from_doc(docs) diff --git a/emmet-core/emmet/core/symmetry.py b/emmet-core/emmet/core/symmetry.py index 243abab7a6..645fdca7ee 100644 --- a/emmet-core/emmet/core/symmetry.py +++ b/emmet-core/emmet/core/symmetry.py @@ -1,4 +1,6 @@ -from typing import Any +from __future__ import annotations + +from typing import TYPE_CHECKING from pydantic import BaseModel, Field from pymatgen.core import Structure @@ -13,6 +15,9 @@ from emmet.core.settings import EmmetSettings from emmet.core.utils import ValueEnum +if TYPE_CHECKING: + from typing import Any + SETTINGS = EmmetSettings() diff --git a/emmet-core/emmet/core/utils.py b/emmet-core/emmet/core/utils.py index f7dd44e24c..0c43015242 100644 --- a/emmet-core/emmet/core/utils.py +++ b/emmet-core/emmet/core/utils.py @@ -8,7 +8,7 @@ from enum import Enum from itertools import groupby from math import gcd -from typing import TYPE_CHECKING, Any, Iterator +from typing import TYPE_CHECKING import numpy as np from monty.io import zopen @@ -38,7 +38,8 @@ bson = None # type: ignore if TYPE_CHECKING: - from collections.abc import Mapping + from collections.abc import Iterator, Mapping + from typing import Any from emmet.core.typing import PathLike diff --git a/emmet-core/emmet/core/vasp/material.py b/emmet-core/emmet/core/vasp/material.py index 89ce967e4e..c634a9a655 100644 --- a/emmet-core/emmet/core/vasp/material.py +++ b/emmet-core/emmet/core/vasp/material.py @@ -1,6 +1,6 @@ """Core definition of a Materials Document""" -from typing import Mapping +from collections.abc import Mapping from pydantic import BaseModel, Field from pymatgen.analysis.structure_analyzer import SpacegroupAnalyzer From f8603939be949bedd01242f1c02cc8e3b22af9ff Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Mon, 16 Jun 2025 15:52:54 -0700 Subject: [PATCH 4/9] the present is unannotated --- emmet-api/tests/materials/summary/test_query_operators.py | 3 +-- emmet-builders/emmet/builders/materials/absorption_spectrum.py | 1 + emmet-builders/emmet/builders/materials/corrected_entries.py | 2 ++ emmet-builders/emmet/builders/materials/dielectric.py | 2 ++ emmet-builders/emmet/builders/materials/elasticity.py | 2 ++ emmet-builders/emmet/builders/materials/magnetism.py | 2 ++ emmet-builders/emmet/builders/materials/thermo.py | 2 ++ emmet-builders/emmet/builders/molecules/atomic.py | 2 ++ emmet-builders/emmet/builders/molecules/bonds.py | 2 ++ emmet-builders/emmet/builders/molecules/electric.py | 2 ++ emmet-builders/emmet/builders/molecules/metal_binding.py | 2 ++ emmet-builders/emmet/builders/molecules/orbitals.py | 2 ++ emmet-builders/emmet/builders/molecules/redox.py | 2 ++ emmet-builders/emmet/builders/molecules/summary.py | 2 ++ emmet-builders/emmet/builders/molecules/thermo.py | 2 ++ emmet-builders/emmet/builders/molecules/trajectory.py | 2 ++ emmet-builders/emmet/builders/molecules/vibration.py | 2 ++ emmet-builders/emmet/builders/qchem/molecules.py | 2 ++ emmet-builders/emmet/builders/vasp/materials.py | 2 ++ emmet-core/emmet/core/molecules/bonds.py | 2 ++ emmet-core/emmet/core/molecules/redox.py | 2 ++ emmet-core/emmet/core/molecules/summary.py | 2 ++ emmet-core/emmet/core/qc_tasks.py | 1 + emmet-core/emmet/core/qchem/calc_types/utils.py | 2 ++ emmet-core/emmet/core/qchem/task.py | 1 + emmet-core/emmet/core/structure_group.py | 2 ++ emmet-core/emmet/core/summary.py | 2 ++ 27 files changed, 50 insertions(+), 2 deletions(-) diff --git a/emmet-api/tests/materials/summary/test_query_operators.py b/emmet-api/tests/materials/summary/test_query_operators.py index 606d9cf229..6d582596c4 100644 --- a/emmet-api/tests/materials/summary/test_query_operators.py +++ b/emmet-api/tests/materials/summary/test_query_operators.py @@ -12,10 +12,9 @@ SearchESQuery, ) -from emmet.core.summary import SummaryStats +from emmet.core.summary import SummaryDoc, SummaryStats from pymatgen.analysis.magnetism import Ordering -from emmet.core.summary import SummaryDoc def test_has_props_query(): diff --git a/emmet-builders/emmet/builders/materials/absorption_spectrum.py b/emmet-builders/emmet/builders/materials/absorption_spectrum.py index 0fea459945..62d7fc0d83 100644 --- a/emmet-builders/emmet/builders/materials/absorption_spectrum.py +++ b/emmet-builders/emmet/builders/materials/absorption_spectrum.py @@ -1,3 +1,4 @@ +from __future__ import annotations from math import ceil import numpy as np diff --git a/emmet-builders/emmet/builders/materials/corrected_entries.py b/emmet-builders/emmet/builders/materials/corrected_entries.py index 320c43ef5d..535440fd5a 100644 --- a/emmet-builders/emmet/builders/materials/corrected_entries.py +++ b/emmet-builders/emmet/builders/materials/corrected_entries.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import copy import warnings from collections import defaultdict diff --git a/emmet-builders/emmet/builders/materials/dielectric.py b/emmet-builders/emmet/builders/materials/dielectric.py index c4d0add2d7..e0a0a6b005 100644 --- a/emmet-builders/emmet/builders/materials/dielectric.py +++ b/emmet-builders/emmet/builders/materials/dielectric.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from math import ceil import numpy as np diff --git a/emmet-builders/emmet/builders/materials/elasticity.py b/emmet-builders/emmet/builders/materials/elasticity.py index 38461505c4..5aebff2e07 100644 --- a/emmet-builders/emmet/builders/materials/elasticity.py +++ b/emmet-builders/emmet/builders/materials/elasticity.py @@ -17,6 +17,8 @@ 7. Fit the elastic tensor. """ +from __future__ import annotations + from datetime import datetime import numpy as np diff --git a/emmet-builders/emmet/builders/materials/magnetism.py b/emmet-builders/emmet/builders/materials/magnetism.py index f9e51949c5..065da63550 100644 --- a/emmet-builders/emmet/builders/materials/magnetism.py +++ b/emmet-builders/emmet/builders/materials/magnetism.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from math import ceil from maggma.builders import Builder diff --git a/emmet-builders/emmet/builders/materials/thermo.py b/emmet-builders/emmet/builders/materials/thermo.py index 48e2c2421c..e2c302066b 100644 --- a/emmet-builders/emmet/builders/materials/thermo.py +++ b/emmet-builders/emmet/builders/materials/thermo.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import warnings from datetime import datetime from itertools import chain diff --git a/emmet-builders/emmet/builders/molecules/atomic.py b/emmet-builders/emmet/builders/molecules/atomic.py index a11ed8cca5..251693e0b2 100644 --- a/emmet-builders/emmet/builders/molecules/atomic.py +++ b/emmet-builders/emmet/builders/molecules/atomic.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from collections import defaultdict from datetime import datetime from itertools import chain diff --git a/emmet-builders/emmet/builders/molecules/bonds.py b/emmet-builders/emmet/builders/molecules/bonds.py index 8b19d56f05..02027bbeee 100644 --- a/emmet-builders/emmet/builders/molecules/bonds.py +++ b/emmet-builders/emmet/builders/molecules/bonds.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from collections import defaultdict from datetime import datetime from itertools import chain diff --git a/emmet-builders/emmet/builders/molecules/electric.py b/emmet-builders/emmet/builders/molecules/electric.py index 20ca4ee977..d4bc7092ad 100644 --- a/emmet-builders/emmet/builders/molecules/electric.py +++ b/emmet-builders/emmet/builders/molecules/electric.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from collections import defaultdict from datetime import datetime from itertools import chain diff --git a/emmet-builders/emmet/builders/molecules/metal_binding.py b/emmet-builders/emmet/builders/molecules/metal_binding.py index 4b789b4918..18049e4f4c 100644 --- a/emmet-builders/emmet/builders/molecules/metal_binding.py +++ b/emmet-builders/emmet/builders/molecules/metal_binding.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import copy from datetime import datetime from itertools import chain diff --git a/emmet-builders/emmet/builders/molecules/orbitals.py b/emmet-builders/emmet/builders/molecules/orbitals.py index 91fd0251ed..af4ce82fe5 100644 --- a/emmet-builders/emmet/builders/molecules/orbitals.py +++ b/emmet-builders/emmet/builders/molecules/orbitals.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from collections import defaultdict from datetime import datetime from itertools import chain diff --git a/emmet-builders/emmet/builders/molecules/redox.py b/emmet-builders/emmet/builders/molecules/redox.py index 02ae1e5ac1..1c655a89ce 100644 --- a/emmet-builders/emmet/builders/molecules/redox.py +++ b/emmet-builders/emmet/builders/molecules/redox.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import copy from collections import defaultdict from datetime import datetime diff --git a/emmet-builders/emmet/builders/molecules/summary.py b/emmet-builders/emmet/builders/molecules/summary.py index 840f2e8d96..ec14009026 100644 --- a/emmet-builders/emmet/builders/molecules/summary.py +++ b/emmet-builders/emmet/builders/molecules/summary.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from datetime import datetime from itertools import chain from math import ceil diff --git a/emmet-builders/emmet/builders/molecules/thermo.py b/emmet-builders/emmet/builders/molecules/thermo.py index b55df2d698..0a410c4cb5 100644 --- a/emmet-builders/emmet/builders/molecules/thermo.py +++ b/emmet-builders/emmet/builders/molecules/thermo.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from collections import defaultdict from datetime import datetime from itertools import chain diff --git a/emmet-builders/emmet/builders/molecules/trajectory.py b/emmet-builders/emmet/builders/molecules/trajectory.py index cf44a98e11..69cf1f4bfa 100644 --- a/emmet-builders/emmet/builders/molecules/trajectory.py +++ b/emmet-builders/emmet/builders/molecules/trajectory.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from collections import defaultdict from datetime import datetime from itertools import chain diff --git a/emmet-builders/emmet/builders/molecules/vibration.py b/emmet-builders/emmet/builders/molecules/vibration.py index 89054c2cb0..143168f082 100644 --- a/emmet-builders/emmet/builders/molecules/vibration.py +++ b/emmet-builders/emmet/builders/molecules/vibration.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from collections import defaultdict from datetime import datetime from itertools import chain diff --git a/emmet-builders/emmet/builders/qchem/molecules.py b/emmet-builders/emmet/builders/qchem/molecules.py index c749c2ab87..ec4e056c31 100644 --- a/emmet-builders/emmet/builders/qchem/molecules.py +++ b/emmet-builders/emmet/builders/qchem/molecules.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from datetime import datetime from itertools import chain, groupby from math import ceil diff --git a/emmet-builders/emmet/builders/vasp/materials.py b/emmet-builders/emmet/builders/vasp/materials.py index 9da37b74d2..9d918b6044 100644 --- a/emmet-builders/emmet/builders/vasp/materials.py +++ b/emmet-builders/emmet/builders/vasp/materials.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from datetime import datetime from itertools import chain from math import ceil diff --git a/emmet-core/emmet/core/molecules/bonds.py b/emmet-core/emmet/core/molecules/bonds.py index 2ed137191d..04ced0f93f 100644 --- a/emmet-core/emmet/core/molecules/bonds.py +++ b/emmet-core/emmet/core/molecules/bonds.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import copy from hashlib import blake2b from typing import TYPE_CHECKING diff --git a/emmet-core/emmet/core/molecules/redox.py b/emmet-core/emmet/core/molecules/redox.py index 0eed6b7d77..8619177669 100644 --- a/emmet-core/emmet/core/molecules/redox.py +++ b/emmet-core/emmet/core/molecules/redox.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from hashlib import blake2b from typing import TYPE_CHECKING diff --git a/emmet-core/emmet/core/molecules/summary.py b/emmet-core/emmet/core/molecules/summary.py index 674de76c9e..af69d88763 100644 --- a/emmet-core/emmet/core/molecules/summary.py +++ b/emmet-core/emmet/core/molecules/summary.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from enum import Enum from hashlib import blake2b from typing import TYPE_CHECKING diff --git a/emmet-core/emmet/core/qc_tasks.py b/emmet-core/emmet/core/qc_tasks.py index 125a0f9ca1..13497e89bc 100644 --- a/emmet-core/emmet/core/qc_tasks.py +++ b/emmet-core/emmet/core/qc_tasks.py @@ -1,6 +1,7 @@ """Core definition of a Q-Chem Task Document""" # mypy: ignore-errors +from __future__ import annotations import logging import re diff --git a/emmet-core/emmet/core/qchem/calc_types/utils.py b/emmet-core/emmet/core/qchem/calc_types/utils.py index aac1270ad4..132111db3a 100644 --- a/emmet-core/emmet/core/qchem/calc_types/utils.py +++ b/emmet-core/emmet/core/qchem/calc_types/utils.py @@ -1,5 +1,7 @@ """Utilities to determine level of theory, task type, and calculation type for Q-Chem calculations""" +from __future__ import annotations + from typing import TYPE_CHECKING from emmet.core.qchem.calc_types import CalcType, LevelOfTheory, TaskType diff --git a/emmet-core/emmet/core/qchem/task.py b/emmet-core/emmet/core/qchem/task.py index 67ad4e8a70..2ebc1da8a2 100644 --- a/emmet-core/emmet/core/qchem/task.py +++ b/emmet-core/emmet/core/qchem/task.py @@ -1,6 +1,7 @@ """Core definition of a Q-Chem Task Document""" # mypy: ignore-errors +from __future__ import annotations from typing import Any, TYPE_CHECKING diff --git a/emmet-core/emmet/core/structure_group.py b/emmet-core/emmet/core/structure_group.py index 5829ecacf2..cffbdcbc04 100644 --- a/emmet-core/emmet/core/structure_group.py +++ b/emmet-core/emmet/core/structure_group.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import logging import operator from datetime import datetime diff --git a/emmet-core/emmet/core/summary.py b/emmet-core/emmet/core/summary.py index 02864868a2..74204a94f8 100644 --- a/emmet-core/emmet/core/summary.py +++ b/emmet-core/emmet/core/summary.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from enum import Enum from typing import TYPE_CHECKING From ad61eb7354c8d20d9d209498b53ee8b59e93990a Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Fri, 20 Jun 2025 17:58:50 -0700 Subject: [PATCH 5/9] add structure top level field to polar docs --- emmet-core/emmet/core/polar.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/emmet-core/emmet/core/polar.py b/emmet-core/emmet/core/polar.py index a8e849c3f6..e4571fb26b 100644 --- a/emmet-core/emmet/core/polar.py +++ b/emmet-core/emmet/core/polar.py @@ -40,6 +40,10 @@ class DielectricDoc(PropertyDoc): n: float = Field(description="Refractive index.") + structure: Structure | None = Field( + None, description="The structure associated with this calculation." + ) + @classmethod def from_ionic_and_electronic( cls, @@ -93,6 +97,10 @@ class PiezoelectricDoc(PropertyDoc): description="Normalized strain direction for maximum piezo repsonse" ) + structure: Structure | None = Field( + None, description="The structure associated with this calculation." + ) + @classmethod def from_ionic_and_electronic( cls, From a10320ee209668d4101c2212fd54aca789ecb61b Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Tue, 24 Jun 2025 10:51:33 -0700 Subject: [PATCH 6/9] make structure an optional top-level in property doc, but exclude from json schema and model dump by default --- emmet-core/emmet/core/bonds.py | 14 ++++----- emmet-core/emmet/core/chemenv.py | 10 +++---- emmet-core/emmet/core/elasticity.py | 8 ++--- emmet-core/emmet/core/material_property.py | 34 ++++++++++++++++------ emmet-core/emmet/core/oxidation_states.py | 16 +++++----- emmet-core/emmet/core/polar.py | 10 ++----- emmet-core/emmet/core/summary.py | 11 +++---- 7 files changed, 55 insertions(+), 48 deletions(-) diff --git a/emmet-core/emmet/core/bonds.py b/emmet-core/emmet/core/bonds.py index 348f411c76..f43674b756 100644 --- a/emmet-core/emmet/core/bonds.py +++ b/emmet-core/emmet/core/bonds.py @@ -1,4 +1,3 @@ -import logging from typing import Any import numpy as np @@ -48,7 +47,7 @@ def from_structure( "CrystalNN", "MinimumDistanceNN", ), - **kwargs + **kwargs, ): """ Calculate @@ -67,6 +66,8 @@ def from_structure( for method in preferred_methods ] + warnings: list[str] = [] + for method in preferred_methods: try: sg = StructureGraph.from_local_env_strategy(structure, method) @@ -94,16 +95,15 @@ def from_structure( break except Exception as e: - logging.warning( - "Failed to calculate bonding: {} {} {}".format( - material_id, method, e - ) + warnings.append( + f"Failed to calculate bonding: {material_id} {method} {e}" ) if bonding_info: return super().from_structure( meta_structure=structure, material_id=material_id, + warnings=warnings, **bonding_info, - **kwargs + **kwargs, ) diff --git a/emmet-core/emmet/core/chemenv.py b/emmet-core/emmet/core/chemenv.py index f0c5a9af5f..b53a955c75 100644 --- a/emmet-core/emmet/core/chemenv.py +++ b/emmet-core/emmet/core/chemenv.py @@ -316,11 +316,6 @@ class ChemEnvDoc(PropertyDoc): property_name: str = "coord_environment" - structure: Structure = Field( - ..., - description="The structure used in the generation of the chemical environment data", - ) - valences: list[int | float] = Field( description="List of valences for each site in this material to determine cations" ) @@ -372,6 +367,10 @@ class ChemEnvDoc(PropertyDoc): warnings: str | None = Field(None, description="Warning") + structure: Structure | None = Field( + None, description="The structure associated with this property.", exclude=True + ) + @classmethod def from_structure( cls, @@ -527,7 +526,6 @@ def from_structure( return super().from_structure( meta_structure=structure, material_id=material_id, - structure=structure, **d, **kwargs, ) diff --git a/emmet-core/emmet/core/elasticity.py b/emmet-core/emmet/core/elasticity.py index df6778f57b..19ce12ae9a 100644 --- a/emmet-core/emmet/core/elasticity.py +++ b/emmet-core/emmet/core/elasticity.py @@ -168,10 +168,6 @@ class WarningMessage(BaseModel): class ElasticityDoc(PropertyDoc): property_name: str = "elasticity" - structure: Structure | None = Field( - None, description="Structure to compute the elasticity" - ) - order: int = Field( default=2, description="Order of the expansion of the elastic tensor" ) @@ -215,6 +211,10 @@ class ElasticityDoc(PropertyDoc): description="State of the fitting/analysis: `successful` or `failed`", ) + structure: Structure | None = Field( + None, description="Structure used to compute the elasticity.", exclude=False + ) + @classmethod def from_deformations_and_stresses( cls, diff --git a/emmet-core/emmet/core/material_property.py b/emmet-core/emmet/core/material_property.py index 18a6700702..d55652180f 100644 --- a/emmet-core/emmet/core/material_property.py +++ b/emmet-core/emmet/core/material_property.py @@ -6,7 +6,8 @@ from datetime import datetime from typing import TYPE_CHECKING -from pydantic import Field, field_validator +from pydantic import Field, model_validator +from pydantic.json_schema import SkipJsonSchema from pymatgen.core import Structure from emmet.core.common import convert_datetime @@ -17,14 +18,17 @@ from emmet.core.vasp.validation import DeprecationMessage if TYPE_CHECKING: + from typing import Any from typing_extensions import Self class PropertyDoc(StructureMetadata): """ - Base model definition for any singular materials property. This may contain any amount - of structure metadata for the purpose of search - This is intended to be inherited and extended not used directly + Base model definition for any singular materials property. + + This may contain any amount of structure metadata for the + purpose of search. This is intended to be inherited and + extended, not used directly """ property_name: str @@ -57,10 +61,16 @@ class PropertyDoc(StructureMetadata): [], description="Any warnings related to this property." ) - @field_validator("last_updated", mode="before") + structure: SkipJsonSchema[Structure | None] = Field( + None, description="The structure associated with this property.", exclude=True + ) + + @model_validator(mode="before") @classmethod - def handle_datetime(cls, v): - return convert_datetime(cls, v) + def handle_datetime(cls, config: Any) -> Any: + if dt := config.get("last_updated"): + config["last_updated"] = convert_datetime(cls, dt) + return config @classmethod def from_structure( # type: ignore[override] @@ -70,9 +80,15 @@ def from_structure( # type: ignore[override] **kwargs, ) -> Self: """ - Builds a materials document using the minimal amount of information + Builds a materials document using a minimal amount of information. + + Note that structure is stored as a private attr, and will not + be included in `PropertyDoc().model_dump()` """ return super().from_structure( - meta_structure=meta_structure, material_id=material_id, **kwargs + meta_structure=meta_structure, + structure=meta_structure, + material_id=material_id, + **kwargs, ) # type: ignore diff --git a/emmet-core/emmet/core/oxidation_states.py b/emmet-core/emmet/core/oxidation_states.py index 46200a698f..bc992a71c3 100644 --- a/emmet-core/emmet/core/oxidation_states.py +++ b/emmet-core/emmet/core/oxidation_states.py @@ -16,10 +16,6 @@ class OxidationStateDoc(PropertyDoc): property_name: str = "oxidation" - structure: Structure = Field( - ..., - description="The structure used in the generation of the oxidation state data.", - ) possible_species: list[str] = Field( description="Possible charged species in this material." ) @@ -33,6 +29,12 @@ class OxidationStateDoc(PropertyDoc): None, description="Method used to compute oxidation states." ) + structure: Structure | None = Field( + None, + description="The structure used in the generation of the oxidation state data.", + exclude=False, + ) + @classmethod def from_structure(cls, structure: Structure, material_id: MPID | None = None, **kwargs): # type: ignore[override] # TODO: add check for if it already has oxidation states, if so pass this along unchanged ("method": "manual") @@ -105,9 +107,5 @@ def from_structure(cls, structure: Structure, material_id: MPID | None = None, * d["state"] = "unsuccessful" return super().from_structure( - meta_structure=structure, - material_id=material_id, - structure=structure, - **d, - **kwargs + meta_structure=structure, material_id=material_id, **d, **kwargs ) diff --git a/emmet-core/emmet/core/polar.py b/emmet-core/emmet/core/polar.py index e4571fb26b..eef704ff0f 100644 --- a/emmet-core/emmet/core/polar.py +++ b/emmet-core/emmet/core/polar.py @@ -1,5 +1,7 @@ """Core definition for Polar property Document""" +from __future__ import annotations + import numpy as np from pydantic import BaseModel, Field from pymatgen.analysis.piezo import PiezoTensor as BasePiezoTensor @@ -40,10 +42,6 @@ class DielectricDoc(PropertyDoc): n: float = Field(description="Refractive index.") - structure: Structure | None = Field( - None, description="The structure associated with this calculation." - ) - @classmethod def from_ionic_and_electronic( cls, @@ -97,10 +95,6 @@ class PiezoelectricDoc(PropertyDoc): description="Normalized strain direction for maximum piezo repsonse" ) - structure: Structure | None = Field( - None, description="The structure associated with this calculation." - ) - @classmethod def from_ionic_and_electronic( cls, diff --git a/emmet-core/emmet/core/summary.py b/emmet-core/emmet/core/summary.py index 74204a94f8..64a5063655 100644 --- a/emmet-core/emmet/core/summary.py +++ b/emmet-core/emmet/core/summary.py @@ -147,11 +147,6 @@ class SummaryDoc(PropertyDoc): # Materials - structure: Structure = Field( - ..., - description="The lowest energy structure for this material.", - ) - task_ids: list[MPID] = Field( [], title="Calculation IDs", @@ -425,6 +420,12 @@ class SummaryDoc(PropertyDoc): {}, description="External database IDs corresponding to this material." ) + structure: Structure | None = Field( + None, + description="The lowest energy structure for this material.", + exclude=False, + ) + @classmethod def from_docs( cls, material_id: MPID | None = None, **docs: dict[str, dict] From 1edb39f769424dc092fa07c257734ee8977952fe Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Tue, 24 Jun 2025 14:45:00 -0700 Subject: [PATCH 7/9] class instantiation fixes, mypy checks for bonding --- emmet-core/emmet/core/bonds.py | 25 ++++++++++++++++------ emmet-core/emmet/core/chemenv.py | 1 - emmet-core/emmet/core/common.py | 1 + emmet-core/emmet/core/elasticity.py | 1 - emmet-core/emmet/core/material_property.py | 10 ++++----- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/emmet-core/emmet/core/bonds.py b/emmet-core/emmet/core/bonds.py index f43674b756..c281d8f8e1 100644 --- a/emmet-core/emmet/core/bonds.py +++ b/emmet-core/emmet/core/bonds.py @@ -1,4 +1,6 @@ -from typing import Any +from __future__ import annotations + +from typing import Any, TYPE_CHECKING import numpy as np from pydantic import Field @@ -9,6 +11,14 @@ AVAILABLE_METHODS = {nn.__name__: nn for nn in NearNeighbors.__subclasses__()} +if TYPE_CHECKING: + + from typing_extensions import Self + + from pymatgen.core import Structure + + from emmet.core.mpid import MPID + class BondingDoc(PropertyDoc): """Structure graphs representing chemical bonds calculated from structure @@ -41,14 +51,14 @@ class BondingDoc(PropertyDoc): @classmethod def from_structure( cls, - structure, - material_id, - preferred_methods=( + structure: Structure, + material_id: str | MPID, + preferred_methods: tuple[str | NearNeighbors, ...] = ( "CrystalNN", "MinimumDistanceNN", ), **kwargs, - ): + ) -> Self | None: """ Calculate @@ -61,14 +71,14 @@ def from_structure( """ bonding_info = None - preferred_methods = [ # type: ignore + bond_analysis_methods: list[NearNeighbors] = [ AVAILABLE_METHODS[method]() if isinstance(method, str) else method for method in preferred_methods ] warnings: list[str] = [] - for method in preferred_methods: + for method in bond_analysis_methods: try: sg = StructureGraph.from_local_env_strategy(structure, method) @@ -107,3 +117,4 @@ def from_structure( **bonding_info, **kwargs, ) + return None diff --git a/emmet-core/emmet/core/chemenv.py b/emmet-core/emmet/core/chemenv.py index b53a955c75..53ea9837f4 100644 --- a/emmet-core/emmet/core/chemenv.py +++ b/emmet-core/emmet/core/chemenv.py @@ -462,7 +462,6 @@ def from_structure( return super().from_structure( meta_structure=structure, material_id=material_id, - structure=structure, **d, **kwargs, ) diff --git a/emmet-core/emmet/core/common.py b/emmet-core/emmet/core/common.py index de38324945..f073008537 100644 --- a/emmet-core/emmet/core/common.py +++ b/emmet-core/emmet/core/common.py @@ -23,6 +23,7 @@ def convert_datetime(cls, v): return dt v = MontyDecoder().process_decoded(v) + print(v) if not v.tzinfo: v = v.replace(tzinfo=timezone.utc) return v diff --git a/emmet-core/emmet/core/elasticity.py b/emmet-core/emmet/core/elasticity.py index 19ce12ae9a..fd470002c3 100644 --- a/emmet-core/emmet/core/elasticity.py +++ b/emmet-core/emmet/core/elasticity.py @@ -356,7 +356,6 @@ def from_deformations_and_stresses( return cls.from_structure( structure, material_id, - structure=structure, order=2, elastic_tensor=et_doc, compliance_tensor=ct_doc, diff --git a/emmet-core/emmet/core/material_property.py b/emmet-core/emmet/core/material_property.py index d55652180f..29ea8c169f 100644 --- a/emmet-core/emmet/core/material_property.py +++ b/emmet-core/emmet/core/material_property.py @@ -6,7 +6,7 @@ from datetime import datetime from typing import TYPE_CHECKING -from pydantic import Field, model_validator +from pydantic import Field, field_validator from pydantic.json_schema import SkipJsonSchema from pymatgen.core import Structure @@ -65,12 +65,10 @@ class PropertyDoc(StructureMetadata): None, description="The structure associated with this property.", exclude=True ) - @model_validator(mode="before") + @field_validator("last_updated", mode="before") @classmethod - def handle_datetime(cls, config: Any) -> Any: - if dt := config.get("last_updated"): - config["last_updated"] = convert_datetime(cls, dt) - return config + def handle_datetime(cls, v: Any) -> datetime: + return convert_datetime(v) @classmethod def from_structure( # type: ignore[override] From a1a0249fc72ee3e60f9565ef99fe877d5f6bf8c4 Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Wed, 25 Jun 2025 10:40:55 -0700 Subject: [PATCH 8/9] fix convert datetime --- emmet-core/emmet/core/material_property.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emmet-core/emmet/core/material_property.py b/emmet-core/emmet/core/material_property.py index 29ea8c169f..ea2ab68d4e 100644 --- a/emmet-core/emmet/core/material_property.py +++ b/emmet-core/emmet/core/material_property.py @@ -68,7 +68,7 @@ class PropertyDoc(StructureMetadata): @field_validator("last_updated", mode="before") @classmethod def handle_datetime(cls, v: Any) -> datetime: - return convert_datetime(v) + return convert_datetime(cls, v) @classmethod def from_structure( # type: ignore[override] From d32b92f665a4dce19e725c06bbf5593cd5fe2f37 Mon Sep 17 00:00:00 2001 From: esoteric-ephemera Date: Fri, 27 Jun 2025 13:34:55 -0700 Subject: [PATCH 9/9] remove extraneous print statements --- emmet-core/emmet/core/common.py | 1 - emmet-core/emmet/core/qchem/calculation.py | 2 +- emmet-core/emmet/core/xrd.py | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/emmet-core/emmet/core/common.py b/emmet-core/emmet/core/common.py index f073008537..de38324945 100644 --- a/emmet-core/emmet/core/common.py +++ b/emmet-core/emmet/core/common.py @@ -23,7 +23,6 @@ def convert_datetime(cls, v): return dt v = MontyDecoder().process_decoded(v) - print(v) if not v.tzinfo: v = v.replace(tzinfo=timezone.utc) return v diff --git a/emmet-core/emmet/core/qchem/calculation.py b/emmet-core/emmet/core/qchem/calculation.py index 94203efdbb..966752e18f 100644 --- a/emmet-core/emmet/core/qchem/calculation.py +++ b/emmet-core/emmet/core/qchem/calculation.py @@ -391,7 +391,7 @@ def from_qchem_files( ) if store_energy_trajectory: - print("Still have to figure the energy trajectory") + warnings.warn("Still have to figure the energy trajectory") return cls( dir_name=str(dir_name), diff --git a/emmet-core/emmet/core/xrd.py b/emmet-core/emmet/core/xrd.py index 15f93f7c1b..9558e475de 100644 --- a/emmet-core/emmet/core/xrd.py +++ b/emmet-core/emmet/core/xrd.py @@ -43,7 +43,6 @@ class XRDDoc(SpectrumDoc): @model_validator(mode="before") @classmethod def get_target_and_edge(cls, values: dict): - print("Validations") # Only do this if neither target not edge is defined if "target" not in values and "edge" not in values: try: