1a5f9918aSopenharmony_ci 2a5f9918aSopenharmony_ci__all__ = ['BaseResolver', 'Resolver'] 3a5f9918aSopenharmony_ci 4a5f9918aSopenharmony_cifrom .error import * 5a5f9918aSopenharmony_cifrom .nodes import * 6a5f9918aSopenharmony_ci 7a5f9918aSopenharmony_ciimport re 8a5f9918aSopenharmony_ci 9a5f9918aSopenharmony_ciclass ResolverError(YAMLError): 10a5f9918aSopenharmony_ci pass 11a5f9918aSopenharmony_ci 12a5f9918aSopenharmony_ciclass BaseResolver: 13a5f9918aSopenharmony_ci 14a5f9918aSopenharmony_ci DEFAULT_SCALAR_TAG = 'tag:yaml.org,2002:str' 15a5f9918aSopenharmony_ci DEFAULT_SEQUENCE_TAG = 'tag:yaml.org,2002:seq' 16a5f9918aSopenharmony_ci DEFAULT_MAPPING_TAG = 'tag:yaml.org,2002:map' 17a5f9918aSopenharmony_ci 18a5f9918aSopenharmony_ci yaml_implicit_resolvers = {} 19a5f9918aSopenharmony_ci yaml_path_resolvers = {} 20a5f9918aSopenharmony_ci 21a5f9918aSopenharmony_ci def __init__(self): 22a5f9918aSopenharmony_ci self.resolver_exact_paths = [] 23a5f9918aSopenharmony_ci self.resolver_prefix_paths = [] 24a5f9918aSopenharmony_ci 25a5f9918aSopenharmony_ci @classmethod 26a5f9918aSopenharmony_ci def add_implicit_resolver(cls, tag, regexp, first): 27a5f9918aSopenharmony_ci if not 'yaml_implicit_resolvers' in cls.__dict__: 28a5f9918aSopenharmony_ci implicit_resolvers = {} 29a5f9918aSopenharmony_ci for key in cls.yaml_implicit_resolvers: 30a5f9918aSopenharmony_ci implicit_resolvers[key] = cls.yaml_implicit_resolvers[key][:] 31a5f9918aSopenharmony_ci cls.yaml_implicit_resolvers = implicit_resolvers 32a5f9918aSopenharmony_ci if first is None: 33a5f9918aSopenharmony_ci first = [None] 34a5f9918aSopenharmony_ci for ch in first: 35a5f9918aSopenharmony_ci cls.yaml_implicit_resolvers.setdefault(ch, []).append((tag, regexp)) 36a5f9918aSopenharmony_ci 37a5f9918aSopenharmony_ci @classmethod 38a5f9918aSopenharmony_ci def add_path_resolver(cls, tag, path, kind=None): 39a5f9918aSopenharmony_ci # Note: `add_path_resolver` is experimental. The API could be changed. 40a5f9918aSopenharmony_ci # `new_path` is a pattern that is matched against the path from the 41a5f9918aSopenharmony_ci # root to the node that is being considered. `node_path` elements are 42a5f9918aSopenharmony_ci # tuples `(node_check, index_check)`. `node_check` is a node class: 43a5f9918aSopenharmony_ci # `ScalarNode`, `SequenceNode`, `MappingNode` or `None`. `None` 44a5f9918aSopenharmony_ci # matches any kind of a node. `index_check` could be `None`, a boolean 45a5f9918aSopenharmony_ci # value, a string value, or a number. `None` and `False` match against 46a5f9918aSopenharmony_ci # any _value_ of sequence and mapping nodes. `True` matches against 47a5f9918aSopenharmony_ci # any _key_ of a mapping node. A string `index_check` matches against 48a5f9918aSopenharmony_ci # a mapping value that corresponds to a scalar key which content is 49a5f9918aSopenharmony_ci # equal to the `index_check` value. An integer `index_check` matches 50a5f9918aSopenharmony_ci # against a sequence value with the index equal to `index_check`. 51a5f9918aSopenharmony_ci if not 'yaml_path_resolvers' in cls.__dict__: 52a5f9918aSopenharmony_ci cls.yaml_path_resolvers = cls.yaml_path_resolvers.copy() 53a5f9918aSopenharmony_ci new_path = [] 54a5f9918aSopenharmony_ci for element in path: 55a5f9918aSopenharmony_ci if isinstance(element, (list, tuple)): 56a5f9918aSopenharmony_ci if len(element) == 2: 57a5f9918aSopenharmony_ci node_check, index_check = element 58a5f9918aSopenharmony_ci elif len(element) == 1: 59a5f9918aSopenharmony_ci node_check = element[0] 60a5f9918aSopenharmony_ci index_check = True 61a5f9918aSopenharmony_ci else: 62a5f9918aSopenharmony_ci raise ResolverError("Invalid path element: %s" % element) 63a5f9918aSopenharmony_ci else: 64a5f9918aSopenharmony_ci node_check = None 65a5f9918aSopenharmony_ci index_check = element 66a5f9918aSopenharmony_ci if node_check is str: 67a5f9918aSopenharmony_ci node_check = ScalarNode 68a5f9918aSopenharmony_ci elif node_check is list: 69a5f9918aSopenharmony_ci node_check = SequenceNode 70a5f9918aSopenharmony_ci elif node_check is dict: 71a5f9918aSopenharmony_ci node_check = MappingNode 72a5f9918aSopenharmony_ci elif node_check not in [ScalarNode, SequenceNode, MappingNode] \ 73a5f9918aSopenharmony_ci and not isinstance(node_check, str) \ 74a5f9918aSopenharmony_ci and node_check is not None: 75a5f9918aSopenharmony_ci raise ResolverError("Invalid node checker: %s" % node_check) 76a5f9918aSopenharmony_ci if not isinstance(index_check, (str, int)) \ 77a5f9918aSopenharmony_ci and index_check is not None: 78a5f9918aSopenharmony_ci raise ResolverError("Invalid index checker: %s" % index_check) 79a5f9918aSopenharmony_ci new_path.append((node_check, index_check)) 80a5f9918aSopenharmony_ci if kind is str: 81a5f9918aSopenharmony_ci kind = ScalarNode 82a5f9918aSopenharmony_ci elif kind is list: 83a5f9918aSopenharmony_ci kind = SequenceNode 84a5f9918aSopenharmony_ci elif kind is dict: 85a5f9918aSopenharmony_ci kind = MappingNode 86a5f9918aSopenharmony_ci elif kind not in [ScalarNode, SequenceNode, MappingNode] \ 87a5f9918aSopenharmony_ci and kind is not None: 88a5f9918aSopenharmony_ci raise ResolverError("Invalid node kind: %s" % kind) 89a5f9918aSopenharmony_ci cls.yaml_path_resolvers[tuple(new_path), kind] = tag 90a5f9918aSopenharmony_ci 91a5f9918aSopenharmony_ci def descend_resolver(self, current_node, current_index): 92a5f9918aSopenharmony_ci if not self.yaml_path_resolvers: 93a5f9918aSopenharmony_ci return 94a5f9918aSopenharmony_ci exact_paths = {} 95a5f9918aSopenharmony_ci prefix_paths = [] 96a5f9918aSopenharmony_ci if current_node: 97a5f9918aSopenharmony_ci depth = len(self.resolver_prefix_paths) 98a5f9918aSopenharmony_ci for path, kind in self.resolver_prefix_paths[-1]: 99a5f9918aSopenharmony_ci if self.check_resolver_prefix(depth, path, kind, 100a5f9918aSopenharmony_ci current_node, current_index): 101a5f9918aSopenharmony_ci if len(path) > depth: 102a5f9918aSopenharmony_ci prefix_paths.append((path, kind)) 103a5f9918aSopenharmony_ci else: 104a5f9918aSopenharmony_ci exact_paths[kind] = self.yaml_path_resolvers[path, kind] 105a5f9918aSopenharmony_ci else: 106a5f9918aSopenharmony_ci for path, kind in self.yaml_path_resolvers: 107a5f9918aSopenharmony_ci if not path: 108a5f9918aSopenharmony_ci exact_paths[kind] = self.yaml_path_resolvers[path, kind] 109a5f9918aSopenharmony_ci else: 110a5f9918aSopenharmony_ci prefix_paths.append((path, kind)) 111a5f9918aSopenharmony_ci self.resolver_exact_paths.append(exact_paths) 112a5f9918aSopenharmony_ci self.resolver_prefix_paths.append(prefix_paths) 113a5f9918aSopenharmony_ci 114a5f9918aSopenharmony_ci def ascend_resolver(self): 115a5f9918aSopenharmony_ci if not self.yaml_path_resolvers: 116a5f9918aSopenharmony_ci return 117a5f9918aSopenharmony_ci self.resolver_exact_paths.pop() 118a5f9918aSopenharmony_ci self.resolver_prefix_paths.pop() 119a5f9918aSopenharmony_ci 120a5f9918aSopenharmony_ci def check_resolver_prefix(self, depth, path, kind, 121a5f9918aSopenharmony_ci current_node, current_index): 122a5f9918aSopenharmony_ci node_check, index_check = path[depth-1] 123a5f9918aSopenharmony_ci if isinstance(node_check, str): 124a5f9918aSopenharmony_ci if current_node.tag != node_check: 125a5f9918aSopenharmony_ci return 126a5f9918aSopenharmony_ci elif node_check is not None: 127a5f9918aSopenharmony_ci if not isinstance(current_node, node_check): 128a5f9918aSopenharmony_ci return 129a5f9918aSopenharmony_ci if index_check is True and current_index is not None: 130a5f9918aSopenharmony_ci return 131a5f9918aSopenharmony_ci if (index_check is False or index_check is None) \ 132a5f9918aSopenharmony_ci and current_index is None: 133a5f9918aSopenharmony_ci return 134a5f9918aSopenharmony_ci if isinstance(index_check, str): 135a5f9918aSopenharmony_ci if not (isinstance(current_index, ScalarNode) 136a5f9918aSopenharmony_ci and index_check == current_index.value): 137a5f9918aSopenharmony_ci return 138a5f9918aSopenharmony_ci elif isinstance(index_check, int) and not isinstance(index_check, bool): 139a5f9918aSopenharmony_ci if index_check != current_index: 140a5f9918aSopenharmony_ci return 141a5f9918aSopenharmony_ci return True 142a5f9918aSopenharmony_ci 143a5f9918aSopenharmony_ci def resolve(self, kind, value, implicit): 144a5f9918aSopenharmony_ci if kind is ScalarNode and implicit[0]: 145a5f9918aSopenharmony_ci if value == '': 146a5f9918aSopenharmony_ci resolvers = self.yaml_implicit_resolvers.get('', []) 147a5f9918aSopenharmony_ci else: 148a5f9918aSopenharmony_ci resolvers = self.yaml_implicit_resolvers.get(value[0], []) 149a5f9918aSopenharmony_ci wildcard_resolvers = self.yaml_implicit_resolvers.get(None, []) 150a5f9918aSopenharmony_ci for tag, regexp in resolvers + wildcard_resolvers: 151a5f9918aSopenharmony_ci if regexp.match(value): 152a5f9918aSopenharmony_ci return tag 153a5f9918aSopenharmony_ci implicit = implicit[1] 154a5f9918aSopenharmony_ci if self.yaml_path_resolvers: 155a5f9918aSopenharmony_ci exact_paths = self.resolver_exact_paths[-1] 156a5f9918aSopenharmony_ci if kind in exact_paths: 157a5f9918aSopenharmony_ci return exact_paths[kind] 158a5f9918aSopenharmony_ci if None in exact_paths: 159a5f9918aSopenharmony_ci return exact_paths[None] 160a5f9918aSopenharmony_ci if kind is ScalarNode: 161a5f9918aSopenharmony_ci return self.DEFAULT_SCALAR_TAG 162a5f9918aSopenharmony_ci elif kind is SequenceNode: 163a5f9918aSopenharmony_ci return self.DEFAULT_SEQUENCE_TAG 164a5f9918aSopenharmony_ci elif kind is MappingNode: 165a5f9918aSopenharmony_ci return self.DEFAULT_MAPPING_TAG 166a5f9918aSopenharmony_ci 167a5f9918aSopenharmony_ciclass Resolver(BaseResolver): 168a5f9918aSopenharmony_ci pass 169a5f9918aSopenharmony_ci 170a5f9918aSopenharmony_ciResolver.add_implicit_resolver( 171a5f9918aSopenharmony_ci 'tag:yaml.org,2002:bool', 172a5f9918aSopenharmony_ci re.compile(r'''^(?:yes|Yes|YES|no|No|NO 173a5f9918aSopenharmony_ci |true|True|TRUE|false|False|FALSE 174a5f9918aSopenharmony_ci |on|On|ON|off|Off|OFF)$''', re.X), 175a5f9918aSopenharmony_ci list('yYnNtTfFoO')) 176a5f9918aSopenharmony_ci 177a5f9918aSopenharmony_ciResolver.add_implicit_resolver( 178a5f9918aSopenharmony_ci 'tag:yaml.org,2002:float', 179a5f9918aSopenharmony_ci re.compile(r'''^(?:[-+]?(?:[0-9][0-9_]*)\.[0-9_]*(?:[eE][-+][0-9]+)? 180a5f9918aSopenharmony_ci |\.[0-9][0-9_]*(?:[eE][-+][0-9]+)? 181a5f9918aSopenharmony_ci |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\.[0-9_]* 182a5f9918aSopenharmony_ci |[-+]?\.(?:inf|Inf|INF) 183a5f9918aSopenharmony_ci |\.(?:nan|NaN|NAN))$''', re.X), 184a5f9918aSopenharmony_ci list('-+0123456789.')) 185a5f9918aSopenharmony_ci 186a5f9918aSopenharmony_ciResolver.add_implicit_resolver( 187a5f9918aSopenharmony_ci 'tag:yaml.org,2002:int', 188a5f9918aSopenharmony_ci re.compile(r'''^(?:[-+]?0b[0-1_]+ 189a5f9918aSopenharmony_ci |[-+]?0[0-7_]+ 190a5f9918aSopenharmony_ci |[-+]?(?:0|[1-9][0-9_]*) 191a5f9918aSopenharmony_ci |[-+]?0x[0-9a-fA-F_]+ 192a5f9918aSopenharmony_ci |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$''', re.X), 193a5f9918aSopenharmony_ci list('-+0123456789')) 194a5f9918aSopenharmony_ci 195a5f9918aSopenharmony_ciResolver.add_implicit_resolver( 196a5f9918aSopenharmony_ci 'tag:yaml.org,2002:merge', 197a5f9918aSopenharmony_ci re.compile(r'^(?:<<)$'), 198a5f9918aSopenharmony_ci ['<']) 199a5f9918aSopenharmony_ci 200a5f9918aSopenharmony_ciResolver.add_implicit_resolver( 201a5f9918aSopenharmony_ci 'tag:yaml.org,2002:null', 202a5f9918aSopenharmony_ci re.compile(r'''^(?: ~ 203a5f9918aSopenharmony_ci |null|Null|NULL 204a5f9918aSopenharmony_ci | )$''', re.X), 205a5f9918aSopenharmony_ci ['~', 'n', 'N', '']) 206a5f9918aSopenharmony_ci 207a5f9918aSopenharmony_ciResolver.add_implicit_resolver( 208a5f9918aSopenharmony_ci 'tag:yaml.org,2002:timestamp', 209a5f9918aSopenharmony_ci re.compile(r'''^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] 210a5f9918aSopenharmony_ci |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]? 211a5f9918aSopenharmony_ci (?:[Tt]|[ \t]+)[0-9][0-9]? 212a5f9918aSopenharmony_ci :[0-9][0-9] :[0-9][0-9] (?:\.[0-9]*)? 213a5f9918aSopenharmony_ci (?:[ \t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$''', re.X), 214a5f9918aSopenharmony_ci list('0123456789')) 215a5f9918aSopenharmony_ci 216a5f9918aSopenharmony_ciResolver.add_implicit_resolver( 217a5f9918aSopenharmony_ci 'tag:yaml.org,2002:value', 218a5f9918aSopenharmony_ci re.compile(r'^(?:=)$'), 219a5f9918aSopenharmony_ci ['=']) 220a5f9918aSopenharmony_ci 221a5f9918aSopenharmony_ci# The following resolver is only for documentation purposes. It cannot work 222a5f9918aSopenharmony_ci# because plain scalars cannot start with '!', '&', or '*'. 223a5f9918aSopenharmony_ciResolver.add_implicit_resolver( 224a5f9918aSopenharmony_ci 'tag:yaml.org,2002:yaml', 225a5f9918aSopenharmony_ci re.compile(r'^(?:!|&|\*)$'), 226a5f9918aSopenharmony_ci list('!&*')) 227a5f9918aSopenharmony_ci 228