File: emitter.py

package info (click to toggle)
python-dynaconf 3.2.12-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,900 kB
  • sloc: python: 21,464; sh: 9; makefile: 4
file content (671 lines) | stat: -rw-r--r-- 35,831 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
from __future__ import absolute_import,print_function
_T='\ufeff'
_S='\ue000'
_R='\ud7ff'
_Q='%%%02X'
_P='version'
_O="-;/?:@&=+$,_.~*'()[]"
_N=' \n\x85\u2028\u2029'
_M='\xa0'
_L='...'
_K='\\'
_J="'"
_I='?'
_H='"'
_G='!'
_F='\n\x85\u2028\u2029'
_E='\n'
_D=' '
_C=False
_B=None
_A=True
import sys
from.error import YAMLError,YAMLStreamError
from.events import*
from.compat import utf8,text_type,PY2,nprint,dbg,DBG_EVENT,check_anchorname_char
if _C:from typing import Any,Dict,List,Union,Text,Tuple,Optional;from.compat import StreamType
__all__=['Emitter','EmitterError']
class EmitterError(YAMLError):0
class ScalarAnalysis:
	def __init__(self,scalar,empty,multiline,allow_flow_plain,allow_block_plain,allow_single_quoted,allow_double_quoted,allow_block):self.scalar=scalar;self.empty=empty;self.multiline=multiline;self.allow_flow_plain=allow_flow_plain;self.allow_block_plain=allow_block_plain;self.allow_single_quoted=allow_single_quoted;self.allow_double_quoted=allow_double_quoted;self.allow_block=allow_block
class Indents:
	def __init__(self):self.values=[]
	def append(self,val,seq):self.values.append((val,seq))
	def pop(self):return self.values.pop()[0]
	def last_seq(self):
		try:return self.values[-2][1]
		except IndexError:return _C
	def seq_flow_align(self,seq_indent,column):
		if len(self.values)<2 or not self.values[-1][1]:return 0
		base=self.values[-1][0]if self.values[-1][0]is not _B else 0;return base+seq_indent-column-1
	def __len__(self):return len(self.values)
