From 0740530651f786a5530632b212209d435d2cbff7 Mon Sep 17 00:00:00 2001 From: Matthew Evans Date: Mon, 18 Jan 2021 14:25:55 +0000 Subject: [PATCH] Add fallback values for enum fields to use on validation --- optimade/validator/config.py | 15 ++++++++++-- optimade/validator/validator.py | 43 +++++++++++++++------------------ 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/optimade/validator/config.py b/optimade/validator/config.py index d9de66fd40..de626cfa0c 100644 --- a/optimade/validator/config.py +++ b/optimade/validator/config.py @@ -7,10 +7,10 @@ """ -from typing import Dict, Any, Set +from typing import Dict, Any, Set, List from pydantic import BaseSettings, Field -from optimade.models import InfoResponse, IndexInfoResponse, DataType +from optimade.models import InfoResponse, IndexInfoResponse, DataType, StructureFeatures from optimade.validator.utils import ( ValidatorLinksResponse, ValidatorReferenceResponseOne, @@ -50,6 +50,12 @@ "links": ValidatorLinksResponse, } +_ENUM_DUMMY_VALUES = { + "structures": { + "structure_features": [allowed.value for allowed in StructureFeatures] + } +} + _UNIQUE_PROPERTIES = ("id", "immutable_id") @@ -159,5 +165,10 @@ class ValidatorConfig(BaseSettings): description="Field names to treat as top-level", ) + enum_fallback_values: Dict[str, Dict[str, List[str]]] = Field( + _ENUM_DUMMY_VALUES, + description="Provide fallback values for enum fields to use when validating filters.", + ) + VALIDATOR_CONFIG = ValidatorConfig() diff --git a/optimade/validator/validator.py b/optimade/validator/validator.py index 432dc023b0..6e770c2201 100644 --- a/optimade/validator/validator.py +++ b/optimade/validator/validator.py @@ -685,7 +685,12 @@ def _construct_single_property_filters( # Otherwise, None values are not allowed for MUST's, and entire missing fields are not allowed raise ResponseError(msg) + using_fallback = False if prop_type == DataType.LIST: + if not test_value: + test_value = CONF.enum_fallback_values.get(endp).get(prop) + using_fallback = True + if not test_value or ( isinstance(test_value[0], dict) or isinstance(test_value[0], list) ): @@ -713,22 +718,17 @@ def _construct_single_property_filters( request, multistage=True, optional=query_optional, + expected_status_code=(200, 501), ) if not response: if query_optional: - return None, "" + return ( + None, + "Optional query {query!r} returned {reversed_response.status_code}.", + ) raise ResponseError( - f"Unable to perform {request}: failed with error {message}." - ) - - if response.status_code == 501: - self._log.warning( - f"Implementation returned {response.content} for {query}" - ) - return ( - True, - "Implementation safely reported that filter {query} was not implemented.", + f"Unable to perform mandatory query {query!r}: responded with status code {response.status_code}" ) response = response.json() @@ -776,22 +776,17 @@ def _construct_single_property_filters( reversed_request, multistage=True, optional=query_optional, + expected_status_code=(200, 501), ) if not reversed_response: if query_optional: - return None, "" + return ( + None, + "Optional query {query!r} returned {reversed_response.status_code}.", + ) raise ResponseError( - f"Unable to perform {reversed_request}: failed with error {message}." - ) - - if reversed_response.status_code == 501: - self._log.warning( - f"Implementation returned {reversed_response.content} for {reversed_query}" - ) - return ( - True, - "Implementation safely reported that filter {reversed_query} was not implemented.", + f"Unable to perform mandatory query {query!r}: responded with status code {reversed_response.status_code}" ) reversed_response = reversed_response.json() @@ -829,8 +824,8 @@ def _construct_single_property_filters( f"Objects {excluded} were not necessarily excluded by {query}" ) - # check that at least the archetypal structure was returned - if not excluded: + # check that at least the archetypal structure was returned, unless we are using a fallback value + if not excluded and not using_fallback: if ( num_data_returned[operator] is not None and num_data_returned[operator] < 1