Skip to content

Commit ffb8fbc

Browse files
resolve merge conf
2 parents 17d66f0 + 2478637 commit ffb8fbc

52 files changed

Lines changed: 1075 additions & 495 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# The Materials Project API
22

3-
[![testing](https://github.com/materialsproject/api/workflows/testing/badge.svg)](https://github.com/materialsproject/api/actions?query=workflow%3Atesting)
3+
[![testing](https://github.com/materialsproject/api/actions/workflows/testing.yml/badge.svg?branch=main)](https://github.com/materialsproject/api/actions?query=workflow%3Atesting+branch%3Amain)
44
[![codecov](https://codecov.io/gh/materialsproject/api/branch/main/graph/badge.svg)](https://codecov.io/gh/materialsproject/api)
5-
![python](https://img.shields.io/badge/Python-3.9+-blue.svg?logo=python&logoColor=white)
5+
![python](https://img.shields.io/badge/Python-3.11+-blue.svg?logo=python&logoColor=white)
66

77
This repository is the development environment for the new Materials Project API. A core client implementation will reside here. For information on how to use the API, please see the updated [documentation](https://docs.materialsproject.org/downloading-data/how-do-i-download-the-materials-project-database).

mp_api/client/core/utils.py

Lines changed: 11 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
from __future__ import annotations
22

33
import os
4-
import re
54
from typing import TYPE_CHECKING, Literal
65

76
import orjson
87
from emmet.core import __version__ as _EMMET_CORE_VER
8+
from emmet.core.mpid_ext import validate_identifier
99
from monty.json import MontyDecoder
1010
from packaging.version import parse as parse_version
1111

1212
from mp_api.client.core.settings import MAPIClientSettings
1313

1414
if TYPE_CHECKING:
15-
from monty.json import MSONable
15+
from typing import Any
1616

1717
_MAPI_SETTINGS = MAPIClientSettings()
1818

@@ -26,6 +26,10 @@ def _compare_emmet_ver(
2626
_compare_emmet_ver("0.84.0rc0","<") returns
2727
emmet.core.__version__ < "0.84.0rc0"
2828
29+
This function may not be used anywhere in the client, but it should
30+
be preserved for future use, in case some degree of backwards
31+
compatibility or feature buy-in is needed.
32+
2933
Parameters
3034
-----------
3135
ref_version : str
@@ -39,40 +43,16 @@ def _compare_emmet_ver(
3943
)(parse_version(ref_version))
4044

4145

42-
if _compare_emmet_ver("0.85.0", ">="):
43-
from emmet.core.mpid_ext import validate_identifier
44-
else:
45-
validate_identifier = None
46-
47-
48-
def load_json(json_like: str | bytes, deser: bool = False, encoding: str = "utf-8"):
46+
def load_json(
47+
json_like: str | bytes, deser: bool = False, encoding: str = "utf-8"
48+
) -> Any:
4949
"""Utility to load json in consistent manner."""
5050
data = orjson.loads(
5151
json_like if isinstance(json_like, bytes) else json_like.encode(encoding)
5252
)
5353
return MontyDecoder().process_decoded(data) if deser else data
5454

5555

56-
def _legacy_id_validation(id_list: list[str]) -> list[str]:
57-
"""Legacy utility to validate IDs, pre-AlphaID transition.
58-
59-
This function is temporarily maintained to allow for
60-
backwards compatibility with older versions of emmet, and will
61-
not be preserved.
62-
"""
63-
pattern = "(mp|mvc|mol|mpcule)-.*"
64-
if malformed_ids := {
65-
entry for entry in id_list if re.match(pattern, entry) is None
66-
}:
67-
raise ValueError(
68-
f"{'Entry' if len(malformed_ids) == 1 else 'Entries'}"
69-
f" {', '.join(malformed_ids)}"
70-
f"{'is' if len(malformed_ids) == 1 else 'are'} not formatted correctly!"
71-
)
72-
73-
return id_list
74-
75-
7656
def validate_api_key(api_key: str | None = None) -> str:
7757
"""Utility to find and pre-check validity of an API key."""
7858
# SETTINGS tries to read API key from ~/.config/.pmgrc.yaml
@@ -92,7 +72,7 @@ def validate_api_key(api_key: str | None = None) -> str:
9272
return api_key
9373

9474

95-
def validate_ids(id_list: list[str]):
75+
def validate_ids(id_list: list[str]) -> list[str]:
9676
"""Function to validate material and task IDs.
9777
9878
Args:
@@ -113,36 +93,4 @@ def validate_ids(id_list: list[str]):
11393
# TODO: after the transition to AlphaID in the document models,
11494
# The following line should be changed to
11595
# return [validate_identifier(idx,serialize=True) for idx in id_list]
116-
if validate_identifier:
117-
return [str(validate_identifier(idx)) for idx in id_list]
118-
return _legacy_id_validation(id_list)
119-
120-
121-
def allow_msonable_dict(monty_cls: type[MSONable]):
122-
"""Patch Monty to allow for dict values for MSONable."""
123-
124-
def validate_monty(cls, v, _):
125-
"""Stub validator for MSONable as a dictionary only."""
126-
if isinstance(v, cls):
127-
return v
128-
elif isinstance(v, dict):
129-
# Just validate the simple Monty Dict Model
130-
errors = []
131-
if v.get("@module", "") != monty_cls.__module__:
132-
errors.append("@module")
133-
134-
if v.get("@class", "") != monty_cls.__name__:
135-
errors.append("@class")
136-
137-
if len(errors) > 0:
138-
raise ValueError(
139-
"Missing Monty seriailzation fields in dictionary: {errors}"
140-
)
141-
142-
return v
143-
else:
144-
raise ValueError(f"Must provide {cls.__name__} or MSONable dictionary")
145-
146-
monty_cls.validate_monty_v2 = classmethod(validate_monty)
147-
148-
return monty_cls
96+
return [str(validate_identifier(idx)) for idx in id_list]

mp_api/client/mprester.py

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from emmet.core.mpid import MPID, AlphaID
1212
from emmet.core.settings import EmmetSettings
1313
from emmet.core.tasks import TaskDoc
14+
from emmet.core.types.enums import ThermoType
1415
from emmet.core.vasp.calc_types import CalcType
1516
from packaging import version
1617
from pymatgen.analysis.phase_diagram import PhaseDiagram
@@ -25,12 +26,7 @@
2526
from mp_api.client.core import BaseRester, MPRestError
2627
from mp_api.client.core._oxygen_evolution import OxygenEvolution
2728
from mp_api.client.core.settings import MAPIClientSettings
28-
from mp_api.client.core.utils import (
29-
_compare_emmet_ver,
30-
load_json,
31-
validate_api_key,
32-
validate_ids,
33-
)
29+
from mp_api.client.core.utils import load_json, validate_api_key, validate_ids
3430
from mp_api.client.routes import GeneralStoreRester, MessagesRester, UserSettingsRester
3531
from mp_api.client.routes.materials import (
3632
AbsorptionRester,
@@ -65,11 +61,6 @@
6561
from mp_api.client.routes.materials.materials import MaterialsRester
6662
from mp_api.client.routes.molecules import MoleculeRester
6763

68-
if _compare_emmet_ver("0.85.0", ">="):
69-
from emmet.core.types.enums import ThermoType
70-
else:
71-
from emmet.core.thermo import ThermoType
72-
7364
if TYPE_CHECKING:
7465
from typing import Any, Literal
7566

@@ -220,6 +211,9 @@ def __init__(
220211
"chemenv",
221212
]
222213

214+
if not self.endpoint.endswith("/"):
215+
self.endpoint += "/"
216+
223217
# Check if emmet version of server is compatible
224218
emmet_version = MPRester.get_emmet_version(self.endpoint)
225219

@@ -234,9 +228,6 @@ def __init__(
234228
if notify_db_version:
235229
raise NotImplementedError("This has not yet been implemented.")
236230

237-
if not self.endpoint.endswith("/"):
238-
self.endpoint += "/"
239-
240231
# Dynamically set rester attributes.
241232
# First, materials and molecules top level resters are set.
242233
# Nested rested are then setup to be loaded dynamically with custom __getattr__ functions.
@@ -369,8 +360,8 @@ def contribs(self):
369360
self._contribs = None
370361
warnings.warn(
371362
"mpcontribs-client not installed. "
372-
"Install the package to query MPContribs data, or construct pourbaix diagrams: "
373-
"'pip install mpcontribs-client'"
363+
"Install the package to query MPContribs data, construct pourbaix diagrams, "
364+
"or to compute cohesive energies: 'pip install mpcontribs-client'"
374365
)
375366
except Exception as error:
376367
self._contribs = None

mp_api/client/routes/materials/absorption.py

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ class AbsorptionRester(BaseRester):
1616
def search(
1717
self,
1818
material_ids: str | list[str] | None = None,
19-
chemsys: str | list[str] | None = None,
20-
elements: list[str] | None = None,
21-
exclude_elements: list[str] | None = None,
22-
formula: list[str] | None = None,
19+
num_sites: int | tuple[int, int] | None = None,
20+
num_elements: int | tuple[int, int] | None = None,
21+
volume: float | tuple[float, float] | None = None,
22+
density: float | tuple[float, float] | None = None,
23+
band_gap: float | tuple[float, float] | None = None,
2324
num_chunks: int | None = None,
2425
chunk_size: int = 1000,
2526
all_fields: bool = True,
@@ -28,14 +29,26 @@ def search(
2829
"""Query for optical absorption spectra data.
2930
3031
Arguments:
31-
material_ids (str, List[str]): Search for optical absorption data associated with the specified Material IDs
32-
chemsys (str, List[str]): A chemical system or list of chemical systems
33-
(e.g., Li-Fe-O, Si-*, [Si-O, Li-Fe-P]).
34-
elements (List[str]): A list of elements.
35-
exclude_elements (List[str]): A list of elements to exclude.
36-
formula (str, List[str]): A formula including anonymized formula
37-
or wild cards (e.g., Fe2O3, ABO3, Si*). A list of chemical formulas can also be passed
38-
(e.g., [Fe2O3, ABO3]).
32+
material_ids (str, List[str]):
33+
Search for optical absorption data associated with the
34+
specified Material ID(s)
35+
num_sites (int, tuple[int, int]):
36+
Search with a single number or a range of number of sites
37+
in the structure.
38+
num_elements (int, tuple[int, int]):
39+
Search with a single number or a range of number of distinct
40+
elements in the structure.
41+
volume (float, tuple[float, float]):
42+
Search with a single number or a range of structural
43+
(lattice) volumes in ų.
44+
If a single number, an uncertainty of ±0.01 is automatically used.
45+
density (float, tuple[float, float]):
46+
Search with a single number or a range of structural
47+
(lattice) densities, in g/cm³.
48+
If a single number, an uncertainty of ±0.01 is automatically used.
49+
band_gap (float, tuple[float, float]):
50+
Search with a single number or a range of band gaps in eV.
51+
If a single number, an uncertainty of ±0.01 is automatically used.
3952
num_chunks (int): Maximum number of chunks of data to yield. None will yield all possible.
4053
chunk_size (int): Number of data entries per chunk.
4154
all_fields (bool): Whether to return all fields in the document. Defaults to True.
@@ -46,23 +59,27 @@ def search(
4659
"""
4760
query_params = defaultdict(dict) # type: dict
4861

49-
if formula:
50-
if isinstance(formula, str):
51-
formula = [formula]
52-
53-
query_params.update({"formula": ",".join(formula)})
54-
55-
if chemsys:
56-
if isinstance(chemsys, str):
57-
chemsys = [chemsys]
58-
59-
query_params.update({"chemsys": ",".join(chemsys)})
60-
61-
if elements:
62-
query_params.update({"elements": ",".join(elements)})
63-
64-
if exclude_elements:
65-
query_params.update({"exclude_elements": ",".join(exclude_elements)})
62+
aliased = {
63+
"num_sites": "nsites",
64+
"num_elements": "nelements",
65+
"band_gap": "bandgap",
66+
}
67+
user_query = locals()
68+
for k in ("num_sites", "num_elements", "volume", "density", "band_gap"):
69+
if (value := user_query.get(k)) is not None:
70+
if k in ("num_sites", "num_elements") and isinstance(value, int):
71+
value = (value, value)
72+
elif k in ("volume", "density", "band_gap") and isinstance(
73+
value, int | float
74+
):
75+
value = (value - 1e-2, value + 1e-2)
76+
77+
query_params.update(
78+
{
79+
f"{aliased.get(k,k)}_min": value[0],
80+
f"{aliased.get(k,k)}_max": value[1],
81+
}
82+
)
6683

6784
if material_ids:
6885
if isinstance(material_ids, str):
@@ -77,7 +94,6 @@ def search(
7794
}
7895

7996
return super()._search(
80-
formulae=formula,
8197
num_chunks=num_chunks,
8298
chunk_size=chunk_size,
8399
all_fields=all_fields,

mp_api/client/routes/materials/electrodes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,5 @@ class ConversionElectrodeRester(BaseElectrodeRester):
173173
"elements",
174174
"stability_charge",
175175
"stability_discharge",
176+
"exclude_elements",
176177
]

0 commit comments

Comments
 (0)