From e73562c6f14d1d71a9fea174d58465e1b13f68af Mon Sep 17 00:00:00 2001 From: Anthon van der Neut Date: Tue, 9 Mar 2021 09:02:50 +0100 Subject: remove python 2 specific code add future deprecation warning to old style functions --- README.rst | 13 + __init__.py | 13 +- _doc/conf.py | 16 +- _test/data/construct-python-str-utf8-py2.code | 2 +- _test/data/construct-python-unicode-utf8-py2.code | 2 +- _test/data/construct-str-utf8-py2.code | 2 +- _test/lib/canonical.py | 112 +++-- _test/lib/test_appliance.py | 22 +- _test/lib/test_canonical.py | 3 +- _test/lib/test_constructor.py | 14 +- _test/lib/test_errors.py | 15 +- _test/lib/test_input_output.py | 296 ++++--------- _test/lib/test_mark.py | 7 +- _test/lib/test_reader.py | 13 +- _test/lib/test_recursive.py | 15 +- _test/lib/test_representer.py | 5 +- _test/lib/test_resolver.py | 15 +- _test/lib/test_structure.py | 72 ++-- _test/lib/test_tokens.py | 5 +- _test/lib/test_yaml_ext.py | 27 +- _test/roundtrip.py | 93 ++-- _test/test_a_dedent.py | 1 + _test/test_add_xxx.py | 68 +-- _test/test_anchor.py | 70 ++- _test/test_api_change.py | 12 +- _test/test_class_register.py | 8 +- _test/test_collections.py | 3 +- _test/test_comment_manipulation.py | 2 - _test/test_comments.py | 16 +- _test/test_contextmanager.py | 2 - _test/test_cyaml.py | 29 +- _test/test_deprecation.py | 2 - _test/test_documents.py | 8 +- _test/test_float.py | 2 - _test/test_indentation.py | 23 +- _test/test_int.py | 2 - _test/test_issues.py | 43 +- _test/test_json_numbers.py | 5 +- _test/test_literal.py | 6 +- _test/test_none.py | 32 +- _test/test_numpy.py | 2 - _test/test_program_config.py | 1 + _test/test_spec_examples.py | 1 + _test/test_string.py | 2 - _test/test_tag.py | 4 +- _test/test_version.py | 4 +- _test/test_yamlfile.py | 26 +- _test/test_yamlobject.py | 8 +- _test/test_z_data.py | 13 +- _test/test_z_olddata.py | 2 - anchor.py | 1 + comments.py | 89 +--- compat.py | 99 +---- composer.py | 17 +- constructor.py | 502 +++++++++++----------- cyaml.py | 2 - dumper.py | 2 - emitter.py | 380 ++++++++-------- error.py | 24 +- events.py | 12 +- loader.py | 3 - main.py | 92 ++-- nodes.py | 18 +- parser.py | 66 +-- reader.py | 77 ++-- representer.py | 358 +++++---------- resolver.py | 102 ++--- scalarbool.py | 4 - scalarfloat.py | 3 - scalarint.py | 7 +- scalarstring.py | 16 +- scanner.py | 95 ++-- serializer.py | 10 +- timestamp.py | 3 - tokens.py | 9 +- util.py | 32 +- 76 files changed, 1369 insertions(+), 1813 deletions(-) diff --git a/README.rst b/README.rst index 0adfa00..4178078 100644 --- a/README.rst +++ b/README.rst @@ -61,6 +61,19 @@ ChangeLog .. should insert NEXT: at the beginning of line for next key (with empty line) +NEXT: + - this release no longer supports Python 2.7, most if not all Python 2 + specific code is removed. The 0.17.x series is the last to support Python 3.5 + - remove Python2 specific code branches and adaptations (u-strings) + - prepare % code for f-strings using _F + - allow PyOxidisation (`issue 324 `__ + resp. `issue 171 https://github.com/indygreg/PyOxidizer/issues/171>`__) + - replaced Python 2 compatible enforcement of keyword arguments with '*' + - the old top level *functions* `load`, `safe_load`, `round_trip_load`, + `dump`, `safe_dump`, `round_trip_dump`, as well as their `_all` variants for + multi-document streams, now issue a `PendingDeprecationWarning` (e.g. when + run from pytest, but also Python is started with `-Wd`) + 0.16.13 (2021-03-05): - fix for issue 359: could not update() CommentedMap with keyword arguments (reported by `Steve Franchak `__) diff --git a/__init__.py b/__init__.py index 7964157..816eaa3 100644 --- a/__init__.py +++ b/__init__.py @@ -1,14 +1,12 @@ # coding: utf-8 -from __future__ import print_function, absolute_import, division, unicode_literals - if False: # MYPY from typing import Dict, Any # NOQA _package_data = dict( full_package_name='ruamel.yaml', - version_info=(0, 16, 13), - __version__='0.16.13', + version_info=(0, 17, 0, 'dev'), + __version__='0.17.0.dev', author='Anthon van der Neut', author_email='a.van.der.neut@ruamel.eu', description='ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order', # NOQA @@ -21,23 +19,20 @@ _package_data = dict( 'docs': ['ryd'], }, classifiers=[ - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy', - 'Programming Language :: Python :: Implementation :: Jython', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Text Processing :: Markup', 'Typing :: Typed', ], keywords='yaml 1.2 parser round-trip preserve quotes order config', read_the_docs='yaml', - supported=[(2, 7), (3, 5)], # minimum + supported=[(3, 5)], # minimum tox=dict( - env='*', # remove 'pn', no longer test narrow Python 2.7 for unicode patterns and PyPy + env='*f', # f for 3.5 deps='ruamel.std.pathlib', fl8excl='_test/lib', ), diff --git a/_doc/conf.py b/_doc/conf.py index 30a76f5..45869b1 100644 --- a/_doc/conf.py +++ b/_doc/conf.py @@ -45,11 +45,11 @@ source_suffix = ['.rst'] master_doc = 'index' # General information about the project. -project = u'yaml' -copyright = u'2017-2019, Anthon van der Neut, Ruamel bvba' -author = u'Anthon van der Neut' +project = 'yaml' +copyright = '2017-2021, Anthon van der Neut, Ruamel bvba' +author = 'Anthon van der Neut' -# The version info for the project you're documenting, acts as replacement for +# The version info for the project you are documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # @@ -251,8 +251,8 @@ latex_documents = [ ( master_doc, 'yaml.tex', - u'Python YAML package documentation', - u'Anthon van der Neut', + 'Python YAML package documentation', + 'Anthon van der Neut', 'manual', ) ] @@ -282,7 +282,7 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, 'yaml', u'yaml Documentation', [author], 1)] +man_pages = [(master_doc, 'yaml', 'yaml Documentation', [author], 1)] # If true, show URL addresses after external links. # man_show_urls = False @@ -297,7 +297,7 @@ texinfo_documents = [ ( master_doc, 'yaml', - u'yaml Documentation', + 'yaml Documentation', author, 'yaml', 'One line description of project.', diff --git a/_test/data/construct-python-str-utf8-py2.code b/_test/data/construct-python-str-utf8-py2.code index 47b28ab..6ca7d8f 100644 --- a/_test/data/construct-python-str-utf8-py2.code +++ b/_test/data/construct-python-str-utf8-py2.code @@ -1 +1 @@ -u'\u042d\u0442\u043e \u0443\u043d\u0438\u043a\u043e\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430'.encode('utf-8') +'\u042d\u0442\u043e \u0443\u043d\u0438\u043a\u043e\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430'.encode('utf-8') diff --git a/_test/data/construct-python-unicode-utf8-py2.code b/_test/data/construct-python-unicode-utf8-py2.code index 2793ac7..9f66032 100644 --- a/_test/data/construct-python-unicode-utf8-py2.code +++ b/_test/data/construct-python-unicode-utf8-py2.code @@ -1 +1 @@ -u'\u042d\u0442\u043e \u0443\u043d\u0438\u043a\u043e\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430' +'\u042d\u0442\u043e \u0443\u043d\u0438\u043a\u043e\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430' diff --git a/_test/data/construct-str-utf8-py2.code b/_test/data/construct-str-utf8-py2.code index 2793ac7..9f66032 100644 --- a/_test/data/construct-str-utf8-py2.code +++ b/_test/data/construct-str-utf8-py2.code @@ -1 +1 @@ -u'\u042d\u0442\u043e \u0443\u043d\u0438\u043a\u043e\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430' +'\u042d\u0442\u043e \u0443\u043d\u0438\u043a\u043e\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430' diff --git a/_test/lib/canonical.py b/_test/lib/canonical.py index af2c3cf..1cab1ff 100644 --- a/_test/lib/canonical.py +++ b/_test/lib/canonical.py @@ -3,7 +3,6 @@ import ruamel.yaml from ruamel.yaml.composer import Composer from ruamel.yaml.constructor import Constructor from ruamel.yaml.resolver import Resolver -from ruamel.yaml.compat import unichr, PY3 class CanonicalError(ruamel.yaml.YAMLError): @@ -13,14 +12,11 @@ class CanonicalError(ruamel.yaml.YAMLError): class CanonicalScanner: def __init__(self, data): try: - if PY3: - if isinstance(data, bytes): - data = data.decode('utf-8') - else: - data = unicode(data, 'utf-8') # NOQA + if isinstance(data, bytes): + data = data.decode('utf-8') except UnicodeDecodeError: raise CanonicalError('utf-8 stream is expected') - self.data = data + u'\0' + self.data = data + '\0' self.index = 0 self.tokens = [] self.scanned = False @@ -59,51 +55,51 @@ class CanonicalScanner: while True: self.find_token() ch = self.data[self.index] - if ch == u'\0': + if ch == '\0': self.tokens.append(ruamel.yaml.StreamEndToken(None, None)) break - elif ch == u'%': + elif ch == '%': self.tokens.append(self.scan_directive()) - elif ch == u'-' and self.data[self.index : self.index + 3] == u'---': + elif ch == '-' and self.data[self.index : self.index + 3] == '---': self.index += 3 self.tokens.append(ruamel.yaml.DocumentStartToken(None, None)) - elif ch == u'[': + elif ch == '[': self.index += 1 self.tokens.append(ruamel.yaml.FlowSequenceStartToken(None, None)) - elif ch == u'{': + elif ch == '{': self.index += 1 self.tokens.append(ruamel.yaml.FlowMappingStartToken(None, None)) - elif ch == u']': + elif ch == ']': self.index += 1 self.tokens.append(ruamel.yaml.FlowSequenceEndToken(None, None)) - elif ch == u'}': + elif ch == '}': self.index += 1 self.tokens.append(ruamel.yaml.FlowMappingEndToken(None, None)) - elif ch == u'?': + elif ch == '?': self.index += 1 self.tokens.append(ruamel.yaml.KeyToken(None, None)) - elif ch == u':': + elif ch == ':': self.index += 1 self.tokens.append(ruamel.yaml.ValueToken(None, None)) - elif ch == u',': + elif ch == ',': self.index += 1 self.tokens.append(ruamel.yaml.FlowEntryToken(None, None)) - elif ch == u'*' or ch == u'&': + elif ch == '*' or ch == '&': self.tokens.append(self.scan_alias()) - elif ch == u'!': + elif ch == '!': self.tokens.append(self.scan_tag()) - elif ch == u'"': + elif ch == '"': self.tokens.append(self.scan_scalar()) else: raise CanonicalError('invalid token') self.scanned = True - DIRECTIVE = u'%YAML 1.1' + DIRECTIVE = '%YAML 1.1' def scan_directive(self): if ( self.data[self.index : self.index + len(self.DIRECTIVE)] == self.DIRECTIVE - and self.data[self.index + len(self.DIRECTIVE)] in u' \n\0' + and self.data[self.index + len(self.DIRECTIVE)] in ' \n\0' ): self.index += len(self.DIRECTIVE) return ruamel.yaml.DirectiveToken('YAML', (1, 1), None, None) @@ -111,13 +107,13 @@ class CanonicalScanner: raise CanonicalError('invalid directive') def scan_alias(self): - if self.data[self.index] == u'*': + if self.data[self.index] == '*': TokenClass = ruamel.yaml.AliasToken else: TokenClass = ruamel.yaml.AnchorToken self.index += 1 start = self.index - while self.data[self.index] not in u', \n\0': + while self.data[self.index] not in ', \n\0': self.index += 1 value = self.data[start : self.index] return TokenClass(value, None, None) @@ -125,38 +121,38 @@ class CanonicalScanner: def scan_tag(self): self.index += 1 start = self.index - while self.data[self.index] not in u' \n\0': + while self.data[self.index] not in ' \n\0': self.index += 1 value = self.data[start : self.index] if not value: - value = u'!' - elif value[0] == u'!': + value = '!' + elif value[0] == '!': value = 'tag:yaml.org,2002:' + value[1:] - elif value[0] == u'<' and value[-1] == u'>': + elif value[0] == '<' and value[-1] == '>': value = value[1:-1] else: - value = u'!' + value + value = '!' + value return ruamel.yaml.TagToken(value, None, None) QUOTE_CODES = {'x': 2, 'u': 4, 'U': 8} QUOTE_REPLACES = { - u'\\': u'\\', - u'"': u'"', - u' ': u' ', - u'a': u'\x07', - u'b': u'\x08', - u'e': u'\x1B', - u'f': u'\x0C', - u'n': u'\x0A', - u'r': u'\x0D', - u't': u'\x09', - u'v': u'\x0B', - u'N': u'\u0085', - u'L': u'\u2028', - u'P': u'\u2029', - u'_': u'_', - u'0': u'\x00', + '\\': '\\', + '"': '"', + ' ': ' ', + 'a': '\x07', + 'b': '\x08', + 'e': '\x1B', + 'f': '\x0C', + 'n': '\x0A', + 'r': '\x0D', + 't': '\x09', + 'v': '\x0B', + 'N': '\u0085', + 'L': '\u2028', + 'P': '\u2029', + '_': '_', + '0': '\x00', } def scan_scalar(self): @@ -164,32 +160,32 @@ class CanonicalScanner: chunks = [] start = self.index ignore_spaces = False - while self.data[self.index] != u'"': - if self.data[self.index] == u'\\': + while self.data[self.index] != '"': + if self.data[self.index] == '\\': ignore_spaces = False chunks.append(self.data[start : self.index]) self.index += 1 ch = self.data[self.index] self.index += 1 - if ch == u'\n': + if ch == '\n': ignore_spaces = True elif ch in self.QUOTE_CODES: length = self.QUOTE_CODES[ch] code = int(self.data[self.index : self.index + length], 16) - chunks.append(unichr(code)) + chunks.append(chr(code)) self.index += length else: if ch not in self.QUOTE_REPLACES: raise CanonicalError('invalid escape code') chunks.append(self.QUOTE_REPLACES[ch]) start = self.index - elif self.data[self.index] == u'\n': + elif self.data[self.index] == '\n': chunks.append(self.data[start : self.index]) - chunks.append(u' ') + chunks.append(' ') self.index += 1 start = self.index ignore_spaces = True - elif ignore_spaces and self.data[self.index] == u' ': + elif ignore_spaces and self.data[self.index] == ' ': self.index += 1 start = self.index else: @@ -202,12 +198,12 @@ class CanonicalScanner: def find_token(self): found = False while not found: - while self.data[self.index] in u' \t': + while self.data[self.index] in ' \t': self.index += 1 - if self.data[self.index] == u'#': - while self.data[self.index] != u'\n': + if self.data[self.index] == '#': + while self.data[self.index] != '\n': self.index += 1 - if self.data[self.index] == u'\n': + if self.data[self.index] == '\n': self.index += 1 else: found = True @@ -378,7 +374,9 @@ ruamel.yaml.canonical_load = canonical_load def canonical_load_all(stream): - return ruamel.yaml.load_all(stream, Loader=CanonicalLoader) + yaml = ruamel.yaml.YAML(typ='safe', pure=True) + yaml.Loader = CanonicalLoader + return yaml.load_all(stream) ruamel.yaml.canonical_load_all = canonical_load_all diff --git a/_test/lib/test_appliance.py b/_test/lib/test_appliance.py index 137c271..d624ebe 100644 --- a/_test/lib/test_appliance.py +++ b/_test/lib/test_appliance.py @@ -1,13 +1,10 @@ -from __future__ import print_function - import sys import os import types import traceback import pprint import argparse -from ruamel.yaml.compat import PY3 # DATA = 'tests/data' # determine the position of data dynamically relative to program @@ -35,7 +32,8 @@ def find_test_filenames(directory): for filename in os.listdir(directory): if os.path.isfile(os.path.join(directory, filename)): base, ext = os.path.splitext(filename) - if base.endswith('-py2' if PY3 else '-py3'): + # ToDo: remove + if base.endswith('-py2'): continue filenames.setdefault(base, []).append(ext) filenames = sorted(filenames.items()) @@ -105,13 +103,7 @@ def parse_arguments(args): def execute(function, filenames, verbose): - if PY3: - name = function.__name__ - else: - if hasattr(function, 'unittest_name'): - name = function.unittest_name - else: - name = function.func_name + name = function.__name__ if verbose: sys.stdout.write('=' * 75 + '\n') sys.stdout.write('%s(%s)...\n' % (name, ', '.join(filenames))) @@ -164,12 +156,8 @@ def display(results, verbose): for filename in filenames: sys.stdout.write('-' * 75 + '\n') sys.stdout.write('%s:\n' % filename) - if PY3: - with open(filename, 'r', errors='replace') as fp: - data = fp.read() - else: - with open(filename, 'rb') as fp: - data = fp.read() + with open(filename, 'r', errors='replace') as fp: + data = fp.read() sys.stdout.write(data) if data and data[-1] != '\n': sys.stdout.write('\n') diff --git a/_test/lib/test_canonical.py b/_test/lib/test_canonical.py index 48a1764..b5cd14d 100644 --- a/_test/lib/test_canonical.py +++ b/_test/lib/test_canonical.py @@ -1,5 +1,4 @@ -# from __future__ import absolute_import -from __future__ import print_function + import ruamel.yaml import canonical # NOQA diff --git a/_test/lib/test_constructor.py b/_test/lib/test_constructor.py index a66ff1a..738aaec 100644 --- a/_test/lib/test_constructor.py +++ b/_test/lib/test_constructor.py @@ -1,9 +1,6 @@ -from __future__ import absolute_import -from __future__ import print_function import ruamel.yaml import pprint -from ruamel.yaml.compat import PY2 import datetime @@ -211,7 +208,6 @@ def _make_objects(): def __setstate__(self, state): self.baz = state - # if PY3 or PY2: InitArgs = NewArgs InitArgsWithState = NewArgsWithState @@ -291,8 +287,6 @@ def _serialize_value(data): return '{%s}' % ', '.join(items) elif isinstance(data, datetime.datetime): return repr(data.utctimetuple()) - elif PY2 and isinstance(data, unicode): # NOQA - return data.encode('utf-8') elif isinstance(data, float) and data != data: return '?' else: @@ -303,9 +297,11 @@ def test_constructor_types(data_filename, code_filename, verbose=False): _make_objects() native1 = None native2 = None + yaml = ruamel.yaml.YAML(typ='safe', pure=True) + yaml.loader = MyLoader try: with open(data_filename, 'rb') as fp0: - native1 = list(ruamel.yaml.load_all(fp0, Loader=MyLoader)) + native1 = list(yaml.load_all(fp0)) if len(native1) == 1: native1 = native1[0] with open(code_filename, 'rb') as fp0: @@ -337,7 +333,9 @@ def test_roundtrip_data(code_filename, roundtrip_filename, verbose=False): _make_objects() with open(code_filename, 'rb') as fp0: value1 = fp0.read() - native2 = list(ruamel.yaml.load_all(value1, Loader=MyLoader)) + yaml = YAML(typ='safe', pure=True) + yaml.Loader = MyLoader + native2 = list(yaml.load_all(value1)) if len(native2) == 1: native2 = native2[0] try: diff --git a/_test/lib/test_errors.py b/_test/lib/test_errors.py index b43540c..c0fd3df 100644 --- a/_test/lib/test_errors.py +++ b/_test/lib/test_errors.py @@ -1,14 +1,15 @@ -from __future__ import absolute_import -from __future__ import print_function -import ruamel.yaml as yaml +import ruamel.yaml +YAML = ruamel.yaml.YAML + import test_emitter import warnings -warnings.simplefilter('ignore', yaml.error.UnsafeLoaderWarning) +warnings.simplefilter('ignore', ruamel.yaml.error.UnsafeLoaderWarning) def test_loader_error(error_filename, verbose=False): + yaml = YAML(typ='safe', pure=True) try: with open(error_filename, 'rb') as fp0: list(yaml.load_all(fp0)) @@ -23,6 +24,7 @@ test_loader_error.unittest = ['.loader-error'] def test_loader_error_string(error_filename, verbose=False): + yaml = YAML(typ='safe', pure=True) try: with open(error_filename, 'rb') as fp0: list(yaml.load_all(fp0.read())) @@ -37,6 +39,7 @@ test_loader_error_string.unittest = ['.loader-error'] def test_loader_error_single(error_filename, verbose=False): + yaml = YAML(typ='safe', pure=True) try: with open(error_filename, 'rb') as fp0: yaml.load(fp0.read()) @@ -51,10 +54,11 @@ test_loader_error_single.unittest = ['.single-loader-error'] def test_emitter_error(error_filename, verbose=False): + yaml = YAML(typ='safe', pure=True) with open(error_filename, 'rb') as fp0: events = list(yaml.load(fp0, Loader=test_emitter.EventsLoader)) try: - yaml.emit(events) + ruamel.yaml.emit(events) except yaml.YAMLError as exc: if verbose: print('%s:' % exc.__class__.__name__, exc) @@ -66,6 +70,7 @@ test_emitter_error.unittest = ['.emitter-error'] def test_dumper_error(error_filename, verbose=False): + yaml = YAML(typ='safe', pure=True) with open(error_filename, 'rb') as fp0: code = fp0.read() try: diff --git a/_test/lib/test_input_output.py b/_test/lib/test_input_output.py index c36477f..37bda3d 100644 --- a/_test/lib/test_input_output.py +++ b/_test/lib/test_input_output.py @@ -1,79 +1,39 @@ -from __future__ import absolute_import -from __future__ import print_function -import ruamel.yaml as yaml +from ruamel.yaml import YAML import codecs import tempfile import os import os.path -from ruamel.yaml.compat import PY2, PY3, StringIO, BytesIO +from ruamel.yaml.compat import StringIO, BytesIO -if PY2: - - def _unicode_open(file, encoding, errors='strict'): - info = codecs.lookup(encoding) - if isinstance(info, tuple): - reader = info[2] - writer = info[3] - else: - reader = info.streamreader - writer = info.streamwriter - srw = codecs.StreamReaderWriter(file, reader, writer, errors) - srw.encoding = encoding - return srw - - -if PY3: - - def test_unicode_input(unicode_filename, verbose=False): - with open(unicode_filename, 'rb') as fp: - data = fp.read().decode('utf-8') - value = ' '.join(data.split()) - output = yaml.load(data) - assert output == value, (output, value) - output = yaml.load(StringIO(data)) +def test_unicode_input(unicode_filename, verbose=False): + yaml = YAML(typ='safe', pure=True) + with open(unicode_filename, 'rb') as fp: + data = fp.read().decode('utf-8') + value = ' '.join(data.split()) + output = yaml.load(data) + assert output == value, (output, value) + output = yaml.load(StringIO(data)) + assert output == value, (output, value) + for input in [ + data.encode('utf-8'), + codecs.BOM_UTF8 + data.encode('utf-8'), + codecs.BOM_UTF16_BE + data.encode('utf-16-be'), + codecs.BOM_UTF16_LE + data.encode('utf-16-le'), + ]: + if verbose: + print('INPUT:', repr(input[:10]), '...') + output = yaml.load(input) assert output == value, (output, value) - for input in [ - data.encode('utf-8'), - codecs.BOM_UTF8 + data.encode('utf-8'), - codecs.BOM_UTF16_BE + data.encode('utf-16-be'), - codecs.BOM_UTF16_LE + data.encode('utf-16-le'), - ]: - if verbose: - print('INPUT:', repr(input[:10]), '...') - output = yaml.load(input) - assert output == value, (output, value) - output = yaml.load(BytesIO(input)) - assert output == value, (output, value) - - -else: - - def test_unicode_input(unicode_filename, verbose=False): - with open(unicode_filename, 'rb') as fp: - data = fp.read().decode('utf-8') - value = ' '.join(data.split()) - output = yaml.load(_unicode_open(StringIO(data.encode('utf-8')), 'utf-8')) + output = yaml.load(BytesIO(input)) assert output == value, (output, value) - for input in [ - data, - data.encode('utf-8'), - codecs.BOM_UTF8 + data.encode('utf-8'), - codecs.BOM_UTF16_BE + data.encode('utf-16-be'), - codecs.BOM_UTF16_LE + data.encode('utf-16-le'), - ]: - if verbose: - print('INPUT:', repr(input[:10]), '...') - output = yaml.load(input) - assert output == value, (output, value) - output = yaml.load(StringIO(input)) - assert output == value, (output, value) test_unicode_input.unittest = ['.unicode'] def test_unicode_input_errors(unicode_filename, verbose=False): + yaml = YAML(typ='safe', pure=True) with open(unicode_filename, 'rb') as fp: data = fp.read().decode('utf-8') for input in [ @@ -92,7 +52,7 @@ def test_unicode_input_errors(unicode_filename, verbose=False): else: raise AssertionError('expected an exception') try: - yaml.load(BytesIO(input) if PY3 else StringIO(input)) + yaml.load(BytesIO(input)) except yaml.YAMLError as exc: if verbose: print(exc) @@ -102,108 +62,63 @@ def test_unicode_input_errors(unicode_filename, verbose=False): test_unicode_input_errors.unittest = ['.unicode'] -if PY3: - def test_unicode_output(unicode_filename, verbose=False): - with open(unicode_filename, 'rb') as fp: - data = fp.read().decode('utf-8') - value = ' '.join(data.split()) - for allow_unicode in [False, True]: - data1 = yaml.dump(value, allow_unicode=allow_unicode) - for encoding in [None, 'utf-8', 'utf-16-be', 'utf-16-le']: - stream = StringIO() +def test_unicode_output(unicode_filename, verbose=False): + yaml = YAML(typ='safe', pure=True) + with open(unicode_filename, 'rb') as fp: + data = fp.read().decode('utf-8') + value = ' '.join(data.split()) + for allow_unicode in [False, True]: + data1 = yaml.dump(value, allow_unicode=allow_unicode) + for encoding in [None, 'utf-8', 'utf-16-be', 'utf-16-le']: + stream = StringIO() + yaml.dump(value, stream, encoding=encoding, allow_unicode=allow_unicode) + data2 = stream.getvalue() + data3 = yaml.dump(value, encoding=encoding, allow_unicode=allow_unicode) + if encoding is not None: + assert isinstance(data3, bytes) + data3 = data3.decode(encoding) + stream = BytesIO() + if encoding is None: + try: + yaml.dump( + value, stream, encoding=encoding, allow_unicode=allow_unicode + ) + except TypeError as exc: + if verbose: + print(exc) + data4 = None + else: + raise AssertionError('expected an exception') + else: yaml.dump(value, stream, encoding=encoding, allow_unicode=allow_unicode) - data2 = stream.getvalue() - data3 = yaml.dump(value, encoding=encoding, allow_unicode=allow_unicode) - if encoding is not None: - assert isinstance(data3, bytes) - data3 = data3.decode(encoding) - stream = BytesIO() - if encoding is None: + data4 = stream.getvalue() + if verbose: + print('BYTES:', data4[:50]) + data4 = data4.decode(encoding) + for copy in [data1, data2, data3, data4]: + if copy is None: + continue + assert isinstance(copy, str) + if allow_unicode: try: - yaml.dump( - value, stream, encoding=encoding, allow_unicode=allow_unicode - ) - except TypeError as exc: + copy[4:].encode('ascii') + except UnicodeEncodeError as exc: if verbose: print(exc) - data4 = None else: raise AssertionError('expected an exception') else: - yaml.dump(value, stream, encoding=encoding, allow_unicode=allow_unicode) - data4 = stream.getvalue() - if verbose: - print('BYTES:', data4[:50]) - data4 = data4.decode(encoding) - for copy in [data1, data2, data3, data4]: - if copy is None: - continue - assert isinstance(copy, str) - if allow_unicode: - try: - copy[4:].encode('ascii') - except UnicodeEncodeError as exc: - if verbose: - print(exc) - else: - raise AssertionError('expected an exception') - else: - copy[4:].encode('ascii') - assert isinstance(data1, str), (type(data1), encoding) - assert isinstance(data2, str), (type(data2), encoding) - - -else: - - def test_unicode_output(unicode_filename, verbose=False): - with open(unicode_filename, 'rb') as fp: - data = fp.read().decode('utf-8') - value = ' '.join(data.split()) - for allow_unicode in [False, True]: - data1 = yaml.dump(value, allow_unicode=allow_unicode) - for encoding in [None, 'utf-8', 'utf-16-be', 'utf-16-le']: - stream = StringIO() - yaml.dump( - value, - _unicode_open(stream, 'utf-8'), - encoding=encoding, - allow_unicode=allow_unicode, - ) - data2 = stream.getvalue() - data3 = yaml.dump(value, encoding=encoding, allow_unicode=allow_unicode) - stream = StringIO() - yaml.dump(value, stream, encoding=encoding, allow_unicode=allow_unicode) - data4 = stream.getvalue() - for copy in [data1, data2, data3, data4]: - if allow_unicode: - try: - copy[4:].encode('ascii') - except (UnicodeDecodeError, UnicodeEncodeError) as exc: - if verbose: - print(exc) - else: - raise AssertionError('expected an exception') - else: - copy[4:].encode('ascii') - assert isinstance(data1, str), (type(data1), encoding) - data1.decode('utf-8') - assert isinstance(data2, str), (type(data2), encoding) - data2.decode('utf-8') - if encoding is None: - assert isinstance(data3, unicode), (type(data3), encoding) # NOQA - assert isinstance(data4, unicode), (type(data4), encoding) # NOQA - else: - assert isinstance(data3, str), (type(data3), encoding) - data3.decode(encoding) - assert isinstance(data4, str), (type(data4), encoding) - data4.decode(encoding) + copy[4:].encode('ascii') + assert isinstance(data1, str), (type(data1), encoding) + assert isinstance(data2, str), (type(data2), encoding) test_unicode_output.unittest = ['.unicode'] def test_file_output(unicode_filename, verbose=False): + yaml = YAML(typ='safe', pure=True) with open(unicode_filename, 'rb') as fp: data = fp.read().decode('utf-8') handle, filename = tempfile.mkstemp() @@ -212,32 +127,17 @@ def test_file_output(unicode_filename, verbose=False): stream = StringIO() yaml.dump(data, stream, allow_unicode=True) data1 = stream.getvalue() - if PY3: - stream = BytesIO() - yaml.dump(data, stream, encoding='utf-16-le', allow_unicode=True) - data2 = stream.getvalue().decode('utf-16-le')[1:] - with open(filename, 'w', encoding='utf-16-le') as stream: - yaml.dump(data, stream, allow_unicode=True) - with open(filename, 'r', encoding='utf-16-le') as fp0: - data3 = fp0.read() - with open(filename, 'wb') as stream: - yaml.dump(data, stream, encoding='utf-8', allow_unicode=True) - with open(filename, 'r', encoding='utf-8') as fp0: - data4 = fp0.read() - else: - with open(filename, 'wb') as stream: - yaml.dump(data, stream, allow_unicode=True) - with open(filename, 'rb') as fp0: - data2 = fp0.read() - with open(filename, 'wb') as stream: - yaml.dump(data, stream, encoding='utf-16-le', allow_unicode=True) - with open(filename, 'rb') as fp0: - data3 = fp0.read().decode('utf-16-le')[1:].encode('utf-8') - stream = _unicode_open(open(filename, 'wb'), 'utf-8') + stream = BytesIO() + yaml.dump(data, stream, encoding='utf-16-le', allow_unicode=True) + data2 = stream.getvalue().decode('utf-16-le')[1:] + with open(filename, 'w', encoding='utf-16-le') as stream: yaml.dump(data, stream, allow_unicode=True) - stream.close() - with open(filename, 'rb') as fp0: - data4 = fp0.read() + with open(filename, 'r', encoding='utf-16-le') as fp0: + data3 = fp0.read() + with open(filename, 'wb') as stream: + yaml.dump(data, stream, encoding='utf-8', allow_unicode=True) + with open(filename, 'r', encoding='utf-8') as fp0: + data4 = fp0.read() assert data1 == data2, (data1, data2) assert data1 == data3, (data1, data3) assert data1 == data4, (data1, data4) @@ -250,40 +150,26 @@ test_file_output.unittest = ['.unicode'] def test_unicode_transfer(unicode_filename, verbose=False): + yaml = YAML(typ='safe', pure=True) with open(unicode_filename, 'rb') as fp: data = fp.read().decode('utf-8') for encoding in [None, 'utf-8', 'utf-16-be', 'utf-16-le']: input = data - if PY3: - if encoding is not None: - input = ('\ufeff' + input).encode(encoding) - output1 = yaml.emit(yaml.parse(input), allow_unicode=True) - if encoding is None: - stream = StringIO() - else: - stream = BytesIO() - yaml.emit(yaml.parse(input), stream, allow_unicode=True) - output2 = stream.getvalue() - assert isinstance(output1, str), (type(output1), encoding) - if encoding is None: - assert isinstance(output2, str), (type(output1), encoding) - else: - assert isinstance(output2, bytes), (type(output1), encoding) - output2.decode(encoding) - else: - if encoding is not None: - input = (u'\ufeff' + input).encode(encoding) - output1 = yaml.emit(yaml.parse(input), allow_unicode=True) + if encoding is not None: + input = ('\ufeff' + input).encode(encoding) + output1 = yaml.emit(yaml.parse(input), allow_unicode=True) + if encoding is None: stream = StringIO() - yaml.emit(yaml.parse(input), _unicode_open(stream, 'utf-8'), allow_unicode=True) - output2 = stream.getvalue() - if encoding is None: - assert isinstance(output1, unicode), (type(output1), encoding) # NOQA - else: - assert isinstance(output1, str), (type(output1), encoding) - output1.decode(encoding) - assert isinstance(output2, str), (type(output2), encoding) - output2.decode('utf-8') + else: + stream = BytesIO() + yaml.emit(yaml.parse(input), stream, allow_unicode=True) + output2 = stream.getvalue() + assert isinstance(output1, str), (type(output1), encoding) + if encoding is None: + assert isinstance(output2, str), (type(output1), encoding) + else: + assert isinstance(output2, bytes), (type(output1), encoding) + output2.decode(encoding) test_unicode_transfer.unittest = ['.unicode'] diff --git a/_test/lib/test_mark.py b/_test/lib/test_mark.py index 0ff2789..2644a79 100644 --- a/_test/lib/test_mark.py +++ b/_test/lib/test_mark.py @@ -1,12 +1,9 @@ -from __future__ import absolute_import -from __future__ import print_function import ruamel.yaml as yaml -from ruamel.yaml.compat import text_type, PY3 def test_marks(marks_filename, verbose=False): - with open(marks_filename, 'r' if PY3 else 'rb') as fp0: + with open(marks_filename, 'r') as fp0: inputs = fp0.read().split('---\n')[1:] for input in inputs: index = 0 @@ -19,7 +16,7 @@ def test_marks(marks_filename, verbose=False): else: column += 1 index += 1 - mark = yaml.Mark(marks_filename, index, line, column, text_type(input), index) + mark = yaml.Mark(marks_filename, index, line, column, str(input), index) snippet = mark.get_snippet(indent=2, max_length=79) if verbose: print(snippet) diff --git a/_test/lib/test_reader.py b/_test/lib/test_reader.py index 6604f24..16b9cd7 100644 --- a/_test/lib/test_reader.py +++ b/_test/lib/test_reader.py @@ -1,17 +1,14 @@ -from __future__ import absolute_import -from __future__ import print_function import codecs # NOQA import io -from ruamel.yaml.compat import PY2 import ruamel.yaml.reader def _run_reader(data, verbose): try: stream = ruamel.yaml.py.reader.Reader(data) - while stream.peek() != u'\0': + while stream.peek() != '\0': stream.forward() except ruamel.yaml.py.reader.ReaderError as exc: if verbose: @@ -27,12 +24,8 @@ def test_stream_error(error_filename, verbose=False): _run_reader(fp0.read(), verbose) for encoding in ['utf-8', 'utf-16-le', 'utf-16-be']: try: - if PY2: - with open(error_filename, 'rb') as fp0: - data = unicode(fp0.read(), encoding) # NOQA - else: - with open(error_filename, 'rb') as fp0: - data = fp0.read().decode(encoding) + with open(error_filename, 'rb') as fp0: + data = fp0.read().decode(encoding) break except UnicodeDecodeError: pass diff --git a/_test/lib/test_recursive.py b/_test/lib/test_recursive.py index c87f879..88858e4 100644 --- a/_test/lib/test_recursive.py +++ b/_test/lib/test_recursive.py @@ -1,7 +1,5 @@ -from __future__ import absolute_import -from __future__ import print_function -import ruamel.yaml as yaml +import ruamel.yaml class AnInstance: @@ -25,6 +23,7 @@ class AnInstanceWithState(AnInstance): def test_recursive(recursive_filename, verbose=False): + yaml = ruamel.yaml.YAML(typ='safe', pure=True) context = globals().copy() with open(recursive_filename, 'rb') as fp0: exec(fp0.read(), context) @@ -33,9 +32,13 @@ def test_recursive(recursive_filename, verbose=False): value2 = None output2 = None try: - output1 = yaml.dump(value1) - value2 = yaml.load(output1) - output2 = yaml.dump(value2) + buf = ruamel.yaml.compat.StringIO() + output1 = yaml.dump(value1, buf) + yaml.load(output1) + value2 = buf.getvalue() + buf = ruamel.yaml.compat.StringIO() + yaml.dump(value2, buf) + output2 = buf.getvalue() assert output1 == output2, (output1, output2) finally: if verbose: diff --git a/_test/lib/test_representer.py b/_test/lib/test_representer.py index a83d2b2..5b2415d 100644 --- a/_test/lib/test_representer.py +++ b/_test/lib/test_representer.py @@ -1,12 +1,11 @@ -from __future__ import absolute_import -from __future__ import print_function -import ruamel.yaml as yaml +from ruamel.yaml import YAML import test_constructor import pprint def test_representer_types(code_filename, verbose=False): + yaml = YAML(typ='safe', pure=True) test_constructor._make_objects() for allow_unicode in [False, True]: for encoding in ['utf-8', 'utf-16-be', 'utf-16-le']: diff --git a/_test/lib/test_resolver.py b/_test/lib/test_resolver.py index 0a04e7a..24373a7 100644 --- a/_test/lib/test_resolver.py +++ b/_test/lib/test_resolver.py @@ -1,16 +1,13 @@ -from __future__ import absolute_import -from __future__ import print_function import ruamel.yaml as yaml import pprint -from ruamel.yaml.compat import PY3 def test_implicit_resolver(data_filename, detect_filename, verbose=False): correct_tag = None node = None try: - with open(detect_filename, 'r' if PY3 else 'rb') as fp0: + with open(detect_filename, 'r') as fp0: correct_tag = fp0.read().strip() with open(data_filename, 'rb') as fp0: node = yaml.compose(fp0) @@ -38,14 +35,14 @@ def _make_path_loader_and_dumper(): class MyDumper(yaml.Dumper): pass - yaml.add_path_resolver(u'!root', [], Loader=MyLoader, Dumper=MyDumper) - yaml.add_path_resolver(u'!root/scalar', [], str, Loader=MyLoader, Dumper=MyDumper) + yaml.add_path_resolver('!root', [], Loader=MyLoader, Dumper=MyDumper) + yaml.add_path_resolver('!root/scalar', [], str, Loader=MyLoader, Dumper=MyDumper) yaml.add_path_resolver( - u'!root/key11/key12/*', ['key11', 'key12'], Loader=MyLoader, Dumper=MyDumper + '!root/key11/key12/*', ['key11', 'key12'], Loader=MyLoader, Dumper=MyDumper ) - yaml.add_path_resolver(u'!root/key21/1/*', ['key21', 1], Loader=MyLoader, Dumper=MyDumper) + yaml.add_path_resolver('!root/key21/1/*', ['key21', 1], Loader=MyLoader, Dumper=MyDumper) yaml.add_path_resolver( - u'!root/key31/*/*/key14/map', + '!root/key31/*/*/key14/map', ['key31', None, None, 'key14'], dict, Loader=MyLoader, diff --git a/_test/lib/test_structure.py b/_test/lib/test_structure.py index 2656bbb..470d267 100644 --- a/_test/lib/test_structure.py +++ b/_test/lib/test_structure.py @@ -1,36 +1,33 @@ -from __future__ import absolute_import -from __future__ import print_function -import ruamel.yaml as yaml +import ruamel.yaml import canonical # NOQA import pprint -from ruamel.yaml.compat import text_type, PY3 def _convert_structure(loader): - if loader.check_event(yaml.ScalarEvent): + if loader.check_event(ruamel.yaml.ScalarEvent): event = loader.get_event() if event.tag or event.anchor or event.value: return True else: return None - elif loader.check_event(yaml.SequenceStartEvent): + elif loader.check_event(ruamel.yaml.SequenceStartEvent): loader.get_event() sequence = [] - while not loader.check_event(yaml.SequenceEndEvent): + while not loader.check_event(ruamel.yaml.SequenceEndEvent): sequence.append(_convert_structure(loader)) loader.get_event() return sequence - elif loader.check_event(yaml.MappingStartEvent): + elif loader.check_event(ruamel.yaml.MappingStartEvent): loader.get_event() mapping = [] - while not loader.check_event(yaml.MappingEndEvent): + while not loader.check_event(ruamel.yaml.MappingEndEvent): key = _convert_structure(loader) value = _convert_structure(loader) mapping.append((key, value)) loader.get_event() return mapping - elif loader.check_event(yaml.AliasEvent): + elif loader.check_event(ruamel.yaml.AliasEvent): loader.get_event() return '*' else: @@ -40,17 +37,17 @@ def _convert_structure(loader): def test_structure(data_filename, structure_filename, verbose=False): nodes1 = [] - with open(structure_filename, 'r' if PY3 else 'rb') as fp: + with open(structure_filename, 'r') as fp: nodes2 = eval(fp.read()) try: with open(data_filename, 'rb') as fp: - loader = yaml.Loader(fp) + loader = ruamel.yaml.Loader(fp) while loader.check_event(): if loader.check_event( - yaml.StreamStartEvent, - yaml.StreamEndEvent, - yaml.DocumentStartEvent, - yaml.DocumentEndEvent, + ruamel.yaml.StreamStartEvent, + ruamel.yaml.StreamEndEvent, + ruamel.yaml.DocumentStartEvent, + ruamel.yaml.DocumentEndEvent, ): loader.get_event() continue @@ -73,12 +70,12 @@ def _compare_events(events1, events2, full=False): assert len(events1) == len(events2), (len(events1), len(events2)) for event1, event2 in zip(events1, events2): assert event1.__class__ == event2.__class__, (event1, event2) - if isinstance(event1, yaml.AliasEvent) and full: + if isinstance(event1, ruamel.yaml.AliasEvent) and full: assert event1.anchor == event2.anchor, (event1, event2) - if isinstance(event1, (yaml.ScalarEvent, yaml.CollectionStartEvent)): - if (event1.tag not in [None, u'!'] and event2.tag not in [None, u'!']) or full: + if isinstance(event1, (ruamel.yaml.ScalarEvent, ruamel.yaml.CollectionStartEvent)): + if (event1.tag not in [None, '!'] and event2.tag not in [None, '!']) or full: assert event1.tag == event2.tag, (event1, event2) - if isinstance(event1, yaml.ScalarEvent): + if isinstance(event1, ruamel.yaml.ScalarEvent): assert event1.value == event2.value, (event1, event2) @@ -87,9 +84,9 @@ def test_parser(data_filename, canonical_filename, verbose=False): events2 = None try: with open(data_filename, 'rb') as fp0: - events1 = list(yaml.parse(fp0)) + events1 = list(ruamel.yaml.parse(fp0)) with open(canonical_filename, 'rb') as fp0: - events2 = list(yaml.canonical_parse(fp0)) + events2 = list(ruamel.yaml.canonical_parse(fp0)) _compare_events(events1, events2) finally: if verbose: @@ -107,9 +104,9 @@ def test_parser_on_canonical(canonical_filename, verbose=False): events2 = None try: with open(canonical_filename, 'rb') as fp0: - events1 = list(yaml.parse(fp0)) + events1 = list(ruamel.yaml.parse(fp0)) with open(canonical_filename, 'rb') as fp0: - events2 = list(yaml.canonical_parse(fp0)) + events2 = list(ruamel.yaml.canonical_parse(fp0)) _compare_events(events1, events2, full=True) finally: if verbose: @@ -125,7 +122,7 @@ test_parser_on_canonical.unittest = ['.canonical'] def _compare_nodes(node1, node2): assert node1.__class__ == node2.__class__, (node1, node2) assert node1.tag == node2.tag, (node1, node2) - if isinstance(node1, yaml.ScalarNode): + if isinstance(node1, ruamel.yaml.ScalarNode): assert node1.value == node2.value, (node1, node2) else: assert len(node1.value) == len(node2.value), (node1, node2) @@ -142,9 +139,9 @@ def test_composer(data_filename, canonical_filename, verbose=False): nodes2 = None try: with open(data_filename, 'rb') as fp0: - nodes1 = list(yaml.compose_all(fp0)) + nodes1 = list(ruamel.yaml.compose_all(fp0)) with open(canonical_filename, 'rb') as fp0: - nodes2 = list(yaml.canonical_compose_all(fp0)) + nodes2 = list(ruamel.yaml.canonical_compose_all(fp0)) assert len(nodes1) == len(nodes2), (len(nodes1), len(nodes2)) for node1, node2 in zip(nodes1, nodes2): _compare_nodes(node1, node2) @@ -162,39 +159,39 @@ test_composer.unittest = ['.data', '.canonical'] def _make_loader(): global MyLoader - class MyLoader(yaml.Loader): + class MyLoader(ruamel.yaml.Loader): def construct_sequence(self, node): - return tuple(yaml.Loader.construct_sequence(self, node)) + return tuple(ruamel.yaml.Loader.construct_sequence(self, node)) def construct_mapping(self, node): pairs = self.construct_pairs(node) - pairs.sort(key=(lambda i: text_type(i))) + pairs.sort(key=(lambda i: str(i))) return pairs def construct_undefined(self, node): return self.construct_scalar(node) - MyLoader.add_constructor(u'tag:yaml.org,2002:map', MyLoader.construct_mapping) + MyLoader.add_constructor('tag:yaml.org,2002:map', MyLoader.construct_mapping) MyLoader.add_constructor(None, MyLoader.construct_undefined) def _make_canonical_loader(): global MyCanonicalLoader - class MyCanonicalLoader(yaml.CanonicalLoader): + class MyCanonicalLoader(ruamel.yaml.CanonicalLoader): def construct_sequence(self, node): - return tuple(yaml.CanonicalLoader.construct_sequence(self, node)) + return tuple(ruamel.yaml.CanonicalLoader.construct_sequence(self, node)) def construct_mapping(self, node): pairs = self.construct_pairs(node) - pairs.sort(key=(lambda i: text_type(i))) + pairs.sort(key=(lambda i: str(i))) return pairs def construct_undefined(self, node): return self.construct_scalar(node) MyCanonicalLoader.add_constructor( - u'tag:yaml.org,2002:map', MyCanonicalLoader.construct_mapping + 'tag:yaml.org,2002:map', MyCanonicalLoader.construct_mapping ) MyCanonicalLoader.add_constructor(None, MyCanonicalLoader.construct_undefined) @@ -204,11 +201,12 @@ def test_constructor(data_filename, canonical_filename, verbose=False): _make_canonical_loader() native1 = None native2 = None + yaml = YAML(typ='safe') try: with open(data_filename, 'rb') as fp0: - native1 = list(yaml.load_all(fp0, Loader=MyLoader)) + native1 = list(yaml.load(fp0, Loader=MyLoader)) with open(canonical_filename, 'rb') as fp0: - native2 = list(yaml.load_all(fp0, Loader=MyCanonicalLoader)) + native2 = list(yaml.load(fp0, Loader=MyCanonicalLoader)) assert native1 == native2, (native1, native2) finally: if verbose: diff --git a/_test/lib/test_tokens.py b/_test/lib/test_tokens.py index cdb41ba..1483db8 100644 --- a/_test/lib/test_tokens.py +++ b/_test/lib/test_tokens.py @@ -1,9 +1,6 @@ -from __future__ import absolute_import -from __future__ import print_function import ruamel.yaml as yaml import pprint -from ruamel.yaml.compat import PY3 # Tokens mnemonic: # directive: % @@ -48,7 +45,7 @@ _replaces = { def test_tokens(data_filename, tokens_filename, verbose=False): tokens1 = [] - with open(tokens_filename, 'r' if PY3 else 'rb') as fp: + with open(tokens_filename, 'r') as fp: tokens2 = fp.read().split() try: with open(data_filename, 'rb') as fp1: diff --git a/_test/lib/test_yaml_ext.py b/_test/lib/test_yaml_ext.py index e36ddd0..fd2d4ed 100644 --- a/_test/lib/test_yaml_ext.py +++ b/_test/lib/test_yaml_ext.py @@ -1,13 +1,9 @@ # coding: utf-8 -from __future__ import absolute_import -from __future__ import print_function - import _ruamel_yaml import ruamel.yaml import types import pprint -from ruamel.yaml.compat import PY3 ruamel.yaml.PyBaseLoader = ruamel.yaml.BaseLoader ruamel.yaml.PySafeLoader = ruamel.yaml.SafeLoader @@ -311,9 +307,9 @@ def _compare_emitters(data, verbose): c_value = getattr(c_event, attribute, None) if ( attribute == 'tag' - and value in [None, u'!'] - and py_value in [None, u'!'] - and c_value in [None, u'!'] + and value in [None, '!'] + and py_value in [None, '!'] + and c_value in [None, '!'] ): continue if attribute == 'explicit' and (py_value or c_value): @@ -349,14 +345,7 @@ def wrap_ext_function(function): finally: _tear_down() - if PY3: - wrapper.__name__ = '%s_ext' % function.__name__ - else: - try: - wrapper.__name__ = '%s_ext' % function.__name__ - except TypeError: - pass - wrapper.unittest_name = '%s_ext' % function.__name__ + wrapper.__name__ = '%s_ext' % function.__name__ wrapper.unittest = function.unittest wrapper.skip = getattr(function, 'skip', []) + ['.skip-ext'] return wrapper @@ -374,12 +363,8 @@ def wrap_ext(collections): if isinstance(value, types.FunctionType) and hasattr(value, 'unittest'): functions.append(wrap_ext_function(value)) for function in functions: - if PY3: - assert function.__name__ not in globals() - globals()[function.__name__] = function - else: - assert function.unittest_name not in globals() - globals()[function.unittest_name] = function + assert function.__name__ not in globals() + globals()[function.__name__] = function import test_tokens # NOQA diff --git a/_test/roundtrip.py b/_test/roundtrip.py index af8a555..f8f4b21 100644 --- a/_test/roundtrip.py +++ b/_test/roundtrip.py @@ -1,15 +1,14 @@ # coding: utf-8 -from __future__ import print_function - """ helper routines for testing round trip of commented YAML data """ import sys import textwrap +import io from ruamel.std.pathlib import Path -enforce = object() +unset = object() def dedent(data): @@ -29,50 +28,86 @@ def round_trip_load(inp, preserve_quotes=None, version=None): import ruamel.yaml # NOQA dinp = dedent(inp) - return ruamel.yaml.load( - dinp, - Loader=ruamel.yaml.RoundTripLoader, - preserve_quotes=preserve_quotes, - version=version, - ) + yaml = ruamel.yaml.YAML() + yaml.preserve_quotes = preserve_quotes + yaml.version = version + return yaml.load(dinp) def round_trip_load_all(inp, preserve_quotes=None, version=None): import ruamel.yaml # NOQA dinp = dedent(inp) - return ruamel.yaml.load_all( - dinp, - Loader=ruamel.yaml.RoundTripLoader, - preserve_quotes=preserve_quotes, - version=version, - ) + yaml = ruamel.yaml.YAML() + yaml.preserve_quotes = preserve_quotes + yaml.version = version + return yaml.load_all(dinp) def round_trip_dump( data, - stream=None, + stream=None, *, indent=None, block_seq_indent=None, + default_flow_style=unset, top_level_colon_align=None, prefix_colon=None, explicit_start=None, explicit_end=None, version=None, + allow_unicode=True, ): import ruamel.yaml # NOQA - return ruamel.yaml.round_trip_dump( - data, - stream=stream, - indent=indent, - block_seq_indent=block_seq_indent, - top_level_colon_align=top_level_colon_align, - prefix_colon=prefix_colon, - explicit_start=explicit_start, - explicit_end=explicit_end, - version=version, - ) + yaml = ruamel.yaml.YAML() + yaml.indent(mapping=indent, sequence=indent, offset=block_seq_indent) + if default_flow_style is not unset: + yaml.default_flow_style = default_flow_style + yaml.top_level_colon_align = top_level_colon_align + yaml.prefix_colon = prefix_colon + yaml.explicit_start = explicit_start + yaml.explicit_end = explicit_end + yaml.version = version + yaml.allow_unicode = allow_unicode + if stream is not None: + yaml.dump(data, stream=stream) + return + buf = io.StringIO() + yaml.dump(data, stream=buf) + return buf.getvalue() + + +def round_trip_dump_all( + data, + stream=None, *, + indent=None, + block_seq_indent=None, + default_flow_style=unset, + top_level_colon_align=None, + prefix_colon=None, + explicit_start=None, + explicit_end=None, + version=None, + allow_unicode=None, +): + import ruamel.yaml # NOQA + + yaml = ruamel.yaml.YAML() + yaml.indent(mapping=indent, sequence=indent, offset=block_seq_indent) + if default_flow_style is not unset: + yaml.default_flow_style = default_flow_style + yaml.top_level_colon_align = top_level_colon_align + yaml.prefix_colon = prefix_colon + yaml.explicit_start = explicit_start + yaml.explicit_end = explicit_end + yaml.version = version + yaml.allow_unicode = allow_unicode + if stream is not None: + yaml.dump(data, stream=stream) + return + buf = io.StringIO() + yaml.dump_all(data, stream=buf) + return buf.getvalue() def diff(inp, outp, file_name='stdin'): @@ -242,7 +277,7 @@ def YAML(**kw): def round_trip(self, stream, **kw): from ruamel.yaml.compat import StringIO, BytesIO # NOQA - assert isinstance(stream, (ruamel.yaml.compat.text_type, str)) + assert isinstance(stream, str) lkw = kw.copy() if stream and stream[0] == '\n': stream = stream[1:] @@ -259,7 +294,7 @@ def YAML(**kw): def round_trip_all(self, stream, **kw): from ruamel.yaml.compat import StringIO, BytesIO # NOQA - assert isinstance(stream, (ruamel.yaml.compat.text_type, str)) + assert isinstance(stream, str) lkw = kw.copy() if stream and stream[0] == '\n': stream = stream[1:] diff --git a/_test/test_a_dedent.py b/_test/test_a_dedent.py index fc6157a..447bdde 100644 --- a/_test/test_a_dedent.py +++ b/_test/test_a_dedent.py @@ -1,3 +1,4 @@ +# coding: utf-8 from roundtrip import dedent diff --git a/_test/test_add_xxx.py b/_test/test_add_xxx.py index 085e352..8beac65 100644 --- a/_test/test_add_xxx.py +++ b/_test/test_add_xxx.py @@ -3,7 +3,7 @@ import re import pytest # NOQA -from roundtrip import dedent +from roundtrip import dedent, round_trip_dump # NOQA # from PyYAML docs @@ -22,48 +22,50 @@ def dice_constructor(loader, node): def dice_representer(dumper, data): - return dumper.represent_scalar(u'!dice', u'{}d{}'.format(*data)) + return dumper.represent_scalar('!dice', '{}d{}'.format(*data)) def test_dice_constructor(): import ruamel.yaml # NOQA - ruamel.yaml.add_constructor(u'!dice', dice_constructor) - data = ruamel.yaml.load('initial hit points: !dice 8d4', Loader=ruamel.yaml.Loader) + yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) + ruamel.yaml.add_constructor('!dice', dice_constructor) + data = yaml.load('initial hit points: !dice 8d4') assert str(data) == "{'initial hit points': Dice(8,4)}" def test_dice_constructor_with_loader(): import ruamel.yaml # NOQA - ruamel.yaml.add_constructor(u'!dice', dice_constructor, Loader=ruamel.yaml.Loader) - data = ruamel.yaml.load('initial hit points: !dice 8d4', Loader=ruamel.yaml.Loader) + yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) + ruamel.yaml.add_constructor('!dice', dice_constructor, Loader=ruamel.yaml.Loader) + data = yaml.load('initial hit points: !dice 8d4') assert str(data) == "{'initial hit points': Dice(8,4)}" def test_dice_representer(): import ruamel.yaml # NOQA + yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) + yaml.default_flow_style = False ruamel.yaml.add_representer(Dice, dice_representer) # ruamel.yaml 0.15.8+ no longer forces quotes tagged scalars - assert ( - ruamel.yaml.dump(dict(gold=Dice(10, 6)), default_flow_style=False) - == 'gold: !dice 10d6\n' - ) + buf = ruamel.yaml.compat.StringIO() + yaml.dump(dict(gold=Dice(10, 6)), buf) + assert buf.getvalue() == 'gold: !dice 10d6\n' def test_dice_implicit_resolver(): import ruamel.yaml # NOQA + yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) + yaml.default_flow_style = False pattern = re.compile(r'^\d+d\d+$') - ruamel.yaml.add_implicit_resolver(u'!dice', pattern) - assert ( - ruamel.yaml.dump(dict(treasure=Dice(10, 20)), default_flow_style=False) - == 'treasure: 10d20\n' - ) - assert ruamel.yaml.load('damage: 5d10', Loader=ruamel.yaml.Loader) == dict( - damage=Dice(5, 10) - ) + ruamel.yaml.add_implicit_resolver('!dice', pattern) + buf = ruamel.yaml.compat.StringIO() + yaml.dump(dict(treasure=Dice(10, 20)), buf) + assert buf.getvalue() == 'treasure: 10d20\n' + assert yaml.load('damage: 5d10') == dict(damage=Dice(5, 10)) class Obj1(dict): @@ -82,7 +84,7 @@ class Obj1(dict): class YAMLObj1(object): - yaml_tag = u'!obj:' + yaml_tag = '!obj:' @classmethod def from_yaml(cls, loader, suffix, node): @@ -103,24 +105,30 @@ class YAMLObj1(object): def test_yaml_obj(): import ruamel.yaml # NOQA + yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) ruamel.yaml.add_representer(Obj1, YAMLObj1.to_yaml) ruamel.yaml.add_multi_constructor(YAMLObj1.yaml_tag, YAMLObj1.from_yaml) - x = ruamel.yaml.load('!obj:x.2\na: 1', Loader=ruamel.yaml.Loader) + x = yaml.load('!obj:x.2\na: 1') print(x) - assert ruamel.yaml.dump(x) == """!obj:x.2 "{'a': 1}"\n""" + buf = ruamel.yaml.compat.StringIO() + yaml.dump(x, buf) + assert buf.getvalue() == """!obj:x.2 "{'a': 1}"\n""" def test_yaml_obj_with_loader_and_dumper(): import ruamel.yaml # NOQA + yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) ruamel.yaml.add_representer(Obj1, YAMLObj1.to_yaml, Dumper=ruamel.yaml.Dumper) ruamel.yaml.add_multi_constructor( YAMLObj1.yaml_tag, YAMLObj1.from_yaml, Loader=ruamel.yaml.Loader ) - x = ruamel.yaml.load('!obj:x.2\na: 1', Loader=ruamel.yaml.Loader) + x = yaml.load('!obj:x.2\na: 1') # x = ruamel.yaml.load('!obj:x.2\na: 1') print(x) - assert ruamel.yaml.dump(x) == """!obj:x.2 "{'a': 1}"\n""" + buf = ruamel.yaml.compat.StringIO() + yaml.dump(x, buf) + assert buf.getvalue() == """!obj:x.2 "{'a': 1}"\n""" # ToDo use nullege to search add_multi_representer and add_path_resolver @@ -135,7 +143,7 @@ def test_issue_127(): class Ref(ruamel.yaml.YAMLObject): yaml_constructor = ruamel.yaml.RoundTripConstructor yaml_representer = ruamel.yaml.RoundTripRepresenter - yaml_tag = u'!Ref' + yaml_tag = '!Ref' def __init__(self, logical_id): self.logical_id = logical_id @@ -163,7 +171,11 @@ def test_issue_127(): - Five Six - 'Seven Eight' """) - data = ruamel.yaml.round_trip_load(document, preserve_quotes=True) - assert ruamel.yaml.round_trip_dump(data, indent=4, block_seq_indent=2) == document.replace( - '\n Two and', ' Two and' - ) + yaml = ruamel.yaml.YAML() + yaml.preserve_quotes = True + yaml.default_flow_style = None + yaml.indent(sequence=4, offset=2) + data = yaml.load(document) + buf = ruamel.yaml.compat.StringIO() + yaml.dump(data, buf) + assert buf.getvalue() == document.replace('\n Two and', ' Two and') diff --git a/_test/test_anchor.py b/_test/test_anchor.py index dec1261..3c83886 100644 --- a/_test/test_anchor.py +++ b/_test/test_anchor.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function - """ testing of anchors and the aliases referring to them """ @@ -46,20 +44,20 @@ class TestAnchorsAliases: """test if id matches the anchor template""" from ruamel.yaml.serializer import templated_id - assert templated_id(u'id001') - assert templated_id(u'id999') - assert templated_id(u'id1000') - assert templated_id(u'id0001') - assert templated_id(u'id0000') - assert not templated_id(u'id02') - assert not templated_id(u'id000') - assert not templated_id(u'x000') + assert templated_id('id001') + assert templated_id('id999') + assert templated_id('id1000') + assert templated_id('id0001') + assert templated_id('id0000') + assert not templated_id('id02') + assert not templated_id('id000') + assert not templated_id('x000') # def test_re_matcher(self): # import re - # assert re.compile(u'id(?!000)\\d{3,}').match('id001') - # assert not re.compile(u'id(?!000\\d*)\\d{3,}').match('id000') - # assert re.compile(u'id(?!000$)\\d{3,}').match('id0001') + # assert re.compile('id(?!000)\\d{3,}').match('id001') + # assert not re.compile('id(?!000\\d*)\\d{3,}').match('id000') + # assert re.compile('id(?!000$)\\d{3,}').match('id0001') def test_anchor_assigned(self): from ruamel.yaml.comments import CommentedMap @@ -283,7 +281,8 @@ class TestAnchorsAliases: components: server: {<<: *server_service} """) - data = ruamel.yaml.safe_load(ys) + yaml = ruamel.yaml.YAML(typ='safe', pure=True) + data = yaml.load(ys) assert data['services']['shell']['components']['server']['port'] == 8000 def test_issue_130a(self): @@ -308,7 +307,8 @@ class TestAnchorsAliases: components: server: {<<: *server_service} """) - data = ruamel.yaml.safe_load(ys) + yaml = ruamel.yaml.YAML(typ='safe', pure=True) + data = yaml.load(ys) assert data['services']['shell']['components']['server']['port'] == 4000 @@ -332,9 +332,9 @@ class TestMergeKeysValues: # in the following d always has "expanded" the merges def test_merge_for(self): - from ruamel.yaml import safe_load + from ruamel.yaml import YAML - d = safe_load(self.yaml_str) + d = YAML(typ='safe', pure=True).load(self.yaml_str) data = round_trip_load(self.yaml_str) count = 0 for x in data[2]: @@ -343,9 +343,9 @@ class TestMergeKeysValues: assert count == len(d[2]) def test_merge_keys(self): - from ruamel.yaml import safe_load + from ruamel.yaml import YAML - d = safe_load(self.yaml_str) + d = YAML(typ='safe', pure=True).load(self.yaml_str) data = round_trip_load(self.yaml_str) count = 0 for x in data[2].keys(): @@ -354,9 +354,9 @@ class TestMergeKeysValues: assert count == len(d[2]) def test_merge_values(self): - from ruamel.yaml import safe_load + from ruamel.yaml import YAML - d = safe_load(self.yaml_str) + d = YAML(typ='safe', pure=True).load(self.yaml_str) data = round_trip_load(self.yaml_str) count = 0 for x in data[2].values(): @@ -365,9 +365,9 @@ class TestMergeKeysValues: assert count == len(d[2]) def test_merge_items(self): - from ruamel.yaml import safe_load + from ruamel.yaml import YAML - d = safe_load(self.yaml_str) + d = YAML(typ='safe', pure=True).load(self.yaml_str) data = round_trip_load(self.yaml_str) count = 0 for x in data[2].items(): @@ -376,10 +376,9 @@ class TestMergeKeysValues: assert count == len(d[2]) def test_len_items_delete(self): - from ruamel.yaml import safe_load - from ruamel.yaml.compat import PY3 + from ruamel.yaml import YAML - d = safe_load(self.yaml_str) + d = YAML(typ='safe', pure=True).load(self.yaml_str) data = round_trip_load(self.yaml_str) x = data[2].items() print('d2 items', d[2].items(), len(d[2].items()), x, len(x)) @@ -387,16 +386,13 @@ class TestMergeKeysValues: print('ref', ref) assert len(x) == ref del data[2]['m'] - if PY3: - ref -= 1 + ref -= 1 assert len(x) == ref del data[2]['d'] - if PY3: - ref -= 1 + ref -= 1 assert len(x) == ref del data[2]['a'] - if PY3: - ref -= 1 + ref -= 1 assert len(x) == ref def test_issue_196_cast_of_dict(self, capsys): @@ -467,7 +463,7 @@ class TestMergeKeysValues: class TestDuplicateKeyThroughAnchor: def test_duplicate_key_00(self): from ruamel.yaml import version_info - from ruamel.yaml import safe_load, round_trip_load + from ruamel.yaml import YAML from ruamel.yaml.constructor import DuplicateKeyFutureWarning, DuplicateKeyError s = dedent("""\ @@ -481,14 +477,14 @@ class TestDuplicateKeyThroughAnchor: pass elif version_info < (0, 16, 0): with pytest.warns(DuplicateKeyFutureWarning): - safe_load(s) + YAML(typ='safe', pure=True).load(s) with pytest.warns(DuplicateKeyFutureWarning): - round_trip_load(s) + YAML(typ='rt').load(s) else: with pytest.raises(DuplicateKeyError): - safe_load(s) + YAML(typ='safe', pure=True).load(s) with pytest.raises(DuplicateKeyError): - round_trip_load(s) + YAML(typ='rt').load(s) def test_duplicate_key_01(self): # so issue https://stackoverflow.com/a/52852106/1307905 diff --git a/_test/test_api_change.py b/_test/test_api_change.py index b47a551..4ce61b6 100644 --- a/_test/test_api_change.py +++ b/_test/test_api_change.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function - """ testing of anchors and the aliases referring to them """ @@ -158,7 +156,7 @@ class TestLoadAll: fn = Path(str(tmpdir)) / 'test.yaml' fn.write_text( - textwrap.dedent(u"""\ + textwrap.dedent("""\ --- - a --- @@ -196,10 +194,10 @@ class TestDumpLoadUnicode: from ruamel.yaml import YAML yaml = YAML() - text_dict = {'text': u'HELLO_WORLD©'} + text_dict = {'text': 'HELLO_WORLD©'} file_name = str(tmpdir) + '/tstFile.yaml' yaml.dump(text_dict, open(file_name, 'w')) - assert open(file_name, 'rb').read().decode('utf-8') == u'text: HELLO_WORLD©\n' + assert open(file_name, 'rb').read().decode('utf-8') == 'text: HELLO_WORLD©\n' def test_read_unicode(self, tmpdir): from ruamel.yaml import YAML @@ -207,9 +205,9 @@ class TestDumpLoadUnicode: yaml = YAML() file_name = str(tmpdir) + '/tstFile.yaml' with open(file_name, 'wb') as fp: - fp.write(u'text: HELLO_WORLD©\n'.encode('utf-8')) + fp.write('text: HELLO_WORLD©\n'.encode('utf-8')) text_dict = yaml.load(open(file_name, 'r')) - assert text_dict['text'] == u'HELLO_WORLD©' + assert text_dict['text'] == 'HELLO_WORLD©' class TestFlowStyle: diff --git a/_test/test_class_register.py b/_test/test_class_register.py index 126d93f..d996269 100644 --- a/_test/test_class_register.py +++ b/_test/test_class_register.py @@ -14,7 +14,7 @@ class User0(object): class User1(object): - yaml_tag = u'!user' + yaml_tag = '!user' def __init__(self, name, age): self.name = name @@ -22,7 +22,7 @@ class User1(object): @classmethod def to_yaml(cls, representer, node): - return representer.represent_scalar(cls.yaml_tag, u'{.name}-{.age}'.format(node, node)) + return representer.represent_scalar(cls.yaml_tag, '{.name}-{.age}'.format(node, node)) @classmethod def from_yaml(cls, constructor, node): @@ -116,7 +116,7 @@ class TestDecorator(object): @yaml_object(yml) class User3(object): - yaml_tag = u'!USER' + yaml_tag = '!USER' def __init__(self, name, age): self.name = name @@ -125,7 +125,7 @@ class TestDecorator(object): @classmethod def to_yaml(cls, representer, node): return representer.represent_scalar( - cls.yaml_tag, u'{.name}-{.age}'.format(node, node) + cls.yaml_tag, '{.name}-{.age}'.format(node, node) ) @classmethod diff --git a/_test/test_collections.py b/_test/test_collections.py index e6033bb..40af9db 100644 --- a/_test/test_collections.py +++ b/_test/test_collections.py @@ -16,6 +16,5 @@ from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # NO class TestOrderedDict: def test_ordereddict(self): from collections import OrderedDict - import ruamel.yaml # NOQA - assert ruamel.yaml.dump(OrderedDict()) == '!!omap []\n' + assert round_trip_dump(OrderedDict()) == '!!omap []\n' diff --git a/_test/test_comment_manipulation.py b/_test/test_comment_manipulation.py index 7f09a38..6d706f2 100644 --- a/_test/test_comment_manipulation.py +++ b/_test/test_comment_manipulation.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function - import pytest # NOQA from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # NOQA diff --git a/_test/test_comments.py b/_test/test_comments.py index 79acfc8..3173995 100644 --- a/_test/test_comments.py +++ b/_test/test_comments.py @@ -272,26 +272,24 @@ class TestComments: - y # more comment """) data = round_trip_load(x) - dumper = ruamel.yaml.RoundTripDumper for utf in [True, False]: - y = ruamel.yaml.dump( - data, default_flow_style=False, Dumper=dumper, allow_unicode=utf + y = round_trip_dump( + data, default_flow_style=False, allow_unicode=utf ) assert y == x def test_dump_unicode_utf8(self): import ruamel.yaml # NOQA - x = dedent(u"""\ + x = dedent("""\ ab: - x # comment - y # more comment """) data = round_trip_load(x) - dumper = ruamel.yaml.RoundTripDumper for utf in [True, False]: - y = ruamel.yaml.dump( - data, default_flow_style=False, Dumper=dumper, allow_unicode=utf + y = round_trip_dump( + data, default_flow_style=False, allow_unicode=utf ) assert y == x @@ -843,6 +841,6 @@ class TestBlockScalarWithComments: ]: commented_line = test_block_scalar_commented_line_template.format(x) - data = ruamel.yaml.round_trip_load(commented_line) + data = round_trip_load(commented_line) - assert ruamel.yaml.round_trip_dump(data) == commented_line + assert round_trip_dump(data) == commented_line diff --git a/_test/test_contextmanager.py b/_test/test_contextmanager.py index b3bb3be..bdc8b78 100644 --- a/_test/test_contextmanager.py +++ b/_test/test_contextmanager.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function - """ testing of anchors and the aliases referring to them """ diff --git a/_test/test_cyaml.py b/_test/test_cyaml.py index 6b618f3..593d171 100644 --- a/_test/test_cyaml.py +++ b/_test/test_cyaml.py @@ -5,6 +5,8 @@ import platform import pytest from textwrap import dedent +NO_CLIB_VER = (3, 10) + @pytest.mark.skipif( platform.python_implementation() in ['Jython', 'PyPy'], @@ -14,30 +16,29 @@ def test_load_cyaml(): print("???????????????????????", platform.python_implementation()) import ruamel.yaml - if sys.version_info >= (3, 8): + if sys.version_info >= NO_CLIB_VER: return + yaml = ruamel.yaml.YAML(typ='safe', pure=False) assert ruamel.yaml.__with_libyaml__ - from ruamel.yaml.cyaml import CLoader - ruamel.yaml.load('abc: 1', Loader=CLoader) + yaml.load('abc: 1') -@pytest.mark.skipif(sys.version_info >= (3, 8) +@pytest.mark.skipif(sys.version_info >= NO_CLIB_VER or platform.python_implementation() in ['Jython', 'PyPy'], reason='no _PyGC_FINALIZED') def test_dump_cyaml(): import ruamel.yaml - if sys.version_info >= (3, 8): + if sys.version_info >= NO_CLIB_VER: return data = {'a': 1, 'b': 2} - res = ruamel.yaml.dump( - data, - Dumper=ruamel.yaml.cyaml.CSafeDumper, - default_flow_style=False, - allow_unicode=True, - ) - assert res == 'a: 1\nb: 2\n' + yaml = ruamel.yaml.YAML(typ='safe', pure=False) + yaml.default_flow_style = False + yaml.allow_unicode = True + buf = ruamel.yaml.compat.StringIO() + yaml.dump(data, buf) + assert buf.getvalue() == 'a: 1\nb: 2\n' @pytest.mark.skipif( @@ -47,7 +48,7 @@ def test_load_cyaml_1_2(): # issue 155 import ruamel.yaml - if sys.version_info >= (3, 8): + if sys.version_info >= NO_CLIB_VER: return assert ruamel.yaml.__with_libyaml__ inp = dedent("""\ @@ -67,7 +68,7 @@ def test_dump_cyaml_1_2(): import ruamel.yaml from ruamel.yaml.compat import StringIO - if sys.version_info >= (3, 8): + if sys.version_info >= NO_CLIB_VER: return assert ruamel.yaml.__with_libyaml__ yaml = ruamel.yaml.YAML(typ='safe') diff --git a/_test/test_deprecation.py b/_test/test_deprecation.py index 14acd71..b267e66 100644 --- a/_test/test_deprecation.py +++ b/_test/test_deprecation.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function - import sys import pytest # NOQA diff --git a/_test/test_documents.py b/_test/test_documents.py index 05ba7dd..5119f06 100644 --- a/_test/test_documents.py +++ b/_test/test_documents.py @@ -2,7 +2,7 @@ import pytest # NOQA -from roundtrip import round_trip, round_trip_load_all +from roundtrip import round_trip, round_trip_load_all, round_trip_dump_all class TestDocument: @@ -16,8 +16,6 @@ class TestDocument: round_trip(inp, explicit_start=True, explicit_end=True) def test_multi_doc_begin_end(self): - from ruamel import yaml - inp = """\ --- - a @@ -28,9 +26,7 @@ class TestDocument: """ docs = list(round_trip_load_all(inp)) assert docs == [['a'], ['b']] - out = yaml.dump_all( - docs, Dumper=yaml.RoundTripDumper, explicit_start=True, explicit_end=True - ) + out = round_trip_dump_all(docs, explicit_start=True, explicit_end=True) assert out == '---\n- a\n...\n---\n- b\n...\n' def test_multi_doc_no_start(self): diff --git a/_test/test_float.py b/_test/test_float.py index c996efd..8257208 100644 --- a/_test/test_float.py +++ b/_test/test_float.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function, absolute_import, division, unicode_literals - import pytest # NOQA from roundtrip import round_trip, dedent, round_trip_load, round_trip_dump # NOQA diff --git a/_test/test_indentation.py b/_test/test_indentation.py index 6321409..6e0fce2 100644 --- a/_test/test_indentation.py +++ b/_test/test_indentation.py @@ -1,22 +1,13 @@ # coding: utf-8 -from __future__ import absolute_import -from __future__ import print_function -from __future__ import unicode_literals - - import pytest # NOQA from roundtrip import round_trip, round_trip_load, round_trip_dump, dedent, YAML def rt(s): - import ruamel.yaml - res = ruamel.yaml.dump( - ruamel.yaml.load(s, Loader=ruamel.yaml.RoundTripLoader), - Dumper=ruamel.yaml.RoundTripDumper, - ) + res = round_trip_dump(round_trip_load(s)) return res.strip() + '\n' @@ -55,8 +46,6 @@ class TestIndent: # first test by explicitly setting flow style def test_added_inline_list(self): - import ruamel.yaml - s1 = dedent(""" a: - b @@ -64,24 +53,22 @@ class TestIndent: - d """) s = 'a: [b, c, d]\n' - data = ruamel.yaml.load(s1, Loader=ruamel.yaml.RoundTripLoader) + data = round_trip_load(s1) val = data['a'] val.fa.set_flow_style() # print(type(val), '_yaml_format' in dir(val)) - output = ruamel.yaml.dump(data, Dumper=ruamel.yaml.RoundTripDumper) + output = round_trip_dump(data) assert s == output # ############ flow mappings def test_roundtrip_flow_mapping(self): - import ruamel.yaml - s = dedent("""\ - {a: 1, b: hallo} - {j: fka, k: 42} """) - data = ruamel.yaml.load(s, Loader=ruamel.yaml.RoundTripLoader) - output = ruamel.yaml.dump(data, Dumper=ruamel.yaml.RoundTripDumper) + data = round_trip_load(s) + output = round_trip_dump(data) assert s == output def test_roundtrip_sequence_of_inline_mappings_eol_comments(self): diff --git a/_test/test_int.py b/_test/test_int.py index 4e7de6b..aa300df 100644 --- a/_test/test_int.py +++ b/_test/test_int.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function, absolute_import, division, unicode_literals - import pytest # NOQA from roundtrip import dedent, round_trip_load, round_trip_dump diff --git a/_test/test_issues.py b/_test/test_issues.py index 673ba45..736dccb 100644 --- a/_test/test_issues.py +++ b/_test/test_issues.py @@ -1,8 +1,5 @@ # coding: utf-8 -from __future__ import absolute_import, print_function, unicode_literals - - import pytest # NOQA @@ -19,8 +16,6 @@ from roundtrip import ( class TestIssues: def test_issue_61(self): - import ruamel.yaml - s = dedent(""" def1: &ANCHOR1 key1: value1 @@ -30,24 +25,20 @@ class TestIssues: comb: <<: *ANCHOR """) - data = ruamel.yaml.round_trip_load(s) + data = round_trip_load(s) assert str(data['comb']) == str(data['def']) assert str(data['comb']) == "ordereddict([('key', 'value'), ('key1', 'value1')])" def test_issue_82(self, tmpdir): program_src = r''' - from __future__ import print_function - from ruamel import yaml - import re - class SINumber(yaml.YAMLObject): PREFIXES = {'k': 1e3, 'M': 1e6, 'G': 1e9} yaml_loader = yaml.Loader yaml_dumper = yaml.Dumper - yaml_tag = u'!si' + yaml_tag = '!si' yaml_implicit_pattern = re.compile( r'^(?P[0-9]+(?:\.[0-9]+)?)(?P[kMG])$') @@ -200,8 +191,6 @@ class TestIssues: assert res == yaml_str.replace(' b ', ' B ').replace(' d\n', ' D\n') def test_issue_176_test_slicing(self): - from ruamel.yaml.compat import PY2 - mss = round_trip_load('[0, 1, 2, 3, 4]') assert len(mss) == 5 assert mss[2:2] == [] @@ -231,18 +220,10 @@ class TestIssues: m[1::2] = [42, 43] assert m == [0, 42, 2, 43, 4] m = mss[:] - if PY2: - with pytest.raises(ValueError, match='attempt to assign'): - m[1::2] = [42, 43, 44] - else: - with pytest.raises(TypeError, match='too many'): - m[1::2] = [42, 43, 44] - if PY2: - with pytest.raises(ValueError, match='attempt to assign'): - m[1::2] = [42] - else: - with pytest.raises(TypeError, match='not enough'): - m[1::2] = [42] + with pytest.raises(TypeError, match='too many'): + m[1::2] = [42, 43, 44] + with pytest.raises(TypeError, match='not enough'): + m[1::2] = [42] m = mss[:] m += [5] m[1::2] = [42, 43, 44] @@ -288,7 +269,7 @@ class TestIssues: program_src = r''' from ruamel.yaml import YAML - yaml_str = u"""\ + yaml_str = """\ --- foo: ["bar"] """ @@ -409,8 +390,9 @@ class TestIssues: import ruamel.yaml from ruamel.yaml.compat import StringIO + yaml = ruamel.yaml.YAML(typ='safe') buf = StringIO() - ruamel.yaml.safe_dump(['012923'], buf) + yaml.dump(['012923'], buf) assert buf.getvalue() == "['012923']\n" def test_issue_223(self): @@ -421,12 +403,13 @@ class TestIssues: def test_issue_232(self): import ruamel.yaml - from ruamel import yaml + + yaml = YAML(typ='safe', pure=True) with pytest.raises(ruamel.yaml.parser.ParserError): - yaml.safe_load(']') + yaml.load(']') with pytest.raises(ruamel.yaml.parser.ParserError): - yaml.safe_load('{]') + yaml.load('{]') def test_issue_233(self): from ruamel.yaml import YAML diff --git a/_test/test_json_numbers.py b/_test/test_json_numbers.py index 56b7b6f..d89453c 100644 --- a/_test/test_json_numbers.py +++ b/_test/test_json_numbers.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function - import pytest # NOQA import json @@ -10,12 +8,13 @@ import json def load(s, typ=float): import ruamel.yaml + yaml = ruamel.yaml.YAML() x = '{"low": %s }' % (s) print('input: [%s]' % (s), repr(x)) # just to check it is loadable json res = json.loads(x) assert isinstance(res['low'], typ) - ret_val = ruamel.yaml.load(x, ruamel.yaml.RoundTripLoader) + ret_val = yaml.load(x) print(ret_val) return ret_val['low'] diff --git a/_test/test_literal.py b/_test/test_literal.py index 20eb8e9..7192207 100644 --- a/_test/test_literal.py +++ b/_test/test_literal.py @@ -1,5 +1,4 @@ # coding: utf-8 -from __future__ import print_function import pytest # NOQA @@ -64,15 +63,16 @@ class TestNoIndent: def test_root_literal_scalar_no_indent_1_1_old_style(self): from textwrap import dedent - from ruamel.yaml import safe_load + from ruamel.yaml import YAML + yaml = YAML(typ='safe', pure=True) s = 'testing123' inp = """ %YAML 1.1 --- | {} """ - d = safe_load(dedent(inp.format(s))) + d = yaml.load(dedent(inp.format(s))) print(d) assert d == s + '\n' diff --git a/_test/test_none.py b/_test/test_none.py index e313edc..42aef4c 100644 --- a/_test/test_none.py +++ b/_test/test_none.py @@ -1,51 +1,41 @@ # coding: utf-8 - import pytest # NOQA +from roundtrip import round_trip_load, round_trip_dump class TestNone: def test_dump00(self): - import ruamel.yaml # NOQA - data = None - s = ruamel.yaml.round_trip_dump(data) + s = round_trip_dump(data) assert s == 'null\n...\n' - d = ruamel.yaml.round_trip_load(s) + d = round_trip_load(s) assert d == data def test_dump01(self): - import ruamel.yaml # NOQA - data = None - s = ruamel.yaml.round_trip_dump(data, explicit_end=True) + s = round_trip_dump(data, explicit_end=True) assert s == 'null\n...\n' - d = ruamel.yaml.round_trip_load(s) + d = round_trip_load(s) assert d == data def test_dump02(self): - import ruamel.yaml # NOQA - data = None - s = ruamel.yaml.round_trip_dump(data, explicit_end=False) + s = round_trip_dump(data, explicit_end=False) assert s == 'null\n...\n' - d = ruamel.yaml.round_trip_load(s) + d = round_trip_load(s) assert d == data def test_dump03(self): - import ruamel.yaml # NOQA - data = None - s = ruamel.yaml.round_trip_dump(data, explicit_start=True) + s = round_trip_dump(data, explicit_start=True) assert s == '---\n...\n' - d = ruamel.yaml.round_trip_load(s) + d = round_trip_load(s) assert d == data def test_dump04(self): - import ruamel.yaml # NOQA - data = None - s = ruamel.yaml.round_trip_dump(data, explicit_start=True, explicit_end=False) + s = round_trip_dump(data, explicit_start=True, explicit_end=False) assert s == '---\n...\n' - d = ruamel.yaml.round_trip_load(s) + d = round_trip_load(s) assert d == data diff --git a/_test/test_numpy.py b/_test/test_numpy.py index 2747fc4..573f0bd 100644 --- a/_test/test_numpy.py +++ b/_test/test_numpy.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function, absolute_import, division, unicode_literals - try: import numpy except: # NOQA diff --git a/_test/test_program_config.py b/_test/test_program_config.py index dcd8351..821ca15 100644 --- a/_test/test_program_config.py +++ b/_test/test_program_config.py @@ -1,3 +1,4 @@ +# coding: utf-8 import pytest # NOQA diff --git a/_test/test_spec_examples.py b/_test/test_spec_examples.py index bae505d..cead787 100644 --- a/_test/test_spec_examples.py +++ b/_test/test_spec_examples.py @@ -1,3 +1,4 @@ +# coding: utf-8 from roundtrip import YAML import pytest # NOQA diff --git a/_test/test_string.py b/_test/test_string.py index d1f7982..7c10fd4 100644 --- a/_test/test_string.py +++ b/_test/test_string.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function - """ various test cases for string scalars in YAML files '|' for preserved newlines diff --git a/_test/test_tag.py b/_test/test_tag.py index 31a192e..3fd1e05 100644 --- a/_test/test_tag.py +++ b/_test/test_tag.py @@ -11,7 +11,7 @@ def register_xxx(**kw): class XXX(yaml.comments.CommentedMap): @staticmethod def yaml_dump(dumper, data): - return dumper.represent_mapping(u'!xxx', data) + return dumper.represent_mapping('!xxx', data) @classmethod def yaml_load(cls, constructor, node): @@ -19,7 +19,7 @@ def register_xxx(**kw): yield data constructor.construct_mapping(node, data) - yaml.add_constructor(u'!xxx', XXX.yaml_load, constructor=yaml.RoundTripConstructor) + yaml.add_constructor('!xxx', XXX.yaml_load, constructor=yaml.RoundTripConstructor) yaml.add_representer(XXX, XXX.yaml_dump, representer=yaml.RoundTripRepresenter) diff --git a/_test/test_version.py b/_test/test_version.py index 742ec36..e110eed 100644 --- a/_test/test_version.py +++ b/_test/test_version.py @@ -8,7 +8,9 @@ from roundtrip import dedent, round_trip, round_trip_load def load(s, version=None): import ruamel.yaml # NOQA - return ruamel.yaml.round_trip_load(dedent(s), version) + yaml = ruamel.yaml.YAML() + yaml.version = version + return yaml.load(dedent(s)) class TestVersions: diff --git a/_test/test_yamlfile.py b/_test/test_yamlfile.py index a02fcab..f1de872 100644 --- a/_test/test_yamlfile.py +++ b/_test/test_yamlfile.py @@ -1,11 +1,11 @@ - -from __future__ import print_function +# coding: utf-8 """ various test cases for YAML files """ import sys +import io import pytest # NOQA import platform @@ -25,7 +25,7 @@ class TestYAML: import ruamel.yaml # NOQA x = ordereddict([('a', 1), ('b', 2)]) - res = ruamel.yaml.dump(x, default_flow_style=False) + res = round_trip_dump(x, default_flow_style=False) assert res == dedent(""" !!omap - a: 1 @@ -48,7 +48,7 @@ class TestYAML: # OrderedDict mapped to !!omap x = OrderedDict([('a', 1), ('b', 2)]) - res = ruamel.yaml.dump(x, Dumper=ruamel.yaml.RoundTripDumper, default_flow_style=False) + res = round_trip_dump(x, default_flow_style=False) assert res == dedent(""" !!omap - a: 1 @@ -65,7 +65,7 @@ class TestYAML: # OrderedDict mapped to !!omap x = ordereddict([('a', 1), ('b', 2)]) - res = ruamel.yaml.dump(x, Dumper=ruamel.yaml.RoundTripDumper, default_flow_style=False) + res = round_trip_dump(x, default_flow_style=False) assert res == dedent(""" !!omap - a: 1 @@ -89,8 +89,12 @@ class TestYAML: import ruamel.yaml # NOQA x = set(['a', 'b', 'c']) - res = ruamel.yaml.dump(x, default_flow_style=False) - assert res == dedent(""" + # cannot use round_trip_dump, it doesn't show null in block style + buf = io.StringIO() + yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) + yaml.default_flow_style = False + yaml.dump(x, buf) + assert buf.getvalue() == dedent(""" !!set a: null b: null @@ -202,15 +206,19 @@ class TestYAML: def test_load_all_perserve_quotes(self): import ruamel.yaml # NOQA + yaml = ruamel.yaml.YAML() + yaml.preserve_quotes = True s = dedent("""\ a: 'hello' --- b: "goodbye" """) data = [] - for x in ruamel.yaml.round_trip_load_all(s, preserve_quotes=True): + for x in yaml.load_all(s): data.append(x) - out = ruamel.yaml.dump_all(data, Dumper=ruamel.yaml.RoundTripDumper) + buf = ruamel.yaml.compat.StringIO() + yaml.dump_all(data, buf) + out = buf.getvalue() print(type(data[0]['a']), data[0]['a']) # out = ruamel.yaml.round_trip_dump_all(data) print(out) diff --git a/_test/test_yamlobject.py b/_test/test_yamlobject.py index 7c4f7ec..80fb213 100644 --- a/_test/test_yamlobject.py +++ b/_test/test_yamlobject.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function - import sys import pytest # NOQA @@ -9,12 +7,12 @@ from roundtrip import save_and_run # NOQA def test_monster(tmpdir): - program_src = u'''\ + program_src = '''\ import ruamel.yaml from textwrap import dedent class Monster(ruamel.yaml.YAMLObject): - yaml_tag = u'!Monster' + yaml_tag = '!Monster' def __init__(self, name, hp, ac, attacks): self.name = name @@ -48,7 +46,7 @@ def test_monster(tmpdir): @pytest.mark.skipif(sys.version_info < (3, 0), reason='no __qualname__') def test_qualified_name00(tmpdir): """issue 214""" - program_src = u"""\ + program_src = """\ from ruamel.yaml import YAML from ruamel.yaml.compat import StringIO diff --git a/_test/test_z_data.py b/_test/test_z_data.py index a4eec0d..dcd6bd0 100644 --- a/_test/test_z_data.py +++ b/_test/test_z_data.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function, unicode_literals - import sys import pytest # NOQA import warnings # NOQA @@ -9,7 +7,6 @@ import warnings # NOQA from ruamel.std.pathlib import Path base_path = Path('data') # that is ruamel.yaml.data -PY2 = sys.version_info[0] == 2 class YAMLData(object): @@ -70,7 +67,7 @@ class Assert(YAMLData): @property def value(self): - from ruamel.yaml.compat import Mapping + from collections.abc import Mapping if hasattr(self, '_pa'): return self._pa @@ -126,14 +123,10 @@ class TestYAMLData(object): yaml.dump(data, buf) expected = input.value if output is None else output.value value = buf.getvalue() - if PY2: - value = value.decode('utf-8') - print('value', value) - # print('expected', expected) assert value == expected def load_assert(self, input, confirm, yaml_version=None): - from ruamel.yaml.compat import Mapping + from collections.abc import Mapping d = self.yaml_load(input.value, yaml_version=yaml_version)[1] # NOQA print('confirm.value', confirm.value, type(confirm.value)) @@ -159,7 +152,7 @@ class TestYAMLData(object): # this is executed by pytest the methods with names not starting with test_ # are helpers def test_yaml_data(self, yaml, tmpdir): - from ruamel.yaml.compat import Mapping + from collections.abc import Mapping idx = 0 typ = None diff --git a/_test/test_z_olddata.py b/_test/test_z_olddata.py index 91d89db..3857652 100644 --- a/_test/test_z_olddata.py +++ b/_test/test_z_olddata.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function - import sys import os import pytest # NOQA diff --git a/anchor.py b/anchor.py index d702126..a501416 100644 --- a/anchor.py +++ b/anchor.py @@ -1,3 +1,4 @@ +# coding: utf-8 if False: # MYPY from typing import Any, Dict, Optional, List, Union, Optional, Iterator # NOQA diff --git a/comments.py b/comments.py index 13a519e..0bcb916 100644 --- a/comments.py +++ b/comments.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import absolute_import, print_function - """ stuff to deal with comments and formatting on dict/list/ordereddict/set these are not really related, formatting could be factored out as @@ -13,14 +11,11 @@ import copy from ruamel.yaml.compat import ordereddict # type: ignore -from ruamel.yaml.compat import PY2, string_types, MutableSliceableSequence +from ruamel.yaml.compat import MutableSliceableSequence from ruamel.yaml.scalarstring import ScalarString from ruamel.yaml.anchor import Anchor -if PY2: - from collections import MutableSet, Sized, Set, Mapping -else: - from collections.abc import MutableSet, Sized, Set, Mapping +from collections.abc import MutableSet, Sized, Set, Mapping if False: # MYPY from typing import Any, Dict, Optional, List, Union, Optional, Iterator # NOQA @@ -395,7 +390,7 @@ class CommentedSeq(MutableSliceableSequence, list, CommentedBase): # type: igno # try to preserve the scalarstring type if setting an existing key to a new value if idx < len(self): if ( - isinstance(value, string_types) + isinstance(value, str) and not isinstance(value, ScalarString) and isinstance(self[idx], ScalarString) ): @@ -767,7 +762,7 @@ class CommentedMap(ordereddict, CommentedBase): # type: ignore # try to preserve the scalarstring type if setting an existing key to a new value if key in self: if ( - isinstance(value, string_types) + isinstance(value, str) and not isinstance(value, ScalarString) and isinstance(self[key], ScalarString) ): @@ -840,75 +835,22 @@ class CommentedMap(ordereddict, CommentedBase): # type: ignore # type: (Any) -> bool return bool(dict(self) == other) - if PY2: - - def keys(self): - # type: () -> Any - return list(self._keys()) - - def iterkeys(self): - # type: () -> Any - return self._keys() - - def viewkeys(self): - # type: () -> Any - return CommentedMapKeysView(self) - - else: - - def keys(self): - # type: () -> Any - return CommentedMapKeysView(self) - - if PY2: - - def _values(self): - # type: () -> Any - for x in ordereddict.__iter__(self): - yield ordereddict.__getitem__(self, x) - - def values(self): - # type: () -> Any - return list(self._values()) - - def itervalues(self): - # type: () -> Any - return self._values() - - def viewvalues(self): - # type: () -> Any - return CommentedMapValuesView(self) - - else: + def keys(self): + # type: () -> Any + return CommentedMapKeysView(self) - def values(self): - # type: () -> Any - return CommentedMapValuesView(self) + def values(self): + # type: () -> Any + return CommentedMapValuesView(self) def _items(self): # type: () -> Any for x in ordereddict.__iter__(self): yield x, ordereddict.__getitem__(self, x) - if PY2: - - def items(self): - # type: () -> Any - return list(self._items()) - - def iteritems(self): - # type: () -> Any - return self._items() - - def viewitems(self): - # type: () -> Any - return CommentedMapItemsView(self) - - else: - - def items(self): - # type: () -> Any - return CommentedMapItemsView(self) + def items(self): + # type: () -> Any + return CommentedMapItemsView(self) @property def merge(self): @@ -978,10 +920,7 @@ class CommentedKeyMap(CommentedBase, Mapping): # type: ignore try: self._od = ordereddict(*args, **kw) except TypeError: - if PY2: - self._od = ordereddict(args[0].items()) - else: - raise + raise __delitem__ = __setitem__ = clear = pop = popitem = setdefault = update = raise_immutable diff --git a/compat.py b/compat.py index 839166f..7a419dc 100644 --- a/compat.py +++ b/compat.py @@ -1,14 +1,13 @@ # coding: utf-8 -from __future__ import print_function - # partially from package six by Benjamin Peterson import sys import os -import types +import io import traceback from abc import abstractmethod +import collections.abc # fmt: off @@ -50,73 +49,18 @@ PY2 = sys.version_info[0] == 2 PY3 = sys.version_info[0] == 3 -if PY3: - - def utf8(s): - # type: (str) -> str - return s - - def to_str(s): - # type: (str) -> str - return s - - def to_unicode(s): - # type: (str) -> str - return s - - -else: - if False: - unicode = str - - def utf8(s): - # type: (unicode) -> str - return s.encode('utf-8') - - def to_str(s): - # type: (str) -> str - return str(s) +# replace with f-strings when 3.5 support is dropped +# ft = '42' +# assert _F('abc {ft!r}', ft=ft) == 'abc %r' % ft +# 'abc %r' % ft -> _F('abc {ft!r}' -> f'abc {ft!r}' +def _F(s, *superfluous, **kw): + if superfluous: + raise TypeError + return s.format(**kw) - def to_unicode(s): - # type: (str) -> unicode - return unicode(s) # NOQA - -if PY3: - string_types = str - integer_types = int - class_types = type - text_type = str - binary_type = bytes - - MAXSIZE = sys.maxsize - unichr = chr - import io - - StringIO = io.StringIO - BytesIO = io.BytesIO - # have unlimited precision - no_limit_int = int - from collections.abc import Hashable, MutableSequence, MutableMapping, Mapping # NOQA - -else: - string_types = basestring # NOQA - integer_types = (int, long) # NOQA - class_types = (type, types.ClassType) - text_type = unicode # NOQA - binary_type = str - - # to allow importing - unichr = unichr - from StringIO import StringIO as _StringIO - - StringIO = _StringIO - import cStringIO - - BytesIO = cStringIO.StringIO - # have unlimited precision - no_limit_int = long # NOQA not available on Python 3 - from collections import Hashable, MutableSequence, MutableMapping, Mapping # NOQA +StringIO = io.StringIO +BytesIO = io.BytesIO if False: # MYPY # StreamType = Union[BinaryIO, IO[str], IO[unicode], StringIO] @@ -126,12 +70,7 @@ if False: # MYPY StreamTextType = StreamType # Union[Text, StreamType] VersionType = Union[List[int], str, Tuple[int, int]] -if PY3: - builtins_module = 'builtins' -else: - builtins_module = '__builtin__' - -UNICODE_SIZE = 4 if sys.maxunicode > 65535 else 2 +builtins_module = 'builtins' def with_metaclass(meta, *bases): @@ -232,20 +171,20 @@ nprintf = Nprint('/var/tmp/ruamel.yaml.log') def check_namespace_char(ch): # type: (Any) -> bool - if u'\x21' <= ch <= u'\x7E': # ! to ~ + if '\x21' <= ch <= '\x7E': # ! to ~ return True - if u'\xA0' <= ch <= u'\uD7FF': + if '\xA0' <= ch <= '\uD7FF': return True - if (u'\uE000' <= ch <= u'\uFFFD') and ch != u'\uFEFF': # excl. byte order mark + if ('\uE000' <= ch <= '\uFFFD') and ch != '\uFEFF': # excl. byte order mark return True - if u'\U00010000' <= ch <= u'\U0010FFFF': + if '\U00010000' <= ch <= '\U0010FFFF': return True return False def check_anchorname_char(ch): # type: (Any) -> bool - if ch in u',[]{}': + if ch in ',[]{}': return False return check_namespace_char(ch) @@ -264,7 +203,7 @@ def version_tnf(t1, t2=None): return False -class MutableSliceableSequence(MutableSequence): # type: ignore +class MutableSliceableSequence(collections.abc.MutableSequence): # type: ignore __slots__ = () def __getitem__(self, index): diff --git a/composer.py b/composer.py index d8d3d11..3c8ba1c 100644 --- a/composer.py +++ b/composer.py @@ -1,11 +1,9 @@ # coding: utf-8 -from __future__ import absolute_import, print_function - import warnings from ruamel.yaml.error import MarkedYAMLError, ReusedAnchorWarning -from ruamel.yaml.compat import utf8, nprint, nprintf # NOQA +from ruamel.yaml.compat import _F, nprint, nprintf # NOQA from ruamel.yaml.events import ( StreamStartEvent, @@ -113,7 +111,10 @@ class Composer(object): alias = event.anchor if alias not in self.anchors: raise ComposerError( - None, None, 'found undefined alias %r' % utf8(alias), event.start_mark + None, + None, + _F('found undefined alias {alias!r}', alias=alias), + event.start_mark, ) return self.anchors[alias] event = self.parser.peek_event() @@ -122,7 +123,7 @@ class Composer(object): if anchor in self.anchors: # raise ComposerError( # "found duplicate anchor %r; first occurrence" - # % utf8(anchor), self.anchors[anchor].start_mark, + # % (anchor), self.anchors[anchor].start_mark, # "second occurrence", event.start_mark) ws = ( '\nfound duplicate anchor {!r}\nfirst occurrence {}\nsecond occurrence ' @@ -143,7 +144,7 @@ class Composer(object): # type: (Any) -> Any event = self.parser.get_event() tag = event.tag - if tag is None or tag == u'!': + if tag is None or tag == '!': tag = self.resolver.resolve(ScalarNode, event.value, event.implicit) node = ScalarNode( tag, @@ -162,7 +163,7 @@ class Composer(object): # type: (Any) -> Any start_event = self.parser.get_event() tag = start_event.tag - if tag is None or tag == u'!': + if tag is None or tag == '!': tag = self.resolver.resolve(SequenceNode, None, start_event.implicit) node = SequenceNode( tag, @@ -195,7 +196,7 @@ class Composer(object): # type: (Any) -> Any start_event = self.parser.get_event() tag = start_event.tag - if tag is None or tag == u'!': + if tag is None or tag == '!': tag = self.resolver.resolve(MappingNode, None, start_event.implicit) node = MappingNode( tag, diff --git a/constructor.py b/constructor.py index 3b16fe5..7a84bd1 100644 --- a/constructor.py +++ b/constructor.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function, absolute_import, division - import datetime import base64 import binascii @@ -9,16 +7,16 @@ import re import sys import types import warnings +from collections.abc import Hashable, MutableSequence, MutableMapping # type: ignore # fmt: off from ruamel.yaml.error import (MarkedYAMLError, MarkedYAMLFutureWarning, MantissaNoDotYAML1_1Warning) from ruamel.yaml.nodes import * # NOQA from ruamel.yaml.nodes import (SequenceNode, MappingNode, ScalarNode) -from ruamel.yaml.compat import (utf8, builtins_module, to_str, PY2, PY3, # NOQA - text_type, nprint, nprintf, version_tnf) -from ruamel.yaml.compat import ordereddict, Hashable, MutableSequence # type: ignore -from ruamel.yaml.compat import MutableMapping # type: ignore +from ruamel.yaml.compat import (_F, builtins_module, # NOQA + nprint, nprintf, version_tnf) +from ruamel.yaml.compat import ordereddict # type: ignore from ruamel.yaml.comments import * # NOQA from ruamel.yaml.comments import (CommentedMap, CommentedOrderedMap, CommentedSet, @@ -195,7 +193,10 @@ class BaseConstructor(object): # type: (Any) -> Any if not isinstance(node, ScalarNode): raise ConstructorError( - None, None, 'expected a scalar node, but found %s' % node.id, node.start_mark + None, + None, + _F('expected a scalar node, but found {node_id!s}', node_id=node.id), + node.start_mark, ) return node.value @@ -206,7 +207,10 @@ class BaseConstructor(object): """ if not isinstance(node, SequenceNode): raise ConstructorError( - None, None, 'expected a sequence node, but found %s' % node.id, node.start_mark + None, + None, + _F('expected a sequence node, but found {node_id!s}', node_id=node.id), + node.start_mark, ) return [self.construct_object(child, deep=deep) for child in node.value] @@ -217,7 +221,10 @@ class BaseConstructor(object): """ if not isinstance(node, MappingNode): raise ConstructorError( - None, None, 'expected a mapping node, but found %s' % node.id, node.start_mark + None, + None, + _F('expected a mapping node, but found {node_id!s}', node_id=node.id), + node.start_mark, ) total_mapping = self.yaml_base_dict_type() if getattr(node, 'merge', None) is not None: @@ -233,24 +240,13 @@ class BaseConstructor(object): if not isinstance(key, Hashable): if isinstance(key, list): key = tuple(key) - if PY2: - try: - hash(key) - except TypeError as exc: - raise ConstructorError( - 'while constructing a mapping', - node.start_mark, - 'found unacceptable key (%s)' % exc, - key_node.start_mark, - ) - else: - if not isinstance(key, Hashable): - raise ConstructorError( - 'while constructing a mapping', - node.start_mark, - 'found unhashable key', - key_node.start_mark, - ) + if not isinstance(key, Hashable): + raise ConstructorError( + 'while constructing a mapping', + node.start_mark, + 'found unhashable key', + key_node.start_mark, + ) value = self.construct_object(value_node, deep=deep) if check: @@ -267,13 +263,6 @@ class BaseConstructor(object): if key in mapping: if not self.allow_duplicate_keys: mk = mapping.get(key) - if PY2: - if isinstance(key, unicode): - key = key.encode('utf-8') - if isinstance(value, unicode): - value = value.encode('utf-8') - if isinstance(mk, unicode): - mk = mk.encode('utf-8') args = [ 'while constructing a mapping', node.start_mark, @@ -300,9 +289,6 @@ class BaseConstructor(object): # type: (Any, Any, Any, Any, Any) -> None if key in setting: if not self.allow_duplicate_keys: - if PY2: - if isinstance(key, unicode): - key = key.encode('utf-8') args = [ 'while constructing a set', node.start_mark, @@ -326,7 +312,10 @@ class BaseConstructor(object): # type: (Any, bool) -> Any if not isinstance(node, MappingNode): raise ConstructorError( - None, None, 'expected a mapping node, but found %s' % node.id, node.start_mark + None, + None, + _F('expected a mapping node, but found {node_id!s}', node_id=node.id), + node.start_mark, ) pairs = [] for key_node, value_node in node.value: @@ -355,7 +344,7 @@ class SafeConstructor(BaseConstructor): # type: (Any) -> Any if isinstance(node, MappingNode): for key_node, value_node in node.value: - if key_node.tag == u'tag:yaml.org,2002:value': + if key_node.tag == 'tag:yaml.org,2002:value': return self.construct_scalar(value_node) return BaseConstructor.construct_scalar(self, node) @@ -370,7 +359,7 @@ class SafeConstructor(BaseConstructor): index = 0 while index < len(node.value): key_node, value_node = node.value[index] - if key_node.tag == u'tag:yaml.org,2002:merge': + if key_node.tag == 'tag:yaml.org,2002:merge': if merge: # double << key if self.allow_duplicate_keys: del node.value[index] @@ -405,7 +394,10 @@ class SafeConstructor(BaseConstructor): raise ConstructorError( 'while constructing a mapping', node.start_mark, - 'expected a mapping for merging, but found %s' % subnode.id, + _F( + 'expected a mapping for merging, but found {subnode_id!s}', + subnode_id=subnode.id, + ), subnode.start_mark, ) self.flatten_mapping(subnode) @@ -417,12 +409,15 @@ class SafeConstructor(BaseConstructor): raise ConstructorError( 'while constructing a mapping', node.start_mark, - 'expected a mapping or list of mappings for merging, ' - 'but found %s' % value_node.id, + _F( + 'expected a mapping or list of mappings for merging, ' + 'but found {value_node_id!s}', + value_node_id=value_node.id, + ), value_node.start_mark, ) - elif key_node.tag == u'tag:yaml.org,2002:value': - key_node.tag = u'tag:yaml.org,2002:str' + elif key_node.tag == 'tag:yaml.org,2002:value': + key_node.tag = 'tag:yaml.org,2002:str' index += 1 else: index += 1 @@ -446,14 +441,14 @@ class SafeConstructor(BaseConstructor): # YAML 1.2 spec doesn't mention yes/no etc any more, 1.1 does bool_values = { - u'yes': True, - u'no': False, - u'y': True, - u'n': False, - u'true': True, - u'false': False, - u'on': True, - u'off': False, + 'yes': True, + 'no': False, + 'y': True, + 'n': False, + 'true': True, + 'false': False, + 'on': True, + 'off': False, } def construct_yaml_bool(self, node): @@ -463,7 +458,7 @@ class SafeConstructor(BaseConstructor): def construct_yaml_int(self, node): # type: (Any) -> int - value_s = to_str(self.construct_scalar(node)) + value_s = self.construct_scalar(node) value_s = value_s.replace('_', "") sign = +1 if value_s[0] == '-': @@ -499,7 +494,7 @@ class SafeConstructor(BaseConstructor): def construct_yaml_float(self, node): # type: (Any) -> float - value_so = to_str(self.construct_scalar(node)) + value_so = self.construct_scalar(node) value_s = value_so.replace('_', "").lower() sign = +1 if value_s[0] == '-': @@ -527,43 +522,32 @@ class SafeConstructor(BaseConstructor): warnings.warn(MantissaNoDotYAML1_1Warning(node, value_so)) return sign * float(value_s) - if PY3: - - def construct_yaml_binary(self, node): - # type: (Any) -> Any - try: - value = self.construct_scalar(node).encode('ascii') - except UnicodeEncodeError as exc: - raise ConstructorError( - None, - None, - 'failed to convert base64 data into ascii: %s' % exc, - node.start_mark, - ) - try: - if hasattr(base64, 'decodebytes'): - return base64.decodebytes(value) - else: - return base64.decodestring(value) - except binascii.Error as exc: - raise ConstructorError( - None, None, 'failed to decode base64 data: %s' % exc, node.start_mark - ) - - else: - - def construct_yaml_binary(self, node): - # type: (Any) -> Any - value = self.construct_scalar(node) - try: - return to_str(value).decode('base64') - except (binascii.Error, UnicodeEncodeError) as exc: - raise ConstructorError( - None, None, 'failed to decode base64 data: %s' % exc, node.start_mark - ) + def construct_yaml_binary(self, node): + # type: (Any) -> Any + try: + value = self.construct_scalar(node).encode('ascii') + except UnicodeEncodeError as exc: + raise ConstructorError( + None, + None, + _F('failed to convert base64 data into ascii: {exc!s}', exc=exc), + node.start_mark, + ) + try: + if hasattr(base64, 'decodebytes'): + return base64.decodebytes(value) + else: + return base64.decodestring(value) + except binascii.Error as exc: + raise ConstructorError( + None, + None, + _F('failed to decode base64 data: {exc!s}', exc=exc), + node.start_mark, + ) timestamp_regexp = RegExp( - u"""^(?P[0-9][0-9][0-9][0-9]) + """^(?P[0-9][0-9][0-9][0-9]) -(?P[0-9][0-9]?) -(?P[0-9][0-9]?) (?:((?P[Tt])|[ \\t]+) # explictly not retaining extra spaces @@ -637,7 +621,7 @@ class SafeConstructor(BaseConstructor): raise ConstructorError( 'while constructing an ordered map', node.start_mark, - 'expected a sequence, but found %s' % node.id, + _F('expected a sequence, but found {node_id!s}', node_id=node.id), node.start_mark, ) for subnode in node.value: @@ -645,14 +629,20 @@ class SafeConstructor(BaseConstructor): raise ConstructorError( 'while constructing an ordered map', node.start_mark, - 'expected a mapping of length 1, but found %s' % subnode.id, + _F( + 'expected a mapping of length 1, but found {subnode_id!s}', + subnode_id=subnode.id, + ), subnode.start_mark, ) if len(subnode.value) != 1: raise ConstructorError( 'while constructing an ordered map', node.start_mark, - 'expected a single mapping item, but found %d items' % len(subnode.value), + _F( + 'expected a single mapping item, but found {len_subnode_val:d} items', + len_subnode_val=len(subnode.value), + ), subnode.start_mark, ) key_node, value_node = subnode.value[0] @@ -670,7 +660,7 @@ class SafeConstructor(BaseConstructor): raise ConstructorError( 'while constructing pairs', node.start_mark, - 'expected a sequence, but found %s' % node.id, + _F('expected a sequence, but found {node_id!s}', node_id=node.id), node.start_mark, ) for subnode in node.value: @@ -678,14 +668,20 @@ class SafeConstructor(BaseConstructor): raise ConstructorError( 'while constructing pairs', node.start_mark, - 'expected a mapping of length 1, but found %s' % subnode.id, + _F( + 'expected a mapping of length 1, but found {subnode_id!s}', + subnode_id=subnode.id, + ), subnode.start_mark, ) if len(subnode.value) != 1: raise ConstructorError( 'while constructing pairs', node.start_mark, - 'expected a single mapping item, but found %d items' % len(subnode.value), + _F( + 'expected a single mapping item, but found {len_subnode_val:d} items', + len_subnode_val=len(subnode.value), + ), subnode.start_mark, ) key_node, value_node = subnode.value[0] @@ -703,12 +699,7 @@ class SafeConstructor(BaseConstructor): def construct_yaml_str(self, node): # type: (Any) -> Any value = self.construct_scalar(node) - if PY3: - return value - try: - return value.encode('ascii') - except UnicodeEncodeError: - return value + return value def construct_yaml_seq(self, node): # type: (Any) -> Any @@ -739,89 +730,85 @@ class SafeConstructor(BaseConstructor): raise ConstructorError( None, None, - 'could not determine a constructor for the tag %r' % utf8(node.tag), + _F( + 'could not determine a constructor for the tag {node_tag!r}', node_tag=node.tag + ), node.start_mark, ) -SafeConstructor.add_constructor(u'tag:yaml.org,2002:null', SafeConstructor.construct_yaml_null) +SafeConstructor.add_constructor('tag:yaml.org,2002:null', SafeConstructor.construct_yaml_null) -SafeConstructor.add_constructor(u'tag:yaml.org,2002:bool', SafeConstructor.construct_yaml_bool) +SafeConstructor.add_constructor('tag:yaml.org,2002:bool', SafeConstructor.construct_yaml_bool) -SafeConstructor.add_constructor(u'tag:yaml.org,2002:int', SafeConstructor.construct_yaml_int) +SafeConstructor.add_constructor('tag:yaml.org,2002:int', SafeConstructor.construct_yaml_int) SafeConstructor.add_constructor( - u'tag:yaml.org,2002:float', SafeConstructor.construct_yaml_float + 'tag:yaml.org,2002:float', SafeConstructor.construct_yaml_float ) SafeConstructor.add_constructor( - u'tag:yaml.org,2002:binary', SafeConstructor.construct_yaml_binary + 'tag:yaml.org,2002:binary', SafeConstructor.construct_yaml_binary ) SafeConstructor.add_constructor( - u'tag:yaml.org,2002:timestamp', SafeConstructor.construct_yaml_timestamp + 'tag:yaml.org,2002:timestamp', SafeConstructor.construct_yaml_timestamp ) -SafeConstructor.add_constructor(u'tag:yaml.org,2002:omap', SafeConstructor.construct_yaml_omap) +SafeConstructor.add_constructor('tag:yaml.org,2002:omap', SafeConstructor.construct_yaml_omap) SafeConstructor.add_constructor( - u'tag:yaml.org,2002:pairs', SafeConstructor.construct_yaml_pairs + 'tag:yaml.org,2002:pairs', SafeConstructor.construct_yaml_pairs ) -SafeConstructor.add_constructor(u'tag:yaml.org,2002:set', SafeConstructor.construct_yaml_set) +SafeConstructor.add_constructor('tag:yaml.org,2002:set', SafeConstructor.construct_yaml_set) -SafeConstructor.add_constructor(u'tag:yaml.org,2002:str', SafeConstructor.construct_yaml_str) +SafeConstructor.add_constructor('tag:yaml.org,2002:str', SafeConstructor.construct_yaml_str) -SafeConstructor.add_constructor(u'tag:yaml.org,2002:seq', SafeConstructor.construct_yaml_seq) +SafeConstructor.add_constructor('tag:yaml.org,2002:seq', SafeConstructor.construct_yaml_seq) -SafeConstructor.add_constructor(u'tag:yaml.org,2002:map', SafeConstructor.construct_yaml_map) +SafeConstructor.add_constructor('tag:yaml.org,2002:map', SafeConstructor.construct_yaml_map) SafeConstructor.add_constructor(None, SafeConstructor.construct_undefined) -if PY2: - - class classobj: - pass - class Constructor(SafeConstructor): def construct_python_str(self, node): # type: (Any) -> Any - return utf8(self.construct_scalar(node)) + return self.construct_scalar(node) def construct_python_unicode(self, node): # type: (Any) -> Any return self.construct_scalar(node) - if PY3: - - def construct_python_bytes(self, node): - # type: (Any) -> Any - try: - value = self.construct_scalar(node).encode('ascii') - except UnicodeEncodeError as exc: - raise ConstructorError( - None, - None, - 'failed to convert base64 data into ascii: %s' % exc, - node.start_mark, - ) - try: - if hasattr(base64, 'decodebytes'): - return base64.decodebytes(value) - else: - return base64.decodestring(value) - except binascii.Error as exc: - raise ConstructorError( - None, None, 'failed to decode base64 data: %s' % exc, node.start_mark - ) + def construct_python_bytes(self, node): + # type: (Any) -> Any + try: + value = self.construct_scalar(node).encode('ascii') + except UnicodeEncodeError as exc: + raise ConstructorError( + None, + None, + _F('failed to convert base64 data into ascii: {exc!s}', exc=exc), + node.start_mark, + ) + try: + if hasattr(base64, 'decodebytes'): + return base64.decodebytes(value) + else: + return base64.decodestring(value) + except binascii.Error as exc: + raise ConstructorError( + None, + None, + _F('failed to decode base64 data: {exc!s}', exc=exc), + node.start_mark, + ) def construct_python_long(self, node): # type: (Any) -> int val = self.construct_yaml_int(node) - if PY3: - return val - return int(val) + return val def construct_python_complex(self, node): # type: (Any) -> Any @@ -846,7 +833,7 @@ class Constructor(SafeConstructor): raise ConstructorError( 'while constructing a Python module', mark, - 'cannot find module %r (%s)' % (utf8(name), exc), + _F('cannot find module {name!r} ({exc!s})', name=name, exc=exc), mark, ) return sys.modules[name] @@ -860,7 +847,7 @@ class Constructor(SafeConstructor): 'expected non-empty name appended to the tag', mark, ) - if u'.' in name: + if '.' in name: lname = name.split('.') lmodule_name = lname lobject_name = [] # type: List[Any] @@ -882,7 +869,11 @@ class Constructor(SafeConstructor): raise ConstructorError( 'while constructing a Python object', mark, - 'cannot find module %r (%s)' % (utf8(module_name), exc), + _F( + 'cannot find module {module_name!r} ({exc!s})', + module_name=module_name, + exc=exc, + ), mark, ) module = sys.modules[module_name] @@ -894,7 +885,11 @@ class Constructor(SafeConstructor): raise ConstructorError( 'while constructing a Python object', mark, - 'cannot find %r in the module %r' % (utf8(object_name), module.__name__), + _F( + 'cannot find {object_name!r} in the module {module_name!r}', + object_name=object_name, + module_name=module.__name__, + ), mark, ) obj = getattr(obj, lobject_name.pop(0)) @@ -907,7 +902,7 @@ class Constructor(SafeConstructor): raise ConstructorError( 'while constructing a Python name', node.start_mark, - 'expected the empty value, but found %r' % utf8(value), + _F('expected the empty value, but found {value!r}', value=value), node.start_mark, ) return self.find_python_name(suffix, node.start_mark) @@ -919,7 +914,7 @@ class Constructor(SafeConstructor): raise ConstructorError( 'while constructing a Python module', node.start_mark, - 'expected the empty value, but found %r' % utf8(value), + _F('expected the empty value, but found {value!r}', value=value), node.start_mark, ) return self.find_python_module(suffix, node.start_mark) @@ -931,20 +926,10 @@ class Constructor(SafeConstructor): if not kwds: kwds = {} cls = self.find_python_name(suffix, node.start_mark) - if PY3: - if newobj and isinstance(cls, type): - return cls.__new__(cls, *args, **kwds) - else: - return cls(*args, **kwds) + if newobj and isinstance(cls, type): + return cls.__new__(cls, *args, **kwds) else: - if newobj and isinstance(cls, type(classobj)) and not args and not kwds: - instance = classobj() - instance.__class__ = cls - return instance - elif newobj and isinstance(cls, type): - return cls.__new__(cls, *args, **kwds) - else: - return cls(*args, **kwds) + return cls(*args, **kwds) def set_python_instance_state(self, instance, state): # type: (Any, Any) -> None @@ -1013,61 +998,60 @@ class Constructor(SafeConstructor): return self.construct_python_object_apply(suffix, node, newobj=True) -Constructor.add_constructor(u'tag:yaml.org,2002:python/none', Constructor.construct_yaml_null) +Constructor.add_constructor('tag:yaml.org,2002:python/none', Constructor.construct_yaml_null) -Constructor.add_constructor(u'tag:yaml.org,2002:python/bool', Constructor.construct_yaml_bool) +Constructor.add_constructor('tag:yaml.org,2002:python/bool', Constructor.construct_yaml_bool) -Constructor.add_constructor(u'tag:yaml.org,2002:python/str', Constructor.construct_python_str) +Constructor.add_constructor('tag:yaml.org,2002:python/str', Constructor.construct_python_str) Constructor.add_constructor( - u'tag:yaml.org,2002:python/unicode', Constructor.construct_python_unicode + 'tag:yaml.org,2002:python/unicode', Constructor.construct_python_unicode ) -if PY3: - Constructor.add_constructor( - u'tag:yaml.org,2002:python/bytes', Constructor.construct_python_bytes - ) +Constructor.add_constructor( + 'tag:yaml.org,2002:python/bytes', Constructor.construct_python_bytes +) -Constructor.add_constructor(u'tag:yaml.org,2002:python/int', Constructor.construct_yaml_int) +Constructor.add_constructor('tag:yaml.org,2002:python/int', Constructor.construct_yaml_int) Constructor.add_constructor( - u'tag:yaml.org,2002:python/long', Constructor.construct_python_long + 'tag:yaml.org,2002:python/long', Constructor.construct_python_long ) Constructor.add_constructor( - u'tag:yaml.org,2002:python/float', Constructor.construct_yaml_float + 'tag:yaml.org,2002:python/float', Constructor.construct_yaml_float ) Constructor.add_constructor( - u'tag:yaml.org,2002:python/complex', Constructor.construct_python_complex + 'tag:yaml.org,2002:python/complex', Constructor.construct_python_complex ) -Constructor.add_constructor(u'tag:yaml.org,2002:python/list', Constructor.construct_yaml_seq) +Constructor.add_constructor('tag:yaml.org,2002:python/list', Constructor.construct_yaml_seq) Constructor.add_constructor( - u'tag:yaml.org,2002:python/tuple', Constructor.construct_python_tuple + 'tag:yaml.org,2002:python/tuple', Constructor.construct_python_tuple ) -Constructor.add_constructor(u'tag:yaml.org,2002:python/dict', Constructor.construct_yaml_map) +Constructor.add_constructor('tag:yaml.org,2002:python/dict', Constructor.construct_yaml_map) Constructor.add_multi_constructor( - u'tag:yaml.org,2002:python/name:', Constructor.construct_python_name + 'tag:yaml.org,2002:python/name:', Constructor.construct_python_name ) Constructor.add_multi_constructor( - u'tag:yaml.org,2002:python/module:', Constructor.construct_python_module + 'tag:yaml.org,2002:python/module:', Constructor.construct_python_module ) Constructor.add_multi_constructor( - u'tag:yaml.org,2002:python/object:', Constructor.construct_python_object + 'tag:yaml.org,2002:python/object:', Constructor.construct_python_object ) Constructor.add_multi_constructor( - u'tag:yaml.org,2002:python/object/apply:', Constructor.construct_python_object_apply + 'tag:yaml.org,2002:python/object/apply:', Constructor.construct_python_object_apply ) Constructor.add_multi_constructor( - u'tag:yaml.org,2002:python/object/new:', Constructor.construct_python_object_new + 'tag:yaml.org,2002:python/object/new:', Constructor.construct_python_object_new ) @@ -1080,15 +1064,18 @@ class RoundTripConstructor(SafeConstructor): # type: (Any) -> Any if not isinstance(node, ScalarNode): raise ConstructorError( - None, None, 'expected a scalar node, but found %s' % node.id, node.start_mark + None, + None, + _F('expected a scalar node, but found {node_id!s}', node_id=node.id), + node.start_mark, ) - if node.style == '|' and isinstance(node.value, text_type): + if node.style == '|' and isinstance(node.value, str): lss = LiteralScalarString(node.value, anchor=node.anchor) if node.comment and node.comment[1]: lss.comment = node.comment[1][0] # type: ignore return lss - if node.style == '>' and isinstance(node.value, text_type): + if node.style == '>' and isinstance(node.value, str): fold_positions = [] # type: List[int] idx = -1 while True: @@ -1102,7 +1089,7 @@ class RoundTripConstructor(SafeConstructor): if fold_positions: fss.fold_pos = fold_positions # type: ignore return fss - elif bool(self._preserve_quotes) and isinstance(node.value, text_type): + elif bool(self._preserve_quotes) and isinstance(node.value, str): if node.style == "'": return SingleQuotedScalarString(node.value, anchor=node.anchor) if node.style == '"': @@ -1114,7 +1101,7 @@ class RoundTripConstructor(SafeConstructor): def construct_yaml_int(self, node): # type: (Any) -> Any width = None # type: Any - value_su = to_str(self.construct_scalar(node)) + value_su = self.construct_scalar(node) try: sx = value_su.rstrip('_') underscore = [len(sx) - sx.rindex('_') - 1, False, False] # type: Any @@ -1216,7 +1203,7 @@ class RoundTripConstructor(SafeConstructor): # underscore = None m_sign = False # type: Any - value_so = to_str(self.construct_scalar(node)) + value_so = self.construct_scalar(node) value_s = value_so.replace('_', "").lower() sign = +1 if value_s[0] == '-': @@ -1284,21 +1271,16 @@ class RoundTripConstructor(SafeConstructor): value = self.construct_scalar(node) if isinstance(value, ScalarString): return value - if PY3: - return value - try: - return value.encode('ascii') - except AttributeError: - # in case you replace the node dynamically e.g. with a dict - return value - except UnicodeEncodeError: - return value + return value def construct_rt_sequence(self, node, seqtyp, deep=False): # type: (Any, Any, bool) -> Any if not isinstance(node, SequenceNode): raise ConstructorError( - None, None, 'expected a sequence node, but found %s' % node.id, node.start_mark + None, + None, + _F('expected a sequence node, but found {node_id!s}', node_id=node.id), + node.start_mark, ) ret_val = [] if node.comment: @@ -1345,7 +1327,7 @@ class RoundTripConstructor(SafeConstructor): index = 0 while index < len(node.value): key_node, value_node = node.value[index] - if key_node.tag == u'tag:yaml.org,2002:merge': + if key_node.tag == 'tag:yaml.org,2002:merge': if merge_map_list: # double << key if self.allow_duplicate_keys: del node.value[index] @@ -1381,7 +1363,10 @@ class RoundTripConstructor(SafeConstructor): raise ConstructorError( 'while constructing a mapping', node.start_mark, - 'expected a mapping for merging, but found %s' % subnode.id, + _F( + 'expected a mapping for merging, but found {subnode_id!s}', + subnode_id=subnode.id, + ), subnode.start_mark, ) merge_map_list.append((index, constructed(subnode))) @@ -1394,12 +1379,15 @@ class RoundTripConstructor(SafeConstructor): raise ConstructorError( 'while constructing a mapping', node.start_mark, - 'expected a mapping or list of mappings for merging, ' - 'but found %s' % value_node.id, + _F( + 'expected a mapping or list of mappings for merging, ' + 'but found {value_node_id!s}', + value_node_id=value_node.id, + ), value_node.start_mark, ) - elif key_node.tag == u'tag:yaml.org,2002:value': - key_node.tag = u'tag:yaml.org,2002:str' + elif key_node.tag == 'tag:yaml.org,2002:value': + key_node.tag = 'tag:yaml.org,2002:str' index += 1 else: index += 1 @@ -1415,7 +1403,10 @@ class RoundTripConstructor(SafeConstructor): # type: (Any, Any, bool) -> Any if not isinstance(node, MappingNode): raise ConstructorError( - None, None, 'expected a mapping node, but found %s' % node.id, node.start_mark + None, + None, + _F('expected a mapping node, but found {node_id!s}', node_id=node.id), + node.start_mark, ) merge_map = self.flatten_mapping(node) # mapping = {} @@ -1448,24 +1439,13 @@ class RoundTripConstructor(SafeConstructor): elif key_node.flow_style is False: key_m.fa.set_block_style() key = key_m - if PY2: - try: - hash(key) - except TypeError as exc: - raise ConstructorError( - 'while constructing a mapping', - node.start_mark, - 'found unacceptable key (%s)' % exc, - key_node.start_mark, - ) - else: - if not isinstance(key, Hashable): - raise ConstructorError( - 'while constructing a mapping', - node.start_mark, - 'found unhashable key', - key_node.start_mark, - ) + if not isinstance(key, Hashable): + raise ConstructorError( + 'while constructing a mapping', + node.start_mark, + 'found unhashable key', + key_node.start_mark, + ) value = self.construct_object(value_node, deep=deep) if self.check_mapping_key(node, key_node, maptyp, key, value): if key_node.comment and len(key_node.comment) > 4 and key_node.comment[4]: @@ -1500,7 +1480,10 @@ class RoundTripConstructor(SafeConstructor): # type: (Any, Any, bool) -> Any if not isinstance(node, MappingNode): raise ConstructorError( - None, None, 'expected a mapping node, but found %s' % node.id, node.start_mark + None, + None, + _F('expected a mapping node, but found {node_id!s}', node_id=node.id), + node.start_mark, ) if node.comment: typ._yaml_add_comment(node.comment[:2]) @@ -1518,24 +1501,13 @@ class RoundTripConstructor(SafeConstructor): if not isinstance(key, Hashable): if isinstance(key, list): key = tuple(key) - if PY2: - try: - hash(key) - except TypeError as exc: - raise ConstructorError( - 'while constructing a mapping', - node.start_mark, - 'found unacceptable key (%s)' % exc, - key_node.start_mark, - ) - else: - if not isinstance(key, Hashable): - raise ConstructorError( - 'while constructing a mapping', - node.start_mark, - 'found unhashable key', - key_node.start_mark, - ) + if not isinstance(key, Hashable): + raise ConstructorError( + 'while constructing a mapping', + node.start_mark, + 'found unhashable key', + key_node.start_mark, + ) # construct but should be null value = self.construct_object(value_node, deep=deep) # NOQA self.check_set_key(node, key_node, typ, key) @@ -1601,7 +1573,7 @@ class RoundTripConstructor(SafeConstructor): raise ConstructorError( 'while constructing an ordered map', node.start_mark, - 'expected a sequence, but found %s' % node.id, + _F('expected a sequence, but found {node_id!s}', node_id=node.id), node.start_mark, ) for subnode in node.value: @@ -1609,14 +1581,20 @@ class RoundTripConstructor(SafeConstructor): raise ConstructorError( 'while constructing an ordered map', node.start_mark, - 'expected a mapping of length 1, but found %s' % subnode.id, + _F( + 'expected a mapping of length 1, but found {subnode_id!s}', + subnode_id=subnode.id, + ), subnode.start_mark, ) if len(subnode.value) != 1: raise ConstructorError( 'while constructing an ordered map', node.start_mark, - 'expected a single mapping item, but found %d items' % len(subnode.value), + _F( + 'expected a single mapping item, but found {len_subnode_val:d} items', + len_subnode_val=len(subnode.value), + ), subnode.start_mark, ) key_node, value_node = subnode.value[0] @@ -1681,7 +1659,9 @@ class RoundTripConstructor(SafeConstructor): raise ConstructorError( None, None, - 'could not determine a constructor for the tag %r' % utf8(node.tag), + _F( + 'could not determine a constructor for the tag {node_tag!r}', node_tag=node.tag + ), node.start_mark, ) @@ -1756,51 +1736,51 @@ class RoundTripConstructor(SafeConstructor): RoundTripConstructor.add_constructor( - u'tag:yaml.org,2002:null', RoundTripConstructor.construct_yaml_null + 'tag:yaml.org,2002:null', RoundTripConstructor.construct_yaml_null ) RoundTripConstructor.add_constructor( - u'tag:yaml.org,2002:bool', RoundTripConstructor.construct_yaml_bool + 'tag:yaml.org,2002:bool', RoundTripConstructor.construct_yaml_bool ) RoundTripConstructor.add_constructor( - u'tag:yaml.org,2002:int', RoundTripConstructor.construct_yaml_int + 'tag:yaml.org,2002:int', RoundTripConstructor.construct_yaml_int ) RoundTripConstructor.add_constructor( - u'tag:yaml.org,2002:float', RoundTripConstructor.construct_yaml_float + 'tag:yaml.org,2002:float', RoundTripConstructor.construct_yaml_float ) RoundTripConstructor.add_constructor( - u'tag:yaml.org,2002:binary', RoundTripConstructor.construct_yaml_binary + 'tag:yaml.org,2002:binary', RoundTripConstructor.construct_yaml_binary ) RoundTripConstructor.add_constructor( - u'tag:yaml.org,2002:timestamp', RoundTripConstructor.construct_yaml_timestamp + 'tag:yaml.org,2002:timestamp', RoundTripConstructor.construct_yaml_timestamp ) RoundTripConstructor.add_constructor( - u'tag:yaml.org,2002:omap', RoundTripConstructor.construct_yaml_omap + 'tag:yaml.org,2002:omap', RoundTripConstructor.construct_yaml_omap ) RoundTripConstructor.add_constructor( - u'tag:yaml.org,2002:pairs', RoundTripConstructor.construct_yaml_pairs + 'tag:yaml.org,2002:pairs', RoundTripConstructor.construct_yaml_pairs ) RoundTripConstructor.add_constructor( - u'tag:yaml.org,2002:set', RoundTripConstructor.construct_yaml_set + 'tag:yaml.org,2002:set', RoundTripConstructor.construct_yaml_set ) RoundTripConstructor.add_constructor( - u'tag:yaml.org,2002:str', RoundTripConstructor.construct_yaml_str + 'tag:yaml.org,2002:str', RoundTripConstructor.construct_yaml_str ) RoundTripConstructor.add_constructor( - u'tag:yaml.org,2002:seq', RoundTripConstructor.construct_yaml_seq + 'tag:yaml.org,2002:seq', RoundTripConstructor.construct_yaml_seq ) RoundTripConstructor.add_constructor( - u'tag:yaml.org,2002:map', RoundTripConstructor.construct_yaml_map + 'tag:yaml.org,2002:map', RoundTripConstructor.construct_yaml_map ) RoundTripConstructor.add_constructor(None, RoundTripConstructor.construct_undefined) diff --git a/cyaml.py b/cyaml.py index 7a808a5..0ab2828 100644 --- a/cyaml.py +++ b/cyaml.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import absolute_import - from _ruamel_yaml import CParser, CEmitter # type: ignore from ruamel.yaml.constructor import Constructor, BaseConstructor, SafeConstructor diff --git a/dumper.py b/dumper.py index 5d99b4f..7e9bf01 100644 --- a/dumper.py +++ b/dumper.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import absolute_import - from ruamel.yaml.emitter import Emitter from ruamel.yaml.serializer import Serializer from ruamel.yaml.representer import ( diff --git a/emitter.py b/emitter.py index f8c5e16..f5313a0 100644 --- a/emitter.py +++ b/emitter.py @@ -1,8 +1,5 @@ # coding: utf-8 -from __future__ import absolute_import -from __future__ import print_function - # Emitter expects events obeying the following grammar: # stream ::= STREAM-START document* STREAM-END # document ::= DOCUMENT-START node DOCUMENT-END @@ -15,7 +12,7 @@ from ruamel.yaml.error import YAMLError, YAMLStreamError from ruamel.yaml.events import * # NOQA # fmt: off -from ruamel.yaml.compat import utf8, text_type, PY2, nprint, dbg, DBG_EVENT, \ +from ruamel.yaml.compat import _F, nprint, dbg, DBG_EVENT, \ check_anchorname_char # fmt: on @@ -93,8 +90,8 @@ class Indents(object): class Emitter(object): # fmt: off DEFAULT_TAG_PREFIXES = { - u'!': u'!', - u'tag:yaml.org,2002:': u'!!', + '!': '!', + 'tag:yaml.org,2002:': '!!', } # fmt: on @@ -165,7 +162,7 @@ class Emitter(object): self.open_ended = False # colon handling - self.colon = u':' + self.colon = ':' self.prefixed_colon = self.colon if prefix_colon is None else prefix_colon + self.colon # single entry mappings in flow sequence self.brace_single_entry_mapping_in_flow_sequence = ( @@ -189,8 +186,8 @@ class Emitter(object): self.best_width = 80 if width and width > self.best_sequence_indent * 2: self.best_width = width - self.best_line_break = u'\n' # type: Any - if line_break in [u'\r', u'\n', u'\r\n']: + self.best_line_break = '\n' # type: Any + if line_break in ['\r', '\n', '\r\n']: self.best_line_break = line_break # Tag prefixes. @@ -316,20 +313,20 @@ class Emitter(object): def expect_stream_start(self): # type: () -> None if isinstance(self.event, StreamStartEvent): - if PY2: - if self.event.encoding and not getattr(self.stream, 'encoding', None): - self.encoding = self.event.encoding - else: - if self.event.encoding and not hasattr(self.stream, 'encoding'): - self.encoding = self.event.encoding + if self.event.encoding and not hasattr(self.stream, 'encoding'): + self.encoding = self.event.encoding self.write_stream_start() self.state = self.expect_first_document_start else: - raise EmitterError('expected StreamStartEvent, but got %s' % (self.event,)) + raise EmitterError( + _F('expected StreamStartEvent, but got {self_event!s}', self_event=self.event) + ) def expect_nothing(self): # type: () -> None - raise EmitterError('expected nothing, but got %s' % (self.event,)) + raise EmitterError( + _F('expected nothing, but got {self_event!s}', self_event=self.event) + ) # Document handlers. @@ -341,7 +338,7 @@ class Emitter(object): # type: (bool) -> None if isinstance(self.event, DocumentStartEvent): if (self.event.version or self.event.tags) and self.open_ended: - self.write_indicator(u'...', True) + self.write_indicator('...', True) self.write_indent() if self.event.version: version_text = self.prepare_version(self.event.version) @@ -365,30 +362,37 @@ class Emitter(object): ) if not implicit: self.write_indent() - self.write_indicator(u'---', True) + self.write_indicator('---', True) if self.canonical: self.write_indent() self.state = self.expect_document_root elif isinstance(self.event, StreamEndEvent): if self.open_ended: - self.write_indicator(u'...', True) + self.write_indicator('...', True) self.write_indent() self.write_stream_end() self.state = self.expect_nothing else: - raise EmitterError('expected DocumentStartEvent, but got %s' % (self.event,)) + raise EmitterError( + _F( + 'expected DocumentStartEvent, but got {self_event!s}', + self_event=self.event, + ) + ) def expect_document_end(self): # type: () -> None if isinstance(self.event, DocumentEndEvent): self.write_indent() if self.event.explicit: - self.write_indicator(u'...', True) + self.write_indicator('...', True) self.write_indent() self.flush_stream() self.state = self.expect_document_start else: - raise EmitterError('expected DocumentEndEvent, but got %s' % (self.event,)) + raise EmitterError( + _F('expected DocumentEndEvent, but got {self_event!s}', self_event=self.event) + ) def expect_document_root(self): # type: () -> None @@ -407,7 +411,7 @@ class Emitter(object): self.expect_alias() elif isinstance(self.event, (ScalarEvent, CollectionStartEvent)): if ( - self.process_anchor(u'&') + self.process_anchor('&') and isinstance(self.event, ScalarEvent) and self.sequence_context ): @@ -457,13 +461,15 @@ class Emitter(object): else: self.expect_block_mapping() else: - raise EmitterError('expected NodeEvent, but got %s' % (self.event,)) + raise EmitterError( + _F('expected NodeEvent, but got {self_event!s}', self_event=self.event) + ) def expect_alias(self): # type: () -> None if self.event.anchor is None: raise EmitterError('anchor is not specified for alias') - self.process_anchor(u'*') + self.process_anchor('*') self.state = self.states.pop() def expect_scalar(self): @@ -478,7 +484,7 @@ class Emitter(object): def expect_flow_sequence(self): # type: () -> None ind = self.indents.seq_flow_align(self.best_sequence_indent, self.column) - self.write_indicator(u' ' * ind + u'[', True, whitespace=True) + self.write_indicator(' ' * ind + '[', True, whitespace=True) self.increase_indent(flow=True, sequence=True) self.flow_context.append('[') self.state = self.expect_first_flow_sequence_item @@ -489,7 +495,7 @@ class Emitter(object): self.indent = self.indents.pop() popped = self.flow_context.pop() assert popped == '[' - self.write_indicator(u']', False) + self.write_indicator(']', False) if self.event.comment and self.event.comment[0]: # eol comment on empty flow sequence self.write_post_comment(self.event) @@ -509,9 +515,9 @@ class Emitter(object): popped = self.flow_context.pop() assert popped == '[' if self.canonical: - self.write_indicator(u',', False) + self.write_indicator(',', False) self.write_indent() - self.write_indicator(u']', False) + self.write_indicator(']', False) if self.event.comment and self.event.comment[0]: # eol comment on flow sequence self.write_post_comment(self.event) @@ -519,7 +525,7 @@ class Emitter(object): self.no_newline = False self.state = self.states.pop() else: - self.write_indicator(u',', False) + self.write_indicator(',', False) if self.canonical or self.column > self.best_width: self.write_indent() self.states.append(self.expect_flow_sequence_item) @@ -530,7 +536,7 @@ class Emitter(object): def expect_flow_mapping(self, single=False): # type: (Optional[bool]) -> None ind = self.indents.seq_flow_align(self.best_sequence_indent, self.column) - map_init = u'{' + map_init = '{' if ( single and self.flow_level @@ -539,8 +545,8 @@ class Emitter(object): and not self.brace_single_entry_mapping_in_flow_sequence ): # single map item with flow context, no curly braces necessary - map_init = u'' - self.write_indicator(u' ' * ind + map_init, True, whitespace=True) + map_init = '' + self.write_indicator(' ' * ind + map_init, True, whitespace=True) self.flow_context.append(map_init) self.increase_indent(flow=True, sequence=False) self.state = self.expect_first_flow_mapping_key @@ -551,7 +557,7 @@ class Emitter(object): self.indent = self.indents.pop() popped = self.flow_context.pop() assert popped == '{' # empty flow mapping - self.write_indicator(u'}', False) + self.write_indicator('}', False) if self.event.comment and self.event.comment[0]: # eol comment on empty mapping self.write_post_comment(self.event) @@ -565,7 +571,7 @@ class Emitter(object): self.states.append(self.expect_flow_mapping_simple_value) self.expect_node(mapping=True, simple_key=True) else: - self.write_indicator(u'?', True) + self.write_indicator('?', True) self.states.append(self.expect_flow_mapping_value) self.expect_node(mapping=True) @@ -576,12 +582,12 @@ class Emitter(object): # self.write_pre_comment(self.event) self.indent = self.indents.pop() popped = self.flow_context.pop() - assert popped in [u'{', u''] + assert popped in ['{', ''] if self.canonical: - self.write_indicator(u',', False) + self.write_indicator(',', False) self.write_indent() - if popped != u'': - self.write_indicator(u'}', False) + if popped != '': + self.write_indicator('}', False) if self.event.comment and self.event.comment[0]: # eol comment on flow mapping, never reached on empty mappings self.write_post_comment(self.event) @@ -589,14 +595,14 @@ class Emitter(object): self.no_newline = False self.state = self.states.pop() else: - self.write_indicator(u',', False) + self.write_indicator(',', False) if self.canonical or self.column > self.best_width: self.write_indent() if not self.canonical and self.check_simple_key(): self.states.append(self.expect_flow_mapping_simple_value) self.expect_node(mapping=True, simple_key=True) else: - self.write_indicator(u'?', True) + self.write_indicator('?', True) self.states.append(self.expect_flow_mapping_value) self.expect_node(mapping=True) @@ -646,7 +652,7 @@ class Emitter(object): nonl = self.no_newline if self.column == 0 else False self.write_indent() ind = self.sequence_dash_offset # if len(self.indents) > 1 else 0 - self.write_indicator(u' ' * ind + u'-', True, indention=True) + self.write_indicator(' ' * ind + '-', True, indention=True) if nonl or self.sequence_dash_offset + 2 > self.best_sequence_indent: self.no_newline = True self.states.append(self.expect_block_sequence_item) @@ -684,25 +690,25 @@ class Emitter(object): ): # sequence keys try: if self.event.style == '?': - self.write_indicator(u'?', True, indention=True) + self.write_indicator('?', True, indention=True) except AttributeError: # aliases have no style pass self.states.append(self.expect_block_mapping_simple_value) self.expect_node(mapping=True, simple_key=True) if isinstance(self.event, AliasEvent): - self.stream.write(u' ') + self.stream.write(' ') else: - self.write_indicator(u'?', True, indention=True) + self.write_indicator('?', True, indention=True) self.states.append(self.expect_block_mapping_value) self.expect_node(mapping=True) def expect_block_mapping_simple_value(self): # type: () -> None if getattr(self.event, 'style', None) != '?': - # prefix = u'' + # prefix = '' if self.indent == 0 and self.top_level_colon_align is not None: # write non-prefixed colon - c = u' ' * (self.top_level_colon_align - self.column) + self.colon + c = ' ' * (self.top_level_colon_align - self.column) + self.colon else: c = self.prefixed_colon self.write_indicator(c, False) @@ -801,8 +807,12 @@ class Emitter(object): if isinstance(self.event, ScalarEvent): if self.style is None: self.style = self.choose_scalar_style() - if self.event.value == '' and self.style == "'" and \ - tag == 'tag:yaml.org,2002:null' and self.alt_null is not None: + if ( + self.event.value == '' + and self.style == "'" + and tag == 'tag:yaml.org,2002:null' + and self.alt_null is not None + ): self.event.value = self.alt_null self.analysis = None self.style = self.choose_scalar_style() @@ -813,7 +823,7 @@ class Emitter(object): self.prepared_tag = None return if self.event.implicit[0] and tag is None: - tag = u'!' + tag = '!' self.prepared_tag = None else: if (not self.canonical or tag is None) and self.event.implicit: @@ -902,21 +912,29 @@ class Emitter(object): # type: (Any) -> Any major, minor = version if major != 1: - raise EmitterError('unsupported YAML version: %d.%d' % (major, minor)) - return u'%d.%d' % (major, minor) + raise EmitterError( + _F('unsupported YAML version: {major:d}.{minor:d}', major=major, minor=minor) + ) + return _F('{major:d}.{minor:d}', major=major, minor=minor) def prepare_tag_handle(self, handle): # type: (Any) -> Any if not handle: raise EmitterError('tag handle must not be empty') - if handle[0] != u'!' or handle[-1] != u'!': - raise EmitterError("tag handle must start and end with '!': %r" % (utf8(handle))) + if handle[0] != '!' or handle[-1] != '!': + raise EmitterError( + _F("tag handle must start and end with '!': {handle!r}", handle=handle) + ) for ch in handle[1:-1]: if not ( - u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' or ch in u'-_' + '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z' or ch in '-_' ): raise EmitterError( - 'invalid character %r in the tag handle: %r' % (utf8(ch), utf8(handle)) + _F( + 'invalid character {ch!r} in the tag handle: {handle!r}', + ch=ch, + handle=handle, + ) ) return handle @@ -926,24 +944,24 @@ class Emitter(object): raise EmitterError('tag prefix must not be empty') chunks = [] # type: List[Any] start = end = 0 - if prefix[0] == u'!': + if prefix[0] == '!': end = 1 - ch_set = u"-;/?:@&=+$,_.~*'()[]" + ch_set = "-;/?:@&=+$,_.~*'()[]" if self.dumper: version = getattr(self.dumper, 'version', (1, 2)) if version is None or version >= (1, 2): - ch_set += u'#' + ch_set += '#' while end < len(prefix): ch = prefix[end] - if u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' or ch in ch_set: + if '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z' or ch in ch_set: end += 1 else: if start < end: chunks.append(prefix[start:end]) start = end = end + 1 - data = utf8(ch) + data = ch for ch in data: - chunks.append(u'%%%02X' % ord(ch)) + chunks.append(_F('%{ord_ch:02X}', ord_ch=ord(ch))) if start < end: chunks.append(prefix[start:end]) return "".join(chunks) @@ -952,46 +970,46 @@ class Emitter(object): # type: (Any) -> Any if not tag: raise EmitterError('tag must not be empty') - if tag == u'!': + if tag == '!': return tag handle = None suffix = tag prefixes = sorted(self.tag_prefixes.keys()) for prefix in prefixes: - if tag.startswith(prefix) and (prefix == u'!' or len(prefix) < len(tag)): + if tag.startswith(prefix) and (prefix == '!' or len(prefix) < len(tag)): handle = self.tag_prefixes[prefix] suffix = tag[len(prefix) :] chunks = [] # type: List[Any] start = end = 0 - ch_set = u"-;/?:@&=+$,_.~*'()[]" + ch_set = "-;/?:@&=+$,_.~*'()[]" if self.dumper: version = getattr(self.dumper, 'version', (1, 2)) if version is None or version >= (1, 2): - ch_set += u'#' + ch_set += '#' while end < len(suffix): ch = suffix[end] if ( - u'0' <= ch <= u'9' - or u'A' <= ch <= u'Z' - or u'a' <= ch <= u'z' + '0' <= ch <= '9' + or 'A' <= ch <= 'Z' + or 'a' <= ch <= 'z' or ch in ch_set - or (ch == u'!' and handle != u'!') + or (ch == '!' and handle != '!') ): end += 1 else: if start < end: chunks.append(suffix[start:end]) start = end = end + 1 - data = utf8(ch) + data = ch for ch in data: - chunks.append(u'%%%02X' % ord(ch)) + chunks.append(_F('%{ord_ch:02X}', ord_ch=ord(ch))) if start < end: chunks.append(suffix[start:end]) suffix_text = "".join(chunks) if handle: - return u'%s%s' % (handle, suffix_text) + return _F('{handle!s}{suffix_text!s}', handle=handle, suffix_text=suffix_text) else: - return u'!<%s>' % suffix_text + return _F('!<{suffix_text!s}>', suffix_text=suffix_text) def prepare_anchor(self, anchor): # type: (Any) -> Any @@ -1000,7 +1018,11 @@ class Emitter(object): for ch in anchor: if not check_anchorname_char(ch): raise EmitterError( - 'invalid character %r in the anchor: %r' % (utf8(ch), utf8(anchor)) + _F( + 'invalid character {ch!r} in the anchor: {anchor!r}', + ch=ch, + anchor=anchor, + ) ) return anchor @@ -1034,7 +1056,7 @@ class Emitter(object): space_break = False # Check document indicators. - if scalar.startswith(u'---') or scalar.startswith(u'...'): + if scalar.startswith('---') or scalar.startswith('...'): block_indicators = True flow_indicators = True @@ -1042,7 +1064,7 @@ class Emitter(object): preceeded_by_whitespace = True # Last character or followed by a whitespace. - followed_by_whitespace = len(scalar) == 1 or scalar[1] in u'\0 \t\r\n\x85\u2028\u2029' + followed_by_whitespace = len(scalar) == 1 or scalar[1] in '\0 \t\r\n\x85\u2028\u2029' # The previous character is a space. previous_space = False @@ -1057,43 +1079,43 @@ class Emitter(object): # Check for indicators. if index == 0: # Leading indicators are special characters. - if ch in u'#,[]{}&*!|>\'"%@`': + if ch in '#,[]{}&*!|>\'"%@`': flow_indicators = True block_indicators = True - if ch in u'?:': # ToDo + if ch in '?:': # ToDo if self.serializer.use_version == (1, 1): flow_indicators = True elif len(scalar) == 1: # single character flow_indicators = True if followed_by_whitespace: block_indicators = True - if ch == u'-' and followed_by_whitespace: + if ch == '-' and followed_by_whitespace: flow_indicators = True block_indicators = True else: # Some indicators cannot appear within a scalar as well. - if ch in u',[]{}': # http://yaml.org/spec/1.2/spec.html#id2788859 + if ch in ',[]{}': # http://yaml.org/spec/1.2/spec.html#id2788859 flow_indicators = True - if ch == u'?' and self.serializer.use_version == (1, 1): + if ch == '?' and self.serializer.use_version == (1, 1): flow_indicators = True - if ch == u':': + if ch == ':': if followed_by_whitespace: flow_indicators = True block_indicators = True - if ch == u'#' and preceeded_by_whitespace: + if ch == '#' and preceeded_by_whitespace: flow_indicators = True block_indicators = True # Check for line breaks, special, and unicode characters. - if ch in u'\n\x85\u2028\u2029': + if ch in '\n\x85\u2028\u2029': line_breaks = True - if not (ch == u'\n' or u'\x20' <= ch <= u'\x7E'): + if not (ch == '\n' or '\x20' <= ch <= '\x7E'): if ( - ch == u'\x85' - or u'\xA0' <= ch <= u'\uD7FF' - or u'\uE000' <= ch <= u'\uFFFD' - or (self.unicode_supplementary and (u'\U00010000' <= ch <= u'\U0010FFFF')) - ) and ch != u'\uFEFF': + ch == '\x85' + or '\xA0' <= ch <= '\uD7FF' + or '\uE000' <= ch <= '\uFFFD' + or (self.unicode_supplementary and ('\U00010000' <= ch <= '\U0010FFFF')) + ) and ch != '\uFEFF': # unicode_characters = True if not self.allow_unicode: special_characters = True @@ -1101,7 +1123,7 @@ class Emitter(object): special_characters = True # Detect important whitespace combinations. - if ch == u' ': + if ch == ' ': if index == 0: leading_space = True if index == len(scalar) - 1: @@ -1110,7 +1132,7 @@ class Emitter(object): break_space = True previous_space = True previous_break = False - elif ch in u'\n\x85\u2028\u2029': + elif ch in '\n\x85\u2028\u2029': if index == 0: leading_break = True if index == len(scalar) - 1: @@ -1125,9 +1147,9 @@ class Emitter(object): # Prepare for the next character. index += 1 - preceeded_by_whitespace = ch in u'\0 \t\r\n\x85\u2028\u2029' + preceeded_by_whitespace = ch in '\0 \t\r\n\x85\u2028\u2029' followed_by_whitespace = ( - index + 1 >= len(scalar) or scalar[index + 1] in u'\0 \t\r\n\x85\u2028\u2029' + index + 1 >= len(scalar) or scalar[index + 1] in '\0 \t\r\n\x85\u2028\u2029' ) # Let's decide what styles are allowed. @@ -1194,7 +1216,7 @@ class Emitter(object): # type: () -> None # Write BOM if needed. if self.encoding and self.encoding.startswith('utf-16'): - self.stream.write(u'\uFEFF'.encode(self.encoding)) + self.stream.write('\uFEFF'.encode(self.encoding)) def write_stream_end(self): # type: () -> None @@ -1205,7 +1227,7 @@ class Emitter(object): if self.whitespace or not need_whitespace: data = indicator else: - data = u' ' + indicator + data = ' ' + indicator self.whitespace = whitespace self.indention = self.indention and indention self.column += len(data) @@ -1228,7 +1250,7 @@ class Emitter(object): self.write_line_break() if self.column < indent: self.whitespace = True - data = u' ' * (indent - self.column) + data = ' ' * (indent - self.column) self.column = indent if self.encoding: data = data.encode(self.encoding) @@ -1248,7 +1270,7 @@ class Emitter(object): def write_version_directive(self, version_text): # type: (Any) -> None - data = u'%%YAML %s' % version_text + data = _F('%YAML {version_text!s}', version_text=version_text) if self.encoding: data = data.encode(self.encoding) self.stream.write(data) @@ -1256,7 +1278,11 @@ class Emitter(object): def write_tag_directive(self, handle_text, prefix_text): # type: (Any, Any) -> None - data = u'%%TAG %s %s' % (handle_text, prefix_text) + data = _F( + '%TAG {handle_text!s} {prefix_text!s}', + handle_text=handle_text, + prefix_text=prefix_text, + ) if self.encoding: data = data.encode(self.encoding) self.stream.write(data) @@ -1271,7 +1297,7 @@ class Emitter(object): self.write_line_break() if self.requested_indent != 0: self.write_indent() - self.write_indicator(u"'", True) + self.write_indicator("'", True) spaces = False breaks = False start = end = 0 @@ -1280,7 +1306,7 @@ class Emitter(object): if end < len(text): ch = text[end] if spaces: - if ch is None or ch != u' ': + if ch is None or ch != ' ': if ( start + 1 == end and self.column > self.best_width @@ -1297,18 +1323,18 @@ class Emitter(object): self.stream.write(data) start = end elif breaks: - if ch is None or ch not in u'\n\x85\u2028\u2029': - if text[start] == u'\n': + if ch is None or ch not in '\n\x85\u2028\u2029': + if text[start] == '\n': self.write_line_break() for br in text[start:end]: - if br == u'\n': + if br == '\n': self.write_line_break() else: self.write_line_break(br) self.write_indent() start = end else: - if ch is None or ch in u' \n\x85\u2028\u2029' or ch == u"'": + if ch is None or ch in ' \n\x85\u2028\u2029' or ch == "'": if start < end: data = text[start:end] self.column += len(data) @@ -1316,35 +1342,35 @@ class Emitter(object): data = data.encode(self.encoding) self.stream.write(data) start = end - if ch == u"'": - data = u"''" + if ch == "'": + data = "''" self.column += 2 if bool(self.encoding): data = data.encode(self.encoding) self.stream.write(data) start = end + 1 if ch is not None: - spaces = ch == u' ' - breaks = ch in u'\n\x85\u2028\u2029' + spaces = ch == ' ' + breaks = ch in '\n\x85\u2028\u2029' end += 1 - self.write_indicator(u"'", False) + self.write_indicator("'", False) ESCAPE_REPLACEMENTS = { - u'\0': u'0', - u'\x07': u'a', - u'\x08': u'b', - u'\x09': u't', - u'\x0A': u'n', - u'\x0B': u'v', - u'\x0C': u'f', - u'\x0D': u'r', - u'\x1B': u'e', - u'"': u'"', - u'\\': u'\\', - u'\x85': u'N', - u'\xA0': u'_', - u'\u2028': u'L', - u'\u2029': u'P', + '\0': '0', + '\x07': 'a', + '\x08': 'b', + '\x09': 't', + '\x0A': 'n', + '\x0B': 'v', + '\x0C': 'f', + '\x0D': 'r', + '\x1B': 'e', + '"': '"', + '\\': '\\', + '\x85': 'N', + '\xA0': '_', + '\u2028': 'L', + '\u2029': 'P', } def write_double_quoted(self, text, split=True): @@ -1354,7 +1380,7 @@ class Emitter(object): self.write_line_break() if self.requested_indent != 0: self.write_indent() - self.write_indicator(u'"', True) + self.write_indicator('"', True) start = end = 0 while end <= len(text): ch = None @@ -1362,12 +1388,12 @@ class Emitter(object): ch = text[end] if ( ch is None - or ch in u'"\\\x85\u2028\u2029\uFEFF' + or ch in '"\\\x85\u2028\u2029\uFEFF' or not ( - u'\x20' <= ch <= u'\x7E' + '\x20' <= ch <= '\x7E' or ( self.allow_unicode - and (u'\xA0' <= ch <= u'\uD7FF' or u'\uE000' <= ch <= u'\uFFFD') + and ('\xA0' <= ch <= '\uD7FF' or '\uE000' <= ch <= '\uFFFD') ) ) ): @@ -1380,13 +1406,13 @@ class Emitter(object): start = end if ch is not None: if ch in self.ESCAPE_REPLACEMENTS: - data = u'\\' + self.ESCAPE_REPLACEMENTS[ch] - elif ch <= u'\xFF': - data = u'\\x%02X' % ord(ch) - elif ch <= u'\uFFFF': - data = u'\\u%04X' % ord(ch) + data = '\\' + self.ESCAPE_REPLACEMENTS[ch] + elif ch <= '\xFF': + data = _F('\\x{ord_ch:02X}', ord_ch=ord(ch)) + elif ch <= '\uFFFF': + data = _F('\\u{ord_ch:04X}', ord_ch=ord(ch)) else: - data = u'\\U%08X' % ord(ch) + data = _F('\\U{ord_ch:08X}', ord_ch=ord(ch)) self.column += len(data) if bool(self.encoding): data = data.encode(self.encoding) @@ -1394,11 +1420,11 @@ class Emitter(object): start = end + 1 if ( 0 < end < len(text) - 1 - and (ch == u' ' or start >= end) + and (ch == ' ' or start >= end) and self.column + (end - start) > self.best_width and split ): - data = text[start:end] + u'\\' + data = text[start:end] + '\\' if start < end: start = end self.column += len(data) @@ -1408,24 +1434,24 @@ class Emitter(object): self.write_indent() self.whitespace = False self.indention = False - if text[start] == u' ': - data = u'\\' + if text[start] == ' ': + data = '\\' self.column += len(data) if bool(self.encoding): data = data.encode(self.encoding) self.stream.write(data) end += 1 - self.write_indicator(u'"', False) + self.write_indicator('"', False) def determine_block_hints(self, text): # type: (Any) -> Any indent = 0 - indicator = u'' - hints = u'' + indicator = '' + hints = '' if text: - if text[0] in u' \n\x85\u2028\u2029': + if text[0] in ' \n\x85\u2028\u2029': indent = self.best_sequence_indent - hints += text_type(indent) + hints += str(indent) elif self.root_context: for end in ['\n---', '\n...']: pos = 0 @@ -1443,18 +1469,18 @@ class Emitter(object): break if pos > 0: indent = self.best_sequence_indent - if text[-1] not in u'\n\x85\u2028\u2029': - indicator = u'-' - elif len(text) == 1 or text[-2] in u'\n\x85\u2028\u2029': - indicator = u'+' + if text[-1] not in '\n\x85\u2028\u2029': + indicator = '-' + elif len(text) == 1 or text[-2] in '\n\x85\u2028\u2029': + indicator = '+' hints += indicator return hints, indent, indicator def write_folded(self, text): # type: (Any) -> None hints, _indent, _indicator = self.determine_block_hints(text) - self.write_indicator(u'>' + hints, True) - if _indicator == u'+': + self.write_indicator('>' + hints, True) + if _indicator == '+': self.open_ended = True self.write_line_break() leading_space = True @@ -1466,17 +1492,17 @@ class Emitter(object): if end < len(text): ch = text[end] if breaks: - if ch is None or ch not in u'\n\x85\u2028\u2029\a': + if ch is None or ch not in '\n\x85\u2028\u2029\a': if ( not leading_space and ch is not None - and ch != u' ' - and text[start] == u'\n' + and ch != ' ' + and text[start] == '\n' ): self.write_line_break() - leading_space = ch == u' ' + leading_space = ch == ' ' for br in text[start:end]: - if br == u'\n': + if br == '\n': self.write_line_break() else: self.write_line_break(br) @@ -1484,7 +1510,7 @@ class Emitter(object): self.write_indent() start = end elif spaces: - if ch != u' ': + if ch != ' ': if start + 1 == end and self.column > self.best_width: self.write_indent() else: @@ -1495,13 +1521,13 @@ class Emitter(object): self.stream.write(data) start = end else: - if ch is None or ch in u' \n\x85\u2028\u2029\a': + if ch is None or ch in ' \n\x85\u2028\u2029\a': data = text[start:end] self.column += len(data) if bool(self.encoding): data = data.encode(self.encoding) self.stream.write(data) - if ch == u'\a': + if ch == '\a': if end < (len(text) - 1) and not text[end + 2].isspace(): self.write_line_break() self.write_indent() @@ -1512,21 +1538,21 @@ class Emitter(object): self.write_line_break() start = end if ch is not None: - breaks = ch in u'\n\x85\u2028\u2029' - spaces = ch == u' ' + breaks = ch in '\n\x85\u2028\u2029' + spaces = ch == ' ' end += 1 def write_literal(self, text, comment=None): # type: (Any, Any) -> None hints, _indent, _indicator = self.determine_block_hints(text) - self.write_indicator(u'|' + hints, True) + self.write_indicator('|' + hints, True) try: comment = comment[1][0] if comment: self.stream.write(comment) except (TypeError, IndexError): pass - if _indicator == u'+': + if _indicator == '+': self.open_ended = True self.write_line_break() breaks = True @@ -1536,21 +1562,21 @@ class Emitter(object): if end < len(text): ch = text[end] if breaks: - if ch is None or ch not in u'\n\x85\u2028\u2029': + if ch is None or ch not in '\n\x85\u2028\u2029': for br in text[start:end]: - if br == u'\n': + if br == '\n': self.write_line_break() else: self.write_line_break(br) if ch is not None: if self.root_context: idnx = self.indent if self.indent is not None else 0 - self.stream.write(u' ' * (_indent + idnx)) + self.stream.write(' ' * (_indent + idnx)) else: self.write_indent() start = end else: - if ch is None or ch in u'\n\x85\u2028\u2029': + if ch is None or ch in '\n\x85\u2028\u2029': data = text[start:end] if bool(self.encoding): data = data.encode(self.encoding) @@ -1559,7 +1585,7 @@ class Emitter(object): self.write_line_break() start = end if ch is not None: - breaks = ch in u'\n\x85\u2028\u2029' + breaks = ch in '\n\x85\u2028\u2029' end += 1 def write_plain(self, text, split=True): @@ -1574,7 +1600,7 @@ class Emitter(object): if not text: return if not self.whitespace: - data = u' ' + data = ' ' self.column += len(data) if self.encoding: data = data.encode(self.encoding) @@ -1589,7 +1615,7 @@ class Emitter(object): if end < len(text): ch = text[end] if spaces: - if ch != u' ': + if ch != ' ': if start + 1 == end and self.column > self.best_width and split: self.write_indent() self.whitespace = False @@ -1602,11 +1628,11 @@ class Emitter(object): self.stream.write(data) start = end elif breaks: - if ch not in u'\n\x85\u2028\u2029': # type: ignore - if text[start] == u'\n': + if ch not in '\n\x85\u2028\u2029': # type: ignore + if text[start] == '\n': self.write_line_break() for br in text[start:end]: - if br == u'\n': + if br == '\n': self.write_line_break() else: self.write_line_break(br) @@ -1615,7 +1641,7 @@ class Emitter(object): self.indention = False start = end else: - if ch is None or ch in u' \n\x85\u2028\u2029': + if ch is None or ch in ' \n\x85\u2028\u2029': data = text[start:end] self.column += len(data) if self.encoding: @@ -1627,8 +1653,8 @@ class Emitter(object): raise start = end if ch is not None: - spaces = ch == u' ' - breaks = ch in u'\n\x85\u2028\u2029' + spaces = ch == ' ' + breaks = ch in '\n\x85\u2028\u2029' end += 1 def write_comment(self, comment, pre=False): diff --git a/error.py b/error.py index d5f1553..6853e2d 100644 --- a/error.py +++ b/error.py @@ -1,11 +1,9 @@ # coding: utf-8 -from __future__ import absolute_import - import warnings import textwrap -from ruamel.yaml.compat import utf8 +from ruamel.yaml.compat import _F if False: # MYPY from typing import Any, Dict, Optional, List, Text # NOQA @@ -36,7 +34,12 @@ class StreamMark(object): def __str__(self): # type: () -> Any - where = ' in "%s", line %d, column %d' % (self.name, self.line + 1, self.column + 1) + where = _F( + ' in "{sname!s}", line {sline1:d}, column {scolumn1:d}', + sname=self.name, + sline1=self.line + 1, + scolumn1=self.column + 1, + ) return where def __eq__(self, other): @@ -71,7 +74,7 @@ class StringMark(StreamMark): return None head = "" start = self.pointer - while start > 0 and self.buffer[start - 1] not in u'\0\r\n\x85\u2028\u2029': + while start > 0 and self.buffer[start - 1] not in '\0\r\n\x85\u2028\u2029': start -= 1 if self.pointer - start > max_length / 2 - 1: head = ' ... ' @@ -79,13 +82,13 @@ class StringMark(StreamMark): break tail = "" end = self.pointer - while end < len(self.buffer) and self.buffer[end] not in u'\0\r\n\x85\u2028\u2029': + while end < len(self.buffer) and self.buffer[end] not in '\0\r\n\x85\u2028\u2029': end += 1 if end - self.pointer > max_length / 2 - 1: tail = ' ... ' end -= 5 break - snippet = utf8(self.buffer[start:end]) + snippet = self.buffer[start:end] caret = '^' caret = '^ (line: {})'.format(self.line + 1) return ( @@ -101,7 +104,12 @@ class StringMark(StreamMark): def __str__(self): # type: () -> Any snippet = self.get_snippet() - where = ' in "%s", line %d, column %d' % (self.name, self.line + 1, self.column + 1) + where = _F( + ' in "{sname!s}", line {sline1:d}, column {scolumn1:d}', + sname=self.name, + sline1=self.line + 1, + scolumn1=self.column + 1, + ) if snippet is not None: where += ':\n' + snippet return where diff --git a/events.py b/events.py index 58b2121..693519d 100644 --- a/events.py +++ b/events.py @@ -1,5 +1,7 @@ # coding: utf-8 +from ruamel.yaml.compat import _F + # Abstract classes. if False: # MYPY @@ -30,10 +32,16 @@ class Event(object): for key in ['anchor', 'tag', 'implicit', 'value', 'flow_style', 'style'] if hasattr(self, key) ] - arguments = ', '.join(['%s=%r' % (key, getattr(self, key)) for key in attributes]) + 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 '%s(%s)' % (self.__class__.__name__, arguments) + return _F( + '{self_class_name!s}{}arguments!s}', + self_class_name=self.__class__.__name__, + arguments=arguments, + ) class NodeEvent(Event): diff --git a/loader.py b/loader.py index 979ec62..b04ef18 100644 --- a/loader.py +++ b/loader.py @@ -1,8 +1,5 @@ # coding: utf-8 -from __future__ import absolute_import - - from ruamel.yaml.reader import Reader from ruamel.yaml.scanner import Scanner, RoundTripScanner from ruamel.yaml.parser import Parser, RoundTripParser diff --git a/main.py b/main.py index a452a39..08ed2eb 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import absolute_import, unicode_literals, print_function - import sys import os import warnings @@ -18,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, PY3, nprint +from ruamel.yaml.compat import StringIO, BytesIO, with_metaclass, nprint from ruamel.yaml.resolver import VersionedResolver, Resolver # NOQA from ruamel.yaml.representer import ( BaseRepresenter, @@ -37,11 +35,7 @@ from ruamel.yaml.loader import Loader as UnsafeLoader if False: # MYPY from typing import List, Set, Dict, Union, Any, Callable, Optional, Text # NOQA from ruamel.yaml.compat import StreamType, StreamTextType, VersionType # NOQA - - if PY3: - from pathlib import Path - else: - Path = Any + from pathlib import Path try: from _ruamel_yaml import CParser, CEmitter # type: ignore @@ -50,8 +44,6 @@ except: # NOQA # import io -enforce = object() - # YAML is an acronym, i.e. spoken: rhymes with "camel". And thus a # subset of abbreviations, which should be all caps according to PEP8 @@ -59,11 +51,10 @@ enforce = object() class YAML(object): def __init__( - self, _kw=enforce, typ=None, pure=False, output=None, plug_ins=None # input=None, + self, *, typ=None, pure=False, output=None, plug_ins=None # input=None, ): # type: (Any, Optional[Text], Any, Any, Any) -> None """ - _kw: not used, forces keyword arguments in 2.7 (in 3 you can do (*, safe_load=..) typ: 'rt'/None -> RoundTripLoader/RoundTripDumper, (default) 'safe' -> SafeLoader/SafeDumper, 'unsafe' -> normal/unsafe Loader/Dumper @@ -72,11 +63,6 @@ class YAML(object): input/output: needed to work as context manager plug_ins: a list of plug-in files """ - if _kw is not enforce: - raise TypeError( - '{}.__init__() takes no positional argument but at least ' - 'one was given ({!r})'.format(self.__class__.__name__, _kw) - ) self.typ = ['rt'] if typ is None else (typ if isinstance(typ, list) else [typ]) self.pure = pure @@ -352,17 +338,12 @@ class YAML(object): except AttributeError: pass - def load_all(self, stream, _kw=enforce): # , skip=None): + def load_all(self, stream): # *, skip=None): # type: (Union[Path, StreamTextType], Any) -> Any - if _kw is not enforce: - raise TypeError( - '{}.__init__() takes no positional argument but at least ' - 'one was given ({!r})'.format(self.__class__.__name__, _kw) - ) if not hasattr(stream, 'read') and hasattr(stream, 'open'): # pathlib.Path() instance with stream.open('r') as fp: - for d in self.load_all(fp, _kw=enforce): + for d in self.load_all(fp): yield d return # if skip is None: @@ -429,16 +410,11 @@ class YAML(object): return loader, loader return self.constructor, self.parser - def dump(self, data, stream=None, _kw=enforce, transform=None): + def dump(self, data, stream=None, *, transform=None): # type: (Any, Union[Path, StreamType], Any, Any) -> Any if self._context_manager: if not self._output: raise TypeError('Missing output stream while dumping from context manager') - if _kw is not enforce: - raise TypeError( - '{}.dump() takes one positional argument but at least ' - 'two were given ({!r})'.format(self.__class__.__name__, _kw) - ) if transform is not None: raise TypeError( '{}.dump() in the context manager cannot have transform keyword ' @@ -448,17 +424,12 @@ class YAML(object): else: # old style if stream is None: raise TypeError('Need a stream argument when not dumping from context manager') - return self.dump_all([data], stream, _kw, transform=transform) + return self.dump_all([data], stream, transform=transform) - def dump_all(self, documents, stream, _kw=enforce, transform=None): + def dump_all(self, documents, stream, *, transform=None): # type: (Any, Union[Path, StreamType], Any, Any) -> Any if self._context_manager: raise NotImplementedError - if _kw is not enforce: - raise TypeError( - '{}.dump(_all) takes two positional argument but at least ' - 'three were given ({!r})'.format(self.__class__.__name__, _kw) - ) self._output = stream self._context_manager = YAMLContextManager(self, transform=transform) for data in documents: @@ -467,7 +438,7 @@ class YAML(object): self._output = None self._context_manager = None - def Xdump_all(self, documents, stream, _kw=enforce, transform=None): + def Xdump_all(self, documents, stream, *, transform=None): # type: (Any, Union[Path, StreamType], Any, Any) -> Any """ Serialize a sequence of Python objects into a YAML stream. @@ -475,12 +446,7 @@ class YAML(object): if not hasattr(stream, 'write') and hasattr(stream, 'open'): # pathlib.Path() instance with stream.open('w') as fp: - return self.dump_all(documents, fp, _kw, transform=transform) - if _kw is not enforce: - raise TypeError( - '{}.dump(_all) takes two positional argument but at least ' - 'three were given ({!r})'.format(self.__class__.__name__, _kw) - ) + return self.dump_all(documents, fp, transform=transform) # The stream should have the methods `write` and possibly `flush`. if self.top_level_colon_align is True: tlca = max([len(str(x)) for x in documents[0]]) # type: Any @@ -630,7 +596,16 @@ class YAML(object): # helpers def official_plug_ins(self): # type: () -> Any - bd = os.path.dirname(__file__) + """search for list of subdirs that are plug-ins, if __file__ is not available, e.g. + single file installers that are not properly emulating a file-system (issue 324) + no plug-ins will be found. If any are packaged, you know which file that are + and you can explicitly provide it during instantiation: + yaml = ruamel.yaml.YAML(plug_ins=['ruamel/yaml/jinja2/__plug_in__']) + """ + try: + bd = os.path.dirname(__file__) + except NameError: + return [] gpbd = os.path.dirname(os.path.dirname(bd)) res = [x.replace(gpbd, "")[1:-3] for x in glob.glob(bd + '/*/__plug_in__.py')] return res @@ -882,6 +857,20 @@ def yaml_object(yml): ######################################################################################## +def warn_deprecation(fun, method, arg=''): + from ruamel.yaml.compat import _F + + warnings.warn( + _F( + '\n{fun} will be removed, use\n\n yaml=YAML({arg})\n yaml.{method}(...)\n\ninstead', # NOQA + fun=fun, + method=method, + arg=arg, + ), + PendingDeprecationWarning, # this will show when testing with pytest/tox + stacklevel=3, + ) +######################################################################################## def scan(stream, Loader=Loader): @@ -943,6 +932,7 @@ def load(stream, Loader=None, version=None, preserve_quotes=None): Parse the first YAML document in a stream and produce the corresponding Python object. """ + warn_deprecation('load', 'load', arg="typ='unsafe', pure=True") if Loader is None: warnings.warn(UnsafeLoaderWarning.text, UnsafeLoaderWarning, stacklevel=2) Loader = UnsafeLoader @@ -967,6 +957,7 @@ def load_all(stream, Loader=None, version=None, preserve_quotes=None): Parse all YAML documents in a stream and produce corresponding Python objects. """ + warn_deprecation('load_all', 'load_all', arg="typ='unsafe', pure=True") if Loader is None: warnings.warn(UnsafeLoaderWarning.text, UnsafeLoaderWarning, stacklevel=2) Loader = UnsafeLoader @@ -993,6 +984,7 @@ def safe_load(stream, version=None): and produce the corresponding Python object. Resolve only basic YAML tags. """ + warn_deprecation('safe_load', 'load', arg="typ='safe', pure=True") return load(stream, SafeLoader, version) @@ -1003,6 +995,7 @@ def safe_load_all(stream, version=None): and produce corresponding Python objects. Resolve only basic YAML tags. """ + warn_deprecation('safe_load_all', 'load_all', arg="typ='safe', pure=True") return load_all(stream, SafeLoader, version) @@ -1013,6 +1006,7 @@ def round_trip_load(stream, version=None, preserve_quotes=None): and produce the corresponding Python object. Resolve only basic YAML tags. """ + warn_deprecation('round_trip_load_all', 'load') return load(stream, RoundTripLoader, version, preserve_quotes=preserve_quotes) @@ -1023,6 +1017,7 @@ def round_trip_load_all(stream, version=None, preserve_quotes=None): and produce corresponding Python objects. Resolve only basic YAML tags. """ + warn_deprecation('round_trip_load_all', 'load_all') return load_all(stream, RoundTripLoader, version, preserve_quotes=preserve_quotes) @@ -1066,7 +1061,7 @@ def emit( return getvalue() -enc = None if PY3 else 'utf-8' +enc = None def serialize_all( @@ -1158,6 +1153,7 @@ def dump_all( Serialize a sequence of Python objects into a YAML stream. If stream is None, return the produced string instead. """ + warn_deprecation('dump_all', 'dump_all', arg="typ='unsafe', pure=True") getvalue = None if top_level_colon_align is True: top_level_colon_align = max([len(str(x)) for x in documents[0]]) @@ -1231,6 +1227,7 @@ def dump( default_style ∈ None, '', '"', "'", '|', '>' """ + warn_deprecation('dump', 'dump', arg="typ='unsafe', pure=True") return dump_all( [data], stream, @@ -1258,6 +1255,7 @@ def safe_dump_all(documents, stream=None, **kwds): Produce only basic YAML tags. If stream is None, return the produced string instead. """ + warn_deprecation('safe_dump_all', 'dump_all', arg="typ='safe', pure=True") return dump_all(documents, stream, Dumper=SafeDumper, **kwds) @@ -1268,6 +1266,7 @@ def safe_dump(data, stream=None, **kwds): Produce only basic YAML tags. If stream is None, return the produced string instead. """ + warn_deprecation('safe_dump', 'dump', arg="typ='safe', pure=True") return dump_all([data], stream, Dumper=SafeDumper, **kwds) @@ -1293,6 +1292,7 @@ def round_trip_dump( ): # type: (Any, Optional[StreamType], Any, Any, Any, Optional[bool], Optional[int], Optional[int], Optional[bool], Any, Any, Optional[bool], Optional[bool], Optional[VersionType], Any, Any, Any, Any) -> Optional[str] # NOQA allow_unicode = True if allow_unicode is None else allow_unicode + warn_deprecation('round_trip_dump', 'dump') return dump_all( [data], stream, diff --git a/nodes.py b/nodes.py index da86e9c..f51f989 100644 --- a/nodes.py +++ b/nodes.py @@ -1,9 +1,8 @@ # coding: utf-8 -from __future__ import print_function - import sys -from .compat import string_types + +from ruamel.yaml.compat import _F if False: # MYPY from typing import Dict, Any, Text # NOQA @@ -30,18 +29,23 @@ class Node(object): # elif len(value) == 1: # value = '<1 item>' # else: - # value = '<%d items>' % len(value) + # value = f'<{len(value)} items>' # else: # if len(value) > 75: - # value = repr(value[:70]+u' ... ') + # value = repr(value[:70]+' ... ') # else: # value = repr(value) value = repr(value) - return '%s(tag=%r, value=%s)' % (self.__class__.__name__, self.tag, value) + return _F( + '{class_name!s}(tag={self_tag!r}, value={value!s})', + class_name=self.__class__.__name__, + self_tag=self.tag, + value=value, + ) def dump(self, indent=0): # type: (int) -> None - if isinstance(self.value, string_types): + if isinstance(self.value, str): sys.stdout.write( '{}{}(tag={!r}, value={!r})\n'.format( ' ' * indent, self.__class__.__name__, self.tag, self.value diff --git a/parser.py b/parser.py index 10deaa8..f1ee9de 100644 --- a/parser.py +++ b/parser.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import absolute_import - # The following YAML grammar is LL(1) and is parsed by a recursive descent # parser. # @@ -80,7 +78,7 @@ from ruamel.yaml.error import MarkedYAMLError from ruamel.yaml.tokens import * # NOQA from ruamel.yaml.events import * # NOQA from ruamel.yaml.scanner import Scanner, RoundTripScanner, ScannerError # NOQA -from ruamel.yaml.compat import utf8, nprint, nprintf # NOQA +from ruamel.yaml.compat import _F, nprint, nprintf # NOQA if False: # MYPY from typing import Any, Dict, Optional, List # NOQA @@ -96,7 +94,7 @@ class Parser(object): # Since writing a recursive-descendant parser is a straightforward task, we # do not give many comments here. - DEFAULT_TAGS = {u'!': u'!', u'!!': u'tag:yaml.org,2002:'} + DEFAULT_TAGS = {'!': '!', '!!': 'tag:yaml.org,2002:'} def __init__(self, loader): # type: (Any) -> None @@ -213,7 +211,10 @@ class Parser(object): raise ParserError( None, None, - "expected '', but found %r" % self.scanner.peek_token().id, + _F( + "expected '', but found {pt!r}", + pt=self.scanner.peek_token().id, + ), self.scanner.peek_token().start_mark, ) token = self.scanner.get_token() @@ -272,7 +273,7 @@ class Parser(object): self.tag_handles = {} while self.scanner.check_token(DirectiveToken): token = self.scanner.get_token() - if token.name == u'YAML': + if token.name == 'YAML': if yaml_version is not None: raise ParserError( None, None, 'found duplicate YAML directive', token.start_mark @@ -282,15 +283,18 @@ class Parser(object): raise ParserError( None, None, - 'found incompatible YAML document (version 1.* is ' 'required)', + 'found incompatible YAML document (version 1.* is required)', token.start_mark, ) yaml_version = token.value - elif token.name == u'TAG': + elif token.name == 'TAG': handle, prefix = token.value if handle in self.tag_handles: raise ParserError( - None, None, 'duplicate tag handle %r' % utf8(handle), token.start_mark + None, + None, + _F('duplicate tag handle {handle!r}', handle=handle), + token.start_mark, ) self.tag_handles[handle] = prefix if bool(self.tag_handles): @@ -378,13 +382,13 @@ class Parser(object): raise ParserError( 'while parsing a node', start_mark, - 'found undefined tag handle %r' % utf8(handle), + _F('found undefined tag handle {handle!r}', handle=handle), tag_mark, ) tag = self.transform_tag(handle, suffix) else: tag = suffix - # if tag == u'!': + # if tag == '!': # raise ParserError("while parsing a node", start_mark, # "found non-specific tag '!'", tag_mark, # "Please check 'http://pyyaml.org/wiki/YAMLNonSpecificTag' @@ -392,7 +396,7 @@ class Parser(object): if start_mark is None: start_mark = end_mark = self.scanner.peek_token().start_mark event = None - implicit = tag is None or tag == u'!' + implicit = tag is None or tag == '!' if indentless_sequence and self.scanner.check_token(BlockEntryToken): comment = None pt = self.scanner.peek_token() @@ -410,7 +414,7 @@ class Parser(object): token = self.scanner.get_token() # self.scanner.peek_token_same_line_comment(token) end_mark = token.end_mark - if (token.plain and tag is None) or tag == u'!': + if (token.plain and tag is None) or tag == '!': implicit = (True, False) elif tag is None: implicit = (False, True) @@ -487,9 +491,9 @@ class Parser(object): node = 'flow' token = self.scanner.peek_token() raise ParserError( - 'while parsing a %s node' % node, + _F('while parsing a {node!s} node', node=node), start_mark, - 'expected the node content, but found %r' % token.id, + _F('expected the node content, but found {token_id!r}', token_id=token.id), token.start_mark, ) return event @@ -521,7 +525,7 @@ class Parser(object): raise ParserError( 'while parsing a block collection', self.marks[-1], - 'expected , but found %r' % token.id, + _F('expected , but found {token_id!r}', token_id=token.id), token.start_mark, ) token = self.scanner.get_token() # BlockEndToken @@ -585,7 +589,7 @@ class Parser(object): raise ParserError( 'while parsing a block mapping', self.marks[-1], - 'expected , but found %r' % token.id, + _F('expected , but found {token_id!r}', token_id=token.id), token.start_mark, ) token = self.scanner.get_token() @@ -652,7 +656,7 @@ class Parser(object): raise ParserError( 'while parsing a flow sequence', self.marks[-1], - "expected ',' or ']', but got %r" % token.id, + _F("expected ',' or ']', but got {token_id!r}", token_id=token.id), token.start_mark, ) @@ -726,7 +730,7 @@ class Parser(object): raise ParserError( 'while parsing a flow mapping', self.marks[-1], - "expected ',' or '}', but got %r" % token.id, + _F("expected ',' or '}', but got {token_id!r}", token_id=token.id), token.start_mark, ) if self.scanner.check_token(KeyToken): @@ -785,18 +789,18 @@ class RoundTripParser(Parser): # type: (Any, Any) -> Any # return self.tag_handles[handle]+suffix if handle == '!!' and suffix in ( - u'null', - u'bool', - u'int', - u'float', - u'binary', - u'timestamp', - u'omap', - u'pairs', - u'set', - u'str', - u'seq', - u'map', + 'null', + 'bool', + 'int', + 'float', + 'binary', + 'timestamp', + 'omap', + 'pairs', + 'set', + 'str', + 'seq', + 'map', ): return Parser.transform_tag(self, handle, suffix) return handle + suffix diff --git a/reader.py b/reader.py index b056a04..3a1656a 100644 --- a/reader.py +++ b/reader.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import absolute_import - # This module contains abstractions for the input stream. You don't have to # looks further, there are no pretty code. # @@ -24,7 +22,7 @@ from __future__ import absolute_import import codecs from ruamel.yaml.error import YAMLError, FileMark, StringMark, YAMLStreamError -from ruamel.yaml.compat import text_type, binary_type, PY3, UNICODE_SIZE +from ruamel.yaml.compat import _F # NOQA from ruamel.yaml.util import RegExp if False: # MYPY @@ -45,20 +43,25 @@ class ReaderError(YAMLError): def __str__(self): # type: () -> str - if isinstance(self.character, binary_type): - return "'%s' codec can't decode byte #x%02x: %s\n" ' in "%s", position %d' % ( - self.encoding, - ord(self.character), - self.reason, - self.name, - self.position, + if isinstance(self.character, bytes): + return _F( + "'{self_encoding!s}' codec can't decode byte #x{ord_self_character:02x}: " + '{self_reason!s}\n' + ' in "{self_name!s}", position {self_position:d}', + self_encoding=self.encoding, + ord_self_character=ord(self.character), + self_reason=self.reason, + self_name=self.name, + self_position=self.position, ) else: - return 'unacceptable character #x%04x: %s\n' ' in "%s", position %d' % ( - self.character, - self.reason, - self.name, - self.position, + return _F( + 'unacceptable character #x{self_character:04x}: {self._reason!s}\n' + ' in "{self_name!s}", position {self_position:d}', + self_character=self.character, + self_reason=self.reason, + self_name=self.name, + self_position=self.position, ) @@ -69,8 +72,8 @@ class Reader(object): # - adds '\0' to the end. # Reader accepts - # - a `str` object (PY2) / a `bytes` object (PY3), - # - a `unicode` object (PY2) / a `str` object (PY3), + # - a `bytes` object, + # - a `str` object, # - a file-like object with its `read` method returning `str`, # - a file-like object with its `read` method returning `unicode`. @@ -112,11 +115,11 @@ class Reader(object): if val is None: return self._stream = None - if isinstance(val, text_type): + if isinstance(val, str): self.name = '' self.check_printable(val) - self.buffer = val + u'\0' # type: ignore - elif isinstance(val, binary_type): + self.buffer = val + '\0' # type: ignore + elif isinstance(val, bytes): self.name = '' self.raw_buffer = val self.determine_encoding() @@ -151,12 +154,12 @@ class Reader(object): ch = self.buffer[self.pointer] self.pointer += 1 self.index += 1 - if ch in u'\n\x85\u2028\u2029' or ( - ch == u'\r' and self.buffer[self.pointer] != u'\n' + if ch in '\n\x85\u2028\u2029' or ( + ch == '\r' and self.buffer[self.pointer] != '\n' ): self.line += 1 self.column = 0 - elif ch != u'\uFEFF': + elif ch != '\uFEFF': self.column += 1 length -= 1 @@ -168,10 +171,10 @@ class Reader(object): ch = self.buffer[self.pointer] self.pointer += 1 self.index += 1 - if ch == u'\n' or (ch == u'\r' and self.buffer[self.pointer] != u'\n'): + if ch == '\n' or (ch == '\r' and self.buffer[self.pointer] != '\n'): self.line += 1 self.column = 0 - elif ch != u'\uFEFF': + elif ch != '\uFEFF': self.column += 1 length -= 1 @@ -188,7 +191,7 @@ class Reader(object): # type: () -> None while not self.eof and (self.raw_buffer is None or len(self.raw_buffer) < 2): self.update_raw() - if isinstance(self.raw_buffer, binary_type): + if isinstance(self.raw_buffer, bytes): if self.raw_buffer.startswith(codecs.BOM_UTF16_LE): self.raw_decode = codecs.utf_16_le_decode # type: ignore self.encoding = 'utf-16-le' @@ -200,18 +203,9 @@ class Reader(object): self.encoding = 'utf-8' self.update(1) - if UNICODE_SIZE == 2: - NON_PRINTABLE = RegExp( - u'[^\x09\x0A\x0D\x20-\x7E\x85' u'\xA0-\uD7FF' u'\uE000-\uFFFD' u']' - ) - else: - NON_PRINTABLE = RegExp( - u'[^\x09\x0A\x0D\x20-\x7E\x85' - u'\xA0-\uD7FF' - u'\uE000-\uFFFD' - u'\U00010000-\U0010FFFF' - u']' - ) + NON_PRINTABLE = RegExp( + '[^\x09\x0A\x0D\x20-\x7E\x85' '\xA0-\uD7FF' '\uE000-\uFFFD' '\U00010000-\U0010FFFF' ']' + ) _printable_ascii = ('\x09\x0A\x0D' + "".join(map(chr, range(0x20, 0x7F)))).encode('ascii') @@ -268,10 +262,7 @@ class Reader(object): try: data, converted = self.raw_decode(self.raw_buffer, 'strict', self.eof) except UnicodeDecodeError as exc: - if PY3: - character = self.raw_buffer[exc.start] - else: - character = exc.object[exc.start] + character = self.raw_buffer[exc.start] if self.stream is not None: position = self.stream_pointer - len(self.raw_buffer) + exc.start elif self.stream is not None: @@ -293,7 +284,7 @@ class Reader(object): def update_raw(self, size=None): # type: (Optional[int]) -> None if size is None: - size = 4096 if PY3 else 1024 + size = 4096 data = self.stream.read(size) if self.raw_buffer is None: self.raw_buffer = data diff --git a/representer.py b/representer.py index 1b5185a..4a27691 100644 --- a/representer.py +++ b/representer.py @@ -1,13 +1,9 @@ # coding: utf-8 -from __future__ import print_function, absolute_import, division - - from ruamel.yaml.error import * # NOQA from ruamel.yaml.nodes import * # NOQA -from ruamel.yaml.compat import text_type, binary_type, to_unicode, PY2, PY3 from ruamel.yaml.compat import ordereddict # type: ignore -from ruamel.yaml.compat import nprint, nprintf # NOQA +from ruamel.yaml.compat import _F, nprint, nprintf # NOQA from ruamel.yaml.scalarstring import ( LiteralScalarString, FoldedScalarString, @@ -35,11 +31,8 @@ import datetime import sys import types -if PY3: - import copyreg - import base64 -else: - import copy_reg as copyreg # type: ignore +import copyreg +import base64 if False: # MYPY from typing import Dict, List, Any, Union, Text, Optional # NOQA @@ -54,16 +47,6 @@ class RepresenterError(YAMLError): pass -if PY2: - - def get_classobj_bases(cls): - # type: (Any) -> Any - bases = [cls] - for base in cls.__bases__: - bases.extend(get_classobj_bases(base)) - return bases - - class BaseRepresenter(object): yaml_representers = {} # type: Dict[Any, Any] @@ -110,15 +93,11 @@ class BaseRepresenter(object): node = self.represented_objects[self.alias_key] # if node is None: # raise RepresenterError( - # "recursive objects are not allowed: %r" % data) + # f"recursive objects are not allowed: {data!r}") return node # self.represented_objects[alias_key] = None self.object_keeper.append(data) data_types = type(data).__mro__ - if PY2: - # if type(data) is types.InstanceType: - if isinstance(data, types.InstanceType): - data_types = get_classobj_bases(data.__class__) + list(data_types) if data_types[0] in self.yaml_representers: node = self.yaml_representers[data_types[0]](self, data) else: @@ -132,7 +111,7 @@ class BaseRepresenter(object): elif None in self.yaml_representers: node = self.yaml_representers[None](self, data) else: - node = ScalarNode(None, text_type(data)) + node = ScalarNode(None, str(data)) # if alias_key is not None: # self.represented_objects[alias_key] = node return node @@ -257,50 +236,25 @@ class SafeRepresenter(BaseRepresenter): # so "data is ()" should not be used if data is None or (isinstance(data, tuple) and data == ()): return True - if isinstance(data, (binary_type, text_type, bool, int, float)): + if isinstance(data, (bytes, str, bool, int, float)): return True return False def represent_none(self, data): # type: (Any) -> Any - return self.represent_scalar(u'tag:yaml.org,2002:null', u'null') - - if PY3: - - def represent_str(self, data): - # type: (Any) -> Any - return self.represent_scalar(u'tag:yaml.org,2002:str', data) - - def represent_binary(self, data): - # type: (Any) -> Any - if hasattr(base64, 'encodebytes'): - data = base64.encodebytes(data).decode('ascii') - else: - data = base64.encodestring(data).decode('ascii') - return self.represent_scalar(u'tag:yaml.org,2002:binary', data, style='|') + return self.represent_scalar('tag:yaml.org,2002:null', 'null') - else: + def represent_str(self, data): + # type: (Any) -> Any + return self.represent_scalar('tag:yaml.org,2002:str', data) - def represent_str(self, data): - # type: (Any) -> Any - tag = None - style = None - try: - data = unicode(data, 'ascii') - tag = u'tag:yaml.org,2002:str' - except UnicodeDecodeError: - try: - data = unicode(data, 'utf-8') - tag = u'tag:yaml.org,2002:str' - except UnicodeDecodeError: - data = data.encode('base64') - tag = u'tag:yaml.org,2002:binary' - style = '|' - return self.represent_scalar(tag, data, style=style) - - def represent_unicode(self, data): - # type: (Any) -> Any - return self.represent_scalar(u'tag:yaml.org,2002:str', data) + def represent_binary(self, data): + # type: (Any) -> Any + if hasattr(base64, 'encodebytes'): + data = base64.encodebytes(data).decode('ascii') + else: + data = base64.encodestring(data).decode('ascii') + return self.represent_scalar('tag:yaml.org,2002:binary', data, style='|') def represent_bool(self, data, anchor=None): # type: (Any, Optional[Any]) -> Any @@ -308,20 +262,14 @@ class SafeRepresenter(BaseRepresenter): value = self.dumper.boolean_representation[bool(data)] except AttributeError: if data: - value = u'true' + value = 'true' else: - value = u'false' - return self.represent_scalar(u'tag:yaml.org,2002:bool', value, anchor=anchor) + value = 'false' + return self.represent_scalar('tag:yaml.org,2002:bool', value, anchor=anchor) def represent_int(self, data): # type: (Any) -> Any - return self.represent_scalar(u'tag:yaml.org,2002:int', text_type(data)) - - if PY2: - - def represent_long(self, data): - # type: (Any) -> Any - return self.represent_scalar(u'tag:yaml.org,2002:int', text_type(data)) + return self.represent_scalar('tag:yaml.org,2002:int', str(data)) inf_value = 1e300 while repr(inf_value) != repr(inf_value * inf_value): @@ -330,15 +278,15 @@ class SafeRepresenter(BaseRepresenter): def represent_float(self, data): # type: (Any) -> Any if data != data or (data == 0.0 and data == 1.0): - value = u'.nan' + value = '.nan' elif data == self.inf_value: - value = u'.inf' + value = '.inf' elif data == -self.inf_value: - value = u'-.inf' + value = '-.inf' else: - value = to_unicode(repr(data)).lower() + value = repr(data).lower() if getattr(self.serializer, 'use_version', None) == (1, 1): - if u'.' not in value and u'e' in value: + if '.' not in value and 'e' in value: # Note that in some cases `repr(data)` represents a float number # without the decimal parts. For instance: # >>> repr(1e17) @@ -346,8 +294,8 @@ class SafeRepresenter(BaseRepresenter): # Unfortunately, this is not a valid float representation according # to the definition of the `!!float` tag in YAML 1.1. We fix # this by adding '.0' before the 'e' symbol. - value = value.replace(u'e', u'.0e', 1) - return self.represent_scalar(u'tag:yaml.org,2002:float', value) + value = value.replace('e', '.0e', 1) + return self.represent_scalar('tag:yaml.org,2002:float', value) def represent_list(self, data): # type: (Any) -> Any @@ -358,38 +306,38 @@ class SafeRepresenter(BaseRepresenter): # pairs = False # break # if not pairs: - return self.represent_sequence(u'tag:yaml.org,2002:seq', data) + return self.represent_sequence('tag:yaml.org,2002:seq', data) # value = [] # for item_key, item_value in data: - # value.append(self.represent_mapping(u'tag:yaml.org,2002:map', + # value.append(self.represent_mapping('tag:yaml.org,2002:map', # [(item_key, item_value)])) - # return SequenceNode(u'tag:yaml.org,2002:pairs', value) + # return SequenceNode('tag:yaml.org,2002:pairs', value) def represent_dict(self, data): # type: (Any) -> Any - return self.represent_mapping(u'tag:yaml.org,2002:map', data) + return self.represent_mapping('tag:yaml.org,2002:map', data) def represent_ordereddict(self, data): # type: (Any) -> Any - return self.represent_omap(u'tag:yaml.org,2002:omap', data) + return self.represent_omap('tag:yaml.org,2002:omap', data) def represent_set(self, data): # type: (Any) -> Any value = {} # type: Dict[Any, None] for key in data: value[key] = None - return self.represent_mapping(u'tag:yaml.org,2002:set', value) + return self.represent_mapping('tag:yaml.org,2002:set', value) def represent_date(self, data): # type: (Any) -> Any - value = to_unicode(data.isoformat()) - return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value) + value = data.isoformat() + return self.represent_scalar('tag:yaml.org,2002:timestamp', value) def represent_datetime(self, data): # type: (Any) -> Any - value = to_unicode(data.isoformat(' ')) - return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value) + value = data.isoformat(' ') + return self.represent_scalar('tag:yaml.org,2002:timestamp', value) def represent_yaml_object(self, tag, data, cls, flow_style=None): # type: (Any, Any, Any, Any) -> Any @@ -401,25 +349,19 @@ class SafeRepresenter(BaseRepresenter): def represent_undefined(self, data): # type: (Any) -> None - raise RepresenterError('cannot represent an object: %s' % (data,)) + raise RepresenterError(_F('cannot represent an object: {data!s}', data=data)) SafeRepresenter.add_representer(type(None), SafeRepresenter.represent_none) SafeRepresenter.add_representer(str, SafeRepresenter.represent_str) -if PY2: - SafeRepresenter.add_representer(unicode, SafeRepresenter.represent_unicode) -else: - SafeRepresenter.add_representer(bytes, SafeRepresenter.represent_binary) +SafeRepresenter.add_representer(bytes, SafeRepresenter.represent_binary) SafeRepresenter.add_representer(bool, SafeRepresenter.represent_bool) SafeRepresenter.add_representer(int, SafeRepresenter.represent_int) -if PY2: - SafeRepresenter.add_representer(long, SafeRepresenter.represent_long) - SafeRepresenter.add_representer(float, SafeRepresenter.represent_float) SafeRepresenter.add_representer(list, SafeRepresenter.represent_list) @@ -447,117 +389,36 @@ SafeRepresenter.add_representer(None, SafeRepresenter.represent_undefined) class Representer(SafeRepresenter): - if PY2: - - def represent_str(self, data): - # type: (Any) -> Any - tag = None - style = None - try: - data = unicode(data, 'ascii') - tag = u'tag:yaml.org,2002:str' - except UnicodeDecodeError: - try: - data = unicode(data, 'utf-8') - tag = u'tag:yaml.org,2002:python/str' - except UnicodeDecodeError: - data = data.encode('base64') - tag = u'tag:yaml.org,2002:binary' - style = '|' - return self.represent_scalar(tag, data, style=style) - - def represent_unicode(self, data): - # type: (Any) -> Any - tag = None - try: - data.encode('ascii') - tag = u'tag:yaml.org,2002:python/unicode' - except UnicodeEncodeError: - tag = u'tag:yaml.org,2002:str' - return self.represent_scalar(tag, data) - - def represent_long(self, data): - # type: (Any) -> Any - tag = u'tag:yaml.org,2002:int' - if int(data) is not data: - tag = u'tag:yaml.org,2002:python/long' - return self.represent_scalar(tag, to_unicode(data)) - def represent_complex(self, data): # type: (Any) -> Any if data.imag == 0.0: - data = u'%r' % data.real + data = repr(data.real) elif data.real == 0.0: - data = u'%rj' % data.imag + data = _F('{data_imag!r}j', data_imag=data.imag) elif data.imag > 0: - data = u'%r+%rj' % (data.real, data.imag) + data = _F('{data_real!r}+{data_imag!r}j', data_real=data.real, data_imag=data.imag) else: - data = u'%r%rj' % (data.real, data.imag) - return self.represent_scalar(u'tag:yaml.org,2002:python/complex', data) + data = _F('{data_real!r}{data_imag!r}j', data_real=data.real, data_imag=data.imag) + return self.represent_scalar('tag:yaml.org,2002:python/complex', data) def represent_tuple(self, data): # type: (Any) -> Any - return self.represent_sequence(u'tag:yaml.org,2002:python/tuple', data) + return self.represent_sequence('tag:yaml.org,2002:python/tuple', data) def represent_name(self, data): # type: (Any) -> Any try: - name = u'%s.%s' % (data.__module__, data.__qualname__) + name = _F( + '{modname!s}.{qualname!s}', modname=data.__module__, qualname=data.__qualname__ + ) except AttributeError: - # probably PY2 - name = u'%s.%s' % (data.__module__, data.__name__) - return self.represent_scalar(u'tag:yaml.org,2002:python/name:' + name, "") + # ToDo: check if this can be reached in Py3 + name = _F('{modname!s}.{name!s}', modname=data.__module__, name=data.__name__) + return self.represent_scalar('tag:yaml.org,2002:python/name:' + name, "") def represent_module(self, data): # type: (Any) -> Any - return self.represent_scalar(u'tag:yaml.org,2002:python/module:' + data.__name__, "") - - if PY2: - - def represent_instance(self, data): - # type: (Any) -> Any - # For instances of classic classes, we use __getinitargs__ and - # __getstate__ to serialize the data. - - # If data.__getinitargs__ exists, the object must be reconstructed - # by calling cls(**args), where args is a tuple returned by - # __getinitargs__. Otherwise, the cls.__init__ method should never - # be called and the class instance is created by instantiating a - # trivial class and assigning to the instance's __class__ variable. - - # If data.__getstate__ exists, it returns the state of the object. - # Otherwise, the state of the object is data.__dict__. - - # We produce either a !!python/object or !!python/object/new node. - # If data.__getinitargs__ does not exist and state is a dictionary, - # we produce a !!python/object node . Otherwise we produce a - # !!python/object/new node. - - cls = data.__class__ - class_name = u'%s.%s' % (cls.__module__, cls.__name__) - args = None - state = None - if hasattr(data, '__getinitargs__'): - args = list(data.__getinitargs__()) - if hasattr(data, '__getstate__'): - state = data.__getstate__() - else: - state = data.__dict__ - if args is None and isinstance(state, dict): - return self.represent_mapping( - u'tag:yaml.org,2002:python/object:' + class_name, state - ) - if isinstance(state, dict) and not state: - return self.represent_sequence( - u'tag:yaml.org,2002:python/object/new:' + class_name, args - ) - value = {} - if bool(args): - value['args'] = args - value['state'] = state # type: ignore - return self.represent_mapping( - u'tag:yaml.org,2002:python/object/new:' + class_name, value - ) + return self.represent_scalar('tag:yaml.org,2002:python/module:' + data.__name__, "") def represent_object(self, data): # type: (Any) -> Any @@ -585,7 +446,7 @@ class Representer(SafeRepresenter): elif hasattr(data, '__reduce__'): reduce = data.__reduce__() else: - raise RepresenterError('cannot represent object: %r' % (data,)) + raise RepresenterError(_F('cannot represent object: {data!r}', data=data)) reduce = (list(reduce) + [None] * 5)[:5] function, args, state, listitems, dictitems = reduce args = list(args) @@ -598,19 +459,23 @@ class Representer(SafeRepresenter): if function.__name__ == '__newobj__': function = args[0] args = args[1:] - tag = u'tag:yaml.org,2002:python/object/new:' + tag = 'tag:yaml.org,2002:python/object/new:' newobj = True else: - tag = u'tag:yaml.org,2002:python/object/apply:' + tag = 'tag:yaml.org,2002:python/object/apply:' newobj = False try: - function_name = u'%s.%s' % (function.__module__, function.__qualname__) + function_name = _F( + '{fun!s}.{qualname!s}', fun=function.__module__, qualname=function.__qualname__ + ) except AttributeError: - # probably PY2 - function_name = u'%s.%s' % (function.__module__, function.__name__) + # ToDo: check if this can be reached in Py3 + function_name = _F( + '{fun!s}.{name!s}', fun=function.__module__, name=function.__name__ + ) if not args and not listitems and not dictitems and isinstance(state, dict) and newobj: return self.represent_mapping( - u'tag:yaml.org,2002:python/object:' + function_name, state + 'tag:yaml.org,2002:python/object:' + function_name, state ) if not listitems and not dictitems and isinstance(state, dict) and not state: return self.represent_sequence(tag + function_name, args) @@ -626,31 +491,18 @@ class Representer(SafeRepresenter): return self.represent_mapping(tag + function_name, value) -if PY2: - Representer.add_representer(str, Representer.represent_str) - - Representer.add_representer(unicode, Representer.represent_unicode) - - Representer.add_representer(long, Representer.represent_long) - Representer.add_representer(complex, Representer.represent_complex) Representer.add_representer(tuple, Representer.represent_tuple) Representer.add_representer(type, Representer.represent_name) -if PY2: - Representer.add_representer(types.ClassType, Representer.represent_name) - Representer.add_representer(types.FunctionType, Representer.represent_name) Representer.add_representer(types.BuiltinFunctionType, Representer.represent_name) Representer.add_representer(types.ModuleType, Representer.represent_module) -if PY2: - Representer.add_multi_representer(types.InstanceType, Representer.represent_instance) - Representer.add_multi_representer(object, Representer.represent_object) Representer.add_multi_representer(type, Representer.represent_name) @@ -684,17 +536,15 @@ class RoundTripRepresenter(SafeRepresenter): # type: (Any) -> Any if len(self.represented_objects) == 0 and not self.serializer.use_explicit_start: # this will be open ended (although it is not yet) - return self.represent_scalar(u'tag:yaml.org,2002:null', u'null') - return self.represent_scalar(u'tag:yaml.org,2002:null', "") + return self.represent_scalar('tag:yaml.org,2002:null', 'null') + return self.represent_scalar('tag:yaml.org,2002:null', "") def represent_literal_scalarstring(self, data): # type: (Any) -> Any tag = None style = '|' anchor = data.yaml_anchor(any=True) - if PY2 and not isinstance(data, unicode): - data = unicode(data, 'ascii') - tag = u'tag:yaml.org,2002:str' + tag = 'tag:yaml.org,2002:str' return self.represent_scalar(tag, data, style=style, anchor=anchor) represent_preserved_scalarstring = represent_literal_scalarstring @@ -711,9 +561,7 @@ class RoundTripRepresenter(SafeRepresenter): and (fold_pos < len(data) and not data[fold_pos + 1].isspace()) ): data = data[:fold_pos] + '\a' + data[fold_pos:] - if PY2 and not isinstance(data, unicode): - data = unicode(data, 'ascii') - tag = u'tag:yaml.org,2002:str' + tag = 'tag:yaml.org,2002:str' return self.represent_scalar(tag, data, style=style, anchor=anchor) def represent_single_quoted_scalarstring(self, data): @@ -721,9 +569,7 @@ class RoundTripRepresenter(SafeRepresenter): tag = None style = "'" anchor = data.yaml_anchor(any=True) - if PY2 and not isinstance(data, unicode): - data = unicode(data, 'ascii') - tag = u'tag:yaml.org,2002:str' + tag = 'tag:yaml.org,2002:str' return self.represent_scalar(tag, data, style=style, anchor=anchor) def represent_double_quoted_scalarstring(self, data): @@ -731,9 +577,7 @@ class RoundTripRepresenter(SafeRepresenter): tag = None style = '"' anchor = data.yaml_anchor(any=True) - if PY2 and not isinstance(data, unicode): - data = unicode(data, 'ascii') - tag = u'tag:yaml.org,2002:str' + tag = 'tag:yaml.org,2002:str' return self.represent_scalar(tag, data, style=style, anchor=anchor) def represent_plain_scalarstring(self, data): @@ -741,15 +585,13 @@ class RoundTripRepresenter(SafeRepresenter): tag = None style = '' anchor = data.yaml_anchor(any=True) - if PY2 and not isinstance(data, unicode): - data = unicode(data, 'ascii') - tag = u'tag:yaml.org,2002:str' + tag = 'tag:yaml.org,2002:str' return self.represent_scalar(tag, data, style=style, anchor=anchor) def insert_underscore(self, prefix, s, underscore, anchor=None): # type: (Any, Any, Any, Any) -> Any if underscore is None: - return self.represent_scalar(u'tag:yaml.org,2002:int', prefix + s, anchor=anchor) + return self.represent_scalar('tag:yaml.org,2002:int', prefix + s, anchor=anchor) if underscore[0]: sl = list(s) pos = len(s) - underscore[0] @@ -761,7 +603,7 @@ class RoundTripRepresenter(SafeRepresenter): s = '_' + s if underscore[2]: s += '_' - return self.represent_scalar(u'tag:yaml.org,2002:int', prefix + s, anchor=anchor) + return self.represent_scalar('tag:yaml.org,2002:int', prefix + s, anchor=anchor) def represent_scalar_int(self, data): # type: (Any) -> Any @@ -818,31 +660,31 @@ class RoundTripRepresenter(SafeRepresenter): value = None anchor = data.yaml_anchor(any=True) if data != data or (data == 0.0 and data == 1.0): - value = u'.nan' + value = '.nan' elif data == self.inf_value: - value = u'.inf' + value = '.inf' elif data == -self.inf_value: - value = u'-.inf' + value = '-.inf' if value: - return self.represent_scalar(u'tag:yaml.org,2002:float', value, anchor=anchor) + return self.represent_scalar('tag:yaml.org,2002:float', value, anchor=anchor) if data._exp is None and data._prec > 0 and data._prec == data._width - 1: # no exponent, but trailing dot - value = u'{}{:d}.'.format(data._m_sign if data._m_sign else "", abs(int(data))) + value = '{}{:d}.'.format(data._m_sign if data._m_sign else "", abs(int(data))) elif data._exp is None: # no exponent, "normal" dot prec = data._prec ms = data._m_sign if data._m_sign else "" # -1 for the dot - value = u'{}{:0{}.{}f}'.format( + value = '{}{:0{}.{}f}'.format( ms, abs(data), data._width - len(ms), data._width - prec - 1 ) if prec == 0 or (prec == 1 and ms != ""): - value = value.replace(u'0.', u'.') + value = value.replace('0.', '.') while len(value) < data._width: - value += u'0' + value += '0' else: # exponent - m, es = u'{:{}.{}e}'.format( + m, es = '{:{}.{}e}'.format( # data, data._width, data._width - data._prec + (1 if data._m_sign else 0) data, data._width, @@ -855,28 +697,28 @@ class RoundTripRepresenter(SafeRepresenter): e = int(es) m1, m2 = m.split('.') # always second? while len(m1) + len(m2) < data._width - (1 if data._prec >= 0 else 0): - m2 += u'0' + m2 += '0' if data._m_sign and data > 0: m1 = '+' + m1 - esgn = u'+' if data._e_sign else "" + esgn = '+' if data._e_sign else "" if data._prec < 0: # mantissa without dot - if m2 != u'0': + if m2 != '0': e -= len(m2) else: m2 = "" while (len(m1) + len(m2) - (1 if data._m_sign else 0)) < data._width: - m2 += u'0' + m2 += '0' e -= 1 - value = m1 + m2 + data._exp + u'{:{}0{}d}'.format(e, esgn, data._e_width) + value = m1 + m2 + data._exp + '{:{}0{}d}'.format(e, esgn, data._e_width) elif data._prec == 0: # mantissa with trailing dot e -= len(m2) value = ( - m1 + m2 + u'.' + data._exp + u'{:{}0{}d}'.format(e, esgn, data._e_width) + m1 + m2 + '.' + data._exp + '{:{}0{}d}'.format(e, esgn, data._e_width) ) else: if data._m_lead0 > 0: - m2 = u'0' * (data._m_lead0 - 1) + m1 + m2 - m1 = u'0' + m2 = '0' * (data._m_lead0 - 1) + m1 + m2 + m1 = '0' m2 = m2[: -data._m_lead0] # these should be zeros e += data._m_lead0 while len(m1) < data._prec: @@ -884,12 +726,12 @@ class RoundTripRepresenter(SafeRepresenter): m2 = m2[1:] e -= 1 value = ( - m1 + u'.' + m2 + data._exp + u'{:{}0{}d}'.format(e, esgn, data._e_width) + m1 + '.' + m2 + data._exp + '{:{}0{}d}'.format(e, esgn, data._e_width) ) if value is None: - value = to_unicode(repr(data)).lower() - return self.represent_scalar(u'tag:yaml.org,2002:float', value, anchor=anchor) + value = repr(data).lower() + return self.represent_scalar('tag:yaml.org,2002:float', value, anchor=anchor) def represent_sequence(self, tag, sequence, flow_style=None): # type: (Any, Any, Any) -> Any @@ -962,10 +804,10 @@ class RoundTripRepresenter(SafeRepresenter): # type: (Any) -> Any if isinstance(data, CommentedKeySeq): self.alias_key = None - return self.represent_sequence(u'tag:yaml.org,2002:seq', data, flow_style=True) + return self.represent_sequence('tag:yaml.org,2002:seq', data, flow_style=True) if isinstance(data, CommentedKeyMap): self.alias_key = None - return self.represent_mapping(u'tag:yaml.org,2002:map', data, flow_style=True) + return self.represent_mapping('tag:yaml.org,2002:map', data, flow_style=True) return SafeRepresenter.represent_key(self, data) def represent_mapping(self, tag, mapping, flow_style=None): @@ -1043,7 +885,7 @@ class RoundTripRepresenter(SafeRepresenter): else: arg = self.represent_data(merge_list) arg.flow_style = True - value.insert(merge_pos, (ScalarNode(u'tag:yaml.org,2002:merge', '<<'), arg)) + value.insert(merge_pos, (ScalarNode('tag:yaml.org,2002:merge', '<<'), arg)) return node def represent_omap(self, tag, omap, flow_style=None): @@ -1109,7 +951,7 @@ class RoundTripRepresenter(SafeRepresenter): def represent_set(self, setting): # type: (Any) -> Any flow_style = False - tag = u'tag:yaml.org,2002:set' + tag = 'tag:yaml.org,2002:set' # return self.represent_mapping(tag, value) value = [] # type: List[Any] flow_style = setting.fa.flow_style(flow_style) @@ -1168,7 +1010,7 @@ class RoundTripRepresenter(SafeRepresenter): else: tag = t else: - tag = u'tag:yaml.org,2002:map' + tag = 'tag:yaml.org,2002:map' return self.represent_mapping(tag, data) def represent_list(self, data): @@ -1183,7 +1025,7 @@ class RoundTripRepresenter(SafeRepresenter): else: tag = t else: - tag = u'tag:yaml.org,2002:seq' + tag = 'tag:yaml.org,2002:seq' return self.represent_sequence(tag, data) def represent_datetime(self, data): @@ -1197,7 +1039,7 @@ class RoundTripRepresenter(SafeRepresenter): value = data.isoformat(inter) if _yaml['tz']: value += _yaml['tz'] - return self.represent_scalar(u'tag:yaml.org,2002:timestamp', to_unicode(value)) + return self.represent_scalar('tag:yaml.org,2002:timestamp', value) def represent_tagged_scalar(self, data): # type: (Any) -> Any diff --git a/resolver.py b/resolver.py index 6379943..eab6163 100644 --- a/resolver.py +++ b/resolver.py @@ -1,14 +1,12 @@ # coding: utf-8 -from __future__ import absolute_import - import re if False: # MYPY from typing import Any, Dict, List, Union, Text, Optional # NOQA from ruamel.yaml.compat import VersionType # NOQA -from ruamel.yaml.compat import string_types, _DEFAULT_YAML_VERSION # NOQA +from ruamel.yaml.compat import _DEFAULT_YAML_VERSION, _F # NOQA from ruamel.yaml.error import * # NOQA from ruamel.yaml.nodes import MappingNode, ScalarNode, SequenceNode # NOQA from ruamel.yaml.util import RegExp # NOQA @@ -24,77 +22,77 @@ __all__ = ['BaseResolver', 'Resolver', 'VersionedResolver'] # - a list of first characters to match implicit_resolvers = [ ([(1, 2)], - u'tag:yaml.org,2002:bool', - RegExp(u'''^(?:true|True|TRUE|false|False|FALSE)$''', re.X), - list(u'tTfF')), + 'tag:yaml.org,2002:bool', + RegExp('''^(?:true|True|TRUE|false|False|FALSE)$''', re.X), + list('tTfF')), ([(1, 1)], - u'tag:yaml.org,2002:bool', - RegExp(u'''^(?:y|Y|yes|Yes|YES|n|N|no|No|NO + 'tag:yaml.org,2002:bool', + RegExp('''^(?:y|Y|yes|Yes|YES|n|N|no|No|NO |true|True|TRUE|false|False|FALSE |on|On|ON|off|Off|OFF)$''', re.X), - list(u'yYnNtTfFoO')), + list('yYnNtTfFoO')), ([(1, 2)], - u'tag:yaml.org,2002:float', - RegExp(u'''^(?: + 'tag:yaml.org,2002:float', + RegExp('''^(?: [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)? |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+) |[-+]?\\.[0-9_]+(?:[eE][-+][0-9]+)? |[-+]?\\.(?:inf|Inf|INF) |\\.(?:nan|NaN|NAN))$''', re.X), - list(u'-+0123456789.')), + list('-+0123456789.')), ([(1, 1)], - u'tag:yaml.org,2002:float', - RegExp(u'''^(?: + 'tag:yaml.org,2002:float', + RegExp('''^(?: [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)? |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+) |\\.[0-9_]+(?:[eE][-+][0-9]+)? |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]* # sexagesimal float |[-+]?\\.(?:inf|Inf|INF) |\\.(?:nan|NaN|NAN))$''', re.X), - list(u'-+0123456789.')), + list('-+0123456789.')), ([(1, 2)], - u'tag:yaml.org,2002:int', - RegExp(u'''^(?:[-+]?0b[0-1_]+ + 'tag:yaml.org,2002:int', + RegExp('''^(?:[-+]?0b[0-1_]+ |[-+]?0o?[0-7_]+ |[-+]?[0-9_]+ |[-+]?0x[0-9a-fA-F_]+)$''', re.X), - list(u'-+0123456789')), + list('-+0123456789')), ([(1, 1)], - u'tag:yaml.org,2002:int', - RegExp(u'''^(?:[-+]?0b[0-1_]+ + 'tag:yaml.org,2002:int', + RegExp('''^(?:[-+]?0b[0-1_]+ |[-+]?0?[0-7_]+ |[-+]?(?:0|[1-9][0-9_]*) |[-+]?0x[0-9a-fA-F_]+ |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$''', re.X), # sexagesimal int - list(u'-+0123456789')), + list('-+0123456789')), ([(1, 2), (1, 1)], - u'tag:yaml.org,2002:merge', - RegExp(u'^(?:<<)$'), - [u'<']), + 'tag:yaml.org,2002:merge', + RegExp('^(?:<<)$'), + ['<']), ([(1, 2), (1, 1)], - u'tag:yaml.org,2002:null', - RegExp(u'''^(?: ~ + 'tag:yaml.org,2002:null', + RegExp('''^(?: ~ |null|Null|NULL | )$''', re.X), - [u'~', u'n', u'N', u'']), + ['~', 'n', 'N', '']), ([(1, 2), (1, 1)], - u'tag:yaml.org,2002:timestamp', - RegExp(u'''^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] + 'tag:yaml.org,2002:timestamp', + RegExp('''^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]? (?:[Tt]|[ \\t]+)[0-9][0-9]? :[0-9][0-9] :[0-9][0-9] (?:\\.[0-9]*)? (?:[ \\t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$''', re.X), - list(u'0123456789')), + list('0123456789')), ([(1, 2), (1, 1)], - u'tag:yaml.org,2002:value', - RegExp(u'^(?:=)$'), - [u'=']), + 'tag:yaml.org,2002:value', + RegExp('^(?:=)$'), + ['=']), # The following resolver is only for documentation purposes. It cannot work # because plain scalars cannot start with '!', '&', or '*'. ([(1, 2), (1, 1)], - u'tag:yaml.org,2002:yaml', - RegExp(u'^(?:!|&|\\*)$'), - list(u'!&*')), + 'tag:yaml.org,2002:yaml', + RegExp('^(?:!|&|\\*)$'), + list('!&*')), ] # fmt: on @@ -105,9 +103,9 @@ class ResolverError(YAMLError): class BaseResolver(object): - DEFAULT_SCALAR_TAG = u'tag:yaml.org,2002:str' - DEFAULT_SEQUENCE_TAG = u'tag:yaml.org,2002:seq' - DEFAULT_MAPPING_TAG = u'tag:yaml.org,2002:map' + DEFAULT_SCALAR_TAG = 'tag:yaml.org,2002:str' + DEFAULT_SEQUENCE_TAG = 'tag:yaml.org,2002:seq' + DEFAULT_MAPPING_TAG = 'tag:yaml.org,2002:map' yaml_implicit_resolvers = {} # type: Dict[Any, Any] yaml_path_resolvers = {} # type: Dict[Any, Any] @@ -186,7 +184,9 @@ class BaseResolver(object): node_check = element[0] index_check = True else: - raise ResolverError('Invalid path element: %s' % (element,)) + raise ResolverError( + _F('Invalid path element: {element!s}', element=element) + ) else: node_check = None index_check = element @@ -198,12 +198,16 @@ class BaseResolver(object): node_check = MappingNode elif ( node_check not in [ScalarNode, SequenceNode, MappingNode] - and not isinstance(node_check, string_types) + and not isinstance(node_check, str) and node_check is not None ): - raise ResolverError('Invalid node checker: %s' % (node_check,)) - if not isinstance(index_check, (string_types, int)) and index_check is not None: - raise ResolverError('Invalid index checker: %s' % (index_check,)) + raise ResolverError( + _F('Invalid node checker: {node_check!s}', node_check=node_check) + ) + if not isinstance(index_check, (str, int)) and index_check is not None: + raise ResolverError( + _F('Invalid index checker: {index_check!s}', index_check=index_check) + ) new_path.append((node_check, index_check)) if kind is str: kind = ScalarNode @@ -212,7 +216,7 @@ class BaseResolver(object): elif kind is dict: kind = MappingNode elif kind not in [ScalarNode, SequenceNode, MappingNode] and kind is not None: - raise ResolverError('Invalid node kind: %s' % (kind,)) + raise ResolverError(_F('Invalid node kind: {kind!s}', kind=kind)) cls.yaml_path_resolvers[tuple(new_path), kind] = tag def descend_resolver(self, current_node, current_index): @@ -248,7 +252,7 @@ class BaseResolver(object): def check_resolver_prefix(self, depth, path, kind, current_node, current_index): # type: (int, Text, Any, Any, Any) -> bool node_check, index_check = path[depth - 1] - if isinstance(node_check, string_types): + if isinstance(node_check, str): if current_node.tag != node_check: return False elif node_check is not None: @@ -258,7 +262,7 @@ class BaseResolver(object): return False if (index_check is False or index_check is None) and current_index is None: return False - if isinstance(index_check, string_types): + if isinstance(index_check, str): if not ( isinstance(current_index, ScalarNode) and index_check == current_index.value ): @@ -339,7 +343,7 @@ class VersionedResolver(BaseResolver): if isinstance(version, list): return tuple(version) # assume string - return tuple(map(int, version.split(u'.'))) + return tuple(map(int, version.split('.'))) @property def versioned_resolver(self): @@ -348,6 +352,8 @@ class VersionedResolver(BaseResolver): select the resolver based on the version we are parsing """ version = self.processing_version + if isinstance(version, str): + version = tuple(map(int, version.split('.'))) if version not in self._version_implicit_resolver: for x in implicit_resolvers: if version in x[0]: diff --git a/scalarbool.py b/scalarbool.py index fc8f8c2..3862464 100644 --- a/scalarbool.py +++ b/scalarbool.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function, absolute_import, division, unicode_literals - """ You cannot subclass bool, and this is necessary for round-tripping anchored bool values (and also if you want to preserve the original way of writing) @@ -18,8 +16,6 @@ if False: # MYPY __all__ = ['ScalarBoolean'] -# no need for no_limit_int -> int - class ScalarBoolean(int): def __new__(cls, *args, **kw): diff --git a/scalarfloat.py b/scalarfloat.py index 0404df3..9d41879 100644 --- a/scalarfloat.py +++ b/scalarfloat.py @@ -1,9 +1,6 @@ # coding: utf-8 -from __future__ import print_function, absolute_import, division, unicode_literals - import sys -from .compat import no_limit_int # NOQA from ruamel.yaml.anchor import Anchor if False: # MYPY diff --git a/scalarint.py b/scalarint.py index 581a8df..3923206 100644 --- a/scalarint.py +++ b/scalarint.py @@ -1,8 +1,5 @@ # coding: utf-8 -from __future__ import print_function, absolute_import, division, unicode_literals - -from .compat import no_limit_int # NOQA from ruamel.yaml.anchor import Anchor if False: # MYPY @@ -11,13 +8,13 @@ if False: # MYPY __all__ = ['ScalarInt', 'BinaryInt', 'OctalInt', 'HexInt', 'HexCapsInt', 'DecimalInt'] -class ScalarInt(no_limit_int): +class ScalarInt(int): def __new__(cls, *args, **kw): # type: (Any, Any, Any) -> Any width = kw.pop('width', None) # type: ignore underscore = kw.pop('underscore', None) # type: ignore anchor = kw.pop('anchor', None) # type: ignore - v = no_limit_int.__new__(cls, *args, **kw) # type: ignore + v = int.__new__(cls, *args, **kw) # type: ignore v._width = width v._underscore = underscore if anchor is not None: diff --git a/scalarstring.py b/scalarstring.py index f164639..f5fb6a2 100644 --- a/scalarstring.py +++ b/scalarstring.py @@ -1,8 +1,5 @@ # coding: utf-8 -from __future__ import print_function, absolute_import, division, unicode_literals - -from ruamel.yaml.compat import text_type from ruamel.yaml.anchor import Anchor if False: # MYPY @@ -21,20 +18,20 @@ __all__ = [ ] -class ScalarString(text_type): +class ScalarString(str): __slots__ = Anchor.attrib def __new__(cls, *args, **kw): # type: (Any, Any) -> Any anchor = kw.pop('anchor', None) # type: ignore - ret_val = text_type.__new__(cls, *args, **kw) # type: ignore + ret_val = str.__new__(cls, *args, **kw) # type: ignore if anchor is not None: ret_val.yaml_set_anchor(anchor, always_dump=True) return ret_val def replace(self, old, new, maxreplace=-1): # type: (Any, Any, int) -> Any - return type(self)((text_type.replace(self, old, new, maxreplace))) + return type(self)((str.replace(self, old, new, maxreplace))) @property def anchor(self): @@ -129,8 +126,7 @@ def walk_tree(base, map=None): map[':'] = SingleQuotedScalarString walk_tree(data, map=map) """ - from ruamel.yaml.compat import string_types - from ruamel.yaml.compat import MutableMapping, MutableSequence # type: ignore + from collections.abc import MutableMapping, MutableSequence # type: ignore if map is None: map = {'\n': preserve_literal} @@ -138,7 +134,7 @@ def walk_tree(base, map=None): if isinstance(base, MutableMapping): for k in base: v = base[k] # type: Text - if isinstance(v, string_types): + if isinstance(v, str): for ch in map: if ch in v: base[k] = map[ch](v) @@ -147,7 +143,7 @@ def walk_tree(base, map=None): walk_tree(v, map=map) elif isinstance(base, MutableSequence): for idx, elem in enumerate(base): - if isinstance(elem, string_types): + if isinstance(elem, str): for ch in map: if ch in elem: # type: ignore base[idx] = map[ch](elem) diff --git a/scanner.py b/scanner.py index df85ae0..2ea82d3 100644 --- a/scanner.py +++ b/scanner.py @@ -1,7 +1,5 @@ # coding: utf-8 -from __future__ import print_function, absolute_import, division, unicode_literals - # Scanner produces tokens of the following types: # STREAM-START # STREAM-END @@ -32,7 +30,7 @@ from __future__ import print_function, absolute_import, division, unicode_litera from ruamel.yaml.error import MarkedYAMLError from ruamel.yaml.tokens import * # NOQA -from ruamel.yaml.compat import utf8, unichr, PY3, check_anchorname_char, nprint # NOQA +from ruamel.yaml.compat import _F, check_anchorname_char, nprint # NOQA if False: # MYPY from typing import Any, Dict, Optional, List, Union, Text # NOQA @@ -245,7 +243,7 @@ class Scanner(object): return self.fetch_document_end() # TODO: support for BOM within a stream. - # if ch == u'\uFEFF': + # if ch == '\uFEFF': # return self.fetch_bom() <-- issue BOMToken # Note: the order of the following checks is NOT significant. @@ -318,7 +316,7 @@ class Scanner(object): raise ScannerError( 'while scanning for the next token', None, - 'found character %r that cannot start any token' % utf8(ch), + _F('found character {ch!r} that cannot start any token', ch=ch), self.reader.get_mark(), ) @@ -917,7 +915,7 @@ class Scanner(object): raise ScannerError( 'while scanning a directive', start_mark, - 'expected alphabetic or numeric character, but found %r' % utf8(ch), + _F('expected alphabetic or numeric character, but found {ch!r}', ch=ch), self.reader.get_mark(), ) value = self.reader.prefix(length) @@ -927,7 +925,7 @@ class Scanner(object): raise ScannerError( 'while scanning a directive', start_mark, - 'expected alphabetic or numeric character, but found %r' % utf8(ch), + _F('expected alphabetic or numeric character, but found {ch!r}', ch=ch), self.reader.get_mark(), ) return value @@ -944,7 +942,7 @@ class Scanner(object): raise ScannerError( 'while scanning a directive', start_mark, - "expected a digit or '.', but found %r" % utf8(srp()), + _F("expected a digit or '.', but found {srp_call!r}", srp_call=srp()), self.reader.get_mark(), ) srf() @@ -953,7 +951,7 @@ class Scanner(object): raise ScannerError( 'while scanning a directive', start_mark, - "expected a digit or ' ', but found %r" % utf8(srp()), + _F("expected a digit or '.', but found {srp_call!r}", srp_call=srp()), self.reader.get_mark(), ) self.yaml_version = (major, minor) @@ -969,7 +967,7 @@ class Scanner(object): raise ScannerError( 'while scanning a directive', start_mark, - 'expected a digit, but found %r' % utf8(ch), + _F('expected a digit, but found {ch!r}', ch=ch), self.reader.get_mark(), ) length = 0 @@ -1001,7 +999,7 @@ class Scanner(object): raise ScannerError( 'while scanning a directive', start_mark, - "expected ' ', but found %r" % utf8(ch), + _F("expected ' ', but found {ch!r}", ch=ch), self.reader.get_mark(), ) return value @@ -1015,7 +1013,7 @@ class Scanner(object): raise ScannerError( 'while scanning a directive', start_mark, - "expected ' ', but found %r" % utf8(ch), + _F("expected ' ', but found {ch!r}", ch=ch), self.reader.get_mark(), ) return value @@ -1035,7 +1033,7 @@ class Scanner(object): raise ScannerError( 'while scanning a directive', start_mark, - 'expected a comment or a line break, but found %r' % utf8(ch), + _F('expected a comment or a line break, but found {ch!r}', ch=ch), self.reader.get_mark(), ) self.scan_line_break() @@ -1060,16 +1058,16 @@ class Scanner(object): self.reader.forward() length = 0 ch = srp(length) - # while u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z' \ - # or ch in u'-_': + # while '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z' \ + # or ch in '-_': while check_anchorname_char(ch): length += 1 ch = srp(length) if not length: raise ScannerError( - 'while scanning an %s' % (name,), + _F('while scanning an {name!s}', name=name), start_mark, - 'expected alphabetic or numeric character, but found %r' % utf8(ch), + _F('expected alphabetic or numeric character, but found {ch!r}', ch=ch), self.reader.get_mark(), ) value = self.reader.prefix(length) @@ -1079,9 +1077,9 @@ class Scanner(object): # assert ch1 == ch if ch not in '\0 \t\r\n\x85\u2028\u2029?:,[]{}%@`': raise ScannerError( - 'while scanning an %s' % (name,), + _F('while scanning an {name!s}', name=name), start_mark, - 'expected alphabetic or numeric character, but found %r' % utf8(ch), + _F('expected alphabetic or numeric character, but found {ch!r}', ch=ch), self.reader.get_mark(), ) end_mark = self.reader.get_mark() @@ -1101,7 +1099,7 @@ class Scanner(object): raise ScannerError( 'while parsing a tag', start_mark, - "expected '>', but found %r" % utf8(srp()), + _F("expected '>', but found {srp_call!r}", srp_call=srp()), self.reader.get_mark(), ) self.reader.forward() @@ -1130,7 +1128,7 @@ class Scanner(object): raise ScannerError( 'while scanning a tag', start_mark, - "expected ' ', but found %r" % utf8(ch), + _F("expected ' ', but found {ch!r}", ch=ch), self.reader.get_mark(), ) value = (handle, suffix) @@ -1209,10 +1207,10 @@ class Scanner(object): # This is Clark Evans's interpretation (also in the spec # examples): # - # if folded and line_break == u'\n': + # if folded and line_break == '\n': # if not breaks: # if srp() not in ' \t': - # chunks.append(u' ') + # chunks.append(' ') # else: # chunks.append(line_break) # else: @@ -1295,7 +1293,7 @@ class Scanner(object): raise ScannerError( 'while scanning a block scalar', start_mark, - 'expected chomping or indentation indicators, but found %r' % utf8(ch), + _F('expected chomping or indentation indicators, but found {ch!r}', ch=ch), self.reader.get_mark(), ) return chomping, increment @@ -1320,7 +1318,7 @@ class Scanner(object): raise ScannerError( 'while scanning a block scalar', start_mark, - 'expected a comment or a line break, but found %r' % utf8(ch), + _F('expected a comment or a line break, but found {ch!r}', ch=ch), self.reader.get_mark(), ) self.scan_line_break() @@ -1442,12 +1440,16 @@ class Scanner(object): raise ScannerError( 'while scanning a double-quoted scalar', start_mark, - 'expected escape sequence of %d hexdecimal ' - 'numbers, but found %r' % (length, utf8(srp(k))), + _F( + 'expected escape sequence of {length:d} hexdecimal ' + 'numbers, but found {srp_call!r}', + length=length, + srp_call=srp(k), + ), self.reader.get_mark(), ) code = int(self.reader.prefix(length), 16) - chunks.append(unichr(code)) + chunks.append(chr(code)) srf(length) elif ch in '\n\r\x85\u2028\u2029': self.scan_line_break() @@ -1456,7 +1458,7 @@ class Scanner(object): raise ScannerError( 'while scanning a double-quoted scalar', start_mark, - 'found unknown escape character %r' % utf8(ch), + _F('found unknown escape character {ch!r}', ch=ch), self.reader.get_mark(), ) else: @@ -1640,9 +1642,9 @@ class Scanner(object): ch = srp() if ch != '!': raise ScannerError( - 'while scanning a %s' % (name,), + _F('while scanning an {name!s}', name=name), start_mark, - "expected '!', but found %r" % utf8(ch), + _F("expected '!', but found {ch!r}", ch=ch), self.reader.get_mark(), ) length = 1 @@ -1654,9 +1656,9 @@ class Scanner(object): if ch != '!': self.reader.forward(length) raise ScannerError( - 'while scanning a %s' % (name,), + _F('while scanning an {name!s}', name=name), start_mark, - "expected '!', but found %r" % utf8(ch), + _F("expected '!', but found {ch!r}", ch=ch), self.reader.get_mark(), ) length += 1 @@ -1693,9 +1695,9 @@ class Scanner(object): length = 0 if not chunks: raise ScannerError( - 'while parsing a %s' % (name,), + _F('while parsing an {name!s}', name=name), start_mark, - 'expected URI, but found %r' % utf8(ch), + _F('expected URI, but found {ch!r}', ch=ch), self.reader.get_mark(), ) return "".join(chunks) @@ -1712,24 +1714,23 @@ class Scanner(object): for k in range(2): if srp(k) not in '0123456789ABCDEFabcdef': raise ScannerError( - 'while scanning a %s' % (name,), + _F('while scanning an {name!s}', name=name), start_mark, - 'expected URI escape sequence of 2 hexdecimal numbers,' - ' but found %r' % utf8(srp(k)), + _F( + 'expected URI escape sequence of 2 hexdecimal numbers,' + ' but found {srp_call!r}', + srp_call=srp(k), + ), self.reader.get_mark(), ) - if PY3: - code_bytes.append(int(self.reader.prefix(2), 16)) - else: - code_bytes.append(chr(int(self.reader.prefix(2), 16))) + code_bytes.append(int(self.reader.prefix(2), 16)) srf(2) try: - if PY3: - value = bytes(code_bytes).decode('utf-8') - else: - value = unicode(b"".join(code_bytes), 'utf-8') + value = bytes(code_bytes).decode('utf-8') except UnicodeDecodeError as exc: - raise ScannerError('while scanning a %s' % (name,), start_mark, str(exc), mark) + raise ScannerError( + _F('while scanning an {name!s}', name=name), + start_mark, str(exc), mark) return value def scan_line_break(self): diff --git a/serializer.py b/serializer.py index a37885c..19b0424 100644 --- a/serializer.py +++ b/serializer.py @@ -1,9 +1,7 @@ # coding: utf-8 -from __future__ import absolute_import - from ruamel.yaml.error import YAMLError -from ruamel.yaml.compat import nprint, DBG_NODE, dbg, string_types, nprintf # NOQA +from ruamel.yaml.compat import nprint, DBG_NODE, dbg, nprintf # NOQA from ruamel.yaml.util import RegExp from ruamel.yaml.events import ( @@ -34,8 +32,8 @@ class SerializerError(YAMLError): class Serializer(object): # 'id' and 3+ numbers, but not 000 - ANCHOR_TEMPLATE = u'id%03d' - ANCHOR_RE = RegExp(u'id(?!000$)\\d{3,}') + ANCHOR_TEMPLATE = 'id%03d' + ANCHOR_RE = RegExp('id(?!000$)\\d{3,}') def __init__( self, @@ -53,7 +51,7 @@ class Serializer(object): self.use_encoding = encoding self.use_explicit_start = explicit_start self.use_explicit_end = explicit_end - if isinstance(version, string_types): + if isinstance(version, str): self.use_version = tuple(map(int, version.split('.'))) else: self.use_version = version # type: ignore diff --git a/timestamp.py b/timestamp.py index e44db44..b123951 100644 --- a/timestamp.py +++ b/timestamp.py @@ -1,8 +1,5 @@ - # coding: utf-8 -from __future__ import print_function, absolute_import, division, unicode_literals - import datetime import copy diff --git a/tokens.py b/tokens.py index 5f5a663..3d3c566 100644 --- a/tokens.py +++ b/tokens.py @@ -1,7 +1,6 @@ -# # header # coding: utf-8 -from __future__ import unicode_literals +from ruamel.yaml.compat import _F if False: # MYPY from typing import Text, Any, Dict, Optional, List # NOQA @@ -24,7 +23,9 @@ class Token(object): # hasattr('self', key)] attributes = [key for key in self.__slots__ if not key.endswith('_mark')] attributes.sort() - arguments = ', '.join(['%s=%r' % (key, getattr(self, key)) for key in attributes]) + arguments = ', '.join( + [_F('{key!s}={gattr!r})', key=key, gattr=getattr(self, key)) for key in attributes] + ) if SHOWLINES: try: arguments += ', line: ' + str(self.start_mark.line) @@ -81,7 +82,7 @@ class Token(object): # nprint('mco2:', self, target, target.comment, empty) return self if c[0] and tc[0] or c[1] and tc[1]: - raise NotImplementedError('overlap in comment %r %r' % (c, tc)) + raise NotImplementedError(_F('overlap in comment {c!r} {tc!r}', c=c, tc=tc)) if c[0]: tc[0] = c[0] if c[1]: diff --git a/util.py b/util.py index 1788254..1f0b71b 100644 --- a/util.py +++ b/util.py @@ -4,12 +4,9 @@ some helper functions that might be generally useful """ -from __future__ import absolute_import, print_function - from functools import partial import re -from .compat import text_type, binary_type if False: # MYPY from typing import Any, Dict, Optional, List, Text # NOQA @@ -66,9 +63,9 @@ def load_yaml_guess_indent(stream, **kw): - if there are no block sequences, indent is taken from nested mappings, block sequence indent is unset (None) in that case """ - from .main import round_trip_load + from .main import YAML - # load a YAML document, guess the indentation, if you use TABs you're on your own + # load a YAML document, guess the indentation, if you use TABs you are on your own def leading_spaces(line): # type: (Any) -> int idx = 0 @@ -76,9 +73,9 @@ def load_yaml_guess_indent(stream, **kw): idx += 1 return idx - if isinstance(stream, text_type): + if isinstance(stream, str): yaml_str = stream # type: Any - elif isinstance(stream, binary_type): + elif isinstance(stream, bytes): # most likely, but the Reader checks BOM for this yaml_str = stream.decode('utf-8') else: @@ -117,7 +114,8 @@ def load_yaml_guess_indent(stream, **kw): prev_line_key_only = None if indent is None and map_indent is not None: indent = map_indent - return round_trip_load(yaml_str, **kw), indent, block_seq_indent + yaml = YAML() + return yaml.load(yaml_str, **kw), indent, block_seq_indent def configobj_walker(cfg): @@ -145,28 +143,28 @@ def _walk_section(s, level=0): from configobj import Section assert isinstance(s, Section) - indent = u' ' * level + indent = ' ' * level for name in s.scalars: for c in s.comments[name]: yield indent + c.strip() x = s[name] - if u'\n' in x: - i = indent + u' ' - x = u'|\n' + i + x.strip().replace(u'\n', u'\n' + i) + if '\n' in x: + i = indent + ' ' + x = '|\n' + i + x.strip().replace('\n', '\n' + i) elif ':' in x: - x = u"'" + x.replace(u"'", u"''") + u"'" - line = u'{0}{1}: {2}'.format(indent, name, x) + x = "'" + x.replace("'", "''") + "'" + line = '{0}{1}: {2}'.format(indent, name, x) c = s.inline_comments[name] if c: - line += u' ' + c + line += ' ' + c yield line for name in s.sections: for c in s.comments[name]: yield indent + c.strip() - line = u'{0}{1}:'.format(indent, name) + line = '{0}{1}:'.format(indent, name) c = s.inline_comments[name] if c: - line += u' ' + c + line += ' ' + c yield line for val in _walk_section(s[name], level=level + 1): yield val -- cgit v1.2.1