示例#1
0
class JsonApi(BaseModel):
    """An object describing the server's implementation"""

    version: str = StrictField(default="1.0",
                               description="Version of the json API used")
    meta: Optional[Meta] = StrictField(
        None, description="Non-standard meta information")
示例#2
0
class EntryInfoProperty(BaseModel):

    description: str = StrictField(
        ..., description="A human-readable description of the entry property")

    unit: Optional[str] = StrictField(
        None,
        description="""The physical unit of the entry property.
This MUST be a valid representation of units according to version 2.1 of [The Unified Code for Units of Measure](https://unitsofmeasure.org/ucum.html).
It is RECOMMENDED that non-standard (non-SI) units are described in the description for the property.""",
    )

    sortable: Optional[bool] = StrictField(
        None,
        description=
        """Defines whether the entry property can be used for sorting with the "sort" parameter.
If the entry listing endpoint supports sorting, this key MUST be present for sortable properties with value `true`.""",
    )

    type: Optional[DataType] = StrictField(
        None,
        description="""The type of the property's value.
This MUST be any of the types defined in the Data types section.
For the purpose of compatibility with future versions of this specification, a client MUST accept values that are not `string` values specifying any of the OPTIMADE Data types, but MUST then also disregard the `type` field.
Note, if the value is a nested type, only the outermost type should be reported.
E.g., for the entry resource `structures`, the `species` property is defined as a list of dictionaries, hence its `type` value would be `list`.""",
    )
示例#3
0
class Relationship(BaseModel):
    """Representation references from the resource object in which it’s defined to other resource objects."""

    links: Optional[RelationshipLinks] = StrictField(
        None,
        description=
        "a links object containing at least one of the following: self, related",
    )
    data: Optional[Union[BaseResource, List[BaseResource]]] = StrictField(
        None, description="Resource linkage")
    meta: Optional[Meta] = StrictField(
        None,
        description=
        "a meta object that contains non-standard meta-information about the relationship.",
    )

    @root_validator(pre=True)
    def at_least_one_relationship_key_must_be_set(cls, values):
        for value in values.values():
            if value is not None:
                break
        else:
            raise ValueError(
                "Either 'links', 'data', or 'meta' MUST be specified for Relationship"
            )
        return values
示例#4
0
class RelationshipLinks(BaseModel):
    """A resource object **MAY** contain references to other resource objects ("relationships").
    Relationships may be to-one or to-many.
    Relationships can be specified by including a member in a resource's links object.

    """

    self: Optional[Union[AnyUrl, Link]] = StrictField(
        None,
        description=
        """A link for the relationship itself (a 'relationship link').
This link allows the client to directly manipulate the relationship.
When fetched successfully, this link returns the [linkage](https://jsonapi.org/format/1.0/#document-resource-object-linkage) for the related resources as its primary data.
(See [Fetching Relationships](https://jsonapi.org/format/1.0/#fetching-relationships).)""",
    )
    related: Optional[Union[AnyUrl, Link]] = StrictField(
        None,
        description=
        "A [related resource link](https://jsonapi.org/format/1.0/#document-resource-object-related-resource-links).",
    )

    @root_validator(pre=True)
    def either_self_or_related_must_be_specified(cls, values):
        for value in values.values():
            if value is not None:
                break
        else:
            raise ValueError(
                "Either 'self' or 'related' MUST be specified for RelationshipLinks"
            )
        return values
示例#5
0
class BaseResource(BaseModel):
    """Minimum requirements to represent a Resource"""

    id: str = StrictField(..., description="Resource ID")
    type: str = StrictField(..., description="Resource type")

    class Config:
        @staticmethod
        def schema_extra(schema: Dict[str, Any],
                         model: Type["BaseResource"]) -> None:
            """Ensure `id` and `type` are the first two entries in the list required properties.

            Note:
                This _requires_ that `id` and `type` are the _first_ model fields defined
                for all sub-models of `BaseResource`.

            """
            if "id" not in schema.get("required", []):
                schema["required"] = ["id"] + schema.get("required", [])
            if "type" not in schema.get("required", []):
                required = []
                for field in schema.get("required", []):
                    required.append(field)
                    if field == "id":
                        # To make sure the property order match the listed properties,
                        # this ensures "type" is added immediately after "id".
                        required.append("type")
                schema["required"] = required
