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/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..62d7fc0d83 100644 --- a/emmet-builders/emmet/builders/materials/absorption_spectrum.py +++ b/emmet-builders/emmet/builders/materials/absorption_spectrum.py @@ -1,5 +1,5 @@ +from __future__ import annotations from math import ceil -from typing import Iterator import numpy as np from maggma.builders import Builder @@ -10,6 +10,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..535440fd5a 100644 --- a/emmet-builders/emmet/builders/materials/corrected_entries.py +++ b/emmet-builders/emmet/builders/materials/corrected_entries.py @@ -1,10 +1,11 @@ +from __future__ import annotations + import copy import warnings from collections import defaultdict 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 +17,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..e0a0a6b005 100644 --- a/emmet-builders/emmet/builders/materials/dielectric.py +++ b/emmet-builders/emmet/builders/materials/dielectric.py @@ -1,5 +1,6 @@ +from __future__ import annotations + from math import ceil -from typing import Iterator import numpy as np from maggma.builders import Builder @@ -10,6 +11,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..5aebff2e07 100644 --- a/emmet-builders/emmet/builders/materials/elasticity.py +++ b/emmet-builders/emmet/builders/materials/elasticity.py @@ -17,8 +17,9 @@ 7. Fit the elastic tensor. """ +from __future__ import annotations + from datetime import datetime -from typing import Any, Generator import numpy as np from maggma.core import Builder, Store @@ -33,6 +34,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..065da63550 100644 --- a/emmet-builders/emmet/builders/materials/magnetism.py +++ b/emmet-builders/emmet/builders/materials/magnetism.py @@ -1,5 +1,6 @@ +from __future__ import annotations + from math import ceil -from typing import Iterator from maggma.builders import Builder from maggma.stores import Store @@ -9,6 +10,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..e2c302066b 100644 --- a/emmet-builders/emmet/builders/materials/thermo.py +++ b/emmet-builders/emmet/builders/materials/thermo.py @@ -1,8 +1,9 @@ +from __future__ import annotations + import warnings 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 +16,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 +55,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..251693e0b2 100644 --- a/emmet-builders/emmet/builders/molecules/atomic.py +++ b/emmet-builders/emmet/builders/molecules/atomic.py @@ -1,8 +1,9 @@ +from __future__ import annotations + from collections import defaultdict 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 +20,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..02027bbeee 100644 --- a/emmet-builders/emmet/builders/molecules/bonds.py +++ b/emmet-builders/emmet/builders/molecules/bonds.py @@ -1,8 +1,9 @@ +from __future__ import annotations + from collections import defaultdict 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 +15,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..d4bc7092ad 100644 --- a/emmet-builders/emmet/builders/molecules/electric.py +++ b/emmet-builders/emmet/builders/molecules/electric.py @@ -1,8 +1,9 @@ +from __future__ import annotations + from collections import defaultdict 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 +15,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..18049e4f4c 100644 --- a/emmet-builders/emmet/builders/molecules/metal_binding.py +++ b/emmet-builders/emmet/builders/molecules/metal_binding.py @@ -1,8 +1,10 @@ +from __future__ import annotations + import copy 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 +20,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..af4ce82fe5 100644 --- a/emmet-builders/emmet/builders/molecules/orbitals.py +++ b/emmet-builders/emmet/builders/molecules/orbitals.py @@ -1,8 +1,10 @@ +from __future__ import annotations + from collections import defaultdict 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 +16,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..1c655a89ce 100644 --- a/emmet-builders/emmet/builders/molecules/redox.py +++ b/emmet-builders/emmet/builders/molecules/redox.py @@ -1,9 +1,10 @@ +from __future__ import annotations + import copy from collections import defaultdict 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 +18,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..ec14009026 100644 --- a/emmet-builders/emmet/builders/molecules/summary.py +++ b/emmet-builders/emmet/builders/molecules/summary.py @@ -1,7 +1,8 @@ +from __future__ import annotations + 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 +12,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..0a410c4cb5 100644 --- a/emmet-builders/emmet/builders/molecules/thermo.py +++ b/emmet-builders/emmet/builders/molecules/thermo.py @@ -1,8 +1,9 @@ +from __future__ import annotations + from collections import defaultdict 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 +18,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..69cf1f4bfa 100644 --- a/emmet-builders/emmet/builders/molecules/trajectory.py +++ b/emmet-builders/emmet/builders/molecules/trajectory.py @@ -1,8 +1,9 @@ +from __future__ import annotations + from collections import defaultdict 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 +15,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..143168f082 100644 --- a/emmet-builders/emmet/builders/molecules/vibration.py +++ b/emmet-builders/emmet/builders/molecules/vibration.py @@ -1,8 +1,10 @@ +from __future__ import annotations + from collections import defaultdict 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 +16,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..ec4e056c31 100644 --- a/emmet-builders/emmet/builders/qchem/molecules.py +++ b/emmet-builders/emmet/builders/qchem/molecules.py @@ -1,7 +1,8 @@ +from __future__ import annotations + 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 +20,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 +561,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..9d918b6044 100644 --- a/emmet-builders/emmet/builders/vasp/materials.py +++ b/emmet-builders/emmet/builders/vasp/materials.py @@ -1,7 +1,8 @@ +from __future__ import annotations + 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 +14,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/bonds.py b/emmet-core/emmet/core/bonds.py index 348f411c76..c281d8f8e1 100644 --- a/emmet-core/emmet/core/bonds.py +++ b/emmet-core/emmet/core/bonds.py @@ -1,5 +1,6 @@ -import logging -from typing import Any +from __future__ import annotations + +from typing import Any, TYPE_CHECKING import numpy as np from pydantic import Field @@ -10,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 @@ -42,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 - ): + **kwargs, + ) -> Self | None: """ Calculate @@ -62,12 +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 ] - for method in preferred_methods: + warnings: list[str] = [] + + for method in bond_analysis_methods: try: sg = StructureGraph.from_local_env_strategy(structure, method) @@ -94,16 +105,16 @@ 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, ) + return None diff --git a/emmet-core/emmet/core/chemenv.py b/emmet-core/emmet/core/chemenv.py index f0c5a9af5f..53ea9837f4 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, @@ -463,7 +462,6 @@ def from_structure( return super().from_structure( meta_structure=structure, material_id=material_id, - structure=structure, **d, **kwargs, ) @@ -527,7 +525,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..fd470002c3 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, @@ -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/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..ea2ab68d4e 100644 --- a/emmet-core/emmet/core/material_property.py +++ b/emmet-core/emmet/core/material_property.py @@ -2,10 +2,12 @@ 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 pydantic.json_schema import SkipJsonSchema from pymatgen.core import Structure from emmet.core.common import convert_datetime @@ -15,14 +17,18 @@ from emmet.core.utils import utcnow from emmet.core.vasp.validation import DeprecationMessage -S = TypeVar("S", bound="PropertyDoc") +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 @@ -55,22 +61,32 @@ class PropertyDoc(StructureMetadata): [], description="Any warnings related to this property." ) + structure: SkipJsonSchema[Structure | None] = Field( + None, description="The structure associated with this property.", exclude=True + ) + @field_validator("last_updated", mode="before") @classmethod - def handle_datetime(cls, v): + def handle_datetime(cls, v: Any) -> datetime: return convert_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 + 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/molecules/bonds.py b/emmet-core/emmet/core/molecules/bonds.py index 06ddeb390d..b41fc58104 100644 --- a/emmet-core/emmet/core/molecules/bonds.py +++ b/emmet-core/emmet/core/molecules/bonds.py @@ -1,6 +1,8 @@ +from __future__ import annotations + 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 +15,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..8619177669 100644 --- a/emmet-core/emmet/core/molecules/redox.py +++ b/emmet-core/emmet/core/molecules/redox.py @@ -1,5 +1,7 @@ +from __future__ import annotations + from hashlib import blake2b -from typing import Any, Type, TypeVar +from typing import TYPE_CHECKING from pydantic import Field @@ -10,15 +12,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 +96,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 +119,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..af69d88763 100644 --- a/emmet-core/emmet/core/molecules/summary.py +++ b/emmet-core/emmet/core/molecules/summary.py @@ -1,6 +1,8 @@ +from __future__ import annotations + 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 +12,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 +480,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/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 a8e849c3f6..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 diff --git a/emmet-core/emmet/core/qc_tasks.py b/emmet-core/emmet/core/qc_tasks.py index e9db29d84c..13497e89bc 100644 --- a/emmet-core/emmet/core/qc_tasks.py +++ b/emmet-core/emmet/core/qc_tasks.py @@ -1,11 +1,13 @@ +"""Core definition of a Q-Chem Task Document""" + # mypy: ignore-errors +from __future__ import annotations -"""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 +20,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 +287,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..132111db3a 100644 --- a/emmet-core/emmet/core/qchem/calc_types/utils.py +++ b/emmet-core/emmet/core/qchem/calc_types/utils.py @@ -1,10 +1,15 @@ """Utilities to determine level of theory, task type, and calculation type for Q-Chem calculations""" -from typing import Any +from __future__ import annotations + +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/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/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..2ebc1da8a2 100644 --- a/emmet-core/emmet/core/qchem/task.py +++ b/emmet-core/emmet/core/qchem/task.py @@ -1,7 +1,9 @@ +"""Core definition of a Q-Chem Task Document""" + # mypy: ignore-errors +from __future__ import annotations -"""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 +22,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..cffbdcbc04 100644 --- a/emmet-core/emmet/core/structure_group.py +++ b/emmet-core/emmet/core/structure_group.py @@ -1,8 +1,10 @@ +from __future__ import annotations + import logging 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 +16,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..64a5063655 100644 --- a/emmet-core/emmet/core/summary.py +++ b/emmet-core/emmet/core/summary.py @@ -1,5 +1,7 @@ +from __future__ import annotations + 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 +13,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): @@ -144,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", @@ -422,8 +420,16 @@ 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]): + 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/tasks.py b/emmet-core/emmet/core/tasks.py index f3955cb045..f78ec671bb 100644 --- a/emmet-core/emmet/core/tasks.py +++ b/emmet-core/emmet/core/tasks.py @@ -1150,8 +1150,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] = {} @@ -1160,11 +1159,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/utils.py b/emmet-core/emmet/core/utils.py index 93948cae0d..d06f59af48 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/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/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 diff --git a/emmet-core/emmet/core/vasp/utils.py b/emmet-core/emmet/core/vasp/utils.py index e4ca72c2a3..5afb41e0a2 100644 --- a/emmet-core/emmet/core/vasp/utils.py +++ b/emmet-core/emmet/core/vasp/utils.py @@ -177,11 +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", - ): + for k in ("vasprun", "contcar", "outcar", "oszicar"): if k in f: by_type[f"{k}_file"].append(_f) break 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: