|
|
|
from __future__ import absolute_import
|
|
|
|
_H='yaml_implicit_resolvers'
|
|
|
|
_G='-+0123456789'
|
|
|
|
_F='tag:yaml.org,2002:int'
|
|
|
|
_E='-+0123456789.'
|
|
|
|
_D='tag:yaml.org,2002:float'
|
|
|
|
_C='tag:yaml.org,2002:bool'
|
|
|
|
_B=False
|
|
|
|
_A=None
|
|
|
|
import re
|
|
|
|
if _B:from typing import Any,Dict,List,Union,Text,Optional;from.compat import VersionType
|
|
|
|
from.compat import string_types,_DEFAULT_YAML_VERSION
|
|
|
|
from.error import*
|
|
|
|
from.nodes import MappingNode,ScalarNode,SequenceNode
|
|
|
|
from.util import RegExp
|
|
|
|
__all__=['BaseResolver','Resolver','VersionedResolver']
|
|
|
|
implicit_resolvers=[([(1,2)],_C,RegExp('^(?:true|True|TRUE|false|False|FALSE)$',re.X),list('tTfF')),([(1,1)],_C,RegExp('^(?:y|Y|yes|Yes|YES|n|N|no|No|NO\n |true|True|TRUE|false|False|FALSE\n |on|On|ON|off|Off|OFF)$',re.X),list('yYnNtTfFoO')),([(1,2)],_D,RegExp('^(?:\n [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?\n |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)\n |[-+]?\\.[0-9_]+(?:[eE][-+][0-9]+)?\n |[-+]?\\.(?:inf|Inf|INF)\n |\\.(?:nan|NaN|NAN))$',re.X),list(_E)),([(1,1)],_D,RegExp('^(?:\n [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?\n |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)\n |\\.[0-9_]+(?:[eE][-+][0-9]+)?\n |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]* # sexagesimal float\n |[-+]?\\.(?:inf|Inf|INF)\n |\\.(?:nan|NaN|NAN))$',re.X),list(_E)),([(1,2)],_F,RegExp('^(?:[-+]?0b[0-1_]+\n |[-+]?0o?[0-7_]+\n |[-+]?[0-9_]+\n |[-+]?0x[0-9a-fA-F_]+)$',re.X),list(_G)),([(1,1)],_F,RegExp('^(?:[-+]?0b[0-1_]+\n |[-+]?0?[0-7_]+\n |[-+]?(?:0|[1-9][0-9_]*)\n |[-+]?0x[0-9a-fA-F_]+\n |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$',re.X),list(_G)),([(1,2),(1,1)],'tag:yaml.org,2002:merge',RegExp('^(?:<<)$'),['<']),([(1,2),(1,1)],'tag:yaml.org,2002:null',RegExp('^(?: ~\n |null|Null|NULL\n | )$',re.X),['~','n','N','']),([(1,2),(1,1)],'tag:yaml.org,2002:timestamp',RegExp('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n (?:[Tt]|[ \\t]+)[0-9][0-9]?\n :[0-9][0-9] :[0-9][0-9] (?:\\.[0-9]*)?\n (?:[ \\t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$',re.X),list('0123456789')),([(1,2),(1,1)],'tag:yaml.org,2002:value',RegExp('^(?:=)$'),['=']),([(1,2),(1,1)],'tag:yaml.org,2002:yaml',RegExp('^(?:!|&|\\*)$'),list('!&*'))]
|
|
|
|
class ResolverError(YAMLError):0
|
|
|
|
class BaseResolver:
|
|
|
|
DEFAULT_SCALAR_TAG='tag:yaml.org,2002:str';DEFAULT_SEQUENCE_TAG='tag:yaml.org,2002:seq';DEFAULT_MAPPING_TAG='tag:yaml.org,2002:map';yaml_implicit_resolvers={};yaml_path_resolvers={}
|
|
|
|
def __init__(self,loadumper=_A):
|
|
|
|
self.loadumper=loadumper
|
|
|
|
if self.loadumper is not _A and getattr(self.loadumper,'_resolver',_A)is _A:self.loadumper._resolver=self.loadumper
|
|
|
|
self._loader_version=_A;self.resolver_exact_paths=[];self.resolver_prefix_paths=[]
|
|
|
|
@property
|
|
|
|
def parser(self):
|
|
|
|
if self.loadumper is not _A:
|
|
|
|
if hasattr(self.loadumper,'typ'):return self.loadumper.parser
|
|
|
|
return self.loadumper._parser
|
|
|
|
@classmethod
|
|
|
|
def add_implicit_resolver_base(cls,tag,regexp,first):
|
|
|
|
if _H not in cls.__dict__:cls.yaml_implicit_resolvers=dict((k,cls.yaml_implicit_resolvers[k][:])for k in cls.yaml_implicit_resolvers)
|
|
|
|
if first is _A:first=[_A]
|
|
|
|
for ch in first:cls.yaml_implicit_resolvers.setdefault(ch,[]).append((tag,regexp))
|
|
|
|
@classmethod
|
|
|
|
def add_implicit_resolver(cls,tag,regexp,first):
|
|
|
|
if _H not in cls.__dict__:cls.yaml_implicit_resolvers=dict((k,cls.yaml_implicit_resolvers[k][:])for k in cls.yaml_implicit_resolvers)
|
|
|
|
if first is _A:first=[_A]
|
|
|
|
for ch in first:cls.yaml_implicit_resolvers.setdefault(ch,[]).append((tag,regexp))
|
|
|
|
implicit_resolvers.append(([(1,2),(1,1)],tag,regexp,first))
|
|
|
|
@classmethod
|
|
|
|
def add_path_resolver(cls,tag,path,kind=_A):
|
|
|
|
if'yaml_path_resolvers'not in cls.__dict__:cls.yaml_path_resolvers=cls.yaml_path_resolvers.copy()
|
|
|
|
new_path=[]
|
|
|
|
for element in path:
|
|
|
|
if isinstance(element,(list,tuple)):
|
|
|
|
if len(element)==2:node_check,index_check=element
|
|
|
|
elif len(element)==1:node_check=element[0];index_check=True
|
|
|
|
else:raise ResolverError('Invalid path element: %s'%(element,))
|
|
|
|
else:node_check=_A;index_check=element
|
|
|
|
if node_check is str:node_check=ScalarNode
|
|
|
|
elif node_check is list:node_check=SequenceNode
|
|
|
|
elif node_check is dict:node_check=MappingNode
|
|
|
|
elif node_check not in[ScalarNode,SequenceNode,MappingNode]and not isinstance(node_check,string_types)and node_check is not _A:raise ResolverError('Invalid node checker: %s'%(node_check,))
|
|
|
|
if not isinstance(index_check,(string_types,int))and index_check is not _A:raise ResolverError('Invalid index checker: %s'%(index_check,))
|
|
|
|
new_path.append((node_check,index_check))
|
|
|
|
if kind is str:kind=ScalarNode
|
|
|
|
elif kind is list:kind=SequenceNode
|
|
|
|
elif kind is dict:kind=MappingNode
|
|
|
|
elif kind not in[ScalarNode,SequenceNode,MappingNode]and kind is not _A:raise ResolverError('Invalid node kind: %s'%(kind,))
|
|
|
|
cls.yaml_path_resolvers[tuple(new_path),kind]=tag
|
|
|
|
def descend_resolver(self,current_node,current_index):
|
|
|
|
if not self.yaml_path_resolvers:return
|
|
|
|
exact_paths={};prefix_paths=[]
|
|
|
|
if current_node:
|
|
|
|
depth=len(self.resolver_prefix_paths)
|
|
|
|
for(path,kind)in self.resolver_prefix_paths[-1]:
|
|
|
|
if self.check_resolver_prefix(depth,path,kind,current_node,current_index):
|
|
|
|
if len(path)>depth:prefix_paths.append((path,kind))
|
|
|
|
else:exact_paths[kind]=self.yaml_path_resolvers[path,kind]
|
|
|
|
else:
|
|
|
|
for(path,kind)in self.yaml_path_resolvers:
|
|
|
|
if not path:exact_paths[kind]=self.yaml_path_resolvers[path,kind]
|
|
|
|
else:prefix_paths.append((path,kind))
|
|
|
|
self.resolver_exact_paths.append(exact_paths);self.resolver_prefix_paths.append(prefix_paths)
|
|
|
|
def ascend_resolver(self):
|
|
|
|
if not self.yaml_path_resolvers:return
|
|
|
|
self.resolver_exact_paths.pop();self.resolver_prefix_paths.pop()
|
|
|
|
def check_resolver_prefix(self,depth,path,kind,current_node,current_index):
|
|
|
|
node_check,index_check=path[depth-1]
|
|
|
|
if isinstance(node_check,string_types):
|
|
|
|
if current_node.tag!=node_check:return _B
|
|
|
|
elif node_check is not _A:
|
|
|
|
if not isinstance(current_node,node_check):return _B
|
|
|
|
if index_check is True and current_index is not _A:return _B
|
|
|
|
if(index_check is _B or index_check is _A)and current_index is _A:return _B
|
|
|
|
if isinstance(index_check,string_types):
|
|
|
|
if not(isinstance(current_index,ScalarNode)and index_check==current_index.value):return _B
|
|
|
|
elif isinstance(index_check,int)and not isinstance(index_check,bool):
|
|
|
|
if index_check!=current_index:return _B
|
|
|
|
return True
|
|
|
|
def resolve(self,kind,value,implicit):
|
|
|
|
if kind is ScalarNode and implicit[0]:
|
|
|
|
if value=='':resolvers=self.yaml_implicit_resolvers.get('',[])
|
|
|
|
else:resolvers=self.yaml_implicit_resolvers.get(value[0],[])
|
|
|
|
resolvers+=self.yaml_implicit_resolvers.get(_A,[])
|
|
|
|
for(tag,regexp)in resolvers:
|
|
|
|
if regexp.match(value):return tag
|
|
|
|
implicit=implicit[1]
|
|
|
|
if bool(self.yaml_path_resolvers):
|
|
|
|
exact_paths=self.resolver_exact_paths[-1]
|
|
|
|
if kind in exact_paths:return exact_paths[kind]
|
|
|
|
if _A in exact_paths:return exact_paths[_A]
|
|
|
|
if kind is ScalarNode:return self.DEFAULT_SCALAR_TAG
|
|
|
|
elif kind is SequenceNode:return self.DEFAULT_SEQUENCE_TAG
|
|
|
|
elif kind is MappingNode:return self.DEFAULT_MAPPING_TAG
|
|
|
|
@property
|
|
|
|
def processing_version(self):0
|
|
|
|
class Resolver(BaseResolver):0
|
|
|
|
for ir in implicit_resolvers:
|
|
|
|
if(1,2)in ir[0]:Resolver.add_implicit_resolver_base(*ir[1:])
|
|
|
|
class VersionedResolver(BaseResolver):
|
|
|
|
def __init__(self,version=_A,loader=_A,loadumper=_A):
|
|
|
|
if loader is _A and loadumper is not _A:loader=loadumper
|
|
|
|
BaseResolver.__init__(self,loader);self._loader_version=self.get_loader_version(version);self._version_implicit_resolver={}
|
|
|
|
def add_version_implicit_resolver(self,version,tag,regexp,first):
|
|
|
|
if first is _A:first=[_A]
|
|
|
|
impl_resolver=self._version_implicit_resolver.setdefault(version,{})
|
|
|
|
for ch in first:impl_resolver.setdefault(ch,[]).append((tag,regexp))
|
|
|
|
def get_loader_version(self,version):
|
|
|
|
if version is _A or isinstance(version,tuple):return version
|
|
|
|
if isinstance(version,list):return tuple(version)
|
|
|
|
return tuple(map(int,version.split('.')))
|
|
|
|
@property
|
|
|
|
def versioned_resolver(self):
|
|
|
|
version=self.processing_version
|
|
|
|
if version not in self._version_implicit_resolver:
|
|
|
|
for x in implicit_resolvers:
|
|
|
|
if version in x[0]:self.add_version_implicit_resolver(version,x[1],x[2],x[3])
|
|
|
|
return self._version_implicit_resolver[version]
|
|
|
|
def resolve(self,kind,value,implicit):
|
|
|
|
if kind is ScalarNode and implicit[0]:
|
|
|
|
if value=='':resolvers=self.versioned_resolver.get('',[])
|
|
|
|
else:resolvers=self.versioned_resolver.get(value[0],[])
|
|
|
|
resolvers+=self.versioned_resolver.get(_A,[])
|
|
|
|
for(tag,regexp)in resolvers:
|
|
|
|
if regexp.match(value):return tag
|
|
|
|
implicit=implicit[1]
|
|
|
|
if bool(self.yaml_path_resolvers):
|
|
|
|
exact_paths=self.resolver_exact_paths[-1]
|
|
|
|
if kind in exact_paths:return exact_paths[kind]
|
|
|
|
if _A in exact_paths:return exact_paths[_A]
|
|
|
|
if kind is ScalarNode:return self.DEFAULT_SCALAR_TAG
|
|
|
|
elif kind is SequenceNode:return self.DEFAULT_SEQUENCE_TAG
|
|
|
|
elif kind is MappingNode:return self.DEFAULT_MAPPING_TAG
|
|
|
|
@property
|
|
|
|
def processing_version(self):
|
|
|
|
try:version=self.loadumper._scanner.yaml_version
|
|
|
|
except AttributeError:
|
|
|
|
try:
|
|
|
|
if hasattr(self.loadumper,'typ'):version=self.loadumper.version
|
|
|
|
else:version=self.loadumper._serializer.use_version
|
|
|
|
except AttributeError:version=_A
|
|
|
|
if version is _A:
|
|
|
|
version=self._loader_version
|
|
|
|
if version is _A:version=_DEFAULT_YAML_VERSION
|
|
|
|
return version
|