mp-api 0.46.1rc9__tar.gz → 0.46.2__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 (148) hide show
  1. {mp_api-0.46.1rc9 → mp_api-0.46.2}/.github/workflows/lint.yml +1 -1
  2. {mp_api-0.46.1rc9 → mp_api-0.46.2}/.github/workflows/release.yml +7 -3
  3. {mp_api-0.46.1rc9 → mp_api-0.46.2}/.github/workflows/testing.yml +2 -12
  4. {mp_api-0.46.1rc9 → mp_api-0.46.2}/.github/workflows/upgrade_dependencies.yml +2 -2
  5. {mp_api-0.46.1rc9 → mp_api-0.46.2}/.pre-commit-config.yaml +5 -5
  6. {mp_api-0.46.1rc9 → mp_api-0.46.2}/PKG-INFO +17 -5
  7. {mp_api-0.46.1rc9 → mp_api-0.46.2}/docs/conf.py +2 -0
  8. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/_test_utils.py +54 -7
  9. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/__init__.py +1 -0
  10. mp_api-0.46.2/mp_api/client/contribs/__init__.py +16 -0
  11. mp_api-0.46.2/mp_api/client/contribs/_logger.py +97 -0
  12. mp_api-0.46.2/mp_api/client/contribs/_types.py +351 -0
  13. mp_api-0.46.2/mp_api/client/contribs/_units.py +21 -0
  14. mp_api-0.46.2/mp_api/client/contribs/client.py +2541 -0
  15. mp_api-0.46.2/mp_api/client/contribs/schemas.py +376 -0
  16. mp_api-0.46.2/mp_api/client/contribs/settings.py +90 -0
  17. mp_api-0.46.2/mp_api/client/contribs/utils.py +150 -0
  18. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/core/client.py +365 -236
  19. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/core/exceptions.py +4 -0
  20. mp_api-0.46.2/mp_api/client/core/schemas.py +216 -0
  21. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/core/settings.py +6 -0
  22. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/core/utils.py +12 -5
  23. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/mprester.py +185 -103
  24. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/__init__.py +1 -0
  25. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/chemenv.py +12 -12
  26. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/doi.py +1 -0
  27. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/electrodes.py +19 -6
  28. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/electronic_structure.py +150 -39
  29. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/eos.py +24 -8
  30. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/grain_boundaries.py +1 -0
  31. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/materials.py +4 -1
  32. mp_api-0.46.2/mp_api/client/routes/materials/phonon.py +422 -0
  33. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/similarity.py +1 -0
  34. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/substrates.py +1 -0
  35. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/surface_properties.py +1 -0
  36. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/synthesis.py +1 -0
  37. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/tasks.py +13 -22
  38. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/thermo.py +76 -37
  39. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/xas.py +44 -10
  40. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/molecules/__init__.py +1 -0
  41. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/molecules/jcesr.py +1 -0
  42. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/molecules/molecules.py +1 -0
  43. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/molecules/summary.py +1 -0
  44. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/mcp/_schemas.py +2 -2
  45. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/mcp/mp_mcp.py +1 -0
  46. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/mcp/server.py +1 -0
  47. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/mcp/tools.py +4 -3
  48. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api.egg-info/PKG-INFO +17 -5
  49. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api.egg-info/SOURCES.txt +19 -0
  50. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api.egg-info/requires.txt +17 -4
  51. {mp_api-0.46.1rc9 → mp_api-0.46.2}/pyproject.toml +22 -6
  52. {mp_api-0.46.1rc9 → mp_api-0.46.2}/requirements/requirements-ubuntu-latest_py3.11.txt +27 -27
  53. {mp_api-0.46.1rc9 → mp_api-0.46.2}/requirements/requirements-ubuntu-latest_py3.11_extras.txt +159 -136
  54. {mp_api-0.46.1rc9 → mp_api-0.46.2}/requirements/requirements-ubuntu-latest_py3.12.txt +27 -27
  55. {mp_api-0.46.1rc9 → mp_api-0.46.2}/requirements/requirements-ubuntu-latest_py3.12_extras.txt +157 -136
  56. mp_api-0.46.2/requirements/requirements-ubuntu-latest_py3.13.txt +175 -0
  57. mp_api-0.46.2/requirements/requirements-ubuntu-latest_py3.13_extras.txt +698 -0
  58. mp_api-0.46.2/requirements/requirements-ubuntu-latest_py3.14.txt +175 -0
  59. mp_api-0.46.2/requirements/requirements-ubuntu-latest_py3.14_extras.txt +698 -0
  60. mp_api-0.46.2/tests/client/contribs/conftest.py +11 -0
  61. mp_api-0.46.2/tests/client/contribs/test_client.py +59 -0
  62. mp_api-0.46.2/tests/client/contribs/test_contribs_schemas.py +162 -0
  63. mp_api-0.46.2/tests/client/contribs/test_contribs_utils.py +38 -0
  64. mp_api-0.46.2/tests/client/contribs/test_types.py +87 -0
  65. mp_api-0.46.2/tests/client/core/test_schemas.py +108 -0
  66. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_chemenv.py +2 -3
  67. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_electrodes.py +8 -12
  68. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_electronic_structure.py +7 -5
  69. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_eos.py +15 -3
  70. mp_api-0.46.2/tests/client/materials/test_phonon.py +104 -0
  71. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_provenance.py +1 -1
  72. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_summary.py +1 -1
  73. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_thermo.py +3 -3
  74. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_xas.py +13 -10
  75. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/molecules/test_jcesr.py +12 -8
  76. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/molecules/test_summary.py +3 -4
  77. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/test_client.py +5 -2
  78. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/test_core_client.py +5 -4
  79. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/test_mprester.py +162 -131
  80. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/mcp/test_tools.py +1 -1
  81. mp_api-0.46.1rc9/mp_api/client/routes/materials/phonon.py +0 -156
  82. mp_api-0.46.1rc9/tests/client/materials/test_phonon.py +0 -80
  83. {mp_api-0.46.1rc9 → mp_api-0.46.2}/.coveragerc +0 -0
  84. {mp_api-0.46.1rc9 → mp_api-0.46.2}/.gitignore +0 -0
  85. {mp_api-0.46.1rc9 → mp_api-0.46.2}/CODE_OF_CONDUCT.md +0 -0
  86. {mp_api-0.46.1rc9 → mp_api-0.46.2}/LICENSE +0 -0
  87. {mp_api-0.46.1rc9 → mp_api-0.46.2}/README.md +0 -0
  88. {mp_api-0.46.1rc9 → mp_api-0.46.2}/dev/generate_mcp_tools.py +1 -1
  89. {mp_api-0.46.1rc9 → mp_api-0.46.2}/dev/inspect_mcp.sh +0 -0
  90. {mp_api-0.46.1rc9 → mp_api-0.46.2}/docs/Makefile +0 -0
  91. {mp_api-0.46.1rc9 → mp_api-0.46.2}/docs/_templates/custom-class-template.rst +0 -0
  92. {mp_api-0.46.1rc9 → mp_api-0.46.2}/docs/_templates/custom-module-template.rst +0 -0
  93. {mp_api-0.46.1rc9 → mp_api-0.46.2}/docs/index.rst +0 -0
  94. {mp_api-0.46.1rc9 → mp_api-0.46.2}/docs/make.bat +0 -0
  95. {mp_api-0.46.1rc9 → mp_api-0.46.2}/docs/modules.rst +0 -0
  96. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/__init__.py +0 -0
  97. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/_server_utils.py +0 -0
  98. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/core/__init__.py +0 -0
  99. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/core/_oxygen_evolution.py +0 -0
  100. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/__init__.py +0 -0
  101. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/_server.py +0 -0
  102. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/absorption.py +0 -0
  103. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/alloys.py +0 -0
  104. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/bonds.py +0 -0
  105. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/dielectric.py +0 -0
  106. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/elasticity.py +0 -0
  107. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/magnetism.py +0 -0
  108. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/oxidation_states.py +0 -0
  109. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/piezo.py +0 -0
  110. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/provenance.py +0 -0
  111. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/robocrys.py +0 -0
  112. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/client/routes/materials/summary.py +0 -0
  113. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/mcp/__init__.py +0 -0
  114. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/mcp/utils.py +0 -0
  115. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api/py.typed +0 -0
  116. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api.egg-info/dependency_links.txt +0 -0
  117. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api.egg-info/entry_points.txt +0 -0
  118. {mp_api-0.46.1rc9 → mp_api-0.46.2}/mp_api.egg-info/top_level.txt +0 -0
  119. {mp_api-0.46.1rc9 → mp_api-0.46.2}/setup.cfg +0 -0
  120. {mp_api-0.46.1rc9 → mp_api-0.46.2}/test_files/Si_mp_149.cif +0 -0
  121. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/__init__.py +0 -0
  122. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/__init__.py +0 -0
  123. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/core/test_oxygen_evolution.py +0 -0
  124. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/core/test_utils.py +0 -0
  125. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/__init__.py +0 -0
  126. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_absorption.py +0 -0
  127. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_alloys.py +0 -0
  128. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_bonds.py +0 -0
  129. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_dielectric.py +0 -0
  130. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_doi.py +0 -0
  131. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_elasticity.py +0 -0
  132. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_grain_boundary.py +0 -0
  133. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_magnetism.py +0 -0
  134. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_materials.py +0 -0
  135. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_oxidation_states.py +0 -0
  136. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_piezo.py +0 -0
  137. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_robocrys.py +0 -0
  138. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_similarity.py +0 -0
  139. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_substrates.py +0 -0
  140. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_surface_properties.py +0 -0
  141. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_synthesis.py +0 -0
  142. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/materials/test_tasks.py +0 -0
  143. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/molecules/__init__.py +0 -0
  144. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/molecules/test_molecules.py +0 -0
  145. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/client/test_heartbeat.py +0 -0
  146. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/mcp/__init__.py +0 -0
  147. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/mcp/test_server.py +0 -0
  148. {mp_api-0.46.1rc9 → mp_api-0.46.2}/tests/mcp/test_utils.py +0 -0
