Source code for ipfx.attach_metadata.sink.metadata_sink
"""Base class for metadata sinks, which serve as a staging ground for metadata
attachment.
"""
import abc
import collections
from typing import (
TypeVar, Union, Collection, List, Dict, Any, Set, Optional
)
TV = TypeVar("TV")
OneOrMany = Union[TV, Collection[TV]]
[docs]class MetadataSink(abc.ABC):
""" Abstract(ish) interface for metadata sinks.
"""
@abc.abstractproperty
def targets(self) -> List[Dict[str, Any]]:
""" A sequence of preregistered targets. Calling serialize with no
arguments will write to these.
"""
@abc.abstractproperty
def supported_cell_fields(self) -> Set[str]:
""" The names of each cell-level field supported by this sink.
"""
@abc.abstractproperty
def supported_sweep_fields(self) -> Set[str]:
""" The names of each sweep-level field supported by this sink.
"""
[docs] @abc.abstractmethod
def serialize(self, targets: Optional[OneOrMany[Dict[str, Any]]] = None):
""" Writes this sink's data to an external target or targets. Does not
modify this sink.
Parameters
----------
targets : If provided, these targets will be written to. Otherwise,
write to targets previously defined by register_target.
"""
[docs] @abc.abstractmethod
def register(self, name: str, value: Any, sweep_id: Optional[int] = None):
""" Attaches a named piece of metadata to this sink's internal store.
Should dispatch to a protected method which carries out appropriate
validations and transformations.
Parameters
----------
name : the well-known name of the metadata
value : the value of the metadata (before any required transformations)
sweep_id : If provided, this will be interpreted as sweep-level
metadata and sweep_id will be used to identify the sweep to which
value ought to be attached. If None, this will be interpreted as
cell-level metadata
Raises
------
ValueError : An argued piece of metadata is not supported by this sink
"""
[docs] def register_targets(self, targets: OneOrMany[Dict[str, Any]]):
""" Configures targets for this sink. Calls to serialize (without
new targets supplied) will write to these targets.
Parameters
----------
targets : Configure these targets. Each should be a dictionary which
passes this class's validate_target method
"""
if targets is None:
raise ValueError("must argue targets")
targets = self._ensure_plural_targets(targets)
for target in targets:
self.register_target(target)
[docs] def register_target(self, target: Dict[str, Any]):
"""Preregister a single target specification on this sink.
Parameters
----------
target : Must provide parameters required for serialization
"""
self.targets.append(target)
def _ensure_plural_targets(
self,
targets: Optional[OneOrMany[Dict[str, Any]]] = None
) -> List[Dict[str, Any]]:
"""Convenience for getting a list of targets. Used in register_targets.
Parameters
----------
targets :
if None: use this objects targets attribute
if a single dict: wrap it in a list
if a sequence: convert it to a list
Returns
-------
a list of target dictionaries
"""
if targets is None:
targets = self.targets
elif isinstance(targets, dict):
targets = [targets]
elif isinstance(targets, collections.Sequence):
targets = list(targets)
else:
raise ValueError(
f"unable to serialize to targets of type {type(targets)}"
)
return targets