Skip to content

adapter

EntryAdapter

Base class for lazy resource entry adapters.

Attributes:

Name Type Description
ENTRY_RESOURCE type[EntryResource]

Entry resource to store entry as.

_type_converters dict[str, Callable]

Dictionary of valid conversion types for entry.

_type_ingesters dict[str, Callable]

Dictionary of valid ingestion types mapped to ingestion functions.

_type_ingesters_by_type dict[str, type]

Dictionary mapping the keys of _type_ingesters to data types that can be ingested.

as_<_type_converters> dict[str, type]

Convert entry to a type listed in _type_converters.

from_<_type_converters> dict[str, type]

Convert an external type to the corresponding OPTIMADE model.

Source code in optimade/adapters/base.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
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
class EntryAdapter:
    """
    Base class for lazy resource entry adapters.

    Attributes:
        ENTRY_RESOURCE: Entry resource to store entry as.
        _type_converters: Dictionary of valid conversion types for entry.
        _type_ingesters: Dictionary of valid ingestion types mapped to ingestion functions.
        _type_ingesters_by_type: Dictionary mapping the keys of `_type_ingesters` to data
            types that can be ingested.
        as_<_type_converters>: Convert entry to a type listed in `_type_converters`.
        from_<_type_converters>: Convert an external type to the corresponding OPTIMADE model.

    """

    ENTRY_RESOURCE: type[EntryResource] = EntryResource
    _type_converters: dict[str, Callable] = {}
    _type_ingesters: dict[str, Callable] = {}
    _type_ingesters_by_type: dict[str, type] = {}

    def __init__(self, entry: dict[str, Any]) -> None:
        """
        Parameters:
            entry (dict): A JSON OPTIMADE single resource entry.
        """
        self._converted: dict[str, Any] = {}

        self._entry = self.ENTRY_RESOURCE(**entry)

        # Note that these return also the default values for otherwise non-provided properties.
        self._common_converters = {
            # Return JSON serialized string, see https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeljson
            "json": self.entry.model_dump_json,
            # Return Python dict, see https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeldict
            "dict": self.entry.model_dump,
        }

    @property
    def entry(self) -> EntryResource:
        """Get OPTIMADE entry.

        Returns:
            The entry resource.

        """
        return self._entry

    def convert(self, format: str) -> Any:
        """Convert OPTIMADE entry to desired format.

        Parameters:
            format (str): Type or format to which the entry should be converted.

        Raises:
            AttributeError: If `format` can not be found in `_type_converters` or `_common_converters`.

        Returns:
            The converted entry according to the desired format or type.

        """
        if (
            format not in self._type_converters
            and format not in self._common_converters
        ):
            raise AttributeError(
                f"Non-valid entry type to convert to: {format}\nValid entry types: "
                f"{tuple(self._type_converters.keys()) + tuple(self._common_converters.keys())}"
            )

        if self._converted.get(format, None) is None:
            if format in self._type_converters:
                self._converted[format] = self._type_converters[format](self.entry)
            else:
                self._converted[format] = self._common_converters[format]()

        return self._converted[format]

    @classmethod
    def ingest_from(cls, data: Any, format: Optional[str] = None) -> Any:
        """Convert desired format to OPTIMADE format.

        Parameters:
            data (Any): The data to convert.
            format (str): Type or format to which the entry should be converted.

        Raises:
            AttributeError: If `format` can not be found in `_type_ingesters`.

        Returns:
            The ingested Structure.

        """

        if format is None:
            for key, instance_type in cls._type_ingesters_by_type.items():
                if isinstance(data, instance_type):
                    format = key
                    break

            else:
                raise AttributeError(
                    f"Non entry type to data of type {type(data)} from.\n"
                    f"Valid entry types: {tuple(cls._type_ingesters.keys())}"
                )

        if format not in cls._type_ingesters:
            raise AttributeError(
                f"Non-valid entry type to ingest from: {format}\n"
                f"Valid entry types: {tuple(cls._type_ingesters.keys())}"
            )

        return cls(
            {
                "attributes": cls._type_ingesters[format](data).model_dump(),
                "id": "",
                "type": "structures",
            }
        )

    @staticmethod
    def _get_model_attributes(
        starting_instances: Union[tuple[BaseModel, ...], list[BaseModel]], name: str
    ) -> Any:
        """Helper method for retrieving the OPTIMADE model's attribute, supporting "."-nested attributes"""
        for res in starting_instances:
            nested_attributes = name.split(".")
            for nested_attribute in nested_attributes:
                if nested_attribute in getattr(res, "model_fields", {}):
                    res = getattr(res, nested_attribute)
                else:
                    res = None
                    break
            if res is not None:
                return res
        raise AttributeError

    def __getattr__(self, name: str) -> Any:
        """Get converted entry or attribute from OPTIMADE entry.

        Support any level of "."-nested OPTIMADE `ENTRY_RESOURCE` attributes, e.g.,
        `attributes.species` for [`StuctureResource`][optimade.models.structures.StructureResource].

        Note:
            All nested attributes must individually be subclasses of `pydantic.BaseModel`,
            i.e., one can not access nested attributes in lists by passing a "."-nested `name` to this method,
            e.g., `attributes.species.name` or `attributes.species[0].name` will not work for variable `name`.

        Order:

        - Try to return converted entry if using `as_<_type_converters key>`.
        - Try to return OPTIMADE `ENTRY_RESOURCE` (nested) attribute.
        - Try to return OPTIMADE `ENTRY_RESOURCE.attributes` (nested) attribute.
        - Raise `AttributeError`.

        Parameters:
            name (str): Requested attribute.

        Raises:
            AttributeError: If the requested attribute is not recognized.
                See above for the description of the order in which an attribute is tested for validity.

        """
        # as_<entry_type>
        if name.startswith("as_"):
            entry_type = "_".join(name.split("_")[1:])
            return self.convert(entry_type)

        # Try returning ENTRY_RESOURCE attribute
        try:
            res = self._get_model_attributes((self.entry, self.entry.attributes), name)
        except AttributeError:
            pass
        else:
            return res

        # Non-valid attribute
        _entry_resource_name = re.match(
            r"(<class ')([a-zA-Z_]+\.)*([a-zA-Z_]+)('>)", str(self.ENTRY_RESOURCE)
        )
        entry_resource_name = (
            _entry_resource_name.group(3)
            if _entry_resource_name is not None
            else "UNKNOWN RESOURCE"
        )
        raise AttributeError(
            f"Unknown attribute: {name}\n"
            "If you want to get a converted entry as <entry_type> use `as_<entry_type>`, "
            f"where `<entry_type>` is one of {tuple(self._type_converters.keys()) + tuple(self._common_converters.keys())}\n"
            f"Otherwise, you can try to retrieve an OPTIMADE {entry_resource_name} attribute or property."
        )

