# Emitter expects events obeying the following grammar:# stream ::= STREAM-START document* STREAM-END# document ::= DOCUMENT-START node DOCUMENT-END# node ::= SCALAR | sequence | mapping# sequence ::= SEQUENCE-START node* SEQUENCE-END# mapping ::= MAPPING-START (node node)* MAPPING-END__all__=['Emitter','EmitterError']from.errorimportYAMLErrorfrom.eventsimport*classEmitterError(YAMLError):passclassScalarAnalysis:def__init__(self,scalar,empty,multiline,allow_flow_plain,allow_block_plain,allow_single_quoted,allow_double_quoted,allow_block):self.scalar=scalarself.empty=emptyself.multiline=multilineself.allow_flow_plain=allow_flow_plainself.allow_block_plain=allow_block_plainself.allow_single_quoted=allow_single_quotedself.allow_double_quoted=allow_double_quotedself.allow_block=allow_blockclassEmitter:DEFAULT_TAG_PREFIXES={'!':'!','tag:yaml.org,2002:':'!!',}def__init__(self,stream,canonical=None,indent=None,width=None,allow_unicode=None,line_break=None):# The stream should have the methods `write` and possibly `flush`.self.stream=stream# Encoding can be overriden by STREAM-START.self.encoding=None# Emitter is a state machine with a stack of states to handle nested# structures.self.states=[]self.state=self.expect_stream_start# Current event and the event queue.self.events=[]self.event=None# The current indentation level and the stack of previous indents.self.indents=[]self.indent=None# Flow level.self.flow_level=0# Contexts.self.root_context=Falseself.sequence_context=Falseself.mapping_context=Falseself.simple_key_context=False# Characteristics of the last emitted character:# - current position.# - is it a whitespace?# - is it an indention character# (indentation space, '-', '?', or ':')?self.line=0self.column=0self.whitespace=Trueself.indention=True# Whether the document requires an explicit document indicatorself.open_ended=False# Formatting details.self.canonical=canonicalself.allow_unicode=allow_unicodeself.best_indent=2ifindentand1<indent<10:self.best_indent=indentself.best_width=80ifwidthandwidth>self.best_indent*2:self.best_width=widthself.best_line_break='\n'ifline_breakin['\r','\n','\r\n']:self.best_line_break=line_break# Tag prefixes.self.tag_prefixes=None# Prepared anchor and tag.self.prepared_anchor=Noneself.prepared_tag=None# Scalar analysis and style.self.analysis=Noneself.style=Nonedefemit(self,event):self.events.append(event)whilenotself.need_more_events():self.event=self.events.pop(0)self.state()self.event=None# In some cases, we wait for a few next events before emitting.defneed_more_events(self):ifnotself.events:returnTrueevent=self.events[0]ifisinstance(event,DocumentStartEvent):returnself.need_events(1)elifisinstance(event,SequenceStartEvent):returnself.need_events(2)elifisinstance(event,MappingStartEvent):returnself.need_events(3)else:returnFalsedefneed_events(self,count):level=0foreventinself.events[1:]:ifisinstance(event,(DocumentStartEvent,CollectionStartEvent)):level+=1elifisinstance(event,(DocumentEndEvent,CollectionEndEvent)):level-=1elifisinstance(event,StreamEndEvent):level=-1iflevel<0:returnFalsereturn(len(self.events)<count+1)defincrease_indent(self,flow=False,indentless=False):self.indents.append(self.indent)ifself.indentisNone:ifflow:self.indent=self.best_indentelse:self.indent=0elifnotindentless:self.indent+=self.best_indent# States.# Stream handlers.defexpect_stream_start(self):ifisinstance(self.event,StreamStartEvent):ifself.event.encodingandnothasattr(self.stream,'encoding'):self.encoding=self.event.encodingself.write_stream_start()self.state=self.expect_first_document_startelse:raiseEmitterError("expected StreamStartEvent, but got %s"%self.event)defexpect_nothing(self):raiseEmitterError("expected nothing, but got %s"%self.event)# Document handlers.defexpect_first_document_start(self):returnself.expect_document_start(first=True)defexpect_document_start(self,first=False):ifisinstance(self.event,DocumentStartEvent):if(self.event.versionorself.event.tags)andself.open_ended:self.write_indicator('...',True)self.write_indent()ifself.event.version:version_text=self.prepare_version(self.event.version)self.write_version_directive(version_text)self.tag_prefixes=self.DEFAULT_TAG_PREFIXES.copy()ifself.event.tags:handles=sorted(self.event.tags.keys())forhandleinhandles:prefix=self.event.tags[handle]self.tag_prefixes[prefix]=handlehandle_text=self.prepare_tag_handle(handle)prefix_text=self.prepare_tag_prefix(prefix)self.write_tag_directive(handle_text,prefix_text)implicit=(firstandnotself.event.explicitandnotself.canonicalandnotself.event.versionandnotself.event.tagsandnotself.check_empty_document())ifnotimplicit:self.write_indent()self.write_indicator('---',True)ifself.canonical:self.write_indent()self.state=self.expect_document_rootelifisinstance(self.event,StreamEndEvent):ifself.open_ended:self.write_indicator('...',True)self.write_indent()self.write_stream_end()self.state=self.expect_nothingelse:raiseEmitterError("expected DocumentStartEvent, but got %s"%self.event)defexpect_document_end(self):ifisinstance(self.event,DocumentEndEvent):self.write_indent()ifself.event.explicit:self.write_indicator('...',True)self.write_indent()self.flush_stream()self.state=self.expect_document_startelse:raiseEmitterError("expected DocumentEndEvent, but got %s"%self.event)defexpect_document_root(self):self.states.append(self.expect_document_end)self.expect_node(root=True)# Node handlers.defexpect_node(self,root=False,sequence=False,mapping=False,simple_key=False):self.root_context=rootself.sequence_context=sequenceself.mapping_context=mappingself.simple_key_context=simple_keyifisinstance(self.event,AliasEvent):self.expect_alias()elifisinstance(self.event,(ScalarEvent,CollectionStartEvent)):self.process_anchor('&')self.process_tag()ifisinstance(self.event,ScalarEvent):self.expect_scalar()elifisinstance(self.event,SequenceStartEvent):ifself.flow_levelorself.canonicalorself.event.flow_style \
orself.check_empty_sequence():self.expect_flow_sequence()else:self.expect_block_sequence()elifisinstance(self.event,MappingStartEvent):ifself.flow_levelorself.canonicalorself.event.flow_style \
orself.check_empty_mapping():self.expect_flow_mapping()else:self.expect_block_mapping()else:raiseEmitterError("expected NodeEvent, but got %s"%self.event)defexpect_alias(self):ifself.event.anchorisNone:raiseEmitterError("anchor is not specified for alias")self.process_anchor('*')self.state=self.states.pop()defexpect_scalar(self):self.increase_indent(flow=True)self.process_scalar()self.indent=self.indents.pop()self.state=self.states.pop()# Flow sequence handlers.defexpect_flow_sequence(self):self.write_indicator('[',True,whitespace=True)self.flow_level+=1self.increase_indent(flow=True)self.state=self.expect_first_flow_sequence_itemdefexpect_first_flow_sequence_item(self):ifisinstance(self.event,SequenceEndEvent):self.indent=self.indents.pop()self.flow_level-=1self.write_indicator(']',False)self.state=self.states.pop()else:ifself.canonicalorself.column>self.best_width:self.write_indent()self.states.append(self.expect_flow_sequence_item)self.expect_node(sequence=True)defexpect_flow_sequence_item(self):ifisinstance(self.event,SequenceEndEvent):self.indent=self.indents.pop()self.flow_level-=1ifself.canonical:self.write_indicator(',',False)self.write_indent()self.write_indicator(']',False)self.state=self.states.pop()else:self.write_indicator(',',False)ifself.canonicalorself.column>self.best_width:self.write_indent()self.states.append(self.expect_flow_sequence_item)self.expect_node(sequence=True)# Flow mapping handlers.defexpect_flow_mapping(self):self.write_indicator('{',True,whitespace=True)self.flow_level+=1self.increase_indent(flow=True)self.state=self.expect_first_flow_mapping_keydefexpect_first_flow_mapping_key(self):ifisinstance(self.event,MappingEndEvent):self.indent=self.indents.pop()self.flow_level-=1self.write_indicator('}',False)self.state=self.states.pop()else:ifself.canonicalorself.column>self.best_width:self.write_indent()ifnotself.canonicalandself.check_simple_key():self.states.append(self.expect_flow_mapping_simple_value)self.expect_node(mapping=True,simple_key=True)else:self.write_indicator('?',True)self.states.append(self.expect_flow_mapping_value)self.expect_node(mapping=True)defexpect_flow_mapping_key(self):ifisinstance(self.event,MappingEndEvent):self.indent=self.indents.pop()self.flow_level-=1ifself.canonical:self.write_indicator(',',False)self.write_indent()self.write_indicator('}',False)self.state=self.states.pop()else:self.write_indicator(',',False)ifself.canonicalorself.column>self.best_width:self.write_indent()ifnotself.canonicalandself.check_simple_key():self.states.append(self.expect_flow_mapping_simple_value)self.expect_node(mapping=True,simple_key=True)else:self.write_indicator('?',True)self.states.append(self.expect_flow_mapping_value)self.expect_node(mapping=True)defexpect_flow_mapping_simple_value(self):self.write_indicator(':',False)self.states.append(self.expect_flow_mapping_key)self.expect_node(mapping=True)defexpect_flow_mapping_value(self):ifself.canonicalorself.column>self.best_width:self.write_indent()self.write_indicator(':',True)self.states.append(self.expect_flow_mapping_key)self.expect_node(mapping=True)# Block sequence handlers.defexpect_block_sequence(self):indentless=(self.mapping_contextandnotself.indention)self.increase_indent(flow=False,indentless=indentless)self.state=self.expect_first_block_sequence_itemdefexpect_first_block_sequence_item(self):returnself.expect_block_sequence_item(first=True)defexpect_block_sequence_item(self,first=False):ifnotfirstandisinstance(self.event,SequenceEndEvent):self.indent=self.indents.pop()self.state=self.states.pop()else:self.write_indent()self.write_indicator('-',True,indention=True)self.states.append(self.expect_block_sequence_item)self.expect_node(sequence=True)# Block mapping handlers.defexpect_block_mapping(self):self.increase_indent(flow=False)self.state=self.expect_first_block_mapping_keydefexpect_first_block_mapping_key(self):returnself.expect_block_mapping_key(first=True)defexpect_block_mapping_key(self,first=False):ifnotfirstandisinstance(self.event,MappingEndEvent):self.indent=self.indents.pop()self.state=self.states.pop()else:self.write_indent()ifself.check_simple_key():self.states.append(self.expect_block_mapping_simple_value)self.expect_node(mapping=True,simple_key=True)else:self.write_indicator('?',True,indention=True)self.states.append(self.expect_block_mapping_value)self.expect_node(mapping=True)defexpect_block_mapping_simple_value(self):self.write_indicator(':',False)self.states.append(self.expect_block_mapping_key)self.expect_node(mapping=True)defexpect_block_mapping_value(self):self.write_indent()self.write_indicator(':',True,indention=True)self.states.append(self.expect_block_mapping_key)self.expect_node(mapping=True)# Checkers.defcheck_empty_sequence(self):return(isinstance(self.event,SequenceStartEvent)andself.eventsandisinstance(self.events[0],SequenceEndEvent))defcheck_empty_mapping(self):return(isinstance(self.event,MappingStartEvent)andself.eventsandisinstance(self.events[0],MappingEndEvent))defcheck_empty_document(self):ifnotisinstance(self.event,DocumentStartEvent)ornotself.events:returnFalseevent=self.events[0]return(isinstance(event,ScalarEvent)andevent.anchorisNoneandevent.tagisNoneandevent.implicitandevent.value=='')defcheck_simple_key(self):length=0ifisinstance(self.event,NodeEvent)andself.event.anchorisnotNone:ifself.prepared_anchorisNone:self.prepared_anchor=self.prepare_anchor(self.event.anchor)length+=len(self.prepared_anchor)ifisinstance(self.event,(ScalarEvent,CollectionStartEvent)) \
andself.event.tagisnotNone:ifself.prepared_tagisNone:self.prepared_tag=self.prepare_tag(self.event.tag)length+=len(self.prepared_tag)ifisinstance(self.event,ScalarEvent):ifself.analysisisNone:self.analysis=self.analyze_scalar(self.event.value)length+=len(self.analysis.scalar)return(length<128and(isinstance(self.event,AliasEvent)or(isinstance(self.event,ScalarEvent)andnotself.analysis.emptyandnotself.analysis.multiline)orself.check_empty_sequence()orself.check_empty_mapping()))# Anchor, Tag, and Scalar processors.defprocess_anchor(self,indicator):ifself.event.anchorisNone:self.prepared_anchor=Nonereturnifself.prepared_anchorisNone:self.prepared_anchor=self.prepare_anchor(self.event.anchor)ifself.prepared_anchor:self.write_indicator(indicator+self.prepared_anchor,True)self.prepared_anchor=Nonedefprocess_tag(self):tag=self.event.tagifisinstance(self.event,ScalarEvent):ifself.styleisNone:self.style=self.choose_scalar_style()if((notself.canonicalortagisNone)and((self.style==''andself.event.implicit[0])or(self.style!=''andself.event.implicit[1]))):self.prepared_tag=Nonereturnifself.event.implicit[0]andtagisNone:tag='!'self.prepared_tag=Noneelse:if(notself.canonicalortagisNone)andself.event.implicit:self.prepared_tag=NonereturniftagisNone:raiseEmitterError("tag is not specified")ifself.prepared_tagisNone:self.prepared_tag=self.prepare_tag(tag)ifself.prepared_tag:self.write_indicator(self.prepared_tag,True)self.prepared_tag=Nonedefchoose_scalar_style(self):ifself.analysisisNone:self.analysis=self.analyze_scalar(self.event.value)ifself.event.style=='"'orself.canonical:return'"'ifnotself.event.styleandself.event.implicit[0]:if(not(self.simple_key_contextand(self.analysis.emptyorself.analysis.multiline))and(self.flow_levelandself.analysis.allow_flow_plainor(notself.flow_levelandself.analysis.allow_block_plain))):return''ifself.event.styleandself.event.stylein'|>':if(notself.flow_levelandnotself.simple_key_contextandself.analysis.allow_block):returnself.event.styleifnotself.event.styleorself.event.style=='\'':if(self.analysis.allow_single_quotedandnot(self.simple_key_contextandself.analysis.multiline)):return'\''return'"'defprocess_scalar(self):ifself.analysisisNone:self.analysis=self.analyze_scalar(self.event.value)ifself.styleisNone:self.style=self.choose_scalar_style()split=(notself.simple_key_context)#if self.analysis.multiline and split \# and (not self.style or self.style in '\'\"'):# self.write_indent()ifself.style=='"':self.write_double_quoted(self.analysis.scalar,split)elifself.style=='\'':self.write_single_quoted(self.analysis.scalar,split)elifself.style=='>':self.write_folded(self.analysis.scalar)elifself.style=='|':self.write_literal(self.analysis.scalar)else:self.write_plain(self.analysis.scalar,split)self.analysis=Noneself.style=None# Analyzers.defprepare_version(self,version):major,minor=versionifmajor!=1:raiseEmitterError("unsupported YAML version: %d.%d"%(major,minor))return'%d.%d'%(major,minor)defprepare_tag_handle(self,handle):ifnothandle:raiseEmitterError("tag handle must not be empty")ifhandle[0]!='!'orhandle[-1]!='!':raiseEmitterError("tag handle must start and end with '!': %r"%handle)forchinhandle[1:-1]:ifnot('0'<=ch<='9'or'A'<=ch<='Z'or'a'<=ch<='z' \
orchin'-_'):raiseEmitterError("invalid character %r in the tag handle: %r"%(ch,handle))returnhandledefprepare_tag_prefix(self,prefix):ifnotprefix:raiseEmitterError("tag prefix must not be empty")chunks=[]start=end=0ifprefix[0]=='!':end=1whileend<len(prefix):ch=prefix[end]if'0'<=ch<='9'or'A'<=ch<='Z'or'a'<=ch<='z' \
orchin'-;/?!:@&=+$,_.~*\'()[]':end+=1else:ifstart<end:chunks.append(prefix[start:end])start=end=end+1data=ch.encode('utf-8')forchindata:chunks.append('%%%02X'%ord(ch))ifstart<end:chunks.append(prefix[start:end])return''.join(chunks)defprepare_tag(self,tag):ifnottag:raiseEmitterError("tag must not be empty")iftag=='!':returntaghandle=Nonesuffix=tagprefixes=sorted(self.tag_prefixes.keys())forprefixinprefixes:iftag.startswith(prefix) \
and(prefix=='!'orlen(prefix)<len(tag)):handle=self.tag_prefixes[prefix]suffix=tag[len(prefix):]chunks=[]start=end=0whileend<len(suffix):ch=suffix[end]if'0'<=ch<='9'or'A'<=ch<='Z'or'a'<=ch<='z' \
orchin'-;/?:@&=+$,_.~*\'()[]' \
or(ch=='!'andhandle!='!'):end+=1else:ifstart<end:chunks.append(suffix[start:end])start=end=end+1data=ch.encode('utf-8')forchindata:chunks.append('%%%02X'%ord(ch))ifstart<end:chunks.append(suffix[start:end])suffix_text=''.join(chunks)ifhandle:return'%s%s'%(handle,suffix_text)else:return'!<%s>'%suffix_textdefprepare_anchor(self,anchor):ifnotanchor:raiseEmitterError("anchor must not be empty")forchinanchor:ifnot('0'<=ch<='9'or'A'<=ch<='Z'or'a'<=ch<='z' \
orchin'-_'):raiseEmitterError("invalid character %r in the anchor: %r"%(ch,anchor))returnanchordefanalyze_scalar(self,scalar):# Empty scalar is a special case.ifnotscalar:returnScalarAnalysis(scalar=scalar,empty=True,multiline=False,allow_flow_plain=False,allow_block_plain=True,allow_single_quoted=True,allow_double_quoted=True,allow_block=False)# Indicators and special characters.block_indicators=Falseflow_indicators=Falseline_breaks=Falsespecial_characters=False# Important whitespace combinations.leading_space=Falseleading_break=Falsetrailing_space=Falsetrailing_break=Falsebreak_space=Falsespace_break=False# Check document indicators.ifscalar.startswith('---')orscalar.startswith('...'):block_indicators=Trueflow_indicators=True# First character or preceded by a whitespace.preceeded_by_whitespace=True# Last character or followed by a whitespace.followed_by_whitespace=(len(scalar)==1orscalar[1]in'\0\t\r\n\x85\u2028\u2029')# The previous character is a space.previous_space=False# The previous character is a break.previous_break=Falseindex=0whileindex<len(scalar):ch=scalar[index]# Check for indicators.ifindex==0:# Leading indicators are special characters.ifchin'#,[]{}&*!|>\'\"%@`':flow_indicators=Trueblock_indicators=Trueifchin'?:':flow_indicators=Trueiffollowed_by_whitespace:block_indicators=Trueifch=='-'andfollowed_by_whitespace:flow_indicators=Trueblock_indicators=Trueelse:# Some indicators cannot appear within a scalar as well.ifchin',?[]{}':flow_indicators=Trueifch==':':flow_indicators=Trueiffollowed_by_whitespace:block_indicators=Trueifch=='#'andpreceeded_by_whitespace:flow_indicators=Trueblock_indicators=True# Check for line breaks, special, and unicode characters.ifchin'\n\x85\u2028\u2029':line_breaks=Trueifnot(ch=='\n'or'\x20'<=ch<='\x7E'):if(ch=='\x85'or'\xA0'<=ch<='\uD7FF'or'\uE000'<=ch<='\uFFFD')andch!='\uFEFF':unicode_characters=Trueifnotself.allow_unicode:special_characters=Trueelse:special_characters=True# Detect important whitespace combinations.ifch==' ':ifindex==0:leading_space=Trueifindex==len(scalar)-1:trailing_space=Trueifprevious_break:break_space=Trueprevious_space=Trueprevious_break=Falseelifchin'\n\x85\u2028\u2029':ifindex==0:leading_break=Trueifindex==len(scalar)-1:trailing_break=Trueifprevious_space:space_break=Trueprevious_space=Falseprevious_break=Trueelse:previous_space=Falseprevious_break=False# Prepare for the next character.index+=1preceeded_by_whitespace=(chin'\0\t\r\n\x85\u2028\u2029')followed_by_whitespace=(index+1>=len(scalar)orscalar[index+1]in'\0\t\r\n\x85\u2028\u2029')# Let's decide what styles are allowed.allow_flow_plain=Trueallow_block_plain=Trueallow_single_quoted=Trueallow_double_quoted=Trueallow_block=True# Leading and trailing whitespaces are bad for plain scalars.if(leading_spaceorleading_breakortrailing_spaceortrailing_break):allow_flow_plain=allow_block_plain=False# We do not permit trailing spaces for block scalars.iftrailing_space:allow_block=False# Spaces at the beginning of a new line are only acceptable for block# scalars.ifbreak_space:allow_flow_plain=allow_block_plain=allow_single_quoted=False# Spaces followed by breaks, as well as special character are only# allowed for double quoted scalars.ifspace_breakorspecial_characters:allow_flow_plain=allow_block_plain= \
allow_single_quoted=allow_block=False# Although the plain scalar writer supports breaks, we never emit# multiline plain scalars.ifline_breaks:allow_flow_plain=allow_block_plain=False# Flow indicators are forbidden for flow plain scalars.ifflow_indicators:allow_flow_plain=False# Block indicators are forbidden for block plain scalars.ifblock_indicators:allow_block_plain=FalsereturnScalarAnalysis(scalar=scalar,empty=False,multiline=line_breaks,allow_flow_plain=allow_flow_plain,allow_block_plain=allow_block_plain,allow_single_quoted=allow_single_quoted,allow_double_quoted=allow_double_quoted,allow_block=allow_block)# Writers.defflush_stream(self):ifhasattr(self.stream,'flush'):self.stream.flush()defwrite_stream_start(self):# Write BOM if needed.ifself.encodingandself.encoding.startswith('utf-16'):self.stream.write('\uFEFF'.encode(self.encoding))defwrite_stream_end(self):self.flush_stream()defwrite_indicator(self,indicator,need_whitespace,whitespace=False,indention=False):ifself.whitespaceornotneed_whitespace:data=indicatorelse:data=' '+indicatorself.whitespace=whitespaceself.indention=self.indentionandindentionself.column+=len(data)self.open_ended=Falseifself.encoding:data=data.encode(self.encoding)self.stream.write(data)defwrite_indent(self):indent=self.indentor0ifnotself.indentionorself.column>indent \
or(self.column==indentandnotself.whitespace):self.write_line_break()ifself.column<indent:self.whitespace=Truedata=' '*(indent-self.column)self.column=indentifself.encoding:data=data.encode(self.encoding)self.stream.write(data)defwrite_line_break(self,data=None):ifdataisNone:data=self.best_line_breakself.whitespace=Trueself.indention=Trueself.line+=1self.column=0ifself.encoding:data=data.encode(self.encoding)self.stream.write(data)defwrite_version_directive(self,version_text):data='%%YAML %s'%version_textifself.encoding:data=data.encode(self.encoding)self.stream.write(data)self.write_line_break()defwrite_tag_directive(self,handle_text,prefix_text):data='%%TAG %s%s'%(handle_text,prefix_text)ifself.encoding:data=data.encode(self.encoding)self.stream.write(data)self.write_line_break()# Scalar streams.defwrite_single_quoted(self,text,split=True):self.write_indicator('\'',True)spaces=Falsebreaks=Falsestart=end=0whileend<=len(text):ch=Noneifend<len(text):ch=text[end]ifspaces:ifchisNoneorch!=' ':ifstart+1==endandself.column>self.best_widthandsplit \
andstart!=0andend!=len(text):self.write_indent()else:data=text[start:end]self.column+=len(data)ifself.encoding:data=data.encode(self.encoding)self.stream.write(data)start=endelifbreaks:ifchisNoneorchnotin'\n\x85\u2028\u2029':iftext[start]=='\n':self.write_line_break()forbrintext[start:end]:ifbr=='\n':self.write_line_break()else:self.write_line_break(br)self.write_indent()start=endelse:ifchisNoneorchin' \n\x85\u2028\u2029'orch=='\'':ifstart<end:data=text[start:end]self.column+=len(data)ifself.encoding:data=data.encode(self.encoding)self.stream.write(data)start=endifch=='\'':data='\'\''self.column+=2ifself.encoding:data=data.encode(self.encoding)self.stream.write(data)start=end+1ifchisnotNone:spaces=(ch==' ')breaks=(chin'\n\x85\u2028\u2029')end+=1self.write_indicator('\'',False)ESCAPE_REPLACEMENTS={'\0':'0','\x07':'a','\x08':'b','\x09':'t','\x0A':'n','\x0B':'v','\x0C':'f','\x0D':'r','\x1B':'e','\"':'\"','\\':'\\','\x85':'N','\xA0':'_','\u2028':'L','\u2029':'P',}defwrite_double_quoted(self,text,split=True):self.write_indicator('"',True)start=end=0whileend<=len(text):ch=Noneifend<len(text):ch=text[end]ifchisNoneorchin'"\\\x85\u2028\u2029\uFEFF' \
ornot('\x20'<=ch<='\x7E'or(self.allow_unicodeand('\xA0'<=ch<='\uD7FF'or'\uE000'<=ch<='\uFFFD'))):ifstart<end:data=text[start:end]self.column+=len(data)ifself.encoding:data=data.encode(self.encoding)self.stream.write(data)start=endifchisnotNone:ifchinself.ESCAPE_REPLACEMENTS:data='\\'+self.ESCAPE_REPLACEMENTS[ch]elifch<='\xFF':data='\\x%02X'%ord(ch)elifch<='\uFFFF':data='\\u%04X'%ord(ch)else:data='\\U%08X'%ord(ch)self.column+=len(data)ifself.encoding:data=data.encode(self.encoding)self.stream.write(data)start=end+1if0<end<len(text)-1and(ch==' 'orstart>=end) \
andself.column+(end-start)>self.best_widthandsplit:data=text[start:end]+'\\'ifstart<end:start=endself.column+=len(data)ifself.encoding:data=data.encode(self.encoding)self.stream.write(data)self.write_indent()self.whitespace=Falseself.indention=Falseiftext[start]==' ':data='\\'self.column+=len(data)ifself.encoding:data=data.encode(self.encoding)self.stream.write(data)end+=1self.write_indicator('"',False)defdetermine_block_hints(self,text):hints=''iftext:iftext[0]in' \n\x85\u2028\u2029':hints+=str(self.best_indent)iftext[-1]notin'\n\x85\u2028\u2029':hints+='-'eliflen(text)==1ortext[-2]in'\n\x85\u2028\u2029':hints+='+'returnhintsdefwrite_folded(self,text):hints=self.determine_block_hints(text)self.write_indicator('>'+hints,True)ifhints[-1:]=='+':self.open_ended=Trueself.write_line_break()leading_space=Truespaces=Falsebreaks=Truestart=end=0whileend<=len(text):ch=Noneifend<len(text):ch=text[end]ifbreaks:ifchisNoneorchnotin'\n\x85\u2028\u2029':ifnotleading_spaceandchisnotNoneandch!=' ' \
andtext[start]=='\n':self.write_line_break()leading_space=(ch==' ')forbrintext[start:end]:ifbr=='\n':self.write_line_break()else:self.write_line_break(br)ifchisnotNone:self.write_indent()start=endelifspaces:ifch!=' ':ifstart+1==endandself.column>self.best_width:self.write_indent()else:data=text[start:end]self.column+=len(data)ifself.encoding:data=data.encode(self.encoding)self.stream.write(data)start=endelse:ifchisNoneorchin' \n\x85\u2028\u2029':data=text[start:end]self.column+=len(data)ifself.encoding:data=data.encode(self.encoding)self.stream.write(data)ifchisNone:self.write_line_break()start=endifchisnotNone:breaks=(chin'\n\x85\u2028\u2029')spaces=(ch==' ')end+=1defwrite_literal(self,text):hints=self.determine_block_hints(text)self.write_indicator('|'+hints,True)ifhints[-1:]=='+':self.open_ended=Trueself.write_line_break()breaks=Truestart=end=0whileend<=len(text):ch=Noneifend<len(text):ch=text[end]ifbreaks:ifchisNoneorchnotin'\n\x85\u2028\u2029':forbrintext[start:end]:ifbr=='\n':self.write_line_break()else:self.write_line_break(br)ifchisnotNone:self.write_indent()start=endelse:ifchisNoneorchin'\n\x85\u2028\u2029':data=text[start:end]ifself.encoding:data=data.encode(self.encoding)self.stream.write(data)ifchisNone:self.write_line_break()start=endifchisnotNone:breaks=(chin'\n\x85\u2028\u2029')end+=1defwrite_plain(self,text,split=True):ifself.root_context:self.open_ended=Trueifnottext:returnifnotself.whitespace:data=' 'self.column+=len(data)ifself.encoding:data=data.encode(self.encoding)self.stream.write(data)self.whitespace=Falseself.indention=Falsespaces=Falsebreaks=Falsestart=end=0whileend<=len(text):ch=Noneifend<len(text):ch=text[end]ifspaces:ifch!=' ':ifstart+1==endandself.column>self.best_widthandsplit:self.write_indent()self.whitespace=Falseself.indention=Falseelse:data=text[start:end]self.column+=len(data)ifself.encoding:data=data.encode(self.encoding)self.stream.write(data)start=endelifbreaks:ifchnotin'\n\x85\u2028\u2029':iftext[start]=='\n':self.write_line_break()forbrintext[start:end]:ifbr=='\n':self.write_line_break()else:self.write_line_break(br)self.write_indent()self.whitespace=Falseself.indention=Falsestart=endelse:ifchisNoneorchin' \n\x85\u2028\u2029':data=text[start:end]self.column+=len(data)ifself.encoding:data=data.encode(self.encoding)self.stream.write(data)start=endifchisnotNone:spaces=(ch==' ')breaks=(chin'\n\x85\u2028\u2029')end+=1