-- -- --- --- --- --- --- --- ------- ------- ------- |
"""
-- -- --- --- --- --- --- --- ------- ------- ------- |
For managing the state of the wily process.
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
Contains a lazy revision, index and process state model.
-- -- --- --- --- --- --- --- ------- ------- ------- |
"""
-- -- --- --- --- --- --- --- ------- ------- ------- |
from collections import OrderedDict
-- -- --- --- --- --- --- --- ------- ------- ------- |
from dataclasses import dataclass, asdict
-- -- --- --- --- --- --- --- ------- ------- ------- |
from typing import List
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
import wily.cache as cache
-- -- --- --- --- --- --- --- ------- ------- ------- |
from wily import logger
-- -- --- --- --- --- --- --- ------- ------- ------- |
from wily.archivers import Revision, resolve_archiver
-- -- --- --- --- --- --- --- ------- ------- ------- |
from wily.operators import get_metric
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
@dataclass
02 -- --- --- --- --- --- --- ------- ------- ------- |
class IndexedRevision(object):
02 -- --- --- --- --- --- --- ------- ------- ------- |
"""Union of revision and the operators executed."""
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- |
revision: Revision
02 -- --- --- --- --- --- --- ------- ------- ------- |
operators: List
02 -- --- --- --- --- --- --- ------- ------- ------- |
_data = None
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- |
@staticmethod
02 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
def fromdict(d):
02 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
"""Instantiate from a dictionary."""
02 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
rev = Revision(
02 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
key=d["key"],
02 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
author_name=d["author_name"],
02 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
author_email=d["author_email"],
02 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
date=d["date"],
02 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
message=d["message"],
02 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
files=d["files"] if "files" in d else [],
02 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
)
02 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
operators = d["operators"]
02 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
return IndexedRevision(revision=rev, operators=operators)
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def asdict(self):
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""Convert to dictionary."""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
d = asdict(self.revision)
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
d["operators"] = self.operators
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return d
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
def get(self, config, archiver, operator, path, key):
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
"""
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
Get the metric data for this indexed revision.
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:param config: The wily config.
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:type config: :class:`wily.config.WilyConfig`
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:param archiver: The archiver.
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:type archiver: :class:`wily.archivers.Archiver`
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:param operator: The operator to find
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:type operator: ``str``
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:param path: The path to find
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:type path: ``str``
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:param key: The metric key
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
:type key: ``str``
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
"""
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
if not self._data:
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
self._data = cache.get(
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
config=config, archiver=archiver, revision=self.revision.key
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
)["operator_data"]
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
logger.debug(f"Fetching metric {path} - {key} for operator {operator}")
02 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
return get_metric(self._data, operator, path, key)
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def store(self, config, archiver, stats):
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
Store the stats for this indexed revision.
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param config: The wily config.
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:type config: :class:`wily.config.WilyConfig`
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param archiver: The archiver.
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:type archiver: :class:`wily.archivers.Archiver`
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param stats: The data
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:type stats: ``dict``
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self._data = stats
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return cache.store(config, archiver, self.revision, stats)
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- |
class Index(object):
02 -- --- --- --- --- --- --- ------- ------- ------- |
"""The index of the wily cache."""
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- |
operators = None
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def __init__(self, config, archiver):
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
Instantiate a new index.
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param config: The wily config.
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:type config: :class:`wily.config.WilyConfig`
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param archiver: The archiver.
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:type archiver: :class:`wily.archivers.Archiver`
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.config = config
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.archiver = archiver
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.data = (
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
cache.get_archiver_index(config, archiver.name)
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
if cache.has_archiver_index(config, archiver.name)
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
else []
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
)
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self._revisions = OrderedDict(
02 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
{d["key"]: IndexedRevision.fromdict(d) for d in self.data}
02 -- 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
)
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def __len__(self):
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""Use length of revisions as len."""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return len(self._revisions)
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- |
@property
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def last_revision(self):
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
Return the most recent revision.
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:rtype: ``list`` of :class:`LazyRevision`
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return next(iter(self._revisions.values()))
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- |
@property
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def revisions(self):
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
List of all the revisions.
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:rtype: ``list`` of :class:`LazyRevision`
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return list(self._revisions.values())
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- |
@property
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def revision_keys(self):
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
List of all the revision indexes.
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:rtype: ``list`` of ``str``
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return list(self._revisions.keys())
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
def __contains__(self, item):
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
"""
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
Check if index contains `item`.
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
:param item: The item to search for
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
:type item: ``str``, :class:`Revision` or :class:`LazyRevision`
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
:return: ``True`` for contains, ``False`` for not.
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
"""
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
if isinstance(item, Revision):
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
return item.key in self._revisions
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
elif isinstance(item, str):
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
return item in self._revisions
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
else:
02 03 001 003 002 004 004 006 0012.00 0008.00 0000.67 |
raise TypeError("Invalid type for __contains__ in Index.")
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def __getitem__(self, index):
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""Get the revision for a specific index."""
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return self._revisions[index]
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def add(self, revision, operators):
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
Add a revision to the index.
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param revision: The revision.
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:type revision: :class:`Revision` or :class:`LazyRevision`
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
ir = IndexedRevision(
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
revision=revision, operators=[operator.name for operator in operators]
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
)
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self._revisions[revision.key] = ir
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
return ir
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def save(self):
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""Save the index data back to the wily cache."""
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
data = [i.asdict() for i in self._revisions.values()]
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
logger.debug("Saving data")
02 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
cache.store_archiver_index(self.config, self.archiver, data)
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
04 -- --- --- --- --- --- --- ------- ------- ------- |
class State(object):
04 -- --- --- --- --- --- --- ------- ------- ------- |
"""
04 -- --- --- --- --- --- --- ------- ------- ------- |
The wily process state.
04 -- --- --- --- --- --- --- ------- ------- ------- |
04 -- --- --- --- --- --- --- ------- ------- ------- |
Includes indexes for each archiver.
04 -- --- --- --- --- --- --- ------- ------- ------- |
"""
04 -- --- --- --- --- --- --- ------- ------- ------- |
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
def __init__(self, config, archiver=None):
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
Instantiate a new process state.
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param config: The wily configuration.
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:type config: :class:`WilyConfig`
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:param archiver: The archiver (optional).
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
:type archiver: :class:`wily.archivers.Archiver`
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
"""
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
if archiver:
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.archivers = [archiver.name]
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
else:
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.archivers = cache.list_archivers(config)
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
logger.debug(f"Initialised state indexes for archivers {self.archivers}")
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.config = config
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.index = {}
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
for archiver in self.archivers:
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.index[archiver] = Index(self.config, resolve_archiver(archiver))
04 03 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
self.default_archiver = self.archivers[0]
04 -- --- --- --- --- --- --- ------- ------- ------- |
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
def ensure_exists(self):
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
"""Ensure that cache directory exists."""
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
if not cache.exists(self.config):
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
logger.debug("Wily cache not found, creating.")
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
cache.create(self.config)
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
logger.debug("Created wily cache")
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
else:
04 02 001 001 001 001 002 002 0002.00 0001.00 0000.50 |
logger.debug(f"Cache {self.config.cache_path} exists")