Updating PyYAML to 3.08
This commit is contained in:
parent
92345146c7
commit
6ced5a0baa
|
@ -8,10 +8,13 @@ from nodes import *
|
||||||
from loader import *
|
from loader import *
|
||||||
from dumper import *
|
from dumper import *
|
||||||
|
|
||||||
|
__version__ = '3.08'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from cyaml import *
|
from cyaml import *
|
||||||
|
__with_libyaml__ = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
__with_libyaml__ = False
|
||||||
|
|
||||||
def scan(stream, Loader=Loader):
|
def scan(stream, Loader=Loader):
|
||||||
"""
|
"""
|
||||||
|
@ -35,8 +38,7 @@ def compose(stream, Loader=Loader):
|
||||||
and produce the corresponding representation tree.
|
and produce the corresponding representation tree.
|
||||||
"""
|
"""
|
||||||
loader = Loader(stream)
|
loader = Loader(stream)
|
||||||
if loader.check_node():
|
return loader.get_single_node()
|
||||||
return loader.get_node()
|
|
||||||
|
|
||||||
def compose_all(stream, Loader=Loader):
|
def compose_all(stream, Loader=Loader):
|
||||||
"""
|
"""
|
||||||
|
@ -47,6 +49,14 @@ def compose_all(stream, Loader=Loader):
|
||||||
while loader.check_node():
|
while loader.check_node():
|
||||||
yield loader.get_node()
|
yield loader.get_node()
|
||||||
|
|
||||||
|
def load(stream, Loader=Loader):
|
||||||
|
"""
|
||||||
|
Parse the first YAML document in a stream
|
||||||
|
and produce the corresponding Python object.
|
||||||
|
"""
|
||||||
|
loader = Loader(stream)
|
||||||
|
return loader.get_single_data()
|
||||||
|
|
||||||
def load_all(stream, Loader=Loader):
|
def load_all(stream, Loader=Loader):
|
||||||
"""
|
"""
|
||||||
Parse all YAML documents in a stream
|
Parse all YAML documents in a stream
|
||||||
|
@ -56,14 +66,13 @@ def load_all(stream, Loader=Loader):
|
||||||
while loader.check_data():
|
while loader.check_data():
|
||||||
yield loader.get_data()
|
yield loader.get_data()
|
||||||
|
|
||||||
def load(stream, Loader=Loader):
|
def safe_load(stream):
|
||||||
"""
|
"""
|
||||||
Parse the first YAML document in a stream
|
Parse the first YAML document in a stream
|
||||||
and produce the corresponding Python object.
|
and produce the corresponding Python object.
|
||||||
|
Resolve only basic YAML tags.
|
||||||
"""
|
"""
|
||||||
loader = Loader(stream)
|
return load(stream, SafeLoader)
|
||||||
if loader.check_data():
|
|
||||||
return loader.get_data()
|
|
||||||
|
|
||||||
def safe_load_all(stream):
|
def safe_load_all(stream):
|
||||||
"""
|
"""
|
||||||
|
@ -73,14 +82,6 @@ def safe_load_all(stream):
|
||||||
"""
|
"""
|
||||||
return load_all(stream, SafeLoader)
|
return load_all(stream, SafeLoader)
|
||||||
|
|
||||||
def safe_load(stream):
|
|
||||||
"""
|
|
||||||
Parse the first YAML document in a stream
|
|
||||||
and produce the corresponding Python object.
|
|
||||||
Resolve only basic YAML tags.
|
|
||||||
"""
|
|
||||||
return load(stream, SafeLoader)
|
|
||||||
|
|
||||||
def emit(events, stream=None, Dumper=Dumper,
|
def emit(events, stream=None, Dumper=Dumper,
|
||||||
canonical=None, indent=None, width=None,
|
canonical=None, indent=None, width=None,
|
||||||
allow_unicode=None, line_break=None):
|
allow_unicode=None, line_break=None):
|
||||||
|
@ -90,9 +91,6 @@ def emit(events, stream=None, Dumper=Dumper,
|
||||||
"""
|
"""
|
||||||
getvalue = None
|
getvalue = None
|
||||||
if stream is None:
|
if stream is None:
|
||||||
try:
|
|
||||||
from cStringIO import StringIO
|
|
||||||
except ImportError:
|
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
stream = StringIO()
|
stream = StringIO()
|
||||||
getvalue = stream.getvalue
|
getvalue = stream.getvalue
|
||||||
|
@ -114,10 +112,10 @@ def serialize_all(nodes, stream=None, Dumper=Dumper,
|
||||||
"""
|
"""
|
||||||
getvalue = None
|
getvalue = None
|
||||||
if stream is None:
|
if stream is None:
|
||||||
try:
|
if encoding is None:
|
||||||
from cStringIO import StringIO
|
|
||||||
except ImportError:
|
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
|
else:
|
||||||
|
from cStringIO import StringIO
|
||||||
stream = StringIO()
|
stream = StringIO()
|
||||||
getvalue = stream.getvalue
|
getvalue = stream.getvalue
|
||||||
dumper = Dumper(stream, canonical=canonical, indent=indent, width=width,
|
dumper = Dumper(stream, canonical=canonical, indent=indent, width=width,
|
||||||
|
@ -150,10 +148,10 @@ def dump_all(documents, stream=None, Dumper=Dumper,
|
||||||
"""
|
"""
|
||||||
getvalue = None
|
getvalue = None
|
||||||
if stream is None:
|
if stream is None:
|
||||||
try:
|
if encoding is None:
|
||||||
from cStringIO import StringIO
|
|
||||||
except ImportError:
|
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
|
else:
|
||||||
|
from cStringIO import StringIO
|
||||||
stream = StringIO()
|
stream = StringIO()
|
||||||
getvalue = stream.getvalue
|
getvalue = stream.getvalue
|
||||||
dumper = Dumper(stream, default_style=default_style,
|
dumper = Dumper(stream, default_style=default_style,
|
||||||
|
|
|
@ -26,6 +26,27 @@ class Composer(object):
|
||||||
if not self.check_event(StreamEndEvent):
|
if not self.check_event(StreamEndEvent):
|
||||||
return self.compose_document()
|
return self.compose_document()
|
||||||
|
|
||||||
|
def get_single_node(self):
|
||||||
|
# Drop the STREAM-START event.
|
||||||
|
self.get_event()
|
||||||
|
|
||||||
|
# Compose a document if the stream is not empty.
|
||||||
|
document = None
|
||||||
|
if not self.check_event(StreamEndEvent):
|
||||||
|
document = self.compose_document()
|
||||||
|
|
||||||
|
# Ensure that the stream contains no more documents.
|
||||||
|
if not self.check_event(StreamEndEvent):
|
||||||
|
event = self.get_event()
|
||||||
|
raise ComposerError("expected a single document in the stream",
|
||||||
|
document.start_mark, "but found another document",
|
||||||
|
event.start_mark)
|
||||||
|
|
||||||
|
# Drop the STREAM-END event.
|
||||||
|
self.get_event()
|
||||||
|
|
||||||
|
return document
|
||||||
|
|
||||||
def compose_document(self):
|
def compose_document(self):
|
||||||
# Drop the DOCUMENT-START event.
|
# Drop the DOCUMENT-START event.
|
||||||
self.get_event()
|
self.get_event()
|
||||||
|
|
|
@ -37,6 +37,13 @@ class BaseConstructor(object):
|
||||||
if self.check_node():
|
if self.check_node():
|
||||||
return self.construct_document(self.get_node())
|
return self.construct_document(self.get_node())
|
||||||
|
|
||||||
|
def get_single_data(self):
|
||||||
|
# Ensure that the stream contains a single document and construct it.
|
||||||
|
node = self.get_single_node()
|
||||||
|
if node is not None:
|
||||||
|
return self.construct_document(node)
|
||||||
|
return None
|
||||||
|
|
||||||
def construct_document(self, node):
|
def construct_document(self, node):
|
||||||
data = self.construct_object(node)
|
data = self.construct_object(node)
|
||||||
while self.state_generators:
|
while self.state_generators:
|
||||||
|
@ -61,7 +68,6 @@ class BaseConstructor(object):
|
||||||
"found unconstructable recursive node", node.start_mark)
|
"found unconstructable recursive node", node.start_mark)
|
||||||
self.recursive_objects[node] = None
|
self.recursive_objects[node] = None
|
||||||
constructor = None
|
constructor = None
|
||||||
state_constructor = None
|
|
||||||
tag_suffix = None
|
tag_suffix = None
|
||||||
if node.tag in self.yaml_constructors:
|
if node.tag in self.yaml_constructors:
|
||||||
constructor = self.yaml_constructors[node.tag]
|
constructor = self.yaml_constructors[node.tag]
|
||||||
|
@ -314,7 +320,10 @@ class SafeConstructor(BaseConstructor):
|
||||||
second = int(values['second'])
|
second = int(values['second'])
|
||||||
fraction = 0
|
fraction = 0
|
||||||
if values['fraction']:
|
if values['fraction']:
|
||||||
fraction = int(values['fraction'][:6].ljust(6, '0'))
|
fraction = values['fraction'][:6]
|
||||||
|
while len(fraction) < 6:
|
||||||
|
fraction += '0'
|
||||||
|
fraction = int(fraction)
|
||||||
delta = None
|
delta = None
|
||||||
if values['tz_sign']:
|
if values['tz_sign']:
|
||||||
tz_hour = int(values['tz_hour'])
|
tz_hour = int(values['tz_hour'])
|
||||||
|
|
|
@ -41,7 +41,7 @@ class CBaseDumper(CEmitter, BaseRepresenter, BaseResolver):
|
||||||
encoding=None, explicit_start=None, explicit_end=None,
|
encoding=None, explicit_start=None, explicit_end=None,
|
||||||
version=None, tags=None):
|
version=None, tags=None):
|
||||||
CEmitter.__init__(self, stream, canonical=canonical,
|
CEmitter.__init__(self, stream, canonical=canonical,
|
||||||
indent=indent, width=width,
|
indent=indent, width=width, encoding=encoding,
|
||||||
allow_unicode=allow_unicode, line_break=line_break,
|
allow_unicode=allow_unicode, line_break=line_break,
|
||||||
explicit_start=explicit_start, explicit_end=explicit_end,
|
explicit_start=explicit_start, explicit_end=explicit_end,
|
||||||
version=version, tags=tags)
|
version=version, tags=tags)
|
||||||
|
@ -58,7 +58,7 @@ class CSafeDumper(CEmitter, SafeRepresenter, Resolver):
|
||||||
encoding=None, explicit_start=None, explicit_end=None,
|
encoding=None, explicit_start=None, explicit_end=None,
|
||||||
version=None, tags=None):
|
version=None, tags=None):
|
||||||
CEmitter.__init__(self, stream, canonical=canonical,
|
CEmitter.__init__(self, stream, canonical=canonical,
|
||||||
indent=indent, width=width,
|
indent=indent, width=width, encoding=encoding,
|
||||||
allow_unicode=allow_unicode, line_break=line_break,
|
allow_unicode=allow_unicode, line_break=line_break,
|
||||||
explicit_start=explicit_start, explicit_end=explicit_end,
|
explicit_start=explicit_start, explicit_end=explicit_end,
|
||||||
version=version, tags=tags)
|
version=version, tags=tags)
|
||||||
|
@ -75,7 +75,7 @@ class CDumper(CEmitter, Serializer, Representer, Resolver):
|
||||||
encoding=None, explicit_start=None, explicit_end=None,
|
encoding=None, explicit_start=None, explicit_end=None,
|
||||||
version=None, tags=None):
|
version=None, tags=None):
|
||||||
CEmitter.__init__(self, stream, canonical=canonical,
|
CEmitter.__init__(self, stream, canonical=canonical,
|
||||||
indent=indent, width=width,
|
indent=indent, width=width, encoding=encoding,
|
||||||
allow_unicode=allow_unicode, line_break=line_break,
|
allow_unicode=allow_unicode, line_break=line_break,
|
||||||
explicit_start=explicit_start, explicit_end=explicit_end,
|
explicit_start=explicit_start, explicit_end=explicit_end,
|
||||||
version=version, tags=tags)
|
version=version, tags=tags)
|
||||||
|
|
|
@ -16,7 +16,7 @@ class BaseDumper(Emitter, Serializer, BaseRepresenter, BaseResolver):
|
||||||
version=None, tags=None):
|
version=None, tags=None):
|
||||||
Emitter.__init__(self, stream, canonical=canonical,
|
Emitter.__init__(self, stream, canonical=canonical,
|
||||||
indent=indent, width=width,
|
indent=indent, width=width,
|
||||||
allow_uncode=allow_unicode, line_break=line_break)
|
allow_unicode=allow_unicode, line_break=line_break)
|
||||||
Serializer.__init__(self, encoding=encoding,
|
Serializer.__init__(self, encoding=encoding,
|
||||||
explicit_start=explicit_start, explicit_end=explicit_end,
|
explicit_start=explicit_start, explicit_end=explicit_end,
|
||||||
version=version, tags=tags)
|
version=version, tags=tags)
|
||||||
|
|
221
yaml/emitter.py
221
yaml/emitter.py
|
@ -11,8 +11,6 @@ __all__ = ['Emitter', 'EmitterError']
|
||||||
from error import YAMLError
|
from error import YAMLError
|
||||||
from events import *
|
from events import *
|
||||||
|
|
||||||
import re
|
|
||||||
|
|
||||||
class EmitterError(YAMLError):
|
class EmitterError(YAMLError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -78,6 +76,9 @@ class Emitter(object):
|
||||||
self.whitespace = True
|
self.whitespace = True
|
||||||
self.indention = True
|
self.indention = True
|
||||||
|
|
||||||
|
# Whether the document requires an explicit document indicator
|
||||||
|
self.open_ended = False
|
||||||
|
|
||||||
# Formatting details.
|
# Formatting details.
|
||||||
self.canonical = canonical
|
self.canonical = canonical
|
||||||
self.allow_unicode = allow_unicode
|
self.allow_unicode = allow_unicode
|
||||||
|
@ -153,7 +154,7 @@ class Emitter(object):
|
||||||
|
|
||||||
def expect_stream_start(self):
|
def expect_stream_start(self):
|
||||||
if isinstance(self.event, StreamStartEvent):
|
if isinstance(self.event, StreamStartEvent):
|
||||||
if self.event.encoding:
|
if self.event.encoding and not getattr(self.stream, 'encoding', None):
|
||||||
self.encoding = self.event.encoding
|
self.encoding = self.event.encoding
|
||||||
self.write_stream_start()
|
self.write_stream_start()
|
||||||
self.state = self.expect_first_document_start
|
self.state = self.expect_first_document_start
|
||||||
|
@ -171,6 +172,9 @@ class Emitter(object):
|
||||||
|
|
||||||
def expect_document_start(self, first=False):
|
def expect_document_start(self, first=False):
|
||||||
if isinstance(self.event, DocumentStartEvent):
|
if isinstance(self.event, DocumentStartEvent):
|
||||||
|
if (self.event.version or self.event.tags) and self.open_ended:
|
||||||
|
self.write_indicator(u'...', True)
|
||||||
|
self.write_indent()
|
||||||
if self.event.version:
|
if self.event.version:
|
||||||
version_text = self.prepare_version(self.event.version)
|
version_text = self.prepare_version(self.event.version)
|
||||||
self.write_version_directive(version_text)
|
self.write_version_directive(version_text)
|
||||||
|
@ -194,6 +198,9 @@ class Emitter(object):
|
||||||
self.write_indent()
|
self.write_indent()
|
||||||
self.state = self.expect_document_root
|
self.state = self.expect_document_root
|
||||||
elif isinstance(self.event, StreamEndEvent):
|
elif isinstance(self.event, StreamEndEvent):
|
||||||
|
if self.open_ended:
|
||||||
|
self.write_indicator(u'...', True)
|
||||||
|
self.write_indent()
|
||||||
self.write_stream_end()
|
self.write_stream_end()
|
||||||
self.state = self.expect_nothing
|
self.state = self.expect_nothing
|
||||||
else:
|
else:
|
||||||
|
@ -538,7 +545,7 @@ class Emitter(object):
|
||||||
raise EmitterError("tag handle must start and end with '!': %r"
|
raise EmitterError("tag handle must start and end with '!': %r"
|
||||||
% (handle.encode('utf-8')))
|
% (handle.encode('utf-8')))
|
||||||
for ch in handle[1:-1]:
|
for ch in handle[1:-1]:
|
||||||
if not (u'0' <= ch <= u'9' or u'A' <= ch <= 'Z' or u'a' <= ch <= 'z' \
|
if not (u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \
|
||||||
or ch in u'-_'):
|
or ch in u'-_'):
|
||||||
raise EmitterError("invalid character %r in the tag handle: %r"
|
raise EmitterError("invalid character %r in the tag handle: %r"
|
||||||
% (ch.encode('utf-8'), handle.encode('utf-8')))
|
% (ch.encode('utf-8'), handle.encode('utf-8')))
|
||||||
|
@ -553,7 +560,7 @@ class Emitter(object):
|
||||||
end = 1
|
end = 1
|
||||||
while end < len(prefix):
|
while end < len(prefix):
|
||||||
ch = prefix[end]
|
ch = prefix[end]
|
||||||
if u'0' <= ch <= u'9' or u'A' <= ch <= 'Z' or u'a' <= ch <= 'z' \
|
if u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \
|
||||||
or ch in u'-;/?!:@&=+$,_.~*\'()[]':
|
or ch in u'-;/?!:@&=+$,_.~*\'()[]':
|
||||||
end += 1
|
end += 1
|
||||||
else:
|
else:
|
||||||
|
@ -583,7 +590,7 @@ class Emitter(object):
|
||||||
start = end = 0
|
start = end = 0
|
||||||
while end < len(suffix):
|
while end < len(suffix):
|
||||||
ch = suffix[end]
|
ch = suffix[end]
|
||||||
if u'0' <= ch <= u'9' or u'A' <= ch <= 'Z' or u'a' <= ch <= 'z' \
|
if u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \
|
||||||
or ch in u'-;/?:@&=+$,_.~*\'()[]' \
|
or ch in u'-;/?:@&=+$,_.~*\'()[]' \
|
||||||
or (ch == u'!' and handle != u'!'):
|
or (ch == u'!' and handle != u'!'):
|
||||||
end += 1
|
end += 1
|
||||||
|
@ -606,7 +613,7 @@ class Emitter(object):
|
||||||
if not anchor:
|
if not anchor:
|
||||||
raise EmitterError("anchor must not be empty")
|
raise EmitterError("anchor must not be empty")
|
||||||
for ch in anchor:
|
for ch in anchor:
|
||||||
if not (u'0' <= ch <= u'9' or u'A' <= ch <= 'Z' or u'a' <= ch <= 'z' \
|
if not (u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \
|
||||||
or ch in u'-_'):
|
or ch in u'-_'):
|
||||||
raise EmitterError("invalid character %r in the anchor: %r"
|
raise EmitterError("invalid character %r in the anchor: %r"
|
||||||
% (ch.encode('utf-8'), anchor.encode('utf-8')))
|
% (ch.encode('utf-8'), anchor.encode('utf-8')))
|
||||||
|
@ -627,15 +634,13 @@ class Emitter(object):
|
||||||
line_breaks = False
|
line_breaks = False
|
||||||
special_characters = False
|
special_characters = False
|
||||||
|
|
||||||
# Whitespaces.
|
# Important whitespace combinations.
|
||||||
inline_spaces = False # non-space space+ non-space
|
leading_space = False
|
||||||
inline_breaks = False # non-space break+ non-space
|
leading_break = False
|
||||||
leading_spaces = False # ^ space+ (non-space | $)
|
trailing_space = False
|
||||||
leading_breaks = False # ^ break+ (non-space | $)
|
trailing_break = False
|
||||||
trailing_spaces = False # (^ | non-space) space+ $
|
break_space = False
|
||||||
trailing_breaks = False # (^ | non-space) break+ $
|
space_break = False
|
||||||
inline_breaks_spaces = False # non-space break+ space+ non-space
|
|
||||||
mixed_breaks_spaces = False # anything else
|
|
||||||
|
|
||||||
# Check document indicators.
|
# Check document indicators.
|
||||||
if scalar.startswith(u'---') or scalar.startswith(u'...'):
|
if scalar.startswith(u'---') or scalar.startswith(u'...'):
|
||||||
|
@ -643,32 +648,23 @@ class Emitter(object):
|
||||||
flow_indicators = True
|
flow_indicators = True
|
||||||
|
|
||||||
# First character or preceded by a whitespace.
|
# First character or preceded by a whitespace.
|
||||||
preceeded_by_space = True
|
preceeded_by_whitespace = True
|
||||||
|
|
||||||
# Last character or followed by a whitespace.
|
# Last character or followed by a whitespace.
|
||||||
followed_by_space = (len(scalar) == 1 or
|
followed_by_whitespace = (len(scalar) == 1 or
|
||||||
scalar[1] in u'\0 \t\r\n\x85\u2028\u2029')
|
scalar[1] in u'\0 \t\r\n\x85\u2028\u2029')
|
||||||
|
|
||||||
# The current series of whitespaces contain plain spaces.
|
# The previous character is a space.
|
||||||
spaces = False
|
previous_space = False
|
||||||
|
|
||||||
# The current series of whitespaces contain line breaks.
|
# The previous character is a break.
|
||||||
breaks = False
|
previous_break = False
|
||||||
|
|
||||||
# The current series of whitespaces contain a space followed by a
|
|
||||||
# break.
|
|
||||||
mixed = False
|
|
||||||
|
|
||||||
# The current series of whitespaces start at the beginning of the
|
|
||||||
# scalar.
|
|
||||||
leading = False
|
|
||||||
|
|
||||||
index = 0
|
index = 0
|
||||||
while index < len(scalar):
|
while index < len(scalar):
|
||||||
ch = scalar[index]
|
ch = scalar[index]
|
||||||
|
|
||||||
# Check for indicators.
|
# Check for indicators.
|
||||||
|
|
||||||
if index == 0:
|
if index == 0:
|
||||||
# Leading indicators are special characters.
|
# Leading indicators are special characters.
|
||||||
if ch in u'#,[]{}&*!|>\'\"%@`':
|
if ch in u'#,[]{}&*!|>\'\"%@`':
|
||||||
|
@ -676,9 +672,9 @@ class Emitter(object):
|
||||||
block_indicators = True
|
block_indicators = True
|
||||||
if ch in u'?:':
|
if ch in u'?:':
|
||||||
flow_indicators = True
|
flow_indicators = True
|
||||||
if followed_by_space:
|
if followed_by_whitespace:
|
||||||
block_indicators = True
|
block_indicators = True
|
||||||
if ch == u'-' and followed_by_space:
|
if ch == u'-' and followed_by_whitespace:
|
||||||
flow_indicators = True
|
flow_indicators = True
|
||||||
block_indicators = True
|
block_indicators = True
|
||||||
else:
|
else:
|
||||||
|
@ -687,14 +683,13 @@ class Emitter(object):
|
||||||
flow_indicators = True
|
flow_indicators = True
|
||||||
if ch == u':':
|
if ch == u':':
|
||||||
flow_indicators = True
|
flow_indicators = True
|
||||||
if followed_by_space:
|
if followed_by_whitespace:
|
||||||
block_indicators = True
|
block_indicators = True
|
||||||
if ch == u'#' and preceeded_by_space:
|
if ch == u'#' and preceeded_by_whitespace:
|
||||||
flow_indicators = True
|
flow_indicators = True
|
||||||
block_indicators = True
|
block_indicators = True
|
||||||
|
|
||||||
# Check for line breaks, special, and unicode characters.
|
# Check for line breaks, special, and unicode characters.
|
||||||
|
|
||||||
if ch in u'\n\x85\u2028\u2029':
|
if ch in u'\n\x85\u2028\u2029':
|
||||||
line_breaks = True
|
line_breaks = True
|
||||||
if not (ch == u'\n' or u'\x20' <= ch <= u'\x7E'):
|
if not (ch == u'\n' or u'\x20' <= ch <= u'\x7E'):
|
||||||
|
@ -706,65 +701,33 @@ class Emitter(object):
|
||||||
else:
|
else:
|
||||||
special_characters = True
|
special_characters = True
|
||||||
|
|
||||||
# Spaces, line breaks, and how they are mixed. State machine.
|
# Detect important whitespace combinations.
|
||||||
|
if ch == u' ':
|
||||||
# Start or continue series of whitespaces.
|
if index == 0:
|
||||||
if ch in u' \n\x85\u2028\u2029':
|
leading_space = True
|
||||||
if spaces and breaks:
|
if index == len(scalar)-1:
|
||||||
if ch != u' ': # break+ (space+ break+) => mixed
|
trailing_space = True
|
||||||
mixed = True
|
if previous_break:
|
||||||
elif spaces:
|
break_space = True
|
||||||
if ch != u' ': # (space+ break+) => mixed
|
previous_space = True
|
||||||
breaks = True
|
previous_break = False
|
||||||
mixed = True
|
elif ch in u'\n\x85\u2028\u2029':
|
||||||
elif breaks:
|
if index == 0:
|
||||||
if ch == u' ': # break+ space+
|
leading_break = True
|
||||||
spaces = True
|
if index == len(scalar)-1:
|
||||||
|
trailing_break = True
|
||||||
|
if previous_space:
|
||||||
|
space_break = True
|
||||||
|
previous_space = False
|
||||||
|
previous_break = True
|
||||||
else:
|
else:
|
||||||
leading = (index == 0)
|
previous_space = False
|
||||||
if ch == u' ': # space+
|
previous_break = False
|
||||||
spaces = True
|
|
||||||
else: # break+
|
|
||||||
breaks = True
|
|
||||||
|
|
||||||
# Series of whitespaces ended with a non-space.
|
|
||||||
elif spaces or breaks:
|
|
||||||
if leading:
|
|
||||||
if spaces and breaks:
|
|
||||||
mixed_breaks_spaces = True
|
|
||||||
elif spaces:
|
|
||||||
leading_spaces = True
|
|
||||||
elif breaks:
|
|
||||||
leading_breaks = True
|
|
||||||
else:
|
|
||||||
if mixed:
|
|
||||||
mixed_breaks_spaces = True
|
|
||||||
elif spaces and breaks:
|
|
||||||
inline_breaks_spaces = True
|
|
||||||
elif spaces:
|
|
||||||
inline_spaces = True
|
|
||||||
elif breaks:
|
|
||||||
inline_breaks = True
|
|
||||||
spaces = breaks = mixed = leading = False
|
|
||||||
|
|
||||||
# Series of whitespaces reach the end.
|
|
||||||
if (spaces or breaks) and (index == len(scalar)-1):
|
|
||||||
if spaces and breaks:
|
|
||||||
mixed_breaks_spaces = True
|
|
||||||
elif spaces:
|
|
||||||
trailing_spaces = True
|
|
||||||
if leading:
|
|
||||||
leading_spaces = True
|
|
||||||
elif breaks:
|
|
||||||
trailing_breaks = True
|
|
||||||
if leading:
|
|
||||||
leading_breaks = True
|
|
||||||
spaces = breaks = mixed = leading = False
|
|
||||||
|
|
||||||
# Prepare for the next character.
|
# Prepare for the next character.
|
||||||
index += 1
|
index += 1
|
||||||
preceeded_by_space = (ch in u'\0 \t\r\n\x85\u2028\u2029')
|
preceeded_by_whitespace = (ch in u'\0 \t\r\n\x85\u2028\u2029')
|
||||||
followed_by_space = (index+1 >= len(scalar) or
|
followed_by_whitespace = (index+1 >= len(scalar) or
|
||||||
scalar[index+1] in u'\0 \t\r\n\x85\u2028\u2029')
|
scalar[index+1] in u'\0 \t\r\n\x85\u2028\u2029')
|
||||||
|
|
||||||
# Let's decide what styles are allowed.
|
# Let's decide what styles are allowed.
|
||||||
|
@ -774,28 +737,28 @@ class Emitter(object):
|
||||||
allow_double_quoted = True
|
allow_double_quoted = True
|
||||||
allow_block = True
|
allow_block = True
|
||||||
|
|
||||||
# Leading and trailing whitespace are bad for plain scalars. We also
|
# Leading and trailing whitespaces are bad for plain scalars.
|
||||||
# do not want to mess with leading whitespaces for block scalars.
|
if (leading_space or leading_break
|
||||||
if leading_spaces or leading_breaks or trailing_spaces:
|
or trailing_space or trailing_break):
|
||||||
allow_flow_plain = allow_block_plain = allow_block = False
|
|
||||||
|
|
||||||
# Trailing breaks are fine for block scalars, but unacceptable for
|
|
||||||
# plain scalars.
|
|
||||||
if trailing_breaks:
|
|
||||||
allow_flow_plain = allow_block_plain = False
|
allow_flow_plain = allow_block_plain = False
|
||||||
|
|
||||||
# The combination of (space+ break+) is only acceptable for block
|
# We do not permit trailing spaces for block scalars.
|
||||||
|
if trailing_space:
|
||||||
|
allow_block = False
|
||||||
|
|
||||||
|
# Spaces at the beginning of a new line are only acceptable for block
|
||||||
# scalars.
|
# scalars.
|
||||||
if inline_breaks_spaces:
|
if break_space:
|
||||||
allow_flow_plain = allow_block_plain = allow_single_quoted = False
|
allow_flow_plain = allow_block_plain = allow_single_quoted = False
|
||||||
|
|
||||||
# Mixed spaces and breaks, as well as special character are only
|
# Spaces followed by breaks, as well as special character are only
|
||||||
# allowed for double quoted scalars.
|
# allowed for double quoted scalars.
|
||||||
if mixed_breaks_spaces or special_characters:
|
if space_break or special_characters:
|
||||||
allow_flow_plain = allow_block_plain = \
|
allow_flow_plain = allow_block_plain = \
|
||||||
allow_single_quoted = allow_block = False
|
allow_single_quoted = allow_block = False
|
||||||
|
|
||||||
# We don't emit multiline plain scalars.
|
# Although the plain scalar writer supports breaks, we never emit
|
||||||
|
# multiline plain scalars.
|
||||||
if line_breaks:
|
if line_breaks:
|
||||||
allow_flow_plain = allow_block_plain = False
|
allow_flow_plain = allow_block_plain = False
|
||||||
|
|
||||||
|
@ -838,6 +801,7 @@ class Emitter(object):
|
||||||
self.whitespace = whitespace
|
self.whitespace = whitespace
|
||||||
self.indention = self.indention and indention
|
self.indention = self.indention and indention
|
||||||
self.column += len(data)
|
self.column += len(data)
|
||||||
|
self.open_ended = False
|
||||||
if self.encoding:
|
if self.encoding:
|
||||||
data = data.encode(self.encoding)
|
data = data.encode(self.encoding)
|
||||||
self.stream.write(data)
|
self.stream.write(data)
|
||||||
|
@ -1008,25 +972,26 @@ class Emitter(object):
|
||||||
end += 1
|
end += 1
|
||||||
self.write_indicator(u'"', False)
|
self.write_indicator(u'"', False)
|
||||||
|
|
||||||
def determine_chomp(self, text):
|
def determine_block_hints(self, text):
|
||||||
tail = text[-2:]
|
hints = u''
|
||||||
while len(tail) < 2:
|
if text:
|
||||||
tail = u' '+tail
|
if text[0] in u' \n\x85\u2028\u2029':
|
||||||
if tail[-1] in u'\n\x85\u2028\u2029':
|
hints += unicode(self.best_indent)
|
||||||
if tail[-2] in u'\n\x85\u2028\u2029':
|
if text[-1] not in u'\n\x85\u2028\u2029':
|
||||||
return u'+'
|
hints += u'-'
|
||||||
else:
|
elif len(text) == 1 or text[-2] in u'\n\x85\u2028\u2029':
|
||||||
return u''
|
hints += u'+'
|
||||||
else:
|
return hints
|
||||||
return u'-'
|
|
||||||
|
|
||||||
def write_folded(self, text):
|
def write_folded(self, text):
|
||||||
chomp = self.determine_chomp(text)
|
hints = self.determine_block_hints(text)
|
||||||
self.write_indicator(u'>'+chomp, True)
|
self.write_indicator(u'>'+hints, True)
|
||||||
self.write_indent()
|
if hints[-1:] == u'+':
|
||||||
leading_space = False
|
self.open_ended = True
|
||||||
|
self.write_line_break()
|
||||||
|
leading_space = True
|
||||||
spaces = False
|
spaces = False
|
||||||
breaks = False
|
breaks = True
|
||||||
start = end = 0
|
start = end = 0
|
||||||
while end <= len(text):
|
while end <= len(text):
|
||||||
ch = None
|
ch = None
|
||||||
|
@ -1072,10 +1037,12 @@ class Emitter(object):
|
||||||
end += 1
|
end += 1
|
||||||
|
|
||||||
def write_literal(self, text):
|
def write_literal(self, text):
|
||||||
chomp = self.determine_chomp(text)
|
hints = self.determine_block_hints(text)
|
||||||
self.write_indicator(u'|'+chomp, True)
|
self.write_indicator(u'|'+hints, True)
|
||||||
self.write_indent()
|
if hints[-1:] == u'+':
|
||||||
breaks = False
|
self.open_ended = True
|
||||||
|
self.write_line_break()
|
||||||
|
breaks = True
|
||||||
start = end = 0
|
start = end = 0
|
||||||
while end <= len(text):
|
while end <= len(text):
|
||||||
ch = None
|
ch = None
|
||||||
|
@ -1105,6 +1072,8 @@ class Emitter(object):
|
||||||
end += 1
|
end += 1
|
||||||
|
|
||||||
def write_plain(self, text, split=True):
|
def write_plain(self, text, split=True):
|
||||||
|
if self.root_context:
|
||||||
|
self.open_ended = True
|
||||||
if not text:
|
if not text:
|
||||||
return
|
return
|
||||||
if not self.whitespace:
|
if not self.whitespace:
|
||||||
|
@ -1113,7 +1082,7 @@ class Emitter(object):
|
||||||
if self.encoding:
|
if self.encoding:
|
||||||
data = data.encode(self.encoding)
|
data = data.encode(self.encoding)
|
||||||
self.stream.write(data)
|
self.stream.write(data)
|
||||||
self.writespace = False
|
self.whitespace = False
|
||||||
self.indention = False
|
self.indention = False
|
||||||
spaces = False
|
spaces = False
|
||||||
breaks = False
|
breaks = False
|
||||||
|
@ -1126,7 +1095,7 @@ class Emitter(object):
|
||||||
if ch != u' ':
|
if ch != u' ':
|
||||||
if start+1 == end and self.column > self.best_width and split:
|
if start+1 == end and self.column > self.best_width and split:
|
||||||
self.write_indent()
|
self.write_indent()
|
||||||
self.writespace = False
|
self.whitespace = False
|
||||||
self.indention = False
|
self.indention = False
|
||||||
else:
|
else:
|
||||||
data = text[start:end]
|
data = text[start:end]
|
||||||
|
|
|
@ -72,8 +72,6 @@ class ParserError(MarkedYAMLError):
|
||||||
class Parser(object):
|
class Parser(object):
|
||||||
# Since writing a recursive-descendant parser is a straightforward task, we
|
# Since writing a recursive-descendant parser is a straightforward task, we
|
||||||
# do not give many comments here.
|
# do not give many comments here.
|
||||||
# Note that we use Python generators. If you rewrite the parser in another
|
|
||||||
# language, you may replace all 'yield'-s with event handler calls.
|
|
||||||
|
|
||||||
DEFAULT_TAGS = {
|
DEFAULT_TAGS = {
|
||||||
u'!': u'!',
|
u'!': u'!',
|
||||||
|
|
|
@ -74,7 +74,7 @@ class ReaderError(YAMLError):
|
||||||
else:
|
else:
|
||||||
return "unacceptable character #x%04x: %s\n" \
|
return "unacceptable character #x%04x: %s\n" \
|
||||||
" in \"%s\", position %d" \
|
" in \"%s\", position %d" \
|
||||||
% (ord(self.character), self.reason,
|
% (self.character, self.reason,
|
||||||
self.name, self.position)
|
self.name, self.position)
|
||||||
|
|
||||||
class Reader(object):
|
class Reader(object):
|
||||||
|
@ -175,7 +175,7 @@ class Reader(object):
|
||||||
if match:
|
if match:
|
||||||
character = match.group()
|
character = match.group()
|
||||||
position = self.index+(len(self.buffer)-self.pointer)+match.start()
|
position = self.index+(len(self.buffer)-self.pointer)+match.start()
|
||||||
raise ReaderError(self.name, position, character,
|
raise ReaderError(self.name, position, ord(character),
|
||||||
'unicode', "special characters are not allowed")
|
'unicode', "special characters are not allowed")
|
||||||
|
|
||||||
def update(self, length):
|
def update(self, length):
|
||||||
|
|
|
@ -286,6 +286,7 @@ SafeRepresenter.add_representer(set,
|
||||||
|
|
||||||
SafeRepresenter.add_representer(datetime.date,
|
SafeRepresenter.add_representer(datetime.date,
|
||||||
SafeRepresenter.represent_date)
|
SafeRepresenter.represent_date)
|
||||||
|
|
||||||
SafeRepresenter.add_representer(datetime.datetime,
|
SafeRepresenter.add_representer(datetime.datetime,
|
||||||
SafeRepresenter.represent_datetime)
|
SafeRepresenter.represent_datetime)
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,8 @@ Resolver.add_implicit_resolver(
|
||||||
|
|
||||||
Resolver.add_implicit_resolver(
|
Resolver.add_implicit_resolver(
|
||||||
u'tag:yaml.org,2002:float',
|
u'tag:yaml.org,2002:float',
|
||||||
re.compile(ur'''^(?:[-+]?(?:[0-9][0-9_]*)?\.[0-9_]*(?:[eE][-+][0-9]+)?
|
re.compile(ur'''^(?:[-+]?(?:[0-9][0-9_]*)\.[0-9_]*(?:[eE][-+][0-9]+)?
|
||||||
|
|\.[0-9_]+(?:[eE][-+][0-9]+)?
|
||||||
|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\.[0-9_]*
|
|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\.[0-9_]*
|
||||||
|[-+]?\.(?:inf|Inf|INF)
|
|[-+]?\.(?:inf|Inf|INF)
|
||||||
|\.(?:nan|NaN|NAN))$''', re.X),
|
|\.(?:nan|NaN|NAN))$''', re.X),
|
||||||
|
@ -191,7 +192,7 @@ Resolver.add_implicit_resolver(
|
||||||
Resolver.add_implicit_resolver(
|
Resolver.add_implicit_resolver(
|
||||||
u'tag:yaml.org,2002:merge',
|
u'tag:yaml.org,2002:merge',
|
||||||
re.compile(ur'^(?:<<)$'),
|
re.compile(ur'^(?:<<)$'),
|
||||||
['<'])
|
[u'<'])
|
||||||
|
|
||||||
Resolver.add_implicit_resolver(
|
Resolver.add_implicit_resolver(
|
||||||
u'tag:yaml.org,2002:null',
|
u'tag:yaml.org,2002:null',
|
||||||
|
@ -212,7 +213,7 @@ Resolver.add_implicit_resolver(
|
||||||
Resolver.add_implicit_resolver(
|
Resolver.add_implicit_resolver(
|
||||||
u'tag:yaml.org,2002:value',
|
u'tag:yaml.org,2002:value',
|
||||||
re.compile(ur'^(?:=)$'),
|
re.compile(ur'^(?:=)$'),
|
||||||
['='])
|
[u'='])
|
||||||
|
|
||||||
# The following resolver is only for documentation purposes. It cannot work
|
# The following resolver is only for documentation purposes. It cannot work
|
||||||
# because plain scalars cannot start with '!', '&', or '*'.
|
# because plain scalars cannot start with '!', '&', or '*'.
|
||||||
|
|
|
@ -807,7 +807,7 @@ class Scanner(object):
|
||||||
# See the specification for details.
|
# See the specification for details.
|
||||||
length = 0
|
length = 0
|
||||||
ch = self.peek(length)
|
ch = self.peek(length)
|
||||||
while u'0' <= ch <= u'9' or u'A' <= ch <= 'Z' or u'a' <= ch <= 'z' \
|
while u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \
|
||||||
or ch in u'-_':
|
or ch in u'-_':
|
||||||
length += 1
|
length += 1
|
||||||
ch = self.peek(length)
|
ch = self.peek(length)
|
||||||
|
@ -846,7 +846,7 @@ class Scanner(object):
|
||||||
def scan_yaml_directive_number(self, start_mark):
|
def scan_yaml_directive_number(self, start_mark):
|
||||||
# See the specification for details.
|
# See the specification for details.
|
||||||
ch = self.peek()
|
ch = self.peek()
|
||||||
if not (u'0' <= ch <= '9'):
|
if not (u'0' <= ch <= u'9'):
|
||||||
raise ScannerError("while scanning a directive", start_mark,
|
raise ScannerError("while scanning a directive", start_mark,
|
||||||
"expected a digit, but found %r" % ch.encode('utf-8'),
|
"expected a digit, but found %r" % ch.encode('utf-8'),
|
||||||
self.get_mark())
|
self.get_mark())
|
||||||
|
@ -912,14 +912,14 @@ class Scanner(object):
|
||||||
# Therefore we restrict aliases to numbers and ASCII letters.
|
# Therefore we restrict aliases to numbers and ASCII letters.
|
||||||
start_mark = self.get_mark()
|
start_mark = self.get_mark()
|
||||||
indicator = self.peek()
|
indicator = self.peek()
|
||||||
if indicator == '*':
|
if indicator == u'*':
|
||||||
name = 'alias'
|
name = 'alias'
|
||||||
else:
|
else:
|
||||||
name = 'anchor'
|
name = 'anchor'
|
||||||
self.forward()
|
self.forward()
|
||||||
length = 0
|
length = 0
|
||||||
ch = self.peek(length)
|
ch = self.peek(length)
|
||||||
while u'0' <= ch <= u'9' or u'A' <= ch <= 'Z' or u'a' <= ch <= 'z' \
|
while u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \
|
||||||
or ch in u'-_':
|
or ch in u'-_':
|
||||||
length += 1
|
length += 1
|
||||||
ch = self.peek(length)
|
ch = self.peek(length)
|
||||||
|
@ -1368,7 +1368,7 @@ class Scanner(object):
|
||||||
length = 1
|
length = 1
|
||||||
ch = self.peek(length)
|
ch = self.peek(length)
|
||||||
if ch != u' ':
|
if ch != u' ':
|
||||||
while u'0' <= ch <= u'9' or u'A' <= ch <= 'Z' or u'a' <= ch <= 'z' \
|
while u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \
|
||||||
or ch in u'-_':
|
or ch in u'-_':
|
||||||
length += 1
|
length += 1
|
||||||
ch = self.peek(length)
|
ch = self.peek(length)
|
||||||
|
@ -1388,7 +1388,7 @@ class Scanner(object):
|
||||||
chunks = []
|
chunks = []
|
||||||
length = 0
|
length = 0
|
||||||
ch = self.peek(length)
|
ch = self.peek(length)
|
||||||
while u'0' <= ch <= u'9' or u'A' <= ch <= 'Z' or u'a' <= ch <= 'z' \
|
while u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \
|
||||||
or ch in u'-;/?:@&=+$,_.!~*\'()[]%':
|
or ch in u'-;/?:@&=+$,_.!~*\'()[]%':
|
||||||
if ch == u'%':
|
if ch == u'%':
|
||||||
chunks.append(self.prefix(length))
|
chunks.append(self.prefix(length))
|
||||||
|
|
|
@ -55,7 +55,7 @@ class Serializer(object):
|
||||||
self.emit(DocumentEndEvent(explicit=self.use_explicit_end))
|
self.emit(DocumentEndEvent(explicit=self.use_explicit_end))
|
||||||
self.serialized_nodes = {}
|
self.serialized_nodes = {}
|
||||||
self.anchors = {}
|
self.anchors = {}
|
||||||
self.last_alias_id = 0
|
self.last_anchor_id = 0
|
||||||
|
|
||||||
def anchor_node(self, node):
|
def anchor_node(self, node):
|
||||||
if node in self.anchors:
|
if node in self.anchors:
|
||||||
|
|
Loading…
Reference in New Issue