entry: EntryResource property

Get OPTIMADE entry.

Returns:

Type Description
EntryResource

The entry resource.

__getattr__(name)

Get converted entry or attribute from OPTIMADE entry.

Support any level of "."-nested OPTIMADE ENTRY_RESOURCE attributes, e.g., attributes.species for StuctureResource.

Note

All nested attributes must individually be subclasses of pydantic.BaseModel, i.e., one can not access nested attributes in lists by passing a "."-nested name to this method, e.g., attributes.species.name or attributes.species[0].name will not work for variable name.

Order:

  • Try to return converted entry if using as_<_type_converters key>.
  • Try to return OPTIMADE ENTRY_RESOURCE (nested) attribute.
  • Try to return OPTIMADE ENTRY_RESOURCE.attributes (nested) attribute.
  • Raise AttributeError.

Parameters:

Name Type Description Default
name str

Requested attribute.

required

Raises:

Type Description
AttributeError

If the requested attribute is not recognized. See above for the description of the order in which an attribute is tested for validity.

Source code in optimade/adapters/base.py
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
def __getattr__(self, name: str) -> Any:
    """Get converted entry or attribute from OPTIMADE entry.

    Support any level of "."-nested OPTIMADE `ENTRY_RESOURCE` attributes, e.g.,
    `attributes.species` for [`StuctureResource`][optimade.models.structures.StructureResource].

    Note:
        All nested attributes must individually be subclasses of `pydantic.BaseModel`,
        i.e., one can not access nested attributes in lists by passing a "."-nested `name` to this method,
        e.g., `attributes.species.name` or `attributes.species[0].name` will not work for variable `name`.

    Order:

    - Try to return converted entry if using `as_<_type_converters key>`.
    - Try to return OPTIMADE `ENTRY_RESOURCE` (nested) attribute.
    - Try to return OPTIMADE `ENTRY_RESOURCE.attributes` (nested) attribute.
    - Raise `AttributeError`.

    Parameters:
        name (str): Requested attribute.

    Raises:
        AttributeError: If the requested attribute is not recognized.
            See above for the description of the order in which an attribute is tested for validity.

    """
    # as_<entry_type>
    if name.startswith("as_"):
        entry_type = "_".join(name.split("_")[1:])
        return self.convert(entry_type)

    # Try returning ENTRY_RESOURCE attribute
    try:
        res = self._get_model_attributes((self.entry, self.entry.attributes), name)
    except AttributeError:
        pass
    else:
        return res

    # Non-valid attribute
    _entry_resource_name = re.match(
        r"(<class ')([a-zA-Z_]+\.)*([a-zA-Z_]+)('>)", str(self.ENTRY_RESOURCE)
    )
    entry_resource_name = (
        _entry_resource_name.group(3)
        if _entry_resource_name is not None
        else "UNKNOWN RESOURCE"
    )
    raise AttributeError(
        f"Unknown attribute: {name}\n"
        "If you want to get a converted entry as <entry_type> use `as_<entry_type>`, "
        f"where `<entry_type>` is one of {tuple(self._type_converters.keys()) + tuple(self._common_converters.keys())}\n"
        f"Otherwise, you can try to retrieve an OPTIMADE {entry_resource_name} attribute or property."
    )

