Skip to content

Commit

Permalink
Fixed the final issue(s)
Browse files Browse the repository at this point in the history
Needed to properly ONLY check if annotation was Union or Optional before
using `get_args()`. Otherwise a type required as a list of strings is
unpacked to `str`, which we do not want.
  • Loading branch information
CasperWA committed Oct 14, 2023
1 parent 081ff49 commit 02ae46e
Show file tree
Hide file tree
Showing 8 changed files with 28 additions and 36 deletions.
2 changes: 0 additions & 2 deletions optimade/filtertransformers/mongo.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
[`MongoTransformer`][optimade.filtertransformers.mongo.MongoTransformer],
which takes the parsed filter and converts it to a valid pymongo/BSON query.
"""


import copy
import itertools
import warnings
Expand Down
6 changes: 5 additions & 1 deletion optimade/models/types.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Annotated
from typing import Annotated, Optional

from pydantic import Field

Expand All @@ -20,3 +20,7 @@
pattern=SEMVER_PATTERN, examples=["0.10.1", "1.0.0-rc.2", "1.2.3-rc.5+develop"]
),
]

AnnotatedType = type(ChemicalSymbol)
OptionalType = type(Optional[str])
UnionType = type(str | int)
1 change: 1 addition & 0 deletions optimade/models/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ def StrictField(

def OptimadeField(
default: "Any" = PydanticUndefined,
*,
support: Optional[Union[str, SupportLevel]] = None,
queryable: Optional[Union[str, SupportLevel]] = None,
unit: Optional[str] = None,
Expand Down
35 changes: 11 additions & 24 deletions optimade/server/entry_collections/entry_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
)

from lark import Transformer
from typing_extensions import _AnnotatedAlias

from optimade.exceptions import BadRequest, Forbidden, NotFound
from optimade.filterparser import LarkParser
from optimade.models import Attributes, EntryResource
from optimade.models.types import AnnotatedType, OptionalType, UnionType
from optimade.server.config import CONFIG, SupportedBackend
from optimade.server.mappers import BaseResourceMapper
from optimade.server.query_params import EntryListingQueryParams, SingleEntryQueryParams
Expand Down Expand Up @@ -171,7 +171,7 @@ def find(
"""
criteria = self.handle_query_params(params)
single_entry = isinstance(params, SingleEntryQueryParams)
response_fields = criteria.pop("fields")
response_fields: Set[str] = criteria.pop("fields")

raw_results, data_returned, more_data_available = self._run_db_query(
criteria, single_entry
Expand All @@ -182,10 +182,10 @@ def find(
response_fields - self.resource_mapper.TOP_LEVEL_NON_ATTRIBUTES_FIELDS
)

bad_optimade_fields = set()
bad_provider_fields = set()
bad_optimade_fields: Set[str] = set()
bad_provider_fields: Set[str] = set()
supported_prefixes = self.resource_mapper.SUPPORTED_PREFIXES
all_attributes = self.resource_mapper.ALL_ATTRIBUTES
all_attributes: Set[str] = self.resource_mapper.ALL_ATTRIBUTES
for field in include_fields:
if field not in all_attributes:
if field.startswith("_"):
Expand Down Expand Up @@ -294,12 +294,13 @@ def get_attribute_fields(self) -> Set[str]:
"""
annotation = self.resource_cls.model_fields["attributes"].annotation
for arg in get_args(annotation):
if arg not in (None, type(None)):
annotation = arg
break
if isinstance(annotation, (OptionalType, UnionType)):
for arg in get_args(annotation):
if arg not in (None, type(None)):
annotation = arg
break

Check warning on line 301 in optimade/server/entry_collections/entry_collections.py

View check run for this annotation

Codecov / codecov/patch

optimade/server/entry_collections/entry_collections.py#L298-L301

Added lines #L298 - L301 were not covered by tests

if isinstance(annotation, _AnnotatedAlias):
if isinstance(annotation, AnnotatedType):
annotation = get_args(annotation)[0]

Check warning on line 304 in optimade/server/entry_collections/entry_collections.py

View check run for this annotation

Codecov / codecov/patch

optimade/server/entry_collections/entry_collections.py#L304

Added line #L304 was not covered by tests

if not issubclass(annotation, Attributes):
Expand All @@ -309,20 +310,6 @@ def get_attribute_fields(self) -> Set[str]:

return set(annotation.model_fields)

# schema = self.resource_cls.model_json_schema(mode="validation")
# attributes = schema["properties"]["attributes"]
# if "allOf" in attributes:
# allOf = attributes.pop("allOf")
# for dict_ in allOf:
# attributes.update(dict_)
# if "$ref" in attributes:
# path = attributes["$ref"].split("/")[1:]
# attributes = schema.copy()
# while path:
# next_key = path.pop(0)
# attributes = attributes[next_key]
# return set(attributes["properties"].keys())

def handle_query_params(
self, params: Union[EntryListingQueryParams, SingleEntryQueryParams]
) -> Dict[str, Any]:
Expand Down
13 changes: 7 additions & 6 deletions optimade/server/schemas.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from typing import TYPE_CHECKING, Dict, Iterable, Optional, get_args

from pydantic import BaseModel, TypeAdapter
from typing_extensions import _AnnotatedAlias

from optimade.models import (
DataType,
Expand All @@ -10,6 +9,7 @@
ReferenceResource,
StructureResource,
)
from optimade.models.types import AnnotatedType, OptionalType, UnionType

if TYPE_CHECKING: # pragma: no cover
from typing import Literal, Union
Expand Down Expand Up @@ -84,12 +84,13 @@ def retrieve_queryable_properties(
# If the field is a Union, get the first non-None type (this includes
# Optional[T])
annotation = value.annotation
for arg in get_args(annotation):
if arg not in (None, type(None)):
annotation = arg
break
if isinstance(annotation, (OptionalType, UnionType)):
for arg in get_args(annotation):
if arg not in (None, type(None)):
annotation = arg
break

if isinstance(annotation, _AnnotatedAlias):
if isinstance(annotation, AnnotatedType):
annotation = get_args(annotation)[0]

# Ensure that the annotation is a builtin type
Expand Down
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ server = [
"uvicorn[standard]~=0.19",
"fastapi~=0.103",
"pyyaml~=6.0",
"typing-extensions~=4.8",
"optimade[mongo]",
]

Expand Down
1 change: 0 additions & 1 deletion requirements-server.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ elasticsearch-dsl==7.4.0
fastapi==0.103.1
mongomock==4.1.2
pymongo==4.5.0
typing-extensions==4.8.0
5 changes: 4 additions & 1 deletion tests/server/test_schemas.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Tests for optimade.server.schemas"""


def test_schemas() -> None:
def test_retrieve_queryable_properties() -> None:
"""Test that the default `ENTRY_INFO_SCHEMAS` contain
all the required information about the OPTIMADE properties
after dereferencing.
Expand Down Expand Up @@ -31,6 +31,9 @@ def test_schemas() -> None:
for key in ("type", "sortable", "queryable", "description"):
assert all(key in properties[field] for field in properties)

# Check that all fields are queryable
assert all(properties[field]["queryable"] for field in properties)


def test_provider_field_schemas() -> None:
"""Tests that the default configured provider fields that have descriptions
Expand Down

0 comments on commit 02ae46e

Please sign in to comment.