mp-api 0.46.3__tar.gz → 0.46.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. {mp_api-0.46.3 → mp_api-0.46.5}/PKG-INFO +3 -3
  2. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/mprester.py +165 -35
  3. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api.egg-info/PKG-INFO +3 -3
  4. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api.egg-info/SOURCES.txt +2 -0
  5. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api.egg-info/requires.txt +2 -2
  6. mp_api-0.46.5/mp_api.egg-info/scm_file_list.json +142 -0
  7. mp_api-0.46.5/mp_api.egg-info/scm_version.json +8 -0
  8. {mp_api-0.46.3 → mp_api-0.46.5}/pyproject.toml +2 -2
  9. {mp_api-0.46.3 → mp_api-0.46.5}/requirements/requirements-ubuntu-latest_py3.11.txt +29 -28
  10. {mp_api-0.46.3 → mp_api-0.46.5}/requirements/requirements-ubuntu-latest_py3.11_extras.txt +84 -86
  11. {mp_api-0.46.3 → mp_api-0.46.5}/requirements/requirements-ubuntu-latest_py3.12.txt +31 -30
  12. {mp_api-0.46.3 → mp_api-0.46.5}/requirements/requirements-ubuntu-latest_py3.12_extras.txt +87 -89
  13. {mp_api-0.46.3 → mp_api-0.46.5}/requirements/requirements-ubuntu-latest_py3.13.txt +31 -30
  14. {mp_api-0.46.3 → mp_api-0.46.5}/requirements/requirements-ubuntu-latest_py3.13_extras.txt +87 -89
  15. {mp_api-0.46.3 → mp_api-0.46.5}/requirements/requirements-ubuntu-latest_py3.14.txt +31 -30
  16. {mp_api-0.46.3 → mp_api-0.46.5}/requirements/requirements-ubuntu-latest_py3.14_extras.txt +87 -89
  17. mp_api-0.46.5/tests/client/contribs/conftest.py +34 -0
  18. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/test_mprester.py +65 -8
  19. mp_api-0.46.3/tests/client/contribs/conftest.py +0 -11
  20. {mp_api-0.46.3 → mp_api-0.46.5}/.coveragerc +0 -0
  21. {mp_api-0.46.3 → mp_api-0.46.5}/.github/workflows/lint.yml +0 -0
  22. {mp_api-0.46.3 → mp_api-0.46.5}/.github/workflows/release.yml +0 -0
  23. {mp_api-0.46.3 → mp_api-0.46.5}/.github/workflows/testing.yml +0 -0
  24. {mp_api-0.46.3 → mp_api-0.46.5}/.github/workflows/upgrade_dependencies.yml +0 -0
  25. {mp_api-0.46.3 → mp_api-0.46.5}/.gitignore +0 -0
  26. {mp_api-0.46.3 → mp_api-0.46.5}/.pre-commit-config.yaml +0 -0
  27. {mp_api-0.46.3 → mp_api-0.46.5}/CODE_OF_CONDUCT.md +0 -0
  28. {mp_api-0.46.3 → mp_api-0.46.5}/LICENSE +0 -0
  29. {mp_api-0.46.3 → mp_api-0.46.5}/README.md +0 -0
  30. {mp_api-0.46.3 → mp_api-0.46.5}/dev/generate_mcp_tools.py +0 -0
  31. {mp_api-0.46.3 → mp_api-0.46.5}/dev/inspect_mcp.sh +0 -0
  32. {mp_api-0.46.3 → mp_api-0.46.5}/docs/Makefile +0 -0
  33. {mp_api-0.46.3 → mp_api-0.46.5}/docs/_templates/custom-class-template.rst +0 -0
  34. {mp_api-0.46.3 → mp_api-0.46.5}/docs/_templates/custom-module-template.rst +0 -0
  35. {mp_api-0.46.3 → mp_api-0.46.5}/docs/conf.py +0 -0
  36. {mp_api-0.46.3 → mp_api-0.46.5}/docs/index.rst +0 -0
  37. {mp_api-0.46.3 → mp_api-0.46.5}/docs/make.bat +0 -0
  38. {mp_api-0.46.3 → mp_api-0.46.5}/docs/modules.rst +0 -0
  39. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/__init__.py +0 -0
  40. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/_test_utils.py +0 -0
  41. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/__init__.py +0 -0
  42. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/_server_utils.py +0 -0
  43. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/contribs/__init__.py +0 -0
  44. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/contribs/_logger.py +0 -0
  45. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/contribs/_types.py +0 -0
  46. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/contribs/_units.py +0 -0
  47. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/contribs/client.py +0 -0
  48. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/contribs/schemas.py +0 -0
  49. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/contribs/settings.py +0 -0
  50. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/contribs/utils.py +0 -0
  51. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/core/__init__.py +0 -0
  52. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/core/_oxygen_evolution.py +0 -0
  53. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/core/client.py +0 -0
  54. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/core/exceptions.py +0 -0
  55. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/core/schemas.py +0 -0
  56. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/core/settings.py +0 -0
  57. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/core/utils.py +0 -0
  58. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/__init__.py +0 -0
  59. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/_server.py +0 -0
  60. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/__init__.py +0 -0
  61. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/absorption.py +0 -0
  62. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/alloys.py +0 -0
  63. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/bonds.py +0 -0
  64. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/chemenv.py +0 -0
  65. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/dielectric.py +0 -0
  66. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/doi.py +0 -0
  67. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/elasticity.py +0 -0
  68. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/electrodes.py +0 -0
  69. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/electronic_structure.py +0 -0
  70. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/eos.py +0 -0
  71. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/grain_boundaries.py +0 -0
  72. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/magnetism.py +0 -0
  73. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/materials.py +0 -0
  74. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/oxidation_states.py +0 -0
  75. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/phonon.py +0 -0
  76. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/piezo.py +0 -0
  77. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/provenance.py +0 -0
  78. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/robocrys.py +0 -0
  79. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/similarity.py +0 -0
  80. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/substrates.py +0 -0
  81. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/summary.py +0 -0
  82. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/surface_properties.py +0 -0
  83. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/synthesis.py +0 -0
  84. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/tasks.py +0 -0
  85. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/thermo.py +0 -0
  86. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/materials/xas.py +0 -0
  87. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/molecules/__init__.py +0 -0
  88. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/molecules/jcesr.py +0 -0
  89. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/molecules/molecules.py +0 -0
  90. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/client/routes/molecules/summary.py +0 -0
  91. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/mcp/__init__.py +0 -0
  92. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/mcp/_schemas.py +0 -0
  93. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/mcp/mp_mcp.py +0 -0
  94. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/mcp/server.py +0 -0
  95. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/mcp/tools.py +0 -0
  96. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/mcp/utils.py +0 -0
  97. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api/py.typed +0 -0
  98. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api.egg-info/dependency_links.txt +0 -0
  99. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api.egg-info/entry_points.txt +0 -0
  100. {mp_api-0.46.3 → mp_api-0.46.5}/mp_api.egg-info/top_level.txt +0 -0
  101. {mp_api-0.46.3 → mp_api-0.46.5}/setup.cfg +0 -0
  102. {mp_api-0.46.3 → mp_api-0.46.5}/test_files/Si_mp_149.cif +0 -0
  103. {mp_api-0.46.3 → mp_api-0.46.5}/tests/__init__.py +0 -0
  104. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/__init__.py +0 -0
  105. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/contribs/test_client.py +0 -0
  106. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/contribs/test_contribs_schemas.py +0 -0
  107. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/contribs/test_contribs_utils.py +0 -0
  108. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/contribs/test_types.py +0 -0
  109. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/core/test_oxygen_evolution.py +0 -0
  110. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/core/test_schemas.py +0 -0
  111. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/core/test_utils.py +0 -0
  112. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/__init__.py +0 -0
  113. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_absorption.py +0 -0
  114. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_alloys.py +0 -0
  115. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_bonds.py +0 -0
  116. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_chemenv.py +0 -0
  117. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_dielectric.py +0 -0
  118. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_doi.py +0 -0
  119. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_elasticity.py +0 -0
  120. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_electrodes.py +0 -0
  121. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_electronic_structure.py +0 -0
  122. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_eos.py +0 -0
  123. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_grain_boundary.py +0 -0
  124. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_magnetism.py +0 -0
  125. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_materials.py +0 -0
  126. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_oxidation_states.py +0 -0
  127. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_phonon.py +0 -0
  128. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_piezo.py +0 -0
  129. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_provenance.py +0 -0
  130. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_robocrys.py +0 -0
  131. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_similarity.py +0 -0
  132. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_substrates.py +0 -0
  133. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_summary.py +0 -0
  134. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_surface_properties.py +0 -0
  135. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_synthesis.py +0 -0
  136. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_tasks.py +0 -0
  137. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_thermo.py +0 -0
  138. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/materials/test_xas.py +0 -0
  139. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/molecules/__init__.py +0 -0
  140. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/molecules/test_jcesr.py +0 -0
  141. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/molecules/test_molecules.py +0 -0
  142. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/molecules/test_summary.py +0 -0
  143. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/test_client.py +0 -0
  144. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/test_core_client.py +0 -0
  145. {mp_api-0.46.3 → mp_api-0.46.5}/tests/client/test_heartbeat.py +0 -0
  146. {mp_api-0.46.3 → mp_api-0.46.5}/tests/mcp/__init__.py +0 -0
  147. {mp_api-0.46.3 → mp_api-0.46.5}/tests/mcp/test_server.py +0 -0
  148. {mp_api-0.46.3 → mp_api-0.46.5}/tests/mcp/test_tools.py +0 -0
  149. {mp_api-0.46.3 → mp_api-0.46.5}/tests/mcp/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mp-api
