Skip to content

Metadata

Metadata generators are device APIs or device description languages. One can either create a Thing in code and generate metadata (code-first), or create a Thing from a metadata (API-first). The interface required to do this is defined here.

A specific metadata format is a bundle of five classes: one per core component - Property, Action, Event and a common base class for common metadata among them, and a class that puts them together.

The W3C Web of Things bundle in hololinked.metadata.td is the reference implementation, and maps onto the five slots as:

slot W3C WoT class
thing ThingModel
property PropertyAffordance
action ActionAffordance
event EventAffordance
interaction InteractionAffordance

Have a look at their code by using the links above.

hololinked.core.interfaces.metadata.MetadataFormat dataclass

Metadata class for each core component.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
@dataclass
class MetadataFormat:
    """Metadata class for each core component."""

    thing: type[Metadata]
    property: type[PropertyMetadata]
    action: type[ActionMetadata]
    event: type[EventMetadata]
    interaction: type[InteractionMetadata]

Attributes

thing instance-attribute

thing: type[Metadata]

property instance-attribute

property: type[PropertyMetadata]

action instance-attribute

action: type[ActionMetadata]

event instance-attribute

event: type[EventMetadata]

interaction instance-attribute

interaction: type[InteractionMetadata]

hololinked.core.interfaces.metadata.Metadata

Bases: BaseModel

A base class to generate device or Thing metadata and conversely produce a Thing instance from the metadata.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
class Metadata(BaseModel):
    """A base class to generate device or Thing metadata and conversely produce a Thing instance from the metadata."""

    model_config = ConfigDict(extra="allow")

    def __init__(
        self,
        thing: Thing | None = None,
        ignore_errors: bool = False,
        skip_names: Optional[list[str]] = [],
    ) -> None:
        """
        Initialize the Metadata.

        Parameters
        ----------
        thing: Thing | None, optional
            The `Thing` instance for which the metadata is being generated. None, if the Thing instance is to be
            produced from the metadata.
        ignore_errors: bool, optional
            Whether to ignore errors during metadata generation. Defaults to False.
        skip_names: list[str], optional
            List of property, action, or event names to skip when generating the metadata. Defaults to an empty list.
        """
        super().__init__()
        self.thing = thing
        self.ignore_errors = ignore_errors
        self.skip_names = skip_names or []

    def generate(self) -> Metadata:
        """Populate the metadata from the Thing instance."""
        raise NotImplementedError("Implement generate() in subclass")

    def produce(self) -> Thing:
        """Produce a Thing instance from the metadata."""
        raise NotImplementedError("Implement produce() in subclass")

    skip_properties: list[str]
    """
    List of default property names to skip when generating the metadata. Different from `skip_names` as
    this list is supposed to be used as a builtin blacklist.
    """

    skip_actions: list[str]
    """
    List of default action names to skip when generating the metadata. Different from `skip_names` as
    this list is supposed to be used as a builtin blacklist.
    """

    skip_events: list[str]
    """
    List of default event names to skip when generating the metadata. Different from `skip_names` as
    this list is supposed to be used as a builtin blacklist.
    """

    def add_interactions(self) -> None:
        """
        Add interaction(-affordances) to the metadata - properties, actions and events.

        This is to be tailored for the specific standard.
        """
        raise NotImplementedError("Implement add_interactions() in subclass")

    def json(self, **kwargs) -> dict[str, Any]:  # ty: ignore[invalid-method-override]
        """
        Return the JSON string representation.

        Returns
        -------
        dict[str, Any]
            The JSON string representation.
        """
        return self.model_dump(**kwargs)

Attributes

thing instance-attribute

thing = thing

skip_properties instance-attribute

skip_properties: list[str]

List of default property names to skip when generating the metadata. Different from skip_names as this list is supposed to be used as a builtin blacklist.

skip_actions instance-attribute

skip_actions: list[str]

List of default action names to skip when generating the metadata. Different from skip_names as this list is supposed to be used as a builtin blacklist.

skip_events instance-attribute

skip_events: list[str]

List of default event names to skip when generating the metadata. Different from skip_names as this list is supposed to be used as a builtin blacklist.