__init__(entry)

Parameters:

Name Type Description Default
entry dict

A JSON OPTIMADE single resource entry.

required
Source code in optimade/adapters/base.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def __init__(self, entry: dict[str, Any]) -> None:
    """
    Parameters:
        entry (dict): A JSON OPTIMADE single resource entry.
    """
    self._converted: dict[str, Any] = {}

    self._entry = self.ENTRY_RESOURCE(**entry)

    # Note that these return also the default values for otherwise non-provided properties.
    self._common_converters = {
        # Return JSON serialized string, see https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeljson
        "json": self.entry.model_dump_json,
        # Return Python dict, see https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeldict
        "dict": self.entry.model_dump,
    }

convert(format)

Convert OPTIMADE entry to desired format.

Parameters:

Name Type Description Default
format str

Type or format to which the entry should be converted.

required

Raises:

Type Description
AttributeError

If format can not be found in _type_converters or _common_converters.

Returns:

Type Description
Any

The converted entry according to the desired format or type.

Source code in optimade/adapters/base.py
 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
def convert(self, format: str) -> Any:
    """Convert OPTIMADE entry to desired format.

    Parameters:
        format (str): Type or format to which the entry should be converted.

    Raises:
        AttributeError: If `format` can not be found in `_type_converters` or `_common_converters`.

    Returns:
        The converted entry according to the desired format or type.

    """
    if (
        format not in self._type_converters
        and format not in self._common_converters
    ):
        raise AttributeError(
            f"Non-valid entry type to convert to: {format}\nValid entry types: "
            f"{tuple(self._type_converters.keys()) + tuple(self._common_converters.keys())}"
        )

    if self._converted.get(format, None) is None:
        if format in self._type_converters:
            self._converted[format] = self._type_converters[format](self.entry)
        else:
            self._converted[format] = self._common_converters[format]()

    return self._converted[format]

ingest_from(data, format=None) classmethod

Convert desired format to OPTIMADE format.

Parameters:

Name Type Description Default
data Any

The data to convert.

required
format str

Type or format to which the entry should be converted.

None

Raises:

Type Description
AttributeError

If format can not be found in _type_ingesters.

Returns:

Type Description
Any

The ingested Structure.