3
- Version: 0.46.3
3
+ Version: 0.46.5
4
4
  Summary: API Client for the Materials Project
5
5
  Author-email: The Materials Project <feedback@materialsproject.org>
6
6
  License-Expression: BSD-3-Clause-LBNL
@@ -17,7 +17,7 @@ Requires-Dist: pymatgen>2024.2.20
17
17
  Requires-Dist: typing-extensions>=3.7.4.1
18
18
  Requires-Dist: requests>=2.23.0
19
19
  Requires-Dist: monty>=2024.12.10
20
- Requires-Dist: emmet-core<0.87.2,>=0.87.0
20
+ Requires-Dist: emmet-core>=0.87.1
21
21
  Requires-Dist: boto3
22
22
  Requires-Dist: orjson<4,>=3.10
23
23
  Requires-Dist: pyarrow>=20.0.0
@@ -40,7 +40,7 @@ Requires-Dist: cachetools; extra == "contribs"
40
40
  Requires-Dist: pymongo; extra == "contribs"
41
41
  Provides-Extra: all
42
42
  Requires-Dist: custodian; extra == "all"
43
- Requires-Dist: emmet-core[all]<0.87.2,>=0.87.0; extra == "all"
43
+ Requires-Dist: emmet-core[all]>=0.87.1; extra == "all"
44
44
  Requires-Dist: fastmcp; extra == "all"
