emitter.py 42 KB

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