Source code for ase2sprkkr.common.parsing_results

import pyparsing as pp


[docs] class Result: """When data are parsed, some (repeated) options can yield special keys, results in agregating"""
[docs] def result(self): return self.value
[docs] class Key: """A base class for items, that have to be treated in a special way"""
[docs] @staticmethod def NONE(x): return x
""" The regular items has no special key """
[docs] def __init__(self, key): self.key = key
[docs] def get(self, too): if self.key in too: out = too[self.key] if out.__class__ is not self.ResultClass: raise pp.ParseException(f"Conflicting values for item {self.key}") return out out = self.ResultClass() too[self.key] = out too.process.append(self.key) return out
[docs] class IgnoredKey(Key): """This key is totaly and silently ignored. Use it for the keys, that should be written, but not read. """
[docs] def add(self, too, val): return
[docs] class ValidateKey(Key): """This key is totaly and silently ignored. Use it for the keys, that should be written, but not read. """
[docs] def add(self, too, val): too.checks.append(val)
[docs] class SubKey(Key): """A base class for items that have subkeys"""
[docs] def __init__(self, key, sub): self.key = key self.sub = self.convert(sub)
[docs] def convert(self, sub): return int(sub)
[docs] class DictKey(SubKey):
[docs] class ResultClass(Result): def __init__(self): self.value = {}
[docs] def add(self, too, value): out = self.get(too) if self.sub in out.value: raise pp.ParseException(f"Duplicate key {self.sub} in {self.key}") out.value[self.sub] = value
[docs] class DefDictKey(DictKey):
[docs] def convert(self, sub): return sub if sub == "def" else int(sub)
[docs] class ArrayKey(SubKey):
[docs] class ResultClass(Result): NOT_SET = object() def __init__(self): self.value = []
[docs] def result(self): return self.value
[docs] def add(self, too, val): out = self.get(too) ln = len(out.value) i = self.sub - 1 if ln < i: out.value += [out.NOT_SET] * (i - ln + 1) if ln == i: out.value.append(val) else: if out.value[i] is not out.NOT_SET: raise pp.ParseException(f"Duplicate key {self.sub} in {self.key}") out.value[i] = val
[docs] class RepeatedKey(Key):
[docs] class ResultClass(Result): def __init__(self): self.value = []
[docs] def add(self, too, val): self.get(too).value.append(val)
[docs] class Values(dict): """Result of dict_from_parsed: dictionary with list of checks on the parsed values."""
[docs] def __init__(self): super().__init__() self.checks = [] self.process = []
[docs] def to_dict(self): return {i: j.to_dict() if isinstance(j, Values) else j for i, j in self.items()}
[docs] def dict_from_parsed(values): """Create a dictionary from the arguments. From duplicate arguments create numpy arrays. Moreover, if there is key of type (a,b), it will be transformed to subdictionary. Such a keys do not allow duplicates. >>> dict_from_parsed([("x", "y"), ((DictKey("a", 1)), 1), ((DictKey("a", 3)), 2)]) {'x': 'y', 'a': {1: 1, 3: 2}} >>> dict_from_parsed([("x", 1), ("x", "2")]) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): pyparsing.exceptions.ParseException: There are non-unique keys: x >>> dict_from_parsed([(RepeatedKey("x"), 1), (RepeatedKey("x"), 2)]) {'x': [1, 2]} """ out = Values() duplicates = set() errors = [] def add(key, value): if isinstance(key, Key): key.add(out, value) elif key in out: duplicates.add(k) else: out[key] = value for k, v in values: try: add(k, v) except Exception as e: errors.append(e) for key in out.process: out[key] = out[key].result() for i in out.checks: try: i(out) except Exception as e: errors.append(e) if duplicates: duplicates = ", ".join((i.upper() for i in duplicates)) errors.append(pp.ParseException(f"There are duplicate items named {duplicates}")) if errors: if len(errors) == 1: raise errors[0] errors = "\n".join((str(e) for e in errors)) raise pp.ParseException(f"There are errors in data: {errors}") return out