Source code for yaml_provenance._list

"""
ListWithProvenance — a list subclass with provenance tracking.
"""

import copy

from ._config import get_config
from ._provenance import Provenance
from ._wrapper import wrapper_with_provenance_factory


[docs] class ListWithProvenance(list): """ A list subclass that tracks provenance for all nested values. Parameters ---------- mylist : list The list to wrap with provenance. provenance : list Provenance data with matching structure to ``mylist``. config : ProvenanceConfig or None Configuration. If ``None``, uses the module-level default. """ def __init__(self, mylist, provenance, config=None): super().__init__(mylist) self._config = config or get_config() self.custom_setitem = False self.put_provenance(provenance) self.custom_setitem = True
[docs] def put_provenance(self, provenance): """ Recursively transforms every element into its WithProvenance object with corresponding provenance (1-to-1 mapping). Parameters ---------- provenance : list Provenance list with same length as ``self``. """ from ._dict import DictWithProvenance if not provenance: provenance = [{}] * len(self) for c, elem in enumerate(self): if isinstance(elem, dict): self[c] = DictWithProvenance(elem, provenance[c], config=self._config) elif isinstance(elem, list): self[c] = ListWithProvenance(elem, provenance[c], config=self._config) elif hasattr(elem, "provenance"): self[c].provenance.extend(provenance[c]) else: self[c] = wrapper_with_provenance_factory(elem, provenance[c])
[docs] def set_provenance(self, provenance): """ Recursively sets the same ``provenance`` on all nested elements. Parameters ---------- provenance : any New provenance value to set. """ from ._dict import DictWithProvenance if not isinstance(provenance, list): provenance = [provenance] for c, elem in enumerate(self): if isinstance(elem, dict): self[c] = DictWithProvenance(elem, {}, config=self._config) self[c].set_provenance(provenance) elif isinstance(elem, list): self[c] = ListWithProvenance(elem, [], config=self._config) self[c].set_provenance(provenance) elif hasattr(elem, "provenance"): self[c].provenance.extend(provenance) else: self[c] = wrapper_with_provenance_factory(elem, provenance)
[docs] def get_provenance(self, index=-1): """ Returns a list of provenance information with matching structure. Parameters ---------- index : int Index into the provenance history. Default: ``-1`` (last/current). Returns ------- list Provenance list. """ from ._dict import DictWithProvenance PROVENANCE_MAPPINGS = (DictWithProvenance, ListWithProvenance) provenance_list = [] for elem in self: if isinstance(elem, PROVENANCE_MAPPINGS): provenance_list.append(elem.get_provenance(index=index)) elif hasattr(elem, "provenance"): provenance_list.append(elem.provenance[index]) else: provenance_list.append(None) return provenance_list
def __setitem__(self, indx, val): """ Extended ``__setitem__`` that preserves provenance history. """ val_new = val config = self._config if ( indx in self and not isinstance(self[indx], (dict, list)) and hasattr(self[indx], "provenance") and hasattr(self, "custom_setitem") and self.custom_setitem ): new_provenance = self[indx].provenance if hasattr(val, "provenance"): new_provenance.extend_and_modified_by( val.provenance, "dict.__setitem__" ) if config.track_history: val_new = copy.deepcopy(val) else: val_new = val val_new.provenance = new_provenance super().__setitem__(indx, val_new)
[docs] def super_setitem(self, indx, val): """ Call the original ``list.__setitem__`` without provenance tracking. """ super().__setitem__(indx, val)