@@ -18,7 +18,7 @@ jobs:
18
18
  - name: Set up Python
19
19
  uses: actions/setup-python@v4
20
20
  with:
21
- python-version: "3.11"
21
+ python-version: "3.12"
22
22
  cache: pip
23
23
 
24
24
  - name: Install dependencies
@@ -16,7 +16,7 @@ jobs:
16
16
 
17
17
  - uses: actions/setup-python@v5
18
18
  with:
19
- python-version: 3.11
19
+ python-version: 3.12
20
20
 
21
21
  - name: Install dependencies
22
22
  run: |
@@ -36,20 +36,24 @@ jobs:
36
36
 
37
37
  docs:
38
38
  runs-on: ubuntu-latest
39
+
39
40
  needs:
40
41
  - deploy
41
42
 
43
+ env:
44
+ PYTHON_VERSION: 3.12
45
+
42
46
  steps:
43
47
  - uses: actions/checkout@v4
44
48
 
45
49
  - uses: actions/setup-python@v5
46
50
  with:
47
- python-version: 3.11
51
+ python-version: ${{ env.PYTHON_VERSION }}
48
52
 
49
53
  - name: Install dependencies
50
54
  run: |
51
55
  python -m pip install --upgrade pip
52
- pip install -r requirements/requirements-ubuntu-latest_py3.11_extras.txt
56
+ pip install -r requirements/requirements-ubuntu-latest_py${{ env.PYTHON_VERSION }}_extras.txt
53
57
  pip install -e .