Source code in optimade/adapters/base.py
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
@classmethod
def ingest_from(cls, data: Any, format: Optional[str] = None) -> Any:
    """Convert desired format to OPTIMADE format.

    Parameters:
        data (Any): The data to convert.
        format (str): Type or format to which the entry should be converted.

    Raises:
        AttributeError: If `format` can not be found in `_type_ingesters`.

    Returns:
        The ingested Structure.

    """

    if format is None:
        for key, instance_type in cls._type_ingesters_by_type.items():
            if isinstance(data, instance_type):
                format = key
                break

        else:
            raise AttributeError(
                f"Non entry type to data of type {type(data)} from.\n"
                f"Valid entry types: {tuple(cls._type_ingesters.keys())}"
            )

    if format not in cls._type_ingesters:
        raise AttributeError(
            f"Non-valid entry type to ingest from: {format}\n"
            f"Valid entry types: {tuple(cls._type_ingesters.keys())}"
        )

    return cls(
        {
            "attributes": cls._type_ingesters[format](data).model_dump(),
            "id": "",
            "type": "structures",
        }
    )

Reference

Bases: EntryAdapter

Lazy reference resource converter.

Go to EntryAdapter to see the full list of methods and properties.

Attributes:

Name Type Description
ENTRY_RESOURCE ReferenceResource

This adapter stores entry resources as ReferenceResources.

_type_converters Dict[str, Callable]

Dictionary of valid conversion types for entry.

There are currently no available types.

as_<_type_converters> Dict[str, Callable]

Convert entry to a type listed in _type_converters.

Source code in optimade/adapters/references/adapter.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Reference(EntryAdapter):
    """
    Lazy reference resource converter.

    Go to [`EntryAdapter`][optimade.adapters.base.EntryAdapter] to see the full list of methods
    and properties.

    Attributes:
        ENTRY_RESOURCE (ReferenceResource): This adapter stores entry resources as
            [`ReferenceResource`][optimade.models.references.ReferenceResource]s.
        _type_converters (Dict[str, Callable]): Dictionary of valid conversion types for entry.

            There are currently no available types.
        as_<_type_converters>: Convert entry to a type listed in `_type_converters`.

    """

    ENTRY_RESOURCE: type[ReferenceResource] = ReferenceResource

entry: EntryResource property

Get OPTIMADE entry.

Returns:

Type Description
EntryResource

The entry resource.

__getattr__(name)

Get converted entry or attribute from OPTIMADE entry.

Support any level of "."-nested OPTIMADE ENTRY_RESOURCE attributes, e.g., attributes.species for StuctureResource.

Note

All nested attributes must individually be subclasses of pydantic.BaseModel, i.e., one can not access nested attributes in lists by passing a "."-nested name to this method, e.g., attributes.species.name or attributes.species[0].name will not work for variable name.

Order:

  • Try to return converted entry if using as_<_type_converters key>.
  • Try to return OPTIMADE ENTRY_RESOURCE (nested) attribute.
  • Try to return OPTIMADE ENTRY_RESOURCE.attributes (nested) attribute.
  • Raise AttributeError.

Parameters:

Name Type Description Default
name str

Requested attribute.

required

Raises:

Type Description
AttributeError

If the requested attribute is not recognized. See above for the description of the order in which an attribute is tested for validity.

Source code in optimade/adapters/base.py
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
def __getattr__(self, name: str) -> Any:
    """Get converted entry or attribute from OPTIMADE entry.

    Support any level of "."-nested OPTIMADE `ENTRY_RESOURCE` attributes, e.g.,
    `attributes.species` for [`StuctureResource`][optimade.models.structures.StructureResource].

    Note:
        All nested attributes must individually be subclasses of `pydantic.BaseModel`,
        i.e., one can not access nested attributes in lists by passing a "."-nested `name` to this method,
        e.g., `attributes.species.name` or `attributes.species[0].name` will not work for variable `name`.

    Order:

    - Try to return converted entry if using `as_<_type_converters key>`.
    - Try to return OPTIMADE `ENTRY_RESOURCE` (nested) attribute.
    - Try to return OPTIMADE `ENTRY_RESOURCE.attributes` (nested) attribute.
    - Raise `AttributeError`.

    Parameters:
        name (str): Requested attribute.

    Raises:
        AttributeError: If the requested attribute is not recognized.
            See above for the description of the order in which an attribute is tested for validity.

    """
    # as_<entry_type>
    if name.startswith("as_"):
        entry_type = "_".join(name.split("_")[1:])
        return self.convert(entry_type)

    # Try returning ENTRY_RESOURCE attribute
    try:
        res = self._get_model_attributes((self.entry, self.entry.attributes), name)
    except AttributeError:
        pass
    else:
        return res

    # Non-valid attribute
    _entry_resource_name = re.match(
        r"(<class ')([a-zA-Z_]+\.)*([a-zA-Z_]+)('>)", str(self.ENTRY_RESOURCE)
    )
    entry_resource_name = (
        _entry_resource_name.group(3)
        if _entry_resource_name is not None
        else "UNKNOWN RESOURCE"
    )
    raise AttributeError(
        f"Unknown attribute: {name}\n"
        "If you want to get a converted entry as <entry_type> use `as_<entry_type>`, "
        f"where `<entry_type>` is one of {tuple(self._type_converters.keys()) + tuple(self._common_converters.keys())}\n"
        f"Otherwise, you can try to retrieve an OPTIMADE {entry_resource_name} attribute or property."
    )

