Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix API Sanitizing MSONable types in combined types #454

Merged
merged 5 commits into from
Jun 18, 2021
Merged
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
6 changes: 3 additions & 3 deletions src/maggma/api/API.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from monty.json import MSONable
from starlette.responses import RedirectResponse
from fastapi.middleware.cors import CORSMiddleware

from maggma import __version__
from maggma.api.resource import Resource
Expand Down Expand Up @@ -82,7 +82,7 @@ def app(self):

@app.get("/heartbeat", include_in_schema=False)
def heartbeat():
""" API Heartbeat for Load Balancing """
"""API Heartbeat for Load Balancing"""

return {
"status": "OK",
Expand All @@ -93,7 +93,7 @@ def heartbeat():

@app.get("/", include_in_schema=False)
def redirect_docs():
""" Redirects the root end point to the docs """
"""Redirects the root end point to the docs"""
return RedirectResponse(url=app.docs_url, status_code=301)

return app
Expand Down
2 changes: 1 addition & 1 deletion src/maggma/api/query_operator/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from maggma.api.query_operator.core import QueryOperator
from maggma.api.query_operator.dynamic import NumericQuery, StringQueryOperator
from maggma.api.query_operator.pagination import PaginationQuery
from maggma.api.query_operator.sparse_fields import SparseFieldsQuery
from maggma.api.query_operator.sorting import SortQuery
from maggma.api.query_operator.sparse_fields import SparseFieldsQuery
from maggma.api.query_operator.submission import SubmissionQuery
15 changes: 8 additions & 7 deletions src/maggma/api/query_operator/dynamic.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import inspect
from typing import Type
from abc import abstractmethod
from typing import Any, Callable, Dict, List, Optional, Tuple
from typing import Any, Callable, Dict, List, Optional, Tuple, Type

from fastapi.params import Query
from monty.json import MontyDecoder
Expand Down Expand Up @@ -81,7 +80,7 @@ def query(**kwargs) -> STORE_PARAMS:
self.query = query # type: ignore

def query(self):
" Stub query function for abstract class "
"Stub query function for abstract class"
pass

@abstractmethod
Expand Down Expand Up @@ -115,7 +114,7 @@ def as_dict(self) -> Dict:


class NumericQuery(DynamicQueryOperator):
" Query Operator to enable searching on numeric fields"
"Query Operator to enable searching on numeric fields"

def field_to_operator(
self, name: str, field: ModelField
Expand All @@ -140,15 +139,17 @@ def field_to_operator(
f"{field.name}_max",
field_type,
Query(
default=None, description=f"Query for maximum value of {title}",
default=None,
description=f"Query for maximum value of {title}",
),
lambda val: {f"{field.name}": {"$lte": val}},
),
(
f"{field.name}_min",
field_type,
Query(
default=None, description=f"Query for minimum value of {title}",
default=None,
description=f"Query for minimum value of {title}",
),
lambda val: {f"{field.name}": {"$gte": val}},
),
Expand Down Expand Up @@ -209,7 +210,7 @@ def field_to_operator(


class StringQueryOperator(DynamicQueryOperator):
" Query Operator to enable searching on numeric fields"
"Query Operator to enable searching on numeric fields"

def field_to_operator(
self, name: str, field: ModelField
Expand Down
13 changes: 9 additions & 4 deletions src/maggma/api/query_operator/pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
class PaginationQuery(QueryOperator):
"""Query opertators to provides Pagination"""

def __init__(self, default_skip: int = 0, default_limit: int = 100, max_limit: int = 1000):
def __init__(
self, default_skip: int = 0, default_limit: int = 100, max_limit: int = 1000
):
"""
Args:
default_skip: the default number of documents to skip
Expand All @@ -21,10 +23,13 @@ def __init__(self, default_skip: int = 0, default_limit: int = 100, max_limit: i
self.max_limit = max_limit

def query(
skip: int = Query(default_skip, description="Number of entries to skip in the search"),
skip: int = Query(
default_skip, description="Number of entries to skip in the search"
),
limit: int = Query(
default_limit,
description="Max number of entries to return in a single query." f" Limited to {max_limit}",
description="Max number of entries to return in a single query."
f" Limited to {max_limit}",
),
) -> STORE_PARAMS:
"""
Expand All @@ -41,7 +46,7 @@ def query(
self.query = query # type: ignore

def query(self):
" Stub query function for abstract class "
"Stub query function for abstract class"
pass

def meta(self) -> Dict:
Expand Down
12 changes: 9 additions & 3 deletions src/maggma/api/query_operator/sorting.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from typing import Optional

from fastapi import HTTPException, Query

from maggma.api.query_operator import QueryOperator
from maggma.api.utils import STORE_PARAMS
from fastapi import HTTPException, Query


class SortQuery(QueryOperator):
Expand All @@ -12,7 +14,10 @@ class SortQuery(QueryOperator):
def query(
self,
field: Optional[str] = Query(None, description="Field to sort with"),
ascending: Optional[bool] = Query(None, description="Whether the sorting should be ascending",),
ascending: Optional[bool] = Query(
None,
description="Whether the sorting should be ascending",
),
) -> STORE_PARAMS:

sort = {}
Expand All @@ -22,7 +27,8 @@ def query(

elif field or ascending is not None:
raise HTTPException(
status_code=400, detail="Must specify both a field and order for sorting.",
status_code=400,
detail="Must specify both a field and order for sorting.",
)

return {"sort": sort}
2 changes: 1 addition & 1 deletion src/maggma/api/query_operator/sparse_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def query(
self.query = query # type: ignore

def query(self):
" Stub query function for abstract class "
"Stub query function for abstract class"
pass

def meta(self) -> Dict:
Expand Down
11 changes: 7 additions & 4 deletions src/maggma/api/query_operator/submission.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from datetime import datetime
from typing import Optional

from fastapi import Query

from maggma.api.query_operator import QueryOperator
from maggma.api.utils import STORE_PARAMS
from fastapi import Query
from datetime import datetime


class SubmissionQuery(QueryOperator):
Expand All @@ -19,7 +21,8 @@ def query(
None, description="Latest status of the submission"
),
last_updated: Optional[datetime] = Query(
None, description="Minimum datetime of status update for submission",
None,
description="Minimum datetime of status update for submission",
),
) -> STORE_PARAMS:

Expand All @@ -45,5 +48,5 @@ def query(
self.query = query

def query(self):
" Stub query function for abstract class "
"Stub query function for abstract class"
pass
8 changes: 6 additions & 2 deletions src/maggma/api/resource/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# isort: off
from maggma.api.resource.core import Resource
from maggma.api.resource.read_resource import ReadOnlyResource, attach_query_ops
from maggma.api.resource.submission import SubmissionResource

# isort: on

from maggma.api.resource.aggregation import AggregationResource
from maggma.api.resource.post_resource import PostOnlyResource
from maggma.api.resource.read_resource import ReadOnlyResource, attach_query_ops
from maggma.api.resource.submission import SubmissionResource
5 changes: 1 addition & 4 deletions src/maggma/api/resource/aggregation.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
from maggma.api.query_operator import QueryOperator
from maggma.api.resource import Resource
from maggma.api.resource.utils import attach_query_ops
from maggma.api.utils import (
STORE_PARAMS,
merge_queries,
)
from maggma.api.utils import STORE_PARAMS, merge_queries
from maggma.core import Store


Expand Down
13 changes: 3 additions & 10 deletions src/maggma/api/resource/post_resource.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
from typing import Any, Dict, List, Optional, Type
from inspect import signature
from typing import Any, Dict, List, Optional, Type

from fastapi import HTTPException, Request
from pydantic import BaseModel

from maggma.api.models import Meta, Response
from maggma.api.query_operator import (
PaginationQuery,
QueryOperator,
SparseFieldsQuery,
)
from maggma.api.query_operator import PaginationQuery, QueryOperator, SparseFieldsQuery
from maggma.api.resource import Resource
from maggma.api.resource.utils import attach_query_ops
from maggma.api.utils import (
STORE_PARAMS,
merge_queries,
)
from maggma.api.utils import STORE_PARAMS, merge_queries
from maggma.core import Store


Expand Down
17 changes: 6 additions & 11 deletions src/maggma/api/resource/read_resource.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
from typing import Any, Dict, List, Optional, Type
from inspect import signature
from typing import Any, Dict, List, Optional, Type

from fastapi import Depends, HTTPException, Path, Request
from pydantic import BaseModel

from maggma.api.models import Meta, Response
from maggma.api.query_operator import (
PaginationQuery,
QueryOperator,
SparseFieldsQuery,
)
from maggma.api.query_operator import PaginationQuery, QueryOperator, SparseFieldsQuery
from maggma.api.resource import Resource
from maggma.api.resource.utils import attach_query_ops
from maggma.api.utils import (
STORE_PARAMS,
merge_queries,
)
from maggma.api.utils import STORE_PARAMS, merge_queries
from maggma.core import Store


Expand Down Expand Up @@ -104,7 +97,9 @@ def field_input():

async def get_by_key(
key: str = Path(
..., alias=key_name, title=f"The {key_name} of the {model_name} to get",
...,
alias=key_name,
title=f"The {key_name} of the {model_name} to get",
),
fields: STORE_PARAMS = Depends(field_input),
):
Expand Down
24 changes: 9 additions & 15 deletions src/maggma/api/resource/submission.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
from typing import Any, List, Optional, Type
from inspect import signature
from datetime import datetime
from enum import Enum
from inspect import signature
from typing import Any, List, Optional, Type
from uuid import uuid4

from fastapi import HTTPException, Path, Request
from pydantic import BaseModel, Field, create_model

from maggma.api.models import Response, Meta

from maggma.api.models import Meta, Response
from maggma.api.query_operator import QueryOperator, SubmissionQuery

from maggma.api.resource import Resource
from maggma.api.resource.utils import attach_query_ops
from maggma.api.utils import (
STORE_PARAMS,
merge_queries,
)
from maggma.api.utils import STORE_PARAMS, merge_queries
from maggma.core import Store
from enum import Enum
from pydantic import create_model, Field, BaseModel


class SubmissionResource(Resource):
Expand Down Expand Up @@ -73,9 +68,7 @@ def __init__(
self.tags = tags or []
self.post_query_operators = post_query_operators
self.get_query_operators = (
[
op for op in get_query_operators if op is not None # type: ignore
]
[op for op in get_query_operators if op is not None] # type: ignore
+ [SubmissionQuery(state_enum)]
if state_enum is not None
else get_query_operators
Expand Down Expand Up @@ -281,7 +274,8 @@ async def post_data(**queries: STORE_PARAMS):
self.store.update(docs=query["criteria"]) # type: ignore
except Exception:
raise HTTPException(
status_code=400, detail="Problem when trying to post data.",
status_code=400,
detail="Problem when trying to post data.",
)

response = {
Expand Down
6 changes: 4 additions & 2 deletions src/maggma/api/resource/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from typing import Callable, List, Dict
from fastapi import Request, Depends
from typing import Callable, Dict, List

from fastapi import Depends, Request

from maggma.api.query_operator import QueryOperator
from maggma.api.utils import STORE_PARAMS, attach_signature

Expand Down
20 changes: 14 additions & 6 deletions src/maggma/api/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import inspect
import sys
from typing import Any, Callable, Dict, List, Optional, Type

from monty.json import MSONable
Expand All @@ -7,6 +8,12 @@
from pydantic.utils import lenient_issubclass
from typing_extensions import Literal

if sys.version_info >= (3, 8):
from typing import get_args
else:
from typing_extensions import get_args


QUERY_PARAMS = ["criteria", "properties", "skip", "limit"]
STORE_PARAMS = Dict[
Literal["criteria", "properties", "sort", "skip", "limit", "request", "pipeline"],
Expand Down Expand Up @@ -110,12 +117,13 @@ def api_sanitize(
field.required = False
field.field_info.default = None

if (
field_type is not None
and lenient_issubclass(field_type, MSONable)
and allow_dict_msonable
):
field.type_ = allow_msonable_dict(field_type)
if field_type is not None and allow_dict_msonable:
if lenient_issubclass(field_type, MSONable):
field.type_ = allow_msonable_dict(field_type)
else:
for sub_type in get_args(field_type):
if lenient_issubclass(sub_type, MSONable):
allow_msonable_dict(sub_type)
field.populate_validators()

return pydantic_model
Expand Down
Loading