Source code for yaflux._base
import os
import pickle
from typing import Any, Optional
from yaflux._results._lock import ResultsLock
from ._metadata import Metadata
from ._results import Results
[docs]
class Base:
"""Base class for analysis pipelines.
This class provides a framework for defining and executing analysis pipelines.
Parameters
----------
parameters : Parameters
The parameters for the analysis.
Attributes
----------
results : Results
The current analysis results.
available_steps : list[str]
List all available steps for the analysis.
completed_steps : list[str]
List all completed steps for the analysis.
"""
def __init__(self, parameters: Optional[Any] = None):
with ResultsLock.allow_mutation(): # Unlock during initialization
self._results = Results()
self._completed_steps = set()
self._step_ordering = [] # Hidden attribute to store the order of performed steps
self.parameters = parameters
@property
def results(self) -> Results:
"""Get the current analysis results."""
return self._results
@property
def available_steps(self) -> list[str]:
"""List all available steps for the analysis."""
steps = []
for cls in self.__class__.__mro__:
for name, method in vars(cls).items():
if hasattr(method, "creates") and name not in steps:
steps.append(name)
return steps
@property
def completed_steps(self) -> list[str]:
"""List all completed steps for the analysis."""
return list(self._completed_steps)
[docs]
def get_step_info(self, step_name: str) -> dict:
"""Get information about a specific analysis step."""
method = getattr(self.__class__, step_name)
if not method or not hasattr(method, "creates"):
raise ValueError(f"No such analysis step: '{step_name}'")
return {
"name": step_name,
"creates": method.creates,
"requires": method.requires,
"completed": step_name in self._completed_steps,
}
[docs]
def get_step_results(self, step_name: str) -> Any:
"""Get the results for a specific analysis step."""
if step_name not in self._completed_steps:
raise ValueError(f"Step '{step_name}' has not been completed")
return self._results.get_step_results(step_name)
[docs]
def save(self, filepath: str, force=False):
"""Save the `Analysis` object to a file using pickle."""
if not force and os.path.exists(filepath):
raise FileExistsError(f"File already exists: '{filepath}'")
with open(filepath, "wb") as file:
pickle.dump(self, file)
[docs]
@classmethod
def load(cls, filepath: str):
"""Load an `Analysis` object from a file using pickle."""
with ResultsLock.allow_mutation():
with open(filepath, "rb") as file:
analysis = pickle.load(file)
return analysis
def visualize_dependencies(self, *args, **kwargs):
"""Create a visualization of step dependencies.
This is a stub that will be replaced with the actual visualization
if graphviz is installed. Install with:
```bash
pip install yaflux[viz]
```
Raises:
ImportError: If graphviz is not installed.
"""
raise ImportError(
"graphviz package is required for visualization. "
"Install with: pip install yaflux[viz]"
)
try:
from ._viz import _check_graphviz, visualize_dependencies
if _check_graphviz():
Base.visualize_dependencies = visualize_dependencies
except ImportError:
pass # Keep the stub method