emitter.py 42 KB

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