Source code for ymp.stage.base
import logging
import os
from typing import Set, Dict, Union, List
log = logging.getLogger(__name__) # pylint: disable=invalid-name
[docs]class BaseStage(object):
"""Base class for stage types"""
#: The name of the stamp file that is touched to indicate
#: completion of the stage.
STAMP_FILENAME = "all_targets.stamp"
def __init__(self, name: str) -> None:
#: The name of the stage is a string uniquely identifying it
#: among all stages.
self.name = name
#: The docstring describing this stage. Visible via ``ymp
#:stage list`` and in the generated sphinx documentation.
self.docstring: str = None
def __str__(self) -> str:
"""Cast to string we just emit our name"""
return self.name
def __repr__(self):
"""Using `repr()` we emit the subclass as well as our name"""
return f"{self.__class__.__name__}({self!s})"
[docs] def doc(self, doc: str) -> None:
"""Add documentation to Stage
Args:
doc: Docstring passed to Sphinx
"""
#: Docstring describing stage
self.docstring = doc
[docs] def match(self, name: str) -> bool:
"""Check if the ``name`` can refer to this stage
As component of a `StageStack`, a stage may be identified by
alternative names and may also be parametrized by suffix
modifiers. Stage types supporting this behavior must override
this function.
"""
return name == self.name
@property
def outputs(self) -> Union[Set[str], Dict[str, str]]:
"""Returns the set of outputs this stage is able to generate.
May return either a `set` or a `dict` with the dictionary
values representing redirections in the case of virtual stages
such as `Pipeline` or `Reference`.
"""
return set()
[docs] def can_provide(self, inputs: Set[str]) -> Dict[str, str]:
"""Determines which of ``inputs`` this stage can provide.
Returns a dictionary with the keys a subset of ``inputs`` and
the values identifying redirections. An empty string indicates
that no redirection is to take place. Otherwise, the string is
the suffix to be appended to the prior `StageStack`.
"""
return {
output: ""
for output in inputs.intersection(self.outputs)
}
[docs] def get_path(self, stack: "StageStack") -> str:
"""On disk location for this stage given ``stack``.
Called by `StageStack` to determine the real path for
virtual stages (which must override this function).
"""
return stack.name
[docs] def get_all_targets(self, stack: "StageStack") -> List[str]:
"""Targets to build to complete this stage given ``stack``.
Typically, this is the StageStack's path appended with the
stamp name.
"""
return [os.path.join(stack.path, self.STAMP_FILENAME)]
[docs]class ConfigStage(BaseStage):
"""Base for stages created via configuration
These Stages derive from the ``yml.yml`` and not from a rules file.
"""
def __init__(self, name: str, cfg: 'MultiProxy'):
#: Semi-colon separated list of file names defining this Stage.
self.filename = ';'.join(cfg.get_files())
#: Line number within the first file at which this Stage is defined.
self.lineno = next(iter(cfg.get_linenos()), None)
super().__init__(name)
#: The configuration object defining this Stage.
self.cfg = cfg
@property
def defined_in(self):
"""List of files defining this stage
Used to invalidate caches.
"""
return self.cfg.get_files()