__init__(entry)

Parameters:

Name Type Description Default
entry dict

A JSON OPTIMADE single resource entry.

required
Source code in optimade/adapters/base.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def __init__(self, entry: dict[str, Any]) -> None:
    """
    Parameters:
        entry (dict): A JSON OPTIMADE single resource entry.
    """
    self._converted: dict[str, Any] = {}

    self._entry = self.ENTRY_RESOURCE(**entry)

    # Note that these return also the default values for otherwise non-provided properties.
    self._common_converters = {
        # Return JSON serialized string, see https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeljson
        "json": self.entry.model_dump_json,
        # Return Python dict, see https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeldict
        "dict": self.entry.model_dump,
    }

convert(format)

Convert OPTIMADE entry to desired format.

Parameters:

Name Type Description Default
format str

Type or format to which the entry should be converted.

required

Raises:

Type Description
AttributeError

If format can not be found in _type_converters or _common_converters.

Returns:

Type Description
Any

The converted entry according to the desired format or type.

Source code in optimade/adapters/base.py
 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
def convert(self, format: str) -> Any:
    """Convert OPTIMADE entry to desired format.

    Parameters:
        format (str): Type or format to which the entry should be converted.

    Raises:
        AttributeError: If `format` can not be found in `_type_converters` or `_common_converters`.

    Returns:
        The converted entry according to the desired format or type.

    """
    if (
        format not in self._type_converters
        and format not in self._common_converters
    ):
        raise AttributeError(
            f"Non-valid entry type to convert to: {format}\nValid entry types: "
            f"{tuple(self._type_converters.keys()) + tuple(self._common_converters.keys())}"
        )

    if self._converted.get(format, None) is None:
        if format in self._type_converters:
            self._converted[format] = self._type_converters[format](self.entry)
        else:
            self._converted[format] = self._common_converters[format]()

    return self._converted[format]

ingest_from(data, format=None) classmethod

Convert desired format to OPTIMADE format.

Parameters:

Name Type Description Default
data Any

The data to convert.

required
format str

Type or format to which the entry should be converted.

None

Raises:

Type Description
AttributeError

If format can not be found in _type_ingesters.

Returns:

Type Description
Any

The ingested Structure.

Source code in optimade/adapters/base.py
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
@classmethod
def ingest_from(cls, data: Any, format: Optional[str] = None) -> Any:
    """Convert desired format to OPTIMADE format.

    Parameters:
        data (Any): The data to convert.
        format (str): Type or format to which the entry should be converted.

    Raises:
        AttributeError: If `format` can not be found in `_type_ingesters`.

    Returns:
        The ingested Structure.

    """

    if format is None:
        for key, instance_type in cls._type_ingesters_by_type.items():
            if isinstance(data, instance_type):
                format = key
                break

        else:
            raise AttributeError(
                f"Non entry type to data of type {type(data)} from.\n"
                f"Valid entry types: {tuple(cls._type_ingesters.keys())}"
            )

    if format not in cls._type_ingesters:
        raise AttributeError(
            f"Non-valid entry type to ingest from: {format}\n"
            f"Valid entry types: {tuple(cls._type_ingesters.keys())}"
        )

    return cls(
        {
            "attributes": cls._type_ingesters[format](data).model_dump(),
            "id": "",
            "type": "structures",
        }
    )

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