示例#6
0
class Link(BaseModel):
    """A link **MUST** be represented as either: a string containing the link's URL or a link object."""

    href: AnyUrl = StrictField(
        ..., description="a string containing the link’s URL.")
    meta: Optional[Meta] = StrictField(
        None,
        description=
        "a meta object containing non-standard meta-information about the link.",
    )
示例#7
0
class EntryResource(Resource):
    """The base model for an entry resource."""

    id: str = OptimadeField(
        ...,
        description="""An entry's ID as defined in section Definition of Terms.

- **Type**: string.

- **Requirements/Conventions**:
    - **Support**: MUST be supported by all implementations, MUST NOT be `null`.
    - **Query**: MUST be a queryable property with support for all mandatory filter features.
    - **Response**: REQUIRED in the response.

- **Examples**:
    - `"db/1234567"`
    - `"cod/2000000"`
    - `"cod/2000000@1234567"`
    - `"nomad/L1234567890"`
    - `"42"`""",
        support=SupportLevel.MUST,
        queryable=SupportLevel.MUST,
    )

    type: str = Field(
        description="""The name of the type of an entry.

- **Type**: string.

- **Requirements/Conventions**:
    - **Support**: MUST be supported by all implementations, MUST NOT be `null`.
    - **Query**: MUST be a queryable property with support for all mandatory filter features.
    - **Response**: REQUIRED in the response.
    - MUST be an existing entry type.
    - The entry of type `<type>` and ID `<id>` MUST be returned in response to a request for `/<type>/<id>` under the versioned base URL.

- **Example**: `"structures"`""",
        support=SupportLevel.MUST,
        queryable=SupportLevel.MUST,
    )

    attributes: EntryResourceAttributes = StrictField(
        ...,
        description=
        """A dictionary, containing key-value pairs representing the entry's properties, except for `type` and `id`.
Database-provider-specific properties need to include the database-provider-specific prefix (see section on Database-Provider-Specific Namespace Prefixes).""",
    )

    relationships: Optional[EntryRelationships] = StrictField(
        None,
        description=
        """A dictionary containing references to other entries according to the description in section Relationships encoded as [JSON API Relationships](https://jsonapi.org/format/1.0/#document-resource-object-relationships).
The OPTIONAL human-readable description of the relationship MAY be provided in the `description` field inside the `meta` dictionary of the JSON API resource identifier object.""",
    )
示例#8
0
class DatabaseCreate(EntryResourceCreate, LinksResourceAttributes):
    """Model for creating new LinksResources representing `/databases` resources in the
    MongoDB.

    Required fields:

    - `name`
    - `base_url`

    Original required fields for a
    [`LinksResourceAttributes`](https://www.optimade.org/optimade-python-tools/api_reference/models/links/#optimade.models.links.LinksResourceAttributes)
    model:

    - `name`
    - `description`
    - `link_type`

    """

    description: Optional[str]
    base_url: Union[AnyUrl, Link]
    homepage: Optional[Union[AnyUrl, Link]] = StrictField(
        None,
        description=(
            "JSON API links object, pointing to a homepage URL for this implementation."
        ),
    )
    link_type: Optional[LinkType] = StrictField(
        None,
        title="Link Type",
        description=(
            "The type of the linked relation.\nMUST be one of these values: 'child', "
            "'root', 'external', 'providers'."
        ),
    )

    @validator("link_type")
    def ensure_database_link_type(cls, value: LinkType) -> LinkType:
        """Ensure databases are not index meta-database-only types

        I.e., ensure they're not of type `"root"` or `"providers"`.

        !!! note
            Both `"external"` and `"child"` can still represent index meta-dbs,
            but `"root"` and `"providers"` can not represent "regular" dbs.

        """
        if value in (LinkType.ROOT, LinkType.PROVIDERS):
            raise ValueError(
                "Databases with 'root' or 'providers' link_type is not allowed for "
                f"gateway-usable database resources. Given link_type: {value}"
            )
        return value
示例#9
0
class EntryRelationships(Relationships):
    """This model wraps the JSON API Relationships to include type-specific top level keys. """

    references: Optional[ReferenceRelationship] = StrictField(
        None,
        description=
        "Object containing links to relationships with entries of the `references` type.",
    )

    structures: Optional[StructureRelationship] = StrictField(
        None,
        description=
        "Object containing links to relationships with entries of the `structures` type.",
    )