class Emitter:
	DEFAULT_TAG_PREFIXES={_G:_G,'tag:yaml.org,2002:':'!!'};MAX_SIMPLE_KEY_LENGTH=128
	def __init__(self,stream,canonical=_B,indent=_B,width=_B,allow_unicode=_B,line_break=_B,block_seq_indent=_B,top_level_colon_align=_B,prefix_colon=_B,brace_single_entry_mapping_in_flow_sequence=_B,dumper=_B):
		self.dumper=dumper
		if self.dumper is not _B and getattr(self.dumper,'_emitter',_B)is _B:self.dumper._emitter=self
		self.stream=stream;self.encoding=_B;self.allow_space_break=_B;self.states=[];self.state=self.expect_stream_start;self.events=[];self.event=_B;self.indents=Indents();self.indent=_B;self.flow_context=[];self.root_context=_C;self.sequence_context=_C;self.mapping_context=_C;self.simple_key_context=_C;self.line=0;self.column=0;self.whitespace=_A;self.indention=_A;self.compact_seq_seq=_A;self.compact_seq_map=_A;self.no_newline=_B;self.open_ended=_C;self.colon=':';self.prefixed_colon=self.colon if prefix_colon is _B else prefix_colon+self.colon;self.brace_single_entry_mapping_in_flow_sequence=brace_single_entry_mapping_in_flow_sequence;self.canonical=canonical;self.allow_unicode=allow_unicode;self.unicode_supplementary=sys.maxunicode>65535;self.sequence_dash_offset=block_seq_indent if block_seq_indent else 0;self.top_level_colon_align=top_level_colon_align;self.best_sequence_indent=2;self.requested_indent=indent
		if indent and 1<indent<10:self.best_sequence_indent=indent
		self.best_map_indent=self.best_sequence_indent;self.best_width=80
		if width and width>self.best_sequence_indent*2:self.best_width=width
		self.best_line_break=_E
		if line_break in['\r',_E,'\r\n']:self.best_line_break=line_break
		self.tag_prefixes=_B;self.prepared_anchor=_B;self.prepared_tag=_B;self.analysis=_B;self.style=_B;self.scalar_after_indicator=_A
	@property
	def stream(self):
		try:return self._stream
		except AttributeError:raise YAMLStreamError('output stream needs to specified')
	@stream.setter
	def stream(self,val):
		if val is _B:return
		if not hasattr(val,'write'):raise YAMLStreamError('stream argument needs to have a write() method')
		self._stream=val
	@property
	def serializer(self):
		try:
			if hasattr(self.dumper,'typ'):return self.dumper.serializer
			return self.dumper._serializer
		except AttributeError:return self
	@property
	def flow_level(self):return len(self.flow_context)
	def dispose(self):self.states=[];self.state=_B
	def emit(self,event):
		if dbg(DBG_EVENT):nprint(event)
		self.events.append(event)
		while not self.need_more_events():self.event=self.events.pop(0);self.state();self.event=_B
	def need_more_events(self):
		if not self.events:return _A
		event=self.events[0]
		if isinstance(event,DocumentStartEvent):return self.need_events(1)
		elif isinstance(event,SequenceStartEvent):return self.need_events(2)
		elif isinstance(event,MappingStartEvent):return self.need_events(3)
		else:return _C
	def need_events(self,count):
		level=0
		for event in self.events[1:]:
			if isinstance(event,(DocumentStartEvent,CollectionStartEvent)):level+=1
			elif isinstance(event,(DocumentEndEvent,CollectionEndEvent)):level-=1
			elif isinstance(event,StreamEndEvent):level=-1
			if level<0:return _C
		return len(self.events)<count+1
	def increase_indent(self,flow=_C,sequence=_B,indentless=_C):
		self.indents.append(self.indent,sequence)
		if self.indent is _B:
			if flow:self.indent=self.requested_indent
			else:self.indent=0
		elif not indentless:self.indent+=self.best_sequence_indent if self.indents.last_seq()else self.best_map_indent
	def expect_stream_start(self):
		A='encoding'
		if isinstance(self.event,StreamStartEvent):
			if PY2:
				if self.event.encoding and not getattr(self.stream,A,_B):self.encoding=self.event.encoding
			elif self.event.encoding and not hasattr(self.stream,A):self.encoding=self.event.encoding
			self.write_stream_start();self.state=self.expect_first_document_start
		else:raise EmitterError('expected StreamStartEvent, but got %s'%(self.event,))
	def expect_nothing(self):raise EmitterError('expected nothing, but got %s'%(self.event,))
	def expect_first_document_start(self):return self.expect_document_start(first=_A)
	def expect_document_start(self,first=_C):
		if isinstance(self.event,DocumentStartEvent):
			if(self.event.version or self.event.tags)and self.open_ended:self.write_indicator(_L,_A);self.write_indent()
			if self.event.version:version_text=self.prepare_version(self.event.version);self.write_version_directive(version_text)
			self.tag_prefixes=self.DEFAULT_TAG_PREFIXES.copy()
			if self.event.tags:
				handles=sorted(self.event.tags.keys())
				for handle in handles:prefix=self.event.tags[handle];self.tag_prefixes[prefix]=handle;handle_text=self.prepare_tag_handle(handle);prefix_text=self.prepare_tag_prefix(prefix);self.write_tag_directive(handle_text,prefix_text)
			implicit=first and not self.event.explicit and not self.canonical and not self.event.version and not self.event.tags and not self.check_empty_document()
			if not implicit:
				self.write_indent();self.write_indicator('---',_A)
				if self.canonical:self.write_indent()
			self.state=self.expect_document_root
		elif isinstance(self.event,StreamEndEvent):
			if self.open_ended:self.write_indicator(_L,_A);self.write_indent()
			self.write_stream_end();self.state=self.expect_nothing
		else:raise EmitterError('expected DocumentStartEvent, but got %s'%(self.event,))
	def expect_document_end(self):
		if isinstance(self.event,DocumentEndEvent):
			self.write_indent()
			if self.event.explicit:self.write_indicator(_L,_A);self.write_indent()
			self.flush_stream();self.state=self.expect_document_start
		else:raise EmitterError('expected DocumentEndEvent, but got %s'%(self.event,))
	def expect_document_root(self):self.states.append(self.expect_document_end);self.expect_node(root=_A)
	def expect_node(self,root=_C,sequence=_C,mapping=_C,simple_key=_C):
		self.root_context=root;self.sequence_context=sequence;self.mapping_context=mapping;self.simple_key_context=simple_key
		if isinstance(self.event,AliasEvent):self.expect_alias()
		elif isinstance(self.event,(ScalarEvent,CollectionStartEvent)):
			if self.process_anchor('&')and isinstance(self.event,ScalarEvent)and self.sequence_context:self.sequence_context=_C
			if root and isinstance(self.event,ScalarEvent)and not self.scalar_after_indicator:self.write_indent()
			self.process_tag()
			if isinstance(self.event,ScalarEvent):self.expect_scalar()
			elif isinstance(self.event,SequenceStartEvent):
				i2,n2=self.indention,self.no_newline
				if self.event.comment:
					if self.event.flow_style is _C and self.event.comment:
						if self.write_post_comment(self.event):self.indention=_C;self.no_newline=_A
					if self.write_pre_comment(self.event):self.indention=i2;self.no_newline=not self.indention
				if self.flow_level or self.canonical or self.event.flow_style or self.check_empty_sequence():self.expect_flow_sequence()
				else:self.expect_block_sequence()
			elif isinstance(self.event,MappingStartEvent):
				if self.event.flow_style is _C and self.event.comment:self.write_post_comment(self.event)
				if self.event.comment and self.event.comment[1]:self.write_pre_comment(self.event)
				if self.flow_level or self.canonical or self.event.flow_style or self.check_empty_mapping():self.expect_flow_mapping(single=self.event.nr_items==1)
				else:self.expect_block_mapping()
		else:raise EmitterError('expected NodeEvent, but got %s'%(self.event,))
	def expect_alias(self):
		if self.event.anchor is _B:raise EmitterError('anchor is not specified for alias')
		self.process_anchor('*');self.state=self.states.pop()
	def expect_scalar(self):self.increase_indent(flow=_A);self.process_scalar();self.indent=self.indents.pop();self.state=self.states.pop()
	def expect_flow_sequence(self):ind=self.indents.seq_flow_align(self.best_sequence_indent,self.column);self.write_indicator(_D*ind+'[',_A,whitespace=_A);self.increase_indent(flow=_A,sequence=_A);self.flow_context.append('[');self.state=self.expect_first_flow_sequence_item
	def expect_first_flow_sequence_item(self):
		if isinstance(self.event,SequenceEndEvent):
			self.indent=self.indents.pop();popped=self.flow_context.pop();assert popped=='[';self.write_indicator(']',_C)
			if self.event.comment and self.event.comment[0]:self.write_post_comment(self.event)
			elif self.flow_level==0:self.write_line_break()
			self.state=self.states.pop()
		else:
			if self.canonical or self.column>self.best_width:self.write_indent()
			self.states.append(self.expect_flow_sequence_item);self.expect_node(sequence=_A)
	def expect_flow_sequence_item(self):
		if isinstance(self.event,SequenceEndEvent):
			self.indent=self.indents.pop();popped=self.flow_context.pop();assert popped=='['
			if self.canonical:self.write_indicator(',',_C);self.write_indent()
			self.write_indicator(']',_C)
			if self.event.comment and self.event.comment[0]:self.write_post_comment(self.event)
			else:self.no_newline=_C
			self.state=self.states.pop()
		else:
			self.write_indicator(',',_C)
			if self.canonical or self.column>self.best_width:self.write_indent()
			self.states.append(self.expect_flow_sequence_item);self.expect_node(sequence=_A)
	def expect_flow_mapping(self,single=_C):
		ind=self.indents.seq_flow_align(self.best_sequence_indent,self.column);map_init='{'
		if single and self.flow_level and self.flow_context[-1]=='['and not self.canonical and not self.brace_single_entry_mapping_in_flow_sequence:map_init=''
		self.write_indicator(_D*ind+map_init,_A,whitespace=_A);self.flow_context.append(map_init);self.increase_indent(flow=_A,sequence=_C);self.state=self.expect_first_flow_mapping_key
	def expect_first_flow_mapping_key(self):
		if isinstance(self.event,MappingEndEvent):
			self.indent=self.indents.pop();popped=self.flow_context.pop();assert popped=='{';self.write_indicator('}',_C)
			if self.event.comment and self.event.comment[0]:self.write_post_comment(self.event)
			elif self.flow_level==0:self.write_line_break()
			self.state=self.states.pop()
		else:
			if self.canonical or self.column>self.best_width:self.write_indent()
			if not self.canonical and self.check_simple_key():self.states.append(self.expect_flow_mapping_simple_value);self.expect_node(mapping=_A,simple_key=_A)
			else:self.write_indicator(_I,_A);self.states.append(self.expect_flow_mapping_value);self.expect_node(mapping=_A)
	def expect_flow_mapping_key(self):
		if isinstance(self.event,MappingEndEvent):
			self.indent=self.indents.pop();popped=self.flow_context.pop();assert popped in['{','']
			if self.canonical:self.write_indicator(',',_C);self.write_indent()
			if popped!='':self.write_indicator('}',_C)
			if self.event.comment and self.event.comment[0]:self.write_post_comment(self.event)
			else:self.no_newline=_C
			self.state=self.states.pop()
		else:
			self.write_indicator(',',_C)
			if self.canonical or self.column>self.best_width:self.write_indent()
			if not self.canonical and self.check_simple_key():self.states.append(self.expect_flow_mapping_simple_value);self.expect_node(mapping=_A,simple_key=_A)
			else:self.write_indicator(_I,_A);self.states.append(self.expect_flow_mapping_value);self.expect_node(mapping=_A)
	def expect_flow_mapping_simple_value(self):self.write_indicator(self.prefixed_colon,_C);self.states.append(self.expect_flow_mapping_key);self.expect_node(mapping=_A)
	def expect_flow_mapping_value(self):
		if self.canonical or self.column>self.best_width:self.write_indent()
		self.write_indicator(self.prefixed_colon,_A);self.states.append(self.expect_flow_mapping_key);self.expect_node(mapping=_A)
	def expect_block_sequence(self):
		if self.mapping_context:indentless=not self.indention
		else:
			indentless=_C
			if not self.compact_seq_seq and self.column!=0:self.write_line_break()
		self.increase_indent(flow=_C,sequence=_A,indentless=indentless);self.state=self.expect_first_block_sequence_item
	def expect_first_block_sequence_item(self):return self.expect_block_sequence_item(first=_A)
	def expect_block_sequence_item(self,first=_C):
		if not first and isinstance(self.event,SequenceEndEvent):
			if self.event.comment and self.event.comment[1]:self.write_pre_comment(self.event)
			self.indent=self.indents.pop();self.state=self.states.pop();self.no_newline=_C
		else:
			if self.event.comment and self.event.comment[1]:self.write_pre_comment(self.event)
			nonl=self.no_newline if self.column==0 else _C;self.write_indent();ind=self.sequence_dash_offset;self.write_indicator(_D*ind+'-',_A,indention=_A)
			if nonl or self.sequence_dash_offset+2>self.best_sequence_indent:self.no_newline=_A
			self.states.append(self.expect_block_sequence_item);self.expect_node(sequence=_A)
	def expect_block_mapping(self):
		if not self.mapping_context and not(self.compact_seq_map or self.column==0):self.write_line_break()
		self.increase_indent(flow=_C,sequence=_C);self.state=self.expect_first_block_mapping_key
	def expect_first_block_mapping_key(self):return self.expect_block_mapping_key(first=_A)
	def expect_block_mapping_key(self,first=_C):
		if not first and isinstance(self.event,MappingEndEvent):
			if self.event.comment and self.event.comment[1]:self.write_pre_comment(self.event)
			self.indent=self.indents.pop();self.state=self.states.pop()
		else:
			if self.event.comment and self.event.comment[1]:self.write_pre_comment(self.event)
			self.write_indent()
			if self.check_simple_key():
				if not isinstance(self.event,(SequenceStartEvent,MappingStartEvent)):
					try:
						if self.event.style==_I:self.write_indicator(_I,_A,indention=_A)
					except AttributeError:pass
				self.states.append(self.expect_block_mapping_simple_value);self.expect_node(mapping=_A,simple_key=_A)
				if isinstance(self.event,AliasEvent):self.stream.write(_D)
			else:self.write_indicator(_I,_A,indention=_A);self.states.append(self.expect_block_mapping_value);self.expect_node(mapping=_A)
	def expect_block_mapping_simple_value(self):
		if getattr(self.event,'style',_B)!=_I:
			if self.indent==0 and self.top_level_colon_align is not _B:c=_D*(self.top_level_colon_align-self.column)+self.colon
			else:c=self.prefixed_colon
			self.write_indicator(c,_C)
		self.states.append(self.expect_block_mapping_key);self.expect_node(mapping=_A)
	def expect_block_mapping_value(self):self.write_indent();self.write_indicator(self.prefixed_colon,_A,indention=_A);self.states.append(self.expect_block_mapping_key);self.expect_node(mapping=_A)
	def check_empty_sequence(self):return isinstance(self.event,SequenceStartEvent)and bool(self.events)and isinstance(self.events[0],SequenceEndEvent)
	def check_empty_mapping(self):return isinstance(self.event,MappingStartEvent)and bool(self.events)and isinstance(self.events[0],MappingEndEvent)
	def check_empty_document(self):
		if not isinstance(self.event,DocumentStartEvent)or not self.events:return _C
		event=self.events[0];return isinstance(event,ScalarEvent)and event.anchor is _B and event.tag is _B and event.implicit and event.value==''
	def check_simple_key(self):
		length=0
		if isinstance(self.event,NodeEvent)and self.event.anchor is not _B:
			if self.prepared_anchor is _B:self.prepared_anchor=self.prepare_anchor(self.event.anchor)
			length+=len(self.prepared_anchor)
		if isinstance(self.event,(ScalarEvent,CollectionStartEvent))and self.event.tag is not _B:
			if self.prepared_tag is _B:self.prepared_tag=self.prepare_tag(self.event.tag)
			length+=len(self.prepared_tag)
		if isinstance(self.event,ScalarEvent):
			if self.analysis is _B:self.analysis=self.analyze_scalar(self.event.value)
			length+=len(self.analysis.scalar)
		return length<self.MAX_SIMPLE_KEY_LENGTH and(isinstance(self.event,AliasEvent)or isinstance(self.event,SequenceStartEvent)and self.event.flow_style is _A or isinstance(self.event,MappingStartEvent)and self.event.flow_style is _A or isinstance(self.event,ScalarEvent)and not(self.analysis.empty and self.style and self.style not in'\'"')and not self.analysis.multiline or self.check_empty_sequence()or self.check_empty_mapping())
	def process_anchor(self,indicator):
		if self.event.anchor is _B:self.prepared_anchor=_B;return _C
		if self.prepared_anchor is _B:self.prepared_anchor=self.prepare_anchor(self.event.anchor)
		if self.prepared_anchor:self.write_indicator(indicator+self.prepared_anchor,_A);self.no_newline=_C
		self.prepared_anchor=_B;return _A
	def process_tag(self):
		tag=self.event.tag
		if isinstance(self.event,ScalarEvent):
			if self.style is _B:self.style=self.choose_scalar_style()
			if(not self.canonical or tag is _B)and(self.style==''and self.event.implicit[0]or self.style!=''and self.event.implicit[1]):self.prepared_tag=_B;return
			if self.event.implicit[0]and tag is _B:tag=_G;self.prepared_tag=_B
		elif(not self.canonical or tag is _B)and self.event.implicit:self.prepared_tag=_B;return
		if tag is _B:raise EmitterError('tag is not specified')
		if self.prepared_tag is _B:self.prepared_tag=self.prepare_tag(tag)
		if self.prepared_tag:
			self.write_indicator(self.prepared_tag,_A)
			if self.sequence_context and not self.flow_level and isinstance(self.event,ScalarEvent):self.no_newline=_A
		self.prepared_tag=_B
	def choose_scalar_style(self):
		if self.analysis is _B:self.analysis=self.analyze_scalar(self.event.value)
		if self.event.style==_H or self.canonical:return _H
		if(not self.event.style or self.event.style==_I)and(self.event.implicit[0]or not self.event.implicit[2]):
			if not(self.simple_key_context and(self.analysis.empty or self.analysis.multiline))and(self.flow_level and self.analysis.allow_flow_plain or not self.flow_level and self.analysis.allow_block_plain):return''
		self.analysis.allow_block=_A
		if self.event.style and self.event.style in'|>':
			if not self.flow_level and not self.simple_key_context and self.analysis.allow_block:return self.event.style
		if not self.event.style and self.analysis.allow_double_quoted:
			if _J in self.event.value or _E in self.event.value:return _H
		if not self.event.style or self.event.style==_J:
			if self.analysis.allow_single_quoted and not(self.simple_key_context and self.analysis.multiline):return _J
		return _H
	def process_scalar(self):
		if self.analysis is _B:self.analysis=self.analyze_scalar(self.event.value)
		if self.style is _B:self.style=self.choose_scalar_style()
		split=not self.simple_key_context
		if self.sequence_context and not self.flow_level:self.write_indent()
		if self.style==_H:self.write_double_quoted(self.analysis.scalar,split)
		elif self.style==_J:self.write_single_quoted(self.analysis.scalar,split)
		elif self.style=='>':self.write_folded(self.analysis.scalar)
		elif self.style=='|':self.write_literal(self.analysis.scalar,self.event.comment)
		else:self.write_plain(self.analysis.scalar,split)
		self.analysis=_B;self.style=_B
		if self.event.comment:self.write_post_comment(self.event)
	def prepare_version(self,version):
		major,minor=version
		if major!=1:raise EmitterError('unsupported YAML version: %d.%d'%(major,minor))
		return'%d.%d'%(major,minor)
	def prepare_tag_handle(self,handle):
		if not handle:raise EmitterError('tag handle must not be empty')
		if handle[0]!=_G or handle[-1]!=_G:raise EmitterError("tag handle must start and end with '!': %r"%utf8(handle))
		for ch in handle[1:-1]:
			if not('0'<=ch<='9'or'A'<=ch<='Z'or'a'<=ch<='z'or ch in'-_'):raise EmitterError('invalid character %r in the tag handle: %r'%(utf8(ch),utf8(handle)))
		return handle
	def prepare_tag_prefix(self,prefix):
		if not prefix:raise EmitterError('tag prefix must not be empty')
		chunks=[];start=end=0
		if prefix[0]==_G:end=1
		ch_set=_O
		if self.dumper:
			version=getattr(self.dumper,_P,(1,2))
			if version is _B or version>=(1,2):ch_set+='#'
		while end<len(prefix):
			ch=prefix[end]
			if'0'<=ch<='9'or'A'<=ch<='Z'or'a'<=ch<='z'or ch in ch_set:end+=1
			else:
				if start<end:chunks.append(prefix[start:end])
				start=end=end+1;data=utf8(ch)
				for ch in data:chunks.append(_Q%ord(ch))
		if start<end:chunks.append(prefix[start:end])
		return''.join(chunks)
	def prepare_tag(self,tag):
		if not tag:raise EmitterError('tag must not be empty')
		if tag==_G:return tag
		handle=_B;suffix=tag;prefixes=sorted(self.tag_prefixes.keys())
		for prefix in prefixes:
			if tag.startswith(prefix)and(prefix==_G or len(prefix)<len(tag)):handle=self.tag_prefixes[prefix];suffix=tag[len(prefix):]
		chunks=[];start=end=0;ch_set=_O
		if self.dumper:
			version=getattr(self.dumper,_P,(1,2))
			if version is _B or version>=(1,2):ch_set+='#'
		while end<len(suffix):
			ch=suffix[end]
			if'0'<=ch<='9'or'A'<=ch<='Z'or'a'<=ch<='z'or ch in ch_set or ch==_G and handle!=_G:end+=1
			else:
				if start<end:chunks.append(suffix[start:end])
				start=end=end+1;data=utf8(ch)
				for ch in data:chunks.append(_Q%ord(ch))
		if start<end:chunks.append(suffix[start:end])
		suffix_text=''.join(chunks)
		if handle:return'%s%s'%(handle,suffix_text)
		else:return'!<%s>'%suffix_text
	def prepare_anchor(self,anchor):
		if not anchor:raise EmitterError('anchor must not be empty')
		for ch in anchor:
			if not check_anchorname_char(ch):raise EmitterError('invalid character %r in the anchor: %r'%(utf8(ch),utf8(anchor)))
		return anchor
	def analyze_scalar(self,scalar):
		A='\x00 \t\r\n\x85\u2028\u2029'
		if not scalar:return ScalarAnalysis(scalar=scalar,empty=_A,multiline=_C,allow_flow_plain=_C,allow_block_plain=_A,allow_single_quoted=_A,allow_double_quoted=_A,allow_block=_C)
		block_indicators=_C;flow_indicators=_C;line_breaks=_C;special_characters=_C;leading_space=_C;leading_break=_C;trailing_space=_C;trailing_break=_C;break_space=_C;space_break=_C
		if scalar.startswith('---')or scalar.startswith(_L):block_indicators=_A;flow_indicators=_A
		preceeded_by_whitespace=_A;followed_by_whitespace=len(scalar)==1 or scalar[1]in A;previous_space=_C;previous_break=_C;index=0
		while index<len(scalar):
			ch=scalar[index]
			if index==0:
				if ch in'#,[]{}&*!|>\'"%@`':flow_indicators=_A;block_indicators=_A
				if ch in'?:':
					if self.serializer.use_version==(1,1):flow_indicators=_A
					elif len(scalar)==1:flow_indicators=_A
					if followed_by_whitespace:block_indicators=_A
				if ch=='-'and followed_by_whitespace:flow_indicators=_A;block_indicators=_A
			else:
				if ch in',[]{}':flow_indicators=_A
				if ch==_I and self.serializer.use_version==(1,1):flow_indicators=_A
				if ch==':':
					if followed_by_whitespace:flow_indicators=_A;block_indicators=_A
				if ch=='#'and preceeded_by_whitespace:flow_indicators=_A;block_indicators=_A
			if ch in _F:line_breaks=_A
			if not(ch==_E or _D<=ch<='~'):
				if(ch=='\x85'or _M<=ch<=_R or _S<=ch<='�'or self.unicode_supplementary and'𐀀'<=ch<='\U0010ffff')and ch!=_T:
					if not self.allow_unicode:special_characters=_A
				else:special_characters=_A
			if ch==_D:
				if index==0:leading_space=_A
				if index==len(scalar)-1:trailing_space=_A
				if previous_break:break_space=_A
				previous_space=_A;previous_break=_C
			elif ch in _F:
				if index==0:leading_break=_A
				if index==len(scalar)-1:trailing_break=_A
				if previous_space:space_break=_A
				previous_space=_C;previous_break=_A
			else:previous_space=_C;previous_break=_C
			index+=1;preceeded_by_whitespace=ch in A;followed_by_whitespace=index+1>=len(scalar)or scalar[index+1]in A
		allow_flow_plain=_A;allow_block_plain=_A;allow_single_quoted=_A;allow_double_quoted=_A;allow_block=_A
		if leading_space or leading_break or trailing_space or trailing_break:allow_flow_plain=allow_block_plain=_C
		if trailing_space:allow_block=_C
		if break_space:allow_flow_plain=allow_block_plain=allow_single_quoted=_C
		if special_characters:allow_flow_plain=allow_block_plain=allow_single_quoted=allow_block=_C
		elif space_break:
			allow_flow_plain=allow_block_plain=allow_single_quoted=_C
			if not self.allow_space_break:allow_block=_C
		if line_breaks:allow_flow_plain=allow_block_plain=_C
		if flow_indicators:allow_flow_plain=_C
		if block_indicators:allow_block_plain=_C
		return ScalarAnalysis(scalar=scalar,empty=_C,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)
	def flush_stream(self):
		if hasattr(self.stream,'flush'):self.stream.flush()
	def write_stream_start(self):
		if self.encoding and self.encoding.startswith('utf-16'):self.stream.write(_T.encode(self.encoding))
	def write_stream_end(self):self.flush_stream()
	def write_indicator(self,indicator,need_whitespace,whitespace=_C,indention=_C):
		if self.whitespace or not need_whitespace:data=indicator
		else:data=_D+indicator
		self.whitespace=whitespace;self.indention=self.indention and indention;self.column+=len(data);self.open_ended=_C
		if bool(self.encoding):data=data.encode(self.encoding)
		self.stream.write(data)
	def write_indent(self):
		indent=self.indent or 0
		if not self.indention or self.column>indent or self.column==indent and not self.whitespace:
			if bool(self.no_newline):self.no_newline=_C
			else:self.write_line_break()
		if self.column<indent:
			self.whitespace=_A;data=_D*(indent-self.column);self.column=indent
			if self.encoding:data=data.encode(self.encoding)
			self.stream.write(data)
	def write_line_break(self,data=_B):
		if data is _B:data=self.best_line_break
		self.whitespace=_A;self.indention=_A;self.line+=1;self.column=0
		if bool(self.encoding):data=data.encode(self.encoding)
		self.stream.write(data)
	def write_version_directive(self,version_text):
		data='%%YAML %s'%version_text
		if self.encoding:data=data.encode(self.encoding)
		self.stream.write(data);self.write_line_break()
	def write_tag_directive(self,handle_text,prefix_text):
		data='%%TAG %s %s'%(handle_text,prefix_text)
		if self.encoding:data=data.encode(self.encoding)
		self.stream.write(data);self.write_line_break()
	def write_single_quoted(self,text,split=_A):
		if self.root_context:
			if self.requested_indent is not _B:
				self.write_line_break()
				if self.requested_indent!=0:self.write_indent()
		self.write_indicator(_J,_A);spaces=_C;breaks=_C;start=end=0
		while end<=len(text):
			ch=_B
			if end<len(text):ch=text[end]
			if spaces:
				if ch is _B or ch!=_D:
					if start+1==end and self.column>self.best_width and split and start!=0 and end!=len(text):self.write_indent()
					else:
						data=text[start:end];self.column+=len(data)
						if bool(self.encoding):data=data.encode(self.encoding)
						self.stream.write(data)
					start=end
			elif breaks:
				if ch is _B or ch not in _F:
					if text[start]==_E:self.write_line_break()
					for br in text[start:end]:
						if br==_E:self.write_line_break()
						else:self.write_line_break(br)
					self.write_indent();start=end
			elif ch is _B or ch in _N or ch==_J:
				if start<end:
					data=text[start:end];self.column+=len(data)
					if bool(self.encoding):data=data.encode(self.encoding)
					self.stream.write(data);start=end
			if ch==_J:
				data="''";self.column+=2
				if bool(self.encoding):data=data.encode(self.encoding)
				self.stream.write(data);start=end+1
			if ch is not _B:spaces=ch==_D;breaks=ch in _F
			end+=1
		self.write_indicator(_J,_C)
	ESCAPE_REPLACEMENTS={'\x00':'0','\x07':'a','\x08':'b','\t':'t',_E:'n','\x0b':'v','\x0c':'f','\r':'r','\x1b':'e',_H:_H,_K:_K,'\x85':'N',_M:'_','\u2028':'L','\u2029':'P'}
	def write_double_quoted(self,text,split=_A):
		if self.root_context:
			if self.requested_indent is not _B:
				self.write_line_break()
				if self.requested_indent!=0:self.write_indent()
		self.write_indicator(_H,_A);start=end=0
		while end<=len(text):
			ch=_B
			if end<len(text):ch=text[end]
			if ch is _B or ch in'"\\\x85\u2028\u2029\ufeff'or not(_D<=ch<='~'or self.allow_unicode and(_M<=ch<=_R or _S<=ch<='�')):
				if start<end:
					data=text[start:end];self.column+=len(data)
					if bool(self.encoding):data=data.encode(self.encoding)
					self.stream.write(data);start=end
				if ch is not _B:
					if ch in self.ESCAPE_REPLACEMENTS:data=_K+self.ESCAPE_REPLACEMENTS[ch]
					elif ch<='ÿ':data='\\x%02X'%ord(ch)
					elif ch<='\uffff':data='\\u%04X'%ord(ch)
					else:data='\\U%08X'%ord(ch)
					self.column+=len(data)
					if bool(self.encoding):data=data.encode(self.encoding)
					self.stream.write(data);start=end+1
			if 0<end<len(text)-1 and(ch==_D or start>=end)and self.column+(end-start)>self.best_width and split:
				data=text[start:end]+_K
				if start<end:start=end
				self.column+=len(data)
				if bool(self.encoding):data=data.encode(self.encoding)
				self.stream.write(data);self.write_indent();self.whitespace=_C;self.indention=_C
				if text[start]==_D:
					data=_K;self.column+=len(data)
					if bool(self.encoding):data=data.encode(self.encoding)
					self.stream.write(data)
			end+=1
		self.write_indicator(_H,_C)
	def determine_block_hints(self,text):
		indent=0;indicator='';hints=''
		if text:
			if text[0]in _N:indent=self.best_sequence_indent;hints+=text_type(indent)
			elif self.root_context:
				for end in['\n---','\n...']:
					pos=0
					while _A:
						pos=text.find(end,pos)
						if pos==-1:break
						try:
							if text[pos+4]in' \r\n':break
						except IndexError:pass
						pos+=1
					if pos>-1:break
				if pos>0:indent=self.best_sequence_indent
			if text[-1]not in _F:indicator='-'
			elif len(text)==1 or text[-2]in _F:indicator='+'
		hints+=indicator;return hints,indent,indicator
	def write_folded(self,text):
		hints,_indent,_indicator=self.determine_block_hints(text);self.write_indicator('>'+hints,_A)
		if _indicator=='+':self.open_ended=_A
		self.write_line_break();leading_space=_A;spaces=_C;breaks=_A;start=end=0
		while end<=len(text):
			ch=_B
			if end<len(text):ch=text[end]
			if breaks:
				if ch is _B or ch not in'\n\x85\u2028\u2029\x07':
					if not leading_space and ch is not _B and ch!=_D and text[start]==_E:self.write_line_break()
					leading_space=ch==_D
					for br in text[start:end]:
						if br==_E:self.write_line_break()
						else:self.write_line_break(br)
					if ch is not _B:self.write_indent()
					start=end
			elif spaces:
				if ch!=_D:
					if start+1==end and self.column>self.best_width:self.write_indent()
					else:
						data=text[start:end];self.column+=len(data)
						if bool(self.encoding):data=data.encode(self.encoding)
						self.stream.write(data)
					start=end
			elif ch is _B or ch in' \n\x85\u2028\u2029\x07':
				data=text[start:end];self.column+=len(data)
				if bool(self.encoding):data=data.encode(self.encoding)
				self.stream.write(data)
				if ch=='\x07':
					if end<len(text)-1 and not text[end+2].isspace():self.write_line_break();self.write_indent();end+=2
					else:raise EmitterError('unexcpected fold indicator \\a before space')
				if ch is _B:self.write_line_break()
				start=end
			if ch is not _B:breaks=ch in _F;spaces=ch==_D
			end+=1
	def write_literal(self,text,comment=_B):
		hints,_indent,_indicator=self.determine_block_hints(text);self.write_indicator('|'+hints,_A)
		try:
			comment=comment[1][0]
			if comment:self.stream.write(comment)
		except(TypeError,IndexError):pass
		if _indicator=='+':self.open_ended=_A
		self.write_line_break();breaks=_A;start=end=0
		while end<=len(text):
			ch=_B
			if end<len(text):ch=text[end]
			if breaks:
				if ch is _B or ch not in _F:
					for br in text[start:end]:
						if br==_E:self.write_line_break()
						else:self.write_line_break(br)
					if ch is not _B:
						if self.root_context:idnx=self.indent if self.indent is not _B else 0;self.stream.write(_D*(_indent+idnx))
						else:self.write_indent()
					start=end
			elif ch is _B or ch in _F:
				data=text[start:end]
				if bool(self.encoding):data=data.encode(self.encoding)
				self.stream.write(data)
				if ch is _B:self.write_line_break()
				start=end
			if ch is not _B:breaks=ch in _F
			end+=1
	def write_plain(self,text,split=_A):
		if self.root_context:
			if self.requested_indent is not _B:
				self.write_line_break()
				if self.requested_indent!=0:self.write_indent()
			else:self.open_ended=_A
		if not text:return
		if not self.whitespace:
			data=_D;self.column+=len(data)
			if self.encoding:data=data.encode(self.encoding)
			self.stream.write(data)
		self.whitespace=_C;self.indention=_C;spaces=_C;breaks=_C;start=end=0
		while end<=len(text):
			ch=_B
			if end<len(text):ch=text[end]
			if spaces:
				if ch!=_D:
					if start+1==end and self.column>self.best_width and split:self.write_indent();self.whitespace=_C;self.indention=_C
					else:
						data=text[start:end];self.column+=len(data)
						if self.encoding:data=data.encode(self.encoding)
						self.stream.write(data)
					start=end
			elif breaks:
				if ch not in _F:
					if text[start]==_E:self.write_line_break()
					for br in text[start:end]:
						if br==_E:self.write_line_break()
						else:self.write_line_break(br)
					self.write_indent();self.whitespace=_C;self.indention=_C;start=end
			elif ch is _B or ch in _N:
				data=text[start:end];self.column+=len(data)
				if self.encoding:data=data.encode(self.encoding)
				try:self.stream.write(data)
				except:sys.stdout.write(repr(data)+_E);raise
				start=end
			if ch is not _B:spaces=ch==_D;breaks=ch in _F
			end+=1
	def write_comment(self,comment,pre=_C):
		value=comment.value
		if not pre and value[-1]==_E:value=value[:-1]
		try:
			col=comment.start_mark.column
			if comment.value and comment.value.startswith(_E):col=self.column
			elif col<self.column+1:ValueError
		except ValueError:col=self.column+1
		try:
			nr_spaces=col-self.column
			if self.column and value.strip()and nr_spaces<1 and value[0]!=_E:nr_spaces=1
			value=_D*nr_spaces+value
			try:
				if bool(self.encoding):value=value.encode(self.encoding)
			except UnicodeDecodeError:pass
			self.stream.write(value)
		except TypeError:raise
		if not pre:self.write_line_break()
	def write_pre_comment(self,event):
		comments=event.comment[1]
		if comments is _B:return _C
		try:
			start_events=MappingStartEvent,SequenceStartEvent
			for comment in comments:
				if isinstance(event,start_events)and getattr(comment,'pre_done',_B):continue
				if self.column!=0:self.write_line_break()
				self.write_comment(comment,pre=_A)
				if isinstance(event,start_events):comment.pre_done=_A
		except TypeError:sys.stdout.write('eventtt {} {}'.format(type(event),event));raise
		return _A
	def write_post_comment(self,event):
		if self.event.comment[0]is _B:return _C
		comment=event.comment[0];self.write_comment(comment);return _A