From 3d77f16e00124b74e150625396617b41e41da014 Mon Sep 17 00:00:00 2001 From: Anthon van der Neut Date: Mon, 19 Apr 2021 08:17:05 +0200 Subject: removed (object), prepare new RTScanner --- _test/test_comments.py | 8 +++ _test/test_z_data.py | 3 ++ anchor.py | 2 +- comments.py | 34 +++++++++---- compat.py | 7 ++- composer.py | 2 +- constructor.py | 2 +- emitter.py | 37 +++++++++----- error.py | 4 +- events.py | 36 ++++++++----- main.py | 6 +-- nodes.py | 2 +- parser.py | 27 ++++++---- reader.py | 2 +- representer.py | 2 +- resolver.py | 2 +- scanner.py | 16 ++---- serializer.py | 2 +- tokens.py | 134 ++++++++++++++++++++++++++++++++++++++++++------- util.py | 2 +- 20 files changed, 240 insertions(+), 90 deletions(-) diff --git a/_test/test_comments.py b/_test/test_comments.py index 3173995..dbf035d 100644 --- a/_test/test_comments.py +++ b/_test/test_comments.py @@ -813,6 +813,14 @@ class TestEmptyValueBeforeComments: - [] """) + def test_comment_after_block_scalar_indicator(self): + round_trip("""\ + a: | # abc + test 1 + test 2 + # all done + """) + test_block_scalar_commented_line_template = """\ y: p diff --git a/_test/test_z_data.py b/_test/test_z_data.py index e48e9d5..965eb3d 100644 --- a/_test/test_z_data.py +++ b/_test/test_z_data.py @@ -89,6 +89,9 @@ def pytest_generate_tests(metafunc): if os.environ.get('RUAMELAUTOTEST') == '1': if path.parent.stem != 'debug': continue + elif path.parent.stem == 'debug': + # don't test debug entries for production + continue stem = path.stem if stem.startswith('.#'): # skip emacs temporary file continue diff --git a/anchor.py b/anchor.py index a501416..1deea78 100644 --- a/anchor.py +++ b/anchor.py @@ -5,7 +5,7 @@ if False: # MYPY anchor_attrib = '_yaml_anchor' -class Anchor(object): +class Anchor: __slots__ = 'value', 'always_dump' attrib = anchor_attrib diff --git a/comments.py b/comments.py index 62dfe3f..d133299 100644 --- a/comments.py +++ b/comments.py @@ -23,9 +23,25 @@ if False: # MYPY # fmt: off __all__ = ['CommentedSeq', 'CommentedKeySeq', 'CommentedMap', 'CommentedOrderedMap', - 'CommentedSet', 'comment_attrib', 'merge_attrib'] + 'CommentedSet', 'comment_attrib', 'merge_attrib', + 'C_POST', 'C_PRE', 'C_SPLIT_ON_FIRST_BLANK', 'C_BLANK_LINE_PRESERVE_SPACE', + ] # fmt: on +# splitting of comments by the scanner +# an EOLC (End-Of-Line Comment) is preceded by some token +# an FLC (Full Line Comment) is a comment not preceded by a token, i.e. # is first non-blank on line +# a BL is a blank line i.e. empty or spaces/tabs only +# bits 0 and 1 are combined, you can choose only one +C_POST = 0b00 +C_PRE = 0b01 +C_SPLIT_ON_FIRST_BLANK = 0b10 # as C_POST, but if blank line then C_PRE everything before first + # blank goes to POST even if no following real FLC +# 0b11 -> reserved for future use +C_BLANK_LINE_PRESERVE_SPACE = 0b100 +# C_EOL_PRESERVE_SPACE2 = 0b1000 + + comment_attrib = '_yaml_comment' format_attrib = '_yaml_format' line_col_attrib = '_yaml_line_col' @@ -33,7 +49,7 @@ merge_attrib = '_yaml_merge' tag_attrib = '_yaml_tag' -class Comment(object): +class Comment: # using sys.getsize tested the Comment objects, __slots__ makes them bigger # and adding self.end did not matter __slots__ = 'comment', '_items', '_end', '_start' @@ -127,7 +143,7 @@ def NoComment(): pass -class Format(object): +class Format: __slots__ = ('_flow_style',) attrib = format_attrib @@ -154,7 +170,7 @@ class Format(object): return self._flow_style -class LineCol(object): +class LineCol: """ line and column information wrt document, values start at zero (0) """ @@ -205,7 +221,7 @@ class LineCol(object): return _F('LineCol({line}, {col})', line=self.line, col=self.col) -class Tag(object): +class Tag: """store tag information for roundtripping""" __slots__ = ('value',) @@ -220,7 +236,7 @@ class Tag(object): return '{0.__class__.__name__}({0.value!r})'.format(self) -class CommentedBase(object): +class CommentedBase: @property def ca(self): # type: () -> Any @@ -274,7 +290,7 @@ class CommentedBase(object): c = com.strip() if len(c) > 0 and c[0] != '#': com = '# ' + com - pre_comments.append(CommentToken(com + '\n', start_mark, None)) + pre_comments.append(CommentToken(com + '\n', start_mark)) def yaml_set_comment_before_after_key( self, key, before=None, indent=0, after=None, after_indent=None @@ -289,7 +305,7 @@ class CommentedBase(object): def comment_token(s, mark): # type: (Any, Any) -> Any # handle empty lines as having no comment - return CommentToken(('# ' if s else "") + s + '\n', mark, None) + return CommentToken(('# ' if s else "") + s + '\n', mark) if after_indent is None: after_indent = indent + 2 @@ -343,7 +359,7 @@ class CommentedBase(object): comment = ' ' + comment column = 0 start_mark = CommentMark(column) - ct = [CommentToken(comment, start_mark, None), None] + ct = [CommentToken(comment, start_mark), None] self._yaml_add_eol_comment(ct, key=key) @property diff --git a/compat.py b/compat.py index 7a419dc..10ebc23 100644 --- a/compat.py +++ b/compat.py @@ -95,7 +95,7 @@ if 'RUAMELDEBUG' in os.environ: if bool(_debug): - class ObjectCounter(object): + class ObjectCounter: def __init__(self): # type: () -> None self.map = {} # type: Dict[Any, Any] @@ -128,7 +128,7 @@ def dbg(val=None): return _debug & val -class Nprint(object): +class Nprint: def __init__(self, file_name=None): # type: (Any) -> None self._max_print = None # type: Any @@ -162,6 +162,9 @@ class Nprint(object): self._max_print = i self._count = None + def fp(self, mode='a'): + out = sys.stdout if self._file_name is None else open(self._file_name, mode) + return out nprint = Nprint() nprintf = Nprint('/var/tmp/ruamel.yaml.log') diff --git a/composer.py b/composer.py index c47c85d..1d7fc65 100644 --- a/composer.py +++ b/composer.py @@ -27,7 +27,7 @@ class ComposerError(MarkedYAMLError): pass -class Composer(object): +class Composer: def __init__(self, loader=None): # type: (Any) -> None self.loader = loader diff --git a/constructor.py b/constructor.py index 3fddba6..7b7426f 100644 --- a/constructor.py +++ b/constructor.py @@ -52,7 +52,7 @@ class DuplicateKeyError(MarkedYAMLFutureWarning): pass -class BaseConstructor(object): +class BaseConstructor: yaml_constructors = {} # type: Dict[Any, Any] yaml_multi_constructors = {} # type: Dict[Any, Any] diff --git a/emitter.py b/emitter.py index 9f37906..afbffc4 100644 --- a/emitter.py +++ b/emitter.py @@ -13,7 +13,7 @@ from ruamel.yaml.events import * # NOQA # fmt: off from ruamel.yaml.compat import _F, nprint, dbg, DBG_EVENT, \ - check_anchorname_char + check_anchorname_char, nprintf # fmt: on if False: # MYPY @@ -27,7 +27,7 @@ class EmitterError(YAMLError): pass -class ScalarAnalysis(object): +class ScalarAnalysis: def __init__( self, scalar, @@ -50,7 +50,7 @@ class ScalarAnalysis(object): self.allow_block = allow_block -class Indents(object): +class Indents: # replacement for the list based stack of None/int def __init__(self): # type: () -> None @@ -87,7 +87,7 @@ class Indents(object): return len(self.values) -class Emitter(object): +class Emitter: # fmt: off DEFAULT_TAG_PREFIXES = { '!': '!', @@ -905,7 +905,12 @@ class Emitter(object): # comment following a folded scalar must dedent (issue 376) self.event.comment[0].column = self.indent - 1 elif self.style == '|': - self.write_literal(self.analysis.scalar, self.event.comment) + # self.write_literal(self.analysis.scalar, self.event.comment) + try: + cmx = self.event.comment[1][0] + except (IndexError, TypeError): + cmx = "" + self.write_literal(self.analysis.scalar, cmx) if ( self.event.comment and self.event.comment[0] @@ -1557,13 +1562,21 @@ class Emitter(object): def write_literal(self, text, comment=None): # type: (Any, Any) -> None hints, _indent, _indicator = self.determine_block_hints(text) - self.write_indicator('|' + hints, True) - try: - comment = comment[1][0] - if comment: - self.stream.write(comment) - except (TypeError, IndexError): - pass + #if comment is not None: + # try: + # hints += comment[1][0] + # except (TypeError, IndexError) as e: + # pass + if not isinstance(comment, str): + comment = '' + self.write_indicator('|' + hints + comment, True) + #try: + # nprintf('selfev', comment) + # cmx = comment[1][0] + # if cmx: + # self.stream.write(cmx) + #except (TypeError, IndexError) as e: + # pass if _indicator == '+': self.open_ended = True self.write_line_break() diff --git a/error.py b/error.py index 04c4c24..30b114a 100644 --- a/error.py +++ b/error.py @@ -22,7 +22,7 @@ __all__ = [ ] -class StreamMark(object): +class StreamMark: __slots__ = 'name', 'index', 'line', 'column' def __init__(self, name, index, line, column): @@ -128,7 +128,7 @@ class StringMark(StreamMark): return where -class CommentMark(object): +class CommentMark: __slots__ = ('column',) def __init__(self, column): diff --git a/events.py b/events.py index 0e44d8d..ef63dad 100644 --- a/events.py +++ b/events.py @@ -13,7 +13,7 @@ def CommentCheck(): pass -class Event(object): +class Event: __slots__ = 'start_mark', 'end_mark', 'comment' def __init__(self, start_mark=None, end_mark=None, comment=CommentCheck): @@ -27,18 +27,30 @@ class Event(object): def __repr__(self): # type: () -> Any - attributes = [ - key - for key in ['anchor', 'tag', 'implicit', 'value', 'flow_style', 'style'] - if hasattr(self, key) - ] - arguments = ', '.join( - [_F('{key!s}={attr!r}', key=key, attr=getattr(self, key)) for key in attributes] - ) - if self.comment not in [None, CommentCheck]: - arguments += ', comment={!r}'.format(self.comment) + if True: + arguments = [] + if hasattr(self, 'value'): + arguments.append(repr(getattr(self, 'value'))) + for key in ['anchor', 'tag', 'implicit', 'flow_style', 'style']: + v = getattr(self, key, None) + if v is not None: + arguments.append(_F('{key!s}={v!r}', key=key, v=v)) + if self.comment not in [None, CommentCheck]: + arguments.append('comment={!r}'.format(self.comment)) + arguments = ', '.join(arguments) + else: + attributes = [ + key + for key in ['anchor', 'tag', 'implicit', 'value', 'flow_style', 'style'] + if hasattr(self, key) + ] + arguments = ', '.join( + [_F('{key!s}={attr!r}', key=key, attr=getattr(self, key)) for key in attributes] + ) + if self.comment not in [None, CommentCheck]: + arguments += ', comment={!r}'.format(self.comment) return _F( - '{self_class_name!s}{arguments!s}', + '{self_class_name!s}({arguments!s})', self_class_name=self.__class__.__name__, arguments=arguments, ) diff --git a/main.py b/main.py index efde0e1..7d2f177 100644 --- a/main.py +++ b/main.py @@ -16,7 +16,7 @@ from ruamel.yaml.nodes import * # NOQA from ruamel.yaml.loader import BaseLoader, SafeLoader, Loader, RoundTripLoader # NOQA from ruamel.yaml.dumper import BaseDumper, SafeDumper, Dumper, RoundTripDumper # NOQA -from ruamel.yaml.compat import StringIO, BytesIO, with_metaclass, nprint +from ruamel.yaml.compat import StringIO, BytesIO, with_metaclass, nprint, nprintf from ruamel.yaml.resolver import VersionedResolver, Resolver # NOQA from ruamel.yaml.representer import ( BaseRepresenter, @@ -49,7 +49,7 @@ except: # NOQA # subset of abbreviations, which should be all caps according to PEP8 -class YAML(object): +class YAML: def __init__(self, *, typ=None, pure=False, output=None, plug_ins=None): # input=None, # type: (Any, Optional[Text], Any, Any, Any) -> None """ @@ -825,7 +825,7 @@ class YAML(object): self.compact_seq_map = seq_map -class YAMLContextManager(object): +class YAMLContextManager: def __init__(self, yaml, transform=None): # type: (Any, Any) -> None # used to be: (Any, Optional[Callable]) -> None self._yaml = yaml diff --git a/nodes.py b/nodes.py index f51f989..0efe3ff 100644 --- a/nodes.py +++ b/nodes.py @@ -8,7 +8,7 @@ if False: # MYPY from typing import Dict, Any, Text # NOQA -class Node(object): +class Node: __slots__ = 'tag', 'value', 'start_mark', 'end_mark', 'comment', 'anchor' def __init__(self, tag, value, start_mark, end_mark, comment=None, anchor=None): diff --git a/parser.py b/parser.py index 76c089b..279fc20 100644 --- a/parser.py +++ b/parser.py @@ -90,7 +90,7 @@ class ParserError(MarkedYAMLError): pass -class Parser(object): +class Parser: # Since writing a recursive-descendant parser is a straightforward task, we # do not give many comments here. @@ -171,7 +171,7 @@ class Parser(object): # type: () -> Any # Parse the stream start. token = self.scanner.get_token() - token.move_comment(self.scanner.peek_token()) + self.move_token_comment(token) event = StreamStartEvent(token.start_mark, token.end_mark, encoding=token.encoding) # Prepare the next state. @@ -357,7 +357,7 @@ class Parser(object): start_mark = end_mark = tag_mark = None if self.scanner.check_token(AnchorToken): token = self.scanner.get_token() - token.move_comment(self.scanner.peek_token()) + self.move_token_comment(token) start_mark = token.start_mark end_mark = token.end_mark anchor = token.value @@ -467,7 +467,7 @@ class Parser(object): comment = pt.comment # nprint('pt0', type(pt)) if comment is None or comment[1] is None: - comment = pt.split_comment() + comment = pt.split_old_comment() # nprint('pt1', comment) event = SequenceStartEvent( anchor, tag, implicit, start_mark, end_mark, flow_style=False, comment=comment @@ -506,7 +506,7 @@ class Parser(object): # type: () -> Any token = self.scanner.get_token() # move any comment from start token - # token.move_comment(self.scanner.peek_token()) + # self.move_token_comment(token) self.marks.append(token.start_mark) return self.parse_block_sequence_entry() @@ -514,7 +514,7 @@ class Parser(object): # type: () -> Any if self.scanner.check_token(BlockEntryToken): token = self.scanner.get_token() - token.move_comment(self.scanner.peek_token()) + self.move_token_comment(token) if not self.scanner.check_token(BlockEntryToken, BlockEndToken): self.states.append(self.parse_block_sequence_entry) return self.parse_block_node() @@ -546,7 +546,7 @@ class Parser(object): # type: () -> Any if self.scanner.check_token(BlockEntryToken): token = self.scanner.get_token() - token.move_comment(self.scanner.peek_token()) + self.move_token_comment(token) if not self.scanner.check_token( BlockEntryToken, KeyToken, ValueToken, BlockEndToken ): @@ -575,7 +575,7 @@ class Parser(object): # type: () -> Any if self.scanner.check_token(KeyToken): token = self.scanner.get_token() - token.move_comment(self.scanner.peek_token()) + self.move_token_comment(token) if not self.scanner.check_token(KeyToken, ValueToken, BlockEndToken): self.states.append(self.parse_block_mapping_value) return self.parse_block_node_or_indentless_sequence() @@ -594,7 +594,7 @@ class Parser(object): token.start_mark, ) token = self.scanner.get_token() - token.move_comment(self.scanner.peek_token()) + self.move_token_comment(token) event = MappingEndEvent(token.start_mark, token.end_mark, comment=token.comment) self.state = self.states.pop() self.marks.pop() @@ -606,10 +606,10 @@ class Parser(object): token = self.scanner.get_token() # value token might have post comment move it to e.g. block if self.scanner.check_token(ValueToken): - token.move_comment(self.scanner.peek_token()) + self.move_token_comment(token) else: if not self.scanner.check_token(KeyToken): - token.move_comment(self.scanner.peek_token(), empty=True) + self.move_token_comment(token, empty=True) # else: empty value for this key cannot move token.comment if not self.scanner.check_token(KeyToken, ValueToken, BlockEndToken): self.states.append(self.parse_block_mapping_key) @@ -782,6 +782,11 @@ class Parser(object): # type: (Any, Any) -> Any return ScalarEvent(None, None, (True, False), "", mark, mark, comment=comment) + def move_token_comment(self, token, nt=None, empty=False): + if getattr(self.loader, 'comment_handling', None) is None: # pre 0.18 + token.move_old_comment(self.scanner.peek_token() if nt is None else nt, empty=empty) + else: + token.move_new_comment(self.scanner.peek_token() if nt is None else nt, empty=empty) class RoundTripParser(Parser): """roundtrip is a safe loader, that wants to see the unmangled tag""" diff --git a/reader.py b/reader.py index 3a1656a..ff62135 100644 --- a/reader.py +++ b/reader.py @@ -65,7 +65,7 @@ class ReaderError(YAMLError): ) -class Reader(object): +class Reader: # Reader: # - determines the data encoding and converts it to a unicode string, # - checks if characters are in allowed range, diff --git a/representer.py b/representer.py index 32e6f58..f3e3e43 100644 --- a/representer.py +++ b/representer.py @@ -47,7 +47,7 @@ class RepresenterError(YAMLError): pass -class BaseRepresenter(object): +class BaseRepresenter: yaml_representers = {} # type: Dict[Any, Any] yaml_multi_representers = {} # type: Dict[Any, Any] diff --git a/resolver.py b/resolver.py index eab6163..a6c97df 100644 --- a/resolver.py +++ b/resolver.py @@ -101,7 +101,7 @@ class ResolverError(YAMLError): pass -class BaseResolver(object): +class BaseResolver: DEFAULT_SCALAR_TAG = 'tag:yaml.org,2002:str' DEFAULT_SEQUENCE_TAG = 'tag:yaml.org,2002:seq' diff --git a/scanner.py b/scanner.py index 547af3c..f98da00 100644 --- a/scanner.py +++ b/scanner.py @@ -28,9 +28,10 @@ # Read comments in the Scanner code for more details. # -from ruamel.yaml.error import MarkedYAMLError +import inspect +from ruamel.yaml.error import MarkedYAMLError, CommentMark from ruamel.yaml.tokens import * # NOQA -from ruamel.yaml.compat import _F, check_anchorname_char, nprint # NOQA +from ruamel.yaml.compat import _F, check_anchorname_char, nprint, nprintf # NOQA if False: # MYPY from typing import Any, Dict, Optional, List, Union, Text # NOQA @@ -48,7 +49,7 @@ class ScannerError(MarkedYAMLError): pass -class SimpleKey(object): +class SimpleKey: # See below simple keys treatment. def __init__(self, token_number, required, index, line, column, mark): @@ -61,7 +62,7 @@ class SimpleKey(object): self.mark = mark -class Scanner(object): +class Scanner: def __init__(self, loader=None): # type: (Any) -> None """Initialize the scanner.""" @@ -1972,10 +1973,3 @@ class RoundTripScanner(Scanner): def scan_block_scalar(self, style, rt=True): # type: (Any, Optional[bool]) -> Any return Scanner.scan_block_scalar(self, style, rt=rt) - - -# try: -# import psyco -# psyco.bind(Scanner) -# except ImportError: -# pass diff --git a/serializer.py b/serializer.py index 19b0424..1a78829 100644 --- a/serializer.py +++ b/serializer.py @@ -29,7 +29,7 @@ class SerializerError(YAMLError): pass -class Serializer(object): +class Serializer: # 'id' and 3+ numbers, but not 000 ANCHOR_TEMPLATE = 'id%03d' diff --git a/tokens.py b/tokens.py index 19a2572..490866b 100644 --- a/tokens.py +++ b/tokens.py @@ -6,10 +6,10 @@ if False: # MYPY from typing import Text, Any, Dict, Optional, List # NOQA from .error import StreamMark # NOQA -SHOWLINES = True +SHOW_LINES = True -class Token(object): +class Token: __slots__ = 'start_mark', 'end_mark', '_comment' def __init__(self, start_mark, end_mark): @@ -23,19 +23,20 @@ class Token(object): # hasattr('self', key)] attributes = [key for key in self.__slots__ if not key.endswith('_mark')] attributes.sort() - arguments = ', '.join( - [_F('{key!s}={gattr!r})', key=key, gattr=getattr(self, key)) for key in attributes] - ) - if SHOWLINES: + #arguments = ', '.join( + # [_F('{key!s}={gattr!r})', key=key, gattr=getattr(self, key)) for key in attributes] + #) + arguments = [_F('{key!s}={gattr!r}', key=key, gattr=getattr(self, key)) for key in attributes] + if SHOW_LINES: try: - arguments += ', line: ' + str(self.start_mark.line) + arguments.append('line: ' + str(self.start_mark.line)) except: # NOQA pass try: - arguments += ', comment: ' + str(self._comment) + arguments.append('comment: ' + str(self._comment)) except: # NOQA pass - return '{}({})'.format(self.__class__.__name__, arguments) + return '{}({})'.format(self.__class__.__name__, ', '.join(arguments)) @property def column(self): @@ -45,29 +46,77 @@ class Token(object): def column(self, pos): self.start_mark.column = pos + # old style ( <= 0.17) is a TWO element list with first being the EOL + # comment concatenated with following FLC/BLNK; and second being a list of FLC/BLNK + # preceding the token + # new style ( >= 0.17 ) is a THREE element list with the first being a list of + # preceding FLC/BLNK, the second EOL and the third following FLC/BLNK + # note that new style has differing order, and does not consist of CommentToken(s) + # but of CommentInfo instances + # any non-assigned values in new style are None, but first and last can be empty list + # new style routines add one comment at a time + + # going to be deprecated in favour of add_comment_eol/post def add_post_comment(self, comment): # type: (Any) -> None if not hasattr(self, '_comment'): self._comment = [None, None] + else: + assert len(self._comment) == 2 # make sure it is version 0 + #if isinstance(comment, CommentToken): + # if comment.value.startswith('# C09'): + # raise self._comment[0] = comment + # going to be deprecated in favour of add_comment_pre def add_pre_comments(self, comments): # type: (Any) -> None if not hasattr(self, '_comment'): self._comment = [None, None] + else: + assert len(self._comment) == 2 # make sure it is version 0 assert self._comment[1] is None self._comment[1] = comments + return - def get_comment(self): - # type: () -> Any - return getattr(self, '_comment', None) + # new style + def add_comment_pre(self, comment): + if not hasattr(self, '_comment'): + self._comment = [[], None, None] + else: + assert len(self._comment) == 3 + if self._comment[0] is None: + self._comment[0] = [] + self._comment[0].append(comment) + + def add_comment_eol(self, comment): + if not hasattr(self, '_comment'): + self._comment = [None, None, None] + else: + assert len(self._comment) == 3 + assert self._comment[1] is None + self._comment[1] = comment + + def add_comment_post(self, comment): + if not hasattr(self, '_comment'): + self._comment = [None, None, []] + else: + assert len(self._comment) == 3 + if self._comment[2] is None: + self._comment[2] = [] + self._comment[2].append(comment) + + + #def get_comment(self): + # # type: () -> Any + # return getattr(self, '_comment', None) @property def comment(self): # type: () -> Any return getattr(self, '_comment', None) - def move_comment(self, target, empty=False): + def move_old_comment(self, target, empty=False): # type: (Any, bool) -> Any """move a comment from this token to target (normally next token) used to combine e.g. comments before a BlockEntryToken to the @@ -97,7 +146,7 @@ class Token(object): tc[1] = c[1] return self - def split_comment(self): + def split_old_comment(self): # type: () -> Any """ split the post part of a comment, and return it as comment to be added. Delete second part if [None, None] @@ -113,6 +162,40 @@ class Token(object): delattr(self, '_comment') return ret_val + def move_new_comment(self, target, empty=False): + # type: (Any, bool) -> Any + """move a comment from this token to target (normally next token) + used to combine e.g. comments before a BlockEntryToken to the + ScalarToken that follows it + empty is a special for empty values -> comment after key + """ + c = self.comment + if c is None: + return + # don't push beyond last element + if isinstance(target, (StreamEndToken, DocumentStartToken)): + return + delattr(self, '_comment') + tc = target.comment + if not tc: # target comment, just insert + # special for empty value in key: value issue 25 + if empty: + c = [c[0], c[1], c[2]] + target._comment = c + # nprint('mco2:', self, target, target.comment, empty) + return self + return + raise NotImplemtedError + # if self and target have both pre, eol or post comments, something seems wrong + for idx in range(3): + if c[idx] and tc[idx]: + raise NotImplementedError(_F('overlap in comment {c!r} {tc!r}', c=c, tc=tc)) + # move the comment parts + for idx in range(3): + if c[idx]: + tc[idx] = c[idx] + return self + # class BOMToken(Token): # id = '' @@ -256,13 +339,26 @@ class ScalarToken(Token): class CommentToken(Token): - __slots__ = 'value', 'pre_done' + __slots__ = '_value', 'pre_done' id = '' - def __init__(self, value, start_mark, end_mark): + def __init__(self, value, start_mark=None, end_mark=None, column=None): # type: (Any, Any, Any) -> None - Token.__init__(self, start_mark, end_mark) - self.value = value + if start_mark is None: + assert columns is not None + self._column = column + Token.__init__(self, start_mark, None) + self._value = value + + @property + def value(self): + if isinstance(self._value, str): + return self._value + return "".join(self._value) + + @value.setter + def value(self, val): + self._value = val def reset(self): # type: () -> None @@ -272,7 +368,7 @@ class CommentToken(Token): def __repr__(self): # type: () -> Any v = '{!r}'.format(self.value) - if SHOWLINES: + if SHOW_LINES: try: v += ', line: ' + str(self.start_mark.line) except: # NOQA diff --git a/util.py b/util.py index 1f0b71b..869aaef 100644 --- a/util.py +++ b/util.py @@ -13,7 +13,7 @@ if False: # MYPY from .compat import StreamTextType # NOQA -class LazyEval(object): +class LazyEval: """ Lightweight wrapper around lazily evaluated func(*args, **kwargs). -- cgit v1.2.1