示例#10
0
class ErrorSource(BaseModel):
    """an object containing references to the source of the error"""

    pointer: Optional[str] = StrictField(
        None,
        description=
        "a JSON Pointer [RFC6901] to the associated entity in the request document "
        '[e.g. "/data" for a primary data object, or "/data/attributes/title" for a specific attribute].',
    )
    parameter: Optional[str] = StrictField(
        None,
        description=
        "a string indicating which URI query parameter caused the error.",
    )
示例#11
0
class OptimadeError(jsonapi.Error):
    """detail MUST be present"""

    detail: str = StrictField(
        ...,
        description="A human-readable explanation specific to this occurrence of the problem.",
    )
示例#12
0
class BaseRelationshipResource(jsonapi.BaseResource):
    """Minimum requirements to represent a relationship resource"""

    meta: Optional[BaseRelationshipMeta] = StrictField(
        None,
        description="Relationship meta field. MUST contain 'description' if supplied.",
    )
示例#13
0
class StructureResponseMany(EntryResponseMany):
    data: Union[List[StructureResource], List[Dict[str, Any]]] = StrictField(
        ...,
        description=
        "List of unique OPTIMADE structures entry resource objects.",
        uniqueItems=True,
    )
示例#14
0
class ErrorLinks(BaseModel):
    """A Links object specific to Error objects"""

    about: Optional[Union[AnyUrl, Link]] = StrictField(
        None,
        description=
        "A link that leads to further details about this particular occurrence of the problem.",
    )
class Relationship(jsonapi.Relationship):
    """Similar to normal JSON API relationship, but with addition of OPTIONAL meta field for a resource."""

    data: Optional[Union[BaseRelationshipResource,
                         List[BaseRelationshipResource]]] = StrictField(
                             None,
                             description="Resource linkage",
                             uniqueItems=True)
示例#16
0
class ResourceLinks(BaseModel):
    """A Resource Links object"""

    self: Optional[Union[AnyUrl, Link]] = StrictField(
        None,
        description=
        "A link that identifies the resource represented by the resource object.",
    )
示例#17
0
class ErrorResponse(Response):
    """errors MUST be present and data MUST be skipped"""

    meta: ResponseMeta = StrictField(
        ..., description="A meta object containing non-standard information")
    errors: List[OptimadeError] = StrictField(
        ...,
        description=
        "A list of OPTIMADE-specific JSON API error objects, where the field detail MUST be present.",
        uniqueItems=True,
    )

    @root_validator(pre=True)
    def data_must_be_skipped(cls, values):
        if values.get("data", None) is not None:
            raise ValueError(
                "data MUST be skipped for failures reporting errors")
        return values
示例#18
0
class IndexInfoAttributes(BaseInfoAttributes):
    """Attributes for Base URL Info endpoint for an Index Meta-Database"""

    is_index: bool = StrictField(
        True,
        const=True,
        description=
        "This must be `true` since this is an index meta-database (see section Index Meta-Database).",
    )
示例#19
0
class IndexRelationship(BaseModel):
    """Index Meta-Database relationship"""

    data: Union[None, RelatedLinksResource] = StrictField(
        ...,
        description=
        """[JSON API resource linkage](http://jsonapi.org/format/1.0/#document-links).
It MUST be either `null` or contain a single Links identifier object with the fields `id` and `type`""",
    )
示例#20
0
class ResponseMetaQuery(BaseModel):
    """ Information on the query that was requested. """

    representation: str = StrictField(
        ...,
        description="""A string with the part of the URL following the versioned or unversioned base URL that serves the API.
Query parameters that have not been used in processing the request MAY be omitted.
In particular, if no query parameters have been involved in processing the request, the query part of the URL MAY be excluded.
Example: `/structures?filter=nelements=2`""",
    )
