Skip to content

Commit

Permalink
Final fixup
Browse files Browse the repository at this point in the history
- Tidy up changes re: `Datatype`
  • Loading branch information
ml-evs committed Oct 15, 2023
1 parent 34a545c commit 63e3f7c
Show file tree
Hide file tree
Showing 13 changed files with 2,229 additions and 1,115 deletions.
849 changes: 591 additions & 258 deletions openapi/index_openapi.json

Large diffs are not rendered by default.

2,349 changes: 1,564 additions & 785 deletions openapi/openapi.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions optimade/client/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,13 +178,13 @@ def _get(
"base_urls": base_url,
"use_async": use_async,
"max_results_per_provider": max_results_per_provider,
"include_providers": set(_.strip() for _ in include_providers.split(","))
"include_providers": {_.strip() for _ in include_providers.split(",")}
if include_providers
else None,
"exclude_providers": set(_.strip() for _ in exclude_providers.split(","))
"exclude_providers": {_.strip() for _ in exclude_providers.split(",")}
if exclude_providers
else None,
"exclude_databases": set(_.strip() for _ in exclude_databases.split(","))
"exclude_databases": {_.strip() for _ in exclude_databases.split(",")}
if exclude_databases
else None,
"silent": silent,
Expand Down
4 changes: 2 additions & 2 deletions optimade/models/entries.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from optimade.models.jsonapi import Attributes, Relationships, Resource
from optimade.models.optimade_json import (
BaseRelationshipResource,
DataType,
Datatype,
Relationship,
)
from optimade.models.utils import OptimadeField, StrictField, SupportLevel
Expand Down Expand Up @@ -203,7 +203,7 @@ class EntryInfoProperty(BaseModel):
] = None

