Skip to content

OPTIMADE Data Models

This page provides documentation for the optimade.models submodule, where all the OPTIMADE (and JSON:API)-defined data models are located.

For example, the three OPTIMADE entry types, structures, references and links, are defined primarily through the corresponding attribute models:

As well as validating data types when creating instances of these models, this package defines several OPTIMADE-specific validators that ensure consistency between fields (e.g., the value of nsites matches the number of positions provided in cartesian_site_positions).

baseinfo

VERSIONED_BASE_URL_PATTERN = '^.+/v[0-1](\\.[0-9]+)*/?$' module-attribute

AvailableApiVersion

Bases: BaseModel

A JSON object containing information about an available API version

Source code in optimade/models/baseinfo.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
class AvailableApiVersion(BaseModel):
    """A JSON object containing information about an available API version"""

    url: Annotated[
        AnyHttpUrl,
        StrictField(
            description="A string specifying a versioned base URL that MUST adhere to the rules in section Base URL",
            json_schema_extra={
                "pattern": VERSIONED_BASE_URL_PATTERN,
            },
        ),
    ]

    version: Annotated[
        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`.""",
        ),
    ]

    @field_validator("url", mode="after")
    @classmethod
    def url_must_be_versioned_base_Url(cls, value: AnyHttpUrl) -> AnyHttpUrl:
        """The URL must be a versioned base URL"""
        if not re.match(VERSIONED_BASE_URL_PATTERN, str(value)):
            raise ValueError(
                f"URL {value} must be a versioned base URL (i.e., must match the "
                f"pattern '{VERSIONED_BASE_URL_PATTERN}')"
            )
        return value

    @model_validator(mode="after")
    def crosscheck_url_and_version(self) -> "AvailableApiVersion":
        """Check that URL version and API version are compatible."""
        url = (
            str(self.url)
            .split("/")[-2 if str(self.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.split("-")[0].split("+")[0].split(".")
        )
        api_version = tuple(
            int(val) for val in str(self.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 self

url: Annotated[AnyHttpUrl, StrictField(description='A string specifying a versioned base URL that MUST adhere to the rules in section Base URL', json_schema_extra={pattern: VERSIONED_BASE_URL_PATTERN})] instance-attribute

version: Annotated[SemanticVersion, StrictField(description="A string containing the full version number of the API served at that versioned base URL.\nThe version number string MUST NOT be prefixed by, e.g., 'v'.\nExamples: `1.0.0`, `1.0.0-rc.2`.")] instance-attribute

crosscheck_url_and_version()

Check that URL version and API version are compatible.

Source code in optimade/models/baseinfo.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
@model_validator(mode="after")
def crosscheck_url_and_version(self) -> "AvailableApiVersion":
    """Check that URL version and API version are compatible."""
    url = (
        str(self.url)
        .split("/")[-2 if str(self.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.split("-")[0].split("+")[0].split(".")
    )
    api_version = tuple(
        int(val) for val in str(self.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 self

url_must_be_versioned_base_Url(value) classmethod

The URL must be a versioned base URL

Source code in optimade/models/baseinfo.py
38
39
40
41
42
43
44
45
46
47
@field_validator("url", mode="after")
@classmethod
def url_must_be_versioned_base_Url(cls, value: AnyHttpUrl) -> AnyHttpUrl:
    """The URL must be a versioned base URL"""
    if not re.match(VERSIONED_BASE_URL_PATTERN, str(value)):
        raise ValueError(
            f"URL {value} must be a versioned base URL (i.e., must match the "
            f"pattern '{VERSIONED_BASE_URL_PATTERN}')"
        )
    return value

BaseInfoAttributes

Bases: BaseModel

Attributes for Base URL Info endpoint

Source code in optimade/models/baseinfo.py
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
class BaseInfoAttributes(BaseModel):
    """Attributes for Base URL Info endpoint"""

    api_version: Annotated[
        SemanticVersion,
        StrictField(
            description="""Presently used full version of the OPTIMADE API.
The version number string MUST NOT be prefixed by, e.g., "v".
Examples: `1.0.0`, `1.0.0-rc.2`.""",
        ),
    ]
    available_api_versions: Annotated[
        list[AvailableApiVersion],
        StrictField(
            description="A list of dictionaries of available API versions at other base URLs",
        ),
    ]
    formats: Annotated[
        list[str], StrictField(description="List of available output formats.")
    ] = ["json"]
    available_endpoints: Annotated[
        list[str],
        StrictField(
            description="List of available endpoints (i.e., the string to be appended to the versioned base URL).",
        ),
    ]
    entry_types_by_format: Annotated[
        dict[str, list[str]],
        StrictField(
            description="Available entry endpoints as a function of output formats."
        ),
    ]
    is_index: Annotated[
        Optional[bool],
        StrictField(
            description="If true, this is an index meta-database base URL (see section Index Meta-Database). "
            "If this member is not provided, the client MUST assume this is not an index meta-database base URL "
            "(i.e., the default is for `is_index` to be `false`).",
        ),
    ] = False

    @model_validator(mode="after")
    def formats_and_endpoints_must_be_valid(self) -> "BaseInfoAttributes":
        for format_, endpoints in self.entry_types_by_format.items():
            if format_ not in self.formats:
                raise ValueError(f"'{format_}' must be listed in formats to be valid")
            for endpoint in endpoints:
                if endpoint not in self.available_endpoints:
                    raise ValueError(
                        f"'{endpoint}' must be listed in available_endpoints to be valid"
                    )
        return self

api_version: Annotated[SemanticVersion, StrictField(description='Presently used full version of the OPTIMADE API.\nThe version number string MUST NOT be prefixed by, e.g., "v".\nExamples: `1.0.0`, `1.0.0-rc.2`.')] instance-attribute

available_api_versions: Annotated[list[AvailableApiVersion], StrictField(description='A list of dictionaries of available API versions at other base URLs')] instance-attribute

available_endpoints: Annotated[list[str], StrictField(description='List of available endpoints (i.e., the string to be appended to the versioned base URL).')] instance-attribute

entry_types_by_format: Annotated[dict[str, list[str]], StrictField(description='Available entry endpoints as a function of output formats.')] instance-attribute

formats: Annotated[list[str], StrictField(description='List of available output formats.')] = ['json'] class-attribute instance-attribute

is_index: Annotated[Optional[bool], StrictField(description='If true, this is an index meta-database base URL (see section Index Meta-Database). If this member is not provided, the client MUST assume this is not an index meta-database base URL (i.e., the default is for `is_index` to be `false`).')] = False class-attribute instance-attribute

formats_and_endpoints_must_be_valid()

Source code in optimade/models/baseinfo.py
112
113
114
115
116
117
118
119
120
121
122
@model_validator(mode="after")
def formats_and_endpoints_must_be_valid(self) -> "BaseInfoAttributes":
    for format_, endpoints in self.entry_types_by_format.items():
        if format_ not in self.formats:
            raise ValueError(f"'{format_}' must be listed in formats to be valid")
        for endpoint in endpoints:
            if endpoint not in self.available_endpoints:
                raise ValueError(
                    f"'{endpoint}' must be listed in available_endpoints to be valid"
                )
    return self

BaseInfoResource

Bases: Resource

Source code in optimade/models/baseinfo.py
125
126
127
128
class BaseInfoResource(Resource):
    id: Literal["/"] = "/"
    type: Literal["info"] = "info"
    attributes: BaseInfoAttributes

attributes: BaseInfoAttributes instance-attribute

id: Literal['/'] = '/' class-attribute instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='a meta object containing non-standard meta-information about a resource that can not be represented as an attribute or relationship.')] = None class-attribute instance-attribute

model_config = ConfigDict(json_schema_extra=resource_json_schema_extra) class-attribute instance-attribute

relationships: Annotated[Optional[Relationships], StrictField(description='[Relationships object](https://jsonapi.org/format/1.0/#document-resource-object-relationships)\ndescribing relationships between the resource and other JSON API resources.')] = None class-attribute instance-attribute

type: Literal['info'] = 'info' class-attribute instance-attribute

entries

EntryInfoProperty

Bases: BaseModel

Source code in optimade/models/entries.py
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
class EntryInfoProperty(BaseModel):
    description: Annotated[
        str,
        StrictField(description="A human-readable description of the entry property"),
    ]

    unit: Annotated[
        Optional[str],
        StrictField(
            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.""",
        ),
    ] = None

    sortable: Annotated[
        Optional[bool],
        StrictField(
            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`.""",
        ),
    ] = None

    type: Annotated[
        Optional[DataType],
        StrictField(
            title="Type",
            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`.""",
        ),
    ] = None

description: Annotated[str, StrictField(description='A human-readable description of the entry property')] instance-attribute

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

type: Annotated[Optional[DataType], StrictField(title=Type, description="The type of the property's value.\nThis MUST be any of the types defined in the Data types section.\nFor 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.\nNote, if the value is a nested type, only the outermost type should be reported.\nE.g., for the entry resource `structures`, the `species` property is defined as a list of dictionaries, hence its `type` value would be `list`.")] = None class-attribute instance-attribute

unit: Annotated[Optional[str], StrictField(description='The physical unit of the entry property.\nThis 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).\nIt is RECOMMENDED that non-standard (non-SI) units are described in the description for the property.')] = None class-attribute instance-attribute

EntryInfoResource

Bases: BaseModel

Source code in optimade/models/entries.py
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
class EntryInfoResource(BaseModel):
    formats: Annotated[
        list[str],
        StrictField(
            description="List of output formats available for this type of entry."
        ),
    ]

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

    properties: Annotated[
        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: Annotated[
        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.",
        ),
    ]

description: Annotated[str, StrictField(description='Description of the entry.')] instance-attribute

formats: Annotated[list[str], StrictField(description='List of output formats available for this type of entry.')] instance-attribute