skip_names instance-attribute

skip_names = skip_names or []

ignore_errors instance-attribute

ignore_errors = ignore_errors

Functions

generate

generate() -> Metadata

Populate the metadata from the Thing instance.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
def generate(self) -> Metadata:
    """Populate the metadata from the Thing instance."""
    raise NotImplementedError("Implement generate() in subclass")

produce

produce() -> Thing

Produce a Thing instance from the metadata.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
def produce(self) -> Thing:
    """Produce a Thing instance from the metadata."""
    raise NotImplementedError("Implement produce() in subclass")

add_interactions

add_interactions() -> None

Add interaction(-affordances) to the metadata - properties, actions and events.

This is to be tailored for the specific standard.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
def add_interactions(self) -> None:
    """
    Add interaction(-affordances) to the metadata - properties, actions and events.

    This is to be tailored for the specific standard.
    """
    raise NotImplementedError("Implement add_interactions() in subclass")

json

json(**kwargs) -> dict[str, Any]

Return the JSON string representation.

Returns:

Type Description
dict[str, Any]

The JSON string representation.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
def json(self, **kwargs) -> dict[str, Any]:  # ty: ignore[invalid-method-override]
    """
    Return the JSON string representation.

    Returns
    -------
    dict[str, Any]
        The JSON string representation.
    """
    return self.model_dump(**kwargs)

hololinked.core.interfaces.metadata.InteractionMetadata

Bases: BaseModel

Generate metadata for a property, action or event.

