outerbounds 0.3.55rc8__py3-none-any.whl → 0.3.133__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. outerbounds/_vendor/PyYAML.LICENSE +20 -0
  2. outerbounds/_vendor/__init__.py +0 -0
  3. outerbounds/_vendor/_yaml/__init__.py +34 -0
  4. outerbounds/_vendor/click/__init__.py +73 -0
  5. outerbounds/_vendor/click/_compat.py +626 -0
  6. outerbounds/_vendor/click/_termui_impl.py +717 -0
  7. outerbounds/_vendor/click/_textwrap.py +49 -0
  8. outerbounds/_vendor/click/_winconsole.py +279 -0
  9. outerbounds/_vendor/click/core.py +2998 -0
  10. outerbounds/_vendor/click/decorators.py +497 -0
  11. outerbounds/_vendor/click/exceptions.py +287 -0
  12. outerbounds/_vendor/click/formatting.py +301 -0
  13. outerbounds/_vendor/click/globals.py +68 -0
  14. outerbounds/_vendor/click/parser.py +529 -0
  15. outerbounds/_vendor/click/py.typed +0 -0
  16. outerbounds/_vendor/click/shell_completion.py +580 -0
  17. outerbounds/_vendor/click/termui.py +787 -0
  18. outerbounds/_vendor/click/testing.py +479 -0
  19. outerbounds/_vendor/click/types.py +1073 -0
  20. outerbounds/_vendor/click/utils.py +580 -0
  21. outerbounds/_vendor/click.LICENSE +28 -0
  22. outerbounds/_vendor/vendor_any.txt +2 -0
  23. outerbounds/_vendor/yaml/__init__.py +471 -0
  24. outerbounds/_vendor/yaml/_yaml.cpython-311-darwin.so +0 -0
  25. outerbounds/_vendor/yaml/composer.py +146 -0
  26. outerbounds/_vendor/yaml/constructor.py +862 -0
  27. outerbounds/_vendor/yaml/cyaml.py +177 -0
  28. outerbounds/_vendor/yaml/dumper.py +138 -0
  29. outerbounds/_vendor/yaml/emitter.py +1239 -0
  30. outerbounds/_vendor/yaml/error.py +94 -0
  31. outerbounds/_vendor/yaml/events.py +104 -0
  32. outerbounds/_vendor/yaml/loader.py +62 -0
  33. outerbounds/_vendor/yaml/nodes.py +51 -0
  34. outerbounds/_vendor/yaml/parser.py +629 -0
  35. outerbounds/_vendor/yaml/reader.py +208 -0
  36. outerbounds/_vendor/yaml/representer.py +378 -0
  37. outerbounds/_vendor/yaml/resolver.py +245 -0
  38. outerbounds/_vendor/yaml/scanner.py +1555 -0
  39. outerbounds/_vendor/yaml/serializer.py +127 -0
  40. outerbounds/_vendor/yaml/tokens.py +129 -0
  41. outerbounds/command_groups/apps_cli.py +450 -0
  42. outerbounds/command_groups/cli.py +9 -5
  43. outerbounds/command_groups/local_setup_cli.py +247 -36
  44. outerbounds/command_groups/perimeters_cli.py +212 -32
  45. outerbounds/command_groups/tutorials_cli.py +111 -0
  46. outerbounds/command_groups/workstations_cli.py +2 -2
  47. outerbounds/utils/kubeconfig.py +2 -2
  48. outerbounds/utils/metaflowconfig.py +93 -16
  49. outerbounds/utils/schema.py +2 -2
  50. outerbounds/utils/utils.py +19 -0
  51. outerbounds/vendor.py +159 -0
  52. {outerbounds-0.3.55rc8.dist-info → outerbounds-0.3.133.dist-info}/METADATA +17 -6
  53. outerbounds-0.3.133.dist-info/RECORD +59 -0
  54. {outerbounds-0.3.55rc8.dist-info → outerbounds-0.3.133.dist-info}/WHEEL +1 -1
  55. outerbounds-0.3.55rc8.dist-info/RECORD +0 -15
  56. {outerbounds-0.3.55rc8.dist-info → outerbounds-0.3.133.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,1239 @@
1
+ # Emitter expects events obeying the following grammar:
2
+ # stream ::= STREAM-START document* STREAM-END
3
+ # document ::= DOCUMENT-START node DOCUMENT-END
4
+ # node ::= SCALAR | sequence | mapping
5
+ # sequence ::= SEQUENCE-START node* SEQUENCE-END
6
+ # mapping ::= MAPPING-START (node node)* MAPPING-END
7
+
8
+ __all__ = ["Emitter", "EmitterError"]
9
+
10
+ from .error import YAMLError
11
+ from .events import *
12
+
13
+
14
+ class EmitterError(YAMLError):
15
+ pass
16
+
17
+
18
+ class ScalarAnalysis:
19
+ def __init__(
20
+ self,
21
+ scalar,
22
+ empty,
23
+ multiline,
24
+ allow_flow_plain,
25
+ allow_block_plain,
26
+ allow_single_quoted,
27
+ allow_double_quoted,
28
+ allow_block,
29
+ ):
30
+ self.scalar = scalar
31
+ self.empty = empty
32
+ self.multiline = multiline
33
+ self.allow_flow_plain = allow_flow_plain
34
+ self.allow_block_plain = allow_block_plain
35
+ self.allow_single_quoted = allow_single_quoted
36
+ self.allow_double_quoted = allow_double_quoted
37
+ self.allow_block = allow_block
38
+
39
+
40
+ class Emitter:
41
+
42
+ DEFAULT_TAG_PREFIXES = {
43
+ "!": "!",
44
+ "tag:yaml.org,2002:": "!!",
45
+ }
46
+
47
+ def __init__(
48
+ self,
49
+ stream,
50
+ canonical=None,
51
+ indent=None,
52
+ width=None,
53
+ allow_unicode=None,
54
+ line_break=None,
55
+ ):
56
+
57
+ # The stream should have the methods `write` and possibly `flush`.
58
+ self.stream = stream
59
+
60
+ # Encoding can be overridden by STREAM-START.
61
+ self.encoding = None
62
+
63
+ # Emitter is a state machine with a stack of states to handle nested
64
+ # structures.
65
+ self.states = []
66
+ self.state = self.expect_stream_start
67
+
68
+ # Current event and the event queue.
69
+ self.events = []
70
+ self.event = None
71
+
72
+ # The current indentation level and the stack of previous indents.
73
+ self.indents = []
74
+ self.indent = None
75
+
76
+ # Flow level.
77
+ self.flow_level = 0
78
+
79
+ # Contexts.
80
+ self.root_context = False
81
+ self.sequence_context = False
82
+ self.mapping_context = False
83
+ self.simple_key_context = False
84
+
85
+ # Characteristics of the last emitted character:
86
+ # - current position.
87
+ # - is it a whitespace?
88
+ # - is it an indention character
89
+ # (indentation space, '-', '?', or ':')?
90
+ self.line = 0
91
+ self.column = 0
92
+ self.whitespace = True
93
+ self.indention = True
94
+
95
+ # Whether the document requires an explicit document indicator
96
+ self.open_ended = False
97
+
98
+ # Formatting details.
99
+ self.canonical = canonical
100
+ self.allow_unicode = allow_unicode
101
+ self.best_indent = 2
102
+ if indent and 1 < indent < 10:
103
+ self.best_indent = indent
104
+ self.best_width = 80
105
+ if width and width > self.best_indent * 2:
106
+ self.best_width = width
107
+ self.best_line_break = "\n"
108
+ if line_break in ["\r", "\n", "\r\n"]:
109
+ self.best_line_break = line_break
110
+
111
+ # Tag prefixes.
112
+ self.tag_prefixes = None
113
+
114
+ # Prepared anchor and tag.
115
+ self.prepared_anchor = None
116
+ self.prepared_tag = None
117
+
118
+ # Scalar analysis and style.
119
+ self.analysis = None
120
+ self.style = None
121
+
122
+ def dispose(self):
123
+ # Reset the state attributes (to clear self-references)
124
+ self.states = []
125
+ self.state = None
126
+
127
+ def emit(self, event):
128
+ self.events.append(event)
129
+ while not self.need_more_events():
130
+ self.event = self.events.pop(0)
131
+ self.state()
132
+ self.event = None
133
+
134
+ # In some cases, we wait for a few next events before emitting.
135
+
136
+ def need_more_events(self):
137
+ if not self.events:
138
+ return True
139
+ event = self.events[0]
140
+ if isinstance(event, DocumentStartEvent):
141
+ return self.need_events(1)
142
+ elif isinstance(event, SequenceStartEvent):
143
+ return self.need_events(2)
144
+ elif isinstance(event, MappingStartEvent):
145
+ return self.need_events(3)
146
+ else:
147
+ return False
148
+
149
+ def need_events(self, count):
150
+ level = 0
151
+ for event in self.events[1:]:
152
+ if isinstance(event, (DocumentStartEvent, CollectionStartEvent)):
153
+ level += 1
154
+ elif isinstance(event, (DocumentEndEvent, CollectionEndEvent)):
155
+ level -= 1
156
+ elif isinstance(event, StreamEndEvent):
157
+ level = -1
158
+ if level < 0:
159
+ return False
160
+ return len(self.events) < count + 1
161
+
162
+ def increase_indent(self, flow=False, indentless=False):
163
+ self.indents.append(self.indent)
164
+ if self.indent is None:
165
+ if flow:
166
+ self.indent = self.best_indent
167
+ else:
168
+ self.indent = 0
169
+ elif not indentless:
170
+ self.indent += self.best_indent
171
+
172
+ # States.
173
+
174
+ # Stream handlers.
175
+
176
+ def expect_stream_start(self):
177
+ if isinstance(self.event, StreamStartEvent):
178
+ if self.event.encoding and not hasattr(self.stream, "encoding"):
179
+ self.encoding = self.event.encoding
180
+ self.write_stream_start()
181
+ self.state = self.expect_first_document_start
182
+ else:
183
+ raise EmitterError("expected StreamStartEvent, but got %s" % self.event)
184
+
185
+ def expect_nothing(self):
186
+ raise EmitterError("expected nothing, but got %s" % self.event)
187
+
188
+ # Document handlers.
189
+
190
+ def expect_first_document_start(self):
191
+ return self.expect_document_start(first=True)
192
+
193
+ def expect_document_start(self, first=False):
194
+ if isinstance(self.event, DocumentStartEvent):
195
+ if (self.event.version or self.event.tags) and self.open_ended:
196
+ self.write_indicator("...", True)
197
+ self.write_indent()
198
+ if self.event.version:
199
+ version_text = self.prepare_version(self.event.version)
200
+ self.write_version_directive(version_text)
201
+ self.tag_prefixes = self.DEFAULT_TAG_PREFIXES.copy()
202
+ if self.event.tags:
203
+ handles = sorted(self.event.tags.keys())
204
+ for handle in handles:
205
+ prefix = self.event.tags[handle]
206
+ self.tag_prefixes[prefix] = handle
207
+ handle_text = self.prepare_tag_handle(handle)
208
+ prefix_text = self.prepare_tag_prefix(prefix)
209
+ self.write_tag_directive(handle_text, prefix_text)
210
+ implicit = (
211
+ first
212
+ and not self.event.explicit
213
+ and not self.canonical
214
+ and not self.event.version
215
+ and not self.event.tags
216
+ and not self.check_empty_document()
217
+ )
218
+ if not implicit:
219
+ self.write_indent()
220
+ self.write_indicator("---", True)
221
+ if self.canonical:
222
+ self.write_indent()
223
+ self.state = self.expect_document_root
224
+ elif isinstance(self.event, StreamEndEvent):
225
+ if self.open_ended:
226
+ self.write_indicator("...", True)
227
+ self.write_indent()
228
+ self.write_stream_end()
229
+ self.state = self.expect_nothing
230
+ else:
231
+ raise EmitterError("expected DocumentStartEvent, but got %s" % self.event)
232
+
233
+ def expect_document_end(self):
234
+ if isinstance(self.event, DocumentEndEvent):
235
+ self.write_indent()
236
+ if self.event.explicit:
237
+ self.write_indicator("...", True)
238
+ self.write_indent()
239
+ self.flush_stream()
240
+ self.state = self.expect_document_start
241
+ else:
242
+ raise EmitterError("expected DocumentEndEvent, but got %s" % self.event)
243
+
244
+ def expect_document_root(self):
245
+ self.states.append(self.expect_document_end)
246
+ self.expect_node(root=True)
247
+
248
+ # Node handlers.
249
+
250
+ def expect_node(self, root=False, sequence=False, mapping=False, simple_key=False):
251
+ self.root_context = root
252
+ self.sequence_context = sequence
253
+ self.mapping_context = mapping
254
+ self.simple_key_context = simple_key
255
+ if isinstance(self.event, AliasEvent):
256
+ self.expect_alias()
257
+ elif isinstance(self.event, (ScalarEvent, CollectionStartEvent)):
258
+ self.process_anchor("&")
259
+ self.process_tag()
260
+ if isinstance(self.event, ScalarEvent):
261
+ self.expect_scalar()
262
+ elif isinstance(self.event, SequenceStartEvent):
263
+ if (
264
+ self.flow_level
265
+ or self.canonical
266
+ or self.event.flow_style
267
+ or self.check_empty_sequence()
268
+ ):
269
+ self.expect_flow_sequence()
270
+ else:
271
+ self.expect_block_sequence()
272
+ elif isinstance(self.event, MappingStartEvent):
273
+ if (
274
+ self.flow_level
275
+ or self.canonical
276
+ or self.event.flow_style
277
+ or self.check_empty_mapping()
278
+ ):
279
+ self.expect_flow_mapping()
280
+ else:
281
+ self.expect_block_mapping()
282
+ else:
283
+ raise EmitterError("expected NodeEvent, but got %s" % self.event)
284
+
285
+ def expect_alias(self):
286
+ if self.event.anchor is None:
287
+ raise EmitterError("anchor is not specified for alias")
288
+ self.process_anchor("*")
289
+ self.state = self.states.pop()
290
+
291
+ def expect_scalar(self):
292
+ self.increase_indent(flow=True)
293
+ self.process_scalar()
294
+ self.indent = self.indents.pop()
295
+ self.state = self.states.pop()
296
+
297
+ # Flow sequence handlers.
298
+
299
+ def expect_flow_sequence(self):
300
+ self.write_indicator("[", True, whitespace=True)
301
+ self.flow_level += 1
302
+ self.increase_indent(flow=True)
303
+ self.state = self.expect_first_flow_sequence_item
304
+
305
+ def expect_first_flow_sequence_item(self):
306
+ if isinstance(self.event, SequenceEndEvent):
307
+ self.indent = self.indents.pop()
308
+ self.flow_level -= 1
309
+ self.write_indicator("]", False)
310
+ self.state = self.states.pop()
311
+ else:
312
+ if self.canonical or self.column > self.best_width:
313
+ self.write_indent()
314
+ self.states.append(self.expect_flow_sequence_item)
315
+ self.expect_node(sequence=True)
316
+
317
+ def expect_flow_sequence_item(self):
318
+ if isinstance(self.event, SequenceEndEvent):
319
+ self.indent = self.indents.pop()
320
+ self.flow_level -= 1
321
+ if self.canonical:
322
+ self.write_indicator(",", False)
323
+ self.write_indent()
324
+ self.write_indicator("]", False)
325
+ self.state = self.states.pop()
326
+ else:
327
+ self.write_indicator(",", False)
328
+ if self.canonical or self.column > self.best_width:
329
+ self.write_indent()
330
+ self.states.append(self.expect_flow_sequence_item)
331
+ self.expect_node(sequence=True)
332
+
333
+ # Flow mapping handlers.
334
+
335
+ def expect_flow_mapping(self):
336
+ self.write_indicator("{", True, whitespace=True)
337
+ self.flow_level += 1
338
+ self.increase_indent(flow=True)
339
+ self.state = self.expect_first_flow_mapping_key
340
+
341
+ def expect_first_flow_mapping_key(self):
342
+ if isinstance(self.event, MappingEndEvent):
343
+ self.indent = self.indents.pop()
344
+ self.flow_level -= 1
345
+ self.write_indicator("}", False)
346
+ self.state = self.states.pop()
347
+ else:
348
+ if self.canonical or self.column > self.best_width:
349
+ self.write_indent()
350
+ if not self.canonical and self.check_simple_key():
351
+ self.states.append(self.expect_flow_mapping_simple_value)
352
+ self.expect_node(mapping=True, simple_key=True)
353
+ else:
354
+ self.write_indicator("?", True)
355
+ self.states.append(self.expect_flow_mapping_value)
356
+ self.expect_node(mapping=True)
357
+
358
+ def expect_flow_mapping_key(self):
359
+ if isinstance(self.event, MappingEndEvent):
360
+ self.indent = self.indents.pop()
361
+ self.flow_level -= 1
362
+ if self.canonical:
363
+ self.write_indicator(",", False)
364
+ self.write_indent()
365
+ self.write_indicator("}", False)
366
+ self.state = self.states.pop()
367
+ else:
368
+ self.write_indicator(",", False)
369
+ if self.canonical or self.column > self.best_width:
370
+ self.write_indent()
371
+ if not self.canonical and self.check_simple_key():
372
+ self.states.append(self.expect_flow_mapping_simple_value)
373
+ self.expect_node(mapping=True, simple_key=True)
374
+ else:
375
+ self.write_indicator("?", True)
376
+ self.states.append(self.expect_flow_mapping_value)
377
+ self.expect_node(mapping=True)
378
+
379
+ def expect_flow_mapping_simple_value(self):
380
+ self.write_indicator(":", False)
381
+ self.states.append(self.expect_flow_mapping_key)
382
+ self.expect_node(mapping=True)
383
+
384
+ def expect_flow_mapping_value(self):
385
+ if self.canonical or self.column > self.best_width:
386
+ self.write_indent()
387
+ self.write_indicator(":", True)
388
+ self.states.append(self.expect_flow_mapping_key)
389
+ self.expect_node(mapping=True)
390
+
391
+ # Block sequence handlers.
392
+
393
+ def expect_block_sequence(self):
394
+ indentless = self.mapping_context and not self.indention
395
+ self.increase_indent(flow=False, indentless=indentless)
396
+ self.state = self.expect_first_block_sequence_item
397
+
398
+ def expect_first_block_sequence_item(self):
399
+ return self.expect_block_sequence_item(first=True)
400
+
401
+ def expect_block_sequence_item(self, first=False):
402
+ if not first and isinstance(self.event, SequenceEndEvent):
403
+ self.indent = self.indents.pop()
404
+ self.state = self.states.pop()
405
+ else:
406
+ self.write_indent()
407
+ self.write_indicator("-", True, indention=True)
408
+ self.states.append(self.expect_block_sequence_item)
409
+ self.expect_node(sequence=True)
410
+
411
+ # Block mapping handlers.
412
+
413
+ def expect_block_mapping(self):
414
+ self.increase_indent(flow=False)
415
+ self.state = self.expect_first_block_mapping_key
416
+
417
+ def expect_first_block_mapping_key(self):
418
+ return self.expect_block_mapping_key(first=True)
419
+
420
+ def expect_block_mapping_key(self, first=False):
421
+ if not first and isinstance(self.event, MappingEndEvent):
422
+ self.indent = self.indents.pop()
423
+ self.state = self.states.pop()
424
+ else:
425
+ self.write_indent()
426
+ if self.check_simple_key():
427
+ self.states.append(self.expect_block_mapping_simple_value)
428
+ self.expect_node(mapping=True, simple_key=True)
429
+ else:
430
+ self.write_indicator("?", True, indention=True)
431
+ self.states.append(self.expect_block_mapping_value)
432
+ self.expect_node(mapping=True)
433
+
434
+ def expect_block_mapping_simple_value(self):
435
+ self.write_indicator(":", False)
436
+ self.states.append(self.expect_block_mapping_key)
437
+ self.expect_node(mapping=True)
438
+
439
+ def expect_block_mapping_value(self):
440
+ self.write_indent()
441
+ self.write_indicator(":", True, indention=True)
442
+ self.states.append(self.expect_block_mapping_key)
443
+ self.expect_node(mapping=True)
444
+
445
+ # Checkers.
446
+
447
+ def check_empty_sequence(self):
448
+ return (
449
+ isinstance(self.event, SequenceStartEvent)
450
+ and self.events
451
+ and isinstance(self.events[0], SequenceEndEvent)
452
+ )
453
+
454
+ def check_empty_mapping(self):
455
+ return (
456
+ isinstance(self.event, MappingStartEvent)
457
+ and self.events
458
+ and isinstance(self.events[0], MappingEndEvent)
459
+ )
460
+
461
+ def check_empty_document(self):
462
+ if not isinstance(self.event, DocumentStartEvent) or not self.events:
463
+ return False
464
+ event = self.events[0]
465
+ return (
466
+ isinstance(event, ScalarEvent)
467
+ and event.anchor is None
468
+ and event.tag is None
469
+ and event.implicit
470
+ and event.value == ""
471
+ )
472
+
473
+ def check_simple_key(self):
474
+ length = 0
475
+ if isinstance(self.event, NodeEvent) and self.event.anchor is not None:
476
+ if self.prepared_anchor is None:
477
+ self.prepared_anchor = self.prepare_anchor(self.event.anchor)
478
+ length += len(self.prepared_anchor)
479
+ if (
480
+ isinstance(self.event, (ScalarEvent, CollectionStartEvent))
481
+ and self.event.tag is not None
482
+ ):
483
+ if self.prepared_tag is None:
484
+ self.prepared_tag = self.prepare_tag(self.event.tag)
485
+ length += len(self.prepared_tag)
486
+ if isinstance(self.event, ScalarEvent):
487
+ if self.analysis is None:
488
+ self.analysis = self.analyze_scalar(self.event.value)
489
+ length += len(self.analysis.scalar)
490
+ return length < 128 and (
491
+ isinstance(self.event, AliasEvent)
492
+ or (
493
+ isinstance(self.event, ScalarEvent)
494
+ and not self.analysis.empty
495
+ and not self.analysis.multiline
496
+ )
497
+ or self.check_empty_sequence()
498
+ or self.check_empty_mapping()
499
+ )
500
+
501
+ # Anchor, Tag, and Scalar processors.
502
+
503
+ def process_anchor(self, indicator):
504
+ if self.event.anchor is None:
505
+ self.prepared_anchor = None
506
+ return
507
+ if self.prepared_anchor is None:
508
+ self.prepared_anchor = self.prepare_anchor(self.event.anchor)
509
+ if self.prepared_anchor:
510
+ self.write_indicator(indicator + self.prepared_anchor, True)
511
+ self.prepared_anchor = None
512
+
513
+ def process_tag(self):
514
+ tag = self.event.tag
515
+ if isinstance(self.event, ScalarEvent):
516
+ if self.style is None:
517
+ self.style = self.choose_scalar_style()
518
+ if (not self.canonical or tag is None) and (
519
+ (self.style == "" and self.event.implicit[0])
520
+ or (self.style != "" and self.event.implicit[1])
521
+ ):
522
+ self.prepared_tag = None
523
+ return
524
+ if self.event.implicit[0] and tag is None:
525
+ tag = "!"
526
+ self.prepared_tag = None
527
+ else:
528
+ if (not self.canonical or tag is None) and self.event.implicit:
529
+ self.prepared_tag = None
530
+ return
531
+ if tag is None:
532
+ raise EmitterError("tag is not specified")
533
+ if self.prepared_tag is None:
534
+ self.prepared_tag = self.prepare_tag(tag)
535
+ if self.prepared_tag:
536
+ self.write_indicator(self.prepared_tag, True)
537
+ self.prepared_tag = None
538
+
539
+ def choose_scalar_style(self):
540
+ if self.analysis is None:
541
+ self.analysis = self.analyze_scalar(self.event.value)
542
+ if self.event.style == '"' or self.canonical:
543
+ return '"'
544
+ if not self.event.style and self.event.implicit[0]:
545
+ if not (
546
+ self.simple_key_context
547
+ and (self.analysis.empty or self.analysis.multiline)
548
+ ) and (
549
+ self.flow_level
550
+ and self.analysis.allow_flow_plain
551
+ or (not self.flow_level and self.analysis.allow_block_plain)
552
+ ):
553
+ return ""
554
+ if self.event.style and self.event.style in "|>":
555
+ if (
556
+ not self.flow_level
557
+ and not self.simple_key_context
558
+ and self.analysis.allow_block
559
+ ):
560
+ return self.event.style
561
+ if not self.event.style or self.event.style == "'":
562
+ if self.analysis.allow_single_quoted and not (
563
+ self.simple_key_context and self.analysis.multiline
564
+ ):
565
+ return "'"
566
+ return '"'
567
+
568
+ def process_scalar(self):
569
+ if self.analysis is None:
570
+ self.analysis = self.analyze_scalar(self.event.value)
571
+ if self.style is None:
572
+ self.style = self.choose_scalar_style()
573
+ split = not self.simple_key_context
574
+ # if self.analysis.multiline and split \
575
+ # and (not self.style or self.style in '\'\"'):
576
+ # self.write_indent()
577
+ if self.style == '"':
578
+ self.write_double_quoted(self.analysis.scalar, split)
579
+ elif self.style == "'":
580
+ self.write_single_quoted(self.analysis.scalar, split)
581
+ elif self.style == ">":
582
+ self.write_folded(self.analysis.scalar)
583
+ elif self.style == "|":
584
+ self.write_literal(self.analysis.scalar)
585
+ else:
586
+ self.write_plain(self.analysis.scalar, split)
587
+ self.analysis = None
588
+ self.style = None
589
+
590
+ # Analyzers.
591
+
592
+ def prepare_version(self, version):
593
+ major, minor = version
594
+ if major != 1:
595
+ raise EmitterError("unsupported YAML version: %d.%d" % (major, minor))
596
+ return "%d.%d" % (major, minor)
597
+
598
+ def prepare_tag_handle(self, handle):
599
+ if not handle:
600
+ raise EmitterError("tag handle must not be empty")
601
+ if handle[0] != "!" or handle[-1] != "!":
602
+ raise EmitterError("tag handle must start and end with '!': %r" % handle)
603
+ for ch in handle[1:-1]:
604
+ if not (
605
+ "0" <= ch <= "9" or "A" <= ch <= "Z" or "a" <= ch <= "z" or ch in "-_"
606
+ ):
607
+ raise EmitterError(
608
+ "invalid character %r in the tag handle: %r" % (ch, handle)
609
+ )
610
+ return handle
611
+
612
+ def prepare_tag_prefix(self, prefix):
613
+ if not prefix:
614
+ raise EmitterError("tag prefix must not be empty")
615
+ chunks = []
616
+ start = end = 0
617
+ if prefix[0] == "!":
618
+ end = 1
619
+ while end < len(prefix):
620
+ ch = prefix[end]
621
+ if (
622
+ "0" <= ch <= "9"
623
+ or "A" <= ch <= "Z"
624
+ or "a" <= ch <= "z"
625
+ or ch in "-;/?!:@&=+$,_.~*'()[]"
626
+ ):
627
+ end += 1
628
+ else:
629
+ if start < end:
630
+ chunks.append(prefix[start:end])
631
+ start = end = end + 1
632
+ data = ch.encode("utf-8")
633
+ for ch in data:
634
+ chunks.append("%%%02X" % ord(ch))
635
+ if start < end:
636
+ chunks.append(prefix[start:end])
637
+ return "".join(chunks)
638
+
639
+ def prepare_tag(self, tag):
640
+ if not tag:
641
+ raise EmitterError("tag must not be empty")
642
+ if tag == "!":
643
+ return tag
644
+ handle = None
645
+ suffix = tag
646
+ prefixes = sorted(self.tag_prefixes.keys())
647
+ for prefix in prefixes:
648
+ if tag.startswith(prefix) and (prefix == "!" or len(prefix) < len(tag)):
649
+ handle = self.tag_prefixes[prefix]
650
+ suffix = tag[len(prefix) :]
651
+ chunks = []
652
+ start = end = 0
653
+ while end < len(suffix):
654
+ ch = suffix[end]
655
+ if (
656
+ "0" <= ch <= "9"
657
+ or "A" <= ch <= "Z"
658
+ or "a" <= ch <= "z"
659
+ or ch in "-;/?:@&=+$,_.~*'()[]"
660
+ or (ch == "!" and handle != "!")
661
+ ):
662
+ end += 1
663
+ else:
664
+ if start < end:
665
+ chunks.append(suffix[start:end])
666
+ start = end = end + 1
667
+ data = ch.encode("utf-8")
668
+ for ch in data:
669
+ chunks.append("%%%02X" % ch)
670
+ if start < end:
671
+ chunks.append(suffix[start:end])
672
+ suffix_text = "".join(chunks)
673
+ if handle:
674
+ return "%s%s" % (handle, suffix_text)
675
+ else:
676
+ return "!<%s>" % suffix_text
677
+
678
+ def prepare_anchor(self, anchor):
679
+ if not anchor:
680
+ raise EmitterError("anchor must not be empty")
681
+ for ch in anchor:
682
+ if not (
683
+ "0" <= ch <= "9" or "A" <= ch <= "Z" or "a" <= ch <= "z" or ch in "-_"
684
+ ):
685
+ raise EmitterError(
686
+ "invalid character %r in the anchor: %r" % (ch, anchor)
687
+ )
688
+ return anchor
689
+
690
+ def analyze_scalar(self, scalar):
691
+
692
+ # Empty scalar is a special case.
693
+ if not scalar:
694
+ return ScalarAnalysis(
695
+ scalar=scalar,
696
+ empty=True,
697
+ multiline=False,
698
+ allow_flow_plain=False,
699
+ allow_block_plain=True,
700
+ allow_single_quoted=True,
701
+ allow_double_quoted=True,
702
+ allow_block=False,
703
+ )
704
+
705
+ # Indicators and special characters.
706
+ block_indicators = False
707
+ flow_indicators = False
708
+ line_breaks = False
709
+ special_characters = False
710
+
711
+ # Important whitespace combinations.
712
+ leading_space = False
713
+ leading_break = False
714
+ trailing_space = False
715
+ trailing_break = False
716
+ break_space = False
717
+ space_break = False
718
+
719
+ # Check document indicators.
720
+ if scalar.startswith("---") or scalar.startswith("..."):
721
+ block_indicators = True
722
+ flow_indicators = True
723
+
724
+ # First character or preceded by a whitespace.
725
+ preceded_by_whitespace = True
726
+
727
+ # Last character or followed by a whitespace.
728
+ followed_by_whitespace = (
729
+ len(scalar) == 1 or scalar[1] in "\0 \t\r\n\x85\u2028\u2029"
730
+ )
731
+
732
+ # The previous character is a space.
733
+ previous_space = False
734
+
735
+ # The previous character is a break.
736
+ previous_break = False
737
+
738
+ index = 0
739
+ while index < len(scalar):
740
+ ch = scalar[index]
741
+
742
+ # Check for indicators.
743
+ if index == 0:
744
+ # Leading indicators are special characters.
745
+ if ch in "#,[]{}&*!|>'\"%@`":
746
+ flow_indicators = True
747
+ block_indicators = True
748
+ if ch in "?:":
749
+ flow_indicators = True
750
+ if followed_by_whitespace:
751
+ block_indicators = True
752
+ if ch == "-" and followed_by_whitespace:
753
+ flow_indicators = True
754
+ block_indicators = True
755
+ else:
756
+ # Some indicators cannot appear within a scalar as well.
757
+ if ch in ",?[]{}":
758
+ flow_indicators = True
759
+ if ch == ":":
760
+ flow_indicators = True
761
+ if followed_by_whitespace:
762
+ block_indicators = True
763
+ if ch == "#" and preceded_by_whitespace:
764
+ flow_indicators = True
765
+ block_indicators = True
766
+
767
+ # Check for line breaks, special, and unicode characters.
768
+ if ch in "\n\x85\u2028\u2029":
769
+ line_breaks = True
770
+ if not (ch == "\n" or "\x20" <= ch <= "\x7E"):
771
+ if (
772
+ ch == "\x85"
773
+ or "\xA0" <= ch <= "\uD7FF"
774
+ or "\uE000" <= ch <= "\uFFFD"
775
+ or "\U00010000" <= ch < "\U0010ffff"
776
+ ) and ch != "\uFEFF":
777
+ unicode_characters = True
778
+ if not self.allow_unicode:
779
+ special_characters = True
780
+ else:
781
+ special_characters = True
782
+
783
+ # Detect important whitespace combinations.
784
+ if ch == " ":
785
+ if index == 0:
786
+ leading_space = True
787
+ if index == len(scalar) - 1:
788
+ trailing_space = True
789
+ if previous_break:
790
+ break_space = True
791
+ previous_space = True
792
+ previous_break = False
793
+ elif ch in "\n\x85\u2028\u2029":
794
+ if index == 0:
795
+ leading_break = True
796
+ if index == len(scalar) - 1:
797
+ trailing_break = True
798
+ if previous_space:
799
+ space_break = True
800
+ previous_space = False
801
+ previous_break = True
802
+ else:
803
+ previous_space = False
804
+ previous_break = False
805
+
806
+ # Prepare for the next character.
807
+ index += 1
808
+ preceded_by_whitespace = ch in "\0 \t\r\n\x85\u2028\u2029"
809
+ followed_by_whitespace = (
810
+ index + 1 >= len(scalar)
811
+ or scalar[index + 1] in "\0 \t\r\n\x85\u2028\u2029"
812
+ )
813
+
814
+ # Let's decide what styles are allowed.
815
+ allow_flow_plain = True
816
+ allow_block_plain = True
817
+ allow_single_quoted = True
818
+ allow_double_quoted = True
819
+ allow_block = True
820
+
821
+ # Leading and trailing whitespaces are bad for plain scalars.
822
+ if leading_space or leading_break or trailing_space or trailing_break:
823
+ allow_flow_plain = allow_block_plain = False
824
+
825
+ # We do not permit trailing spaces for block scalars.
826
+ if trailing_space:
827
+ allow_block = False
828
+
829
+ # Spaces at the beginning of a new line are only acceptable for block
830
+ # scalars.
831
+ if break_space:
832
+ allow_flow_plain = allow_block_plain = allow_single_quoted = False
833
+
834
+ # Spaces followed by breaks, as well as special character are only
835
+ # allowed for double quoted scalars.
836
+ if space_break or special_characters:
837
+ allow_flow_plain = (
838
+ allow_block_plain
839
+ ) = allow_single_quoted = allow_block = False
840
+
841
+ # Although the plain scalar writer supports breaks, we never emit
842
+ # multiline plain scalars.
843
+ if line_breaks:
844
+ allow_flow_plain = allow_block_plain = False
845
+
846
+ # Flow indicators are forbidden for flow plain scalars.
847
+ if flow_indicators:
848
+ allow_flow_plain = False
849
+
850
+ # Block indicators are forbidden for block plain scalars.
851
+ if block_indicators:
852
+ allow_block_plain = False
853
+
854
+ return ScalarAnalysis(
855
+ scalar=scalar,
856
+ empty=False,
857
+ multiline=line_breaks,
858
+ allow_flow_plain=allow_flow_plain,
859
+ allow_block_plain=allow_block_plain,
860
+ allow_single_quoted=allow_single_quoted,
861
+ allow_double_quoted=allow_double_quoted,
862
+ allow_block=allow_block,
863
+ )
864
+
865
+ # Writers.
866
+
867
+ def flush_stream(self):
868
+ if hasattr(self.stream, "flush"):
869
+ self.stream.flush()
870
+
871
+ def write_stream_start(self):
872
+ # Write BOM if needed.
873
+ if self.encoding and self.encoding.startswith("utf-16"):
874
+ self.stream.write("\uFEFF".encode(self.encoding))
875
+
876
+ def write_stream_end(self):
877
+ self.flush_stream()
878
+
879
+ def write_indicator(
880
+ self, indicator, need_whitespace, whitespace=False, indention=False
881
+ ):
882
+ if self.whitespace or not need_whitespace:
883
+ data = indicator
884
+ else:
885
+ data = " " + indicator
886
+ self.whitespace = whitespace
887
+ self.indention = self.indention and indention
888
+ self.column += len(data)
889
+ self.open_ended = False
890
+ if self.encoding:
891
+ data = data.encode(self.encoding)
892
+ self.stream.write(data)
893
+
894
+ def write_indent(self):
895
+ indent = self.indent or 0
896
+ if (
897
+ not self.indention
898
+ or self.column > indent
899
+ or (self.column == indent and not self.whitespace)
900
+ ):
901
+ self.write_line_break()
902
+ if self.column < indent:
903
+ self.whitespace = True
904
+ data = " " * (indent - self.column)
905
+ self.column = indent
906
+ if self.encoding:
907
+ data = data.encode(self.encoding)
908
+ self.stream.write(data)
909
+
910
+ def write_line_break(self, data=None):
911
+ if data is None:
912
+ data = self.best_line_break
913
+ self.whitespace = True
914
+ self.indention = True
915
+ self.line += 1
916
+ self.column = 0
917
+ if self.encoding:
918
+ data = data.encode(self.encoding)
919
+ self.stream.write(data)
920
+
921
+ def write_version_directive(self, version_text):
922
+ data = "%%YAML %s" % version_text
923
+ if self.encoding:
924
+ data = data.encode(self.encoding)
925
+ self.stream.write(data)
926
+ self.write_line_break()
927
+
928
+ def write_tag_directive(self, handle_text, prefix_text):
929
+ data = "%%TAG %s %s" % (handle_text, prefix_text)
930
+ if self.encoding:
931
+ data = data.encode(self.encoding)
932
+ self.stream.write(data)
933
+ self.write_line_break()
934
+
935
+ # Scalar streams.
936
+
937
+ def write_single_quoted(self, text, split=True):
938
+ self.write_indicator("'", True)
939
+ spaces = False
940
+ breaks = False
941
+ start = end = 0
942
+ while end <= len(text):
943
+ ch = None
944
+ if end < len(text):
945
+ ch = text[end]
946
+ if spaces:
947
+ if ch is None or ch != " ":
948
+ if (
949
+ start + 1 == end
950
+ and self.column > self.best_width
951
+ and split
952
+ and start != 0
953
+ and end != len(text)
954
+ ):
955
+ self.write_indent()
956
+ else:
957
+ data = text[start:end]
958
+ self.column += len(data)
959
+ if self.encoding:
960
+ data = data.encode(self.encoding)
961
+ self.stream.write(data)
962
+ start = end
963
+ elif breaks:
964
+ if ch is None or ch not in "\n\x85\u2028\u2029":
965
+ if text[start] == "\n":
966
+ self.write_line_break()
967
+ for br in text[start:end]:
968
+ if br == "\n":
969
+ self.write_line_break()
970
+ else:
971
+ self.write_line_break(br)
972
+ self.write_indent()
973
+ start = end
974
+ else:
975
+ if ch is None or ch in " \n\x85\u2028\u2029" or ch == "'":
976
+ if start < end:
977
+ data = text[start:end]
978
+ self.column += len(data)
979
+ if self.encoding:
980
+ data = data.encode(self.encoding)
981
+ self.stream.write(data)
982
+ start = end
983
+ if ch == "'":
984
+ data = "''"
985
+ self.column += 2
986
+ if self.encoding:
987
+ data = data.encode(self.encoding)
988
+ self.stream.write(data)
989
+ start = end + 1
990
+ if ch is not None:
991
+ spaces = ch == " "
992
+ breaks = ch in "\n\x85\u2028\u2029"
993
+ end += 1
994
+ self.write_indicator("'", False)
995
+
996
+ ESCAPE_REPLACEMENTS = {
997
+ "\0": "0",
998
+ "\x07": "a",
999
+ "\x08": "b",
1000
+ "\x09": "t",
1001
+ "\x0A": "n",
1002
+ "\x0B": "v",
1003
+ "\x0C": "f",
1004
+ "\x0D": "r",
1005
+ "\x1B": "e",
1006
+ '"': '"',
1007
+ "\\": "\\",
1008
+ "\x85": "N",
1009
+ "\xA0": "_",
1010
+ "\u2028": "L",
1011
+ "\u2029": "P",
1012
+ }
1013
+
1014
+ def write_double_quoted(self, text, split=True):
1015
+ self.write_indicator('"', True)
1016
+ start = end = 0
1017
+ while end <= len(text):
1018
+ ch = None
1019
+ if end < len(text):
1020
+ ch = text[end]
1021
+ if (
1022
+ ch is None
1023
+ or ch in '"\\\x85\u2028\u2029\uFEFF'
1024
+ or not (
1025
+ "\x20" <= ch <= "\x7E"
1026
+ or (
1027
+ self.allow_unicode
1028
+ and ("\xA0" <= ch <= "\uD7FF" or "\uE000" <= ch <= "\uFFFD")
1029
+ )
1030
+ )
1031
+ ):
1032
+ if start < end:
1033
+ data = text[start:end]
1034
+ self.column += len(data)
1035
+ if self.encoding:
1036
+ data = data.encode(self.encoding)
1037
+ self.stream.write(data)
1038
+ start = end
1039
+ if ch is not None:
1040
+ if ch in self.ESCAPE_REPLACEMENTS:
1041
+ data = "\\" + self.ESCAPE_REPLACEMENTS[ch]
1042
+ elif ch <= "\xFF":
1043
+ data = "\\x%02X" % ord(ch)
1044
+ elif ch <= "\uFFFF":
1045
+ data = "\\u%04X" % ord(ch)
1046
+ else:
1047
+ data = "\\U%08X" % ord(ch)
1048
+ self.column += len(data)
1049
+ if self.encoding:
1050
+ data = data.encode(self.encoding)
1051
+ self.stream.write(data)
1052
+ start = end + 1
1053
+ if (
1054
+ 0 < end < len(text) - 1
1055
+ and (ch == " " or start >= end)
1056
+ and self.column + (end - start) > self.best_width
1057
+ and split
1058
+ ):
1059
+ data = text[start:end] + "\\"
1060
+ if start < end:
1061
+ start = end
1062
+ self.column += len(data)
1063
+ if self.encoding:
1064
+ data = data.encode(self.encoding)
1065
+ self.stream.write(data)
1066
+ self.write_indent()
1067
+ self.whitespace = False
1068
+ self.indention = False
1069
+ if text[start] == " ":
1070
+ data = "\\"
1071
+ self.column += len(data)
1072
+ if self.encoding:
1073
+ data = data.encode(self.encoding)
1074
+ self.stream.write(data)
1075
+ end += 1
1076
+ self.write_indicator('"', False)
1077
+
1078
+ def determine_block_hints(self, text):
1079
+ hints = ""
1080
+ if text:
1081
+ if text[0] in " \n\x85\u2028\u2029":
1082
+ hints += str(self.best_indent)
1083
+ if text[-1] not in "\n\x85\u2028\u2029":
1084
+ hints += "-"
1085
+ elif len(text) == 1 or text[-2] in "\n\x85\u2028\u2029":
1086
+ hints += "+"
1087
+ return hints
1088
+
1089
+ def write_folded(self, text):
1090
+ hints = self.determine_block_hints(text)
1091
+ self.write_indicator(">" + hints, True)
1092
+ if hints[-1:] == "+":
1093
+ self.open_ended = True
1094
+ self.write_line_break()
1095
+ leading_space = True
1096
+ spaces = False
1097
+ breaks = True
1098
+ start = end = 0
1099
+ while end <= len(text):
1100
+ ch = None
1101
+ if end < len(text):
1102
+ ch = text[end]
1103
+ if breaks:
1104
+ if ch is None or ch not in "\n\x85\u2028\u2029":
1105
+ if (
1106
+ not leading_space
1107
+ and ch is not None
1108
+ and ch != " "
1109
+ and text[start] == "\n"
1110
+ ):
1111
+ self.write_line_break()
1112
+ leading_space = ch == " "
1113
+ for br in text[start:end]:
1114
+ if br == "\n":
1115
+ self.write_line_break()
1116
+ else:
1117
+ self.write_line_break(br)
1118
+ if ch is not None:
1119
+ self.write_indent()
1120
+ start = end
1121
+ elif spaces:
1122
+ if ch != " ":
1123
+ if start + 1 == end and self.column > self.best_width:
1124
+ self.write_indent()
1125
+ else:
1126
+ data = text[start:end]
1127
+ self.column += len(data)
1128
+ if self.encoding:
1129
+ data = data.encode(self.encoding)
1130
+ self.stream.write(data)
1131
+ start = end
1132
+ else:
1133
+ if ch is None or ch in " \n\x85\u2028\u2029":
1134
+ data = text[start:end]
1135
+ self.column += len(data)
1136
+ if self.encoding:
1137
+ data = data.encode(self.encoding)
1138
+ self.stream.write(data)
1139
+ if ch is None:
1140
+ self.write_line_break()
1141
+ start = end
1142
+ if ch is not None:
1143
+ breaks = ch in "\n\x85\u2028\u2029"
1144
+ spaces = ch == " "
1145
+ end += 1
1146
+
1147
+ def write_literal(self, text):
1148
+ hints = self.determine_block_hints(text)
1149
+ self.write_indicator("|" + hints, True)
1150
+ if hints[-1:] == "+":
1151
+ self.open_ended = True
1152
+ self.write_line_break()
1153
+ breaks = True
1154
+ start = end = 0
1155
+ while end <= len(text):
1156
+ ch = None
1157
+ if end < len(text):
1158
+ ch = text[end]
1159
+ if breaks:
1160
+ if ch is None or ch not in "\n\x85\u2028\u2029":
1161
+ for br in text[start:end]:
1162
+ if br == "\n":
1163
+ self.write_line_break()
1164
+ else:
1165
+ self.write_line_break(br)
1166
+ if ch is not None:
1167
+ self.write_indent()
1168
+ start = end
1169
+ else:
1170
+ if ch is None or ch in "\n\x85\u2028\u2029":
1171
+ data = text[start:end]
1172
+ if self.encoding:
1173
+ data = data.encode(self.encoding)
1174
+ self.stream.write(data)
1175
+ if ch is None:
1176
+ self.write_line_break()
1177
+ start = end
1178
+ if ch is not None:
1179
+ breaks = ch in "\n\x85\u2028\u2029"
1180
+ end += 1
1181
+
1182
+ def write_plain(self, text, split=True):
1183
+ if self.root_context:
1184
+ self.open_ended = True
1185
+ if not text:
1186
+ return
1187
+ if not self.whitespace:
1188
+ data = " "
1189
+ self.column += len(data)
1190
+ if self.encoding:
1191
+ data = data.encode(self.encoding)
1192
+ self.stream.write(data)
1193
+ self.whitespace = False
1194
+ self.indention = False
1195
+ spaces = False
1196
+ breaks = False
1197
+ start = end = 0
1198
+ while end <= len(text):
1199
+ ch = None
1200
+ if end < len(text):
1201
+ ch = text[end]
1202
+ if spaces:
1203
+ if ch != " ":
1204
+ if start + 1 == end and self.column > self.best_width and split:
1205
+ self.write_indent()
1206
+ self.whitespace = False
1207
+ self.indention = False
1208
+ else:
1209
+ data = text[start:end]
1210
+ self.column += len(data)
1211
+ if self.encoding:
1212
+ data = data.encode(self.encoding)
1213
+ self.stream.write(data)
1214
+ start = end
1215
+ elif breaks:
1216
+ if ch not in "\n\x85\u2028\u2029":
1217
+ if text[start] == "\n":
1218
+ self.write_line_break()
1219
+ for br in text[start:end]:
1220
+ if br == "\n":
1221
+ self.write_line_break()
1222
+ else:
1223
+ self.write_line_break(br)
1224
+ self.write_indent()
1225
+ self.whitespace = False
1226
+ self.indention = False
1227
+ start = end
1228
+ else:
1229
+ if ch is None or ch in " \n\x85\u2028\u2029":
1230
+ data = text[start:end]
1231
+ self.column += len(data)
1232
+ if self.encoding:
1233
+ data = data.encode(self.encoding)
1234
+ self.stream.write(data)
1235
+ start = end
1236
+ if ch is not None:
1237
+ spaces = ch == " "
1238
+ breaks = ch in "\n\x85\u2028\u2029"
1239
+ end += 1