jroproc_base.py
360 lines
| 9.5 KiB
| text/x-python
|
PythonLexer
|
r487 | ''' | ||
|
r568 | |||
$Author: murco $ | ||||
$Id: jroproc_base.py 1 2012-11-12 18:56:07Z murco $ | ||||
|
r487 | ''' | ||
|
r929 | import inspect | ||
from fuzzywuzzy import process | ||||
def checkKwargs(method, kwargs): | ||||
currentKwargs = kwargs | ||||
choices = inspect.getargspec(method).args | ||||
try: | ||||
choices.remove('self') | ||||
except Exception as e: | ||||
pass | ||||
try: | ||||
choices.remove('dataOut') | ||||
except Exception as e: | ||||
pass | ||||
for kwarg in kwargs: | ||||
fuzz = process.extractOne(kwarg, choices) | ||||
if fuzz is None: | ||||
continue | ||||
if fuzz[1] < 100: | ||||
|
r931 | raise Exception('\x1b[0;32;40mDid you mean {} instead of {} in {}? \x1b[0m'. | ||
|
r929 | format(fuzz[0], kwarg, method.__self__.__class__.__name__)) | ||
|
r487 | |||
|
r568 | class ProcessingUnit(object): | ||
|
r860 | |||
|
r487 | """ | ||
Esta es la clase base para el procesamiento de datos. | ||||
|
r860 | |||
|
r487 | Contiene el metodo "call" para llamar operaciones. Las operaciones pueden ser: | ||
- Metodos internos (callMethod) | ||||
- Objetos del tipo Operation (callObject). Antes de ser llamados, estos objetos | ||||
tienen que ser agreagados con el metodo "add". | ||||
|
r860 | |||
|
r487 | """ | ||
# objeto de datos de entrada (Voltage, Spectra o Correlation) | ||||
dataIn = None | ||||
dataInList = [] | ||||
|
r860 | |||
|
r487 | # objeto de datos de entrada (Voltage, Spectra o Correlation) | ||
dataOut = None | ||||
|
r860 | |||
|
r487 | operations2RunDict = None | ||
|
r860 | |||
|
r487 | isConfig = False | ||
|
r860 | |||
r889 | def __init__(self, *args, **kwargs): | |||
|
r860 | |||
|
r487 | self.dataIn = None | ||
self.dataInList = [] | ||||
|
r860 | |||
|
r573 | self.dataOut = None | ||
|
r860 | |||
|
r487 | self.operations2RunDict = {} | ||
|
r906 | self.operationKwargs = {} | ||
|
r860 | |||
|
r487 | self.isConfig = False | ||
|
r860 | |||
r889 | self.args = args | |||
self.kwargs = kwargs | ||||
|
r1096 | |||
if not hasattr(self, 'name'): | ||||
self.name = self.__class__.__name__ | ||||
|
r929 | checkKwargs(self.run, kwargs) | ||
def getAllowedArgs(self): | ||||
|
r1097 | if hasattr(self, '__attrs__'): | ||
return self.__attrs__ | ||||
else: | ||||
return inspect.getargspec(self.run).args | ||||
r889 | ||||
|
r906 | def addOperationKwargs(self, objId, **kwargs): | ||
''' | ||||
''' | ||||
|
r929 | |||
|
r906 | self.operationKwargs[objId] = kwargs | ||
|
r929 | |||
|
r487 | def addOperation(self, opObj, objId): | ||
|
r860 | |||
|
r487 | """ | ||
Agrega un objeto del tipo "Operation" (opObj) a la lista de objetos "self.objectList" y retorna el | ||||
|
r860 | identificador asociado a este objeto. | ||
|
r487 | Input: | ||
|
r860 | |||
|
r487 | object : objeto de la clase "Operation" | ||
|
r860 | |||
|
r487 | Return: | ||
|
r860 | |||
|
r487 | objId : identificador del objeto, necesario para ejecutar la operacion | ||
""" | ||||
|
r860 | |||
|
r487 | self.operations2RunDict[objId] = opObj | ||
|
r860 | |||
|
r487 | return objId | ||
|
r860 | |||
|
r577 | def getOperationObj(self, objId): | ||
|
r860 | |||
|
r577 | if objId not in self.operations2RunDict.keys(): | ||
return None | ||||
|
r860 | |||
|
r577 | return self.operations2RunDict[objId] | ||
|
r860 | |||
|
r487 | def operation(self, **kwargs): | ||
|
r860 | |||
|
r487 | """ | ||
Operacion directa sobre la data (dataOut.data). Es necesario actualizar los valores de los | ||||
atributos del objeto dataOut | ||||
|
r860 | |||
|
r487 | Input: | ||
|
r860 | |||
|
r487 | **kwargs : Diccionario de argumentos de la funcion a ejecutar | ||
""" | ||||
|
r860 | |||
|
r684 | raise NotImplementedError | ||
|
r860 | |||
|
r906 | def callMethod(self, name, opId): | ||
|
r860 | |||
|
r487 | """ | ||
Ejecuta el metodo con el nombre "name" y con argumentos **kwargs de la propia clase. | ||||
|
r860 | |||
|
r487 | Input: | ||
name : nombre del metodo a ejecutar | ||||
|
r860 | |||
|
r487 | **kwargs : diccionario con los nombres y valores de la funcion a ejecutar. | ||
|
r860 | |||
|
r487 | """ | ||
|
r860 | |||
|
r568 | #Checking the inputs | ||
|
r487 | if name == 'run': | ||
|
r860 | |||
|
r487 | if not self.checkInputs(): | ||
self.dataOut.flagNoData = True | ||||
return False | ||||
else: | ||||
#Si no es un metodo RUN la entrada es la misma dataOut (interna) | ||||
|
r906 | if self.dataOut is not None and self.dataOut.isEmpty(): | ||
|
r487 | return False | ||
|
r860 | |||
|
r487 | #Getting the pointer to method | ||
methodToCall = getattr(self, name) | ||||
|
r860 | |||
|
r487 | #Executing the self method | ||
|
r860 | |||
r889 | if hasattr(self, 'mp'): | |||
|
r929 | if name=='run': | ||
if self.mp is False: | ||||
|
r906 | self.mp = True | ||
self.start() | ||||
|
r937 | else: | ||
self.operationKwargs[opId]['parent'] = self.kwargs | ||||
|
r929 | methodToCall(**self.operationKwargs[opId]) | ||
r889 | else: | |||
|
r929 | if name=='run': | ||
|
r906 | methodToCall(**self.kwargs) | ||
|
r929 | else: | ||
|
r906 | methodToCall(**self.operationKwargs[opId]) | ||
|
r860 | |||
|
r611 | if self.dataOut is None: | ||
|
r573 | return False | ||
|
r860 | |||
|
r487 | if self.dataOut.isEmpty(): | ||
return False | ||||
|
r860 | |||
|
r487 | return True | ||
|
r860 | |||
r889 | def callObject(self, objId): | |||
|
r860 | |||
|
r487 | """ | ||
Ejecuta la operacion asociada al identificador del objeto "objId" | ||||
|
r860 | |||
|
r487 | Input: | ||
|
r860 | |||
|
r487 | objId : identificador del objeto a ejecutar | ||
|
r860 | |||
|
r487 | **kwargs : diccionario con los nombres y valores de la funcion a ejecutar. | ||
|
r860 | |||
|
r487 | Return: | ||
|
r860 | |||
None | ||||
|
r487 | """ | ||
|
r860 | |||
r889 | if self.dataOut is not None and self.dataOut.isEmpty(): | |||
|
r487 | return False | ||
|
r860 | |||
|
r487 | externalProcObj = self.operations2RunDict[objId] | ||
|
r860 | |||
r889 | if hasattr(externalProcObj, 'mp'): | |||
if externalProcObj.mp is False: | ||||
|
r937 | externalProcObj.kwargs['parent'] = self.kwargs | ||
|
r906 | self.operationKwargs[objId] = externalProcObj.kwargs | ||
r889 | externalProcObj.mp = True | |||
externalProcObj.start() | ||||
else: | ||||
externalProcObj.run(self.dataOut, **externalProcObj.kwargs) | ||||
|
r906 | self.operationKwargs[objId] = externalProcObj.kwargs | ||
|
r860 | |||
|
r487 | return True | ||
|
r860 | |||
r889 | def call(self, opType, opName=None, opId=None): | |||
|
r487 | """ | ||
|
r568 | Return True si ejecuta la operacion interna nombrada "opName" o la operacion externa | ||
identificada con el id "opId"; con los argumentos "**kwargs". | ||||
|
r860 | |||
|
r568 | False si la operacion no se ha ejecutado. | ||
|
r860 | |||
|
r568 | Input: | ||
|
r860 | |||
|
r568 | opType : Puede ser "self" o "external" | ||
|
r860 | |||
|
r691 | Depende del tipo de operacion para llamar a:callMethod or callObject: | ||
|
r860 | |||
|
r691 | 1. If opType = "self": Llama a un metodo propio de esta clase: | ||
|
r860 | |||
|
r691 | name_method = getattr(self, name) | ||
name_method(**kwargs) | ||||
|
r860 | |||
|
r691 | 2. If opType = "other" o"external": Llama al metodo "run()" de una instancia de la | ||
clase "Operation" o de un derivado de ella: | ||||
|
r860 | |||
|
r691 | instanceName = self.operationList[opId] | ||
instanceName.run(**kwargs) | ||||
|
r860 | |||
|
r568 | opName : Si la operacion es interna (opType = 'self'), entonces el "opName" sera | ||
usada para llamar a un metodo interno de la clase Processing | ||||
|
r860 | |||
|
r691 | opId : Si la operacion es externa (opType = 'other' o 'external), entonces el | ||
"opId" sera usada para llamar al metodo "run" de la clase Operation | ||||
registrada anteriormente con ese Id | ||||
|
r860 | |||
|
r568 | Exception: | ||
Este objeto de tipo Operation debe de haber sido agregado antes con el metodo: | ||||
"addOperation" e identificado con el valor "opId" = el id de la operacion. | ||||
|
r691 | De lo contrario retornara un error del tipo ValueError | ||
|
r860 | |||
|
r487 | """ | ||
|
r860 | |||
|
r487 | if opType == 'self': | ||
|
r860 | |||
|
r487 | if not opName: | ||
|
r684 | raise ValueError, "opName parameter should be defined" | ||
|
r860 | |||
|
r906 | sts = self.callMethod(opName, opId) | ||
|
r860 | |||
|
r691 | elif opType == 'other' or opType == 'external' or opType == 'plotter': | ||
|
r860 | |||
|
r487 | if not opId: | ||
|
r684 | raise ValueError, "opId parameter should be defined" | ||
|
r860 | |||
|
r487 | if opId not in self.operations2RunDict.keys(): | ||
|
r691 | raise ValueError, "Any operation with id=%s has been added" %str(opId) | ||
|
r860 | |||
r889 | sts = self.callObject(opId) | |||
|
r860 | |||
|
r691 | else: | ||
raise ValueError, "opType should be 'self', 'external' or 'plotter'; and not '%s'" %opType | ||||
|
r860 | |||
return sts | ||||
|
r487 | def setInput(self, dataIn): | ||
|
r860 | |||
|
r487 | self.dataIn = dataIn | ||
self.dataInList.append(dataIn) | ||||
|
r860 | |||
|
r487 | def getOutputObj(self): | ||
|
r860 | |||
|
r487 | return self.dataOut | ||
|
r860 | |||
|
r487 | def checkInputs(self): | ||
r889 | ||||
|
r487 | for thisDataIn in self.dataInList: | ||
|
r860 | |||
|
r487 | if thisDataIn.isEmpty(): | ||
return False | ||||
|
r860 | |||
|
r487 | return True | ||
|
r860 | |||
|
r487 | def setup(self): | ||
|
r860 | |||
|
r684 | raise NotImplementedError | ||
|
r860 | |||
|
r487 | def run(self): | ||
|
r860 | |||
|
r684 | raise NotImplementedError | ||
|
r860 | |||
|
r573 | def close(self): | ||
#Close every thread, queue or any other object here is it is neccesary. | ||||
return | ||||
|
r860 | |||
|
r568 | class Operation(object): | ||
|
r860 | |||
|
r487 | """ | ||
Clase base para definir las operaciones adicionales que se pueden agregar a la clase ProcessingUnit | ||||
y necesiten acumular informacion previa de los datos a procesar. De preferencia usar un buffer de | ||||
acumulacion dentro de esta clase | ||||
|
r860 | |||
|
r487 | Ejemplo: Integraciones coherentes, necesita la informacion previa de los n perfiles anteriores (bufffer) | ||
|
r860 | |||
|
r487 | """ | ||
|
r860 | |||
|
r487 | __buffer = None | ||
isConfig = False | ||||
|
r860 | |||
r889 | def __init__(self, **kwargs): | |||
|
r860 | |||
|
r487 | self.__buffer = None | ||
self.isConfig = False | ||||
r889 | self.kwargs = kwargs | |||
|
r1096 | if not hasattr(self, 'name'): | ||
self.name = self.__class__.__name__ | ||||
|
r929 | checkKwargs(self.run, kwargs) | ||
def getAllowedArgs(self): | ||||
|
r1097 | if hasattr(self, '__attrs__'): | ||
return self.__attrs__ | ||||
else: | ||||
return inspect.getargspec(self.run).args | ||||
|
r860 | |||
|
r487 | def setup(self): | ||
|
r860 | |||
|
r487 | self.isConfig = True | ||
|
r860 | |||
|
r684 | raise NotImplementedError | ||
|
r487 | |||
def run(self, dataIn, **kwargs): | ||||
|
r860 | |||
|
r487 | """ | ||
|
r568 | Realiza las operaciones necesarias sobre la dataIn.data y actualiza los | ||
atributos del objeto dataIn. | ||||
|
r860 | |||
|
r487 | Input: | ||
|
r860 | |||
|
r487 | dataIn : objeto del tipo JROData | ||
|
r860 | |||
|
r487 | Return: | ||
|
r860 | |||
|
r487 | None | ||
|
r860 | |||
|
r487 | Affected: | ||
__buffer : buffer de recepcion de datos. | ||||
|
r860 | |||
|
r487 | """ | ||
if not self.isConfig: | ||||
self.setup(**kwargs) | ||||
|
r860 | |||
|
r684 | raise NotImplementedError | ||
|
r860 | |||
|
r577 | def close(self): | ||
|
r860 | |||
pass | ||||