1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
__all__ = ['BaseResolver', 'Resolver', 'ResolverError']
from error import MarkedYAMLError
from nodes import *
import re
# Not really used.
class ResolverError(MarkedYAMLError):
pass
class BaseResolver:
DEFAULT_SCALAR_TAG = u'tag:yaml.org,2002:str'
DEFAULT_SEQUENCE_TAG = u'tag:yaml.org,2002:seq'
DEFAULT_MAPPING_TAG = u'tag:yaml.org,2002:map'
def __init__(self, composer):
self.composer = composer
self.resolved_nodes = {}
def check(self):
# If there are more documents available?
return self.composer.check()
def get(self):
# Resolve and return the root node of the next document.
if self.composer.check():
return self.resolve_document(self.composer.get())
def __iter__(self):
# Iterator protocol.
while self.composer.check():
yield self.resolve_document(self.composer.get())
def resolve_document(self, node):
self.resolve_node([], node)
return node
self.resolved_nodes = {}
def resolve_node(self, path, node):
if node in self.resolved_nodes:
return
self.resolved_nodes[node] = None
if isinstance(node, ScalarNode):
self.resolve_scalar(path, node)
elif isinstance(node, SequenceNode):
self.resolve_sequence(path, node)
for index in range(len(node.value)):
self.resolve_node(path+[(node, index)], node.value[index])
elif isinstance(node, MappingNode):
self.resolve_mapping(path, node)
for key in node.value:
self.resolve_node(path+[node, None], key)
self.resolve_node(path+[node, key], node.value[key])
def resolve_scalar(self, path, node):
if node.tag is None:
node.tag = self.detect_scalar(node.value)
if node.tag is None or node.tag == u'!':
node.tag = self.DEFAULT_SCALAR_TAG
def resolve_sequence(self, path, node):
if node.tag is None or node.tag == u'!':
node.tag = self.DEFAULT_SEQUENCE_TAG
def resolve_mapping(self, path, node):
if node.tag is None or node.tag == u'!':
node.tag = self.DEFAULT_MAPPING_TAG
def detect_scalar(self, value):
if value == u'':
detectors = self.yaml_detectors.get(u'', [])
else:
detectors = self.yaml_detectors.get(value[0], [])
detectors += self.yaml_detectors.get(None, [])
for tag, regexp in detectors:
if regexp.match(value):
return tag
def add_detector(cls, tag, regexp, first):
if not 'yaml_detectors' in cls.__dict__:
cls.yaml_detectors = cls.yaml_detectors.copy()
for ch in first:
cls.yaml_detectors.setdefault(ch, []).append((tag, regexp))
add_detector = classmethod(add_detector)
yaml_detectors = {}
class Resolver(BaseResolver):
pass
Resolver.add_detector(
u'tag:yaml.org,2002:bool',
re.compile(ur'''^(?:y|Y|yes|Yes|YES|n|N|no|No|NO
|true|True|TRUE|false|False|FALSE
|on|On|ON|off|Off|OFF)$''', re.X),
list(u'yYnNtTfFoO'))
Resolver.add_detector(
u'tag:yaml.org,2002:float',
re.compile(ur'''^(?:[-+]?(?:[0-9][0-9_]*)?\.[0-9_]*(?:[eE][-+][0-9]+)?
|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\.[0-9_]*
|[-+]?\.(?:inf|Inf|INF)
|\.(?:nan|NaN|NAN))$''', re.X),
list(u'-+0123456789.'))
Resolver.add_detector(
u'tag:yaml.org,2002:int',
re.compile(ur'''^(?:[-+]?0b[0-1_]+
|[-+]?0[0-7_]+
|[-+]?(?:0|[1-9][0-9_]*)
|[-+]?0x[0-9a-fA-F_]+
|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$''', re.X),
list(u'-+0123456789'))
Resolver.add_detector(
u'tag:yaml.org,2002:merge',
re.compile(ur'^(?:<<)$'),
['<'])
Resolver.add_detector(
u'tag:yaml.org,2002:null',
re.compile(ur'''^(?: ~
|null|Null|NULL
| )$''', re.X),
[u'~', u'n', u'N', u''])
Resolver.add_detector(
u'tag:yaml.org,2002:timestamp',
re.compile(ur'''^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]
|[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?
(?:[Tt]|[ \t]+)[0-9][0-9]?
:[0-9][0-9] :[0-9][0-9] (?:\.[0-9]*)?
(?:[ \t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$''', re.X),
list(u'0123456789'))
Resolver.add_detector(
u'tag:yaml.org,2002:value',
re.compile(ur'^(?:=)$'),
['='])
# The following detector is only for documentation purposes. It cannot work
# because plain scalars cannot start with '!', '&', or '*'.
Resolver.add_detector(
u'tag:yaml.org,2002:yaml',
re.compile(ur'^(?:!|&|\*)$'),
list(u'!&*'))
|