示例#21
0
class AvailableApiVersion(BaseModel):
    """A JSON object containing information about an available API version"""

    url: AnyHttpUrl = StrictField(
        ...,
        description=
        "A string specifying a versioned base URL that MUST adhere to the rules in section Base URL",
        pattern=r".+/v[0-1](\.[0-9]+)*/?$",
    )

    version: SemanticVersion = StrictField(
        ...,
        description=
        """A string containing the full version number of the API served at that versioned base URL.
The version number string MUST NOT be prefixed by, e.g., 'v'.
Examples: `1.0.0`, `1.0.0-rc.2`.""",
    )

    @validator("url")
    def url_must_be_versioned_base_url(cls, v):
        """The URL must be a valid versioned Base URL"""
        if not re.match(r".+/v[0-1](\.[0-9]+)*/?$", v):
            raise ValueError(f"url MUST be a versioned base URL. It is: {v}")
        return v

    @root_validator(pre=False, skip_on_failure=True)
    def crosscheck_url_and_version(cls, values):
        """ Check that URL version and API version are compatible. """
        url_version = (values["url"].split(
            "/")[-2 if values["url"].endswith("/") else -1].replace("v", ""))
        # as with version urls, we need to split any release tags or build metadata out of these URLs
        url_version = tuple(
            int(val)
            for val in url_version.split("-")[0].split("+")[0].split("."))
        api_version = tuple(
            int(val) for val in values["version"].split("-")[0].split("+")
            [0].split("."))
        if any(a != b for a, b in zip(url_version, api_version)):
            raise ValueError(
                f"API version {api_version} is not compatible with url version {url_version}."
            )
        return values
示例#22
0
class Provider(BaseModel):
    """Information on the database provider of the implementation."""

    name: str = StrictField(..., description="a short name for the database provider")

    description: str = StrictField(
        ..., description="a longer description of the database provider"
    )

    prefix: str = StrictField(
        ...,
        description="database-provider-specific prefix as found in section Database-Provider-Specific Namespace Prefixes.",
    )

    homepage: Optional[Union[AnyHttpUrl, jsonapi.Link]] = StrictField(
        None,
        description="a [JSON API links object](http://jsonapi.org/format/1.0#document-links) "
        "pointing to homepage of the database provider, either "
        "directly as a string, or as a link object.",
    )
示例#23
0
class IndexInfoResource(BaseInfoResource):
    """Index Meta-Database Base URL Info endpoint resource"""

    attributes: IndexInfoAttributes = Field(...)
    relationships: Union[None, Dict[
        DefaultRelationship, IndexRelationship]] = StrictField(
            ...,
            description=
            """Reference to the Links identifier object under the `links` endpoint that the provider has chosen as their 'default' OPTIMADE API database.
A client SHOULD present this database as the first choice when an end-user chooses this provider.""",
        )
示例#24
0
class LinksResource(EntryResource):
    """A Links endpoint resource object"""

    type: str = StrictField(
        "links",
        const="links",
        description="These objects are described in detail in the section Links Endpoint",
        pattern="^links$",
    )

    attributes: LinksResourceAttributes = StrictField(
        ...,
        description="A dictionary containing key-value pairs representing the Links resource's properties.",
    )

    @root_validator(pre=True)
    def relationships_must_not_be_present(cls, values):
        if values.get("relationships", None) is not None:
            raise ValueError('"relationships" is not allowed for links resources')
        return values
示例#25
0
class EntryInfoResource(BaseModel):

    formats: List[str] = StrictField(
        ...,
        description="List of output formats available for this type of entry.")

    description: str = StrictField(...,
                                   description="Description of the entry.")

    properties: Dict[str, EntryInfoProperty] = StrictField(
        ...,
        description=
        "A dictionary describing queryable properties for this entry type, where each key is a property name.",
    )

    output_fields_by_format: Dict[str, List[str]] = StrictField(
        ...,
        description=
        "Dictionary of available output fields for this entry type, where the keys are the values of the `formats` list and the values are the keys of the `properties` dictionary.",
    )
 class CorrectModelWithStrictField(BaseModel):
     # check that unit and uniqueItems are passed through
     good_field: List[str] = StrictField(
         ...,
         support=SupportLevel.MUST,
         queryable=SupportLevel.OPTIONAL,
         description="Unit test to make sure that StrictField allows through OptimadeField keys",
         pattern="^structures$",
         unit="stringiness",
         uniqueItems=True,
         sortable=True,
     )
示例#27
0
class ToplevelLinks(BaseModel):
    """A set of Links objects, possibly including pagination"""

    self: Optional[Union[AnyUrl,
                         Link]] = StrictField(None,
                                              description="A link to itself")
    related: Optional[Union[AnyUrl, Link]] = StrictField(
        None, description="A related resource link")

    # Pagination
    first: Optional[Union[AnyUrl, Link]] = StrictField(
        None, description="The first page of data")
    last: Optional[Union[AnyUrl, Link]] = StrictField(
        None, description="The last page of data")
    prev: Optional[Union[AnyUrl, Link]] = StrictField(
        None, description="The previous page of data")
    next: Optional[Union[AnyUrl, Link]] = StrictField(
        None, description="The next page of data")

    @root_validator(pre=False)
    def check_additional_keys_are_links(cls, values):
        """The `ToplevelLinks` class allows any additional keys, as long as
        they are also Links or Urls themselves.

        """
        for key, value in values.items():
            if key not in cls.schema()["properties"]:
                values[key] = parse_obj_as(Optional[Union[AnyUrl, Link]],
                                           value)

        return values

    class Config:
        extra = "allow"
