Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
resolver.py393 linesDownload Raw Back to yaml
1 2from __future__ import annotations3 4import re5 6if False:  # MYPY7    from typing import Any, Dict, List, Union, Text, Optional  # NOQA8    from ruamel.yaml.compat import VersionType  # NOQA9 10from ruamel.yaml.tag import Tag11from ruamel.yaml.compat import _DEFAULT_YAML_VERSION  # NOQA12from ruamel.yaml.error import *  # NOQA13from ruamel.yaml.nodes import MappingNode, ScalarNode, SequenceNode  # NOQA14from ruamel.yaml.util import RegExp  # NOQA15 16__all__ = ['BaseResolver', 'Resolver', 'VersionedResolver']17 18 19# fmt: off20# resolvers consist of21# - a list of applicable version22# - a tag23# - a regexp24# - a list of first characters to match25implicit_resolvers = [26    ([(1, 2)],27        'tag:yaml.org,2002:bool',28        RegExp('''^(?:true|True|TRUE|false|False|FALSE)$''', re.X),29        list('tTfF')),30    ([(1, 1)],31        'tag:yaml.org,2002:bool',32        RegExp('''^(?:y|Y|yes|Yes|YES|n|N|no|No|NO33        |true|True|TRUE|false|False|FALSE34        |on|On|ON|off|Off|OFF)$''', re.X),35        list('yYnNtTfFoO')),36    ([(1, 2)],37        'tag:yaml.org,2002:float',38        RegExp('''^(?:39         [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?40        |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)41        |[-+]?\\.[0-9_]+(?:[eE][-+][0-9]+)?42        |[-+]?\\.(?:inf|Inf|INF)43        |\\.(?:nan|NaN|NAN))$''', re.X),44        list('-+0123456789.')),45    ([(1, 1)],46        'tag:yaml.org,2002:float',47        RegExp('''^(?:48         [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?49        |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)50        |\\.[0-9_]+(?:[eE][-+][0-9]+)?51        |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*  # sexagesimal float52        |[-+]?\\.(?:inf|Inf|INF)53        |\\.(?:nan|NaN|NAN))$''', re.X),54        list('-+0123456789.')),55    ([(1, 2)],56        'tag:yaml.org,2002:int',57        RegExp('''^(?:[-+]?0b[0-1_]+58        |[-+]?0o?[0-7_]+59        |[-+]?[0-9_]+60        |[-+]?0x[0-9a-fA-F_]+)$''', re.X),61        list('-+0123456789')),62    ([(1, 1)],63        'tag:yaml.org,2002:int',64        RegExp('''^(?:[-+]?0b[0-1_]+65        |[-+]?0?[0-7_]+66        |[-+]?(?:0|[1-9][0-9_]*)67        |[-+]?0x[0-9a-fA-F_]+68        |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$''', re.X),  # sexagesimal int69        list('-+0123456789')),70    ([(1, 2), (1, 1)],71        'tag:yaml.org,2002:merge',72        RegExp('^(?:<<)$'),73        ['<']),74    ([(1, 2), (1, 1)],75        'tag:yaml.org,2002:null',76        RegExp('''^(?: ~77        |null|Null|NULL78        | )$''', re.X),79        ['~', 'n', 'N', '']),80    ([(1, 2), (1, 1)],81        'tag:yaml.org,2002:timestamp',82        RegExp('''^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]83        |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?84        (?:[Tt]|[ \\t]+)[0-9][0-9]?85        :[0-9][0-9] :[0-9][0-9] (?:\\.[0-9]*)?86        (?:[ \\t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$''', re.X),87        list('0123456789')),88    ([(1, 2), (1, 1)],89        'tag:yaml.org,2002:value',90        RegExp('^(?:=)$'),91        ['=']),92    # The following resolver is only for documentation purposes. It cannot work93    # because plain scalars cannot start with '!', '&', or '*'.94    ([(1, 2), (1, 1)],95        'tag:yaml.org,2002:yaml',96        RegExp('^(?:!|&|\\*)$'),97        list('!&*')),98]99# fmt: on100 101 102class ResolverError(YAMLError):103    pass104 105 106class BaseResolver:107 108    DEFAULT_SCALAR_TAG = Tag(suffix='tag:yaml.org,2002:str')109    DEFAULT_SEQUENCE_TAG = Tag(suffix='tag:yaml.org,2002:seq')110    DEFAULT_MAPPING_TAG = Tag(suffix='tag:yaml.org,2002:map')111 112    yaml_implicit_resolvers: Dict[Any, Any] = {}113    yaml_path_resolvers: Dict[Any, Any] = {}114 115    def __init__(self: Any, loadumper: Any = None) -> None:116        self.loadumper = loadumper117        if self.loadumper is not None and getattr(self.loadumper, '_resolver', None) is None:118            self.loadumper._resolver = self.loadumper119        self._loader_version: Any = None120        self.resolver_exact_paths: List[Any] = []121        self.resolver_prefix_paths: List[Any] = []122 123    @property124    def parser(self) -> Any:125        if self.loadumper is not None:126            if hasattr(self.loadumper, 'typ'):127                return self.loadumper.parser128            return self.loadumper._parser129        return None130 131    @classmethod132    def add_implicit_resolver_base(cls, tag: Any, regexp: Any, first: Any) -> None:133        if 'yaml_implicit_resolvers' not in cls.__dict__:134            # deepcopy doesn't work here135            cls.yaml_implicit_resolvers = {136                k: cls.yaml_implicit_resolvers[k][:] for k in cls.yaml_implicit_resolvers137            }138        if first is None:139            first = [None]140        for ch in first:141            cls.yaml_implicit_resolvers.setdefault(ch, []).append((tag, regexp))142 143    @classmethod144    def add_implicit_resolver(cls, tag: Any, regexp: Any, first: Any) -> None:145        if 'yaml_implicit_resolvers' not in cls.__dict__:146            # deepcopy doesn't work here147            cls.yaml_implicit_resolvers = {148                k: cls.yaml_implicit_resolvers[k][:] for k in cls.yaml_implicit_resolvers149            }150        if first is None:151            first = [None]152        for ch in first:153            cls.yaml_implicit_resolvers.setdefault(ch, []).append((tag, regexp))154        implicit_resolvers.append(([(1, 2), (1, 1)], tag, regexp, first))155 156    # @classmethod157    # def add_implicit_resolver(cls, tag, regexp, first):158 159    @classmethod160    def add_path_resolver(cls, tag: Any, path: Any, kind: Any = None) -> None:161        # Note: `add_path_resolver` is experimental.  The API could be changed.162        # `new_path` is a pattern that is matched against the path from the163        # root to the node that is being considered.  `node_path` elements are164        # tuples `(node_check, index_check)`.  `node_check` is a node class:165        # `ScalarNode`, `SequenceNode`, `MappingNode` or `None`.  `None`166        # matches any kind of a node.  `index_check` could be `None`, a boolean167        # value, a string value, or a number.  `None` and `False` match against168        # any _value_ of sequence and mapping nodes.  `True` matches against169        # any _key_ of a mapping node.  A string `index_check` matches against170        # a mapping value that corresponds to a scalar key which content is171        # equal to the `index_check` value.  An integer `index_check` matches172        # against a sequence value with the index equal to `index_check`.173        if 'yaml_path_resolvers' not in cls.__dict__:174            cls.yaml_path_resolvers = cls.yaml_path_resolvers.copy()175        new_path: List[Any] = []176        for element in path:177            if isinstance(element, (list, tuple)):178                if len(element) == 2:179                    node_check, index_check = element180                elif len(element) == 1:181                    node_check = element[0]182                    index_check = True183                else:184                    raise ResolverError(f'Invalid path element: {element!s}')185            else:186                node_check = None187                index_check = element188            if node_check is str:189                node_check = ScalarNode190            elif node_check is list:191                node_check = SequenceNode192            elif node_check is dict:193                node_check = MappingNode194            elif (195                node_check not in [ScalarNode, SequenceNode, MappingNode]196                and not isinstance(node_check, str)197                and node_check is not None198            ):199                raise ResolverError(f'Invalid node checker: {node_check!s}')200            if not isinstance(index_check, (str, int)) and index_check is not None:201                raise ResolverError(f'Invalid index checker: {index_check!s}')202            new_path.append((node_check, index_check))203        if kind is str:204            kind = ScalarNode205        elif kind is list:206            kind = SequenceNode207        elif kind is dict:208            kind = MappingNode209        elif kind not in [ScalarNode, SequenceNode, MappingNode] and kind is not None:210            raise ResolverError(f'Invalid node kind: {kind!s}')211        cls.yaml_path_resolvers[tuple(new_path), kind] = tag212 213    def descend_resolver(self, current_node: Any, current_index: Any) -> None:214        if not self.yaml_path_resolvers:215            return216        exact_paths = {}217        prefix_paths = []218        if current_node:219            depth = len(self.resolver_prefix_paths)220            for path, kind in self.resolver_prefix_paths[-1]:221                if self.check_resolver_prefix(depth, path, kind, current_node, current_index):222                    if len(path) > depth:223                        prefix_paths.append((path, kind))224                    else:225                        exact_paths[kind] = self.yaml_path_resolvers[path, kind]226        else:227            for path, kind in self.yaml_path_resolvers:228                if not path:229                    exact_paths[kind] = self.yaml_path_resolvers[path, kind]230                else:231                    prefix_paths.append((path, kind))232        self.resolver_exact_paths.append(exact_paths)233        self.resolver_prefix_paths.append(prefix_paths)234 235    def ascend_resolver(self) -> None:236        if not self.yaml_path_resolvers:237            return238        self.resolver_exact_paths.pop()239        self.resolver_prefix_paths.pop()240 241    def check_resolver_prefix(242        self, depth: int, path: Any, kind: Any, current_node: Any, current_index: Any,243    ) -> bool:244        node_check, index_check = path[depth - 1]245        if isinstance(node_check, str):246            if current_node.tag != node_check:247                return False248        elif node_check is not None:249            if not isinstance(current_node, node_check):250                return False251        if index_check is True and current_index is not None:252            return False253        if (index_check is False or index_check is None) and current_index is None:254            return False255        if isinstance(index_check, str):256            if not (257                isinstance(current_index, ScalarNode) and index_check == current_index.value258            ):259                return False260        elif isinstance(index_check, int) and not isinstance(index_check, bool):261            if index_check != current_index:262                return False263        return True264 265    def resolve(self, kind: Any, value: Any, implicit: Any) -> Any:266        if kind is ScalarNode and implicit[0]:267            if value == "":268                resolvers = self.yaml_implicit_resolvers.get("", [])269            else:270                resolvers = self.yaml_implicit_resolvers.get(value[0], [])271            resolvers += self.yaml_implicit_resolvers.get(None, [])272            for tag, regexp in resolvers:273                if regexp.match(value):274                    return Tag(suffix=tag)275            implicit = implicit[1]276        if bool(self.yaml_path_resolvers):277            exact_paths = self.resolver_exact_paths[-1]278            if kind in exact_paths:279                return Tag(suffix=exact_paths[kind])280            if None in exact_paths:281                return Tag(suffix=exact_paths[None])282        if kind is ScalarNode:283            return self.DEFAULT_SCALAR_TAG284        elif kind is SequenceNode:285            return self.DEFAULT_SEQUENCE_TAG286        elif kind is MappingNode:287            return self.DEFAULT_MAPPING_TAG288 289    @property290    def processing_version(self) -> Any:291        return None292 293 294class Resolver(BaseResolver):295    pass296 297 298for ir in implicit_resolvers:299    if (1, 2) in ir[0]:300        Resolver.add_implicit_resolver_base(*ir[1:])301 302 303class VersionedResolver(BaseResolver):304    """305    contrary to the "normal" resolver, the smart resolver delays loading306    the pattern matching rules. That way it can decide to load 1.1 rules307    or the (default) 1.2 rules, that no longer support octal without 0o, sexagesimals308    and Yes/No/On/Off booleans.309    """310 311    def __init__(312        self, version: Optional[VersionType] = None, loader: Any = None, loadumper: Any = None,313    ) -> None:314        if loader is None and loadumper is not None:315            loader = loadumper316        BaseResolver.__init__(self, loader)317        self._loader_version = self.get_loader_version(version)318        self._version_implicit_resolver: Dict[Any, Any] = {}319 320    def add_version_implicit_resolver(321        self, version: VersionType, tag: Any, regexp: Any, first: Any,322    ) -> None:323        if first is None:324            first = [None]325        impl_resolver = self._version_implicit_resolver.setdefault(version, {})326        for ch in first:327            impl_resolver.setdefault(ch, []).append((tag, regexp))328 329    def get_loader_version(self, version: Optional[VersionType]) -> Any:330        if version is None or isinstance(version, tuple):331            return version332        if isinstance(version, list):333            return tuple(version)334        # assume string335        assert isinstance(version, str)336        return tuple(map(int, version.split('.')))337 338    @property339    def versioned_resolver(self) -> Any:340        """341        select the resolver based on the version we are parsing342        """343        version = self.processing_version344        if isinstance(version, str):345            version = tuple(map(int, version.split('.')))346        if version not in self._version_implicit_resolver:347            for x in implicit_resolvers:348                if version in x[0]:349                    self.add_version_implicit_resolver(version, x[1], x[2], x[3])350        return self._version_implicit_resolver[version]351 352    def resolve(self, kind: Any, value: Any, implicit: Any) -> Any:353        if kind is ScalarNode and implicit[0]:354            if value == "":355                resolvers = self.versioned_resolver.get("", [])356            else:357                resolvers = self.versioned_resolver.get(value[0], [])358            resolvers += self.versioned_resolver.get(None, [])359            for tag, regexp in resolvers:360                if regexp.match(value):361                    return Tag(suffix=tag)362            implicit = implicit[1]363        if bool(self.yaml_path_resolvers):364            exact_paths = self.resolver_exact_paths[-1]365            if kind in exact_paths:366                return Tag(suffix=exact_paths[kind])367            if None in exact_paths:368                return Tag(suffix=exact_paths[None])369        if kind is ScalarNode:370            return self.DEFAULT_SCALAR_TAG371        elif kind is SequenceNode:372            return self.DEFAULT_SEQUENCE_TAG373        elif kind is MappingNode:374            return self.DEFAULT_MAPPING_TAG375 376    @property377    def processing_version(self) -> Any:378        try:379            version = self.loadumper._scanner.yaml_version380        except AttributeError:381            try:382                if hasattr(self.loadumper, 'typ'):383                    version = self.loadumper.version384                else:385                    version = self.loadumper._serializer.use_version  # dumping386            except AttributeError:387                version = None388        if version is None:389            version = self._loader_version390            if version is None:391                version = _DEFAULT_YAML_VERSION392        return version393 
codekingpro/portable-devtools · Team Ai