diff --git a/common/python/nomadcore/simple_parser.py b/common/python/nomadcore/simple_parser.py index 96aeeb27246504136ea375b4fae4fc9861dff84e..91175134038c5f23109fa0b9deef35435f34d50a 100644 --- a/common/python/nomadcore/simple_parser.py +++ b/common/python/nomadcore/simple_parser.py @@ -510,12 +510,20 @@ class CompiledMatcher(object): self.possibleNextsEnd = possibleNextsEnd self.possibleNextsRe = self.matchersToRe(possibleNexts) self.possibleNextsEndRe = self.matchersToRe(possibleNextsEnd) + strValueTransform = parserBuilder.strValueTransform + if strValueTransform is None: + strValueTransform = {} converters = {} + transformers = {} groups = extractGroupNames(matcher.startReStr) if matcher.endReStr: groups.extend(extractGroupNames(matcher.endReStr)) for gName, units in groups: metaInfo = parserBuilder.metaInfoEnv.infoKinds[gName] + if units in strValueTransform: + # override units by output units of string transform function + transformers[gName] = strValueTransform[units][0] + units = strValueTransform[units][1] if units: # By default use the unit given in metainfo target_unit = metaInfo.units @@ -535,11 +543,16 @@ class CompiledMatcher(object): converters[gName] = unit_conversion.convert_unit_function(units, target_unit) self.converters = converters + self.transformers = transformers def addStrValue(self, backend, metaNameWithUnits, strValue): """adds a string value with unit conversions (only for the groups in start and endRe)""" metaName = metaNameWithUnits.split("__")[0] - value = backend.convertScalarStringValue(metaName, strValue) + transformer = self.transformers.get(metaName, None) + if transformer: + value = transformer(strValue) + else: + value = backend.convertScalarStringValue(metaName, strValue) self.addValue(backend, metaName, value) def addValue(self, backend, metaName, value): @@ -699,8 +712,32 @@ def extractOnOpenTriggers(obj): triggers[name] = getattr(obj, attr) return triggers +def extractStrValueTransforms(obj): + """extracts all string-to-value transformations from obj + + name of transformation method starts with 'strValueTransform_' + and then have a 'pseudo-unit-name' starting with 'str', which can then be + referenced as a 'unit' in regex group names. + Output units of transform method can be specified as function attribute + 'units' + def strValueTransform_strDate(self.string) + .... + strValueTransform_strDate.units = 's' + would than be used, if you have + (?P<time_run_date_start__strDate>...) + in your regex""" + transform = {} + for attr in dir(obj): + match = re.match(r"strValueTransform_(str\S+)", attr) + if match: + name = match.group(1) + callback = getattr(obj, attr) + units = getattr(callback, 'units', None) + transform[name] = [callback, units] + return transform + class SimpleParserBuilder(object): - def __init__(self, rootMatcher, metaInfoEnv, metaInfoToKeep=None, default_units=None, metainfo_units=None): + def __init__(self, rootMatcher, metaInfoEnv, metaInfoToKeep=None, default_units=None, metainfo_units=None, strValueTransform=None): """ Args: metaInfoToKeep: A list of metanames. Any SimpleMatchers (and their @@ -721,6 +758,7 @@ class SimpleParserBuilder(object): self.metaInfoToKeep = metaInfoToKeep self.default_units = default_units self.metainfo_units = metainfo_units + self.strValueTransform = strValueTransform def verifyMetaInfo(self, outF): missingMeta = {} @@ -1047,9 +1085,9 @@ class SimpleParser(object): while self.parseStep(): pass -def compileParser(simpleParser, metaInfo, metaInfoToKeep, default_units=None, metainfo_units=None): +def compileParser(simpleParser, metaInfo, metaInfoToKeep, default_units=None, metainfo_units=None, strValueTransform=None): """compiles the given simple parser""" - parserBuilder = SimpleParserBuilder(simpleParser, metaInfo, metaInfoToKeep, default_units, metainfo_units) + parserBuilder = SimpleParserBuilder(simpleParser, metaInfo, metaInfoToKeep, default_units, metainfo_units, strValueTransform) if logger.isEnabledFor(logging.DEBUG): s = io.StringIO() s.write("matchers:") @@ -1098,7 +1136,8 @@ def mainFunction(mainFileDescription, metainfo_units=None, superBackend=None, metaInfoToKeep=None, - mainFile=None): + mainFile=None, + strValueTransform={}): """ Args: default_units: A list of default unit definitions. @@ -1192,8 +1231,15 @@ def mainFunction(mainFileDescription, else: jsonBackend = superBackend + if superContext: + strValueTransform = dict(strValueTransform) + for attr, callback in extractStrValueTransforms(superContext).items(): + oldCallbacks = strValueTransform.get(attr, None) + if attr not in strValueTransform: + strValueTransform[attr] = callback # initialize the parser builder - parserBuilder = compileParser(mainFileDescription, metaInfoEnv, metaInfoToKeep, default_units, metainfo_units) + parserBuilder = compileParser(mainFileDescription, metaInfoEnv, metaInfoToKeep, default_units, metainfo_units, + strValueTransform) if superContext: onClose = dict(onClose)