45
45
  Requires-Dist: flask; extra == "all"
46
46
  Provides-Extra: test
@@ -1,11 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import itertools
4
+ import json
4
5
  import os
6
+ import re
5
7
  import warnings
6
8
  from collections import defaultdict
7
9
  from functools import cache, lru_cache
8
10
  from typing import TYPE_CHECKING
11
+ from urllib.parse import urlencode
9
12
 
10
13
  from emmet.core.band_theory import BSPathType
11
14
  from emmet.core.mpid import MPID, AlphaID
@@ -43,7 +46,7 @@ from mp_api.client.routes.materials import MATERIALS_RESTERS
43
46
  from mp_api.client.routes.molecules import MOLECULES_RESTERS
44
47
 
45
48
  if TYPE_CHECKING:
46
- from collections.abc import Sequence
49
+ from collections.abc import Iterable, Sequence
47
50
  from typing import Any, Literal
48
51
 
49
52
  import numpy as np
@@ -88,6 +91,16 @@ TOP_LEVEL_RESTERS = [
88
91
  ]
89
92
 
90
93
 
94
+ def _all_subchemsyses(elements: Iterable[str]) -> list[str]:
95
+ """Every chemical (sub)system spanned by `elements`, as sorted dash-joined strings."""
96
+ element_set = set(elements)
97
+ return [
98
+ "-".join(sorted(els))
99
+ for n in range(1, len(element_set) + 1)
100
+ for els in itertools.combinations(element_set, n)
101
+ ]
102
+
103
+
91
104
  class MPRester(_Rester):
92
105
  """Access the new Materials Project API."""
93
106
 
@@ -657,8 +670,10 @@ class MPRester(_Rester):
657
670
  entry_dict["correction"] = 0.0
658
671
  entry_dict["energy_adjustments"] = []
659
672
 
660
- if property_data:
661
- entry_dict["data"] = {prop: doc[prop] for prop in property_data}
673
+ if (
674
+ property_data
675
+ ): # merge property_data, retaining entry data (e.g. `oxidation_states`)
676
+ entry_dict["data"] |= {prop: doc[prop] for prop in property_data}
662
677
 
663
678
  if conventional_unit_cell:
664
679
  entry_struct = Structure.from_dict(entry_dict["structure"])
@@ -1054,6 +1069,26 @@ class MPRester(_Rester):
1054
1069
  **kwargs,
1055
1070
  )
1056
1071
 
