emmet-api 0.87.0.dev10__tar.gz → 0.87.0.dev11__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.
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/Dockerfile +2 -1
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/PKG-INFO +5 -5
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/query_operator/__init__.py +2 -1
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/query_operator/pagination.py +64 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/resource/__init__.py +2 -0
- emmet_api-0.87.0.dev11/emmet/api/resource/search_resource.py +144 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/resource/utils.py +43 -45
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/electronic_structure/query_operators.py +2 -1
- emmet_api-0.87.0.dev11/emmet/api/routes/materials/materials/utils.py +271 -0
- emmet_api-0.87.0.dev11/emmet/api/routes/materials/tasks/query_operators.py +330 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/tasks/resources.py +14 -16
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/tasks/query_operators.py +1 -1
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/utils.py +2 -12
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet_api.egg-info/PKG-INFO +5 -5
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet_api.egg-info/SOURCES.txt +1 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet_api.egg-info/requires.txt +3 -3
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/pyproject.toml +4 -4
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/requirements/deployment.txt +37 -42
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/requirements/ubuntu-latest_py3.11.txt +39 -41
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/requirements/ubuntu-latest_py3.11_extras.txt +58 -60
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/requirements/ubuntu-latest_py3.12.txt +39 -41
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/requirements/ubuntu-latest_py3.12_extras.txt +58 -60
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/requirements/ubuntu-latest_py3.13.txt +40 -42
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/requirements/ubuntu-latest_py3.13_extras.txt +58 -60
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/mapi/test_utils.py +22 -27
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/electronic_structure/test_query_operators.py +3 -4
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/tasks/test_query_operators.py +1 -1
- emmet_api-0.87.0.dev10/emmet/api/routes/materials/materials/utils.py +0 -148
- emmet_api-0.87.0.dev10/emmet/api/routes/materials/tasks/query_operators.py +0 -197
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/app.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/defect_resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/API.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/core/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/core/api.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/core/assets/mp_logo.svg +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/core/assets/mp_logo_small.png +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/core/documentation.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/core/global_header.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/core/settings.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/default_responses.yaml +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/models.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/py.typed +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/query_operator/core.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/query_operator/dynamic.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/query_operator/sorting.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/query_operator/sparse_fields.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/query_operator/submission.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/resource/aggregation.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/resource/core.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/resource/post_resource.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/resource/read_resource.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/resource/submission.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/_consumer/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/_consumer/query_operator.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/_consumer/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/_general_store/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/_general_store/query_operator.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/_general_store/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/_messages/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/_messages/query_operator.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/_messages/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/defects/tasks/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/defects/tasks/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/dois/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/dois/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/legacy/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/legacy/jcesr/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/legacy/jcesr/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/legacy/jcesr/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/absorption/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/absorption/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/alloys/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/alloys/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/alloys/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/bonds/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/bonds/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/bonds/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/charge_density/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/charge_density/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/charge_density/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/chemenv/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/chemenv/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/chemenv/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/conversion_electrodes/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/conversion_electrodes/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/dielectric/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/dielectric/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/dielectric/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/elasticity/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/elasticity/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/elasticity/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/electronic_structure/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/electronic_structure/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/eos/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/eos/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/fermi/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/fermi/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/grain_boundary/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/grain_boundary/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/grain_boundary/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/insertion_electrodes/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/insertion_electrodes/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/insertion_electrodes/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/insertion_electrodes/utils.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/magnetism/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/magnetism/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/magnetism/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/materials/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/materials/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/materials/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/mpcomplete/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/mpcomplete/query_operator.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/mpcomplete/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/oxidation_states/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/oxidation_states/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/oxidation_states/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/phonon/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/phonon/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/phonon/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/piezo/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/piezo/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/piezo/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/provenance/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/provenance/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/robocrys/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/robocrys/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/robocrys/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/similarity/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/similarity/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/similarity/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/substrates/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/substrates/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/substrates/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/summary/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/summary/hint_scheme.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/summary/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/summary/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/surface_properties/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/surface_properties/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/surface_properties/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/synthesis/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/synthesis/data_adaptor.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/synthesis/data_adaptor_synpro.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/synthesis/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/synthesis/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/synthesis/utils.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/tasks/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/tasks/hint_scheme.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/tasks/utils.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/thermo/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/thermo/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/thermo/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/xas/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/xas/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/materials/xas/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/association/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/association/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/bonds/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/bonds/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/bonds/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/electric/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/electric/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/electric/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/metal_binding/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/metal_binding/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/metal_binding/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/molecules/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/molecules/hint_scheme.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/molecules/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/molecules/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/orbitals/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/orbitals/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/partial_charges/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/partial_charges/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/partial_spins/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/partial_spins/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/redox/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/redox/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/redox/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/summary/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/summary/hint_scheme.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/summary/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/summary/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/tasks/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/tasks/hint_scheme.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/tasks/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/tasks/utils.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/thermo/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/thermo/query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/thermo/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/utils.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/vibrations/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet/api/routes/molecules/vibrations/resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet_api.egg-info/dependency_links.txt +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/emmet_api.egg-info/top_level.txt +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/healthcheck.sh +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/material_resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/molecule_resources.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/setup.cfg +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/start.sh +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/_consumer/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/_consumer/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/_general_store/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/_general_store/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/async_mongomock.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/conftest.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/core/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/core/test_mapi.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/legacy/molecules/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/legacy/molecules/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/mapi/test_aggregation_resource.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/mapi/test_api.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/mapi/test_post_resource.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/mapi/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/mapi/test_read_resource.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/mapi/test_submission_resource.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/bonds/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/bonds/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/charge_density/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/charge_density/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/chemenv/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/chemenv/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/dielectric/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/dielectric/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/elasticity/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/elasticity/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/electrodes/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/electrodes/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/electrodes/test_utils.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/electronic_structure/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/eos/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/grain_boundary/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/grain_boundary/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/magnetism/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/magnetism/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/materials/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/materials/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/materials/test_utils.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/mpcomplete/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/mpcomplete/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/oxidation_states/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/oxidation_states/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/piezo/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/piezo/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/robocrys/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/robocrys/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/similarity/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/similarity/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/substrates/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/substrates/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/summary/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/summary/test_hint_scheme.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/summary/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/surface_properties/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/surface_properties/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/synthesis/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/synthesis/test_adaptor.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/synthesis/test_adaptor_synpro.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/synthesis/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/synthesis/test_utils.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/tasks/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/tasks/test_utils.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/thermo/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/thermo/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/xas/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/materials/xas/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/bonds/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/bonds/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/electric/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/electric/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/metal_binding/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/metal_binding/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/molecules/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/molecules/test_hint_scheme.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/molecules/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/redox/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/redox/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/summary/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/summary/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/tasks/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/tasks/test_hint_scheme.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/tasks/test_query_operators.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/tasks/test_utils.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/thermo/__init__.py +0 -0
- {emmet_api-0.87.0.dev10 → emmet_api-0.87.0.dev11}/tests/molecules/thermo/test_query_operators.py +0 -0
|
@@ -18,7 +18,8 @@ RUN wget -q https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-
|
|
|
18
18
|
chmod +x wait-for-it.sh && mv wait-for-it.sh /root/.local/bin/
|
|
19
19
|
|
|
20
20
|
FROM base
|
|
21
|
-
ARG BUILDARCH
|
|
21
|
+
ARG BUILDARCH
|
|
22
|
+
ENV BUILDARCH=x86_64
|
|
22
23
|
COPY --from=builder /root/.local/lib/python3.11/site-packages /root/.local/lib/python3.11/site-packages
|
|
23
24
|
COPY --from=builder /root/.local/bin /root/.local/bin
|
|
24
25
|
COPY --from=builder /usr/lib/$BUILDARCH-linux-gnu/libsnappy* /usr/lib/$BUILDARCH-linux-gnu/
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: emmet-api
|
|
3
|
-
Version: 0.87.0.
|
|
3
|
+
Version: 0.87.0.dev11
|
|
4
4
|
Summary: Emmet API Server
|
|
5
5
|
Author-email: The Materials Project <feedback@materialsproject.org>
|
|
6
|
-
License:
|
|
6
|
+
License-Expression: BSD-3-Clause-LBNL
|
|
7
7
|
Project-URL: Homepage, https://github.com/materialsproject/emmet/tree/main/emmet-api/
|
|
8
8
|
Project-URL: Documentation, https://materialsproject.github.io/emmet/
|
|
9
9
|
Requires-Python: >=3.11
|
|
10
|
-
Requires-Dist: emmet-core
|
|
10
|
+
Requires-Dist: emmet-core<0.87.0,>=0.86.3rc1
|
|
11
11
|
Requires-Dist: fastapi>=0.123.1
|
|
12
|
-
Requires-Dist: gunicorn
|
|
12
|
+
Requires-Dist: gunicorn==24.1.1
|
|
13
13
|
Requires-Dist: boto3
|
|
14
|
-
Requires-Dist: ddtrace
|
|
14
|
+
Requires-Dist: ddtrace==4.3.0
|
|
15
15
|
Requires-Dist: setproctitle
|
|
16
16
|
Requires-Dist: shapely
|
|
17
17
|
Requires-Dist: asgi-logger
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from emmet.api.query_operator.core import QueryOperator
|
|
2
2
|
from emmet.api.query_operator.dynamic import NumericQuery, StringQueryOperator
|
|
3
|
-
from emmet.api.query_operator.pagination import PaginationQuery
|
|
3
|
+
from emmet.api.query_operator.pagination import AtlasPaginationQuery, PaginationQuery
|
|
4
4
|
from emmet.api.query_operator.sorting import SortQuery
|
|
5
5
|
from emmet.api.query_operator.sparse_fields import SparseFieldsQuery
|
|
6
6
|
from emmet.api.query_operator.submission import SubmissionQuery
|
|
@@ -9,6 +9,7 @@ __all__ = [
|
|
|
9
9
|
"QueryOperator",
|
|
10
10
|
"NumericQuery",
|
|
11
11
|
"StringQueryOperator",
|
|
12
|
+
"AtlasPaginationQuery",
|
|
12
13
|
"PaginationQuery",
|
|
13
14
|
"SortQuery",
|
|
14
15
|
"SparseFieldsQuery",
|
|
@@ -4,6 +4,70 @@ from emmet.api.query_operator import QueryOperator
|
|
|
4
4
|
from emmet.api.utils import STORE_PARAMS
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
class AtlasPaginationQuery(QueryOperator):
|
|
8
|
+
"""Query operators to provides pagination for Atlas Search queries."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, default_limit: int = 100, max_limit: int = 1000):
|
|
11
|
+
"""
|
|
12
|
+
Args:
|
|
13
|
+
default_limit: the default number of documents to return
|
|
14
|
+
max_limit: max number of documents to return.
|
|
15
|
+
"""
|
|
16
|
+
self.default_limit = default_limit
|
|
17
|
+
self.max_limit = max_limit
|
|
18
|
+
|
|
19
|
+
def query(
|
|
20
|
+
_forward: bool = Query(
|
|
21
|
+
True,
|
|
22
|
+
description="Whether to page forward (True) or backward (False) in the search results.",
|
|
23
|
+
),
|
|
24
|
+
_pagination_token: str = Query(
|
|
25
|
+
None, description="Pagination token for the next set of results."
|
|
26
|
+
),
|
|
27
|
+
_skip: int = Query(
|
|
28
|
+
0,
|
|
29
|
+
description="Number of entries to skip in the search.",
|
|
30
|
+
),
|
|
31
|
+
_limit: int = Query(
|
|
32
|
+
default_limit,
|
|
33
|
+
description=f"Max number of entries to return in a single query. Limited to {max_limit}.",
|
|
34
|
+
),
|
|
35
|
+
) -> STORE_PARAMS:
|
|
36
|
+
"""
|
|
37
|
+
Pagination parameters for the API Endpoint.
|
|
38
|
+
"""
|
|
39
|
+
if _limit > max_limit:
|
|
40
|
+
raise HTTPException(
|
|
41
|
+
status_code=400,
|
|
42
|
+
detail="Requested more data per query than allowed by this endpoint."
|
|
43
|
+
f" The max limit is {max_limit} entries",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
if _skip < 0 or _limit < 0:
|
|
47
|
+
raise HTTPException(
|
|
48
|
+
status_code=400,
|
|
49
|
+
detail="Cannot request negative _skip or _limit values",
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
"forward": _forward,
|
|
54
|
+
"pagination_token": _pagination_token,
|
|
55
|
+
"skip": _skip,
|
|
56
|
+
"limit": _limit,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
self.query = query # type: ignore
|
|
60
|
+
|
|
61
|
+
def query(self):
|
|
62
|
+
"""Stub query function for abstract class."""
|
|
63
|
+
|
|
64
|
+
def meta(self) -> dict:
|
|
65
|
+
"""
|
|
66
|
+
Metadata for the pagination params.
|
|
67
|
+
"""
|
|
68
|
+
return {"max_limit": self.max_limit}
|
|
69
|
+
|
|
70
|
+
|
|
7
71
|
class PaginationQuery(QueryOperator):
|
|
8
72
|
"""Query operators to provides Pagination."""
|
|
9
73
|
|
|
@@ -12,6 +12,7 @@ from emmet.api.resource.aggregation import AggregationResource
|
|
|
12
12
|
from emmet.api.resource.post_resource import PostOnlyResource
|
|
13
13
|
from emmet.api.resource.read_resource import ReadOnlyResource, attach_query_ops
|
|
14
14
|
from emmet.api.resource.submission import SubmissionResource
|
|
15
|
+
from emmet.api.resource.search_resource import SearchResource
|
|
15
16
|
|
|
16
17
|
__all__ = [
|
|
17
18
|
"Resource",
|
|
@@ -23,4 +24,5 @@ __all__ = [
|
|
|
23
24
|
"ReadOnlyResource",
|
|
24
25
|
"attach_query_ops",
|
|
25
26
|
"SubmissionResource",
|
|
27
|
+
"SearchResource",
|
|
26
28
|
]
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from inspect import signature
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import orjson
|
|
5
|
+
from fastapi import HTTPException, Request, Response
|
|
6
|
+
from pymongo.errors import NetworkTimeout, PyMongoError
|
|
7
|
+
|
|
8
|
+
from emmet.api.models import Meta
|
|
9
|
+
from emmet.api.query_operator import QueryOperator
|
|
10
|
+
from emmet.api.resource import CollectionResource
|
|
11
|
+
from emmet.api.resource.utils import (
|
|
12
|
+
attach_query_ops,
|
|
13
|
+
generate_atlas_search_pipeline,
|
|
14
|
+
)
|
|
15
|
+
from emmet.api.utils import STORE_PARAMS, merge_atlas_queries, serialization_helper
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SearchResource(CollectionResource):
|
|
19
|
+
"""
|
|
20
|
+
Implements a REST Compatible Resource as a GET URL endpoint
|
|
21
|
+
This class provides a number of convenience features
|
|
22
|
+
including full pagination, field projection.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
*args,
|
|
28
|
+
disable_validation: bool = False,
|
|
29
|
+
enable_default_search: bool = True,
|
|
30
|
+
query_to_configure_on_request: QueryOperator | None = None,
|
|
31
|
+
**kwargs,
|
|
32
|
+
):
|
|
33
|
+
"""
|
|
34
|
+
Args:
|
|
35
|
+
disable_validation: Whether to use ORJSON and provide a direct FastAPI response.
|
|
36
|
+
Note this will disable auto JSON serialization and response validation with the
|
|
37
|
+
provided model.
|
|
38
|
+
enable_default_search: Enable default endpoint search behavior.
|
|
39
|
+
query_to_configure_on_request: Query operator to configure on request
|
|
40
|
+
"""
|
|
41
|
+
self.disable_validation = disable_validation
|
|
42
|
+
self.enable_default_search = enable_default_search
|
|
43
|
+
self.query_to_configure_on_request = query_to_configure_on_request
|
|
44
|
+
|
|
45
|
+
super().__init__(*args, **kwargs)
|
|
46
|
+
|
|
47
|
+
def prepare_endpoint(self):
|
|
48
|
+
"""
|
|
49
|
+
Internal method to prepare the endpoint by setting up default handlers
|
|
50
|
+
for routes.
|
|
51
|
+
"""
|
|
52
|
+
if self.enable_default_search:
|
|
53
|
+
self.build_dynamic_model_search()
|
|
54
|
+
|
|
55
|
+
def build_dynamic_model_search(self):
|
|
56
|
+
model_name = self.model.__name__
|
|
57
|
+
|
|
58
|
+
async def search(**queries: dict[str, STORE_PARAMS]) -> dict | Response:
|
|
59
|
+
|
|
60
|
+
request: Request = queries.pop("request") # type: ignore
|
|
61
|
+
temp_response: Response = queries.pop("temp_response") # type: ignore
|
|
62
|
+
|
|
63
|
+
if self.query_to_configure_on_request is not None:
|
|
64
|
+
# give the key name "request", arbitrary choice, as only the value gets merged into the query
|
|
65
|
+
queries["groups"] = self.header_processor.configure_query_on_request( # type: ignore
|
|
66
|
+
request=request, query_operator=self.query_to_configure_on_request
|
|
67
|
+
)
|
|
68
|
+
# allowed query parameters
|
|
69
|
+
query_params = [
|
|
70
|
+
entry
|
|
71
|
+
for _, i in enumerate(self.query_operators)
|
|
72
|
+
for entry in signature(i.query).parameters
|
|
73
|
+
]
|
|
74
|
+
# check for overlap between allowed query parameters and request query parameters
|
|
75
|
+
overlap = [key for key in request.query_params if key not in query_params]
|
|
76
|
+
if any(overlap):
|
|
77
|
+
if "limit" in overlap or "skip" in overlap:
|
|
78
|
+
raise HTTPException(
|
|
79
|
+
status_code=400,
|
|
80
|
+
detail="'limit' and 'skip' parameters have been renamed. "
|
|
81
|
+
"Please update your API client to the newest version.",
|
|
82
|
+
)
|
|
83
|
+
else:
|
|
84
|
+
raise HTTPException(
|
|
85
|
+
status_code=400,
|
|
86
|
+
detail="Request contains query parameters which cannot be used: {}".format(
|
|
87
|
+
", ".join(overlap)
|
|
88
|
+
),
|
|
89
|
+
)
|
|
90
|
+
query: dict[Any, Any] = merge_atlas_queries(list(queries.values())) # type: ignore
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
pipeline = generate_atlas_search_pipeline(query)
|
|
94
|
+
cursor = await self.collection.aggregate(pipeline)
|
|
95
|
+
data = await cursor.to_list()
|
|
96
|
+
except (NetworkTimeout, PyMongoError) as e:
|
|
97
|
+
raise HTTPException(
|
|
98
|
+
status_code=504 if e.timeout else 500,
|
|
99
|
+
detail=f"Server error: {e}",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# results are returned reversed when paginating backwards so we need to fix that
|
|
103
|
+
reverse = any(
|
|
104
|
+
"$search" in p and "searchBefore" in p["$search"] for p in pipeline
|
|
105
|
+
)
|
|
106
|
+
if reverse:
|
|
107
|
+
data = list(reversed(data))
|
|
108
|
+
|
|
109
|
+
operator_meta = {}
|
|
110
|
+
|
|
111
|
+
for operator in self.query_operators:
|
|
112
|
+
data = operator.post_process(data, query)
|
|
113
|
+
operator_meta.update(operator.meta())
|
|
114
|
+
|
|
115
|
+
if data and "meta" in data[0] and data[0]["meta"]:
|
|
116
|
+
meta = Meta(
|
|
117
|
+
total_doc=data[0]["meta"].get("count", {}).get("total", 1),
|
|
118
|
+
facet=data[0]["meta"].get("facet", {}),
|
|
119
|
+
pagination_token=data[-1].get("meta_pagination_token", ""),
|
|
120
|
+
)
|
|
121
|
+
else:
|
|
122
|
+
meta = Meta(total_doc=0)
|
|
123
|
+
|
|
124
|
+
response = {"data": data if data else [], "meta": {**meta.dict(), **operator_meta}} # type: ignore
|
|
125
|
+
|
|
126
|
+
if self.disable_validation:
|
|
127
|
+
response = Response(orjson.dumps(response, default=serialization_helper)) # type: ignore
|
|
128
|
+
|
|
129
|
+
if self.header_processor is not None:
|
|
130
|
+
if self.disable_validation:
|
|
131
|
+
self.header_processor.process_header(response, request)
|
|
132
|
+
else:
|
|
133
|
+
self.header_processor.process_header(temp_response, request)
|
|
134
|
+
|
|
135
|
+
return response
|
|
136
|
+
|
|
137
|
+
self.router.get(
|
|
138
|
+
self.sub_path,
|
|
139
|
+
tags=self.tags,
|
|
140
|
+
summary=f"Get {model_name} documents",
|
|
141
|
+
response_model=self.response_model,
|
|
142
|
+
response_description=f"Search for a {model_name}",
|
|
143
|
+
response_model_exclude_unset=True,
|
|
144
|
+
)(attach_query_ops(search, self.query_operators))
|
|
@@ -6,8 +6,6 @@ from emmet.api.query_operator import QueryOperator
|
|
|
6
6
|
from emmet.api.utils import STORE_PARAMS, attach_signature
|
|
7
7
|
from pymongo.asynchronous.collection import AsyncCollection
|
|
8
8
|
|
|
9
|
-
NON_STORED_SOURCES = ["calcs_reversed", "orig_inputs"]
|
|
10
|
-
|
|
11
9
|
|
|
12
10
|
class CollectionWithKey:
|
|
13
11
|
|
|
@@ -74,62 +72,62 @@ def generate_query_pipeline(query: dict):
|
|
|
74
72
|
def generate_atlas_search_pipeline(query: dict):
|
|
75
73
|
"""
|
|
76
74
|
Generate the aggregation pipeline for Atlas Search queries.
|
|
77
|
-
|
|
78
|
-
Args:
|
|
79
|
-
query: Query parameters
|
|
80
|
-
store: Store containing endpoint data
|
|
81
75
|
"""
|
|
82
76
|
pipeline = []
|
|
77
|
+
operator: dict = {}
|
|
83
78
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
79
|
+
if not query.get("criteria"):
|
|
80
|
+
operator = {"exists": {"path": "_id"}}
|
|
81
|
+
else:
|
|
82
|
+
operator = {"compound": {"must": [], "mustNot": []}}
|
|
83
|
+
|
|
84
|
+
# Build the must clauses
|
|
85
|
+
for q in query["criteria"]:
|
|
86
|
+
if not q.get("mustNot", False):
|
|
87
|
+
if "must" in q:
|
|
88
|
+
# If q has a "must" key, expand its contents instead of using q directly
|
|
89
|
+
operator["compound"]["must"].extend(q["must"])
|
|
90
|
+
else:
|
|
91
|
+
# Use the query as-is
|
|
92
|
+
operator["compound"]["must"].append(q)
|
|
93
|
+
else:
|
|
94
|
+
operator["compound"]["mustNot"].extend(q["mustNot"])
|
|
95
|
+
|
|
96
|
+
search_base = {
|
|
97
|
+
"$search": {
|
|
98
|
+
"index": "default",
|
|
99
|
+
"returnStoredSource": True,
|
|
100
|
+
"count": {"type": "total"},
|
|
88
101
|
}
|
|
89
102
|
}
|
|
90
|
-
# append the mustNot criteria to the compound operator
|
|
91
|
-
operator["compound"]["mustNot"] = [
|
|
92
|
-
q["mustNot"] for q in query["criteria"] if q.get("mustNot", False)
|
|
93
|
-
]
|
|
94
|
-
|
|
95
|
-
if query.get("facets", False):
|
|
96
|
-
pipeline.append(
|
|
97
|
-
{
|
|
98
|
-
"$search": {
|
|
99
|
-
"index": "default",
|
|
100
|
-
"facet": {"operator": operator, "facets": query["facets"]},
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
)
|
|
104
|
-
else:
|
|
105
|
-
pipeline.append({"$search": {"index": "default", **operator}})
|
|
106
|
-
# add returnedStoredSource: True if non-stored source are not present in "properties"
|
|
107
|
-
# for quicker document retrieval, otherwise, do a full lookup
|
|
108
|
-
return_stored_source = not any(
|
|
109
|
-
prop in NON_STORED_SOURCES for prop in query.get("properties", [])
|
|
110
|
-
)
|
|
111
|
-
if return_stored_source:
|
|
112
|
-
pipeline[0]["$search"]["returnStoredSource"] = True # type: ignore
|
|
113
103
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
104
|
+
if p_token := query.get("pagination_token", None):
|
|
105
|
+
search_base["$search"][
|
|
106
|
+
f"search{'After' if query.get('forward', True) else 'Before'}"
|
|
107
|
+
] = p_token
|
|
108
|
+
|
|
109
|
+
search_base["$search"].update(operator)
|
|
110
|
+
|
|
111
|
+
sort_dict = {"sort": {"_id": 1}}
|
|
112
|
+
if query.get("sort", False):
|
|
113
|
+
sort_dict["sort"] = {**sort_dict["sort"], **query["sort"]}
|
|
114
|
+
# add sort to $search stage
|
|
115
|
+
search_base["$search"].update(sort_dict)
|
|
121
116
|
|
|
122
|
-
|
|
117
|
+
pipeline.append(search_base)
|
|
118
|
+
|
|
119
|
+
projection_dict = {
|
|
120
|
+
"_id": 0,
|
|
121
|
+
"meta": "$$SEARCH_META",
|
|
122
|
+
"meta_pagination_token": {"$meta": "searchSequenceToken"},
|
|
123
|
+
}
|
|
123
124
|
if query.get("properties", False):
|
|
124
125
|
projection_dict.update({p: 1 for p in query["properties"]})
|
|
125
|
-
pipeline.
|
|
126
|
+
pipeline.append({"$project": projection_dict}) # type: ignore
|
|
126
127
|
|
|
127
128
|
pipeline.append({"$skip": query.get("skip", 0)})
|
|
128
129
|
|
|
129
130
|
if query.get("limit", False):
|
|
130
131
|
pipeline.append({"$limit": query["limit"]})
|
|
131
132
|
|
|
132
|
-
if query.get("facets", False):
|
|
133
|
-
pipeline.append({"$facet": {"docs": [], "meta": [{"$replaceWith": "$$SEARCH_META"}, {"$limit": 1}]}}) # type: ignore
|
|
134
|
-
|
|
135
133
|
return pipeline
|
|
@@ -10,7 +10,8 @@ from pymatgen.analysis.magnetism.analyzer import Ordering
|
|
|
10
10
|
from pymatgen.core.periodic_table import Element
|
|
11
11
|
from pymatgen.electronic_structure.core import OrbitalType, Spin
|
|
12
12
|
|
|
13
|
-
from emmet.core.
|
|
13
|
+
from emmet.core.band_theory import BSPathType
|
|
14
|
+
from emmet.core.electronic_structure import DOSProjectionType
|
|
14
15
|
from emmet.core.mpid import MPID, AlphaID
|
|
15
16
|
|
|
16
17
|
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from fastapi import HTTPException
|
|
3
|
+
from pymatgen.core import Composition
|
|
4
|
+
from pymatgen.core.periodic_table import DummySpecies
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def formula_to_criteria(formulas: str) -> dict:
|
|
8
|
+
"""
|
|
9
|
+
Santizes formula into a dictionary to search with wild cards
|
|
10
|
+
|
|
11
|
+
Arguments:
|
|
12
|
+
formula: formula with wildcards in it for unknown elements
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
Mongo style search criteria for this formula
|
|
16
|
+
"""
|
|
17
|
+
dummies = "AEGJLMQRXZ"
|
|
18
|
+
|
|
19
|
+
formula_list = [formula.strip() for formula in formulas.split(",")]
|
|
20
|
+
|
|
21
|
+
if "*" in formulas:
|
|
22
|
+
if len(formula_list) > 1:
|
|
23
|
+
raise HTTPException(
|
|
24
|
+
status_code=400,
|
|
25
|
+
detail="Wild cards only supported for single formula queries.",
|
|
26
|
+
)
|
|
27
|
+
else:
|
|
28
|
+
# Wild card in formula
|
|
29
|
+
nstars = formulas.count("*")
|
|
30
|
+
|
|
31
|
+
formula_dummies = formulas.replace("*", "{}").format(*dummies[:nstars])
|
|
32
|
+
|
|
33
|
+
try:
|
|
34
|
+
integer_formula = Composition(
|
|
35
|
+
formula_dummies
|
|
36
|
+
).get_integer_formula_and_factor()[0]
|
|
37
|
+
except ValueError:
|
|
38
|
+
raise HTTPException(
|
|
39
|
+
status_code=400,
|
|
40
|
+
detail="Problem processing formula with wild cards.",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
comp = Composition(integer_formula).reduced_composition
|
|
44
|
+
crit: dict[str, Any] = {"formula_anonymous": comp.anonymized_formula}
|
|
45
|
+
real_elts = [
|
|
46
|
+
e.name for e in comp.elements if not isinstance(e, DummySpecies)
|
|
47
|
+
]
|
|
48
|
+
crit.update(
|
|
49
|
+
{
|
|
50
|
+
f"composition_reduced.{el}": n
|
|
51
|
+
for el, n in comp.to_reduced_dict.items()
|
|
52
|
+
if el in real_elts
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
return crit
|
|
56
|
+
|
|
57
|
+
else:
|
|
58
|
+
try:
|
|
59
|
+
composition_list = [Composition(formula) for formula in formula_list]
|
|
60
|
+
except ValueError:
|
|
61
|
+
raise HTTPException(
|
|
62
|
+
status_code=400,
|
|
63
|
+
detail="Problem processing one or more provided formulas.",
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
if any(
|
|
67
|
+
isinstance(el, DummySpecies) for comp in composition_list for el in comp
|
|
68
|
+
):
|
|
69
|
+
# Assume fully anonymized formula
|
|
70
|
+
if len(formula_list) == 1:
|
|
71
|
+
return {"formula_anonymous": composition_list[0].anonymized_formula}
|
|
72
|
+
else:
|
|
73
|
+
return {
|
|
74
|
+
"formula_anonymous": {
|
|
75
|
+
"$in": [comp.anonymized_formula for comp in composition_list]
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
else:
|
|
80
|
+
if len(formula_list) == 1:
|
|
81
|
+
comp = composition_list[0]
|
|
82
|
+
# Paranoia below about floating-point "equality"
|
|
83
|
+
crit = {"nelements": len(comp)}
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
crit.update(
|
|
87
|
+
{
|
|
88
|
+
f"composition_reduced.{el}": n
|
|
89
|
+
for el, n in comp.to_reduced_dict.items()
|
|
90
|
+
}
|
|
91
|
+
)
|
|
92
|
+
except IndexError:
|
|
93
|
+
raise HTTPException(
|
|
94
|
+
status_code=400,
|
|
95
|
+
detail="Problem processing one or more provided formulas.",
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
return crit
|
|
99
|
+
else:
|
|
100
|
+
return {
|
|
101
|
+
"formula_pretty": {
|
|
102
|
+
"$in": [comp.reduced_formula for comp in composition_list]
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def formula_to_atlas_criteria(formulas: str) -> dict:
|
|
108
|
+
"""
|
|
109
|
+
Converts formula into Atlas Search query criteria for composition-based searches
|
|
110
|
+
|
|
111
|
+
Arguments:
|
|
112
|
+
formula: formula with wildcards in it for unknown elements
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
Atlas Search style query criteria for this formula
|
|
116
|
+
"""
|
|
117
|
+
dummies = "AEGJLMQRXZ"
|
|
118
|
+
formula_list = [formula.strip() for formula in formulas.split(",")]
|
|
119
|
+
must_clauses: list[dict[str, Any]] = []
|
|
120
|
+
|
|
121
|
+
if "*" in formulas:
|
|
122
|
+
if len(formula_list) > 1:
|
|
123
|
+
raise HTTPException(
|
|
124
|
+
status_code=400,
|
|
125
|
+
detail="Wild cards only supported for single formula queries.",
|
|
126
|
+
)
|
|
127
|
+
else:
|
|
128
|
+
# Wild card in formula
|
|
129
|
+
nstars = formulas.count("*")
|
|
130
|
+
formula_dummies = formulas.replace("*", "{}").format(*dummies[:nstars])
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
integer_formula = Composition(
|
|
134
|
+
formula_dummies
|
|
135
|
+
).get_integer_formula_and_factor()[0]
|
|
136
|
+
except ValueError:
|
|
137
|
+
raise HTTPException(
|
|
138
|
+
status_code=400,
|
|
139
|
+
detail="Problem processing formula with wild cards.",
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
comp = Composition(integer_formula).reduced_composition
|
|
143
|
+
real_elts = [
|
|
144
|
+
e.name for e in comp.elements if not isinstance(e, DummySpecies)
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
# Build Atlas Search compound query
|
|
148
|
+
must_clauses = [
|
|
149
|
+
{
|
|
150
|
+
"text": {
|
|
151
|
+
"query": comp.anonymized_formula,
|
|
152
|
+
"path": "formula_anonymous",
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
# Add element-specific clauses
|
|
158
|
+
must_clauses += [
|
|
159
|
+
{"equals": {"path": f"composition_reduced.{el}", "value": n}}
|
|
160
|
+
for el, n in comp.to_reduced_dict.items()
|
|
161
|
+
if el in real_elts
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
return {"must": must_clauses}
|
|
165
|
+
|
|
166
|
+
else:
|
|
167
|
+
try:
|
|
168
|
+
composition_list = [Composition(formula) for formula in formula_list]
|
|
169
|
+
except ValueError:
|
|
170
|
+
raise HTTPException(
|
|
171
|
+
status_code=400,
|
|
172
|
+
detail="Problem processing one or more provided formulas.",
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
if any(
|
|
176
|
+
isinstance(el, DummySpecies) for comp in composition_list for el in comp
|
|
177
|
+
):
|
|
178
|
+
# Assume fully anonymized formula
|
|
179
|
+
anonymized_formulas = [comp.anonymized_formula for comp in composition_list]
|
|
180
|
+
|
|
181
|
+
if len(formula_list) == 1:
|
|
182
|
+
return {
|
|
183
|
+
"text": {
|
|
184
|
+
"query": anonymized_formulas[0],
|
|
185
|
+
"path": "formula_anonymous",
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
else:
|
|
189
|
+
return {
|
|
190
|
+
"in": {
|
|
191
|
+
"path": "formula_anonymous",
|
|
192
|
+
"value": anonymized_formulas,
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
else:
|
|
197
|
+
if len(formula_list) == 1:
|
|
198
|
+
comp = composition_list[0]
|
|
199
|
+
|
|
200
|
+
# Build compound query for exact composition match
|
|
201
|
+
must_clauses = [{"equals": {"path": "nelements", "value": len(comp)}}]
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
must_clauses += [
|
|
205
|
+
{
|
|
206
|
+
"equals": {
|
|
207
|
+
"path": f"composition_reduced.{el}",
|
|
208
|
+
"value": n,
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
for el, n in comp.to_reduced_dict.items()
|
|
212
|
+
]
|
|
213
|
+
except IndexError:
|
|
214
|
+
raise HTTPException(
|
|
215
|
+
status_code=400,
|
|
216
|
+
detail="Problem processing one or more provided formulas.",
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
return {"must": must_clauses}
|
|
220
|
+
else:
|
|
221
|
+
# Multiple formulas - use pretty formula matching
|
|
222
|
+
pretty_formulas = [comp.reduced_formula for comp in composition_list]
|
|
223
|
+
return {"in": {"path": "formula_pretty", "value": pretty_formulas}}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def chemsys_to_criteria(chemsys: str) -> dict:
|
|
227
|
+
"""
|
|
228
|
+
Santizes chemsys into a dictionary to search with wild cards
|
|
229
|
+
|
|
230
|
+
Arguments:
|
|
231
|
+
chemsys: A comma delimited string list of chemical systems
|
|
232
|
+
with wildcards in it for unknown elements
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
Mongo style search criteria for this formula
|
|
236
|
+
"""
|
|
237
|
+
|
|
238
|
+
crit = {} # type: dict
|
|
239
|
+
|
|
240
|
+
chemsys_list = [chemsys_val.strip() for chemsys_val in chemsys.split(",")]
|
|
241
|
+
|
|
242
|
+
if "*" in chemsys:
|
|
243
|
+
if len(chemsys_list) > 1:
|
|
244
|
+
raise HTTPException(
|
|
245
|
+
status_code=400,
|
|
246
|
+
detail="Wild cards only supported for single chemsys queries.",
|
|
247
|
+
)
|
|
248
|
+
else:
|
|
249
|
+
eles = chemsys_list[0].split("-")
|
|
250
|
+
|
|
251
|
+
crit["nelements"] = len(eles)
|
|
252
|
+
crit.update(
|
|
253
|
+
{
|
|
254
|
+
f"composition_reduced.{el}": {"$exists": True}
|
|
255
|
+
for el in eles
|
|
256
|
+
if el != "*"
|
|
257
|
+
}
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
return crit
|
|
261
|
+
else:
|
|
262
|
+
query_vals = [
|
|
263
|
+
"-".join(sorted(chemsys_val.split("-"))) for chemsys_val in chemsys_list
|
|
264
|
+
]
|
|
265
|
+
|
|
266
|
+
if len(query_vals) == 1:
|
|
267
|
+
crit["chemsys"] = query_vals[0]
|
|
268
|
+
else:
|
|
269
|
+
crit["chemsys"] = {"$in": query_vals}
|
|
270
|
+
|
|
271
|
+
return crit
|