Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions optimade/filtertransformers/base_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,31 @@

from lark import Transformer, Tree, v_args

from optimade.exceptions import BadRequest
from optimade.server.mappers import BaseResourceMapper
from optimade.warnings import UnknownProviderProperty
if TYPE_CHECKING:
from optimade.server.mappers import BaseResourceMapper

try:
from optimade.warnings import UnknownProviderProperty
except ImportError:

class UnknownProviderProperty(UserWarning): # type: ignore[no-redef]
"""A property with a provider-specific prefix is not recognized by this implementation.
This shim class allows the filtertransformer to be used without the full optimade package.

"""


class FilterTransformerError(Exception):
"""Base class for exceptions in this module."""

status_code: int
detail: str = "There was an error while processing the filter."

def __init__(self, status_code: int = 400, detail: str | None = None):
self.status_code = status_code
if detail is not None:
self.detail = detail


if TYPE_CHECKING: # pragma: no cover
pass
Expand Down Expand Up @@ -82,7 +104,7 @@ class BaseTransformer(Transformer, abc.ABC):

"""

mapper: type[BaseResourceMapper] | None = None
mapper: type["BaseResourceMapper"] | None = None
operator_map: dict[str, str | None] = {
"<": None,
"<=": None,
Expand All @@ -106,7 +128,7 @@ class BaseTransformer(Transformer, abc.ABC):
_quantity_type: type[Quantity] = Quantity
_quantities = None

def __init__(self, mapper: type[BaseResourceMapper] | None = None):
def __init__(self, mapper: type["BaseResourceMapper"] | None = None):
"""Initialise the transformer object, optionally loading in a
resource mapper for use when post-processing.

Expand Down Expand Up @@ -264,7 +286,7 @@ def property(self, args: list) -> Any:

return quantity_name

raise BadRequest(
raise FilterTransformerError(
detail=f"'{quantity_name}' is not a known or searchable quantity"
)

Expand Down
6 changes: 4 additions & 2 deletions optimade/filtertransformers/elasticsearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from lark import v_args

from optimade.filtertransformers import BaseTransformer, Quantity
from optimade.server.mappers import BaseResourceMapper

if TYPE_CHECKING:
from optimade.server.mappers import BaseResourceMapper

__all__ = ("ElasticTransformer",)

Expand Down Expand Up @@ -101,7 +103,7 @@ class ElasticTransformer(BaseTransformer):

def __init__(
self,
mapper: type[BaseResourceMapper],
mapper: type["BaseResourceMapper"],
quantities: dict[str, Quantity] | None = None,
):
if quantities is not None:
Expand Down
22 changes: 18 additions & 4 deletions optimade/filtertransformers/mongo.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,21 @@

from lark import Token, v_args

from optimade.exceptions import BadRequest
from optimade.filtertransformers.base_transformer import BaseTransformer, Quantity
from optimade.warnings import TimestampNotRFCCompliant
from optimade.filtertransformers.base_transformer import (
BaseTransformer,
FilterTransformerError,
Quantity,
)

try:
from optimade.warnings import TimestampNotRFCCompliant
except ImportError:

class TimestampNotRFCCompliant(UserWarning): # type: ignore[no-redef]
"""A timestamp value was not RFC3339 compliant, which may lead to undefined behaviour.
This shim class is only used if the `optimade` package is not installed.
"""


__all__ = ("MongoTransformer",)

Expand Down Expand Up @@ -425,7 +437,9 @@ def replace_only_filter(subdict: dict, prop: str, expr: dict):
"relationships.references.data.id",
"relationships.structures.data.id",
):
raise BadRequest(f"Unable to query on unrecognised field {prop}.")
raise FilterTransformerError(
detail=f"Unable to query on unrecognised field {prop}."
)
first_part_prop = ".".join(prop.split(".")[:-1])
subdict["$and"].append(
{
Expand Down
2 changes: 2 additions & 0 deletions optimade/server/exception_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from pydantic import ValidationError

from optimade.exceptions import BadRequest, OptimadeHTTPException
from optimade.filtertransformers.base_transformer import FilterTransformerError
from optimade.models import ErrorResponse, ErrorSource, OptimadeError
from optimade.server.config import CONFIG
from optimade.server.logger import LOGGER
Expand Down Expand Up @@ -228,6 +229,7 @@ def general_exception_handler(request: Request, exc: Exception) -> JSONAPIRespon
] = [
(StarletteHTTPException, http_exception_handler),
(OptimadeHTTPException, http_exception_handler),
(FilterTransformerError, http_exception_handler),
(RequestValidationError, request_validation_exception_handler),
(ValidationError, validation_exception_handler),
(VisitError, grammar_not_implemented_handler),
Expand Down
Loading