class Implementation(BaseModel):
    """Information on the server implementation"""

    name: Optional[str] = StrictField(None,
                                      description="name of the implementation")

    version: Optional[str] = StrictField(
        None, description="version string of the current implementation")

    homepage: Optional[Union[AnyHttpUrl, jsonapi.Link]] = StrictField(
        None,
        description=
        "A [JSON API links object](http://jsonapi.org/format/1.0/#document-links) pointing to the homepage of the implementation.",
    )

    source_url: Optional[Union[AnyUrl, jsonapi.Link]] = StrictField(
        None,
        description=
        "A [JSON API links object](http://jsonapi.org/format/1.0/#document-links) pointing to the implementation source, either downloadable archive or version control system.",
    )

    maintainer: Optional[ImplementationMaintainer] = StrictField(
        None,
        description=
        "A dictionary providing details about the maintainer of the implementation.",
    )

    issue_tracker: Optional[Union[AnyUrl, jsonapi.Link]] = StrictField(
        None,
        description=
        "A [JSON API links object](http://jsonapi.org/format/1.0/#document-links) pointing to the implementation's issue tracker.",
    )
示例#29
0
class LinksResourceAttributes(Attributes):
    """Links endpoint resource object attributes"""

    name: str = StrictField(
        ...,
        description=
        "Human-readable name for the OPTIMADE API implementation, e.g., for use in clients to show the name to the end-user.",
    )
    description: str = StrictField(
        ...,
        description=
        "Human-readable description for the OPTIMADE API implementation, e.g., for use in clients to show a description to the end-user.",
    )
    base_url: Optional[Union[AnyUrl, Link]] = StrictField(
        ...,
        description=
        "JSON API links object, pointing to the base URL for this implementation",
    )

    homepage: Optional[Union[AnyUrl, Link]] = StrictField(
        ...,
        description=
        "JSON API links object, pointing to a homepage URL for this implementation",
    )

    link_type: LinkType = StrictField(
        ...,
        title="Link Type",
        description="""The type of the linked relation.
MUST be one of these values: 'child', 'root', 'external', 'providers'.""",
    )

    aggregate: Optional[Aggregate] = StrictField(
        Aggregate.OK,
        title="Aggregate",
        description=
        """A string indicating whether a client that is following links to aggregate results from different OPTIMADE implementations should follow this link or not.
This flag SHOULD NOT be indicated for links where `link_type` is not `child`.

If not specified, clients MAY assume that the value is `ok`.
If specified, and the value is anything different than `ok`, the client MUST assume that the server is suggesting not to follow the link during aggregation by default (also if the value is not among the known ones, in case a future specification adds new accepted values).

Specific values indicate the reason why the server is providing the suggestion.
A client MAY follow the link anyway if it has reason to do so (e.g., if the client is looking for all test databases, it MAY follow the links marked with `aggregate`=`test`).

If specified, it MUST be one of the values listed in section Link Aggregate Options.""",
    )

    no_aggregate_reason: Optional[str] = StrictField(
        None,
        description=
        """An OPTIONAL human-readable string indicating the reason for suggesting not to aggregate results following the link.
It SHOULD NOT be present if `aggregate`=`ok`.""",
    )
示例#30
0
class Resource(BaseResource):
    """Resource objects appear in a JSON API document to represent resources."""

    links: Optional[ResourceLinks] = StrictField(
        None,
        description="a links object containing links related to the resource.")
    meta: Optional[Meta] = StrictField(
        None,
        description=
        "a meta object containing non-standard meta-information about a resource that can not be represented as an attribute or relationship.",
    )
    attributes: Optional[Attributes] = StrictField(
        None,
        description=
        "an attributes object representing some of the resource’s data.",
    )
    relationships: Optional[Relationships] = StrictField(
        None,
        description=
        """[Relationships object](https://jsonapi.org/format/1.0/#document-resource-object-relationships)
describing relationships between the resource and other JSON API resources.""",
    )