##// END OF EJS Templates
Add __attrs__ attribute to Process clasess to improve CLI finder
Add __attrs__ attribute to Process clasess to improve CLI finder

File last commit:

r1097:fefd86c58472
r1097:fefd86c58472
Show More
jroproc_base.py
360 lines | 9.5 KiB | text/x-python | PythonLexer
'''
$Author: murco $
$Id: jroproc_base.py 1 2012-11-12 18:56:07Z murco $
'''
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:
raise Exception('\x1b[0;32;40mDid you mean {} instead of {} in {}? \x1b[0m'.
format(fuzz[0], kwarg, method.__self__.__class__.__name__))
class ProcessingUnit(object):
"""
Esta es la clase base para el procesamiento de datos.
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".
"""
# objeto de datos de entrada (Voltage, Spectra o Correlation)
dataIn = None
dataInList = []
# objeto de datos de entrada (Voltage, Spectra o Correlation)
dataOut = None
operations2RunDict = None
isConfig = False
def __init__(self, *args, **kwargs):
self.dataIn = None
self.dataInList = []
self.dataOut = None
self.operations2RunDict = {}
self.operationKwargs = {}
self.isConfig = False
self.args = args
self.kwargs = kwargs
if not hasattr(self, 'name'):
self.name = self.__class__.__name__
checkKwargs(self.run, kwargs)
def getAllowedArgs(self):
if hasattr(self, '__attrs__'):
return self.__attrs__
else:
return inspect.getargspec(self.run).args
def addOperationKwargs(self, objId, **kwargs):
'''
'''
self.operationKwargs[objId] = kwargs
def addOperation(self, opObj, objId):
"""
Agrega un objeto del tipo "Operation" (opObj) a la lista de objetos "self.objectList" y retorna el
identificador asociado a este objeto.
Input:
object : objeto de la clase "Operation"
Return:
objId : identificador del objeto, necesario para ejecutar la operacion
"""
self.operations2RunDict[objId] = opObj
return objId
def getOperationObj(self, objId):
if objId not in self.operations2RunDict.keys():
return None
return self.operations2RunDict[objId]
def operation(self, **kwargs):
"""
Operacion directa sobre la data (dataOut.data). Es necesario actualizar los valores de los
atributos del objeto dataOut
Input:
**kwargs : Diccionario de argumentos de la funcion a ejecutar
"""
raise NotImplementedError
def callMethod(self, name, opId):
"""
Ejecuta el metodo con el nombre "name" y con argumentos **kwargs de la propia clase.
Input:
name : nombre del metodo a ejecutar
**kwargs : diccionario con los nombres y valores de la funcion a ejecutar.
"""
#Checking the inputs
if name == 'run':
if not self.checkInputs():
self.dataOut.flagNoData = True
return False
else:
#Si no es un metodo RUN la entrada es la misma dataOut (interna)
if self.dataOut is not None and self.dataOut.isEmpty():
return False
#Getting the pointer to method
methodToCall = getattr(self, name)
#Executing the self method
if hasattr(self, 'mp'):
if name=='run':
if self.mp is False:
self.mp = True
self.start()
else:
self.operationKwargs[opId]['parent'] = self.kwargs
methodToCall(**self.operationKwargs[opId])
else:
if name=='run':
methodToCall(**self.kwargs)
else:
methodToCall(**self.operationKwargs[opId])
if self.dataOut is None:
return False
if self.dataOut.isEmpty():
return False
return True
def callObject(self, objId):
"""
Ejecuta la operacion asociada al identificador del objeto "objId"
Input:
objId : identificador del objeto a ejecutar
**kwargs : diccionario con los nombres y valores de la funcion a ejecutar.
Return:
None
"""
if self.dataOut is not None and self.dataOut.isEmpty():
return False
externalProcObj = self.operations2RunDict[objId]
if hasattr(externalProcObj, 'mp'):
if externalProcObj.mp is False:
externalProcObj.kwargs['parent'] = self.kwargs
self.operationKwargs[objId] = externalProcObj.kwargs
externalProcObj.mp = True
externalProcObj.start()
else:
externalProcObj.run(self.dataOut, **externalProcObj.kwargs)
self.operationKwargs[objId] = externalProcObj.kwargs
return True
def call(self, opType, opName=None, opId=None):
"""
Return True si ejecuta la operacion interna nombrada "opName" o la operacion externa
identificada con el id "opId"; con los argumentos "**kwargs".
False si la operacion no se ha ejecutado.
Input:
opType : Puede ser "self" o "external"
Depende del tipo de operacion para llamar a:callMethod or callObject:
1. If opType = "self": Llama a un metodo propio de esta clase:
name_method = getattr(self, name)
name_method(**kwargs)
2. If opType = "other" o"external": Llama al metodo "run()" de una instancia de la
clase "Operation" o de un derivado de ella:
instanceName = self.operationList[opId]
instanceName.run(**kwargs)
opName : Si la operacion es interna (opType = 'self'), entonces el "opName" sera
usada para llamar a un metodo interno de la clase Processing
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
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.
De lo contrario retornara un error del tipo ValueError
"""
if opType == 'self':
if not opName:
raise ValueError, "opName parameter should be defined"
sts = self.callMethod(opName, opId)
elif opType == 'other' or opType == 'external' or opType == 'plotter':
if not opId:
raise ValueError, "opId parameter should be defined"
if opId not in self.operations2RunDict.keys():
raise ValueError, "Any operation with id=%s has been added" %str(opId)
sts = self.callObject(opId)
else:
raise ValueError, "opType should be 'self', 'external' or 'plotter'; and not '%s'" %opType
return sts
def setInput(self, dataIn):
self.dataIn = dataIn
self.dataInList.append(dataIn)
def getOutputObj(self):
return self.dataOut
def checkInputs(self):
for thisDataIn in self.dataInList:
if thisDataIn.isEmpty():
return False
return True
def setup(self):
raise NotImplementedError
def run(self):
raise NotImplementedError
def close(self):
#Close every thread, queue or any other object here is it is neccesary.
return
class Operation(object):
"""
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
Ejemplo: Integraciones coherentes, necesita la informacion previa de los n perfiles anteriores (bufffer)
"""
__buffer = None
isConfig = False
def __init__(self, **kwargs):
self.__buffer = None
self.isConfig = False
self.kwargs = kwargs
if not hasattr(self, 'name'):
self.name = self.__class__.__name__
checkKwargs(self.run, kwargs)
def getAllowedArgs(self):
if hasattr(self, '__attrs__'):
return self.__attrs__
else:
return inspect.getargspec(self.run).args
def setup(self):
self.isConfig = True
raise NotImplementedError
def run(self, dataIn, **kwargs):
"""
Realiza las operaciones necesarias sobre la dataIn.data y actualiza los
atributos del objeto dataIn.
Input:
dataIn : objeto del tipo JROData
Return:
None
Affected:
__buffer : buffer de recepcion de datos.
"""
if not self.isConfig:
self.setup(**kwargs)
raise NotImplementedError
def close(self):
pass