1072
+ def _get_unmixed_entries(
1073
+ self, chemsyses: list[str], **kwargs
1074
+ ) -> list[ComputedStructureEntry]:
1075
+ """Get the GGA(+U) and r2SCAN entries for `chemsyses` as separate, un-mixed entries.
1076
+
1077
+ `MaterialsProjectDFTMixingScheme` needs both functionals side by side, as returned
1078
+ by this helper function, while entries returned by the mixed thermo type cannot be
1079
+ used with it.
1080
+ """
1081
+ return [
1082
+ entry
1083
+ for thermo_type in (ThermoType.GGA_GGA_U, ThermoType.R2SCAN)
1084
+ for entry in self.get_entries(
1085
+ chemsyses,
1086
+ compatible_only=True,
1087
+ additional_criteria={"thermo_types": [thermo_type.value]},
1088
+ **kwargs,
1089
+ )
1090
+ ]
1091
+
1057
1092
  def get_entries_in_chemsys(
1058
1093
  self,
1059
1094
  elements: str | list[str],
@@ -1073,6 +1108,14 @@ class MPRester(_Rester):
1073
1108
  Note that by default this returns mixed GGA/GGA+U/r2SCAN entries. For others,
1074
1109
  pass GGA/GGA+U, or R2SCAN as thermo_types in additional_criteria.
1075
1110
 
1111
+ Mixed entries are taken from the MP-built phase diagram for the whole chemical
1112
+ system, so they share one energy scale and reproduce the hull shown on
1113
+ https://materialsproject.org. Narrowing the query with `additional_criteria`,
1114
+ or passing ``compatible_only = False``, cannot be served that way and returns
1115
+ entries that are *not* immediately suitable for constructing a phase diagram;
1116
+ ``property_data`` and ``conventional_unit_cell`` re-apply the mixing scheme here
1117
+ instead, which can differ slightly from MP. Warnings are thrown for these cases.
1118
+
1076
1119
  Args:
1077
1120
  elements (str or [str]): Parent chemical system string comprising element
1078
1121
  symbols separated by dashes, e.g., "Li-Fe-O" or List of element
@@ -1114,11 +1157,7 @@ class MPRester(_Rester):
1114
1157
  "or identify a subset of relevant chemical systems to query first."
1115
1158
  )
1116
1159
 
1117
- all_chemsyses = [
1118
- "-".join(sorted(els))
1119
- for i in range(len(elements_set))
1120
- for els in itertools.combinations(elements_set, i + 1)
1121
- ]
1160
+ all_chemsyses = _all_subchemsyses(elements_set)
1122
1161
 
1123
1162
  if additional_criteria is None:
1124
1163
  warnings.warn(
@@ -1131,15 +1170,79 @@ class MPRester(_Rester):
1131
1170
  stacklevel=2,
1132
1171
  )
1133
1172
 
