Skip to content

Commit e0a5db9

Browse files
authored
Release v0.46.0 (#1051)
2 parents cf9bde6 + 4d06de9 commit e0a5db9

File tree

11 files changed

+168
-191
lines changed

11 files changed

+168
-191
lines changed

mp_api/client/core/settings.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,7 @@ class MAPIClientSettings(BaseSettings):
8585
_MAX_LIST_LENGTH, description="Maximum length of query parameter list"
8686
)
8787

88-
ENDPOINT: str = Field(
89-
_DEFAULT_ENDPOINT, description="The default API endpoint to use."
90-
)
88+
ENDPOINT: str = Field("", description="The default API endpoint to use.")
9189

9290
LTOL: float = Field(
9391
_EMMET_SETTINGS.LTOL,

mp_api/client/core/utils.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import os
4+
import warnings
45
from importlib import import_module
56
from typing import TYPE_CHECKING, Literal
67
from urllib.parse import urljoin
@@ -11,7 +12,7 @@
1112
from monty.json import MontyDecoder
1213
from packaging.version import parse as parse_version
1314

14-
from mp_api.client.core.exceptions import MPRestError
15+
from mp_api.client.core.exceptions import MPRestError, MPRestWarning
1516
from mp_api.client.core.settings import MAPI_CLIENT_SETTINGS
1617

1718
if TYPE_CHECKING:
@@ -54,7 +55,7 @@ def load_json(
5455
return MontyDecoder().process_decoded(data) if deser else data
5556

5657

57-
def validate_api_key(api_key: str | None = None) -> str:
58+
def validate_api_key(api_key: str | None = None) -> str | None:
5859
"""Find and validate an API key."""
5960
# SETTINGS tries to read API key from ~/.config/.pmgrc.yaml
6061
api_key = api_key or os.getenv("MP_API_KEY")
@@ -63,11 +64,22 @@ def validate_api_key(api_key: str | None = None) -> str:
6364

6465
api_key = PMG_SETTINGS.get("PMG_MAPI_KEY")
6566

66-
if not api_key or len(api_key) != 32:
67-
addendum = " Valid API keys are 32 characters." if api_key else ""
67+
if not api_key:
68+
# The web server requires the client to initialize without an API key.
69+
# Only warn the user if the API key cannot be identified to permit
70+
# the web server to run.
71+
warnings.warn(
72+
"No API key found, please set explicitly or in "
73+
"the `MP_API_KEY` environment variable.",
74+
category=MPRestWarning,
75+
stacklevel=2,
76+
)
77+
78+
elif isinstance(api_key, str) and len(api_key) != 32:
6879
raise MPRestError(
6980
"Please obtain a valid API key from https://materialsproject.org/api "
70-
f"and export it as an environment variable `MP_API_KEY`.{addendum}"
81+
"and export it as an environment variable `MP_API_KEY`. "
82+
"Valid API keys are 32 characters."
7183
)
7284

7385
return api_key

mp_api/client/mprester.py

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,22 @@
5252
"mp_api.client.routes.materials.materials.MaterialsRester"
5353
),
5454
**{f"materials/{k}": v for k, v in MATERIALS_RESTERS.items() if k not in {"doi"}},
55-
"doi": MATERIALS_RESTERS["doi"],
5655
**{f"molecules/{k}": v for k, v in MOLECULES_RESTERS.items()},
56+
}
57+
GENERIC_RESTERS = {
58+
"doi": MATERIALS_RESTERS["doi"],
5759
**GENERIC_RESTERS,
5860
}
5961

62+
TOP_LEVEL_RESTERS = [
63+
"molecules/core",
64+
"materials/core",
65+
"_general_store",
66+
"_messages",
67+
"_user_settings",
68+
"doi",
69+
]
70+
6071