A property, action or event is called as an interaction(-affordance), and the metadata generated for it is named here as interaction metadata. This base class defines metadata methods common to all of properties, actions or events, and could be common to different metadata or device description standards. Specific standards need to extend this class.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
class InteractionMetadata(BaseModel):
    """
    Generate metadata for a property, action or event.

    A property, action or event is called as an interaction(-affordance), and the metadata generated for it
    is named here as interaction metadata. This base class defines metadata methods common to all of properties,
    actions or events, and could be common to different metadata or device description standards. Specific standards
    need to extend this class.
    """

    _custom_metadata_generators: ClassVar[dict]

    def __init__(self):
        super().__init__()
        self._name = None
        self._objekt = None
        self._thing_id = None
        self._thing_cls = None
        self._owner = None

    @property
    def what(self) -> Enum:
        """Whether it is a property, action or event."""
        raise NotImplementedError("Unknown interaction (property, action, or event?), implement in subclass")

    @property
    def owner(self) -> Thing:
        """
        Owning `Thing` instance or `Thing` class of the interaction.

        Depending on how this object was created, returns either an instance or a class.

        Raises
        ------
        AttributeError
            If the owner is not set, which means this interaction is not properly bound to a `Thing`
            instance or class. Dont explicitly instantiate this class without the context of a `Thing` instance
            or class, or at least dont prematurely access this attribute.
        """
        if self._owner is None:
            raise AttributeError("owner is not set for this interaction")
        return self._owner

    @property
    def owner_cls(self) -> ThingMeta:
        """
        Return the owning `Thing` class of the interaction.

        Raises
        ------
        AttributeError
            If the owner is not set, which means this interaction is not properly bound to a `Thing`
            instance or class. Dont explicitly instantiate this class without the context of a `Thing` instance
            or class, or at least dont prematurely access this attribute.
        """
        if self._thing_cls is None:
            raise AttributeError("owner_cls is not set for this interaction")
        return self._thing_cls

    @property
    def objekt(self) -> Property | Action | Event:
        """
        Object instance of the interaction, instance of `Property`, `Action` or `Event`.

        Raises
        ------
        AttributeError
            If the metadata is not bound to any interaction object.
            Use `Thing<instance>.<property>.to_metadata()` only method to generate this metadata
            from a property object or similarly for action and event.
        """
        if self._objekt is None:
            raise AttributeError("Metadata bound to unknown object (property, action or event).")
        return self._objekt

    @property
    def name(self) -> str:
        """
        Name of the interaction that could be used as a key in the metadata.

        Raises
        ------
        AttributeError
            If the metadata is not bound to any interaction object. This usually happens
            when the metadata is not generated from an interaction object, but created manually or from a
            different source. Use `Thing<instance>.<property>.to_metadata()` only to generate the metadata
            from a property object, and similarly for action and event.
        """
        if self._name is None:
            raise AttributeError("Metadata bound to unknown object (property, action or event).")
        return self._name

    @property
    def thing_id(self) -> str:
        """
        ID of the `Thing` instance owning the interaction, if available, otherwise None.

        Raises
        ------
        AttributeError
            If the metadata is not bound to any `Thing` instance. This usually happens
            when the metadata is not generated from an interaction object, but created manually or from a
            different source. Use `thing.properties.descriptors[<property>].to_metadata()`
            only to generate the metadata from a property object, and similarly for an action and event.
        """
        if self._thing_id is None:
            raise AttributeError("Metadata bound to unknown Thing (property, action or event's owner unknown).")
        return self._thing_id

    @property
    def thing_cls(self) -> ThingMeta:
        """
        `Thing` class owning the interaction.

        Raises
        ------
        AttributeError
            If the metadata is not bound to any `Thing` class. This usually happens
            when the metadata is not generated from a `Thing` class, but created manually or from a
            different source. Use `thing.properties.descriptors[<property>].to_metadata()` or `Thing.properties.descriptors[<property>].to_metadata()` only method to generate the metadata from a property object, and similarly for action and event.
            only method to generate the metadata from a property object, and similarly for action and event.
        """
        if self._thing_cls is None:
            raise AttributeError("Metadata bound to unknown Thing class (property, action or event's owner unknown).")
        return self._thing_cls

    def build(self) -> None:
        """Populate the fields of the metadata for the specific interaction."""
        raise NotImplementedError("build must be implemented in subclass of InteractionMetadata")

    @classmethod
    def from_descriptor(
        cls,
        interaction: Property | Action | Event,
        owner: Thing | ThingMeta,
    ) -> Self:
        """
        Instantitate and build the metadata for the specific interaction.

        Use the `json()` method to get the JSON representation of the metadata.

        Note that this method is different from `build()` method as its supposed to be used as a classmethod
        to create an instance. Although, it internally calls `build()`, and some additional steps can be included.

        Parameters
        ----------
        interaction: Property | Action | Event
            interaction object for which the metadata is to be built
        owner: Thing | ThingMeta
            owner of the interaction

        Returns
        -------
        PropertyMetadata | ActionMetadata | EventMetadata
            Instance of this class with the metadata fields populated.
        """
        raise NotImplementedError("from_descriptor() must be implemented in subclass of InteractionMetadata")

    @classmethod
    def from_metadata(cls, name: str, metadata: dict[str, Any]) -> Self:
        """
        Populate the metadata from the provided JSON and return it as an instance of this class.

        It is assumed that the interaction is a key in the provided JSON, so one needs to supply the name.

        Parameters
        ----------
        name: str
            name of the interaction used as key in the metadata
        metadata: JSON
            metadata JSON dictionary (the entire one, not just the component of the interaction)

        Returns
        -------
        Self
            Instance of this class.

        Raises
        ------
        ValueError
            If the interaction type cannot be determined from the metadata.
        """
        raise NotImplementedError

    def to_descriptor(self) -> Property | Action | Event:
        """
        Convert the metadata back to a `Property`, `Action` or `Event` descriptor object.

        Returns
        -------
        Property | Action | Event
            The corresponding descriptor object of the interaction.

        Raises
        ------
        NotImplementedError
            If the method is not implemented in the subclass, or if the metadata cannot be converted to any of the descriptor objects.
        """
        raise NotImplementedError("to_descriptor() must be implemented in subclass of InteractionMetadata")

    @classmethod
    def register_descriptor(
        cls,
        descriptor: Property | Action | Event,
        metadata_generator: type[InteractionMetadata],
    ) -> None:
        """
        Register a custom metadata generator for a descriptor.

        Parameters
        ----------
        descriptor: Property | Action | Event
            The descriptor class
        metadata_generator: type[InteractionMetadata]
            `InteractionMetadata` subclass that implements the custom metadata generation logic for the descriptor.
            Either override the `from_descriptor()` method or the `build()` method.

        Raises
        ------
        TypeError
            If the descriptor is not an instance of `Property`, `Action` or `Event`, or if the metadata generator is not an
            instance of `InteractionMetadata`.
        """
        raise NotImplementedError

    def build_non_compliant_metadata(self) -> None:
        """If there is additional non standard metadata to be added, they can be added here."""
        pass

    def override_defaults(self, **kwargs):
        """
        Override default values with provided keyword arguments, especially thing_id, owner name, object name etc.

        Any logic to trigger side effects while setting those values should be handled here, either by
        reimplementing the method in the subclass or calling the super().override_defaults(**kwargs).
        """
        for key, value in kwargs.items():
            if key == "name":
                self._name = value
            elif key == "thing_id":
                self._thing_id = value
            elif key == "owner":
                self._owner = value
            elif key == "thing_cls":
                self._thing_cls = value
            elif hasattr(self, key) or key in self.model_fields:
                setattr(self, key, value)

    def __hash__(self):
        return hash(
            self.thing_id if self.thing_id else "" + self.thing_cls.__name__ if self.thing_cls else "" + self.name
        )

    def __str__(self):
        if self.thing_cls:
            return f"{self.__class__.__name__}({self.thing_cls.__name__}({self.thing_id}).{self.name})"
        return f"{self.__class__.__name__}({self.name} of {self.thing_id})"

    def __eq__(self, value):
        if not isinstance(value, self.__class__):
            return False
        if self.thing_id is None or value.thing_id is None:
            if self.owner is None or value.owner is None:
                # cannot determine anymore
                return False
            # basically you need to have an owner for the interaction affordance
            # and a name to determine its equality. We should never check the owner
            # by the name, but by the object, otherwise the equality cannot be gauranteed
            if (self.owner == value.owner or self.thing_cls == value.thing_cls) and self.name == value.name:
                return True
            return False
        return self.thing_id == value.thing_id and self.name == value.name

    def __deepcopy__(self, memo):  # ty: ignore[invalid-method-override]
        raise NotImplementedError("Implement in subclass")

    def __getstate__(self):
        state = self.__dict__.copy()
        # Remove possibly unpicklable entries
        if "_owner" in state:
            del state["_owner"]
        if "_thing_cls" in state:
            del state["_thing_cls"]
        if "_objekt" in state:
            del state["_objekt"]
        return state

    def json(self) -> dict[str, Any]:  # ty: ignore[invalid-method-override]
        """Return the JSON representation."""
        raise NotImplementedError("json() must be implemented in subclass of InteractionMetadata")

