Newer
Older
from earthdiagnostics.variable import VarType, Domain
Javier Vegas-Regidor
committed
Javier Vegas-Regidor
committed
class Diagnostic(object):
Javier Vegas-Regidor
committed
Base class for the diagnostics. Provides a common interface for them and also
has a mechanism that allows diagnostic retrieval by name.
:param data_manager: data manager that will be used to store and retrieve the necessary data
:type data_manager: DataManager
Javier Vegas-Regidor
committed
alias = None
"""
Alias to call the diagnostic. Must be overridden at the derived clases
"""
def __init__(self, data_manager):
self.data_manager = data_manager
self.required_vars = []
self.generated_vars = []
self.can_run_multiple_instances = True
def register(cls):
"""
Register a new diagnostic using the given alias. It must be call using the derived class.
:param cls: diagnostic class to register
:type cls: Diagnostic
"""
if not issubclass(cls, Diagnostic):
raise ValueError('Class {0} must be derived from Diagnostic'.format(cls))
if cls.alias is None:
raise ValueError('Diagnostic class {0} must have defined an alias'.format(cls))
Diagnostic._diag_list[cls.alias] = cls
# noinspection PyProtectedMember
@staticmethod
def get_diagnostic(name):
"""
Return the class for a diagnostic given its name
:param name: diagnostic alias
:type name: str
:return: the selected Diagnostic class, None if name can not be found
:rtype: Diagnostic
"""
if name in Diagnostic._diag_list.keys():
return Diagnostic._diag_list[name]
def send_file(self, filetosend, domain, var, startdate, member, chunk=None, grid=None, region=None,
Javier Vegas-Regidor
committed
box=None, rename_var=None, frequency=None, year=None, date_str=None, move_old=False,
vartype=VarType.MEAN):
Javier Vegas-Regidor
committed
"""
:param filetosend:
:param domain:
:type domain: Domain
:param var:
:param startdate:
:param member:
:param chunk:
:param grid:
:param region:
:param box:
:param rename_var:
:param frequency:
:param year:
:param date_str:
:param move_old:
:return:
"""
self.data_manager.send_file(filetosend, domain, var, startdate, member, chunk, grid, region,
Javier Vegas-Regidor
committed
box, rename_var, frequency, year, date_str, move_old, diagnostic=self,
vartype=vartype)
Javier Vegas-Regidor
committed
def compute(self):
"""
Calculates the diagnostic and stores the output
Must be implemented by derived classes
"""
raise NotImplementedError("Class must override compute method")
def generate_jobs(cls, diags, options):
"""
Generate the instances of the diagnostics that will be run by the manager
Must be implemented by derived classes.
:param diags: diagnostics manager
:type diags: Diags
:param options: list of strings containing the options passed to the diagnostic
:return:
"""
raise NotImplementedError("Class must override generate_jobs class method")
@staticmethod
def process_options(options, options_available):
processed = dict()
options = options[1:]
for x in range(len(options_available)):
option_definition = options_available[x]
if len(options) <= x:
option_value = ''
else:
option_value = options[x]
processed[option_definition.name] = option_definition.parse(option_value)
return processed
def __str__(self):
"""
Must be implemented by derived classes
:return:
"""
return 'Developer must override base class __str__ method'
class DiagnosticOption(object):
def __init__(self, name, default_value=None):
self.name = name
self.default_value = default_value
def parse(self, option_value):
option_value = self.check_default(option_value)
return option_value
def check_default(self, option_value):
if option_value == '':
if self.default_value is None:
raise DiagnosticOptionError('Option {0} is not optional'.format(self.name))
else:
return self.default_value
return option_value
class DiagnosticFloatOption(DiagnosticOption):
def parse(self, option_value):
return float(self.check_default(option_value))
class DiagnosticIntOption(DiagnosticOption):
def parse(self, option_value):
return int(self.check_default(option_value))
class DiagnosticDomainOption(DiagnosticOption):
def parse(self, option_value):
return Domain.parse(self.check_default(option_value))
class DiagnosticComplexStrOption(DiagnosticOption):
def parse(self, option_value):
return self.check_default(option_value).replace('&;', ',').replace('&.', ' ')
class DiagnosticBoolOption(DiagnosticOption):
def parse(self, option_value):
option_value = self.check_default(option_value)
if isinstance(option_value, bool):
return option_value
else:
return option_value.lower() in ('true', 't', 'yes')
class DiagnosticOptionError(Exception):
pass