diff --git a/tests/test_cli.py b/tests/test_cli.py index 241e0f4a..444f2f9e 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -286,8 +286,8 @@ def test_run_with_implicit_extends_config(self): with RunContext(self) as ctx: cli.run(('-d', 'default', '-f', 'parsable', path)) - expected_out = ('%s:1:1: [warning] missing document start "---" ' - '(document-start)\n' % path) + expected_out = (f'{path}:1:1: [warning] missing document start "---" ' + f'(document-start)\n') self.assertEqual( (ctx.returncode, ctx.stdout, ctx.stderr), (0, expected_out, '')) @@ -424,9 +424,9 @@ def test_run_one_problem_file(self): cli.run(('-f', 'parsable', path)) self.assertEqual(ctx.returncode, 1) self.assertEqual(ctx.stdout, ( - '%s:2:4: [error] trailing spaces (trailing-spaces)\n' - '%s:3:4: [error] no new line character at the end of file ' - '(new-line-at-end-of-file)\n' % (path, path))) + f'{path}:2:4: [error] trailing spaces (trailing-spaces)\n' + f'{path}:3:4: [error] no new line character at the end of file ' + f'(new-line-at-end-of-file)\n')) self.assertEqual(ctx.stderr, '') def test_run_one_warning(self): @@ -476,8 +476,8 @@ def test_run_multiple_files(self): cli.run(['-f', 'parsable'] + items) self.assertEqual((ctx.returncode, ctx.stderr), (1, '')) self.assertEqual(ctx.stdout, ( - '%s:3:1: [error] duplication of key "key" in mapping ' - '(key-duplicates)\n') % path) + f'{path}:3:1: [error] duplication of key "key" in mapping ' + f'(key-duplicates)\n')) def test_run_piped_output_nocolor(self): path = os.path.join(self.wd, 'a.yaml') @@ -486,11 +486,11 @@ def test_run_piped_output_nocolor(self): cli.run((path, )) self.assertEqual((ctx.returncode, ctx.stderr), (1, '')) self.assertEqual(ctx.stdout, ( - '%s\n' - ' 2:4 error trailing spaces (trailing-spaces)\n' - ' 3:4 error no new line character at the end of file ' - '(new-line-at-end-of-file)\n' - '\n' % path)) + f'{path}\n' + f' 2:4 error trailing spaces (trailing-spaces)\n' + f' 3:4 error no new line character at the end of file ' + f'(new-line-at-end-of-file)\n' + f'\n')) def test_run_default_format_output_in_tty(self): path = os.path.join(self.wd, 'a.yaml') @@ -517,13 +517,13 @@ def test_run_default_format_output_in_tty(self): output.close() self.assertEqual(out, ( - '\033[4m%s\033[0m\n' - ' \033[2m2:4\033[0m \033[31merror\033[0m ' - 'trailing spaces \033[2m(trailing-spaces)\033[0m\n' - ' \033[2m3:4\033[0m \033[31merror\033[0m ' - 'no new line character at the end of file ' - '\033[2m(new-line-at-end-of-file)\033[0m\n' - '\n' % path)) + f'\033[4m{path}\033[0m\n' + f' \033[2m2:4\033[0m \033[31merror\033[0m ' + f'trailing spaces \033[2m(trailing-spaces)\033[0m\n' + f' \033[2m3:4\033[0m \033[31merror\033[0m ' + f'no new line character at the end of file ' + f'\033[2m(new-line-at-end-of-file)\033[0m\n' + f'\n')) def test_run_default_format_output_without_tty(self): path = os.path.join(self.wd, 'a.yaml') @@ -531,11 +531,11 @@ def test_run_default_format_output_without_tty(self): with RunContext(self) as ctx: cli.run((path, )) expected_out = ( - '%s\n' - ' 2:4 error trailing spaces (trailing-spaces)\n' - ' 3:4 error no new line character at the end of file ' - '(new-line-at-end-of-file)\n' - '\n' % path) + f'{path}\n' + f' 2:4 error trailing spaces (trailing-spaces)\n' + f' 3:4 error no new line character at the end of file ' + f'(new-line-at-end-of-file)\n' + f'\n') self.assertEqual( (ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, '')) @@ -545,11 +545,11 @@ def test_run_auto_output_without_tty_output(self): with RunContext(self) as ctx: cli.run((path, '--format', 'auto')) expected_out = ( - '%s\n' - ' 2:4 error trailing spaces (trailing-spaces)\n' - ' 3:4 error no new line character at the end of file ' - '(new-line-at-end-of-file)\n' - '\n' % path) + f'{path}\n' + f' 2:4 error trailing spaces (trailing-spaces)\n' + f' 3:4 error no new line character at the end of file ' + f'(new-line-at-end-of-file)\n' + f'\n') self.assertEqual( (ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, '')) @@ -559,13 +559,13 @@ def test_run_format_colored(self): with RunContext(self) as ctx: cli.run((path, '--format', 'colored')) expected_out = ( - '\033[4m%s\033[0m\n' - ' \033[2m2:4\033[0m \033[31merror\033[0m ' - 'trailing spaces \033[2m(trailing-spaces)\033[0m\n' - ' \033[2m3:4\033[0m \033[31merror\033[0m ' - 'no new line character at the end of file ' - '\033[2m(new-line-at-end-of-file)\033[0m\n' - '\n' % path) + f'\033[4m{path}\033[0m\n' + f' \033[2m2:4\033[0m \033[31merror\033[0m ' + f'trailing spaces \033[2m(trailing-spaces)\033[0m\n' + f' \033[2m3:4\033[0m \033[31merror\033[0m ' + f'no new line character at the end of file ' + f'\033[2m(new-line-at-end-of-file)\033[0m\n' + f'\n') self.assertEqual( (ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, '')) @@ -575,10 +575,10 @@ def test_run_format_colored_warning(self): with RunContext(self) as ctx: cli.run((path, '--format', 'colored')) expected_out = ( - '\033[4m%s\033[0m\n' - ' \033[2m1:1\033[0m \033[33mwarning\033[0m ' - 'missing document start "---" \033[2m(document-start)\033[0m\n' - '\n' % path) + f'\033[4m{path}\033[0m\n' + f' \033[2m1:1\033[0m \033[33mwarning\033[0m ' + f'missing document start "---" \033[2m(document-start)\033[0m\n' + f'\n') self.assertEqual( (ctx.returncode, ctx.stdout, ctx.stderr), (0, expected_out, '')) @@ -588,13 +588,12 @@ def test_run_format_github(self): with RunContext(self) as ctx: cli.run((path, '--format', 'github')) expected_out = ( - '::group::%s\n' - '::error file=%s,line=2,col=4::2:4 [trailing-spaces] trailing' - ' spaces\n' - '::error file=%s,line=3,col=4::3:4 [new-line-at-end-of-file] no' - ' new line character at the end of file\n' - '::endgroup::\n\n' - % (path, path, path)) + f'::group::{path}\n' + f'::error file={path},line=2,col=4::2:4 [trailing-spaces] trailing' + f' spaces\n' + f'::error file={path},line=3,col=4::3:4 [new-line-at-end-of-file]' + f' no new line character at the end of file\n' + f'::endgroup::\n\n') self.assertEqual( (ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, '')) @@ -608,13 +607,12 @@ def test_github_actions_detection(self): os.environ['GITHUB_WORKFLOW'] = 'something' cli.run((path, )) expected_out = ( - '::group::%s\n' - '::error file=%s,line=2,col=4::2:4 [trailing-spaces] trailing' - ' spaces\n' - '::error file=%s,line=3,col=4::3:4 [new-line-at-end-of-file] no' - ' new line character at the end of file\n' - '::endgroup::\n\n' - % (path, path, path)) + f'::group::{path}\n' + f'::error file={path},line=2,col=4::2:4 [trailing-spaces] trailing' + f' spaces\n' + f'::error file={path},line=3,col=4::3:4 [new-line-at-end-of-file]' + f' no new line character at the end of file\n' + f'::endgroup::\n\n') self.assertEqual( (ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, '')) @@ -640,11 +638,11 @@ def test_run_no_warnings(self): with RunContext(self) as ctx: cli.run((path, '--no-warnings', '-f', 'auto')) expected_out = ( - '%s\n' - ' 2:4 error trailing spaces (trailing-spaces)\n' - ' 3:4 error no new line character at the end of file ' - '(new-line-at-end-of-file)\n' - '\n' % path) + f'{path}\n' + f' 2:4 error trailing spaces (trailing-spaces)\n' + f' 3:4 error no new line character at the end of file ' + f'(new-line-at-end-of-file)\n' + f'\n') self.assertEqual( (ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, '')) @@ -671,10 +669,10 @@ def test_run_non_universal_newline(self): with RunContext(self) as ctx: cli.run(('-d', 'rules:\n new-lines:\n type: unix', path)) expected_out = ( - '%s\n' - ' 1:4 error wrong new line character: expected \\n' - ' (new-lines)\n' - '\n' % path) + f'{path}\n' + f' 1:4 error wrong new line character: expected \\n' + f' (new-lines)\n' + f'\n') self.assertEqual( (ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, '')) diff --git a/tests/test_spec_examples.py b/tests/test_spec_examples.py index c04e3995..ac68e12e 100644 --- a/tests/test_spec_examples.py +++ b/tests/test_spec_examples.py @@ -39,7 +39,7 @@ # text = text.replace('\u21d4', '') # byte order mark # text = text.replace('\u2192', '\t') # right arrow # text = text.replace('\u00b0', '') # empty scalar -# with open('tests/yaml-1.2-spec-examples/%s' % id, 'w', +# with open(f'tests/yaml-1.2-spec-examples/{id}', 'w', # encoding='utf-8') as g: # g.write(text) diff --git a/yamllint/cli.py b/yamllint/cli.py index d7fa1561..604e5940 100644 --- a/yamllint/cli.py +++ b/yamllint/cli.py @@ -49,52 +49,41 @@ def supports_color(): class Format: @staticmethod def parsable(problem, filename): - return ('%(file)s:%(line)s:%(column)s: [%(level)s] %(message)s' % - {'file': filename, - 'line': problem.line, - 'column': problem.column, - 'level': problem.level, - 'message': problem.message}) + return (f'{filename}:{problem.line}:{problem.column}: ' + f'[{problem.level}] {problem.message}') @staticmethod def standard(problem, filename): - line = ' %d:%d' % (problem.line, problem.column) + line = f' {problem.line}:{problem.column}' line += max(12 - len(line), 0) * ' ' line += problem.level line += max(21 - len(line), 0) * ' ' line += problem.desc if problem.rule: - line += ' (%s)' % problem.rule + line += f' ({problem.rule})' return line @staticmethod def standard_color(problem, filename): - line = ' \033[2m%d:%d\033[0m' % (problem.line, problem.column) + line = f' \033[2m{problem.line}:{problem.column}\033[0m' line += max(20 - len(line), 0) * ' ' if problem.level == 'warning': - line += '\033[33m%s\033[0m' % problem.level + line += f'\033[33m{problem.level}\033[0m' else: - line += '\033[31m%s\033[0m' % problem.level + line += f'\033[31m{problem.level}\033[0m' line += max(38 - len(line), 0) * ' ' line += problem.desc if problem.rule: - line += ' \033[2m(%s)\033[0m' % problem.rule + line += f' \033[2m({problem.rule})\033[0m' return line @staticmethod def github(problem, filename): - line = '::' - line += problem.level - line += ' file=' + filename + ',' - line += 'line=' + format(problem.line) + ',' - line += 'col=' + format(problem.column) - line += '::' - line += format(problem.line) - line += ':' - line += format(problem.column) - line += ' ' + line = f'::{problem.level} file={format(filename)},' \ + f'line={format(problem.line)},col={format(problem.column)}' \ + f'::{format(problem.line)}:{format(problem.column)} ' if problem.rule: - line += '[' + problem.rule + '] ' + line += f'[{problem.rule}] ' line += problem.desc return line @@ -118,12 +107,12 @@ def show_problems(problems, file, args_format, no_warn): print(Format.parsable(problem, file)) elif args_format == 'github': if first: - print('::group::%s' % file) + print(f'::group::{file}') first = False print(Format.github(problem, file)) elif args_format == 'colored': if first: - print('\033[4m%s\033[0m' % file) + print(f'\033[4m{file}\033[0m') first = False print(Format.standard_color(problem, file)) else: @@ -184,7 +173,7 @@ def run(argv=None): action='store_true', help='output only error level problems') parser.add_argument('-v', '--version', action='version', - version='{} {}'.format(APP_NAME, APP_VERSION)) + version=f'{APP_NAME} {APP_VERSION}') args = parser.parse_args(argv) @@ -202,7 +191,7 @@ def run(argv=None): try: if args.config_data is not None: if args.config_data != '' and ':' not in args.config_data: - args.config_data = 'extends: ' + args.config_data + args.config_data = f'extends: {args.config_data}' conf = YamlLintConfig(content=args.config_data) elif args.config_file is not None: conf = YamlLintConfig(file=args.config_file) diff --git a/yamllint/config.py b/yamllint/config.py index a5ef405e..ca4baf7e 100644 --- a/yamllint/config.py +++ b/yamllint/config.py @@ -76,7 +76,7 @@ def parse(self, raw_content): try: conf = yaml.safe_load(raw_content) except Exception as e: - raise YamlLintConfigError('invalid config: %s' % e) + raise YamlLintConfigError(f'invalid config: {e}') if not isinstance(conf, dict): raise YamlLintConfigError('invalid config: not a dict') @@ -95,7 +95,7 @@ def parse(self, raw_content): try: self.extend(base) except Exception as e: - raise YamlLintConfigError('invalid config: %s' % e) + raise YamlLintConfigError(f'invalid config: {e}') if 'ignore' in conf and 'ignore-from-file' in conf: raise YamlLintConfigError( @@ -143,7 +143,7 @@ def validate(self): try: rule = yamllint.rules.get(id) except Exception as e: - raise YamlLintConfigError('invalid config: %s' % e) + raise YamlLintConfigError(f'invalid config: {e}') self.rules[id] = validate_rule_conf(rule, self.rules[id]) @@ -179,16 +179,16 @@ def validate_rule_conf(rule, conf): continue if optkey not in options: raise YamlLintConfigError( - 'invalid config: unknown option "%s" for rule "%s"' % - (optkey, rule.ID)) + f'invalid config: unknown option "{optkey}" ' + f'for rule "{rule.ID}"') # Example: CONF = {option: (bool, 'mixed')} # → {option: true} → {option: mixed} if isinstance(options[optkey], tuple): if (conf[optkey] not in options[optkey] and type(conf[optkey]) not in options[optkey]): raise YamlLintConfigError( - 'invalid config: option "%s" of "%s" should be in %s' - % (optkey, rule.ID, options[optkey])) + f'invalid config: option "{optkey}" of "{rule.ID}" ' + f'should be in {options[optkey]}') # Example: CONF = {option: ['flag1', 'flag2', int]} # → {option: [flag1]} → {option: [42, flag1, flag2]} elif isinstance(options[optkey], list): @@ -197,16 +197,15 @@ def validate_rule_conf(rule, conf): type(flag) not in options[optkey] for flag in conf[optkey])): raise YamlLintConfigError( - ('invalid config: option "%s" of "%s" should only ' - 'contain values in %s') - % (optkey, rule.ID, str(options[optkey]))) + f'invalid config: option "{optkey}" of "{rule.ID}" ' + f'should only contain values in {options[optkey]}') # Example: CONF = {option: int} # → {option: 42} else: if not isinstance(conf[optkey], options[optkey]): raise YamlLintConfigError( - 'invalid config: option "%s" of "%s" should be %s' - % (optkey, rule.ID, options[optkey].__name__)) + f'invalid config: option "{optkey}" of "{rule.ID}" ' + f'should be {options[optkey].__name__}') for optkey in options: if optkey not in conf: conf[optkey] = options_default[optkey] @@ -214,12 +213,11 @@ def validate_rule_conf(rule, conf): if hasattr(rule, 'VALIDATE'): res = rule.VALIDATE(conf) if res: - raise YamlLintConfigError('invalid config: %s: %s' % - (rule.ID, res)) + raise YamlLintConfigError(f'invalid config: {rule.ID}: {res}') else: - raise YamlLintConfigError(('invalid config: rule "%s": should be ' - 'either "enable", "disable" or a dict') - % rule.ID) + raise YamlLintConfigError( + f'invalid config: rule "{rule.ID}": should be ' + f'either "enable", "disable" or a dict') return conf @@ -228,7 +226,7 @@ def get_extended_config_file(name): # Is it a standard conf shipped with yamllint... if '/' not in name: std_conf = os.path.join(os.path.dirname(os.path.realpath(__file__)), - 'conf', name + '.yaml') + 'conf', f'{name}.yaml') if os.path.isfile(std_conf): return std_conf diff --git a/yamllint/linter.py b/yamllint/linter.py index 5501bb59..0de1f716 100644 --- a/yamllint/linter.py +++ b/yamllint/linter.py @@ -50,7 +50,7 @@ def __init__(self, line, column, desc='', rule=None): @property def message(self): if self.rule is not None: - return '{} ({})'.format(self.desc, self.rule) + return f'{self.desc} ({self.rule})' return self.desc def __eq__(self, other): @@ -63,7 +63,7 @@ def __lt__(self, other): (self.line == other.line and self.column < other.column)) def __repr__(self): - return '%d:%d: %s' % (self.line, self.column, self.message) + return f'{self.line}:{self.column}: {self.message}' def get_cosmetic_problems(buffer, conf, filepath): diff --git a/yamllint/rules/__init__.py b/yamllint/rules/__init__.py index 6b5e4467..606b37a4 100644 --- a/yamllint/rules/__init__.py +++ b/yamllint/rules/__init__.py @@ -68,6 +68,6 @@ def get(id): if id not in _RULES: - raise ValueError('no such rule: "%s"' % id) + raise ValueError(f'no such rule: "{id}"') return _RULES[id] diff --git a/yamllint/rules/empty_lines.py b/yamllint/rules/empty_lines.py index 73a9fd1e..eca78125 100644 --- a/yamllint/rules/empty_lines.py +++ b/yamllint/rules/empty_lines.py @@ -113,5 +113,5 @@ def check(conf, line): max = conf['max-end'] if blank_lines > max: - yield LintProblem(line.line_no, 1, 'too many blank lines (%d > %d)' - % (blank_lines, max)) + yield LintProblem(line.line_no, 1, + f'too many blank lines ({blank_lines} > {max})') diff --git a/yamllint/rules/indentation.py b/yamllint/rules/indentation.py index e63a733a..15e508ba 100644 --- a/yamllint/rules/indentation.py +++ b/yamllint/rules/indentation.py @@ -227,7 +227,7 @@ def __init__(self, type, indent, line_indent=None): self.implicit_block_seq = False def __repr__(self): - return '%s:%d' % (labels[self.type], self.indent) + return f'{labels[self.type]}:{self.indent}' def check_scalar_indentation(conf, token, context): @@ -303,8 +303,8 @@ def detect_indent(base_indent): if indent != expected_indent: yield LintProblem(line_no, indent + 1, - 'wrong indentation: expected %d but found %d' % - (expected_indent, indent)) + f'wrong indentation: expected {expected_indent}' + f'but found {indent}') def _check(conf, token, prev, next, nextnext, context): @@ -342,11 +342,11 @@ def detect_indent(base_indent, next): if found_indentation != expected: if expected < 0: - message = 'wrong indentation: expected at least %d' % \ - (found_indentation + 1) + message = f'wrong indentation: expected ' \ + f'at least {found_indentation + 1}' else: - message = 'wrong indentation: expected %d but found %d' % \ - (expected, found_indentation) + message = f'wrong indentation: expected {expected} ' \ + f'but found {found_indentation}' yield LintProblem(token.start_mark.line + 1, found_indentation + 1, message) diff --git a/yamllint/rules/key_duplicates.py b/yamllint/rules/key_duplicates.py index 3f93e7dc..771a8e2a 100644 --- a/yamllint/rules/key_duplicates.py +++ b/yamllint/rules/key_duplicates.py @@ -95,6 +95,6 @@ def check(conf, token, prev, next, nextnext, context): next.value != '<<'): yield LintProblem( next.start_mark.line + 1, next.start_mark.column + 1, - 'duplication of key "%s" in mapping' % next.value) + f'duplication of key "{next.value}" in mapping') else: context['stack'][-1].keys.append(next.value) diff --git a/yamllint/rules/key_ordering.py b/yamllint/rules/key_ordering.py index ad38ed71..7fa9597a 100644 --- a/yamllint/rules/key_ordering.py +++ b/yamllint/rules/key_ordering.py @@ -122,6 +122,6 @@ def check(conf, token, prev, next, nextnext, context): for key in context['stack'][-1].keys): yield LintProblem( next.start_mark.line + 1, next.start_mark.column + 1, - 'wrong ordering of key "%s" in mapping' % next.value) + f'wrong ordering of key "{next.value}" in mapping') else: context['stack'][-1].keys.append(next.value) diff --git a/yamllint/rules/octal_values.py b/yamllint/rules/octal_values.py index 7796e505..eb24c81f 100644 --- a/yamllint/rules/octal_values.py +++ b/yamllint/rules/octal_values.py @@ -99,8 +99,7 @@ def check(conf, token, prev, next, nextnext, context): IS_OCTAL_NUMBER_PATTERN.match(val[1:])): yield LintProblem( token.start_mark.line + 1, token.end_mark.column + 1, - 'forbidden implicit octal value "%s"' % - token.value) + f'forbidden implicit octal value "{token.value}"') if conf['forbid-explicit-octal']: if isinstance(token, yaml.tokens.ScalarToken): @@ -110,5 +109,4 @@ def check(conf, token, prev, next, nextnext, context): IS_OCTAL_NUMBER_PATTERN.match(val[2:])): yield LintProblem( token.start_mark.line + 1, token.end_mark.column + 1, - 'forbidden explicit octal value "%s"' % - token.value) + f'forbidden explicit octal value "{token.value}"') diff --git a/yamllint/rules/quoted_strings.py b/yamllint/rules/quoted_strings.py index e4c86f16..9380ae57 100644 --- a/yamllint/rules/quoted_strings.py +++ b/yamllint/rules/quoted_strings.py @@ -240,7 +240,7 @@ def check(conf, token, prev, next, nextnext, context): if (token.style is None or not (_quote_match(quote_type, token.style) or (conf['allow-quoted-quotes'] and _has_quoted_quotes(token)))): - msg = "string value is not quoted with %s quotes" % quote_type + msg = f"string value is not quoted with {quote_type} quotes" elif conf['required'] is False: @@ -249,7 +249,7 @@ def check(conf, token, prev, next, nextnext, context): not _quote_match(quote_type, token.style) and not (conf['allow-quoted-quotes'] and _has_quoted_quotes(token))): - msg = "string value is not quoted with %s quotes" % quote_type + msg = f"string value is not quoted with {quote_type} quotes" elif not token.style: is_extra_required = any(re.search(r, token.value) @@ -267,14 +267,14 @@ def check(conf, token, prev, next, nextnext, context): is_extra_allowed = any(re.search(r, token.value) for r in conf['extra-allowed']) if not (is_extra_required or is_extra_allowed): - msg = "string value is redundantly quoted with %s quotes" % ( - quote_type) + msg = f"string value is redundantly quoted with " \ + f"{quote_type} quotes" # But when used need to match config elif (token.style and not _quote_match(quote_type, token.style) and not (conf['allow-quoted-quotes'] and _has_quoted_quotes(token))): - msg = "string value is not quoted with %s quotes" % quote_type + msg = f"string value is not quoted with {quote_type} quotes" elif not token.style: is_extra_required = len(conf['extra-required']) and any(