output_fields_by_format: Annotated[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.')] instance-attribute

properties: Annotated[dict[str, EntryInfoProperty], StrictField(description='A dictionary describing queryable properties for this entry type, where each key is a property name.')] instance-attribute

EntryRelationships

Bases: Relationships

This model wraps the JSON API Relationships to include type-specific top level keys.

Source code in optimade/models/entries.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
class EntryRelationships(Relationships):
    """This model wraps the JSON API Relationships to include type-specific top level keys."""

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

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

references: Annotated[Optional[ReferenceRelationship], StrictField(description='Object containing links to relationships with entries of the `references` type.')] = None class-attribute instance-attribute

structures: Annotated[Optional[StructureRelationship], StrictField(description='Object containing links to relationships with entries of the `structures` type.')] = None class-attribute instance-attribute

check_illegal_relationships_fields()

Source code in optimade/models/jsonapi.py
296
297
298
299
300
301
302
303
304
@model_validator(mode="after")
def check_illegal_relationships_fields(self) -> "Relationships":
    illegal_fields = ("id", "type")
    for field in illegal_fields:
        if hasattr(self, field):
            raise ValueError(
                f"{illegal_fields} MUST NOT be fields under Relationships"
            )
    return self

EntryResource

Bases: Resource

The base model for an entry resource.

Source code in optimade/models/entries.py
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
class EntryResource(Resource):
    """The base model for an entry resource."""

    id: Annotated[
        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: Annotated[
        str,
        OptimadeField(
            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: Annotated[
        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: Annotated[
        Optional[EntryRelationships],
        StrictField(
            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.""",
        ),
    ] = None

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

id: Annotated[str, OptimadeField(description='An entry\'s ID as defined in section Definition of Terms.\n\n- **Type**: string.\n\n- **Requirements/Conventions**:\n - **Support**: MUST be supported by all implementations, MUST NOT be `null`.\n - **Query**: MUST be a queryable property with support for all mandatory filter features.\n - **Response**: REQUIRED in the response.\n\n- **Examples**:\n - `"db/1234567"`\n - `"cod/2000000"`\n - `"cod/2000000@1234567"`\n - `"nomad/L1234567890"`\n - `"42"`', support=SupportLevel.MUST, queryable=SupportLevel.MUST)] instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='a meta object containing non-standard meta-information about a resource that can not be represented as an attribute or relationship.')] = None class-attribute instance-attribute

model_config = ConfigDict(json_schema_extra=resource_json_schema_extra) class-attribute instance-attribute

relationships: Annotated[Optional[EntryRelationships], StrictField(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).\nThe 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.')] = None class-attribute instance-attribute

type: Annotated[str, OptimadeField(description='The name of the type of an entry.\n\n- **Type**: string.\n\n- **Requirements/Conventions**:\n - **Support**: MUST be supported by all implementations, MUST NOT be `null`.\n - **Query**: MUST be a queryable property with support for all mandatory filter features.\n - **Response**: REQUIRED in the response.\n - MUST be an existing entry type.\n - The entry of type `<type>` and ID `<id>` MUST be returned in response to a request for `/<type>/<id>` under the versioned base URL.\n\n- **Example**: `"structures"`', support=SupportLevel.MUST, queryable=SupportLevel.MUST)] instance-attribute

EntryResourceAttributes

Bases: Attributes

Contains key-value pairs representing the entry's properties.

Source code in optimade/models/entries.py
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
class EntryResourceAttributes(Attributes):
    """Contains key-value pairs representing the entry's properties."""

    immutable_id: Annotated[
        Optional[str],
        OptimadeField(
            description="""The entry's immutable ID (e.g., an UUID). This is important for databases having preferred IDs that point to "the latest version" of a record, but still offer access to older variants. This ID maps to the version-specific record, in case it changes in the future.

- **Type**: string.

- **Requirements/Conventions**:
    - **Support**: OPTIONAL support in implementations, i.e., MAY be `null`.
    - **Query**: MUST be a queryable property with support for all mandatory filter features.

- **Examples**:
    - `"8bd3e750-b477-41a0-9b11-3a799f21b44f"`
    - `"fjeiwoj,54;@=%<>#32"` (Strings that are not URL-safe are allowed.)""",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.MUST,
        ),
    ] = None

    last_modified: Annotated[
        Optional[datetime],
        OptimadeField(
            description="""Date and time representing when the entry was last modified.

- **Type**: timestamp.

- **Requirements/Conventions**:
    - **Support**: SHOULD be supported by all implementations, i.e., SHOULD NOT be `null`.
    - **Query**: MUST be a queryable property with support for all mandatory filter features.
    - **Response**: REQUIRED in the response unless the query parameter `response_fields` is present and does not include this property.

- **Example**:
    - As part of JSON response format: `"2007-04-05T14:30:20Z"` (i.e., encoded as an [RFC 3339 Internet Date/Time Format](https://tools.ietf.org/html/rfc3339#section-5.6) string.)""",
            support=SupportLevel.SHOULD,
            queryable=SupportLevel.MUST,
        ),
    ]

    @field_validator("immutable_id", mode="before")
    @classmethod
    def cast_immutable_id_to_str(cls, value: Any) -> str:
        """Convenience validator for casting `immutable_id` to a string."""
        if value is not None and not isinstance(value, str):
            value = str(value)

        return value

immutable_id: Annotated[Optional[str], OptimadeField(description='The entry\'s immutable ID (e.g., an UUID). This is important for databases having preferred IDs that point to "the latest version" of a record, but still offer access to older variants. This ID maps to the version-specific record, in case it changes in the future.\n\n- **Type**: string.\n\n- **Requirements/Conventions**:\n - **Support**: OPTIONAL support in implementations, i.e., MAY be `null`.\n - **Query**: MUST be a queryable property with support for all mandatory filter features.\n\n- **Examples**:\n - `"8bd3e750-b477-41a0-9b11-3a799f21b44f"`\n - `"fjeiwoj,54;@=%<>#32"` (Strings that are not URL-safe are allowed.)', support=SupportLevel.OPTIONAL, queryable=SupportLevel.MUST)] = None class-attribute instance-attribute

last_modified: Annotated[Optional[datetime], OptimadeField(description='Date and time representing when the entry was last modified.\n\n- **Type**: timestamp.\n\n- **Requirements/Conventions**:\n - **Support**: SHOULD be supported by all implementations, i.e., SHOULD NOT be `null`.\n - **Query**: MUST be a queryable property with support for all mandatory filter features.\n - **Response**: REQUIRED in the response unless the query parameter `response_fields` is present and does not include this property.\n\n- **Example**:\n - As part of JSON response format: `"2007-04-05T14:30:20Z"` (i.e., encoded as an [RFC 3339 Internet Date/Time Format](https://tools.ietf.org/html/rfc3339#section-5.6) string.)', support=SupportLevel.SHOULD, queryable=SupportLevel.MUST)] instance-attribute

model_config = ConfigDict(extra='allow') class-attribute instance-attribute

cast_immutable_id_to_str(value) classmethod

Convenience validator for casting immutable_id to a string.

Source code in optimade/models/entries.py
109
110
111
112
113
114
115
116
@field_validator("immutable_id", mode="before")
@classmethod
def cast_immutable_id_to_str(cls, value: Any) -> str:
    """Convenience validator for casting `immutable_id` to a string."""
    if value is not None and not isinstance(value, str):
        value = str(value)

    return value

check_illegal_attributes_fields()

Source code in optimade/models/jsonapi.py
330
331
332
333
334
335
336
337
338
@model_validator(mode="after")
def check_illegal_attributes_fields(self) -> "Attributes":
    illegal_fields = ("relationships", "links", "id", "type")
    for field in illegal_fields:
        if hasattr(self, field):
            raise ValueError(
                f"{illegal_fields} MUST NOT be fields under Attributes"
            )
    return self

ReferenceRelationship

Bases: TypedRelationship

Source code in optimade/models/entries.py
42
43
class ReferenceRelationship(TypedRelationship):
    _req_type: ClassVar[Literal["references"]] = "references"

data: Annotated[Optional[Union[BaseRelationshipResource, list[BaseRelationshipResource]]], StrictField(description='Resource linkage', uniqueItems=True)] = None class-attribute instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='a meta object that contains non-standard meta-information about the relationship.')] = None class-attribute instance-attribute

at_least_one_relationship_key_must_be_set()

Source code in optimade/models/jsonapi.py
279
280
281
282
283
284
285
@model_validator(mode="after")
def at_least_one_relationship_key_must_be_set(self) -> "Relationship":
    if self.links is None and self.data is None and self.meta is None:
        raise ValueError(
            "Either 'links', 'data', or 'meta' MUST be specified for Relationship"
        )
    return self

check_rel_type(data) classmethod

Source code in optimade/models/entries.py
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@field_validator("data", mode="after")
@classmethod
def check_rel_type(
    cls, data: Union[BaseRelationshipResource, list[BaseRelationshipResource]]
) -> list[BaseRelationshipResource]:
    if not isinstance(data, list):
        # All relationships at this point are empty-to-many relationships in JSON:API:
        # https://jsonapi.org/format/1.0/#document-resource-object-linkage
        raise ValueError("`data` key in a relationship must always store a list.")

    if any(obj.type != cls._req_type for obj in data):
        raise ValueError("Object stored in relationship data has wrong type")

    return data

StructureRelationship

Bases: TypedRelationship

Source code in optimade/models/entries.py
46
47
class StructureRelationship(TypedRelationship):
    _req_type: ClassVar[Literal["structures"]] = "structures"

data: Annotated[Optional[Union[BaseRelationshipResource, list[BaseRelationshipResource]]], StrictField(description='Resource linkage', uniqueItems=True)] = None class-attribute instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='a meta object that contains non-standard meta-information about the relationship.')] = None class-attribute instance-attribute

at_least_one_relationship_key_must_be_set()

Source code in optimade/models/jsonapi.py
279
280
281
282
283
284
285
@model_validator(mode="after")
def at_least_one_relationship_key_must_be_set(self) -> "Relationship":
    if self.links is None and self.data is None and self.meta is None:
        raise ValueError(
            "Either 'links', 'data', or 'meta' MUST be specified for Relationship"
        )
    return self

check_rel_type(data) classmethod

Source code in optimade/models/entries.py
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@field_validator("data", mode="after")
@classmethod
def check_rel_type(
    cls, data: Union[BaseRelationshipResource, list[BaseRelationshipResource]]
) -> list[BaseRelationshipResource]:
    if not isinstance(data, list):
        # All relationships at this point are empty-to-many relationships in JSON:API:
        # https://jsonapi.org/format/1.0/#document-resource-object-linkage
        raise ValueError("`data` key in a relationship must always store a list.")

    if any(obj.type != cls._req_type for obj in data):
        raise ValueError("Object stored in relationship data has wrong type")

    return data

TypedRelationship

Bases: Relationship

Source code in optimade/models/entries.py
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class TypedRelationship(Relationship):
    _req_type: ClassVar[str]

    @field_validator("data", mode="after")
    @classmethod
    def check_rel_type(
        cls, data: Union[BaseRelationshipResource, list[BaseRelationshipResource]]
    ) -> list[BaseRelationshipResource]:
        if not isinstance(data, list):
            # All relationships at this point are empty-to-many relationships in JSON:API:
            # https://jsonapi.org/format/1.0/#document-resource-object-linkage
            raise ValueError("`data` key in a relationship must always store a list.")

        if any(obj.type != cls._req_type for obj in data):
            raise ValueError("Object stored in relationship data has wrong type")

        return data

data: Annotated[Optional[Union[BaseRelationshipResource, list[BaseRelationshipResource]]], StrictField(description='Resource linkage', uniqueItems=True)] = None class-attribute instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='a meta object that contains non-standard meta-information about the relationship.')] = None class-attribute instance-attribute

at_least_one_relationship_key_must_be_set()

Source code in optimade/models/jsonapi.py
279
280
281
282
283
284
285
@model_validator(mode="after")
def at_least_one_relationship_key_must_be_set(self) -> "Relationship":
    if self.links is None and self.data is None and self.meta is None:
        raise ValueError(
            "Either 'links', 'data', or 'meta' MUST be specified for Relationship"
        )
    return self

check_rel_type(data) classmethod

Source code in optimade/models/entries.py
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@field_validator("data", mode="after")
@classmethod
def check_rel_type(
    cls, data: Union[BaseRelationshipResource, list[BaseRelationshipResource]]
) -> list[BaseRelationshipResource]:
    if not isinstance(data, list):
        # All relationships at this point are empty-to-many relationships in JSON:API:
        # https://jsonapi.org/format/1.0/#document-resource-object-linkage
        raise ValueError("`data` key in a relationship must always store a list.")

    if any(obj.type != cls._req_type for obj in data):
        raise ValueError("Object stored in relationship data has wrong type")

    return data

index_metadb

IndexInfoAttributes

Bases: BaseInfoAttributes

Attributes for Base URL Info endpoint for an Index Meta-Database

Source code in optimade/models/index_metadb.py
17
18
19
20
21
22
23
24
25
class IndexInfoAttributes(BaseInfoAttributes):
    """Attributes for Base URL Info endpoint for an Index Meta-Database"""

    is_index: Annotated[
        bool,
        StrictField(
            description="This must be `true` since this is an index meta-database (see section Index Meta-Database).",
        ),
    ] = True

api_version: Annotated[SemanticVersion, StrictField(description='Presently used full version of the OPTIMADE API.\nThe version number string MUST NOT be prefixed by, e.g., "v".\nExamples: `1.0.0`, `1.0.0-rc.2`.')] instance-attribute

available_api_versions: Annotated[list[AvailableApiVersion], StrictField(description='A list of dictionaries of available API versions at other base URLs')] instance-attribute

available_endpoints: Annotated[list[str], StrictField(description='List of available endpoints (i.e., the string to be appended to the versioned base URL).')] instance-attribute

entry_types_by_format: Annotated[dict[str, list[str]], StrictField(description='Available entry endpoints as a function of output formats.')] instance-attribute

formats: Annotated[list[str], StrictField(description='List of available output formats.')] = ['json'] class-attribute instance-attribute

is_index: Annotated[bool, StrictField(description='This must be `true` since this is an index meta-database (see section Index Meta-Database).')] = True class-attribute instance-attribute

formats_and_endpoints_must_be_valid()

Source code in optimade/models/baseinfo.py
112
113
114
115
116
117
118
119
120
121
122
@model_validator(mode="after")
def formats_and_endpoints_must_be_valid(self) -> "BaseInfoAttributes":
    for format_, endpoints in self.entry_types_by_format.items():
        if format_ not in self.formats:
            raise ValueError(f"'{format_}' must be listed in formats to be valid")
        for endpoint in endpoints:
            if endpoint not in self.available_endpoints:
                raise ValueError(
                    f"'{endpoint}' must be listed in available_endpoints to be valid"
                )
    return self

IndexInfoResource

Bases: BaseInfoResource

Index Meta-Database Base URL Info endpoint resource

Source code in optimade/models/index_metadb.py
46
47
48
49
50
51
52
53
54
55
56
57
class IndexInfoResource(BaseInfoResource):
    """Index Meta-Database Base URL Info endpoint resource"""

    attributes: IndexInfoAttributes
    relationships: Annotated[  # type: ignore[assignment]
        Optional[dict[Literal["default"], IndexRelationship]],
        StrictField(
            title="Relationships",
            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.""",
        ),
    ]

attributes: IndexInfoAttributes instance-attribute

id: Literal['/'] = '/' class-attribute instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='a meta object containing non-standard meta-information about a resource that can not be represented as an attribute or relationship.')] = None class-attribute instance-attribute

model_config = ConfigDict(json_schema_extra=resource_json_schema_extra) class-attribute instance-attribute

relationships: Annotated[Optional[dict[Literal['default'], IndexRelationship]], StrictField(title=Relationships, description="Reference to the Links identifier object under the `links` endpoint that the provider has chosen as their 'default' OPTIMADE API database.\nA client SHOULD present this database as the first choice when an end-user chooses this provider.")] instance-attribute

type: Literal['info'] = 'info' class-attribute instance-attribute

IndexRelationship

Bases: BaseModel

Index Meta-Database relationship

Source code in optimade/models/index_metadb.py
34
35
36
37
38
39
40
41
42
43
class IndexRelationship(BaseModel):
    """Index Meta-Database relationship"""

    data: Annotated[
        Optional[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`""",
        ),
    ]

data: Annotated[Optional[RelatedLinksResource], StrictField(description='[JSON API resource linkage](http://jsonapi.org/format/1.0/#document-links).\nIt MUST be either `null` or contain a single Links identifier object with the fields `id` and `type`')] instance-attribute

RelatedLinksResource

Bases: BaseResource

A related Links resource object

Source code in optimade/models/index_metadb.py
28
29
30
31
class RelatedLinksResource(BaseResource):
    """A related Links resource object"""

    type: Literal["links"] = "links"

id: Annotated[str, StrictField(description='Resource ID')] instance-attribute

model_config = ConfigDict(json_schema_extra=resource_json_schema_extra) class-attribute instance-attribute

type: Literal['links'] = 'links' class-attribute instance-attribute

jsonapi

This module should reproduce JSON API v1.0 https://jsonapi.org/format/1.0/

JsonLinkType = Union[AnyUrl, Link] module-attribute

Attributes

Bases: BaseModel

Members of the attributes object ("attributes") represent information about the resource object in which it's defined. The keys for Attributes MUST NOT be: relationships links id type

Source code in optimade/models/jsonapi.py
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
class Attributes(BaseModel):
    """
    Members of the attributes object ("attributes\") represent information about the resource object in which it's defined.
    The keys for Attributes MUST NOT be:
        relationships
        links
        id
        type
    """

    model_config = ConfigDict(extra="allow")

    @model_validator(mode="after")
    def check_illegal_attributes_fields(self) -> "Attributes":
        illegal_fields = ("relationships", "links", "id", "type")
        for field in illegal_fields:
            if hasattr(self, field):
                raise ValueError(
                    f"{illegal_fields} MUST NOT be fields under Attributes"
                )
        return self

model_config = ConfigDict(extra='allow') class-attribute instance-attribute

check_illegal_attributes_fields()

Source code in optimade/models/jsonapi.py
330
331
332
333
334
335
336
337
338
@model_validator(mode="after")
def check_illegal_attributes_fields(self) -> "Attributes":
    illegal_fields = ("relationships", "links", "id", "type")
    for field in illegal_fields:
        if hasattr(self, field):
            raise ValueError(
                f"{illegal_fields} MUST NOT be fields under Attributes"
            )
    return self

BaseResource

Bases: BaseModel

Minimum requirements to represent a Resource

Source code in optimade/models/jsonapi.py
218
219
220
221
222
223
224
class BaseResource(BaseModel):
    """Minimum requirements to represent a Resource"""

    model_config = ConfigDict(json_schema_extra=resource_json_schema_extra)

    id: Annotated[str, StrictField(description="Resource ID")]
    type: Annotated[str, StrictField(description="Resource type")]

id: Annotated[str, StrictField(description='Resource ID')] instance-attribute

model_config = ConfigDict(json_schema_extra=resource_json_schema_extra) class-attribute instance-attribute

type: Annotated[str, StrictField(description='Resource type')] instance-attribute

Error

Bases: BaseModel

An error response

Source code in optimade/models/jsonapi.py
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
class Error(BaseModel):
    """An error response"""

    id: Annotated[
        Optional[str],
        StrictField(
            description="A unique identifier for this particular occurrence of the problem.",
        ),
    ] = None
    links: Annotated[
        Optional[ErrorLinks], StrictField(description="A links object storing about")
    ] = None
    status: Annotated[
        Optional[Annotated[str, BeforeValidator(str)]],
        StrictField(
            description="the HTTP status code applicable to this problem, expressed as a string value.",
        ),
    ] = None
    code: Annotated[
        Optional[str],
        StrictField(
            description="an application-specific error code, expressed as a string value.",
        ),
    ] = None
    title: Annotated[
        Optional[str],
        StrictField(
            description="A short, human-readable summary of the problem. "
            "It **SHOULD NOT** change from occurrence to occurrence of the problem, except for purposes of localization.",
        ),
    ] = None
    detail: Annotated[
        Optional[str],
        StrictField(
            description="A human-readable explanation specific to this occurrence of the problem.",
        ),
    ] = None
    source: Annotated[
        Optional[ErrorSource],
        StrictField(
            description="An object containing references to the source of the error"
        ),
    ] = None
    meta: Annotated[
        Optional[Meta],
        StrictField(
            description="a meta object containing non-standard meta-information about the error.",
        ),
    ] = None

    def __hash__(self):
        return hash(self.model_dump_json())

code: Annotated[Optional[str], StrictField(description='an application-specific error code, expressed as a string value.')] = None class-attribute instance-attribute

detail: Annotated[Optional[str], StrictField(description='A human-readable explanation specific to this occurrence of the problem.')] = None class-attribute instance-attribute

id: Annotated[Optional[str], StrictField(description='A unique identifier for this particular occurrence of the problem.')] = None class-attribute instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='a meta object containing non-standard meta-information about the error.')] = None class-attribute instance-attribute