Functions

what

what() -> Enum

Whether it is a property, action or event.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
@property
def what(self) -> Enum:
    """Whether it is a property, action or event."""
    raise NotImplementedError("Unknown interaction (property, action, or event?), implement in subclass")

name

name() -> str

Name of the interaction that could be used as a key in the metadata.

Raises:

Type Description
AttributeError

If the metadata is not bound to any interaction object. This usually happens when the metadata is not generated from an interaction object, but created manually or from a different source. Use Thing<instance>.<property>.to_metadata() only to generate the metadata from a property object, and similarly for action and event.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
@property
def name(self) -> str:
    """
    Name of the interaction that could be used as a key in the metadata.

    Raises
    ------
    AttributeError
        If the metadata is not bound to any interaction object. This usually happens
        when the metadata is not generated from an interaction object, but created manually or from a
        different source. Use `Thing<instance>.<property>.to_metadata()` only to generate the metadata
        from a property object, and similarly for action and event.
    """
    if self._name is None:
        raise AttributeError("Metadata bound to unknown object (property, action or event).")
    return self._name

objekt

objekt() -> Property | Action | Event

Object instance of the interaction, instance of Property, Action or Event.

Raises:

Type Description
AttributeError

If the metadata is not bound to any interaction object. Use Thing<instance>.<property>.to_metadata() only method to generate this metadata from a property object or similarly for action and event.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
@property
def objekt(self) -> Property | Action | Event:
    """
    Object instance of the interaction, instance of `Property`, `Action` or `Event`.

    Raises
    ------
    AttributeError
        If the metadata is not bound to any interaction object.
        Use `Thing<instance>.<property>.to_metadata()` only method to generate this metadata
        from a property object or similarly for action and event.
    """
    if self._objekt is None:
        raise AttributeError("Metadata bound to unknown object (property, action or event).")
    return self._objekt