6172
class MPRester:
6273
"""Access the new Materials Project API."""
@@ -179,27 +190,23 @@ def __init__(
179190
# Nested rested are then setup to be loaded dynamically with custom __getattr__ functions.
180191
self._all_resters = list(RESTER_LAYOUT.values())
181192

182-
# Instantiate top level molecules and materials resters and set them as attributes
183-
core_suffix = ["molecules/core", "materials/core"]
184-
185-
core_resters = {
186-
rest_name.split("/")[0]: lazy_rester(
187-
api_key=self.api_key,
188-
endpoint=self.endpoint,
189-
include_user_agent=self._include_user_agent,
190-
session=self.session,
191-
use_document_model=self.use_document_model,
192-
headers=self.headers,
193-
mute_progress_bars=self.mute_progress_bars,
194-
)
195-
for rest_name, lazy_rester in RESTER_LAYOUT.items()
196-
if rest_name in core_suffix
197-
}
198-
199-
# Set remaining top level resters, or get an attribute-class name mapping
200-
201-
for attr, rester in core_resters.items():
202-
setattr(self, attr, rester)
193+
# Instantiate top level core molecules, materials, and DOI resters, as well
194+
# as the sunder resters to allow the web server to work.
195+
for rest_name, lazy_rester in (RESTER_LAYOUT | GENERIC_RESTERS).items():
196+
if rest_name in TOP_LEVEL_RESTERS:
197+
setattr(
198+
self,
199+
rest_name.split("/")[0],
200+
lazy_rester(
201+
api_key=self.api_key,
202+
endpoint=self.endpoint,
203+
include_user_agent=self._include_user_agent,
204+
session=self.session,
205+
use_document_model=self.use_document_model,
206+
headers=self.headers,
207+
mute_progress_bars=self.mute_progress_bars,
208+
),
209+
)
203210

204211
@property
205212
def contribs(self):
@@ -249,7 +256,11 @@ def __getattr__(self, attr):
249256
)
250257

251258
def __dir__(self):
252-
return dir(MPRester) + self._deprecated_attributes + ["materials", "molecules"]
259+
return (
260+
dir(MPRester)
261+
+ self._deprecated_attributes
262+
+ [r.split("/", 1)[0] for r in TOP_LEVEL_RESTERS if not r.startswith("_")]
263+
)
253264

254265
def get_task_ids_associated_with_material_id(
255266
self, material_id: str, calc_types: list[CalcType] | None = None

mp_api/mcp/tools.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ def search(self, query: str) -> SearchOutput:
7272
7373
Args:
7474
query (str) : A natural language query of either:
75-
- comma-delimited keywords, example: "polyhedra, orthorhombic, superconductor"
75+
- comma-delimited keywords, example: "polyhedra,orthorhombic,superconductor".
76+
This should contain no whitespace; all whitespace will be removed.
7677
- chemical formula, example: "TiO2"
7778
- dash-delimited elements for more general chemical system, example: "Li-P-S"
7879
To query by formula or chemical system, no commas should be present in the query.
@@ -94,11 +95,16 @@ def search(self, query: str) -> SearchOutput:
9495
material_ids=material_ids, fields=["description", "material_id"]
9596
)
9697
else:
97-
robo_docs += self.client.materials.robocrys.search(query)
98+
robo_docs += self.client.materials.robocrys.search(
99+
query.replace(" ", "").split(",")
100+
)
98101

99102
return SearchOutput(
100103
results=[
101-
FetchResult(id=doc["material_id"], text=doc["description"])
104+
FetchResult(
105+
id=doc["material_id"],
106+
text=doc["description"],
107+
)
102108
for doc in robo_docs
103109
]
104110
)