1134
- entries = self.get_entries(
1135
- all_chemsyses,
1136
- compatible_only=compatible_only,
1137
- property_data=property_data,
1138
- conventional_unit_cell=conventional_unit_cell,
1139
- additional_criteria=additional_criteria or DEFAULT_THERMOTYPE_CRITERIA,
1140
- **kwargs,
1173
+ additional_criteria = {
1174
+ **DEFAULT_THERMOTYPE_CRITERIA,
1175
+ **(additional_criteria or {}),
1176
+ } # default thermo type unless the caller explicitly overrides
1177
+
1178
+ # The mixing correction stored on a mixed GGA(+U)/r2SCAN entry is referenced to the hull
1179
+ # of the one chemical system that entry's thermo doc was built for, so the served entries
1180
+ # cannot be pooled _across subsystems_ -- they end up on different absolute energy scales
1181
+ # (issue #1104). Thus we serve MP's phase diagram; built with mixing applied across the
1182
+ # full system, thus self-consistent by construction and identical to the MP website:
1183
+ mixed = set(additional_criteria["thermo_types"]) == {"GGA_GGA+U_R2SCAN"}
1184
+ consistent = (
1185
+ mixed and compatible_only and set(additional_criteria) == {"thermo_types"}
1141
1186
  )
1142
1187
 
1188
+ entries: list[ComputedStructureEntry] | None = None
1189
+ if consistent:
1190
+ if not (property_data or conventional_unit_cell):
1191
+ phase_diagram = self.materials.thermo.get_phase_diagram_from_chemsys(
1192
+ "-".join(sorted(elements_set)),
1193
+ thermo_type=additional_criteria["thermo_types"][0],
1194
+ ) # default, mixed thermotype; takes a single type, not a list
1195
+ if phase_diagram is not None:
1196
+ entries = list(phase_diagram.all_entries)
1197
+
1198
+ if entries is None:
1199
+ # MP has no pre-built diagram for this system, or the entries need reshaping
1200
+ # first, so redo the mixing here as MP does when building PDs. Mixing scheme
1201
+ # is chemical-system dependent, so this can anchor on a different hull than
1202
+ # MP did/would, and it drops entries it cannot place:
1203
+ from pymatgen.entries.mixing_scheme import (
1204
+ MaterialsProjectDFTMixingScheme,
1205
+ )
1206
+
1207
+ warnings.warn(
1208
+ "Reconstructing a common energy scale for these entries with the "
1209
+ "GGA(+U)/r2SCAN mixing scheme, as the Materials Project has no pre-built "
1210
+ "phase diagram to serve for this query. Energies and hull distances may "
1211
+ "differ slightly from https://materialsproject.org, and entries the mixing "
1212
+ "scheme cannot place are dropped.",
1213
+ category=MPRestWarning,
1214
+ stacklevel=2,
1215
+ )
1216
+ entries = MaterialsProjectDFTMixingScheme().process_entries(
1217
+ self._get_unmixed_entries(
1218
+ all_chemsyses,
1219
+ property_data=property_data,
1220
+ conventional_unit_cell=conventional_unit_cell,
1221
+ **kwargs,
1222
+ )
1223
+ )
1224
+ else: # non-consistent
1225
+ if mixed:
1226
+ warnings.warn(
1227
+ "Mixed GGA(+U)/r2SCAN entries can only be placed on a common energy scale "
1228
+ "when the whole chemical system is retrieved with `compatible_only = True`, "
1229
+ "so these entries are not suitable for constructing a phase diagram. Either "
1230
+ "drop the extra `additional_criteria` (and filter the returned entries "
1231
+ "instead), or request a single functional with "
1232
+ '`additional_criteria = {"thermo_types": ["GGA_GGA+U"]}`.',
1233
+ category=MPRestWarning,
1234
+ stacklevel=2,
1235
+ )
1236
+
1237
+ entries = self.get_entries(
1238
+ all_chemsyses,
1239
+ compatible_only=compatible_only,
1240
+ property_data=property_data,
1241
+ conventional_unit_cell=conventional_unit_cell,
1242
+ additional_criteria=additional_criteria,
1243
+ **kwargs,
1244
+ )
1245
+
1143
1246
  if use_gibbs:
1144
1247
  # replace the entries with GibbsComputedStructureEntry
1145
1248
  from pymatgen.entries.computed_entries import GibbsComputedStructureEntry
@@ -1365,45 +1468,66 @@ class MPRester(_Rester):
1365
1468
  if calc_types and calc_type not in calc_types:
1366
1469
  continue
1367
1470
  mp_id = doc["material_id"]
1368
- meta[mp_id].append({"task_id": task_id, "calc_type": calc_type})
1471
+ meta[mp_id].append(
1472
+ {
1473
+ "task_id": str(AlphaID(task_id, prefix="mp").formatted),
1474
+ "task_id_as_alpha": task_id,
1475
+ "calc_type": calc_type,
1476
+ }
1477
+ )
1369
1478
 
1370
1479
  if not meta:
1371
1480
  raise ValueError(f"No tasks found for material id {material_ids}.")
1372
1481
 
1373
1482
  # return a list of URLs for NoMaD Downloads containing the list of files
1374
1483
  # for every external_id in `task_ids`
1375
- # For reference, please visit https://nomad-lab.eu/prod/rae/api/
1484
+ # For reference, please visit https://nomad-lab.eu/prod/v1/api/v1/extensions/docs#/entries/raw
1376
1485
 
1377
1486
  # check if these task ids exist on NOMAD
1378
- prefix = "https://nomad-lab.eu/prod/rae/api/repo/?"
1379
- if file_patterns is not None:
1380
- for file_pattern in file_patterns:
1381
- prefix += f"file_pattern={file_pattern}&"
1382
- prefix += "external_id="
1487
+ nomad_check_endpoint = "https://nomad-lab.eu/prod/v1/api/v1/entries/rawdir"
1488
+ nomad_download_endpoint = "https://nomad-lab.eu/prod/v1/api/v1/entries/raw"
1383
1489
 
1384
1490
  task_ids = [t["task_id"] for tl in meta.values() for t in tl]
1491
+ task_id_query_params: list[tuple[str, dict]] = [
1492
+ (tid, {"json_query": json.dumps({"external_id": tid})}) for tid in task_ids
1493
+ ]
1494
+
1385
1495
  nomad_exist_task_ids = self._check_get_download_info_url_by_task_id(
1386
- prefix=prefix, task_ids=task_ids
1496
+ prefix=nomad_check_endpoint, task_ids=task_id_query_params
1387
1497
  )
1498
+
1388
1499
  if len(nomad_exist_task_ids) != len(task_ids):
1389
1500
  self._print_help_message(
1390
- nomad_exist_task_ids, task_ids, file_patterns, calc_types
1501
+ [pair[0] for pair in nomad_exist_task_ids],
1502
+ task_ids,
1503
+ file_patterns,
1504
+ calc_types,
1391
1505
  )
1392
1506
 
1393
1507
  # generate download links for those that exist
1394
- prefix = "https://nomad-lab.eu/prod/rae/api/raw/query?"
1395
1508
  if file_patterns is not None:
1396
- for file_pattern in file_patterns:
1397
- prefix += f"file_pattern={file_pattern}&"
1398
- prefix += "external_id="
1509
+ if len(file_patterns) == 1:
1510
+ for _, json_query in nomad_exist_task_ids:
1511
+ json_query["glob_pattern"] = file_patterns[0]
1512
+ else:
1513
+ re_pattern = "|".join(re.escape(pattern) for pattern in file_patterns)
1514
+ for _, json_query in nomad_exist_task_ids:
1515
+ json_query["re_pattern"] = re_pattern
1516
+
1517
+ urls = [
1518
+ f"{nomad_download_endpoint}?{urlencode(json_query)}"
1519
+ for _, json_query in nomad_exist_task_ids
1520
+ ]
1399
1521
 
1400
- urls = [prefix + tids for tids in nomad_exist_task_ids]
1401
1522
  return meta, urls
1402
1523
 
1403
- def _check_get_download_info_url_by_task_id(self, prefix, task_ids) -> list[str]:
1404
- prefix = prefix.replace("/raw/query", "/repo/")
1524
+ def _check_get_download_info_url_by_task_id(
1525
+ self, prefix, task_ids
1526
+ ) -> list[tuple[str, dict]]:
1405
1527
  return [
1406
- task_id for task_id in task_ids if self._check_nomad_exist(prefix + task_id)
1528
+ pair
1529
+ for pair in task_ids
1530
+ if self._check_nomad_exist(url=f"{prefix}?{urlencode(pair[1])}")
1407
1531
  ]
1408
1532
 
1409
1533
  @staticmethod
@@ -1411,7 +1535,7 @@ class MPRester(_Rester):
1411
1535
  response = get(url=url)
1412
1536
  if response.status_code != 200:
1413
1537
  return False
1414
- return load_json(response.text)["pagination"]["total"] != 0
1538
+ return response.json()["pagination"]["total"] != 0
1415
1539
 
1416
1540
  @staticmethod
1417
1541
  def _print_help_message(nomad_exist_task_ids, task_ids, file_patterns, calc_types):
@@ -1650,8 +1774,14 @@ class MPRester(_Rester):
1650
1774
 
1651
1775
  joint_entries: Sequence[ComputedEntry | ComputedStructureEntry | PDEntry] = [
1652
1776
  *entries,
1653
- *pd.all_entries,
1654
- ]
1777
+ *(
1778
+ self._get_unmixed_entries(_all_subchemsyses(str(el) for el in chemsys))
1779
+ if thermo_type_valid_str == ThermoType.GGA_GGA_U_R2SCAN.value
1780
+ else pd.all_entries
1781
+ ), # `pd.all_entries` for a mixed hull hold one already-mixed entry per material,
1782
+ ] # which the mixing scheme cannot re-process (needs the GGA(+U) and r2SCAN entries
1783
+ # side by side), and silently drops every entry it cannot pair up -- so we fetch
1784
+ # separately in the mixed case
1655
1785
 
