Advanced Usage#
Analysis Inheritance#
One of yaflux
’s powerful features is its natural support for Python class inheritance. This allows you to:
Build complex analyses by extending simpler ones
Override and customize base analysis steps
Create reusable analysis templates
Share common functionality across multiple analyses
Basic Inheritance#
Let’s look at a simple example of analysis inheritance:
import yaflux as yf
class SimpleAnalysis(yf.Base):
"""A basic analysis pipeline."""
@yf.step(creates="data")
def load_data(self):
return [i for i in range(100)]
@yf.step(creates="proc_a", requires="data")
def process_a(self):
return [i * 2 for i in self.results.data]
@yf.step(creates="proc_b", requires="proc_a")
def process_b(self):
return [i + 1 for i in self.results.proc_a]
class ExtendedAnalysis(SimpleAnalysis):
"""An extended analysis that builds on SimpleAnalysis."""
def __init__(self):
super().__init__()
@yf.step(creates="proc_c", requires=["proc_a", "proc_b"])
def process_c(self):
return [a + b for a, b in zip(self.results.proc_a, self.results.proc_b)]
# Create and use the extended analysis
analysis = ExtendedAnalysis()
analysis.load_data() # Inherited from SimpleAnalysis
analysis.process_a() # Inherited from SimpleAnalysis
analysis.process_b() # Inherited from SimpleAnalysis
analysis.process_c() # Defined in ExtendedAnalysis
Inheritance Features#
Access to Parent Steps#
When you inherit from an analysis class, you get access to all of its steps. These steps:
Maintain their original dependencies
Can be called directly from the child class
Are tracked in the child’s completed_steps
Appear in the child’s available_steps
Step Dependencies#
Dependencies work seamlessly across inheritance boundaries:
class AdvancedAnalysis(SimpleAnalysis):
@yf.step(creates="advanced_result", requires=["proc_a", "proc_b"])
def advanced_step(self):
# Can use results from parent class steps
return [a * b for a, b in zip(
self.results.proc_a,
self.results.proc_b
)]
Method Overriding#
You can override parent steps to customize their behavior:
class CustomAnalysis(SimpleAnalysis):
@yf.step(creates="data") # Same creates/requires as parent
def load_data(self):
# Custom implementation
return [i * 10 for i in range(100)]
Multi-level Inheritance#
yaflux
supports Python’s standard multiple inheritance:
class BaseAnalysis(yf.Base):
@yf.step(creates="base_data")
def load_base(self): ...
class MixinAnalysis(yf.Base):
@yf.step(creates="mixin_data")
def load_mixin(self): ...
class ComplexAnalysis(BaseAnalysis, MixinAnalysis):
@yf.step(creates="final", requires=["base_data", "mixin_data"])
def process_all(self): ...
Visualization Support#
The visualize_dependencies()
method shows the complete dependency graph, including:
Steps from all parent classes
Dependencies between inherited steps
Custom steps in the child class
Cross-inheritance dependencies
Best Practices#
When using inheritance with yaflux
:
Clear Dependencies: Always explicitly declare dependencies using
requires
, even if they come from parent classesConsistent Naming: Use clear, consistent names for results to avoid conflicts between parent and child classes
Documentation: Document dependencies on parent class steps in your docstrings:
@yf.step(creates="final", requires=["base_data"]) def final_step(self): """Process the final result. Requires parent class's load_base_data() to be run first. """ ...
Modular Design: Design base classes to be independently useful while allowing for extension