outerbounds 0.3.68__py3-none-any.whl → 0.3.104__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- outerbounds/_vendor/PyYAML.LICENSE +20 -0
- outerbounds/_vendor/__init__.py +0 -0
- outerbounds/_vendor/_yaml/__init__.py +34 -0
- outerbounds/_vendor/click/__init__.py +73 -0
- outerbounds/_vendor/click/_compat.py +626 -0
- outerbounds/_vendor/click/_termui_impl.py +717 -0
- outerbounds/_vendor/click/_textwrap.py +49 -0
- outerbounds/_vendor/click/_winconsole.py +279 -0
- outerbounds/_vendor/click/core.py +2998 -0
- outerbounds/_vendor/click/decorators.py +497 -0
- outerbounds/_vendor/click/exceptions.py +287 -0
- outerbounds/_vendor/click/formatting.py +301 -0
- outerbounds/_vendor/click/globals.py +68 -0
- outerbounds/_vendor/click/parser.py +529 -0
- outerbounds/_vendor/click/py.typed +0 -0
- outerbounds/_vendor/click/shell_completion.py +580 -0
- outerbounds/_vendor/click/termui.py +787 -0
- outerbounds/_vendor/click/testing.py +479 -0
- outerbounds/_vendor/click/types.py +1073 -0
- outerbounds/_vendor/click/utils.py +580 -0
- outerbounds/_vendor/click.LICENSE +28 -0
- outerbounds/_vendor/vendor_any.txt +2 -0
- outerbounds/_vendor/yaml/__init__.py +471 -0
- outerbounds/_vendor/yaml/_yaml.cpython-311-darwin.so +0 -0
- outerbounds/_vendor/yaml/composer.py +146 -0
- outerbounds/_vendor/yaml/constructor.py +862 -0
- outerbounds/_vendor/yaml/cyaml.py +177 -0
- outerbounds/_vendor/yaml/dumper.py +138 -0
- outerbounds/_vendor/yaml/emitter.py +1239 -0
- outerbounds/_vendor/yaml/error.py +94 -0
- outerbounds/_vendor/yaml/events.py +104 -0
- outerbounds/_vendor/yaml/loader.py +62 -0
- outerbounds/_vendor/yaml/nodes.py +51 -0
- outerbounds/_vendor/yaml/parser.py +629 -0
- outerbounds/_vendor/yaml/reader.py +208 -0
- outerbounds/_vendor/yaml/representer.py +378 -0
- outerbounds/_vendor/yaml/resolver.py +245 -0
- outerbounds/_vendor/yaml/scanner.py +1555 -0
- outerbounds/_vendor/yaml/serializer.py +127 -0
- outerbounds/_vendor/yaml/tokens.py +129 -0
- outerbounds/command_groups/apps_cli.py +586 -0
- outerbounds/command_groups/cli.py +9 -5
- outerbounds/command_groups/local_setup_cli.py +1 -5
- outerbounds/command_groups/perimeters_cli.py +198 -25
- outerbounds/command_groups/tutorials_cli.py +111 -0
- outerbounds/command_groups/workstations_cli.py +2 -2
- outerbounds/utils/kubeconfig.py +2 -2
- outerbounds/utils/metaflowconfig.py +68 -9
- outerbounds/utils/schema.py +2 -2
- outerbounds/utils/utils.py +19 -0
- outerbounds/vendor.py +159 -0
- {outerbounds-0.3.68.dist-info → outerbounds-0.3.104.dist-info}/METADATA +14 -7
- outerbounds-0.3.104.dist-info/RECORD +59 -0
- {outerbounds-0.3.68.dist-info → outerbounds-0.3.104.dist-info}/WHEEL +1 -1
- outerbounds-0.3.68.dist-info/RECORD +0 -15
- {outerbounds-0.3.68.dist-info → outerbounds-0.3.104.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,862 @@
|
|
1
|
+
__all__ = [
|
2
|
+
"BaseConstructor",
|
3
|
+
"SafeConstructor",
|
4
|
+
"FullConstructor",
|
5
|
+
"UnsafeConstructor",
|
6
|
+
"Constructor",
|
7
|
+
"ConstructorError",
|
8
|
+
]
|
9
|
+
|
10
|
+
from .error import *
|
11
|
+
from .nodes import *
|
12
|
+
|
13
|
+
import collections.abc, datetime, base64, binascii, re, sys, types
|
14
|
+
|
15
|
+
|
16
|
+
class ConstructorError(MarkedYAMLError):
|
17
|
+
pass
|
18
|
+
|
19
|
+
|
20
|
+
class BaseConstructor:
|
21
|
+
|
22
|
+
yaml_constructors = {}
|
23
|
+
yaml_multi_constructors = {}
|
24
|
+
|
25
|
+
def __init__(self):
|
26
|
+
self.constructed_objects = {}
|
27
|
+
self.recursive_objects = {}
|
28
|
+
self.state_generators = []
|
29
|
+
self.deep_construct = False
|
30
|
+
|
31
|
+
def check_data(self):
|
32
|
+
# If there are more documents available?
|
33
|
+
return self.check_node()
|
34
|
+
|
35
|
+
def check_state_key(self, key):
|
36
|
+
"""Block special attributes/methods from being set in a newly created
|
37
|
+
object, to prevent user-controlled methods from being called during
|
38
|
+
deserialization"""
|
39
|
+
if self.get_state_keys_blacklist_regexp().match(key):
|
40
|
+
raise ConstructorError(
|
41
|
+
None,
|
42
|
+
None,
|
43
|
+
"blacklisted key '%s' in instance state found" % (key,),
|
44
|
+
None,
|
45
|
+
)
|
46
|
+
|
47
|
+
def get_data(self):
|
48
|
+
# Construct and return the next document.
|
49
|
+
if self.check_node():
|
50
|
+
return self.construct_document(self.get_node())
|
51
|
+
|
52
|
+
def get_single_data(self):
|
53
|
+
# Ensure that the stream contains a single document and construct it.
|
54
|
+
node = self.get_single_node()
|
55
|
+
if node is not None:
|
56
|
+
return self.construct_document(node)
|
57
|
+
return None
|
58
|
+
|
59
|
+
def construct_document(self, node):
|
60
|
+
data = self.construct_object(node)
|
61
|
+
while self.state_generators:
|
62
|
+
state_generators = self.state_generators
|
63
|
+
self.state_generators = []
|
64
|
+
for generator in state_generators:
|
65
|
+
for dummy in generator:
|
66
|
+
pass
|
67
|
+
self.constructed_objects = {}
|
68
|
+
self.recursive_objects = {}
|
69
|
+
self.deep_construct = False
|
70
|
+
return data
|
71
|
+
|
72
|
+
def construct_object(self, node, deep=False):
|
73
|
+
if node in self.constructed_objects:
|
74
|
+
return self.constructed_objects[node]
|
75
|
+
if deep:
|
76
|
+
old_deep = self.deep_construct
|
77
|
+
self.deep_construct = True
|
78
|
+
if node in self.recursive_objects:
|
79
|
+
raise ConstructorError(
|
80
|
+
None, None, "found unconstructable recursive node", node.start_mark
|
81
|
+
)
|
82
|
+
self.recursive_objects[node] = None
|
83
|
+
constructor = None
|
84
|
+
tag_suffix = None
|
85
|
+
if node.tag in self.yaml_constructors:
|
86
|
+
constructor = self.yaml_constructors[node.tag]
|
87
|
+
else:
|
88
|
+
for tag_prefix in self.yaml_multi_constructors:
|
89
|
+
if tag_prefix is not None and node.tag.startswith(tag_prefix):
|
90
|
+
tag_suffix = node.tag[len(tag_prefix) :]
|
91
|
+
constructor = self.yaml_multi_constructors[tag_prefix]
|
92
|
+
break
|
93
|
+
else:
|
94
|
+
if None in self.yaml_multi_constructors:
|
95
|
+
tag_suffix = node.tag
|
96
|
+
constructor = self.yaml_multi_constructors[None]
|
97
|
+
elif None in self.yaml_constructors:
|
98
|
+
constructor = self.yaml_constructors[None]
|
99
|
+
elif isinstance(node, ScalarNode):
|
100
|
+
constructor = self.__class__.construct_scalar
|
101
|
+
elif isinstance(node, SequenceNode):
|
102
|
+
constructor = self.__class__.construct_sequence
|
103
|
+
elif isinstance(node, MappingNode):
|
104
|
+
constructor = self.__class__.construct_mapping
|
105
|
+
if tag_suffix is None:
|
106
|
+
data = constructor(self, node)
|
107
|
+
else:
|
108
|
+
data = constructor(self, tag_suffix, node)
|
109
|
+
if isinstance(data, types.GeneratorType):
|
110
|
+
generator = data
|
111
|
+
data = next(generator)
|
112
|
+
if self.deep_construct:
|
113
|
+
for dummy in generator:
|
114
|
+
pass
|
115
|
+
else:
|
116
|
+
self.state_generators.append(generator)
|
117
|
+
self.constructed_objects[node] = data
|
118
|
+
del self.recursive_objects[node]
|
119
|
+
if deep:
|
120
|
+
self.deep_construct = old_deep
|
121
|
+
return data
|
122
|
+
|
123
|
+
def construct_scalar(self, node):
|
124
|
+
if not isinstance(node, ScalarNode):
|
125
|
+
raise ConstructorError(
|
126
|
+
None,
|
127
|
+
None,
|
128
|
+
"expected a scalar node, but found %s" % node.id,
|
129
|
+
node.start_mark,
|
130
|
+
)
|
131
|
+
return node.value
|
132
|
+
|
133
|
+
def construct_sequence(self, node, deep=False):
|
134
|
+
if not isinstance(node, SequenceNode):
|
135
|
+
raise ConstructorError(
|
136
|
+
None,
|
137
|
+
None,
|
138
|
+
"expected a sequence node, but found %s" % node.id,
|
139
|
+
node.start_mark,
|
140
|
+
)
|
141
|
+
return [self.construct_object(child, deep=deep) for child in node.value]
|
142
|
+
|
143
|
+
def construct_mapping(self, node, deep=False):
|
144
|
+
if not isinstance(node, MappingNode):
|
145
|
+
raise ConstructorError(
|
146
|
+
None,
|
147
|
+
None,
|
148
|
+
"expected a mapping node, but found %s" % node.id,
|
149
|
+
node.start_mark,
|
150
|
+
)
|
151
|
+
mapping = {}
|
152
|
+
for key_node, value_node in node.value:
|
153
|
+
key = self.construct_object(key_node, deep=deep)
|
154
|
+
if not isinstance(key, collections.abc.Hashable):
|
155
|
+
raise ConstructorError(
|
156
|
+
"while constructing a mapping",
|
157
|
+
node.start_mark,
|
158
|
+
"found unhashable key",
|
159
|
+
key_node.start_mark,
|
160
|
+
)
|
161
|
+
value = self.construct_object(value_node, deep=deep)
|
162
|
+
mapping[key] = value
|
163
|
+
return mapping
|
164
|
+
|
165
|
+
def construct_pairs(self, node, deep=False):
|
166
|
+
if not isinstance(node, MappingNode):
|
167
|
+
raise ConstructorError(
|
168
|
+
None,
|
169
|
+
None,
|
170
|
+
"expected a mapping node, but found %s" % node.id,
|
171
|
+
node.start_mark,
|
172
|
+
)
|
173
|
+
pairs = []
|
174
|
+
for key_node, value_node in node.value:
|
175
|
+
key = self.construct_object(key_node, deep=deep)
|
176
|
+
value = self.construct_object(value_node, deep=deep)
|
177
|
+
pairs.append((key, value))
|
178
|
+
return pairs
|
179
|
+
|
180
|
+
@classmethod
|
181
|
+
def add_constructor(cls, tag, constructor):
|
182
|
+
if not "yaml_constructors" in cls.__dict__:
|
183
|
+
cls.yaml_constructors = cls.yaml_constructors.copy()
|
184
|
+
cls.yaml_constructors[tag] = constructor
|
185
|
+
|
186
|
+
@classmethod
|
187
|
+
def add_multi_constructor(cls, tag_prefix, multi_constructor):
|
188
|
+
if not "yaml_multi_constructors" in cls.__dict__:
|
189
|
+
cls.yaml_multi_constructors = cls.yaml_multi_constructors.copy()
|
190
|
+
cls.yaml_multi_constructors[tag_prefix] = multi_constructor
|
191
|
+
|
192
|
+
|
193
|
+
class SafeConstructor(BaseConstructor):
|
194
|
+
def construct_scalar(self, node):
|
195
|
+
if isinstance(node, MappingNode):
|
196
|
+
for key_node, value_node in node.value:
|
197
|
+
if key_node.tag == "tag:yaml.org,2002:value":
|
198
|
+
return self.construct_scalar(value_node)
|
199
|
+
return super().construct_scalar(node)
|
200
|
+
|
201
|
+
def flatten_mapping(self, node):
|
202
|
+
merge = []
|
203
|
+
index = 0
|
204
|
+
while index < len(node.value):
|
205
|
+
key_node, value_node = node.value[index]
|
206
|
+
if key_node.tag == "tag:yaml.org,2002:merge":
|
207
|
+
del node.value[index]
|
208
|
+
if isinstance(value_node, MappingNode):
|
209
|
+
self.flatten_mapping(value_node)
|
210
|
+
merge.extend(value_node.value)
|
211
|
+
elif isinstance(value_node, SequenceNode):
|
212
|
+
submerge = []
|
213
|
+
for subnode in value_node.value:
|
214
|
+
if not isinstance(subnode, MappingNode):
|
215
|
+
raise ConstructorError(
|
216
|
+
"while constructing a mapping",
|
217
|
+
node.start_mark,
|
218
|
+
"expected a mapping for merging, but found %s"
|
219
|
+
% subnode.id,
|
220
|
+
subnode.start_mark,
|
221
|
+
)
|
222
|
+
self.flatten_mapping(subnode)
|
223
|
+
submerge.append(subnode.value)
|
224
|
+
submerge.reverse()
|
225
|
+
for value in submerge:
|
226
|
+
merge.extend(value)
|
227
|
+
else:
|
228
|
+
raise ConstructorError(
|
229
|
+
"while constructing a mapping",
|
230
|
+
node.start_mark,
|
231
|
+
"expected a mapping or list of mappings for merging, but found %s"
|
232
|
+
% value_node.id,
|
233
|
+
value_node.start_mark,
|
234
|
+
)
|
235
|
+
elif key_node.tag == "tag:yaml.org,2002:value":
|
236
|
+
key_node.tag = "tag:yaml.org,2002:str"
|
237
|
+
index += 1
|
238
|
+
else:
|
239
|
+
index += 1
|
240
|
+
if merge:
|
241
|
+
node.value = merge + node.value
|
242
|
+
|
243
|
+
def construct_mapping(self, node, deep=False):
|
244
|
+
if isinstance(node, MappingNode):
|
245
|
+
self.flatten_mapping(node)
|
246
|
+
return super().construct_mapping(node, deep=deep)
|
247
|
+
|
248
|
+
def construct_yaml_null(self, node):
|
249
|
+
self.construct_scalar(node)
|
250
|
+
return None
|
251
|
+
|
252
|
+
bool_values = {
|
253
|
+
"yes": True,
|
254
|
+
"no": False,
|
255
|
+
"true": True,
|
256
|
+
"false": False,
|
257
|
+
"on": True,
|
258
|
+
"off": False,
|
259
|
+
}
|
260
|
+
|
261
|
+
def construct_yaml_bool(self, node):
|
262
|
+
value = self.construct_scalar(node)
|
263
|
+
return self.bool_values[value.lower()]
|
264
|
+
|
265
|
+
def construct_yaml_int(self, node):
|
266
|
+
value = self.construct_scalar(node)
|
267
|
+
value = value.replace("_", "")
|
268
|
+
sign = +1
|
269
|
+
if value[0] == "-":
|
270
|
+
sign = -1
|
271
|
+
if value[0] in "+-":
|
272
|
+
value = value[1:]
|
273
|
+
if value == "0":
|
274
|
+
return 0
|
275
|
+
elif value.startswith("0b"):
|
276
|
+
return sign * int(value[2:], 2)
|
277
|
+
elif value.startswith("0x"):
|
278
|
+
return sign * int(value[2:], 16)
|
279
|
+
elif value[0] == "0":
|
280
|
+
return sign * int(value, 8)
|
281
|
+
elif ":" in value:
|
282
|
+
digits = [int(part) for part in value.split(":")]
|
283
|
+
digits.reverse()
|
284
|
+
base = 1
|
285
|
+
value = 0
|
286
|
+
for digit in digits:
|
287
|
+
value += digit * base
|
288
|
+
base *= 60
|
289
|
+
return sign * value
|
290
|
+
else:
|
291
|
+
return sign * int(value)
|
292
|
+
|
293
|
+
inf_value = 1e300
|
294
|
+
while inf_value != inf_value * inf_value:
|
295
|
+
inf_value *= inf_value
|
296
|
+
nan_value = -inf_value / inf_value # Trying to make a quiet NaN (like C99).
|
297
|
+
|
298
|
+
def construct_yaml_float(self, node):
|
299
|
+
value = self.construct_scalar(node)
|
300
|
+
value = value.replace("_", "").lower()
|
301
|
+
sign = +1
|
302
|
+
if value[0] == "-":
|
303
|
+
sign = -1
|
304
|
+
if value[0] in "+-":
|
305
|
+
value = value[1:]
|
306
|
+
if value == ".inf":
|
307
|
+
return sign * self.inf_value
|
308
|
+
elif value == ".nan":
|
309
|
+
return self.nan_value
|
310
|
+
elif ":" in value:
|
311
|
+
digits = [float(part) for part in value.split(":")]
|
312
|
+
digits.reverse()
|
313
|
+
base = 1
|
314
|
+
value = 0.0
|
315
|
+
for digit in digits:
|
316
|
+
value += digit * base
|
317
|
+
base *= 60
|
318
|
+
return sign * value
|
319
|
+
else:
|
320
|
+
return sign * float(value)
|
321
|
+
|
322
|
+
def construct_yaml_binary(self, node):
|
323
|
+
try:
|
324
|
+
value = self.construct_scalar(node).encode("ascii")
|
325
|
+
except UnicodeEncodeError as exc:
|
326
|
+
raise ConstructorError(
|
327
|
+
None,
|
328
|
+
None,
|
329
|
+
"failed to convert base64 data into ascii: %s" % exc,
|
330
|
+
node.start_mark,
|
331
|
+
)
|
332
|
+
try:
|
333
|
+
if hasattr(base64, "decodebytes"):
|
334
|
+
return base64.decodebytes(value)
|
335
|
+
else:
|
336
|
+
return base64.decodestring(value)
|
337
|
+
except binascii.Error as exc:
|
338
|
+
raise ConstructorError(
|
339
|
+
None, None, "failed to decode base64 data: %s" % exc, node.start_mark
|
340
|
+
)
|
341
|
+
|
342
|
+
timestamp_regexp = re.compile(
|
343
|
+
r"""^(?P<year>[0-9][0-9][0-9][0-9])
|
344
|
+
-(?P<month>[0-9][0-9]?)
|
345
|
+
-(?P<day>[0-9][0-9]?)
|
346
|
+
(?:(?:[Tt]|[ \t]+)
|
347
|
+
(?P<hour>[0-9][0-9]?)
|
348
|
+
:(?P<minute>[0-9][0-9])
|
349
|
+
:(?P<second>[0-9][0-9])
|
350
|
+
(?:\.(?P<fraction>[0-9]*))?
|
351
|
+
(?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
|
352
|
+
(?::(?P<tz_minute>[0-9][0-9]))?))?)?$""",
|
353
|
+
re.X,
|
354
|
+
)
|
355
|
+
|
356
|
+
def construct_yaml_timestamp(self, node):
|
357
|
+
value = self.construct_scalar(node)
|
358
|
+
match = self.timestamp_regexp.match(node.value)
|
359
|
+
values = match.groupdict()
|
360
|
+
year = int(values["year"])
|
361
|
+
month = int(values["month"])
|
362
|
+
day = int(values["day"])
|
363
|
+
if not values["hour"]:
|
364
|
+
return datetime.date(year, month, day)
|
365
|
+
hour = int(values["hour"])
|
366
|
+
minute = int(values["minute"])
|
367
|
+
second = int(values["second"])
|
368
|
+
fraction = 0
|
369
|
+
tzinfo = None
|
370
|
+
if values["fraction"]:
|
371
|
+
fraction = values["fraction"][:6]
|
372
|
+
while len(fraction) < 6:
|
373
|
+
fraction += "0"
|
374
|
+
fraction = int(fraction)
|
375
|
+
if values["tz_sign"]:
|
376
|
+
tz_hour = int(values["tz_hour"])
|
377
|
+
tz_minute = int(values["tz_minute"] or 0)
|
378
|
+
delta = datetime.timedelta(hours=tz_hour, minutes=tz_minute)
|
379
|
+
if values["tz_sign"] == "-":
|
380
|
+
delta = -delta
|
381
|
+
tzinfo = datetime.timezone(delta)
|
382
|
+
elif values["tz"]:
|
383
|
+
tzinfo = datetime.timezone.utc
|
384
|
+
return datetime.datetime(
|
385
|
+
year, month, day, hour, minute, second, fraction, tzinfo=tzinfo
|
386
|
+
)
|
387
|
+
|
388
|
+
def construct_yaml_omap(self, node):
|
389
|
+
# Note: we do not check for duplicate keys, because it's too
|
390
|
+
# CPU-expensive.
|
391
|
+
omap = []
|
392
|
+
yield omap
|
393
|
+
if not isinstance(node, SequenceNode):
|
394
|
+
raise ConstructorError(
|
395
|
+
"while constructing an ordered map",
|
396
|
+
node.start_mark,
|
397
|
+
"expected a sequence, but found %s" % node.id,
|
398
|
+
node.start_mark,
|
399
|
+
)
|
400
|
+
for subnode in node.value:
|
401
|
+
if not isinstance(subnode, MappingNode):
|
402
|
+
raise ConstructorError(
|
403
|
+
"while constructing an ordered map",
|
404
|
+
node.start_mark,
|
405
|
+
"expected a mapping of length 1, but found %s" % subnode.id,
|
406
|
+
subnode.start_mark,
|
407
|
+
)
|
408
|
+
if len(subnode.value) != 1:
|
409
|
+
raise ConstructorError(
|
410
|
+
"while constructing an ordered map",
|
411
|
+
node.start_mark,
|
412
|
+
"expected a single mapping item, but found %d items"
|
413
|
+
% len(subnode.value),
|
414
|
+
subnode.start_mark,
|
415
|
+
)
|
416
|
+
key_node, value_node = subnode.value[0]
|
417
|
+
key = self.construct_object(key_node)
|
418
|
+
value = self.construct_object(value_node)
|
419
|
+
omap.append((key, value))
|
420
|
+
|
421
|
+
def construct_yaml_pairs(self, node):
|
422
|
+
# Note: the same code as `construct_yaml_omap`.
|
423
|
+
pairs = []
|
424
|
+
yield pairs
|
425
|
+
if not isinstance(node, SequenceNode):
|
426
|
+
raise ConstructorError(
|
427
|
+
"while constructing pairs",
|
428
|
+
node.start_mark,
|
429
|
+
"expected a sequence, but found %s" % node.id,
|
430
|
+
node.start_mark,
|
431
|
+
)
|
432
|
+
for subnode in node.value:
|
433
|
+
if not isinstance(subnode, MappingNode):
|
434
|
+
raise ConstructorError(
|
435
|
+
"while constructing pairs",
|
436
|
+
node.start_mark,
|
437
|
+
"expected a mapping of length 1, but found %s" % subnode.id,
|
438
|
+
subnode.start_mark,
|
439
|
+
)
|
440
|
+
if len(subnode.value) != 1:
|
441
|
+
raise ConstructorError(
|
442
|
+
"while constructing pairs",
|
443
|
+
node.start_mark,
|
444
|
+
"expected a single mapping item, but found %d items"
|
445
|
+
% len(subnode.value),
|
446
|
+
subnode.start_mark,
|
447
|
+
)
|
448
|
+
key_node, value_node = subnode.value[0]
|
449
|
+
key = self.construct_object(key_node)
|
450
|
+
value = self.construct_object(value_node)
|
451
|
+
pairs.append((key, value))
|
452
|
+
|
453
|
+
def construct_yaml_set(self, node):
|
454
|
+
data = set()
|
455
|
+
yield data
|
456
|
+
value = self.construct_mapping(node)
|
457
|
+
data.update(value)
|
458
|
+
|
459
|
+
def construct_yaml_str(self, node):
|
460
|
+
return self.construct_scalar(node)
|
461
|
+
|
462
|
+
def construct_yaml_seq(self, node):
|
463
|
+
data = []
|
464
|
+
yield data
|
465
|
+
data.extend(self.construct_sequence(node))
|
466
|
+
|
467
|
+
def construct_yaml_map(self, node):
|
468
|
+
data = {}
|
469
|
+
yield data
|
470
|
+
value = self.construct_mapping(node)
|
471
|
+
data.update(value)
|
472
|
+
|
473
|
+
def construct_yaml_object(self, node, cls):
|
474
|
+
data = cls.__new__(cls)
|
475
|
+
yield data
|
476
|
+
if hasattr(data, "__setstate__"):
|
477
|
+
state = self.construct_mapping(node, deep=True)
|
478
|
+
data.__setstate__(state)
|
479
|
+
else:
|
480
|
+
state = self.construct_mapping(node)
|
481
|
+
data.__dict__.update(state)
|
482
|
+
|
483
|
+
def construct_undefined(self, node):
|
484
|
+
raise ConstructorError(
|
485
|
+
None,
|
486
|
+
None,
|
487
|
+
"could not determine a constructor for the tag %r" % node.tag,
|
488
|
+
node.start_mark,
|
489
|
+
)
|
490
|
+
|
491
|
+
|
492
|
+
SafeConstructor.add_constructor(
|
493
|
+
"tag:yaml.org,2002:null", SafeConstructor.construct_yaml_null
|
494
|
+
)
|
495
|
+
|
496
|
+
SafeConstructor.add_constructor(
|
497
|
+
"tag:yaml.org,2002:bool", SafeConstructor.construct_yaml_bool
|
498
|
+
)
|
499
|
+
|
500
|
+
SafeConstructor.add_constructor(
|
501
|
+
"tag:yaml.org,2002:int", SafeConstructor.construct_yaml_int
|
502
|
+
)
|
503
|
+
|
504
|
+
SafeConstructor.add_constructor(
|
505
|
+
"tag:yaml.org,2002:float", SafeConstructor.construct_yaml_float
|
506
|
+
)
|
507
|
+
|
508
|
+
SafeConstructor.add_constructor(
|
509
|
+
"tag:yaml.org,2002:binary", SafeConstructor.construct_yaml_binary
|
510
|
+
)
|
511
|
+
|
512
|
+
SafeConstructor.add_constructor(
|
513
|
+
"tag:yaml.org,2002:timestamp", SafeConstructor.construct_yaml_timestamp
|
514
|
+
)
|
515
|
+
|
516
|
+
SafeConstructor.add_constructor(
|
517
|
+
"tag:yaml.org,2002:omap", SafeConstructor.construct_yaml_omap
|
518
|
+
)
|
519
|
+
|
520
|
+
SafeConstructor.add_constructor(
|
521
|
+
"tag:yaml.org,2002:pairs", SafeConstructor.construct_yaml_pairs
|
522
|
+
)
|
523
|
+
|
524
|
+
SafeConstructor.add_constructor(
|
525
|
+
"tag:yaml.org,2002:set", SafeConstructor.construct_yaml_set
|
526
|
+
)
|
527
|
+
|
528
|
+
SafeConstructor.add_constructor(
|
529
|
+
"tag:yaml.org,2002:str", SafeConstructor.construct_yaml_str
|
530
|
+
)
|
531
|
+
|
532
|
+
SafeConstructor.add_constructor(
|
533
|
+
"tag:yaml.org,2002:seq", SafeConstructor.construct_yaml_seq
|
534
|
+
)
|
535
|
+
|
536
|
+
SafeConstructor.add_constructor(
|
537
|
+
"tag:yaml.org,2002:map", SafeConstructor.construct_yaml_map
|
538
|
+
)
|
539
|
+
|
540
|
+
SafeConstructor.add_constructor(None, SafeConstructor.construct_undefined)
|
541
|
+
|
542
|
+
|
543
|
+
class FullConstructor(SafeConstructor):
|
544
|
+
# 'extend' is blacklisted because it is used by
|
545
|
+
# construct_python_object_apply to add `listitems` to a newly generate
|
546
|
+
# python instance
|
547
|
+
def get_state_keys_blacklist(self):
|
548
|
+
return ["^extend$", "^__.*__$"]
|
549
|
+
|
550
|
+
def get_state_keys_blacklist_regexp(self):
|
551
|
+
if not hasattr(self, "state_keys_blacklist_regexp"):
|
552
|
+
self.state_keys_blacklist_regexp = re.compile(
|
553
|
+
"(" + "|".join(self.get_state_keys_blacklist()) + ")"
|
554
|
+
)
|
555
|
+
return self.state_keys_blacklist_regexp
|
556
|
+
|
557
|
+
def construct_python_str(self, node):
|
558
|
+
return self.construct_scalar(node)
|
559
|
+
|
560
|
+
def construct_python_unicode(self, node):
|
561
|
+
return self.construct_scalar(node)
|
562
|
+
|
563
|
+
def construct_python_bytes(self, node):
|
564
|
+
try:
|
565
|
+
value = self.construct_scalar(node).encode("ascii")
|
566
|
+
except UnicodeEncodeError as exc:
|
567
|
+
raise ConstructorError(
|
568
|
+
None,
|
569
|
+
None,
|
570
|
+
"failed to convert base64 data into ascii: %s" % exc,
|
571
|
+
node.start_mark,
|
572
|
+
)
|
573
|
+
try:
|
574
|
+
if hasattr(base64, "decodebytes"):
|
575
|
+
return base64.decodebytes(value)
|
576
|
+
else:
|
577
|
+
return base64.decodestring(value)
|
578
|
+
except binascii.Error as exc:
|
579
|
+
raise ConstructorError(
|
580
|
+
None, None, "failed to decode base64 data: %s" % exc, node.start_mark
|
581
|
+
)
|
582
|
+
|
583
|
+
def construct_python_long(self, node):
|
584
|
+
return self.construct_yaml_int(node)
|
585
|
+
|
586
|
+
def construct_python_complex(self, node):
|
587
|
+
return complex(self.construct_scalar(node))
|
588
|
+
|
589
|
+
def construct_python_tuple(self, node):
|
590
|
+
return tuple(self.construct_sequence(node))
|
591
|
+
|
592
|
+
def find_python_module(self, name, mark, unsafe=False):
|
593
|
+
if not name:
|
594
|
+
raise ConstructorError(
|
595
|
+
"while constructing a Python module",
|
596
|
+
mark,
|
597
|
+
"expected non-empty name appended to the tag",
|
598
|
+
mark,
|
599
|
+
)
|
600
|
+
if unsafe:
|
601
|
+
try:
|
602
|
+
__import__(name)
|
603
|
+
except ImportError as exc:
|
604
|
+
raise ConstructorError(
|
605
|
+
"while constructing a Python module",
|
606
|
+
mark,
|
607
|
+
"cannot find module %r (%s)" % (name, exc),
|
608
|
+
mark,
|
609
|
+
)
|
610
|
+
if name not in sys.modules:
|
611
|
+
raise ConstructorError(
|
612
|
+
"while constructing a Python module",
|
613
|
+
mark,
|
614
|
+
"module %r is not imported" % name,
|
615
|
+
mark,
|
616
|
+
)
|
617
|
+
return sys.modules[name]
|
618
|
+
|
619
|
+
def find_python_name(self, name, mark, unsafe=False):
|
620
|
+
if not name:
|
621
|
+
raise ConstructorError(
|
622
|
+
"while constructing a Python object",
|
623
|
+
mark,
|
624
|
+
"expected non-empty name appended to the tag",
|
625
|
+
mark,
|
626
|
+
)
|
627
|
+
if "." in name:
|
628
|
+
module_name, object_name = name.rsplit(".", 1)
|
629
|
+
else:
|
630
|
+
module_name = "builtins"
|
631
|
+
object_name = name
|
632
|
+
if unsafe:
|
633
|
+
try:
|
634
|
+
__import__(module_name)
|
635
|
+
except ImportError as exc:
|
636
|
+
raise ConstructorError(
|
637
|
+
"while constructing a Python object",
|
638
|
+
mark,
|
639
|
+
"cannot find module %r (%s)" % (module_name, exc),
|
640
|
+
mark,
|
641
|
+
)
|
642
|
+
if module_name not in sys.modules:
|
643
|
+
raise ConstructorError(
|
644
|
+
"while constructing a Python object",
|
645
|
+
mark,
|
646
|
+
"module %r is not imported" % module_name,
|
647
|
+
mark,
|
648
|
+
)
|
649
|
+
module = sys.modules[module_name]
|
650
|
+
if not hasattr(module, object_name):
|
651
|
+
raise ConstructorError(
|
652
|
+
"while constructing a Python object",
|
653
|
+
mark,
|
654
|
+
"cannot find %r in the module %r" % (object_name, module.__name__),
|
655
|
+
mark,
|
656
|
+
)
|
657
|
+
return getattr(module, object_name)
|
658
|
+
|
659
|
+
def construct_python_name(self, suffix, node):
|
660
|
+
value = self.construct_scalar(node)
|
661
|
+
if value:
|
662
|
+
raise ConstructorError(
|
663
|
+
"while constructing a Python name",
|
664
|
+
node.start_mark,
|
665
|
+
"expected the empty value, but found %r" % value,
|
666
|
+
node.start_mark,
|
667
|
+
)
|
668
|
+
return self.find_python_name(suffix, node.start_mark)
|
669
|
+
|
670
|
+
def construct_python_module(self, suffix, node):
|
671
|
+
value = self.construct_scalar(node)
|
672
|
+
if value:
|
673
|
+
raise ConstructorError(
|
674
|
+
"while constructing a Python module",
|
675
|
+
node.start_mark,
|
676
|
+
"expected the empty value, but found %r" % value,
|
677
|
+
node.start_mark,
|
678
|
+
)
|
679
|
+
return self.find_python_module(suffix, node.start_mark)
|
680
|
+
|
681
|
+
def make_python_instance(
|
682
|
+
self, suffix, node, args=None, kwds=None, newobj=False, unsafe=False
|
683
|
+
):
|
684
|
+
if not args:
|
685
|
+
args = []
|
686
|
+
if not kwds:
|
687
|
+
kwds = {}
|
688
|
+
cls = self.find_python_name(suffix, node.start_mark)
|
689
|
+
if not (unsafe or isinstance(cls, type)):
|
690
|
+
raise ConstructorError(
|
691
|
+
"while constructing a Python instance",
|
692
|
+
node.start_mark,
|
693
|
+
"expected a class, but found %r" % type(cls),
|
694
|
+
node.start_mark,
|
695
|
+
)
|
696
|
+
if newobj and isinstance(cls, type):
|
697
|
+
return cls.__new__(cls, *args, **kwds)
|
698
|
+
else:
|
699
|
+
return cls(*args, **kwds)
|
700
|
+
|
701
|
+
def set_python_instance_state(self, instance, state, unsafe=False):
|
702
|
+
if hasattr(instance, "__setstate__"):
|
703
|
+
instance.__setstate__(state)
|
704
|
+
else:
|
705
|
+
slotstate = {}
|
706
|
+
if isinstance(state, tuple) and len(state) == 2:
|
707
|
+
state, slotstate = state
|
708
|
+
if hasattr(instance, "__dict__"):
|
709
|
+
if not unsafe and state:
|
710
|
+
for key in state.keys():
|
711
|
+
self.check_state_key(key)
|
712
|
+
instance.__dict__.update(state)
|
713
|
+
elif state:
|
714
|
+
slotstate.update(state)
|
715
|
+
for key, value in slotstate.items():
|
716
|
+
if not unsafe:
|
717
|
+
self.check_state_key(key)
|
718
|
+
setattr(instance, key, value)
|
719
|
+
|
720
|
+
def construct_python_object(self, suffix, node):
|
721
|
+
# Format:
|
722
|
+
# !!python/object:module.name { ... state ... }
|
723
|
+
instance = self.make_python_instance(suffix, node, newobj=True)
|
724
|
+
yield instance
|
725
|
+
deep = hasattr(instance, "__setstate__")
|
726
|
+
state = self.construct_mapping(node, deep=deep)
|
727
|
+
self.set_python_instance_state(instance, state)
|
728
|
+
|
729
|
+
def construct_python_object_apply(self, suffix, node, newobj=False):
|
730
|
+
# Format:
|
731
|
+
# !!python/object/apply # (or !!python/object/new)
|
732
|
+
# args: [ ... arguments ... ]
|
733
|
+
# kwds: { ... keywords ... }
|
734
|
+
# state: ... state ...
|
735
|
+
# listitems: [ ... listitems ... ]
|
736
|
+
# dictitems: { ... dictitems ... }
|
737
|
+
# or short format:
|
738
|
+
# !!python/object/apply [ ... arguments ... ]
|
739
|
+
# The difference between !!python/object/apply and !!python/object/new
|
740
|
+
# is how an object is created, check make_python_instance for details.
|
741
|
+
if isinstance(node, SequenceNode):
|
742
|
+
args = self.construct_sequence(node, deep=True)
|
743
|
+
kwds = {}
|
744
|
+
state = {}
|
745
|
+
listitems = []
|
746
|
+
dictitems = {}
|
747
|
+
else:
|
748
|
+
value = self.construct_mapping(node, deep=True)
|
749
|
+
args = value.get("args", [])
|
750
|
+
kwds = value.get("kwds", {})
|
751
|
+
state = value.get("state", {})
|
752
|
+
listitems = value.get("listitems", [])
|
753
|
+
dictitems = value.get("dictitems", {})
|
754
|
+
instance = self.make_python_instance(suffix, node, args, kwds, newobj)
|
755
|
+
if state:
|
756
|
+
self.set_python_instance_state(instance, state)
|
757
|
+
if listitems:
|
758
|
+
instance.extend(listitems)
|
759
|
+
if dictitems:
|
760
|
+
for key in dictitems:
|
761
|
+
instance[key] = dictitems[key]
|
762
|
+
return instance
|
763
|
+
|
764
|
+
def construct_python_object_new(self, suffix, node):
|
765
|
+
return self.construct_python_object_apply(suffix, node, newobj=True)
|
766
|
+
|
767
|
+
|
768
|
+
FullConstructor.add_constructor(
|
769
|
+
"tag:yaml.org,2002:python/none", FullConstructor.construct_yaml_null
|
770
|
+
)
|
771
|
+
|
772
|
+
FullConstructor.add_constructor(
|
773
|
+
"tag:yaml.org,2002:python/bool", FullConstructor.construct_yaml_bool
|
774
|
+
)
|
775
|
+
|
776
|
+
FullConstructor.add_constructor(
|
777
|
+
"tag:yaml.org,2002:python/str", FullConstructor.construct_python_str
|
778
|
+
)
|
779
|
+
|
780
|
+
FullConstructor.add_constructor(
|
781
|
+
"tag:yaml.org,2002:python/unicode", FullConstructor.construct_python_unicode
|
782
|
+
)
|
783
|
+
|
784
|
+
FullConstructor.add_constructor(
|
785
|
+
"tag:yaml.org,2002:python/bytes", FullConstructor.construct_python_bytes
|
786
|
+
)
|
787
|
+
|
788
|
+
FullConstructor.add_constructor(
|
789
|
+
"tag:yaml.org,2002:python/int", FullConstructor.construct_yaml_int
|
790
|
+
)
|
791
|
+
|
792
|
+
FullConstructor.add_constructor(
|
793
|
+
"tag:yaml.org,2002:python/long", FullConstructor.construct_python_long
|
794
|
+
)
|
795
|
+
|
796
|
+
FullConstructor.add_constructor(
|
797
|
+
"tag:yaml.org,2002:python/float", FullConstructor.construct_yaml_float
|
798
|
+
)
|
799
|
+
|
800
|
+
FullConstructor.add_constructor(
|
801
|
+
"tag:yaml.org,2002:python/complex", FullConstructor.construct_python_complex
|
802
|
+
)
|
803
|
+
|
804
|
+
FullConstructor.add_constructor(
|
805
|
+
"tag:yaml.org,2002:python/list", FullConstructor.construct_yaml_seq
|
806
|
+
)
|
807
|
+
|
808
|
+
FullConstructor.add_constructor(
|
809
|
+
"tag:yaml.org,2002:python/tuple", FullConstructor.construct_python_tuple
|
810
|
+
)
|
811
|
+
|
812
|
+
FullConstructor.add_constructor(
|
813
|
+
"tag:yaml.org,2002:python/dict", FullConstructor.construct_yaml_map
|
814
|
+
)
|
815
|
+
|
816
|
+
FullConstructor.add_multi_constructor(
|
817
|
+
"tag:yaml.org,2002:python/name:", FullConstructor.construct_python_name
|
818
|
+
)
|
819
|
+
|
820
|
+
|
821
|
+
class UnsafeConstructor(FullConstructor):
|
822
|
+
def find_python_module(self, name, mark):
|
823
|
+
return super(UnsafeConstructor, self).find_python_module(
|
824
|
+
name, mark, unsafe=True
|
825
|
+
)
|
826
|
+
|
827
|
+
def find_python_name(self, name, mark):
|
828
|
+
return super(UnsafeConstructor, self).find_python_name(name, mark, unsafe=True)
|
829
|
+
|
830
|
+
def make_python_instance(self, suffix, node, args=None, kwds=None, newobj=False):
|
831
|
+
return super(UnsafeConstructor, self).make_python_instance(
|
832
|
+
suffix, node, args, kwds, newobj, unsafe=True
|
833
|
+
)
|
834
|
+
|
835
|
+
def set_python_instance_state(self, instance, state):
|
836
|
+
return super(UnsafeConstructor, self).set_python_instance_state(
|
837
|
+
instance, state, unsafe=True
|
838
|
+
)
|
839
|
+
|
840
|
+
|
841
|
+
UnsafeConstructor.add_multi_constructor(
|
842
|
+
"tag:yaml.org,2002:python/module:", UnsafeConstructor.construct_python_module
|
843
|
+
)
|
844
|
+
|
845
|
+
UnsafeConstructor.add_multi_constructor(
|
846
|
+
"tag:yaml.org,2002:python/object:", UnsafeConstructor.construct_python_object
|
847
|
+
)
|
848
|
+
|
849
|
+
UnsafeConstructor.add_multi_constructor(
|
850
|
+
"tag:yaml.org,2002:python/object/new:",
|
851
|
+
UnsafeConstructor.construct_python_object_new,
|
852
|
+
)
|
853
|
+
|
854
|
+
UnsafeConstructor.add_multi_constructor(
|
855
|
+
"tag:yaml.org,2002:python/object/apply:",
|
856
|
+
UnsafeConstructor.construct_python_object_apply,
|
857
|
+
)
|
858
|
+
|
859
|
+
# Constructor is same as UnsafeConstructor. Need to leave this in place in case
|
860
|
+
# people have extended it directly.
|
861
|
+
class Constructor(UnsafeConstructor):
|
862
|
+
pass
|