jroproc_base.py
359 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 | ||
|
r1167 | if objId not in list(self.operations2RunDict.keys()): | |
|
r577 | 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: | |
|
r1167 | 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: | |
|
r1167 | raise ValueError("opId parameter should be defined") | |
|
r860 | ||
|
r1167 | if opId not in list(self.operations2RunDict.keys()): | |
raise ValueError("Any operation with id=%s has been added" %str(opId)) | |||
|
r860 | ||
r889 | sts = self.callObject(opId) | ||
|
r860 | ||
|
r691 | else: | |
|
r1167 | 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 | ||
|
r1167 | pass |