pyproject.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ dependencies = [
2424
"typing-extensions>=3.7.4.1",
2525
"requests>=2.23.0",
2626
"monty>=2024.12.10",
27-
"emmet-core>=0.86.3rc0",
27+
"emmet-core>=0.86.3",
2828
"boto3",
2929
"orjson >= 3.10,<4",
3030
]
@@ -33,12 +33,11 @@ dynamic = ["version"]
3333
[project.optional-dependencies]
3434
mcp = ["fastmcp"]
3535
all = [
36-
"emmet-core[all]>=0.86.2",
36+
"emmet-core[all]>=0.86.3",
3737
"custodian",
3838
"mpcontribs-client>=5.10",
3939
"fastmcp",
40-
"matminer>=0.9.3",
41-
"scipy<1.17.0", # pending fixes in matminer
40+
"matminer>=0.10.0",
4241
]
4342
test = [
4443
"pre-commit",

requirements/requirements-ubuntu-latest_py3.11.txt

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
#
77
annotated-types==0.7.0
88
# via pydantic
9-
bibtexparser==1.4.3
9+
bibtexparser==1.4.4
1010
# via pymatgen
1111
blake3==1.0.8
1212
# via emmet-core
13-
boto3==1.42.30
13+
boto3==1.42.38
1414
# via mp-api (pyproject.toml)
15-
botocore==1.42.30
15+
botocore==1.42.38
1616
# via
1717
# boto3
1818
# s3transfer
@@ -24,13 +24,13 @@ contourpy==1.3.3
2424
# via matplotlib
2525
cycler==0.12.1
2626
# via matplotlib
27-
emmet-core==0.87.0.dev4
27+
emmet-core==0.86.3
2828
# via mp-api (pyproject.toml)
2929
fonttools==4.61.1
3030
# via matplotlib
3131
idna==3.11
3232
# via requests
33-
jmespath==1.0.1
33+
jmespath==1.1.0
3434
# via
3535
# boto3
3636
# botocore
@@ -49,8 +49,6 @@ monty==2025.3.3
4949
# pymatgen
5050
mpmath==1.3.0
5151
# via sympy
52-
msgpack==1.1.2
53-
# via mp-api (pyproject.toml)
5452
narwhals==2.15.0
5553
# via plotly
5654
networkx==3.6.1
@@ -65,17 +63,17 @@ numpy==2.4.1
6563
# pymatgen-io-validation
6664
# scipy
6765
# spglib
68-
orjson==3.11.5
66+
orjson==3.11.6
6967
# via
7068
# mp-api (pyproject.toml)
7169
# pymatgen
72-
packaging==25.0
70+
packaging==26.0
7371
# via
7472
# matplotlib
7573
# plotly
7674
palettable==3.3.3
7775
# via pymatgen
78-
pandas==2.3.3
76+
pandas==3.0.0
7977
# via pymatgen
8078
pillow==12.1.0
8179
# via matplotlib
@@ -101,7 +99,7 @@ pymatgen==2025.10.7
10199
# pymatgen-io-validation
102100
pymatgen-io-validation==0.1.2
103101
# via emmet-core
104-
pyparsing==3.3.1
102+
pyparsing==3.3.2
105103
# via
106104
# bibtexparser
107105
# matplotlib
@@ -112,8 +110,6 @@ python-dateutil==2.9.0.post0
112110
# pandas
113111
python-dotenv==1.2.1
114112
# via pydantic-settings
115-
pytz==2025.2
116-
# via pandas
117113
pyyaml==6.0.3
118114
# via pybtex
119115
requests==2.32.5
@@ -127,12 +123,10 @@ ruamel-yaml==0.19.1
127123
# pymatgen
128124
s3transfer==0.16.0
129125
# via boto3
130-
scipy==1.16.3
126+
scipy==1.17.0
131127
# via pymatgen
132128
six==1.17.0
133129
# via python-dateutil
134-
smart-open==7.5.0
135-
# via mp-api (pyproject.toml)
136130
spglib==2.7.0
137131
# via pymatgen
138132
sympy==1.14.0
@@ -154,13 +148,9 @@ typing-inspection==0.4.2
154148
# via
155149
# pydantic
156150
# pydantic-settings
157-
tzdata==2025.3
158-
# via pandas
159-
uncertainties==3.2.4
151+
uncertainties==3.2.3
160152
# via pymatgen
161153
urllib3==2.6.3
162154
# via
163155
# botocore
164156
# requests
165-
wrapt==2.0.1
166-
# via smart-open

0 commit comments

Comments
 (0)