Skip to content

Commit

Permalink
Merge pull request #14 from Materials-Consortia/reorg-models
Browse files Browse the repository at this point in the history
reorg models
  • Loading branch information
dwinston committed Jun 12, 2019
2 parents d90ad05 + 42ea24d commit bcefa54
Show file tree
Hide file tree
Showing 14 changed files with 195 additions and 174 deletions.
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ language: python
python:
- "3.6"
script:
- pip install -e .[schema-validation]
- pip install -e .
- pip install -r requirements.txt
- pip install -r requirements-optional.txt
- pytest
- openapi-spec-validator openapi.json
4 changes: 3 additions & 1 deletion optimade/server/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
from optimade.filterparser import Parser
from optimade.filtertransformers.mongo import MongoTransformer

from .models import NonnegativeInt, Resource, StructureMapper
from .models.util import NonnegativeInt
from .models.jsonapi import Resource
from .models.structures import StructureMapper
from .deps import EntryListingQueryParams


Expand Down
4 changes: 2 additions & 2 deletions optimade/server/deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
from pathlib import Path

from fastapi import Query
from pydantic import EmailStr, Schema, BaseModel
from pydantic import EmailStr

from .models import NonnegativeInt
from .models.util import NonnegativeInt

config = ConfigParser()
config.read(Path(__file__).resolve().parent.joinpath('config.ini'))
Expand Down
7 changes: 3 additions & 4 deletions optimade/server/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@

from .deps import EntryListingQueryParams
from .collections import MongoCollection
from .models import (
Link, Links, StructureResource, OptimadeResponseMeta, OptimadeResponseMetaQuery,
OptimadeStructureResponse,
)
from .models.jsonapi import Link, Links
from .models.structures import StructureResource
from. models.toplevel import OptimadeResponseMeta, OptimadeResponseMetaQuery, OptimadeStructureResponse

config = ConfigParser()
config.read(Path(__file__).resolve().parent.joinpath('config.ini'))
Expand Down
164 changes: 0 additions & 164 deletions optimade/server/models.py

This file was deleted.

Empty file.
17 changes: 17 additions & 0 deletions optimade/server/models/baseinfo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from typing import Dict, List

from pydantic import BaseModel, UrlStr


class BaseInfoAttributes(BaseModel):
api_version: str
available_api_versions: Dict[str, UrlStr]
formats: List[str] = ["json"]
entry_types_by_format: Dict[str, List[str]]
available_endpoints: List[str] = ["structure", "all", "info"]


class BaseInfoResource(BaseModel):
id: str = "/"
type: str = "info"
attributes: BaseInfoAttributes
34 changes: 34 additions & 0 deletions optimade/server/models/entries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from datetime import datetime
from typing import Optional, Dict, List

from pydantic import BaseModel

from .jsonapi import Resource


class EntryResourceAttributes(BaseModel):
local_id: str
last_modified: datetime
immutable_id: Optional[str]


class EntryResource(Resource):
attributes: EntryResourceAttributes


class EntryPropertyInfo(BaseModel):
description: str
unit: Optional[str]


class EntryInfoAttributes(BaseModel):
description: str
properties: Dict[str, EntryPropertyInfo]
formats: List[str] = ["json"]
output_fields_by_format: Dict[str, List[str]]


class EntryInfoResource(BaseModel):
id: str
type: str = "info"
attributes: EntryInfoAttributes
20 changes: 20 additions & 0 deletions optimade/server/models/jsonapi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""
This module should reproduce https://jsonapi.org/schema
"""
from typing import Optional

from pydantic import BaseModel, UrlStr


class Link(BaseModel):
href: UrlStr
meta: Optional[dict]


class Links(BaseModel):
next: Optional[Link]


class Resource(BaseModel):
id: str
type: str
59 changes: 59 additions & 0 deletions optimade/server/models/structures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from optimade.server.models.entries import EntryResourceAttributes, EntryResource


class StructureResourceAttributes(EntryResourceAttributes):
elements: str = None
nelements: int = None
chemical_formula: str = None
formula_prototype: str = None


class StructureResource(EntryResource):
type = "structure"
attributes: StructureResourceAttributes


class StructureMapper:
aliases = (
("id", "task_id"),
("local_id", "task_id"),
("last_modified", "last_updated"),
("formula_prototype", "formula_anonymous"),
("chemical_formula", "pretty_formula"),
)

list_fields = (
"elements",
)

@classmethod
def alias_for(cls, field):
return dict(cls.aliases).get(field, field)

@classmethod
def map_back(cls, doc):
if "_id" in doc:
del doc["_id"]
print(doc)
mapping = ((real, alias) for alias, real in cls.aliases)
newdoc = {}
reals = {real for alias, real in cls.aliases}
for k in doc:
if k not in reals:
newdoc[k] = doc[k]
for real, alias in mapping:
if real in doc:
newdoc[alias] = doc[real]
for k in newdoc:
if k in cls.list_fields:
newdoc[k] = ",".join(sorted(newdoc[k]))

print(newdoc)
if "attributes" in newdoc:
raise Exception("Will overwrite doc field!")
newdoc["attributes"] = newdoc.copy()
newdoc["attributes"].pop("id")
for k in list(newdoc.keys()):
if k not in ("id", "attributes"):
del newdoc[k]
return newdoc
47 changes: 47 additions & 0 deletions optimade/server/models/toplevel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from datetime import datetime
from typing import Union, List

from pydantic import BaseModel, validator, UrlStr, Schema

from optimade.server.models.jsonapi import Links, Resource
from optimade.server.models.structures import StructureResource
from optimade.server.models.util import NonnegativeInt


class OptimadeResponseMetaQuery(BaseModel):
representation: str

@validator('representation')
def representation_must_be_valid_url_with_base(cls, v):
UrlStr(f'https://baseurl.net{v}')
return v


class OptimadeResponseMeta(BaseModel):
"""
A JSON API meta member that contains JSON API meta objects of non-standard meta-information.
In addition to the required fields, it MAY contain
- `data_available`: an integer containing the total number of data objects available in the database.
- `last_id`: a string containing the last ID returned.
- `response_message`: response string from the server.
Other OPTIONAL additional information global to the query that is not specified in this document, MUST start with
a database-provider-specific prefix
"""
query: OptimadeResponseMetaQuery
api_version: str = Schema(..., description="a string containing the version of the API implementation.")
time_stamp: datetime
data_returned: NonnegativeInt
more_data_available: bool


class OptimadeResponse(BaseModel):
links: Links
meta: OptimadeResponseMeta
data: Union[Resource, List[Resource]]


class OptimadeStructureResponse(OptimadeResponse):
data: Union[StructureResource, List[StructureResource]]
5 changes: 5 additions & 0 deletions optimade/server/models/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from pydantic import ConstrainedInt


class NonnegativeInt(ConstrainedInt):
ge = 0

0 comments on commit bcefa54

Please sign in to comment.