owner

owner() -> Thing

Owning Thing instance or Thing class of the interaction.

Depending on how this object was created, returns either an instance or a class.

Raises:

Type Description
AttributeError

If the owner is not set, which means this interaction is not properly bound to a Thing instance or class. Dont explicitly instantiate this class without the context of a Thing instance or class, or at least dont prematurely access this attribute.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
@property
def owner(self) -> Thing:
    """
    Owning `Thing` instance or `Thing` class of the interaction.

    Depending on how this object was created, returns either an instance or a class.

    Raises
    ------
    AttributeError
        If the owner is not set, which means this interaction is not properly bound to a `Thing`
        instance or class. Dont explicitly instantiate this class without the context of a `Thing` instance
        or class, or at least dont prematurely access this attribute.
    """
    if self._owner is None:
        raise AttributeError("owner is not set for this interaction")
    return self._owner

owner_cls

owner_cls() -> ThingMeta

Return the owning Thing class of the interaction.

Raises:

Type Description
AttributeError

If the owner is not set, which means this interaction is not properly bound to a Thing instance or class. Dont explicitly instantiate this class without the context of a Thing instance or class, or at least dont prematurely access this attribute.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
@property
def owner_cls(self) -> ThingMeta:
    """
    Return the owning `Thing` class of the interaction.

    Raises
    ------
    AttributeError
        If the owner is not set, which means this interaction is not properly bound to a `Thing`
        instance or class. Dont explicitly instantiate this class without the context of a `Thing` instance
        or class, or at least dont prematurely access this attribute.
    """
    if self._thing_cls is None:
        raise AttributeError("owner_cls is not set for this interaction")
    return self._thing_cls

thing_cls

thing_cls() -> ThingMeta

Thing class owning the interaction.

Raises:

Type Description
AttributeError

If the metadata is not bound to any Thing class. This usually happens when the metadata is not generated from a Thing class, but created manually or from a different source. Use thing.properties.descriptors[<property>].to_metadata() or Thing.properties.descriptors[<property>].to_metadata() only method to generate the metadata from a property object, and similarly for action and event. only method to generate the metadata from a property object, and similarly for action and event.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
@property
def thing_cls(self) -> ThingMeta:
    """
    `Thing` class owning the interaction.

    Raises
    ------
    AttributeError
        If the metadata is not bound to any `Thing` class. This usually happens
        when the metadata is not generated from a `Thing` class, but created manually or from a
        different source. Use `thing.properties.descriptors[<property>].to_metadata()` or `Thing.properties.descriptors[<property>].to_metadata()` only method to generate the metadata from a property object, and similarly for action and event.
        only method to generate the metadata from a property object, and similarly for action and event.
    """
    if self._thing_cls is None:
        raise AttributeError("Metadata bound to unknown Thing class (property, action or event's owner unknown).")
    return self._thing_cls

thing_id

thing_id() -> str

ID of the Thing instance owning the interaction, if available, otherwise None.

Raises:

Type Description
AttributeError

If the metadata is not bound to any Thing instance. This usually happens when the metadata is not generated from an interaction object, but created manually or from a different source. Use thing.properties.descriptors[<property>].to_metadata() only to generate the metadata from a property object, and similarly for an action and event.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
@property
def thing_id(self) -> str:
    """
    ID of the `Thing` instance owning the interaction, if available, otherwise None.

    Raises
    ------
    AttributeError
        If the metadata is not bound to any `Thing` instance. This usually happens
        when the metadata is not generated from an interaction object, but created manually or from a
        different source. Use `thing.properties.descriptors[<property>].to_metadata()`
        only to generate the metadata from a property object, and similarly for an action and event.
    """
    if self._thing_id is None:
        raise AttributeError("Metadata bound to unknown Thing (property, action or event's owner unknown).")
    return self._thing_id