54
58
 
55
59
  - name: Build
@@ -17,7 +17,7 @@ jobs:
17
17
  strategy:
18
18
  matrix:
19
19
  os: ["ubuntu-latest"]
20
- python-version: ["3.11", "3.12"]
20
+ python-version: ["3.12", "3.13", "3.14"]
21
21
 
22
22
  runs-on: ${{ matrix.os }}
23
23
 
@@ -43,16 +43,6 @@ jobs:
43
43
  if: matrix.os == 'windows-latest'
44
44
  run: echo "SSL_CERT_FILE=$(python -m certifi)" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
45
45
 
46
- - name: Format API key name (Linux/MacOS)
47
- if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'
48
- run: |
49
- echo "API_KEY_NAME=$(echo ${{ format('MP_API_KEY_{0}_{1}', matrix.os, matrix.python-version) }} | awk '{gsub(/-|\./, "_"); print}' | tr '[:lower:]' '[:upper:]')" >> $GITHUB_ENV
50
-
51
- - name: Format API key name (Windows)
52
- if: matrix.os == 'windows-latest'
53
- run: |
54
- echo "API_KEY_NAME=$(echo ${{ format('MP_API_KEY_{0}_{1}', matrix.os, matrix.python-version) }} | awk '{gsub(/-|\./, "_"); print}' | tr '[:lower:]' '[:upper:]')" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
55
-
56
46
  - name: Lint with mypy