type: Annotated[
Optional[DataType],
Optional[Datatype],
StrictField(
title="Type",
description="""The type of the property's value.
Expand Down
4 changes: 2 additions & 2 deletions optimade/models/structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -1013,7 +1013,7 @@ def null_values_for_whole_vector(
return value

for vector in value:
if None in vector and any((isinstance(_, float) for _ in vector)):
if None in vector and any(isinstance(_, float) for _ in vector):
raise ValueError(
"A lattice vector MUST be either all `null` or all numbers "
f"(vector: {vector}, all vectors: {value})"
Expand Down Expand Up @@ -1080,7 +1080,7 @@ def validate_species(
def validate_structure_features(self) -> "StructureResourceAttributes":
if [
StructureFeatures(value)
for value in sorted((_.value for _ in self.structure_features))
for value in sorted(_.value for _ in self.structure_features)
] != self.structure_features:
raise ValueError(
"structure_features MUST be sorted alphabetically, structure_features: "
Expand Down
3 changes: 2 additions & 1 deletion optimade/server/entry_collections/entry_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import re
import warnings
from abc import ABC, abstractmethod
from typing import Any, Iterable, Optional, Union
from collections.abc import Iterable
from typing import Any, Optional, Union

from lark import Transformer

Expand Down
9 changes: 5 additions & 4 deletions optimade/server/schemas.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from typing import TYPE_CHECKING, Any, Iterable, Optional
from collections.abc import Iterable
from typing import TYPE_CHECKING, Any, Optional

from pydantic import BaseModel, TypeAdapter

from optimade.models import (
DataType,
Datatype,
EntryResource,
ErrorResponse,
ReferenceResource,
Expand All @@ -20,7 +21,7 @@
str,
dict[
Literal["description", "unit", "queryable", "support", "sortable", "type"],
Optional[Union[str, SupportLevel, bool, DataType]],
Optional[Union[str, SupportLevel, bool, Datatype]],
],
]

Expand Down Expand Up @@ -117,7 +118,7 @@ def retrieve_queryable_properties(
# Try to get OpenAPI-specific "format" if possible, else get "type"; a mandatory OpenAPI key.
json_schema = TypeAdapter(annotation).json_schema(mode="validation")

properties[name]["type"] = DataType.from_json_type(
properties[name]["type"] = Datatype.from_json_type(
json_schema.get("format", json_schema.get("type"))
)

Expand Down
30 changes: 15 additions & 15 deletions optimade/validator/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from pydantic_settings import BaseSettings

from optimade.models import (
DataType,
Datatype,
IndexInfoResponse,
InfoResponse,
StructureFeatures,
Expand Down Expand Up @@ -71,27 +71,27 @@
substring_operators = ("CONTAINS", "STARTS WITH", "STARTS", "ENDS WITH", "ENDS")

_INCLUSIVE_OPERATORS = {
DataType.STRING: inclusive_ops + substring_operators,
Datatype.STRING: inclusive_ops + substring_operators,
# N.B. "=" and "<=" are disabled due to issue with microseconds stored in database vs API response (see Materials-Consortia/optimade-python-tools/#606)
# ">=" is fine as all microsecond trimming will round times down
DataType.TIMESTAMP: (
Datatype.TIMESTAMP: (
# "=",
# "<=",
">=",
),
DataType.INTEGER: inclusive_ops,
DataType.FLOAT: (),
DataType.LIST: ("HAS", "HAS ALL", "HAS ANY", "LENGTH"),
Datatype.INTEGER: inclusive_ops,
Datatype.FLOAT: (),
Datatype.LIST: ("HAS", "HAS ALL", "HAS ANY", "LENGTH"),
}

exclusive_ops = ("!=", "<", ">")

_EXCLUSIVE_OPERATORS = {
DataType.STRING: exclusive_ops,
DataType.TIMESTAMP: (),
DataType.FLOAT: (),
DataType.INTEGER: exclusive_ops,
DataType.LIST: (),
Datatype.STRING: exclusive_ops,
Datatype.TIMESTAMP: (),
Datatype.FLOAT: (),
Datatype.INTEGER: exclusive_ops,
Datatype.LIST: (),
}


Expand Down Expand Up @@ -151,18 +151,18 @@ class ValidatorConfig(BaseSettings):
),
)

inclusive_operators: dict[DataType, set[str]] = Field(
inclusive_operators: dict[Datatype, set[str]] = Field(
_INCLUSIVE_OPERATORS,
description=(
"Dictionary mapping OPTIMADE `DataType`s to a list of operators that are 'inclusive', "
"Dictionary mapping OPTIMADE `Datatype`s to a list of operators that are 'inclusive', "
"i.e. those that should return entries with the matching value from the filter."
),
)

exclusive_operators: dict[DataType, set[str]] = Field(
exclusive_operators: dict[Datatype, set[str]] = Field(
_EXCLUSIVE_OPERATORS,
description=(
"Dictionary mapping OPTIMADE `DataType`s to a list of operators that are 'exclusive', "
"Dictionary mapping OPTIMADE `Datatype`s to a list of operators that are 'exclusive', "
"i.e. those that should not return entries with the matching value from the filter."
),
)
Expand Down
26 changes: 13 additions & 13 deletions optimade/validator/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class that can be pointed at an OPTIMADE implementation and validated

import requests

from optimade.models import DataType, EntryInfoResponse, SupportLevel
from optimade.models import Datatype, EntryInfoResponse, SupportLevel
from optimade.validator.config import VALIDATOR_CONFIG as CONF
from optimade.validator.utils import (
DEFAULT_CONN_TIMEOUT,
Expand Down Expand Up @@ -590,7 +590,7 @@ def _check_response_fields(
def _construct_queries_for_property(
self,
prop: str,
prop_type: DataType,
prop_type: Datatype,
sortable: bool,
endp: str,
chosen_entry: dict[str, Any],
Expand Down Expand Up @@ -662,7 +662,7 @@ def _construct_queries_for_property(
)

@staticmethod
def _format_test_value(test_value: Any, prop_type: DataType, operator: str) -> str:
def _format_test_value(test_value: Any, prop_type: Datatype, operator: str) -> str:
"""Formats the test value as a string according to the type of the property.
Parameters:
Expand All @@ -674,7 +674,7 @@ def _format_test_value(test_value: Any, prop_type: DataType, operator: str) -> s
The value formatted as a string to use in an OPTIMADE filter.
"""
if prop_type == DataType.LIST:
if prop_type == Datatype.LIST:
if operator in ("HAS ALL", "HAS ANY"):
_vals = sorted(set(test_value))
if isinstance(test_value[0], str):
Expand All @@ -690,7 +690,7 @@ def _format_test_value(test_value: Any, prop_type: DataType, operator: str) -> s
else:
_test_value = test_value[0]

elif prop_type in (DataType.STRING, DataType.TIMESTAMP):
elif prop_type in (Datatype.STRING, Datatype.TIMESTAMP):
_test_value = f'"{test_value}"'

else:
Expand All @@ -701,7 +701,7 @@ def _format_test_value(test_value: Any, prop_type: DataType, operator: str) -> s
def _construct_single_property_filters(
self,
prop: str,
prop_type: DataType,
prop_type: Datatype,
sortable: bool,
endp: str,
chosen_entry: dict[str, Any],
Expand Down Expand Up @@ -755,7 +755,7 @@ def _construct_single_property_filters(
raise ResponseError(msg)

using_fallback = False
if prop_type == DataType.LIST:
if prop_type == Datatype.LIST:
if not test_value:
test_value = CONF.enum_fallback_values.get(endp, {}).get(prop)
using_fallback = True
Expand All @@ -779,7 +779,7 @@ def _construct_single_property_filters(
except ValueError:
pass

if prop_type in (DataType.DICTIONARY,):
if prop_type in (Datatype.DICTIONARY,):
msg = f"Not testing queries on field {prop} of type {prop_type}."
self._log.warning(msg)
return None, msg
Expand Down Expand Up @@ -875,10 +875,10 @@ def _construct_single_property_filters(

# Numeric and string comparisons must work both ways...
if prop_type in (
DataType.STRING,
DataType.INTEGER,
DataType.FLOAT,
DataType.TIMESTAMP,
Datatype.STRING,
Datatype.INTEGER,
Datatype.FLOAT,
Datatype.TIMESTAMP,
) and operator not in (
"CONTAINS",
"STARTS",
Expand All @@ -893,7 +893,7 @@ def _construct_single_property_filters(
reversed_operator = operator.replace(">", "<")

# Don't try to reverse string comparison as it is ill-defined
if prop_type == DataType.STRING and any(
if prop_type == Datatype.STRING and any(
comp in operator for comp in ("<", ">")
):
continue
Expand Down
44 changes: 22 additions & 22 deletions tests/models/test_optimade_json.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import pytest
from pydantic import ValidationError

from optimade.models import DataType, Provider
from optimade.models import Datatype, Provider


def test_convert_python_types():
"""Convert various Python types to OPTIMADE Data types"""
from datetime import datetime

expected_data_type = [
DataType.STRING,
DataType.INTEGER,
DataType.FLOAT,
DataType.LIST,
DataType.DICTIONARY,
DataType.UNKNOWN,
DataType.TIMESTAMP,
Datatype.STRING,
Datatype.INTEGER,
Datatype.FLOAT,
Datatype.LIST,
Datatype.DICTIONARY,
Datatype.UNKNOWN,
Datatype.TIMESTAMP,
]

python_types_as_strings = [
Expand Down Expand Up @@ -47,33 +47,33 @@ def test_convert_python_types():
]:
for index, python_type in enumerate(list_of_python_types):
assert isinstance(
DataType.from_python_type(python_type), DataType
Datatype.from_python_type(python_type), Datatype
), f"python_type: {python_type}"
assert DataType.from_python_type(python_type) == expected_data_type[index]
assert Datatype.from_python_type(python_type) == expected_data_type[index]


def test_convert_json_types():
"""Convert various JSON and OpenAPI types to OPTIMADE Data types"""
json_types = [
("string", DataType.STRING),
("integer", DataType.INTEGER),
("number", DataType.FLOAT),
("array", DataType.LIST),
("object", DataType.DICTIONARY),
("null", DataType.UNKNOWN),
("string", Datatype.STRING),
("integer", Datatype.INTEGER),
("number", Datatype.FLOAT),
("array", Datatype.LIST),
("object", Datatype.DICTIONARY),
("null", Datatype.UNKNOWN),
]
openapi_formats = [
("date-time", DataType.TIMESTAMP),
("email", DataType.STRING),
("uri", DataType.STRING),
("date-time", Datatype.TIMESTAMP),
("email", Datatype.STRING),
("uri", Datatype.STRING),
]

for list_of_schema_types in [json_types, openapi_formats]:
for schema_type, optimade_type in list_of_schema_types:
assert isinstance(
DataType.from_json_type(schema_type), DataType
Datatype.from_json_type(schema_type), Datatype
), f"json_type: {schema_type}"
assert DataType.from_json_type(schema_type) == optimade_type
assert Datatype.from_json_type(schema_type) == optimade_type


def test_get_values():
Expand All @@ -88,7 +88,7 @@ def test_get_values():
"timestamp",
"unknown",
]
assert DataType.get_values() == sorted_data_types
assert Datatype.get_values() == sorted_data_types


@pytest.mark.parametrize(
Expand Down
2 changes: 1 addition & 1 deletion tests/models/test_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ def _minor_deformities() -> "Generator[dict[str, Any], None, None]":
"""Generate minor deformities from correlated structure fields"""
from optimade.models.structures import CORRELATED_STRUCTURE_FIELDS

return ({f: None} for f in set(f for _ in CORRELATED_STRUCTURE_FIELDS for f in _))
return ({f: None} for f in {f for _ in CORRELATED_STRUCTURE_FIELDS for f in _})


@pytest.mark.parametrize("deformity", _minor_deformities())
Expand Down
6 changes: 3 additions & 3 deletions tests/server/routers/test_info.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from optimade.models import DataType, EntryInfoResponse, IndexInfoResponse, InfoResponse
from optimade.models import Datatype, EntryInfoResponse, IndexInfoResponse, InfoResponse

from ..utils import IndexEndpointTests, RegularEndpointTests

Expand Down Expand Up @@ -43,7 +43,7 @@ def test_properties_type(self):
for data_type in types:
if data_type is None:
continue
assert isinstance(DataType(data_type), DataType)
assert isinstance(Datatype(data_type), Datatype)

def test_info_structures_sortable(self):
"""Check the sortable key is present for all properties"""
Expand Down Expand Up @@ -130,7 +130,7 @@ def test_properties_type(self):
for data_type in types:
if data_type is None:
continue
assert isinstance(DataType(data_type), DataType)
assert isinstance(Datatype(data_type), Datatype)


class TestIndexInfoEndpoint(IndexEndpointTests):
Expand Down

0 comments on commit 63e3f7c

Please sign in to comment.