Source code for httk.core.register.schemas
"""Schema and definition resource registries."""
#
# The high-throughput toolkit (httk)
# Copyright (C) 2012-2024 the httk AUTHORS
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation; either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
from functools import cache
from importlib.resources import files
from typing import TYPE_CHECKING, Any, cast
if TYPE_CHECKING:
from ..property_definitions import EntryTypeDefinition, PropertyDefinition
_entry_type_definitions: dict[str, str] = {}
_property_definitions: dict[str, str] = {}
[docs]
def register_entry_type_definition(*, definition_id: str, resource: str) -> None:
"""Register one resource for an entry-type definition IRI.
:param definition_id: The entry-type definition IRI.
:param resource: The package resource reference to load.
:raises ValueError: If ``definition_id`` is already registered.
"""
if definition_id in _entry_type_definitions:
raise ValueError(f"entry-type definition is already registered: {definition_id!r}")
_entry_type_definitions[definition_id] = resource
[docs]
def known_entry_type_definitions() -> list[str]:
"""Return registered entry-type definition IRIs.
:return: Registered entry-type definition identifiers.
"""
return sorted(_entry_type_definitions)
[docs]
def register_property_definition(*, definition_id: str, resource: str) -> None:
"""Register one resource for a property definition IRI.
:param definition_id: The property definition IRI.
:param resource: The package resource reference to load.
:raises ValueError: If ``definition_id`` is already registered.
"""
if definition_id in _property_definitions:
raise ValueError(f"property definition is already registered: {definition_id!r}")
_property_definitions[definition_id] = resource
[docs]
def known_property_definitions() -> list[str]:
"""Return registered property definition IRIs.
:return: Registered property definition identifiers.
"""
return sorted(_property_definitions)
def _resource(resource: str) -> dict[str, Any]:
package, separator, filename = resource.partition(":")
if not separator or not package or not filename:
raise ValueError(f"Invalid registry resource {resource!r}; expected 'package:filename.json'")
return cast(dict[str, Any], json.loads(files(package).joinpath(filename).read_text(encoding="utf-8")))
@cache
[docs]
def load_entry_type_definition(definition_id: str) -> "EntryTypeDefinition":
"""Load and verify a registered entry-type definition resource.
:param definition_id: The registered entry-type definition IRI.
:return: The loaded and validated entry-type definition.
:raises ValueError: If the IRI is unregistered or disagrees with the document.
"""
try:
resource = _entry_type_definitions[definition_id]
except KeyError as exc:
known = ", ".join(known_entry_type_definitions()) or "(none)"
raise ValueError(f"No entry-type definition registered for {definition_id!r}. Known: {known}") from exc
from ..property_definitions import EntryTypeDefinition
document = _resource(resource)
definition = EntryTypeDefinition.from_optimade(definition_id.rsplit("/", 1)[-1], document)
document_id = definition.definition_id
if document_id != definition_id:
raise ValueError(
f"Entry-type definition registration IRI {definition_id!r} does not match document $id {document_id!r}"
)
return definition
@cache
[docs]
def load_property_definition(definition_id: str) -> "PropertyDefinition":
"""Load and verify a registered property definition resource.
:param definition_id: The registered property definition IRI.
:return: The loaded and validated property definition.
:raises ValueError: If the IRI is unregistered or disagrees with the document.
"""
try:
resource = _property_definitions[definition_id]
except KeyError as exc:
known = ", ".join(known_property_definitions()) or "(none)"
raise ValueError(f"No property definition registered for {definition_id!r}. Known: {known}") from exc
from ..property_definitions import PropertyDefinition
document = _resource(resource)
name = document.get("name", definition_id.rsplit("/", 1)[-1])
definition = PropertyDefinition.from_optimade(name, document)
document_id = definition.definition_id
if document_id != definition_id:
raise ValueError(
f"Property definition registration IRI {definition_id!r} does not match document $id {document_id!r}"
)
return definition