57
47
  shell: bash -l {0}
58
48
  run: python -m mypy mp_api/
@@ -60,7 +50,7 @@ jobs:
60
50
  - name: Test with pytest
61
51
  if: always()
62
52
  env:
63
- MP_API_KEY: ${{ secrets[env.API_KEY_NAME] }}
53
+ MP_API_KEY: ${{ secrets.MP_API_KEY_UBUNTU_LATEST_3_12 }}
64
54
  # MP_API_ENDPOINT: https://api-preview.materialsproject.org/
65
55
  run: |
66
56
  pytest -n auto -x --cov=mp_api --cov-report=xml
@@ -11,7 +11,7 @@ jobs:
11
11
  matrix:
12
12
  os: ['ubuntu-latest']
13
13
  package: ["mp-api"]
14
- python-version: ["3.11", "3.12"]
14
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
15
15
  steps:
16
16
  - uses: actions/checkout@v4
17
17
  with:
@@ -49,7 +49,7 @@ jobs:
49
49
  needs: upgrade
50
50
  strategy:
51
51
  matrix:
52
- python-version: ["3.11"]
52
+ python-version: ["3.12"]
53
53
  steps:
54
54
  - uses: actions/checkout@v4
55
55
  with:
@@ -6,24 +6,24 @@ ci:
6
6
 
7
7
  repos:
8
8
  - repo: https://github.com/astral-sh/ruff-pre-commit
9
- rev: v0.0.292
9
+ rev: v0.15.12
10
10
  hooks:
11
11
  - id: ruff
12
12
  args: [--fix, --show-fixes]
13
13
 
14
14
  - repo: https://github.com/psf/black
15
- rev: 23.9.1
15
+ rev: 26.3.1
16
16
  hooks:
17
17
  - id: black
18
18
 
19
19
  - repo: https://github.com/asottile/blacken-docs
20
- rev: "1.16.0"
20
+ rev: "1.20.0"
21
21
  hooks:
22
22
  - id: blacken-docs
23
23
  additional_dependencies: [black>=23.7.0]
24
24
 
25
25
  - repo: https://github.com/pre-commit/pre-commit-hooks
26
- rev: v4.5.0
26
+ rev: v6.0.0
27
27
  hooks:
28
28
  - id: check-case-conflict
29
29
  - id: check-symlinks
@@ -34,7 +34,7 @@ repos:
34
34
  - id: trailing-whitespace
35
35
 
36
36
  - repo: https://github.com/codespell-project/codespell