1656
1786
  new_pd = PhaseDiagram(
1657
1787
  corrector.process_entries(joint_entries) # type: ignore[arg-type]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mp-api
3
- Version: 0.46.3
3
+ Version: 0.46.5
4
4
  Summary: API Client for the Materials Project
5
5
  Author-email: The Materials Project <feedback@materialsproject.org>
6
6
  License-Expression: BSD-3-Clause-LBNL
@@ -17,7 +17,7 @@ Requires-Dist: pymatgen>2024.2.20
17
17
  Requires-Dist: typing-extensions>=3.7.4.1
18
18
  Requires-Dist: requests>=2.23.0
19
19
  Requires-Dist: monty>=2024.12.10
20
- Requires-Dist: emmet-core<0.87.2,>=0.87.0
20
+ Requires-Dist: emmet-core>=0.87.1
21
21
  Requires-Dist: boto3
22
22
  Requires-Dist: orjson<4,>=3.10
23
23
  Requires-Dist: pyarrow>=20.0.0
@@ -40,7 +40,7 @@ Requires-Dist: cachetools; extra == "contribs"
40
40
  Requires-Dist: pymongo; extra == "contribs"
41
41
  Provides-Extra: all
42
42
  Requires-Dist: custodian; extra == "all"
43
- Requires-Dist: emmet-core[all]<0.87.2,>=0.87.0; extra == "all"
43
+ Requires-Dist: emmet-core[all]>=0.87.1; extra == "all"
44
44
  Requires-Dist: fastmcp; extra == "all"
45
45
  Requires-Dist: flask; extra == "all"
46
46
  Provides-Extra: test
@@ -26,6 +26,8 @@ mp_api.egg-info/SOURCES.txt
26
26
  mp_api.egg-info/dependency_links.txt
27
27
  mp_api.egg-info/entry_points.txt
28
28
  mp_api.egg-info/requires.txt
29
+ mp_api.egg-info/scm_file_list.json
30
+ mp_api.egg-info/scm_version.json
29
31
  mp_api.egg-info/top_level.txt
30
32
  mp_api/client/__init__.py
31
33
  mp_api/client/_server_utils.py
@@ -2,7 +2,7 @@ pymatgen>2024.2.20
2
2
  typing-extensions>=3.7.4.1
3
3
  requests>=2.23.0
4
4
  monty>=2024.12.10
5
- emmet-core<0.87.2,>=0.87.0
5
+ emmet-core>=0.87.1
6
6
  boto3
7
7
  orjson<4,>=3.10
8
8
  pyarrow>=20.0.0
@@ -10,7 +10,7 @@ deltalake<1.6.0,>=1.4.0
10
10
 
11
11
  [all]
12
12
  custodian
13
- emmet-core[all]<0.87.2,>=0.87.0
13
+ emmet-core[all]>=0.87.1
14
14
  fastmcp
15
15
  flask
16
16
 
@@ -0,0 +1,142 @@
1
+ {
2
+ "files": [
3
+ ".coveragerc",
4
+ ".github/workflows/lint.yml",
5
+ ".github/workflows/release.yml",
6
+ ".github/workflows/testing.yml",
7
+ ".github/workflows/upgrade_dependencies.yml",
8
+ ".gitignore",
9
+ ".pre-commit-config.yaml",
10
+ "CODE_OF_CONDUCT.md",
11
+ "LICENSE",
12
+ "README.md",
13
+ "dev/generate_mcp_tools.py",
14
+ "dev/inspect_mcp.sh",
15
+ "docs/Makefile",
16
+ "docs/_templates/custom-class-template.rst",
17
+ "docs/_templates/custom-module-template.rst",
18
+ "docs/conf.py",
19
+ "docs/index.rst",
20
+ "docs/make.bat",
21
+ "docs/modules.rst",
22
+ "mp_api/__init__.py",
23
+ "mp_api/_test_utils.py",
24
+ "mp_api/client/__init__.py",
25
+ "mp_api/client/_server_utils.py",
26
+ "mp_api/client/contribs/__init__.py",
27
+ "mp_api/client/contribs/_logger.py",
28
+ "mp_api/client/contribs/_types.py",
29
+ "mp_api/client/contribs/_units.py",
30
+ "mp_api/client/contribs/client.py",
31
+ "mp_api/client/contribs/schemas.py",
32
+ "mp_api/client/contribs/settings.py",
33
+ "mp_api/client/contribs/utils.py",
34
+ "mp_api/client/core/__init__.py",
35
+ "mp_api/client/core/_oxygen_evolution.py",
36
+ "mp_api/client/core/client.py",
37
+ "mp_api/client/core/exceptions.py",
38
+ "mp_api/client/core/schemas.py",
39
+ "mp_api/client/core/settings.py",
40
+ "mp_api/client/core/utils.py",
41
+ "mp_api/client/mprester.py",
42
+ "mp_api/client/routes/__init__.py",
43
+ "mp_api/client/routes/_server.py",
44
+ "mp_api/client/routes/materials/__init__.py",
45
+ "mp_api/client/routes/materials/absorption.py",
46
+ "mp_api/client/routes/materials/alloys.py",
47
+ "mp_api/client/routes/materials/bonds.py",
48
+ "mp_api/client/routes/materials/chemenv.py",
49
+ "mp_api/client/routes/materials/dielectric.py",
50
+ "mp_api/client/routes/materials/doi.py",
51
+ "mp_api/client/routes/materials/elasticity.py",
52
+ "mp_api/client/routes/materials/electrodes.py",
53
+ "mp_api/client/routes/materials/electronic_structure.py",
54
+ "mp_api/client/routes/materials/eos.py",
55
+ "mp_api/client/routes/materials/grain_boundaries.py",
56
+ "mp_api/client/routes/materials/magnetism.py",
57
+ "mp_api/client/routes/materials/materials.py",
58
+ "mp_api/client/routes/materials/oxidation_states.py",
59
+ "mp_api/client/routes/materials/phonon.py",
60
+ "mp_api/client/routes/materials/piezo.py",
61
+ "mp_api/client/routes/materials/provenance.py",
62
+ "mp_api/client/routes/materials/robocrys.py",
63
+ "mp_api/client/routes/materials/similarity.py",
64
+ "mp_api/client/routes/materials/substrates.py",
65
+ "mp_api/client/routes/materials/summary.py",
66
+ "mp_api/client/routes/materials/surface_properties.py",
67
+ "mp_api/client/routes/materials/synthesis.py",
68
+ "mp_api/client/routes/materials/tasks.py",
69
+ "mp_api/client/routes/materials/thermo.py",
70
+ "mp_api/client/routes/materials/xas.py",
71
+ "mp_api/client/routes/molecules/__init__.py",
72
+ "mp_api/client/routes/molecules/jcesr.py",
73
+ "mp_api/client/routes/molecules/molecules.py",
74
+ "mp_api/client/routes/molecules/summary.py",
75
+ "mp_api/mcp/__init__.py",
76
+ "mp_api/mcp/_schemas.py",
77
+ "mp_api/mcp/mp_mcp.py",
78
+ "mp_api/mcp/server.py",
79
+ "mp_api/mcp/tools.py",
80
+ "mp_api/mcp/utils.py",
81
+ "mp_api/py.typed",
82
+ "pyproject.toml",
83
+ "requirements/requirements-ubuntu-latest_py3.11.txt",
84
+ "requirements/requirements-ubuntu-latest_py3.11_extras.txt",
85
+ "requirements/requirements-ubuntu-latest_py3.12.txt",
86
+ "requirements/requirements-ubuntu-latest_py3.12_extras.txt",
87
+ "requirements/requirements-ubuntu-latest_py3.13.txt",
88
+ "requirements/requirements-ubuntu-latest_py3.13_extras.txt",
89
+ "requirements/requirements-ubuntu-latest_py3.14.txt",
90
+ "requirements/requirements-ubuntu-latest_py3.14_extras.txt",
91
+ "test_files/Si_mp_149.cif",
92
+ "tests/__init__.py",
93
+ "tests/client/__init__.py",
94
+ "tests/client/contribs/conftest.py",
95
+ "tests/client/contribs/test_client.py",
96
+ "tests/client/contribs/test_contribs_schemas.py",
97
+ "tests/client/contribs/test_contribs_utils.py",
98
+ "tests/client/contribs/test_types.py",
99
+ "tests/client/core/test_oxygen_evolution.py",
100
+ "tests/client/core/test_schemas.py",
101
+ "tests/client/core/test_utils.py",
102
+ "tests/client/materials/__init__.py",
103
+ "tests/client/materials/test_absorption.py",
104
+ "tests/client/materials/test_alloys.py",
105
+ "tests/client/materials/test_bonds.py",
106
+ "tests/client/materials/test_chemenv.py",
107
+ "tests/client/materials/test_dielectric.py",
108
+ "tests/client/materials/test_doi.py",
109
+ "tests/client/materials/test_elasticity.py",
110
+ "tests/client/materials/test_electrodes.py",
111
+ "tests/client/materials/test_electronic_structure.py",
112
+ "tests/client/materials/test_eos.py",
113
+ "tests/client/materials/test_grain_boundary.py",
114
+ "tests/client/materials/test_magnetism.py",
115
+ "tests/client/materials/test_materials.py",
116
+ "tests/client/materials/test_oxidation_states.py",
117
+ "tests/client/materials/test_phonon.py",
118
+ "tests/client/materials/test_piezo.py",
119
+ "tests/client/materials/test_provenance.py",
120
+ "tests/client/materials/test_robocrys.py",
121
+ "tests/client/materials/test_similarity.py",
122
+ "tests/client/materials/test_substrates.py",
123
+ "tests/client/materials/test_summary.py",
124
+ "tests/client/materials/test_surface_properties.py",
125
+ "tests/client/materials/test_synthesis.py",
126
+ "tests/client/materials/test_tasks.py",
127
+ "tests/client/materials/test_thermo.py",
128
+ "tests/client/materials/test_xas.py",
129
+ "tests/client/molecules/__init__.py",
130
+ "tests/client/molecules/test_jcesr.py",
131
+ "tests/client/molecules/test_molecules.py",
132
+ "tests/client/molecules/test_summary.py",
133
+ "tests/client/test_client.py",
134
+ "tests/client/test_core_client.py",
135
+ "tests/client/test_heartbeat.py",
136
+ "tests/client/test_mprester.py",
137
+ "tests/mcp/__init__.py",
138
+ "tests/mcp/test_server.py",
139
+ "tests/mcp/test_tools.py",
140
+ "tests/mcp/test_utils.py"
141
+ ]
142
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.46.5",
3
+ "distance": 0,
4
+ "node": "ge114cc193551f421ed5cf10bf8854bf474cf6a7e",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-08-18"
8
+ }
@@ -24,7 +24,7 @@ dependencies = [
24
24
  "typing-extensions>=3.7.4.1",
25
25
  "requests>=2.23.0",
26
26
  "monty>=2024.12.10",
27
- "emmet-core>=0.87.0,<0.87.2",
27
+ "emmet-core>=0.87.1",
28
28
  "boto3",
29
29
  "orjson >= 3.10,<4",
30
30
  "pyarrow >= 20.0.0",
@@ -50,7 +50,7 @@ contribs = [
50
50
  ]
51
51
  all = [
52
52
  "custodian",
53
- "emmet-core[all]>=0.87.0,<0.87.2",
53
+ "emmet-core[all]>=0.87.1",
54
54
  "fastmcp",
55
55
  "flask",
56
56
  ]