Source code for jube2.pattern

# JUBE Benchmarking Environment
# Copyright (C) 2008-2024
# Forschungszentrum Juelich GmbH, Juelich Supercomputing Centre
# http://www.fz-juelich.de/jsc/jube
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""Patternset definition"""

from __future__ import (print_function,
                        unicode_literals,
                        division)

import jube2.parameter
import xml.etree.ElementTree as ET

LOGGER = jube2.log.get_logger(__name__)


[docs]class Patternset(object): """A Patternset stores a set of pattern and derived pattern.""" def __init__(self, name=""): self._name = name self._pattern = jube2.parameter.Parameterset("pattern") self._derived_pattern = jube2.parameter.Parameterset("derived_pattern")
[docs] def add_pattern(self, pattern): """Add a additional pattern to the patternset. Existing pattern using the same name will be overwritten""" if pattern.derived: if pattern in self._pattern: self._pattern.delete_parameter(pattern) self._derived_pattern.add_parameter(pattern) else: if pattern in self._derived_pattern: self._derived_pattern.delete_parameter(pattern) self._pattern.add_parameter(pattern)
@property def pattern_storage(self): """Return the pattern storage""" return self._pattern @property def derived_pattern_storage(self): """Return the derived pattern storage""" return self._derived_pattern
[docs] def etree_repr(self): """Return etree object representation""" patternset_etree = ET.Element('patternset') patternset_etree.attrib["name"] = self._name for pattern in self._pattern: patternset_etree.append( pattern.etree_repr()) for pattern in self._derived_pattern: patternset_etree.append( pattern.etree_repr()) return patternset_etree
[docs] def add_patternset(self, patternset): """Add all pattern from given patternset to the current one""" self._pattern.add_parameterset(patternset.pattern_storage) self._derived_pattern.add_parameterset( patternset.derived_pattern_storage)
[docs] def pattern_substitution(self, parametersets=None): """Run pattern substitution using additional parameterset""" if parametersets is None: parametersets = list() self._pattern.parameter_substitution( additional_parametersets=parametersets, final_sub=True)
[docs] def derived_pattern_substitution(self, parametersets=None): """Run derived pattern substitution using additional parameterset""" if parametersets is None: parametersets = list() self._derived_pattern.parameter_substitution( additional_parametersets=parametersets, final_sub=True)
@property def name(self): """Get patternset name""" return self._name
[docs] def copy(self): """Returns a copy of the Parameterset""" new_patternset = Patternset(self._name) new_patternset.add_patternset(self) return new_patternset
[docs] def is_compatible(self, patternset): """Two Patternsets are compatible, if all pattern storages are compatible""" return self.pattern_storage.is_compatible( patternset.pattern_storage) and \ self.pattern_storage.is_compatible( patternset.derived_pattern_storage) and \ self.derived_pattern_storage.is_compatible( patternset.derived_pattern_storage) and \ self.derived_pattern_storage.is_compatible( patternset.pattern_storage)
[docs] def get_incompatible_pattern(self, patternset): """Return a set of incompatible pattern names between the current and the given parameterset""" result = set() result.update(self.pattern_storage.get_incompatible_parameter( patternset.pattern_storage)) result.update(self.pattern_storage.get_incompatible_parameter( patternset.derived_pattern_storage)) result.update(self.derived_pattern_storage.get_incompatible_parameter( patternset.pattern_storage)) result.update(self.derived_pattern_storage.get_incompatible_parameter( patternset.derived_pattern_storage)) return result
def __repr__(self): return "Patternset: pattern:{0} derived pattern:{1}".format( dict([[pattern.name, pattern.value] for pattern in self._pattern]), dict([[pattern.name, pattern.value] for pattern in self._derived_pattern])) def __contains__(self, pattern): if isinstance(pattern, Pattern): if pattern.name in self._pattern: return pattern.is_equivalent( self._pattern[pattern.name]) elif pattern.name in self._derived_pattern: return pattern.is_equivalent( self._derived_pattern[pattern.name]) else: return False else: return (pattern in self._pattern) or \ (pattern in self._derived_pattern) def __getitem__(self, name): """Returns pattern given by name. Is pattern not found, None will be returned""" if name in self._pattern: return self._pattern[name] elif name in self._derived_pattern: return self._derived_pattern[name] else: return None
[docs]class Pattern(jube2.parameter.StaticParameter): """A pattern can be used to scan a result file, using regular expression, or to represent a derived pattern.""" def __init__(self, name, value, pattern_mode="pattern", content_type="string", unit="", default=None, dotall=False): self._derived = pattern_mode != "pattern" if not self._derived: pattern_mode = "text" self._default = default self._dotall = dotall # Unicode conversion value = "" + value self._unit = unit jube2.parameter.StaticParameter.__init__( self, name, value, parameter_type=content_type, parameter_mode=pattern_mode, unit=self._unit) @property def derived(self): """pattern is a derived pattern""" return self._derived @property def content_type(self): """Return pattern type""" return self._type @property def default_value(self): """Return pattern default value""" return self._default @property def dotall(self): """Return pattern dot regex handling""" return self._dotall @property def unit(self): """Return unit""" return self._unit
[docs] def substitute_and_evaluate(self, parametersets=None, final_sub=False, no_templates=True, force_evaluation=False): """Substitute all variables inside the pattern value by using the parameter inside the given parameterset and additional_parameterset. final_sub marks the last substitution. Return the new pattern and a boolean value which represent a change of value """ try: # To take care of default values for derived pattern sets, always # run final_sub instead of force_evaluation. Otherwise no error # will be thrown. Only using the final_sub setup is too late # because the default pattern might be used within another derived # pattern if (self._mode in jube2.conf.ALLOWED_SCRIPTTYPES and force_evaluation and self._default is not None): final_sub = True force_evaluation = False param, changed = \ jube2.parameter.StaticParameter.substitute_and_evaluate( self, parametersets, final_sub, no_templates, force_evaluation) except RuntimeError as re: LOGGER.debug(str(re).replace("parameter", "pattern")) if self._default is not None: value = self._default elif self._type in ["int", "float"]: value = "nan" else: value = "" pattern = Pattern( self._name, value, "text", self._type, self._unit, dotall=self._dotall) pattern.based_on = self return pattern, True if changed: # Convert parameter to pattern if not self.derived: pattern_mode = "pattern" else: pattern_mode = param.mode pattern = Pattern(param.name, param.value, pattern_mode, param.parameter_type, self._unit, dotall=self._dotall) pattern.based_on = param.based_on else: pattern = param return pattern, changed
[docs] def etree_repr(self, use_current_selection=False): """Return etree object representation""" pattern_etree = ET.Element('pattern') pattern_etree.attrib["name"] = self._name pattern_etree.attrib["type"] = self._type pattern_etree.attrib["dotall"] = str(self._dotall) if self._default is not None: pattern_etree.attrib["default"] = self._default if not self._derived: pattern_etree.attrib["mode"] = "pattern" else: pattern_etree.attrib["mode"] = self._mode if self._unit != "": pattern_etree.attrib["unit"] = self._unit pattern_etree.text = self.value return pattern_etree
def __repr__(self): return "Pattern({0})".format(self.__dict__)
[docs]def get_jube_pattern(): """Return jube internal patternset""" patternset = Patternset() # Pattern for integer number patternset.add_pattern(Pattern("jube_pat_int", r"([+-]?\d+)")) # Pattern for integer number, no () patternset.add_pattern(Pattern("jube_pat_nint", r"(?:[+-]?\d+)")) # Pattern for floating point number patternset.add_pattern( Pattern("jube_pat_fp", r"([+-]?(?:\d*\.?\d+(?:[eE][-+]?\d+)?|\d+\.))")) # Pattern for floating point number, no () patternset.add_pattern( Pattern("jube_pat_nfp", r"(?:[+-]?(?:\d*\.?\d+(?:[eE][-+]?\d+)?|\d+\.))")) # Pattern for word (all noblank characters) patternset.add_pattern(Pattern("jube_pat_wrd", r"(\S+)")) # Pattern for word (all noblank characters), no () patternset.add_pattern(Pattern("jube_pat_nwrd", r"(?:\S+)")) # Pattern for blank space (variable length) patternset.add_pattern(Pattern("jube_pat_bl", r"(?:\s+)")) return patternset