source: Annotated[Optional[ErrorSource], StrictField(description='An object containing references to the source of the error')] = None class-attribute instance-attribute

status: Annotated[Optional[Annotated[str, BeforeValidator(str)]], StrictField(description='the HTTP status code applicable to this problem, expressed as a string value.')] = None class-attribute instance-attribute

title: Annotated[Optional[str], StrictField(description='A short, human-readable summary of the problem. It **SHOULD NOT** change from occurrence to occurrence of the problem, except for purposes of localization.')] = None class-attribute instance-attribute

__hash__()

Source code in optimade/models/jsonapi.py
191
192
def __hash__(self):
    return hash(self.model_dump_json())

Bases: BaseModel

A Links object specific to Error objects

Source code in optimade/models/jsonapi.py
112
113
114
115
116
117
118
119
120
class ErrorLinks(BaseModel):
    """A Links object specific to Error objects"""

    about: Annotated[
        Optional[JsonLinkType],
        StrictField(
            description="A link that leads to further details about this particular occurrence of the problem.",
        ),
    ] = None

about: Annotated[Optional[JsonLinkType], StrictField(description='A link that leads to further details about this particular occurrence of the problem.')] = None class-attribute instance-attribute

ErrorSource

Bases: BaseModel

an object containing references to the source of the error

Source code in optimade/models/jsonapi.py
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
class ErrorSource(BaseModel):
    """an object containing references to the source of the error"""

    pointer: Annotated[
        Optional[str],
        StrictField(
            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].',
        ),
    ] = None
    parameter: Annotated[
        Optional[str],
        StrictField(
            description="a string indicating which URI query parameter caused the error.",
        ),
    ] = None

parameter: Annotated[Optional[str], StrictField(description='a string indicating which URI query parameter caused the error.')] = None class-attribute instance-attribute

pointer: Annotated[Optional[str], StrictField(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].')] = None class-attribute instance-attribute

JsonApi

Bases: BaseModel

An object describing the server's implementation

Source code in optimade/models/jsonapi.py
58
59
60
61
62
63
64
65
66
class JsonApi(BaseModel):
    """An object describing the server's implementation"""

    version: Annotated[str, StrictField(description="Version of the json API used")] = (
        "1.0"
    )
    meta: Annotated[
        Optional[Meta], StrictField(description="Non-standard meta information")
    ] = None

meta: Annotated[Optional[Meta], StrictField(description='Non-standard meta information')] = None class-attribute instance-attribute

version: Annotated[str, StrictField(description='Version of the json API used')] = '1.0' class-attribute instance-attribute

Bases: BaseModel

A link MUST be represented as either: a string containing the link's URL or a link object.

Source code in optimade/models/jsonapi.py
41
42
43
44
45
46
47
48
49
50
51
52
class Link(BaseModel):
    """A link **MUST** be represented as either: a string containing the link's URL or a link object."""

    href: Annotated[
        AnyUrl, StrictField(description="a string containing the link's URL.")
    ]
    meta: Annotated[
        Optional[Meta],
        StrictField(
            description="a meta object containing non-standard meta-information about the link.",
        ),
    ] = None

href: Annotated[AnyUrl, StrictField(description="a string containing the link's URL.")] instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='a meta object containing non-standard meta-information about the link.')] = None class-attribute instance-attribute

Meta

Bases: BaseModel

Non-standard meta-information that can not be represented as an attribute or relationship.

Source code in optimade/models/jsonapi.py
35
36
37
38
class Meta(BaseModel):
    """Non-standard meta-information that can not be represented as an attribute or relationship."""

    model_config = ConfigDict(extra="allow")

model_config = ConfigDict(extra='allow') class-attribute instance-attribute

Relationship

Bases: BaseModel

Representation references from the resource object in which it's defined to other resource objects.

Source code in optimade/models/jsonapi.py
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
class Relationship(BaseModel):
    """Representation references from the resource object in which it's defined to other resource objects."""

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

    @model_validator(mode="after")
    def at_least_one_relationship_key_must_be_set(self) -> "Relationship":
        if self.links is None and self.data is None and self.meta is None:
            raise ValueError(
                "Either 'links', 'data', or 'meta' MUST be specified for Relationship"
            )
        return self

data: Annotated[Optional[Union[BaseResource, list[BaseResource]]], StrictField(description='Resource linkage')] = None class-attribute instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='a meta object that contains non-standard meta-information about the relationship.')] = None class-attribute instance-attribute

at_least_one_relationship_key_must_be_set()

Source code in optimade/models/jsonapi.py
279
280
281
282
283
284
285
@model_validator(mode="after")
def at_least_one_relationship_key_must_be_set(self) -> "Relationship":
    if self.links is None and self.data is None and self.meta is None:
        raise ValueError(
            "Either 'links', 'data', or 'meta' MUST be specified for Relationship"
        )
    return self

Bases: 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.