build

build() -> None

Populate the fields of the metadata for the specific interaction.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
def build(self) -> None:
    """Populate the fields of the metadata for the specific interaction."""
    raise NotImplementedError("build must be implemented in subclass of InteractionMetadata")

build_non_compliant_metadata

build_non_compliant_metadata() -> None

If there is additional non standard metadata to be added, they can be added here.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
def build_non_compliant_metadata(self) -> None:
    """If there is additional non standard metadata to be added, they can be added here."""
    pass

from_descriptor classmethod

from_descriptor(interaction: Property | Action | Event, owner: Thing | ThingMeta) -> Self

Instantitate and build the metadata for the specific interaction.

Use the json() method to get the JSON representation of the metadata.

Note that this method is different from build() method as its supposed to be used as a classmethod to create an instance. Although, it internally calls build(), and some additional steps can be included.

Parameters:

Name Type Description Default
interaction
Property | Action | Event

interaction object for which the metadata is to be built

required
owner
Thing | ThingMeta

owner of the interaction

required

Returns:

Type Description
PropertyMetadata | ActionMetadata | EventMetadata

Instance of this class with the metadata fields populated.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
@classmethod
def from_descriptor(
    cls,
    interaction: Property | Action | Event,
    owner: Thing | ThingMeta,
) -> Self:
    """
    Instantitate and build the metadata for the specific interaction.

    Use the `json()` method to get the JSON representation of the metadata.

    Note that this method is different from `build()` method as its supposed to be used as a classmethod
    to create an instance. Although, it internally calls `build()`, and some additional steps can be included.

    Parameters
    ----------
    interaction: Property | Action | Event
        interaction object for which the metadata is to be built
    owner: Thing | ThingMeta
        owner of the interaction

    Returns
    -------
    PropertyMetadata | ActionMetadata | EventMetadata
        Instance of this class with the metadata fields populated.
    """
    raise NotImplementedError("from_descriptor() must be implemented in subclass of InteractionMetadata")

to_descriptor

to_descriptor() -> Property | Action | Event

Convert the metadata back to a Property, Action or Event descriptor object.

Returns:

Type Description
Property | Action | Event

The corresponding descriptor object of the interaction.

Raises:

Type Description
NotImplementedError

If the method is not implemented in the subclass, or if the metadata cannot be converted to any of the descriptor objects.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
def to_descriptor(self) -> Property | Action | Event:
    """
    Convert the metadata back to a `Property`, `Action` or `Event` descriptor object.

    Returns
    -------
    Property | Action | Event
        The corresponding descriptor object of the interaction.

    Raises
    ------
    NotImplementedError
        If the method is not implemented in the subclass, or if the metadata cannot be converted to any of the descriptor objects.
    """
    raise NotImplementedError("to_descriptor() must be implemented in subclass of InteractionMetadata")

from_metadata classmethod

from_metadata(name: str, metadata: dict[str, Any]) -> Self

Populate the metadata from the provided JSON and return it as an instance of this class.

It is assumed that the interaction is a key in the provided JSON, so one needs to supply the name.

Parameters:

Name Type Description Default
name
str

name of the interaction used as key in the metadata

required
metadata
dict[str, Any]

metadata JSON dictionary (the entire one, not just the component of the interaction)

required

Returns:

Type Description
Self

Instance of this class.

Raises:

Type Description
ValueError

If the interaction type cannot be determined from the metadata.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
@classmethod
def from_metadata(cls, name: str, metadata: dict[str, Any]) -> Self:
    """
    Populate the metadata from the provided JSON and return it as an instance of this class.

    It is assumed that the interaction is a key in the provided JSON, so one needs to supply the name.

    Parameters
    ----------
    name: str
        name of the interaction used as key in the metadata
    metadata: JSON
        metadata JSON dictionary (the entire one, not just the component of the interaction)

    Returns
    -------
    Self
        Instance of this class.

    Raises
    ------
    ValueError
        If the interaction type cannot be determined from the metadata.
    """
    raise NotImplementedError

override_defaults

override_defaults(**kwargs)