37
- rev: v2.2.6
37
+ rev: v2.4.2
38
38
  hooks:
39
39
  - id: codespell
40
40
  stages: [pre-commit, commit-msg]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mp-api
3
- Version: 0.46.1rc9
3
+ Version: 0.46.2
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,21 +17,32 @@ 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.86.5,>=0.86.4rc1
20
+ Requires-Dist: emmet-core<0.87.2,>=0.87.0
21
21
  Requires-Dist: boto3
22
22
  Requires-Dist: orjson<4,>=3.10
23
23
  Requires-Dist: pyarrow>=20.0.0
24
- Requires-Dist: deltalake>=1.4.0
24
+ Requires-Dist: deltalake<1.6.0,>=1.4.0
25
25
  Provides-Extra: mcp
26
26
  Requires-Dist: fastmcp; extra == "mcp"
27
27
  Provides-Extra: server
28
28
  Requires-Dist: flask; extra == "server"
29
+ Provides-Extra: contribs
30
+ Requires-Dist: boltons; extra == "contribs"
31
+ Requires-Dist: bravado; extra == "contribs"
32
+ Requires-Dist: filetype; extra == "contribs"
33
+ Requires-Dist: ipython; extra == "contribs"
34
+ Requires-Dist: json2html; extra == "contribs"
35
+ Requires-Dist: pint>=0.25.0; extra == "contribs"
36
+ Requires-Dist: pyIsEmail; extra == "contribs"
37
+ Requires-Dist: requests-futures; extra == "contribs"
38
+ Requires-Dist: swagger-spec-validator; extra == "contribs"
39
+ Requires-Dist: cachetools; extra == "contribs"
40
+ Requires-Dist: pymongo; extra == "contribs"
29
41
  Provides-Extra: all
30
42
  Requires-Dist: custodian; extra == "all"
31
- Requires-Dist: emmet-core[all]<0.86.5,>=0.86.4rc1; extra == "all"
43
+ Requires-Dist: emmet-core[all]<0.87.2,>=0.87.0; extra == "all"
32
44
  Requires-Dist: fastmcp; extra == "all"
33
45
  Requires-Dist: flask; extra == "all"
34
- Requires-Dist: mpcontribs-client>=5.10; extra == "all"
35
46
  Provides-Extra: test
36
47
  Requires-Dist: pre-commit; extra == "test"
37
48
  Requires-Dist: pytest; extra == "test"
@@ -46,6 +57,7 @@ Requires-Dist: mypy-extensions; extra == "test"
46
57
  Requires-Dist: typing-extensions; extra == "test"
47
58
  Requires-Dist: types-setuptools; extra == "test"
48
59
  Requires-Dist: types-requests; extra == "test"
60
+ Requires-Dist: types-tqdm; extra == "test"
49
61
  Provides-Extra: docs
50
62
  Requires-Dist: sphinx; extra == "docs"
51
63
  Dynamic: license-file
@@ -6,6 +6,8 @@
6
6
  # -- Project information -----------------------------------------------------
7
7
  # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
8
8
 
9
+ from __future__ import annotations
10
+
9
11
  project = "mp-api"
10
12
  copyright = "2022, The Materials Project"
11
13
  author = "The Materials Project"
@@ -4,6 +4,8 @@
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
+ from enum import Enum
8
+
7
9
  try:
8
10
  import pytest
9
11
  except ImportError as exc:
@@ -86,19 +88,64 @@ def client_search_testing(
86
88
  assert doc[alt_name_dict.get(param, param)] is not None
87
89
 
88
90
 
89
- def client_pagination(search_method: Callable, id_name: str):
90
- page_1 = search_method(_page=1, chunk_size=NUM_DOCS, fields=[id_name])
91
- page_2 = search_method(_page=2, chunk_size=NUM_DOCS, fields=[id_name])
91
+ def client_pagination(
92
+ search_method: Callable, id_name: str, additional_fields: list[str] | None = None
93
+ ) -> None:
94
+ """Test pagination on an endpoint.
95
+
96
+ Args:
97
+ search_method (Callable) : Client search method to use
98
+ id_name (str) : the name of a field which uniquely indexes a series of documents
99
+ additional_fields (list of str) : Optional other fields to retrieve.
100
+
101
+ Raises:
102
+ AssertionError if pagination does not result in unique sets of documents
103
+ """
104
+ fields = [id_name, *(additional_fields or [])]
105
+ page_1 = search_method(_page=1, chunk_size=NUM_DOCS, fields=fields)
106
+ page_2 = search_method(_page=2, chunk_size=NUM_DOCS, fields=fields)
92
107
  assert all(len(results) == NUM_DOCS for results in (page_1, page_2))
93
108
  assert {str(getattr(doc, id_name)) for doc in page_1}.intersection(
94
109
  {str(getattr(doc, id_name)) for doc in page_2}
95
110
  ) == set()
96
111
 
97
112
 
98
- def client_sort(search_method: Callable, sort_fields: str | Sequence[str]):
113
+ def client_sort(
114
+ search_method: Callable,
115
+ sort_fields: str | Sequence[str],
116
+ aux_query: dict[str, Any] | None = None,
117
+ default_fields: tuple[str, ...] = ("deprecated", "material_id"),
118
+ ):
119
+ """Test sorting on an endpoint.
120
+
121
+ Args:
122
+ search_method (Callable) : Client search method to use
123
+ sort_fields (str or Sequence of str) : fields to sort on
124
+ aux_query (dict) : auxiliary query needed to filter documents
125
+ default_fields (list): default fields to return
126
+
127
+ Raises:
128
+ AssertionError if sorting in ascending or descending order does not work.
129
+ """
130
+
131
+ def _normalize(doc, field: str):
132
+ v = getattr(doc, field)
133
+ # serialize enums
134
+ return v.value if isinstance(v, Enum) else v
135
+
136
+ user_query = {
137
+ k: v
138
+ for k, v in (aux_query or {}).items()
139
+ if k not in ("_page", "_sort_fields", "chunk_size", "fields")
140
+ }
99
141
  for sort_field in [sort_fields] if isinstance(sort_fields, str) else sort_fields:
142
+
100
143
  asc = search_method(
101
- _page=1, _sort_fields=sort_field, chunk_size=NUM_DOCS, fields=[sort_field]
144
+ _page=1,
145
+ _sort_fields=sort_field,
146
+ chunk_size=NUM_DOCS,
147
+ fields=[sort_field, *default_fields],
148
+ **user_query,
102
149
  )
103
150
  desc = search_method(
104
151
  _page=1,
@@ -108,12 +155,12 @@ def client_sort(search_method: Callable, sort_fields: str | Sequence[str]):
108
155
  )
109
156
 
110
157
  idxs = list(range(NUM_DOCS))
111
- assert sorted(idxs, key=lambda idx: getattr(asc[idx], sort_field)) == idxs
158
+ assert sorted(idxs, key=lambda idx: _normalize(asc[idx], sort_field)) == idxs
112
159
 
113
160
  assert (
114
161
  sorted(
115
162
  idxs,
116
- key=lambda idx: getattr(desc[idx], sort_field),
163
+ key=lambda idx: _normalize(desc[idx], sort_field),
117
164
  reverse=True,
118
165
  )
119
166
  == idxs
@@ -1,4 +1,5 @@
1
1
  """Primary MAPI module."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import logging
@@ -0,0 +1,16 @@
1
+ """Pull in core MPContribs client features."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from mp_api.client.contribs._types import Attachment, Table
6
+ from mp_api.client.contribs.client import ContribsClient
7
+ from mp_api.client.contribs.settings import MPCC_SETTINGS
8
+ from mp_api.client.core.exceptions import MPContribsClientError
9
+
10
+ __all__ = [
11
+ "ContribsClient",
12
+ "MPContribsClientError",
13
+ "MPCC_SETTINGS",
14
+ "Table",
15
+ "Attachment",
16
+ ]
@@ -0,0 +1,97 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import os
5
+ import sys
6
+ from io import StringIO
7
+
8
+ from mp_api.client.contribs.settings import MPCC_SETTINGS
9
+
10
+
11
+ class LogFilter(logging.Filter):
12
+ def __init__(self, level: int, *args, **kwargs) -> None:
13
+ """Start an instance of logging.Filter.
14
+
15
+ Args:
16
+ level (int) : logging level
17
+ *args : args to pass to logging.Filter
18
+ **kwargs : kwargs to pass to logging.Filter
19
+ """
20
+ self.level = level
21
+ super().__init__(*args, **kwargs)
22
+
23
+ def filter(self, record: logging.LogRecord) -> bool:
24
+ """Filter whether a message is logged.
25
+
26
+ Args:
27
+ record (logging.LogRecord) : message to test if it
28
+ meets threshold for logging.
29
+
30
+ Returns:
31
+ bool : True if message should be suppressed.
32
+ """
33
+ return record.levelno < self.level
34
+
35
+
36
+ class CustomLoggerAdapter(logging.LoggerAdapter):
37
+ """Adapter for logger to enable prefixing."""
38
+
39
+ def process(self, msg, kwargs):
40
+ """Prefix logging message.
41
+
42
+ Args:
43
+ msg (str) : logging message
44
+ kwargs : args to pass to logging.LoggerAdapter
45
+ """
46
+ prefix = self.extra.get("prefix")
47
+ return f"[{prefix}] {msg}" if prefix else msg, kwargs
48
+
49
+
50
+ def get_logger(name: str = "mp_api.client.contribs") -> CustomLoggerAdapter:
51
+ """Get the default MPContribs logger.
52
+
53
+ Args:
54
+ name (str) : name of the logger
55
+ Returns:
56
+ CustomLoggerAdapter
57
+ """
58
+ logger = logging.getLogger(name)
59
+ process = os.environ.get("SUPERVISOR_PROCESS_NAME")
60
+ group = os.environ.get("SUPERVISOR_GROUP_NAME")
61
+ cfg = {"prefix": f"{group}/{process}"} if process and group else {}
62
+ info_handler = logging.StreamHandler(sys.stdout)
63
+ error_handler = logging.StreamHandler(sys.stderr)
64
+ info_handler.addFilter(LogFilter(logging.WARNING))
65
+ error_handler.setLevel(max(logging.DEBUG, logging.WARNING))
66
+ logger.handlers = [info_handler, error_handler]
67
+ logger.setLevel(MPCC_SETTINGS.CLIENT_LOG_LEVEL)
68
+ return CustomLoggerAdapter(logger, cfg)
69
+
70
+
71
+ MPCC_LOGGER = get_logger()
72
+
73
+
74
+ class TqdmToLogger(StringIO):
75
+ logger: logging.LoggerAdapter = MPCC_LOGGER
76
+ level: int | str = MPCC_SETTINGS.CLIENT_LOG_LEVEL
77
+ buf: str = ""
78
+
79
+ def __init__(
80
+ self, logger: logging.LoggerAdapter = MPCC_LOGGER, level: int | None = None
81
+ ) -> None:
82
+ """Start an instance of a TQDM logger.
83
+
84
+ Args:
85
+ logger (logging.Logger) : Logger to pass through
86
+ level (int) : logging level
87
+ """
88
+ super().__init__()
89
+ self.logger = logger
90
+ self.level = level or logging.INFO
91
+
92
+ def write(self, buf: str) -> int:
93
+ self.buf = buf.strip("\r\n\t ")
94
+ return 1
95
+
96
+ def flush(self) -> None:
97
+ self.logger.log(self.level, self.buf) # type: ignore[arg-type]