<commit_before>#!/bin/python
import ecto
import time

class DeclareModuleError(Exception):
    def __init__(self):
        pass
    def __str__(self):
        return 'need to declare modules'

class DefineInputOutputError(Exception):
    def __init__(self):
        pass
    def __str__(self):
        return 'need to define the inputs and outputs of the black box'

class BlackBox:
    """
    Base class implementing a meta module
    """
    # static dictionaries that have to be filled by each inheriting class
    # the key is the name of an input/output/parameter (as it will be used by other modules/black boxes),
    # and the value is the type of it. E.g. { "K_awesome": calib.CameraIntrinsics.outputs.K }
    PARAMETERS = {}
    INPUTS = {}
    OUTPUTS = {}
    def __init__(self, plasm):
        # contains the different Ecto modules. The key is the name of the module, the value the module itself
        self._modules = {}

        self.connections = {}

        self._declare_modules()
        self._define_input_ouput()
        self._connect(plasm)

    def __getitem__(self, names):
        """
        Get a specific module
        """
        return [ self._modules[name] for name in names ]

    def _connect(self, plasm):
        """
        Define the connections between the ecto modules in self._modules and the main plasm
        """
        raise ConnectError()

    def _declare_modules(self):
        """
        Pure virtual function to declare the different member ecto modules, without their interactions
        It basically fills self._modules
        """
        raise DeclareModuleError()

    def _define_input_ouput():
        """
        Pure virtual function to define the main outputs/inputs of the black box
        """
        raise DefineInputOutputError()<commit_msg>- revert to Ethan's version<commit_after>import ecto
           
class BlackBox(object):
    """
    The BlackBox may be used as an abstraction idium within ecto, to declare reusable plasms.
    
    Users should inherit from BlackBox, and likely will wish to implement a few functions that
    describe their reusable plasm.
    
    Lets look at a simple example:
    
    #your class should inherit from BlackBox
    class MyModule(ecto.BlackBox):
        
        #During initialization, one should allocate all necessary modules
        #and may want to accept parameters in the constructor to initialize said modules.
        def __init__(self, start, step):
            ecto.BlackBox.__init__(self)
            self.generate = ecto_test.Generate(start=start, step=step)
            self.inc = ecto_test.Increment()
        
        def expose_outputs(self):
            return {
                    "out":self.inc["out"]
                   }
        def expose_parameters(self):
            return {
                    "start":self.generate["start"],
                    "step":self.generate["step"]
                    }
        def connections(self):
            return (self.generate["out"] >> self.inc["in"])
        
    """
    def __init__(self):
        self.tendrils = None
    def _get_spec(self,key):
        """ Constructs a TendrilSpecification given a single str key.
        If the same key exists in the inputs and the outputs, a dichotomous spec is generated,
        otherwise, a spec is just retrieve from the mapping. 
        """
        i = self.expose_inputs()
        o = self.expose_outputs()
        p = self.expose_parameters()
        exist_i = key in i.keys()
        exist_o = key in o.keys()
        #dichotomous spec 
        if exist_i and exist_o:
            ospec = o[key]
            ispec = i[key]
            return ecto.TendrilSpecification(ospec.module_out, ispec.module_in, key)
        elif exist_i:
            return i[key].to_spec()
        elif exist_o:
            return o[key].to_spec()
        else:
            raise RuntimeError(key + " does not exist!")
        
    def __getitem__(self, key):
        """ This acts just like any other module when asking for a spec,
        e.g. spec = m["key1","key2"]
        """
        l = []
        if type(key) == str:
            l.append(self._get_spec(key))
        elif type(key) in (list,tuple):
            for x in key:
                l.append(self._get_spec(x))
        else:
            raise TypeError( "May only use a tuple, list, or single string")
        return ecto.TendrilSpecifications(l)
     
    def _getTendrils(self, name):
        """ The blackbox should look like a module, so it needs to have the parameters, inputs, outputs as
        member fields.
        """
        if self.tendrils is None:
            #transforms the TendrilsSpecifications to actual tendrils.
            self.tendrils = { 
                             "outputs" : ecto.TendrilSpecifications.to_tendrils(self.expose_outputs(), 0),
                             "inputs" : ecto.TendrilSpecifications.to_tendrils(self.expose_inputs(), 1),
                             "parameters" : ecto.TendrilSpecifications.to_tendrils(self.expose_parameters(), 2)
                            }
        return self.tendrils[name]
    
    def __getattr__(self, name):
        if name in ("outputs", "inputs", "parameters"):
            return self._getTendrils(name)
        else:
            return object.__getattr__(self, name)
    def expose_outputs(self):
        """ The outputs of a BlackBox should specified by returning a dictionary of string keys to TendrilsSpecifictation.
        {"output":self.mymodule["out_0001"]}
        """
        return {}
    
    def expose_inputs(self):
        """ The inputs of a BlackBox should specified by returning a dictionary of string keys to TendrilsSpecifictation.
        {"input":self.mymodule["in_0001"]}
        """
        return {}
    
    def expose_parameters(self):
        """ The parameters of a BlackBox should specified by returning a dictionary of string keys to TendrilsSpecifictation.
        {"param_01":self.mymodule["foo_param"]}
        """
    
    def connections(self):
        """This is where one should declare the graph, as a tuple of tuples, where each element 
        is (module_inst, 'output_key', module_inst, 'input_key')
        """
        raise NotImplementedError("All BlackBox's must implement at least the connections function....")
{'fraction_non_alphanumeric': 0.08734177215189873, 'fraction_numerical': 0.0023734177215189874, 'mean_word_length': 2.1030927835051547, 'pattern_counts': {'":': 7, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3065038', 'n_tokens_mistral': 1763, 'n_tokens_neox': 1681, 'n_words': 558}