Source code for langtree.operators.base_operators

import copy

from langtree.core.operator import Operator

"""
    Before someone asks why these operators do not inherit from Operator, the answer is twofold:
        1) Explicitly different classes are nice for the conditional blocks
        2) Implementing the freezing present in Operator is not a great idea on a vector OP (way too much mental overhead for a developer, i.e. me)
"""


[docs]def chainable(func): """Decorator that makes a function chainable with its arguments. Args: func (callable): The function to make chainable. Returns: callable: The chainable function. """ def wrapper(*args, **kws): op = Operator(func) op.freeze_call(**kws) return op return wrapper
[docs]class Parallel: def __init__(self, operations): self.operations = [] for operation in operations: self.add(operation)
[docs] def __iadd__(self, other): return self.add(other)
[docs] def __add__(self, other): operations = self.operations if isinstance(other, Sequential): return Parallel(operations + [other]) elif isinstance(other, Parallel): return Parallel(self.operations + other.operations) elif isinstance(other, Operator): return Parallel(operations + [other]) else: raise ValueError( f"{type(other)} is not usable with type:{type(self)}. This class can only add Operators (SequentialOperator, ParallelOperator, Operator)")
[docs] def add(self, other): if isinstance(other, Sequential): self.operations.append(other) elif isinstance(other, Parallel): self.operations.extend(other.operations) elif isinstance(other, Operator): self.operations.append(other) else: raise ValueError( f"{type(other)} is not usable with type:{type(self)}. This class can only add Operators (SequentialOperator, ParallelOperator, Operator)") return self
[docs] def __call__(self, *args, **kwargs): output = [] for operation in self.operations: output.append(operation(*copy.deepcopy(args), **copy.deepcopy(kwargs))) return output
[docs]class Sequential: def __init__(self, operations): self.operations = [] for operation in operations: self.add(operation)
[docs] def __iadd__(self, other): return self.add(other)
[docs] def __add__(self, other): operations = self.operations if isinstance(other, Sequential): return Sequential(operations + other.operations) elif isinstance(other, Parallel): return Sequential(operations + [other]) elif isinstance(other, Operator): return Sequential(operations + [other]) else: raise ValueError( f"{type(other)} is not usable with type:{type(self)}. This class can only add Operators (SequentialOperator, ParallelOperator, Operator)")
[docs] def __call__(self, *args, **kwargs): output = args for i, operation in enumerate(self.operations): if not isinstance(output, tuple): output = tuple([output]) if i == 0: output = operation(*output, **kwargs) else: output = operation(*output) return output
[docs] def add(self, other): if isinstance(other, Sequential): self.operations.extend(other.operations) elif isinstance(other, Parallel): self.operations.append(other) elif isinstance(other, Operator): self.operations.append(other) else: raise ValueError(f"{type(other)} is not usable with type:{type(self)}. This class can only add Operators (SequentialOperator, ParallelOperator, Operator)") return self