emitter.py 42 KB

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