Source code for pyvo.mivot.writer.instance

# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""
MivotInstance is a simple API for building MIVOT instances step by step.

A MIVOT instance is a MIVOT serialisation of an object whose attributes are set
with column values or literals.
A MIVOT instance can contain ATTRIBUTEs elements, COLLECTIONs of elements, or other INSTANCEs.
The MIVOT INSTANCE structure is defined by the data model on which the data is mapped.
"""

from pyvo.utils.prototype import prototype_feature
from pyvo.mivot.utils.exceptions import MappingError
from pyvo.mivot.utils.mivot_utils import MivotUtils

__all__ = ["MivotInstance"]


[docs] @prototype_feature("MIVOT") class MivotInstance: """ API for building <INSTANCE> elements of MIVOT annotation step by step. This class provides methods for incremental construction of a MIVOT instance. It builds <INSTANCE> elements that can contain <ATTRIBUTE>, <INSTANCE>, and <REFERENCE>. Support for <COLLECTION> elements is not yet implemented. The main features are: - Model-agnostic: The implementation is independent of any specific data model. - Syntax validation: Ensures basic MIVOT syntax rules are followed. - Context-agnostic: Ignores context-dependent syntax rules. attributes ---------- _dmtype : string Instance type (class VO-DML ID) _dmrole : string Role played by the instance in the context where it is used (given by the VO-DML serialization of the model) _dmid : string Free identifier of the instance """ def __init__(self, dmtype, *, dmrole=None, dmid=None): """ Parameters ---------- dmtype : str dmtype of the INSTANCE (mandatory) dmrole : str, optional dmrole of the INSTANCE dmid : str, optional dmid of the INSTANCE Raises ------ MappingError If ``dmtype`` is not provided """ if not dmtype: raise MappingError("Cannot build an instance without dmtype") self._dmtype = dmtype self._dmrole = dmrole self._dmid = MivotUtils.format_dmid(dmid) self._content = [] @property def dmid(self): return self._dmid
[docs] def add_attribute(self, dmtype=None, dmrole=None, *, value=None, unit=None): """ Add an <ATTRIBUTE> element to the instance. Parameters ---------- dmtype : str dmtype of the ATTRIBUTE (mandatory) dmrole : str dmrole of the ATTRIBUTE (mandatory) value : str or numerical, optional ID of the column to set the attribute value. If ref is a string starting with a * or is numerical, it is considered as a value (* stripped) as a ref otherwise unit : str, optional Unit of the attribute Raises ------ MappingError If ``dmtype`` or ``dmrole`` is not provided, or if both ``ref`` and ``value`` are not defined """ if not dmtype: raise MappingError("Cannot add an attribute without dmtype") if not dmrole: raise MappingError("Cannot add an attribute without dmrole") ref, literal = MivotUtils.get_ref_or_literal(value) if not ref and not value: raise MappingError("Cannot add an attribute without ref or value") xml_string = f'<ATTRIBUTE dmtype="{dmtype}" dmrole="{dmrole}" ' if unit and unit != "None": xml_string += f'unit="{unit}" ' if literal: xml_string += f'value="{literal}" ' else: xml_string += f'ref="{ref}" ' xml_string += " />" self._content.append(xml_string)
[docs] def add_reference(self, dmrole=None, dmref=None): """ Add a <REFERENCE> element to the instance. Parameters ---------- dmrole : str dmrole of the REFERENCE (mandatory) dmref : str dmref of the REFERENCE (mandatory) Raises ------ MappingError If ``dmrole`` or ``dmref`` is not provided """ if not dmref: raise MappingError("Cannot add a reference without dmref") if not dmrole: raise MappingError("Cannot add a reference without dmrole") xml_string = f'<REFERENCE dmrole="{dmrole}" dmref="{dmref}" />' self._content.append(xml_string)
[docs] def add_instance(self, mivot_instance): """ Add a nested <INSTANCE> element to the instance. Parameters ---------- mivot_instance : MivotInstance INSTANCE to be added Raises ------ MappingError If ``mivot_instance`` is not of type ``MivotInstance`` """ if not isinstance(mivot_instance, MivotInstance): raise MappingError("Instance added must be of type MivotInstance") self._content.append(mivot_instance.xml_string())
[docs] def add_collection(self, dmrole, mivot_instances): """ to be documented """ dm_att = "" if dmrole: dm_att = f"dmrole=\"{dmrole}\"" self._content.append(f'<COLLECTION {dm_att}>') for mivot_instance in mivot_instances: if isinstance(mivot_instance, MivotInstance): self._content.append(mivot_instance.xml_string()) else: self._content.append(mivot_instance) self._content.append("\n") self._content.append("</COLLECTION>")
[docs] def xml_string(self): """ Build and serialize the <INSTANCE> element as a string. Returns ------- str The string representation of the <INSTANCE> element """ xml_string = f'<INSTANCE dmtype="{self._dmtype}" ' if self._dmrole: xml_string += f'dmrole="{self._dmrole}" ' if self._dmid: xml_string += f'dmid="{self._dmid}" ' xml_string += ">\n" for element in self._content: xml_string += " " + element + "\n" xml_string += "</INSTANCE>\n" return xml_string