Override default values with provided keyword arguments, especially thing_id, owner name, object name etc.

Any logic to trigger side effects while setting those values should be handled here, either by reimplementing the method in the subclass or calling the super().override_defaults(**kwargs).

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
def override_defaults(self, **kwargs):
    """
    Override default values with provided keyword arguments, especially thing_id, owner name, object name etc.

    Any logic to trigger side effects while setting those values should be handled here, either by
    reimplementing the method in the subclass or calling the super().override_defaults(**kwargs).
    """
    for key, value in kwargs.items():
        if key == "name":
            self._name = value
        elif key == "thing_id":
            self._thing_id = value
        elif key == "owner":
            self._owner = value
        elif key == "thing_cls":
            self._thing_cls = value
        elif hasattr(self, key) or key in self.model_fields:
            setattr(self, key, value)

register_descriptor classmethod

register_descriptor(descriptor: Property | Action | Event, metadata_generator: type[InteractionMetadata]) -> None

Register a custom metadata generator for a descriptor.

Parameters:

Name Type Description Default
descriptor
Property | Action | Event

The descriptor class

required
metadata_generator
type[InteractionMetadata]

InteractionMetadata subclass that implements the custom metadata generation logic for the descriptor. Either override the from_descriptor() method or the build() method.

required

Raises:

Type Description
TypeError

If the descriptor is not an instance of Property, Action or Event, or if the metadata generator is not an instance of InteractionMetadata.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
@classmethod
def register_descriptor(
    cls,
    descriptor: Property | Action | Event,
    metadata_generator: type[InteractionMetadata],
) -> None:
    """
    Register a custom metadata generator for a descriptor.

    Parameters
    ----------
    descriptor: Property | Action | Event
        The descriptor class
    metadata_generator: type[InteractionMetadata]
        `InteractionMetadata` subclass that implements the custom metadata generation logic for the descriptor.
        Either override the `from_descriptor()` method or the `build()` method.

    Raises
    ------
    TypeError
        If the descriptor is not an instance of `Property`, `Action` or `Event`, or if the metadata generator is not an
        instance of `InteractionMetadata`.
    """
    raise NotImplementedError

json

json() -> dict[str, Any]

Return the JSON representation.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
def json(self) -> dict[str, Any]:  # ty: ignore[invalid-method-override]
    """Return the JSON representation."""
    raise NotImplementedError("json() must be implemented in subclass of InteractionMetadata")

hololinked.core.interfaces.metadata.PropertyMetadata

Bases: InteractionMetadata

Generate property metadata from Property descriptor object.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
class PropertyMetadata(InteractionMetadata):
    """Generate property metadata from `Property` descriptor object."""

    @property
    def what(self) -> Enum:  # noqa: D102
        return ResourceTypes.PROPERTY

    @classmethod
    def from_descriptor(cls, property: Property, owner: Thing | ThingMeta) -> PropertyMetadata:  # noqa: D102 # ty: ignore[invalid-method-override]
        raise NotImplementedError

hololinked.core.interfaces.metadata.ActionMetadata

Bases: InteractionMetadata

Generate action metadata from Action descriptor object.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
class ActionMetadata(InteractionMetadata):
    """Generate action metadata from `Action` descriptor object."""

    @property
    def what(self) -> Enum:  # noqa: D102
        return ResourceTypes.ACTION

    @classmethod
    def from_descriptor(cls, action: Action, owner: Thing | ThingMeta) -> ActionMetadata:  # noqa: D102 # ty: ignore[invalid-method-override]
        raise NotImplementedError

hololinked.core.interfaces.metadata.EventMetadata

Bases: InteractionMetadata

Generate event metadata from Event descriptor object.

Source code in repo/hololinked/hololinked/core/interfaces/metadata.py
class EventMetadata(InteractionMetadata):
    """Generate event metadata from `Event` descriptor object."""

    @property
    def what(self) -> Enum:  # noqa: D102
        return ResourceTypes.EVENT

    @classmethod
    def from_descriptor(cls, event: Event, owner: Thing | ThingMeta) -> EventMetadata:  # noqa: D102 # ty: ignore[invalid-method-override]
        raise NotImplementedError