Source code in optimade/models/jsonapi.py
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
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: Annotated[
        Optional[JsonLinkType],
        StrictField(
            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).)""",
        ),
    ] = None
    related: Annotated[
        Optional[JsonLinkType],
        StrictField(
            description="A [related resource link](https://jsonapi.org/format/1.0/#document-resource-object-related-resource-links).",
        ),
    ] = None

    @model_validator(mode="after")
    def either_self_or_related_must_be_specified(self) -> "RelationshipLinks":
        if self.self is None and self.related is None:
            raise ValueError(
                "Either 'self' or 'related' MUST be specified for RelationshipLinks"
            )
        return self

related: Annotated[Optional[JsonLinkType], StrictField(description='A [related resource link](https://jsonapi.org/format/1.0/#document-resource-object-related-resource-links).')] = None class-attribute instance-attribute

self: Annotated[Optional[JsonLinkType], StrictField(description="A link for the relationship itself (a 'relationship link').\nThis link allows the client to directly manipulate the relationship.\nWhen 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.\n(See [Fetching Relationships](https://jsonapi.org/format/1.0/#fetching-relationships).)")] = None class-attribute instance-attribute

Source code in optimade/models/jsonapi.py
250
251
252
253
254
255
256
@model_validator(mode="after")
def either_self_or_related_must_be_specified(self) -> "RelationshipLinks":
    if self.self is None and self.related is None:
        raise ValueError(
            "Either 'self' or 'related' MUST be specified for RelationshipLinks"
        )
    return self

Relationships

Bases: BaseModel

Members of the relationships object ("relationships") represent references from the resource object in which it's defined to other resource objects. Keys MUST NOT be: type id

Source code in optimade/models/jsonapi.py
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
class Relationships(BaseModel):
    """
    Members of the relationships object (\"relationships\") represent references from the resource object in which it's defined to other resource objects.
    Keys MUST NOT be:
        type
        id
    """

    @model_validator(mode="after")
    def check_illegal_relationships_fields(self) -> "Relationships":
        illegal_fields = ("id", "type")
        for field in illegal_fields:
            if hasattr(self, field):
                raise ValueError(
                    f"{illegal_fields} MUST NOT be fields under Relationships"
                )
        return self

check_illegal_relationships_fields()

Source code in optimade/models/jsonapi.py
296
297
298
299
300
301
302
303
304
@model_validator(mode="after")
def check_illegal_relationships_fields(self) -> "Relationships":
    illegal_fields = ("id", "type")
    for field in illegal_fields:
        if hasattr(self, field):
            raise ValueError(
                f"{illegal_fields} MUST NOT be fields under Relationships"
            )
    return self

Resource

Bases: BaseResource

Resource objects appear in a JSON API document to represent resources.

Source code in optimade/models/jsonapi.py
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
class Resource(BaseResource):
    """Resource objects appear in a JSON API document to represent resources."""

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

attributes: Annotated[Optional[Attributes], StrictField(description='an attributes object representing some of the resource’s data.')] = None class-attribute instance-attribute

id: Annotated[str, StrictField(description='Resource ID')] instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='a meta object containing non-standard meta-information about a resource that can not be represented as an attribute or relationship.')] = None class-attribute instance-attribute

model_config = ConfigDict(json_schema_extra=resource_json_schema_extra) class-attribute instance-attribute

relationships: Annotated[Optional[Relationships], StrictField(description='[Relationships object](https://jsonapi.org/format/1.0/#document-resource-object-relationships)\ndescribing relationships between the resource and other JSON API resources.')] = None class-attribute instance-attribute

type: Annotated[str, StrictField(description='Resource type')] instance-attribute

Bases: BaseModel

A Resource Links object

Source code in optimade/models/jsonapi.py
307
308
309
310
311
312
313
314
315
class ResourceLinks(BaseModel):
    """A Resource Links object"""

    self: Annotated[
        Optional[JsonLinkType],
        StrictField(
            description="A link that identifies the resource represented by the resource object.",
        ),
    ] = None

self: Annotated[Optional[JsonLinkType], StrictField(description='A link that identifies the resource represented by the resource object.')] = None class-attribute instance-attribute

Response

Bases: BaseModel

A top-level response.

Source code in optimade/models/jsonapi.py
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
class Response(BaseModel):
    """A top-level response."""

    data: Annotated[
        Optional[Union[None, Resource, list[Resource]]],
        StrictField(description="Outputted Data", uniqueItems=True),
    ] = None
    meta: Annotated[
        Optional[Meta],
        StrictField(
            description="A meta object containing non-standard information related to the Success",
        ),
    ] = None
    errors: Annotated[
        Optional[list[Error]],
        StrictField(description="A list of unique errors", uniqueItems=True),
    ] = None
    included: Annotated[
        Optional[list[Resource]],
        StrictField(
            description="A list of unique included resources", uniqueItems=True
        ),
    ] = None
    links: Annotated[
        Optional[ToplevelLinks],
        StrictField(description="Links associated with the primary data or errors"),
    ] = None
    jsonapi: Annotated[
        Optional[JsonApi],
        StrictField(description="Information about the JSON API used"),
    ] = None

    @model_validator(mode="after")
    def either_data_meta_or_errors_must_be_set(self) -> "Response":
        required_fields = ("data", "meta", "errors")
        if not any(field in self.model_fields_set for field in required_fields):
            raise ValueError(
                f"At least one of {required_fields} MUST be specified in the top-level response"
            )
        if "errors" in self.model_fields_set and not self.errors:
            raise ValueError("Errors MUST NOT be an empty or 'null' value.")
        return self

    model_config = ConfigDict(
        json_encoders={
            datetime: lambda v: v.astimezone(timezone.utc).strftime(
                "%Y-%m-%dT%H:%M:%SZ"
            )
        }
    )
    """The specification mandates that datetimes must be encoded following
    [RFC3339](https://tools.ietf.org/html/rfc3339), which does not support
    fractional seconds, thus they must be stripped in the response. This can
    cause issues when the underlying database contains fields that do include
    microseconds, as filters may return unexpected results.
    """

data: Annotated[Optional[Union[None, Resource, list[Resource]]], StrictField(description='Outputted Data', uniqueItems=True)] = None class-attribute instance-attribute

errors: Annotated[Optional[list[Error]], StrictField(description='A list of unique errors', uniqueItems=True)] = None class-attribute instance-attribute

included: Annotated[Optional[list[Resource]], StrictField(description='A list of unique included resources', uniqueItems=True)] = None class-attribute instance-attribute

jsonapi: Annotated[Optional[JsonApi], StrictField(description='Information about the JSON API used')] = None class-attribute instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='A meta object containing non-standard information related to the Success')] = None class-attribute instance-attribute

model_config = ConfigDict(json_encoders={datetime: lambda v: v.astimezone(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')}) class-attribute instance-attribute

The specification mandates that datetimes must be encoded following RFC3339, which does not support fractional seconds, thus they must be stripped in the response. This can cause issues when the underlying database contains fields that do include microseconds, as filters may return unexpected results.

either_data_meta_or_errors_must_be_set()

Source code in optimade/models/jsonapi.py
403
404
405
406
407
408
409
410
411
412
@model_validator(mode="after")
def either_data_meta_or_errors_must_be_set(self) -> "Response":
    required_fields = ("data", "meta", "errors")
    if not any(field in self.model_fields_set for field in required_fields):
        raise ValueError(
            f"At least one of {required_fields} MUST be specified in the top-level response"
        )
    if "errors" in self.model_fields_set and not self.errors:
        raise ValueError("Errors MUST NOT be an empty or 'null' value.")
    return self

Bases: BaseModel

A set of Links objects, possibly including pagination

Source code in optimade/models/jsonapi.py
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
class ToplevelLinks(BaseModel):
    """A set of Links objects, possibly including pagination"""

    model_config = ConfigDict(extra="allow")

    self: Annotated[
        Optional[JsonLinkType], StrictField(description="A link to itself")
    ] = None
    related: Annotated[
        Optional[JsonLinkType], StrictField(description="A related resource link")
    ] = None

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

    @model_validator(mode="after")
    def check_additional_keys_are_links(self) -> "ToplevelLinks":
        """The `ToplevelLinks` class allows any additional keys, as long as
        they are also Links or Urls themselves.

        """
        for field, value in self:
            if field not in self.model_fields:
                setattr(
                    self,
                    field,
                    TypeAdapter(Optional[JsonLinkType]).validate_python(value),
                )

        return self

first: Annotated[Optional[JsonLinkType], StrictField(description='The first page of data')] = None class-attribute instance-attribute

last: Annotated[Optional[JsonLinkType], StrictField(description='The last page of data')] = None class-attribute instance-attribute

model_config = ConfigDict(extra='allow') class-attribute instance-attribute

next: Annotated[Optional[JsonLinkType], StrictField(description='The next page of data')] = None class-attribute instance-attribute

prev: Annotated[Optional[JsonLinkType], StrictField(description='The previous page of data')] = None class-attribute instance-attribute

related: Annotated[Optional[JsonLinkType], StrictField(description='A related resource link')] = None class-attribute instance-attribute

self: Annotated[Optional[JsonLinkType], StrictField(description='A link to itself')] = None class-attribute instance-attribute

The ToplevelLinks class allows any additional keys, as long as they are also Links or Urls themselves.

Source code in optimade/models/jsonapi.py
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
@model_validator(mode="after")
def check_additional_keys_are_links(self) -> "ToplevelLinks":
    """The `ToplevelLinks` class allows any additional keys, as long as
    they are also Links or Urls themselves.

    """
    for field, value in self:
        if field not in self.model_fields:
            setattr(
                self,
                field,
                TypeAdapter(Optional[JsonLinkType]).validate_python(value),
            )

    return self

resource_json_schema_extra(schema, model)

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.

Source code in optimade/models/jsonapi.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
def resource_json_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

Aggregate

Bases: Enum

Enumeration of aggregate values

Source code in optimade/models/links.py
25
26
27
28
29
30
31
class Aggregate(Enum):
    """Enumeration of aggregate values"""

    OK = "ok"
    TEST = "test"
    STAGING = "staging"
    NO = "no"

NO = 'no' class-attribute instance-attribute

OK = 'ok' class-attribute instance-attribute

STAGING = 'staging' class-attribute instance-attribute

TEST = 'test' class-attribute instance-attribute

LinkType

Bases: Enum

Enumeration of link_type values

Source code in optimade/models/links.py
16
17
18
19
20
21
22
class LinkType(Enum):
    """Enumeration of link_type values"""

    CHILD = "child"
    ROOT = "root"
    EXTERNAL = "external"
    PROVIDERS = "providers"

CHILD = 'child' class-attribute instance-attribute

EXTERNAL = 'external' class-attribute instance-attribute

PROVIDERS = 'providers' class-attribute instance-attribute

ROOT = 'root' class-attribute instance-attribute

LinksResource

Bases: EntryResource

A Links endpoint resource object

Source code in optimade/models/links.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
class LinksResource(EntryResource):
    """A Links endpoint resource object"""

    type: Annotated[
        Literal["links"],
        StrictField(
            description="These objects are described in detail in the section Links Endpoint",
            pattern="^links$",
        ),
    ] = "links"

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

    @model_validator(mode="after")
    def relationships_must_not_be_present(self) -> "LinksResource":
        if self.relationships or "relationships" in self.model_fields_set:
            raise ValueError('"relationships" is not allowed for links resources')
        return self

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

id: Annotated[str, OptimadeField(description='An entry\'s ID as defined in section Definition of Terms.\n\n- **Type**: string.\n\n- **Requirements/Conventions**:\n - **Support**: MUST be supported by all implementations, MUST NOT be `null`.\n - **Query**: MUST be a queryable property with support for all mandatory filter features.\n - **Response**: REQUIRED in the response.\n\n- **Examples**:\n - `"db/1234567"`\n - `"cod/2000000"`\n - `"cod/2000000@1234567"`\n - `"nomad/L1234567890"`\n - `"42"`', support=SupportLevel.MUST, queryable=SupportLevel.MUST)] instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='a meta object containing non-standard meta-information about a resource that can not be represented as an attribute or relationship.')] = None class-attribute instance-attribute

model_config = ConfigDict(json_schema_extra=resource_json_schema_extra) class-attribute instance-attribute

relationships: Annotated[Optional[EntryRelationships], StrictField(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).\nThe 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.')] = None class-attribute instance-attribute

type: Annotated[Literal['links'], StrictField(description='These objects are described in detail in the section Links Endpoint', pattern='^links$')] = 'links' class-attribute instance-attribute

relationships_must_not_be_present()

Source code in optimade/models/links.py
116
117
118
119
120
@model_validator(mode="after")
def relationships_must_not_be_present(self) -> "LinksResource":
    if self.relationships or "relationships" in self.model_fields_set:
        raise ValueError('"relationships" is not allowed for links resources')
    return self

LinksResourceAttributes

Bases: Attributes

Links endpoint resource object attributes

Source code in optimade/models/links.py
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
class LinksResourceAttributes(Attributes):
    """Links endpoint resource object attributes"""

    name: Annotated[
        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: Annotated[
        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: Annotated[
        Optional[JsonLinkType],
        StrictField(
            description="JSON API links object, pointing to the base URL for this implementation",
        ),
    ]

    homepage: Annotated[
        Optional[JsonLinkType],
        StrictField(
            description="JSON API links object, pointing to a homepage URL for this implementation",
        ),
    ]

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

    aggregate: Annotated[
        Optional[Aggregate],
        StrictField(
            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.""",
        ),
    ] = Aggregate.OK

    no_aggregate_reason: Annotated[
        Optional[str],
        StrictField(
            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`.""",
        ),
    ] = None

aggregate: Annotated[Optional[Aggregate], StrictField(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.\nThis flag SHOULD NOT be indicated for links where `link_type` is not `child`.\n\nIf not specified, clients MAY assume that the value is `ok`.\nIf 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).\n\nSpecific values indicate the reason why the server is providing the suggestion.\nA 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`).\n\nIf specified, it MUST be one of the values listed in section Link Aggregate Options.')] = Aggregate.OK class-attribute instance-attribute

base_url: Annotated[Optional[JsonLinkType], StrictField(description='JSON API links object, pointing to the base URL for this implementation')] instance-attribute

description: Annotated[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.')] instance-attribute

homepage: Annotated[Optional[JsonLinkType], StrictField(description='JSON API links object, pointing to a homepage URL for this implementation')] instance-attribute

model_config = ConfigDict(extra='allow') class-attribute instance-attribute

name: Annotated[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.')] instance-attribute

no_aggregate_reason: Annotated[Optional[str], StrictField(description='An OPTIONAL human-readable string indicating the reason for suggesting not to aggregate results following the link.\nIt SHOULD NOT be present if `aggregate`=`ok`.')] = None class-attribute instance-attribute

check_illegal_attributes_fields()

Source code in optimade/models/jsonapi.py
330
331
332
333
334
335
336
337
338
@model_validator(mode="after")
def check_illegal_attributes_fields(self) -> "Attributes":
    illegal_fields = ("relationships", "links", "id", "type")
    for field in illegal_fields:
        if hasattr(self, field):
            raise ValueError(
                f"{illegal_fields} MUST NOT be fields under Attributes"
            )
    return self

optimade_json

Modified JSON API v1.0 for OPTIMADE API

BaseRelationshipMeta

Bases: Meta

Specific meta field for base relationship resource

Source code in optimade/models/optimade_json.py
404
405
406
407
408
409
410
411
412
class BaseRelationshipMeta(jsonapi.Meta):
    """Specific meta field for base relationship resource"""

    description: Annotated[
        str,
        StrictField(
            description="OPTIONAL human-readable description of the relationship."
        ),
    ]

description: Annotated[str, StrictField(description='OPTIONAL human-readable description of the relationship.')] instance-attribute

model_config = ConfigDict(extra='allow') class-attribute instance-attribute

BaseRelationshipResource

Bases: BaseResource

Minimum requirements to represent a relationship resource

Source code in optimade/models/optimade_json.py
415
416
417
418
419
420
421
422
423
class BaseRelationshipResource(jsonapi.BaseResource):
    """Minimum requirements to represent a relationship resource"""

    meta: Annotated[
        Optional[BaseRelationshipMeta],
        StrictField(
            description="Relationship meta field. MUST contain 'description' if supplied.",
        ),
    ] = None

id: Annotated[str, StrictField(description='Resource ID')] instance-attribute

meta: Annotated[Optional[BaseRelationshipMeta], StrictField(description="Relationship meta field. MUST contain 'description' if supplied.")] = None class-attribute instance-attribute

model_config = ConfigDict(json_schema_extra=resource_json_schema_extra) class-attribute instance-attribute

type: Annotated[str, StrictField(description='Resource type')] instance-attribute

DataType

Bases: Enum

Optimade Data types

See the section "Data types" in the OPTIMADE API specification for more information.

Source code in optimade/models/optimade_json.py
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
class DataType(Enum):
    """Optimade Data types

    See the section "Data types" in the OPTIMADE API specification for more information.
    """

    STRING = "string"
    INTEGER = "integer"
    FLOAT = "float"
    BOOLEAN = "boolean"
    TIMESTAMP = "timestamp"
    LIST = "list"
    DICTIONARY = "dictionary"
    UNKNOWN = "unknown"

    @classmethod
    def get_values(cls) -> list[str]:
        """Get OPTIMADE data types (enum values) as a (sorted) list"""
        return sorted(_.value for _ in cls)

    @classmethod
    def from_python_type(
        cls, python_type: Union[type, str, object]
    ) -> Optional["DataType"]:
        """Get OPTIMADE data type from a Python type"""
        mapping = {
            "bool": cls.BOOLEAN,
            "int": cls.INTEGER,
            "float": cls.FLOAT,
            "complex": None,
            "generator": cls.LIST,
            "list": cls.LIST,
            "tuple": cls.LIST,
            "range": cls.LIST,
            "hash": cls.INTEGER,
            "str": cls.STRING,
            "bytes": cls.STRING,
            "bytearray": None,
            "memoryview": None,
            "set": cls.LIST,
            "frozenset": cls.LIST,
            "dict": cls.DICTIONARY,
            "dict_keys": cls.LIST,
            "dict_values": cls.LIST,
            "dict_items": cls.LIST,
            "Nonetype": cls.UNKNOWN,
            "None": cls.UNKNOWN,
            "datetime": cls.TIMESTAMP,
            "date": cls.TIMESTAMP,
            "time": cls.TIMESTAMP,
            "datetime.datetime": cls.TIMESTAMP,
            "datetime.date": cls.TIMESTAMP,
            "datetime.time": cls.TIMESTAMP,
        }

        if isinstance(python_type, type):
            python_type = python_type.__name__
        elif isinstance(python_type, object):
            if str(python_type) in mapping:
                python_type = str(python_type)
            else:
                python_type = type(python_type).__name__

        return mapping.get(python_type, None)

    @classmethod
    def from_json_type(cls, json_type: str) -> Optional["DataType"]:
        """Get OPTIMADE data type from a named JSON type"""
        mapping = {
            "string": cls.STRING,
            "integer": cls.INTEGER,
            "number": cls.FLOAT,  # actually includes both integer and float
            "object": cls.DICTIONARY,
            "array": cls.LIST,
            "boolean": cls.BOOLEAN,
            "null": cls.UNKNOWN,
            # OpenAPI "format"s:
            "double": cls.FLOAT,
            "float": cls.FLOAT,
            "int32": cls.INTEGER,
            "int64": cls.INTEGER,
            "date": cls.TIMESTAMP,
            "date-time": cls.TIMESTAMP,
            "password": cls.STRING,
            "byte": cls.STRING,
            "binary": cls.STRING,
            # Non-OpenAPI "format"s, but may still be used by pydantic/FastAPI
            "email": cls.STRING,
            "uuid": cls.STRING,
            "uri": cls.STRING,
            "hostname": cls.STRING,
            "ipv4": cls.STRING,
            "ipv6": cls.STRING,
        }

        return mapping.get(json_type, None)

BOOLEAN = 'boolean' class-attribute instance-attribute

DICTIONARY = 'dictionary' class-attribute instance-attribute

FLOAT = 'float' class-attribute instance-attribute

INTEGER = 'integer' class-attribute instance-attribute

LIST = 'list' class-attribute instance-attribute

STRING = 'string' class-attribute instance-attribute

TIMESTAMP = 'timestamp' class-attribute instance-attribute

UNKNOWN = 'unknown' class-attribute instance-attribute

from_json_type(json_type) classmethod

Get OPTIMADE data type from a named JSON type

Source code in optimade/models/optimade_json.py
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
@classmethod
def from_json_type(cls, json_type: str) -> Optional["DataType"]:
    """Get OPTIMADE data type from a named JSON type"""
    mapping = {
        "string": cls.STRING,
        "integer": cls.INTEGER,
        "number": cls.FLOAT,  # actually includes both integer and float
        "object": cls.DICTIONARY,
        "array": cls.LIST,
        "boolean": cls.BOOLEAN,
        "null": cls.UNKNOWN,
        # OpenAPI "format"s:
        "double": cls.FLOAT,
        "float": cls.FLOAT,
        "int32": cls.INTEGER,
        "int64": cls.INTEGER,
        "date": cls.TIMESTAMP,
        "date-time": cls.TIMESTAMP,
        "password": cls.STRING,
        "byte": cls.STRING,
        "binary": cls.STRING,
        # Non-OpenAPI "format"s, but may still be used by pydantic/FastAPI
        "email": cls.STRING,
        "uuid": cls.STRING,
        "uri": cls.STRING,
        "hostname": cls.STRING,
        "ipv4": cls.STRING,
        "ipv6": cls.STRING,
    }

    return mapping.get(json_type, None)

from_python_type(python_type) classmethod

Get OPTIMADE data type from a Python type

Source code in optimade/models/optimade_json.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
@classmethod
def from_python_type(
    cls, python_type: Union[type, str, object]
) -> Optional["DataType"]:
    """Get OPTIMADE data type from a Python type"""
    mapping = {
        "bool": cls.BOOLEAN,
        "int": cls.INTEGER,
        "float": cls.FLOAT,
        "complex": None,
        "generator": cls.LIST,
        "list": cls.LIST,
        "tuple": cls.LIST,
        "range": cls.LIST,
        "hash": cls.INTEGER,
        "str": cls.STRING,
        "bytes": cls.STRING,
        "bytearray": None,
        "memoryview": None,
        "set": cls.LIST,
        "frozenset": cls.LIST,
        "dict": cls.DICTIONARY,
        "dict_keys": cls.LIST,
        "dict_values": cls.LIST,
        "dict_items": cls.LIST,
        "Nonetype": cls.UNKNOWN,
        "None": cls.UNKNOWN,
        "datetime": cls.TIMESTAMP,
        "date": cls.TIMESTAMP,
        "time": cls.TIMESTAMP,
        "datetime.datetime": cls.TIMESTAMP,
        "datetime.date": cls.TIMESTAMP,
        "datetime.time": cls.TIMESTAMP,
    }

    if isinstance(python_type, type):
        python_type = python_type.__name__
    elif isinstance(python_type, object):
        if str(python_type) in mapping:
            python_type = str(python_type)
        else:
            python_type = type(python_type).__name__

    return mapping.get(python_type, None)

get_values() classmethod

Get OPTIMADE data types (enum values) as a (sorted) list

Source code in optimade/models/optimade_json.py
44
45
46
47
@classmethod
def get_values(cls) -> list[str]:
    """Get OPTIMADE data types (enum values) as a (sorted) list"""
    return sorted(_.value for _ in cls)

Implementation

Bases: BaseModel

Information on the server implementation

Source code in optimade/models/optimade_json.py
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
class Implementation(BaseModel):
    """Information on the server implementation"""

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

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

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

    source_url: Annotated[
        Optional[jsonapi.JsonLinkType],
        StrictField(
            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.",
        ),
    ] = None

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

    issue_tracker: Annotated[
        Optional[jsonapi.JsonLinkType],
        StrictField(
            description="A [JSON API links object](http://jsonapi.org/format/1.0/#document-links) pointing to the implementation's issue tracker.",
        ),
    ] = None

homepage: Annotated[Optional[jsonapi.JsonLinkType], StrictField(description='A [JSON API links object](http://jsonapi.org/format/1.0/#document-links) pointing to the homepage of the implementation.')] = None class-attribute instance-attribute

issue_tracker: Annotated[Optional[jsonapi.JsonLinkType], StrictField(description="A [JSON API links object](http://jsonapi.org/format/1.0/#document-links) pointing to the implementation's issue tracker.")] = None class-attribute instance-attribute

maintainer: Annotated[Optional[ImplementationMaintainer], StrictField(description='A dictionary providing details about the maintainer of the implementation.')] = None class-attribute instance-attribute

name: Annotated[Optional[str], StrictField(description='name of the implementation')] = None class-attribute instance-attribute

source_url: Annotated[Optional[jsonapi.JsonLinkType], StrictField(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.')] = None class-attribute instance-attribute

version: Annotated[Optional[str], StrictField(description='version string of the current implementation')] = None class-attribute instance-attribute

ImplementationMaintainer

Bases: BaseModel

Details about the maintainer of the implementation

Source code in optimade/models/optimade_json.py
230
231
232
233
234
235
class ImplementationMaintainer(BaseModel):
    """Details about the maintainer of the implementation"""

    email: Annotated[
        EmailStr, StrictField(description="the maintainer's email address")
    ]

email: Annotated[EmailStr, StrictField(description="the maintainer's email address")] instance-attribute

OptimadeError

Bases: Error

detail MUST be present

Source code in optimade/models/optimade_json.py
127
128
129
130
131
132
133
134
135
class OptimadeError(jsonapi.Error):
    """detail MUST be present"""

    detail: Annotated[
        str,
        StrictField(
            description="A human-readable explanation specific to this occurrence of the problem.",
        ),
    ]

code: Annotated[Optional[str], StrictField(description='an application-specific error code, expressed as a string value.')] = None class-attribute instance-attribute

detail: Annotated[str, StrictField(description='A human-readable explanation specific to this occurrence of the problem.')] instance-attribute

id: Annotated[Optional[str], StrictField(description='A unique identifier for this particular occurrence of the problem.')] = None class-attribute instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='a meta object containing non-standard meta-information about the error.')] = None class-attribute instance-attribute

source: Annotated[Optional[ErrorSource], StrictField(description='An object containing references to the source of the error')] = None class-attribute instance-attribute

status: Annotated[Optional[Annotated[str, BeforeValidator(str)]], StrictField(description='the HTTP status code applicable to this problem, expressed as a string value.')] = None class-attribute instance-attribute

title: Annotated[Optional[str], StrictField(description='A short, human-readable summary of the problem. It **SHOULD NOT** change from occurrence to occurrence of the problem, except for purposes of localization.')] = None class-attribute instance-attribute

__hash__()

Source code in optimade/models/jsonapi.py
191
192
def __hash__(self):
    return hash(self.model_dump_json())

Provider

Bases: BaseModel

Information on the database provider of the implementation.

Source code in optimade/models/optimade_json.py
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
class Provider(BaseModel):
    """Information on the database provider of the implementation."""

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

    description: Annotated[
        str, StrictField(description="a longer description of the database provider")
    ]

    prefix: Annotated[
        str,
        StrictField(
            pattern=r"^[a-z]([a-z]|[0-9]|_)*$",
            description="database-provider-specific prefix as found in section Database-Provider-Specific Namespace Prefixes.",
        ),
    ]

    homepage: Annotated[
        Optional[jsonapi.JsonLinkType],
        StrictField(
            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.",
        ),
    ] = None

description: Annotated[str, StrictField(description='a longer description of the database provider')] instance-attribute

homepage: Annotated[Optional[jsonapi.JsonLinkType], StrictField(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.')] = None class-attribute instance-attribute

name: Annotated[str, StrictField(description='a short name for the database provider')] instance-attribute

prefix: Annotated[str, StrictField(pattern='^[a-z]([a-z]|[0-9]|_)*$', description='database-provider-specific prefix as found in section Database-Provider-Specific Namespace Prefixes.')] instance-attribute

Relationship

Bases: Relationship

Similar to normal JSON API relationship, but with addition of OPTIONAL meta field for a resource.

Source code in optimade/models/optimade_json.py
426
427
428
429
430
431
432
class Relationship(jsonapi.Relationship):
    """Similar to normal JSON API relationship, but with addition of OPTIONAL meta field for a resource."""

    data: Annotated[
        Optional[Union[BaseRelationshipResource, list[BaseRelationshipResource]]],
        StrictField(description="Resource linkage", uniqueItems=True),
    ] = None

data: Annotated[Optional[Union[BaseRelationshipResource, list[BaseRelationshipResource]]], StrictField(description='Resource linkage', uniqueItems=True)] = None class-attribute instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='a meta object that contains non-standard meta-information about the relationship.')] = None class-attribute instance-attribute

at_least_one_relationship_key_must_be_set()

Source code in optimade/models/jsonapi.py
279
280
281
282
283
284
285
@model_validator(mode="after")
def at_least_one_relationship_key_must_be_set(self) -> "Relationship":
    if self.links is None and self.data is None and self.meta is None:
        raise ValueError(
            "Either 'links', 'data', or 'meta' MUST be specified for Relationship"
        )
    return self

ResponseMeta

Bases: Meta

A JSON API meta member that contains JSON API meta objects of non-standard meta-information.

OPTIONAL additional information global to the query that is not specified in this document, MUST start with a database-provider-specific prefix.

Source code in optimade/models/optimade_json.py
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
class ResponseMeta(jsonapi.Meta):
    """
    A [JSON API meta member](https://jsonapi.org/format/1.0#document-meta)
    that contains JSON API meta objects of non-standard
    meta-information.

    OPTIONAL additional information global to the query that is not
    specified in this document, MUST start with a
    database-provider-specific prefix.
    """

    query: Annotated[
        ResponseMetaQuery,
        StrictField(description="Information on the Query that was requested"),
    ]

    api_version: Annotated[
        SemanticVersion,
        StrictField(
            description="""Presently used full version of the OPTIMADE API.
The version number string MUST NOT be prefixed by, e.g., "v".
Examples: `1.0.0`, `1.0.0-rc.2`.""",
        ),
    ]

    more_data_available: Annotated[
        bool,
        StrictField(
            description="`false` if the response contains all data for the request (e.g., a request issued to a single entry endpoint, or a `filter` query at the last page of a paginated response) and `true` if the response is incomplete in the sense that multiple objects match the request, and not all of them have been included in the response (e.g., a query with multiple pages that is not at the last page).",
        ),
    ]

    # start of "SHOULD" fields for meta response
    optimade_schema: Annotated[
        Optional[jsonapi.JsonLinkType],
        StrictField(
            alias="schema",
            description="""A [JSON API links object](http://jsonapi.org/format/1.0/#document-links) that points to a schema for the response.
If it is a string, or a dictionary containing no `meta` field, the provided URL MUST point at an [OpenAPI](https://swagger.io/specification/) schema.
It is possible that future versions of this specification allows for alternative schema types.
Hence, if the `meta` field of the JSON API links object is provided and contains a field `schema_type` that is not equal to the string `OpenAPI` the client MUST not handle failures to parse the schema or to validate the response against the schema as errors.""",
        ),
    ] = None

    time_stamp: Annotated[
        Optional[datetime],
        StrictField(
            description="A timestamp containing the date and time at which the query was executed.",
        ),
    ] = None

    data_returned: Annotated[
        Optional[int],
        StrictField(
            description="An integer containing the total number of data resource objects returned for the current `filter` query, independent of pagination.",
            ge=0,
        ),
    ] = None

    provider: Annotated[
        Optional[Provider],
        StrictField(
            description="information on the database provider of the implementation."
        ),
    ] = None

    # start of "MAY" fields for meta response
    data_available: Annotated[
        Optional[int],
        StrictField(
            description="An integer containing the total number of data resource objects available in the database for the endpoint.",
        ),
    ] = None

    last_id: Annotated[
        Optional[str],
        StrictField(description="a string containing the last ID returned"),
    ] = None

    response_message: Annotated[
        Optional[str], StrictField(description="response string from the server")
    ] = None

    implementation: Annotated[
        Optional[Implementation],
        StrictField(description="a dictionary describing the server implementation"),
    ] = None

    warnings: Annotated[
        Optional[list[Warnings]],
        StrictField(
            description="""A list of warning resource objects representing non-critical errors or warnings.
A warning resource object is defined similarly to a [JSON API error object](http://jsonapi.org/format/1.0/#error-objects), but MUST also include the field `type`, which MUST have the value `"warning"`.
The field `detail` MUST be present and SHOULD contain a non-critical message, e.g., reporting unrecognized search attributes or deprecated features.
The field `status`, representing a HTTP response status code, MUST NOT be present for a warning resource object.
This is an exclusive field for error resource objects.""",
            uniqueItems=True,
        ),
    ] = None

api_version: Annotated[SemanticVersion, StrictField(description='Presently used full version of the OPTIMADE API.\nThe version number string MUST NOT be prefixed by, e.g., "v".\nExamples: `1.0.0`, `1.0.0-rc.2`.')] instance-attribute

data_available: Annotated[Optional[int], StrictField(description='An integer containing the total number of data resource objects available in the database for the endpoint.')] = None class-attribute instance-attribute

data_returned: Annotated[Optional[int], StrictField(description='An integer containing the total number of data resource objects returned for the current `filter` query, independent of pagination.', ge=0)] = None class-attribute instance-attribute

implementation: Annotated[Optional[Implementation], StrictField(description='a dictionary describing the server implementation')] = None class-attribute instance-attribute

last_id: Annotated[Optional[str], StrictField(description='a string containing the last ID returned')] = None class-attribute instance-attribute

model_config = ConfigDict(extra='allow') class-attribute instance-attribute

more_data_available: Annotated[bool, StrictField(description='`false` if the response contains all data for the request (e.g., a request issued to a single entry endpoint, or a `filter` query at the last page of a paginated response) and `true` if the response is incomplete in the sense that multiple objects match the request, and not all of them have been included in the response (e.g., a query with multiple pages that is not at the last page).')] instance-attribute

optimade_schema: Annotated[Optional[jsonapi.JsonLinkType], StrictField(alias=schema, description='A [JSON API links object](http://jsonapi.org/format/1.0/#document-links) that points to a schema for the response.\nIf it is a string, or a dictionary containing no `meta` field, the provided URL MUST point at an [OpenAPI](https://swagger.io/specification/) schema.\nIt is possible that future versions of this specification allows for alternative schema types.\nHence, if the `meta` field of the JSON API links object is provided and contains a field `schema_type` that is not equal to the string `OpenAPI` the client MUST not handle failures to parse the schema or to validate the response against the schema as errors.')] = None class-attribute instance-attribute

provider: Annotated[Optional[Provider], StrictField(description='information on the database provider of the implementation.')] = None class-attribute instance-attribute

query: Annotated[ResponseMetaQuery, StrictField(description='Information on the Query that was requested')] instance-attribute

response_message: Annotated[Optional[str], StrictField(description='response string from the server')] = None class-attribute instance-attribute

time_stamp: Annotated[Optional[datetime], StrictField(description='A timestamp containing the date and time at which the query was executed.')] = None class-attribute instance-attribute

warnings: Annotated[Optional[list[Warnings]], StrictField(description='A list of warning resource objects representing non-critical errors or warnings.\nA warning resource object is defined similarly to a [JSON API error object](http://jsonapi.org/format/1.0/#error-objects), but MUST also include the field `type`, which MUST have the value `"warning"`.\nThe field `detail` MUST be present and SHOULD contain a non-critical message, e.g., reporting unrecognized search attributes or deprecated features.\nThe field `status`, representing a HTTP response status code, MUST NOT be present for a warning resource object.\nThis is an exclusive field for error resource objects.', uniqueItems=True)] = None class-attribute instance-attribute

ResponseMetaQuery

Bases: BaseModel

Information on the query that was requested.

Source code in optimade/models/optimade_json.py
187
188
189
190
191
192
193
194
195
196
197
198
class ResponseMetaQuery(BaseModel):
    """Information on the query that was requested."""

    representation: Annotated[
        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`""",
        ),
    ]

representation: Annotated[str, StrictField(description='A string with the part of the URL following the versioned or unversioned base URL that serves the API.\nQuery parameters that have not been used in processing the request MAY be omitted.\nIn particular, if no query parameters have been involved in processing the request, the query part of the URL MAY be excluded.\nExample: `/structures?filter=nelements=2`')] instance-attribute

Success

Bases: Response

errors are not allowed

Source code in optimade/models/optimade_json.py
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
class Success(jsonapi.Response):
    """errors are not allowed"""

    meta: Annotated[
        ResponseMeta,
        StrictField(description="A meta object containing non-standard information"),
    ]

    @model_validator(mode="after")
    def either_data_meta_or_errors_must_be_set(self) -> "Success":
        """Overwriting the existing validation function, since 'errors' MUST NOT be set."""
        required_fields = ("data", "meta")
        if not any(field in self.model_fields_set for field in required_fields):
            raise ValueError(
                f"At least one of {required_fields} MUST be specified in the top-level response."
            )

        # errors MUST be skipped
        if self.errors or "errors" in self.model_fields_set:
            raise ValueError("'errors' MUST be skipped for a successful response.")

        return self

data: Annotated[Optional[Union[None, Resource, list[Resource]]], StrictField(description='Outputted Data', uniqueItems=True)] = None class-attribute instance-attribute

errors: Annotated[Optional[list[Error]], StrictField(description='A list of unique errors', uniqueItems=True)] = None class-attribute instance-attribute

included: Annotated[Optional[list[Resource]], StrictField(description='A list of unique included resources', uniqueItems=True)] = None class-attribute instance-attribute

jsonapi: Annotated[Optional[JsonApi], StrictField(description='Information about the JSON API used')] = None class-attribute instance-attribute

meta: Annotated[ResponseMeta, StrictField(description='A meta object containing non-standard information')] instance-attribute

model_config = ConfigDict(json_encoders={datetime: lambda v: v.astimezone(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')}) class-attribute instance-attribute

The specification mandates that datetimes must be encoded following RFC3339, which does not support fractional seconds, thus they must be stripped in the response. This can cause issues when the underlying database contains fields that do include microseconds, as filters may return unexpected results.

either_data_meta_or_errors_must_be_set()

Overwriting the existing validation function, since 'errors' MUST NOT be set.

Source code in optimade/models/optimade_json.py
388
389
390
391
392
393
394
395
396
397
398
399
400
401
@model_validator(mode="after")
def either_data_meta_or_errors_must_be_set(self) -> "Success":
    """Overwriting the existing validation function, since 'errors' MUST NOT be set."""
    required_fields = ("data", "meta")
    if not any(field in self.model_fields_set for field in required_fields):
        raise ValueError(
            f"At least one of {required_fields} MUST be specified in the top-level response."
        )

    # errors MUST be skipped
    if self.errors or "errors" in self.model_fields_set:
        raise ValueError("'errors' MUST be skipped for a successful response.")

    return self

Warnings

Bases: OptimadeError

OPTIMADE-specific warning class based on OPTIMADE-specific JSON API Error.

From the specification:

A warning resource object is defined similarly to a JSON API error object, but MUST also include the field type, which MUST have the value "warning". The field detail MUST be present and SHOULD contain a non-critical message, e.g., reporting unrecognized search attributes or deprecated features.

Note: Must be named "Warnings", since "Warning" is a built-in Python class.

Source code in optimade/models/optimade_json.py
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
class Warnings(OptimadeError):
    """OPTIMADE-specific warning class based on OPTIMADE-specific JSON API Error.

    From the specification:

    A warning resource object is defined similarly to a JSON API error object, but MUST also include the field type, which MUST have the value "warning".
    The field detail MUST be present and SHOULD contain a non-critical message, e.g., reporting unrecognized search attributes or deprecated features.

    Note: Must be named "Warnings", since "Warning" is a built-in Python class.

    """

    model_config = ConfigDict(json_schema_extra=warnings_json_schema_extra)

    type: Annotated[
        Literal["warning"],
        StrictField(
            description='Warnings must be of type "warning"',
            pattern="^warning$",
        ),
    ] = "warning"

    @model_validator(mode="after")
    def status_must_not_be_specified(self) -> "Warnings":
        if self.status or "status" in self.model_fields_set:
            raise ValueError("status MUST NOT be specified for warnings")
        return self

code: Annotated[Optional[str], StrictField(description='an application-specific error code, expressed as a string value.')] = None class-attribute instance-attribute

detail: Annotated[str, StrictField(description='A human-readable explanation specific to this occurrence of the problem.')] instance-attribute

id: Annotated[Optional[str], StrictField(description='A unique identifier for this particular occurrence of the problem.')] = None class-attribute instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='a meta object containing non-standard meta-information about the error.')] = None class-attribute instance-attribute

model_config = ConfigDict(json_schema_extra=warnings_json_schema_extra) class-attribute instance-attribute

source: Annotated[Optional[ErrorSource], StrictField(description='An object containing references to the source of the error')] = None class-attribute instance-attribute

status: Annotated[Optional[Annotated[str, BeforeValidator(str)]], StrictField(description='the HTTP status code applicable to this problem, expressed as a string value.')] = None class-attribute instance-attribute

title: Annotated[Optional[str], StrictField(description='A short, human-readable summary of the problem. It **SHOULD NOT** change from occurrence to occurrence of the problem, except for purposes of localization.')] = None class-attribute instance-attribute

type: Annotated[Literal['warning'], StrictField(description='Warnings must be of type "warning"', pattern='^warning$')] = 'warning' class-attribute instance-attribute

__hash__()

Source code in optimade/models/jsonapi.py
191
192
def __hash__(self):
    return hash(self.model_dump_json())

status_must_not_be_specified()

Source code in optimade/models/optimade_json.py
180
181
182
183
184
@model_validator(mode="after")
def status_must_not_be_specified(self) -> "Warnings":
    if self.status or "status" in self.model_fields_set:
        raise ValueError("status MUST NOT be specified for warnings")
    return self

warnings_json_schema_extra(schema, model)

Update OpenAPI JSON schema model for Warning.

  • Ensure type is in the list required properties and in the correct place.
  • Remove status property. This property is not allowed for Warning, nor is it a part of the OPTIMADE definition of the Warning object.
Note

Since type is the last model field defined, it will simply be appended.

Source code in optimade/models/optimade_json.py
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
def warnings_json_schema_extra(schema: dict[str, Any], model: type["Warnings"]) -> None:
    """Update OpenAPI JSON schema model for `Warning`.

    * Ensure `type` is in the list required properties and in the correct place.
    * Remove `status` property.
        This property is not allowed for `Warning`, nor is it a part of the OPTIMADE
        definition of the `Warning` object.

    Note:
        Since `type` is the _last_ model field defined, it will simply be appended.

    """
    if "required" in schema:
        if "type" not in schema["required"]:
            schema["required"].append("type")
        else:
            schema["required"] = ["type"]
    schema.get("properties", {}).pop("status", None)

references

Person

Bases: BaseModel

A person, i.e., an author, editor or other.

Source code in optimade/models/references.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Person(BaseModel):
    """A person, i.e., an author, editor or other."""

    name: Annotated[
        str,
        OptimadeField(
            description="""Full name of the person, REQUIRED.""",
            support=SupportLevel.MUST,
            queryable=SupportLevel.OPTIONAL,
        ),
    ]

    firstname: Annotated[
        Optional[str],
        OptimadeField(
            description="""First name of the person.""",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    lastname: Annotated[
        Optional[str],
        OptimadeField(
            description="""Last name of the person.""",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

firstname: Annotated[Optional[str], OptimadeField(description='First name of the person.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

lastname: Annotated[Optional[str], OptimadeField(description='Last name of the person.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

name: Annotated[str, OptimadeField(description='Full name of the person, REQUIRED.', support=SupportLevel.MUST, queryable=SupportLevel.OPTIONAL)] instance-attribute

ReferenceResource

Bases: EntryResource

The references entries describe bibliographic references.

The following properties are used to provide the bibliographic details:

  • address, annote, booktitle, chapter, crossref, edition, howpublished, institution, journal, key, month, note, number, organization, pages, publisher, school, series, title, volume, year: meanings of these properties match the BibTeX specification, values are strings;
  • bib_type: type of the reference, corresponding to type property in the BibTeX specification, value is string;
  • authors and editors: lists of person objects which are dictionaries with the following keys:
    • name: Full name of the person, REQUIRED.
    • firstname, lastname: Parts of the person's name, OPTIONAL.
  • doi and url: values are strings.
  • Requirements/Conventions:
    • Support: OPTIONAL support in implementations, i.e., any of the properties MAY be null.
    • Query: Support for queries on any of these properties is OPTIONAL. If supported, filters MAY support only a subset of comparison operators.
    • Every references entry MUST contain at least one of the properties.
Source code in optimade/models/references.py
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
class ReferenceResource(EntryResource):
    """The `references` entries describe bibliographic references.

    The following properties are used to provide the bibliographic details:

    - **address**, **annote**, **booktitle**, **chapter**, **crossref**, **edition**, **howpublished**, **institution**, **journal**, **key**, **month**, **note**, **number**, **organization**, **pages**, **publisher**, **school**, **series**, **title**, **volume**, **year**: meanings of these properties match the [BibTeX specification](http://bibtexml.sourceforge.net/btxdoc.pdf), values are strings;
    - **bib_type**: type of the reference, corresponding to **type** property in the BibTeX specification, value is string;
    - **authors** and **editors**: lists of *person objects* which are dictionaries with the following keys:
        - **name**: Full name of the person, REQUIRED.
        - **firstname**, **lastname**: Parts of the person's name, OPTIONAL.
    - **doi** and **url**: values are strings.
    - **Requirements/Conventions**:
        - **Support**: OPTIONAL support in implementations, i.e., any of the properties MAY be `null`.
        - **Query**: Support for queries on any of these properties is OPTIONAL.
            If supported, filters MAY support only a subset of comparison operators.
        - Every references entry MUST contain at least one of the properties.

    """

    type: Annotated[
        Literal["references"],
        OptimadeField(
            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"`""",
            pattern="^references$",
            support=SupportLevel.MUST,
            queryable=SupportLevel.MUST,
        ),
    ] = "references"
    attributes: ReferenceResourceAttributes

    @field_validator("attributes", mode="before")
    @classmethod
    def validate_attributes(cls, value: Any) -> dict[str, Any]:
        if not isinstance(value, dict):
            if isinstance(value, BaseModel):
                value = value.model_dump()
            else:
                raise TypeError("attributes field must be a mapping")
        if not any(prop[1] is not None for prop in value):
            raise ValueError("reference object must have at least one field defined")
        return value

attributes: ReferenceResourceAttributes instance-attribute

id: Annotated[str, OptimadeField(description='An entry\'s ID as defined in section Definition of Terms.\n\n- **Type**: string.\n\n- **Requirements/Conventions**:\n - **Support**: MUST be supported by all implementations, MUST NOT be `null`.\n - **Query**: MUST be a queryable property with support for all mandatory filter features.\n - **Response**: REQUIRED in the response.\n\n- **Examples**:\n - `"db/1234567"`\n - `"cod/2000000"`\n - `"cod/2000000@1234567"`\n - `"nomad/L1234567890"`\n - `"42"`', support=SupportLevel.MUST, queryable=SupportLevel.MUST)] instance-attribute

meta: Annotated[Optional[Meta], StrictField(description='a meta object containing non-standard meta-information about a resource that can not be represented as an attribute or relationship.')] = None class-attribute instance-attribute

model_config = ConfigDict(json_schema_extra=resource_json_schema_extra) class-attribute instance-attribute

relationships: Annotated[Optional[EntryRelationships], StrictField(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).\nThe 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.')] = None class-attribute instance-attribute

type: Annotated[Literal['references'], OptimadeField(description='The name of the type of an entry.\n- **Type**: string.\n- **Requirements/Conventions**:\n - **Support**: MUST be supported by all implementations, MUST NOT be `null`.\n - **Query**: MUST be a queryable property with support for all mandatory filter features.\n - **Response**: REQUIRED in the response.\n - MUST be an existing entry type.\n - The entry of type <type> and ID <id> MUST be returned in response to a request for `/<type>/<id>` under the versioned base URL.\n- **Example**: `"structures"`', pattern='^references$', support=SupportLevel.MUST, queryable=SupportLevel.MUST)] = 'references' class-attribute instance-attribute

validate_attributes(value) classmethod

Source code in optimade/models/references.py
323
324
325
326
327
328
329
330
331
332
333
@field_validator("attributes", mode="before")
@classmethod
def validate_attributes(cls, value: Any) -> dict[str, Any]:
    if not isinstance(value, dict):
        if isinstance(value, BaseModel):
            value = value.model_dump()
        else:
            raise TypeError("attributes field must be a mapping")
    if not any(prop[1] is not None for prop in value):
        raise ValueError("reference object must have at least one field defined")
    return value

ReferenceResourceAttributes

Bases: EntryResourceAttributes

Model that stores the attributes of a reference.

Many properties match the meaning described in the BibTeX specification.

Source code in optimade/models/references.py
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
class ReferenceResourceAttributes(EntryResourceAttributes):
    """Model that stores the attributes of a reference.

    Many properties match the meaning described in the
    [BibTeX specification](http://bibtexml.sourceforge.net/btxdoc.pdf).

    """

    authors: Annotated[
        Optional[list[Person]],
        OptimadeField(
            description="List of person objects containing the authors of the reference.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    editors: Annotated[
        Optional[list[Person]],
        OptimadeField(
            description="List of person objects containing the editors of the reference.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    doi: Annotated[
        Optional[str],
        OptimadeField(
            description="The digital object identifier of the reference.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    url: Annotated[
        Optional[AnyUrl],
        OptimadeField(
            description="The URL of the reference.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    address: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    annote: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    booktitle: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    chapter: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    crossref: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    edition: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    howpublished: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    institution: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    journal: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    key: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    month: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    note: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    number: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    organization: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    pages: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    publisher: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    school: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    series: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    title: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    bib_type: Annotated[
        Optional[str],
        OptimadeField(
            description="Type of the reference, corresponding to the **type** property in the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    volume: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

    year: Annotated[
        Optional[str],
        OptimadeField(
            description="Meaning of property matches the BiBTeX specification.",
            support=SupportLevel.OPTIONAL,
            queryable=SupportLevel.OPTIONAL,
        ),
    ] = None

address: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

annote: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

authors: Annotated[Optional[list[Person]], OptimadeField(description='List of person objects containing the authors of the reference.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

bib_type: Annotated[Optional[str], OptimadeField(description='Type of the reference, corresponding to the **type** property in the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

booktitle: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

chapter: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

crossref: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

doi: Annotated[Optional[str], OptimadeField(description='The digital object identifier of the reference.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

edition: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

editors: Annotated[Optional[list[Person]], OptimadeField(description='List of person objects containing the editors of the reference.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

howpublished: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

immutable_id: Annotated[Optional[str], OptimadeField(description='The entry\'s immutable ID (e.g., an UUID). This is important for databases having preferred IDs that point to "the latest version" of a record, but still offer access to older variants. This ID maps to the version-specific record, in case it changes in the future.\n\n- **Type**: string.\n\n- **Requirements/Conventions**:\n - **Support**: OPTIONAL support in implementations, i.e., MAY be `null`.\n - **Query**: MUST be a queryable property with support for all mandatory filter features.\n\n- **Examples**:\n - `"8bd3e750-b477-41a0-9b11-3a799f21b44f"`\n - `"fjeiwoj,54;@=%<>#32"` (Strings that are not URL-safe are allowed.)', support=SupportLevel.OPTIONAL, queryable=SupportLevel.MUST)] = None class-attribute instance-attribute

institution: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

journal: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

key: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

last_modified: Annotated[Optional[datetime], OptimadeField(description='Date and time representing when the entry was last modified.\n\n- **Type**: timestamp.\n\n- **Requirements/Conventions**:\n - **Support**: SHOULD be supported by all implementations, i.e., SHOULD NOT be `null`.\n - **Query**: MUST be a queryable property with support for all mandatory filter features.\n - **Response**: REQUIRED in the response unless the query parameter `response_fields` is present and does not include this property.\n\n- **Example**:\n - As part of JSON response format: `"2007-04-05T14:30:20Z"` (i.e., encoded as an [RFC 3339 Internet Date/Time Format](https://tools.ietf.org/html/rfc3339#section-5.6) string.)', support=SupportLevel.SHOULD, queryable=SupportLevel.MUST)] instance-attribute

model_config = ConfigDict(extra='allow') class-attribute instance-attribute

month: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

note: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

number: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

organization: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

pages: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

publisher: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

school: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

series: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

title: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

url: Annotated[Optional[AnyUrl], OptimadeField(description='The URL of the reference.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

volume: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

year: Annotated[Optional[str], OptimadeField(description='Meaning of property matches the BiBTeX specification.', support=SupportLevel.OPTIONAL, queryable=SupportLevel.OPTIONAL)] = None class-attribute instance-attribute

cast_immutable_id_to_str(value) classmethod

Convenience validator for casting immutable_id to a string.

Source code in optimade/models/entries.py
109
110
111
112
113
114
115
116
@field_validator("immutable_id", mode="before")
@classmethod
def cast_immutable_id_to_str(cls, value: Any) -> str:
    """Convenience validator for casting `immutable_id` to a string."""
    if value is not None and not isinstance(value, str):
        value = str(value)

    return value

check_illegal_attributes_fields()

Source code in optimade/models/jsonapi.py
330
331
332
333
334
335
336
337
338
@model_validator(mode="after")
def check_illegal_attributes_fields(self) -> "Attributes":
    illegal_fields = ("relationships", "links", "id", "type")
    for field in illegal_fields:
        if hasattr(self, field):
            raise ValueError(
                f"{illegal_fields} MUST NOT be fields under Attributes"
            )
    return self

responses

EntryInfoResponse

Bases: Success

Source code in optimade/models/responses.py
58
59
60
61
62
class EntryInfoResponse(Success):
    data: Annotated[
        EntryInfoResource,
        StrictField(description="OPTIMADE information for an entry endpoint."),
    ]

data: Annotated[EntryInfoResource, StrictField(description='OPTIMADE information for an entry endpoint.')] instance-attribute

errors: Annotated[Optional[list[Error]], StrictField(description='A list of unique errors', uniqueItems=True)] = None class-attribute instance-attribute

included: Annotated[Optional[list[Resource]], StrictField(description='A list of unique included resources', uniqueItems=True)] = None class-attribute instance-attribute

jsonapi: Annotated[Optional[JsonApi], StrictField(description='Information about the JSON API used')] = None class-attribute instance-attribute

meta: Annotated[ResponseMeta, StrictField(description='A meta object containing non-standard information')] instance-attribute

model_config = ConfigDict(json_encoders={datetime: lambda v: v.astimezone(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')}) class-attribute instance-attribute

The specification mandates that datetimes must be encoded following RFC3339, which does not support fractional seconds, thus they must be stripped in the response. This can cause issues when the underlying database contains fields that do include microseconds, as filters may return unexpected results.

either_data_meta_or_errors_must_be_set()

Overwriting the existing validation function, since 'errors' MUST NOT be set.

Source code in optimade/models/optimade_json.py
388
389
390
391
392
393
394
395
396
397
398
399
400
401
@model_validator(mode="after")
def either_data_meta_or_errors_must_be_set(self) -> "Success":
    """Overwriting the existing validation function, since 'errors' MUST NOT be set."""
    required_fields = ("data", "meta")
    if not any(field in self.model_fields_set for field in required_fields):
        raise ValueError(
            f"At least one of {required_fields} MUST be specified in the top-level response."
        )

    # errors MUST be skipped
    if self.errors or "errors" in self.model_fields_set:
        raise ValueError("'errors' MUST be skipped for a successful response.")

    return self

EntryResponseMany

Bases: Success

Source code in optimade/models/responses.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
class EntryResponseMany(Success):
    data: Annotated[  # type: ignore[assignment]
        Union[list[EntryResource], list[dict[str, Any]]],
        StrictField(
            description="List of unique OPTIMADE entry resource objects.",
            uniqueItems=True,
            union_mode="left_to_right",
        ),
    ]
    included: Annotated[
        Optional[Union[list[EntryResource], list[dict[str, Any]]]],
        StrictField(
            description="A list of unique included OPTIMADE entry resources.",
            uniqueItems=True,
            union_mode="left_to_right",
        ),
    ] = None  # type: ignore[assignment]

data: Annotated[Union[list[EntryResource], list[dict[str, Any]]], StrictField(description='List of unique OPTIMADE entry resource objects.', uniqueItems=True, union_mode=left_to_right)] instance-attribute

errors: Annotated[Optional[list[Error]], StrictField(description='A list of unique errors', uniqueItems=True)] = None class-attribute instance-attribute

included: Annotated[Optional[Union[list[EntryResource], list[dict[str, Any]]]], StrictField(description='A list of unique included OPTIMADE entry resources.', uniqueItems=True, union_mode=left_to_right)] = None class-attribute instance-attribute

jsonapi: Annotated[Optional[JsonApi], StrictField(description='Information about the JSON API used')] = None class-attribute instance-attribute

meta: Annotated[ResponseMeta, StrictField(description='A meta object containing non-standard information')] instance-attribute

model_config = ConfigDict(json_encoders={datetime: lambda v: v.astimezone(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')}) class-attribute instance-attribute

The specification mandates that datetimes must be encoded following RFC3339, which does not support fractional seconds, thus they must be stripped in the response. This can cause issues when the underlying database contains fields that do include microseconds, as filters may return unexpected results.

either_data_meta_or_errors_must_be_set()

Overwriting the existing validation function, since 'errors' MUST NOT be set.

Source code in optimade/models/optimade_json.py
388
389
390
391
392
393
394
395
396
397
398
399
400
401
@model_validator(mode="after")
def either_data_meta_or_errors_must_be_set(self) -> "Success":
    """Overwriting the existing validation function, since 'errors' MUST NOT be set."""
    required_fields = ("data", "meta")
    if not any(field in self.model_fields_set for field in required_fields):
        raise ValueError(
            f"At least one of {required_fields} MUST be specified in the top-level response."
        )

    # errors MUST be skipped
    if self.errors or "errors" in self.model_fields_set:
        raise ValueError("'errors' MUST be skipped for a successful response.")

    return self

EntryResponseOne

Bases: Success

Source code in optimade/models/responses.py
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
class EntryResponseOne(Success):
    data: Annotated[
        Optional[Union[EntryResource, dict[str, Any]]],
        StrictField(
            description="The single entry resource returned by this query.",
            union_mode="left_to_right",
        ),
    ] = None  # type: ignore[assignment]
    included: Annotated[
        Optional[Union[list[EntryResource], list[dict[str, Any]]]],
        StrictField(
            description="A list of unique included OPTIMADE entry resources.",
            uniqueItems=True,
            union_mode="left_to_right",
        ),
    ] = None  # type: ignore[assignment]

data: Annotated[Optional[Union[EntryResource, dict[str, Any]]], StrictField(description='The single entry resource returned by this query.', union_mode=left_to_right)] = None class-attribute instance-attribute

errors: Annotated[Optional[list[Error]], StrictField(description='A list of unique errors', uniqueItems=True)] = None class-attribute instance-attribute

included: Annotated[Optional[Union[list[EntryResource], list[dict[str, Any]]]], StrictField(description='A list of unique included OPTIMADE entry resources.', uniqueItems=True, union_mode=left_to_right)] = None class-attribute instance-attribute

jsonapi: Annotated[Optional[JsonApi], StrictField(description='Information about the JSON API used')] = None class-attribute instance-attribute

meta: Annotated[ResponseMeta, StrictField(description='A meta object containing non-standard information')] instance-attribute

model_config = ConfigDict(json_encoders={datetime: lambda v: v.astimezone(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')}) class-attribute instance-attribute

The specification mandates that datetimes must be encoded following RFC3339, which does not support fractional seconds, thus they must be stripped in the response. This can cause issues when the underlying database contains fields that do include microseconds, as filters may return unexpected results.

either_data_meta_or_errors_must_be_set()

Overwriting the existing validation function, since 'errors' MUST NOT be set.

Source code in optimade/models/optimade_json.py
388
389
390
391
392
393
394
395
396
397
398
399
400
401
@model_validator(mode="after")
def either_data_meta_or_errors_must_be_set(self) -> "Success":
    """Overwriting the existing validation function, since 'errors' MUST NOT be set."""
    required_fields = ("data", "meta")
    if not any(field in self.model_fields_set for field in required_fields):
        raise ValueError(
            f"At least one of {required_fields} MUST be specified in the top-level response."
        )

    # errors MUST be skipped
    if self.errors or "errors" in self.model_fields_set:
        raise ValueError("'errors' MUST be skipped for a successful response.")

    return self

ErrorResponse

Bases: Response

errors MUST be present and data MUST be skipped

Source code in optimade/models/responses.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class ErrorResponse(Response):
    """errors MUST be present and data MUST be skipped"""

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

    @model_validator(mode="after")
    def data_must_be_skipped(self) -> "ErrorResponse":
        if self.data or "data" in self.model_fields_set:
            raise ValueError("data MUST be skipped for failures reporting errors.")
        return self

data: Annotated[Optional[Union[None, Resource, list[Resource]]], StrictField(description='Outputted Data', uniqueItems=True)] = None class-attribute instance-attribute

errors: Annotated[list[OptimadeError], StrictField(description='A list of OPTIMADE-specific JSON API error objects, where the field detail MUST be present.', uniqueItems=True)] instance-attribute

included: Annotated[Optional[list[Resource]], StrictField(description='A list of unique included resources', uniqueItems=True)] = None class-attribute instance-attribute

jsonapi: Annotated[Optional[JsonApi], StrictField(description='Information about the JSON API used')] = None class-attribute instance-attribute

meta: Annotated[ResponseMeta, StrictField(description='A meta object containing non-standard information.')] instance-attribute

model_config = ConfigDict(json_encoders={datetime: lambda v: v.astimezone(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')}) class-attribute instance-attribute

The specification mandates that datetimes must be encoded following RFC3339, which does not support fractional seconds, thus they must be stripped in the response. This can cause issues when the underlying database contains fields that do include microseconds, as filters may return unexpected results.

data_must_be_skipped()

Source code in optimade/models/responses.py
45
46
47
48
49
@model_validator(mode="after")
def data_must_be_skipped(self) -> "ErrorResponse":
    if self.data or "data" in self.model_fields_set:
        raise ValueError("data MUST be skipped for failures reporting errors.")
    return self

either_data_meta_or_errors_must_be_set()

Source code in optimade/models/jsonapi.py
403
404
405
406
407
408
409
410
411
412
@model_validator(mode="after")
def either_data_meta_or_errors_must_be_set(self) -> "Response":
    required_fields = ("data", "meta", "errors")
    if not any(field in self.model_fields_set for field in required_fields):
        raise ValueError(
            f"At least one of {required_fields} MUST be specified in the top-level response"
        )
    if "errors" in self.model_fields_set and not self.errors:
        raise ValueError("Errors MUST NOT be an empty or 'null' value.")
    return self

IndexInfoResponse

Bases: Success

Source code in optimade/models/responses.py
52
53
54
55
class IndexInfoResponse(Success):
    data: Annotated[
        IndexInfoResource, StrictField(description="Index meta-database /info data.")
    ]

data: Annotated[IndexInfoResource, StrictField(description='Index meta-database /info data.')] instance-attribute

errors: Annotated[Optional[list[Error]], StrictField(description='A list of unique errors', uniqueItems=True)] = None class-attribute instance-attribute

included: Annotated[Optional[list[Resource]], StrictField(description='A list of unique included resources', uniqueItems=True)] = None class-attribute instance-attribute

jsonapi: Annotated[Optional[JsonApi], StrictField(description='Information about the JSON API used')] = None class-attribute instance-attribute

meta: Annotated[ResponseMeta, StrictField(description='A meta object containing non-standard information')] instance-attribute

model_config = ConfigDict(json_encoders={datetime: lambda v: v.astimezone(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')}) class-attribute instance-attribute

The specification mandates that datetimes must be encoded following RFC3339, which does not support fractional seconds, thus they must be stripped in the response. This can cause issues when the underlying database contains fields that do include microseconds, as filters may return unexpected results.

either_data_meta_or_errors_must_be_set()

Overwriting the existing validation function, since 'errors' MUST NOT be set.

Source code in optimade/models/optimade_json.py
388
389
390
391
392
393
394
395
396
397
398
399
400
401
@model_validator(mode="after")
def either_data_meta_or_errors_must_be_set(self) -> "Success":
    """Overwriting the existing validation function, since 'errors' MUST NOT be set."""
    required_fields = ("data", "meta")
    if not any(field in self.model_fields_set for field in required_fields):
        raise ValueError(
            f"At least one of {required_fields} MUST be specified in the top-level response."
        )

    # errors MUST be skipped
    if self.errors or "errors" in self.model_fields_set:
        raise ValueError("'errors' MUST be skipped for a successful response.")

    return self

InfoResponse

Bases: Success

Source code in optimade/models/responses.py
65
66
67
68
class InfoResponse(Success):
    data: Annotated[
        BaseInfoResource, StrictField(description="The implementations /info data.")
    ]

data: Annotated[BaseInfoResource, StrictField(description='The implementations /info data.')] instance-attribute

errors: Annotated[Optional[list[Error]], StrictField(description='A list of unique errors', uniqueItems=True)] = None class-attribute instance-attribute

included: Annotated[Optional[list[Resource]], StrictField(description='A list of unique included resources', uniqueItems=True)] = None class-attribute instance-attribute

jsonapi: Annotated[Optional[JsonApi], StrictField(description='Information about the JSON API used')] = None class-attribute instance-attribute

meta: Annotated[ResponseMeta, StrictField(description='A meta object containing non-standard information')] instance-attribute

model_config = ConfigDict(json_encoders={datetime: lambda v: v.astimezone(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')})