14 __all__ = [
'Emitter',
'EmitterError']
16 from error
import YAMLError
25 def __init__(self, scalar, empty, multiline,
26 allow_flow_plain, allow_block_plain,
27 allow_single_quoted, allow_double_quoted,
40 DEFAULT_TAG_PREFIXES = {
42 u'tag:yaml.org,2002:' :
u'!!',
45 def __init__(self, stream, canonical=None, indent=None, width=None,
46 allow_unicode=
None, line_break=
None):
90 if indent
and 1 < indent < 10:
96 if line_break
in [
u'\r',
u'\n',
u'\r\n']:
111 self.events.append(event)
113 self.
event = self.events.pop(0)
123 if isinstance(event, DocumentStartEvent):
125 elif isinstance(event, SequenceStartEvent):
127 elif isinstance(event, MappingStartEvent):
134 for event
in self.
events[1:]:
135 if isinstance(event, (DocumentStartEvent, CollectionStartEvent)):
137 elif isinstance(event, (DocumentEndEvent, CollectionEndEvent)):
139 elif isinstance(event, StreamEndEvent):
146 self.indents.append(self.
indent)
160 if isinstance(self.
event, StreamStartEvent):
161 if self.event.encoding:
166 raise EmitterError(
"expected StreamStartEvent, but got %s"
178 if isinstance(self.
event, DocumentStartEvent):
179 if self.event.version:
184 handles = self.event.tags.keys()
186 for handle
in handles:
187 prefix = self.event.tags[handle]
192 implicit = (first
and not self.event.explicit
and not self.
canonical
193 and not self.event.version
and not self.event.tags
201 elif isinstance(self.
event, StreamEndEvent):
205 raise EmitterError(
"expected DocumentStartEvent, but got %s"
209 if isinstance(self.
event, DocumentEndEvent):
211 if self.event.explicit:
217 raise EmitterError(
"expected DocumentEndEvent, but got %s"
226 def expect_node(self, root=False, sequence=False, mapping=False,
232 if isinstance(self.
event, AliasEvent):
234 elif isinstance(self.
event, (ScalarEvent, CollectionStartEvent)):
237 if isinstance(self.
event, ScalarEvent):
239 elif isinstance(self.
event, SequenceStartEvent):
245 elif isinstance(self.
event, MappingStartEvent):
255 if self.event.anchor
is None:
258 self.
state = self.states.pop()
263 self.
indent = self.indents.pop()
264 self.
state = self.states.pop()
275 if isinstance(self.
event, SequenceEndEvent):
276 self.
indent = self.indents.pop()
279 self.
state = self.states.pop()
287 if isinstance(self.
event, SequenceEndEvent):
288 self.
indent = self.indents.pop()
294 self.
state = self.states.pop()
311 if isinstance(self.
event, MappingEndEvent):
312 self.
indent = self.indents.pop()
315 self.
state = self.states.pop()
328 if isinstance(self.
event, MappingEndEvent):
329 self.
indent = self.indents.pop()
335 self.
state = self.states.pop()
371 if not first
and isinstance(self.
event, SequenceEndEvent):
372 self.
indent = self.indents.pop()
373 self.
state = self.states.pop()
390 if not first
and isinstance(self.
event, MappingEndEvent):
391 self.
indent = self.indents.pop()
392 self.
state = self.states.pop()
417 return (isinstance(self.
event, SequenceStartEvent)
and self.
events
418 and isinstance(self.
events[0], SequenceEndEvent))
421 return (isinstance(self.
event, MappingStartEvent)
and self.
events
422 and isinstance(self.
events[0], MappingEndEvent))
425 if not isinstance(self.
event, DocumentStartEvent)
or not self.
events:
428 return (isinstance(event, ScalarEvent)
and event.anchor
is None
429 and event.tag
is None and event.implicit
and event.value ==
u'')
433 if isinstance(self.
event, NodeEvent)
and self.event.anchor
is not None:
437 if isinstance(self.
event, (ScalarEvent, CollectionStartEvent)) \
438 and self.event.tag
is not None:
442 if isinstance(self.
event, ScalarEvent):
445 length +=
len(self.analysis.scalar)
446 return (length < 128
and (isinstance(self.
event, AliasEvent)
447 or (isinstance(self.
event, ScalarEvent)
448 and not self.analysis.empty
and not self.analysis.multiline)
454 if self.event.anchor
is None:
465 if isinstance(self.
event, ScalarEvent):
466 if self.
style is None:
468 if ((
not self.
canonical or tag
is None)
and
469 ((self.
style ==
'' and self.event.implicit[0])
470 or (self.
style !=
'' and self.event.implicit[1]))):
473 if self.event.implicit[0]
and tag
is None:
477 if (
not self.
canonical or tag
is None)
and self.event.implicit:
491 if self.event.style ==
'"' or self.
canonical:
493 if not self.event.style
and self.event.implicit[0]:
495 (self.analysis.empty
or self.analysis.multiline))
496 and (self.
flow_level and self.analysis.allow_flow_plain
497 or (
not self.
flow_level and self.analysis.allow_block_plain))):
499 if self.event.style
and self.event.style
in '|>':
501 and self.analysis.allow_block):
502 return self.event.style
503 if not self.event.style
or self.event.style ==
'\'':
504 if (self.analysis.allow_single_quoted
and
512 if self.
style is None:
518 if self.
style ==
'"':
519 self.write_double_quoted(self.analysis.scalar, split)
520 elif self.
style ==
'\'':
522 elif self.
style ==
'>':
523 self.write_folded(self.analysis.scalar)
524 elif self.
style ==
'|':
525 self.write_literal(self.analysis.scalar)
527 self.write_plain(self.analysis.scalar, split)
534 major, minor = version
536 raise EmitterError(
"unsupported YAML version: %d.%d" % (major, minor))
537 return u'%d.%d' % (major, minor)
542 if handle[0] !=
u'!' or handle[-1] !=
u'!':
543 raise EmitterError(
"tag handle must start and end with '!': %r"
544 % (handle.encode(
'utf-8')))
545 for ch
in handle[1:-1]:
546 if not (
u'0' <= ch <=
u'9' or u'A' <= ch <=
'Z' or u'a' <= ch <=
'z' \
548 raise EmitterError(
"invalid character %r in the tag handle: %r"
549 % (ch.encode(
'utf-8'), handle.encode(
'utf-8')))
557 if prefix[0] ==
u'!':
559 while end <
len(prefix):
561 if u'0' <= ch <=
u'9' or u'A' <= ch <=
'Z' or u'a' <= ch <=
'z' \
562 or ch
in u'-;/?!:@&=+$,_.~*\'()[]':
566 chunks.append(prefix[start:end])
568 data = ch.encode(
'utf-8')
570 chunks.append(
u'%%%02X' % ord(ch))
572 chunks.append(prefix[start:end])
573 return u''.
join(chunks)
583 if tag.startswith(prefix) \
584 and (prefix ==
u'!' or len(prefix) <
len(tag)):
586 suffix = tag[
len(prefix):]
589 while end <
len(suffix):
591 if u'0' <= ch <=
u'9' or u'A' <= ch <=
'Z' or u'a' <= ch <=
'z' \
592 or ch
in u'-;/?:@&=+$,_.~*\'()[]' \
593 or (ch ==
u'!' and handle !=
u'!'):
597 chunks.append(suffix[start:end])
599 data = ch.encode(
'utf-8')
601 chunks.append(
u'%%%02X' % ord(ch))
603 chunks.append(suffix[start:end])
604 suffix_text =
u''.
join(chunks)
606 return u'%s%s' % (handle, suffix_text)
608 return u'!<%s>' % suffix_text
614 if not (
u'0' <= ch <=
u'9' or u'A' <= ch <=
'Z' or u'a' <= ch <=
'z' \
616 raise EmitterError(
"invalid character %r in the anchor: %r"
617 % (ch.encode(
'utf-8'), anchor.encode(
'utf-8')))
625 allow_flow_plain=
False, allow_block_plain=
True,
626 allow_single_quoted=
True, allow_double_quoted=
True,
630 block_indicators =
False
631 flow_indicators =
False
633 special_characters =
False
636 inline_spaces =
False
637 inline_breaks =
False
638 leading_spaces =
False
639 leading_breaks =
False
640 trailing_spaces =
False
641 trailing_breaks =
False
642 inline_breaks_spaces =
False
643 mixed_breaks_spaces =
False
646 if scalar.startswith(
u'---')
or scalar.startswith(
u'...'):
647 block_indicators =
True
648 flow_indicators =
True
651 preceeded_by_space =
True
654 followed_by_space = (
len(scalar) == 1
or
655 scalar[1]
in u'\0 \t\r\n\x85\u2028\u2029')
672 while index <
len(scalar):
679 if ch
in u'#,[]{}&*!|>\'\"%@`':
680 flow_indicators =
True
681 block_indicators =
True
683 flow_indicators =
True
684 if followed_by_space:
685 block_indicators =
True
686 if ch ==
u'-' and followed_by_space:
687 flow_indicators =
True
688 block_indicators =
True
692 flow_indicators =
True
694 flow_indicators =
True
695 if followed_by_space:
696 block_indicators =
True
697 if ch ==
u'#' and preceeded_by_space:
698 flow_indicators =
True
699 block_indicators =
True
703 if ch
in u'\n\x85\u2028\u2029':
705 if not (ch ==
u'\n' or u'\x20' <= ch <=
u'\x7E'):
706 if (ch ==
u'\x85' or u'\xA0' <= ch <=
u'\uD7FF'
707 or u'\uE000' <= ch <=
u'\uFFFD')
and ch !=
u'\uFEFF':
708 unicode_characters =
True
710 special_characters =
True
712 special_characters =
True
717 if ch
in u' \n\x85\u2028\u2029':
718 if spaces
and breaks:
729 leading = (index == 0)
736 elif spaces
or breaks:
738 if spaces
and breaks:
739 mixed_breaks_spaces =
True
741 leading_spaces =
True
743 leading_breaks =
True
746 mixed_breaks_spaces =
True
747 elif spaces
and breaks:
748 inline_breaks_spaces =
True
753 spaces = breaks = mixed = leading =
False
756 if (spaces
or breaks)
and (index ==
len(scalar)-1):
757 if spaces
and breaks:
758 mixed_breaks_spaces =
True
760 trailing_spaces =
True
762 leading_spaces =
True
764 trailing_breaks =
True
766 leading_breaks =
True
767 spaces = breaks = mixed = leading =
False
771 preceeded_by_space = (ch
in u'\0 \t\r\n\x85\u2028\u2029')
772 followed_by_space = (index+1 >=
len(scalar)
or
773 scalar[index+1]
in u'\0 \t\r\n\x85\u2028\u2029')
776 allow_flow_plain =
True
777 allow_block_plain =
True
778 allow_single_quoted =
True
779 allow_double_quoted =
True
784 if leading_spaces
or leading_breaks
or trailing_spaces:
785 allow_flow_plain = allow_block_plain = allow_block =
False
790 allow_flow_plain = allow_block_plain =
False
794 if inline_breaks_spaces:
795 allow_flow_plain = allow_block_plain = allow_single_quoted =
False
799 if mixed_breaks_spaces
or special_characters:
800 allow_flow_plain = allow_block_plain = \
801 allow_single_quoted = allow_block =
False
805 allow_flow_plain = allow_block_plain =
False
809 allow_flow_plain =
False
813 allow_block_plain =
False
816 empty=
False, multiline=line_breaks,
817 allow_flow_plain=allow_flow_plain,
818 allow_block_plain=allow_block_plain,
819 allow_single_quoted=allow_single_quoted,
820 allow_double_quoted=allow_double_quoted,
821 allow_block=allow_block)
826 if hasattr(self.
stream,
'flush'):
831 if self.
encoding and self.encoding.startswith(
'utf-16'):
832 self.stream.write(
u'\xFF\xFE'.encode(self.
encoding))
838 whitespace=
False, indention=
False):
842 data =
u' '+indicator
848 self.stream.write(data)
857 data =
u' '*(indent-self.
column)
861 self.stream.write(data)
872 self.stream.write(data)
875 data =
u'%%YAML %s' % version_text
878 self.stream.write(data)
882 data =
u'%%TAG %s %s' % (handle_text, prefix_text)
885 self.stream.write(data)
895 while end <=
len(text):
900 if ch
is None or ch !=
u' ':
902 and start != 0
and end !=
len(text):
905 data = text[start:end]
909 self.stream.write(data)
912 if ch
is None or ch
not in u'\n\x85\u2028\u2029':
913 if text[start] ==
u'\n':
915 for br
in text[start:end]:
923 if ch
is None or ch
in u' \n\x85\u2028\u2029' or ch ==
u'\'':
925 data = text[start:end]
929 self.stream.write(data)
936 self.stream.write(data)
939 spaces = (ch ==
u' ')
940 breaks = (ch
in u'\n\x85\u2028\u2029')
944 ESCAPE_REPLACEMENTS = {
962 def write_double_quoted(self, text, split=True):
965 while end <=
len(text):
969 if ch
is None or ch
in u'"\\\x85\u2028\u2029\uFEFF' \
970 or not (
u'\x20' <= ch <=
u'\x7E'
972 and (
u'\xA0' <= ch <=
u'\uD7FF'
973 or u'\uE000' <= ch <=
u'\uFFFD'))):
975 data = text[start:end]
979 self.stream.write(data)
982 if ch
in self.ESCAPE_REPLACEMENTS:
983 data =
u'\\'+self.ESCAPE_REPLACEMENTS[ch]
985 data =
u'\\x%02X' % ord(ch)
986 elif ch <=
u'\uFFFF':
987 data =
u'\\u%04X' % ord(ch)
989 data =
u'\\U%08X' % ord(ch)
993 self.stream.write(data)
995 if 0 < end <
len(text)-1
and (ch ==
u' ' or start >= end) \
997 data = text[start:end]+
u'\\'
1003 self.stream.write(data)
1007 if text[start] ==
u' ':
1012 self.stream.write(data)
1016 def determine_chomp(self, text):
1018 while len(tail) < 2:
1020 if tail[-1]
in u'\n\x85\u2028\u2029':
1021 if tail[-2]
in u'\n\x85\u2028\u2029':
1028 def write_folded(self, text):
1029 chomp = self.determine_chomp(text)
1032 leading_space =
False
1036 while end <=
len(text):
1041 if ch
is None or ch
not in u'\n\x85\u2028\u2029':
1042 if not leading_space
and ch
is not None and ch !=
u' ' \
1043 and text[start] ==
u'\n':
1045 leading_space = (ch ==
u' ')
1046 for br
in text[start:end]:
1059 data = text[start:end]
1063 self.stream.write(data)
1066 if ch
is None or ch
in u' \n\x85\u2028\u2029':
1067 data = text[start:end]
1070 self.stream.write(data)
1075 breaks = (ch
in u'\n\x85\u2028\u2029')
1076 spaces = (ch ==
u' ')
1079 def write_literal(self, text):
1080 chomp = self.determine_chomp(text)
1085 while end <=
len(text):
1090 if ch
is None or ch
not in u'\n\x85\u2028\u2029':
1091 for br
in text[start:end]:
1100 if ch
is None or ch
in u'\n\x85\u2028\u2029':
1101 data = text[start:end]
1104 self.stream.write(data)
1109 breaks = (ch
in u'\n\x85\u2028\u2029')
1112 def write_plain(self, text, split=True):
1120 self.stream.write(data)
1121 self.writespace =
False
1126 while end <=
len(text):
1134 self.writespace =
False
1137 data = text[start:end]
1141 self.stream.write(data)
1144 if ch
not in u'\n\x85\u2028\u2029':
1145 if text[start] ==
u'\n':
1147 for br
in text[start:end]:
1157 if ch
is None or ch
in u' \n\x85\u2028\u2029':
1158 data = text[start:end]
1162 self.stream.write(data)
1165 spaces = (ch ==
u' ')
1166 breaks = (ch
in u'\n\x85\u2028\u2029')
def expect_block_sequence
def expect_first_flow_mapping_key
def expect_first_document_start
def expect_first_block_sequence_item
def expect_document_start
def expect_block_mapping_key
def expect_flow_mapping_key
Fstring::size_type len(Fstring const &s)
Length.
def expect_flow_mapping_value
def expect_flow_mapping_simple_value
def expect_block_mapping_value
def expect_flow_sequence_item
def write_version_directive
def expect_block_mapping_simple_value
def expect_block_sequence_item
def expect_first_block_mapping_key
def expect_first_flow_sequence_item