Skip to content

Commit

Permalink
Propagate provider field descriptions from config to info/<entry> end…
Browse files Browse the repository at this point in the history
…points
  • Loading branch information
ml-evs committed Mar 4, 2022
1 parent ca4a4d6 commit 20388bb
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 13 deletions.
4 changes: 3 additions & 1 deletion optimade/server/routers/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ def get_entry_info(request: Request, entry: str) -> EntryInfoResponse:

schema = ENTRY_INFO_SCHEMAS[entry]()
queryable_properties = {"id", "type", "attributes"}
properties = retrieve_queryable_properties(schema, queryable_properties)
properties = retrieve_queryable_properties(
schema, queryable_properties, entry_type=entry
)

output_fields_by_format = {"json": list(properties.keys())}

Expand Down
19 changes: 18 additions & 1 deletion optimade/server/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
ReferenceResource,
)
from optimade.server.exceptions import POSSIBLE_ERRORS
from optimade.server.config import CONFIG

__all__ = ("ENTRY_INFO_SCHEMAS", "ERROR_RESPONSES", "retrieve_queryable_properties")

Expand All @@ -22,7 +23,9 @@


def retrieve_queryable_properties(
schema: dict, queryable_properties: list = None
schema: dict,
queryable_properties: list = None,
entry_type: str = None,
) -> dict:
"""Recursively loops through the schema of a pydantic model and
resolves all references, returning a dictionary of all the
Expand All @@ -31,6 +34,8 @@ def retrieve_queryable_properties(
Parameters:
schema: The schema of the pydantic model.
queryable_properties: The list of properties to find in the schema.
entry_type: An optional entry type for the model. Will be used to
lookup schemas for any config-defined fields.
Returns:
A flat dictionary with properties as keys, containing the field
Expand Down Expand Up @@ -64,4 +69,16 @@ def retrieve_queryable_properties(
value.get("format", value.get("type"))
)

# If specified, check the config for any additional well-described provider fields
if entry_type:
described_provider_fields = [
field
for field in CONFIG.provider_fields[entry_type]
if isinstance(field, dict)
]
for field in described_provider_fields:
name = f"_{CONFIG.provider.prefix}_{field['name']}"
properties[name] = {k: field[k] for k in field if k != "name"}
properties[name]["sortable"] = field.get("sortable", True)

return properties
20 changes: 9 additions & 11 deletions tests/server/routers/test_info.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import pytest

from optimade.models import InfoResponse, EntryInfoResponse, IndexInfoResponse, DataType

from ..utils import RegularEndpointTests, IndexEndpointTests
Expand Down Expand Up @@ -90,7 +88,6 @@ def test_info_structures_unit(self):
else:
assert "unit" not in info_keys, f"Field: {field}"

@pytest.mark.skip("Unskip when PR #277 has been merged.")
def test_provider_fields(self):
"""Check the presence of provider-specific fields"""
from optimade.server.config import CONFIG
Expand All @@ -104,15 +101,16 @@ def test_provider_fields(self):
return

for field in provider_fields:
updated_field_name = f"_{CONFIG.provider.prefix}_{field}"
assert updated_field_name in self.json_response.get("data", {}).get(
"properties", {}
)

for static_key in ["description", "sortable"]:
assert static_key in self.json_response.get("data", {}).get(
if isinstance(field, dict):
updated_field_name = f"_{CONFIG.provider.prefix}_{field}"
assert updated_field_name in self.json_response.get("data", {}).get(
"properties", {}
).get(updated_field_name, {})
)

for static_key in ["description", "sortable"]:
assert static_key in self.json_response.get("data", {}).get(
"properties", {}
).get(updated_field_name, {})


class TestInfoReferencesEndpoint(RegularEndpointTests):
Expand Down
20 changes: 20 additions & 0 deletions tests/server/test_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,23 @@ def test_schemas():
# Check that all expected keys are present for OPTIMADE fields
for key in ("type", "sortable", "queryable", "description"):
assert all(key in properties[field] for field in properties)


def test_provider_field_schemas():
"""Tests that the default configured provider fields that have descriptions
are dereferenced appropriately.
"""
entry = "structures"
test_field = "chemsys"
schema = ENTRY_INFO_SCHEMAS[entry]()
top_level_props = ("id", "type", "attributes")
properties = retrieve_queryable_properties(schema, top_level_props, entry)
name = f"_exmpl_{test_field}"

assert name in properties
assert properties[name] == {
"type": "string",
"description": "A string representing the chemical system in an ordered fashion",
"sortable": True,
}

0 comments on commit 20388bb

Please sign in to comment.