From 3288d0596e4522acfeb12bdfe8c1aaa3974e686c Mon Sep 17 00:00:00 2001 From: Henry Gessau Date: Mon, 11 Dec 2023 08:23:23 -0500 Subject: [PATCH] quoted-strings: Add check-keys option --- tests/rules/test_quoted_strings.py | 721 ++++++++++++++++++++++++++++- yamllint/rules/quoted_strings.py | 40 +- 2 files changed, 751 insertions(+), 10 deletions(-) diff --git a/tests/rules/test_quoted_strings.py b/tests/rules/test_quoted_strings.py index 040ea79..1bcb6f8 100644 --- a/tests/rules/test_quoted_strings.py +++ b/tests/rules/test_quoted_strings.py @@ -18,7 +18,7 @@ from tests.common import RuleTestCase from yamllint import config -class QuotedTestCase(RuleTestCase): +class QuotedValuesTestCase(RuleTestCase): rule_id = 'quoted-strings' def test_disabled(self): @@ -595,3 +595,722 @@ class QuotedTestCase(RuleTestCase): "foo1: '[barbaz]'\n" "foo2: '[bar\"baz]'\n", conf) + + +class QuotedKeysTestCase(RuleTestCase): + rule_id = 'quoted-strings' + + def test_disabled(self): + conf_disabled = "quoted-strings: {}" + key_strings = ('---\n' + 'true: 2\n' + '123: 3\n' + 'foo1: 4\n' + '"foo2": 5\n' + '"false": 6\n' + '"234": 7\n' + '\'bar\': 8\n' + '!!str generic_string: 9\n' + '!!str 456: 10\n' + '!!str "quoted_generic_string": 11\n' + '!!binary binstring: 12\n' + '!!int int_string: 13\n' + '!!bool bool_string: 14\n' + '!!bool "quoted_bool_string": 15\n' + # Sequences and mappings + '? - 16\n' + ' - 17\n' + ': 18\n' + '[119, 219]: 19\n' + '? a: 20\n' + ' "b": 21\n' + ': 22\n' + '{a: 123, "b": 223}: 23\n' + # Multiline strings + '? |\n' + ' line 1\n' + ' line 2\n' + ': 27\n' + '? >\n' + ' line 1\n' + ' line 2\n' + ': 31\n' + '?\n' + ' line 1\n' + ' line 2\n' + ': 35\n' + '?\n' + ' "line 1\\\n' + ' line 2"\n' + ': 39\n') + self.check(key_strings, conf_disabled) + + def test_default(self): + # Default configuration, but with check-keys + conf_default = ("quoted-strings:\n" + " check-keys: true\n") + key_strings = ('---\n' + 'true: 2\n' + '123: 3\n' + 'foo1: 4\n' + '"foo2": 5\n' + '"false": 6\n' + '"234": 7\n' + '\'bar\': 8\n' + '!!str generic_string: 9\n' + '!!str 456: 10\n' + '!!str "quoted_generic_string": 11\n' + '!!binary binstring: 12\n' + '!!int int_string: 13\n' + '!!bool bool_string: 14\n' + '!!bool "quoted_bool_string": 15\n' + # Sequences and mappings + '? - 16\n' + ' - 17\n' + ': 18\n' + '[119, 219]: 19\n' + '? a: 20\n' + ' "b": 21\n' + ': 22\n' + '{a: 123, "b": 223}: 23\n' + # Multiline strings + '? |\n' + ' line 1\n' + ' line 2\n' + ': 27\n' + '? >\n' + ' line 1\n' + ' line 2\n' + ': 31\n' + '?\n' + ' line 1\n' + ' line 2\n' + ': 35\n' + '?\n' + ' "line 1\\\n' + ' line 2"\n' + ': 39\n') + self.check(key_strings, conf_default, problem1=(4, 1), + problem3=(20, 3), problem4=(23, 2), problem5=(33, 3)) + + def test_quote_type_any(self): + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: any\n') + + key_strings = ('---\n' + 'true: 2\n' + '123: 3\n' + 'foo1: 4\n' + '"foo2": 5\n' + '"false": 6\n' + '"234": 7\n' + '\'bar\': 8\n' + '!!str generic_string: 9\n' + '!!str 456: 10\n' + '!!str "quoted_generic_string": 11\n' + '!!binary binstring: 12\n' + '!!int int_string: 13\n' + '!!bool bool_string: 14\n' + '!!bool "quoted_bool_string": 15\n' + # Sequences and mappings + '? - 16\n' + ' - 17\n' + ': 18\n' + '[119, 219]: 19\n' + '? a: 20\n' + ' "b": 21\n' + ': 22\n' + '{a: 123, "b": 223}: 23\n' + # Multiline strings + '? |\n' + ' line 1\n' + ' line 2\n' + ': 27\n' + '? >\n' + ' line 1\n' + ' line 2\n' + ': 31\n' + '?\n' + ' line 1\n' + ' line 2\n' + ': 35\n' + '?\n' + ' "line 1\\\n' + ' line 2"\n' + ': 39\n') + self.check(key_strings, conf, + problem1=(4, 1), problem2=(20, 3), problem3=(23, 2), + problem4=(33, 3)) + + def test_quote_type_single(self): + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: single\n') + + key_strings = ('---\n' + 'true: 2\n' + '123: 3\n' + 'foo1: 4\n' + '"foo2": 5\n' + '"false": 6\n' + '"234": 7\n' + '\'bar\': 8\n' + '!!str generic_string: 9\n' + '!!str 456: 10\n' + '!!str "quoted_generic_string": 11\n' + '!!binary binstring: 12\n' + '!!int int_string: 13\n' + '!!bool bool_string: 14\n' + '!!bool "quoted_bool_string": 15\n' + # Sequences and mappings + '? - 16\n' + ' - 17\n' + ': 18\n' + '[119, 219]: 19\n' + '? a: 20\n' + ' "b": 21\n' + ': 22\n' + '{a: 123, "b": 223}: 23\n' + # Multiline strings + '? |\n' + ' line 1\n' + ' line 2\n' + ': 27\n' + '? >\n' + ' line 1\n' + ' line 2\n' + ': 31\n' + '?\n' + ' line 1\n' + ' line 2\n' + ': 35\n' + '?\n' + ' "line 1\\\n' + ' line 2"\n' + ': 39\n') + self.check(key_strings, conf, + problem1=(4, 1), problem2=(5, 1), problem3=(6, 1), + problem4=(7, 1), problem5=(20, 3), problem6=(21, 3), + problem7=(23, 2), problem8=(23, 10), problem9=(33, 3), + problem10=(37, 3)) + + def test_quote_type_double(self): + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: double\n') + + key_strings = ('---\n' + 'true: 2\n' + '123: 3\n' + 'foo1: 4\n' + '"foo2": 5\n' + '"false": 6\n' + '"234": 7\n' + '\'bar\': 8\n' + '!!str generic_string: 9\n' + '!!str 456: 10\n' + '!!str "quoted_generic_string": 11\n' + '!!binary binstring: 12\n' + '!!int int_string: 13\n' + '!!bool bool_string: 14\n' + '!!bool "quoted_bool_string": 15\n' + # Sequences and mappings + '? - 16\n' + ' - 17\n' + ': 18\n' + '[119, 219]: 19\n' + '? a: 20\n' + ' "b": 21\n' + ': 22\n' + '{a: 123, "b": 223}: 23\n' + # Multiline strings + '? |\n' + ' line 1\n' + ' line 2\n' + ': 27\n' + '? >\n' + ' line 1\n' + ' line 2\n' + ': 31\n' + '?\n' + ' line 1\n' + ' line 2\n' + ': 35\n' + '?\n' + ' "line 1\\\n' + ' line 2"\n' + ': 39\n') + self.check(key_strings, conf, + problem1=(4, 1), problem2=(8, 1), problem3=(20, 3), + problem4=(23, 2), problem5=(33, 3)) + + def test_any_quotes_not_required(self): + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: any\n' + ' required: false\n') + + key_strings = ('---\n' + 'true: 2\n' + '123: 3\n' + 'foo1: 4\n' + '"foo2": 5\n' + '"false": 6\n' + '"234": 7\n' + '\'bar\': 8\n' + '!!str generic_string: 9\n' + '!!str 456: 10\n' + '!!str "quoted_generic_string": 11\n' + '!!binary binstring: 12\n' + '!!int int_string: 13\n' + '!!bool bool_string: 14\n' + '!!bool "quoted_bool_string": 15\n' + # Sequences and mappings + '? - 16\n' + ' - 17\n' + ': 18\n' + '[119, 219]: 19\n' + '? a: 20\n' + ' "b": 21\n' + ': 22\n' + '{a: 123, "b": 223}: 23\n' + # Multiline strings + '? |\n' + ' line 1\n' + ' line 2\n' + ': 27\n' + '? >\n' + ' line 1\n' + ' line 2\n' + ': 31\n' + '?\n' + ' line 1\n' + ' line 2\n' + ': 35\n' + '?\n' + ' "line 1\\\n' + ' line 2"\n' + ': 39\n') + self.check(key_strings, conf) + + def test_single_quotes_not_required(self): + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: single\n' + ' required: false\n') + + key_strings = ('---\n' + 'true: 2\n' + '123: 3\n' + 'foo1: 4\n' + '"foo2": 5\n' + '"false": 6\n' + '"234": 7\n' + '\'bar\': 8\n' + '!!str generic_string: 9\n' + '!!str 456: 10\n' + '!!str "quoted_generic_string": 11\n' + '!!binary binstring: 12\n' + '!!int int_string: 13\n' + '!!bool bool_string: 14\n' + '!!bool "quoted_bool_string": 15\n' + # Sequences and mappings + '? - 16\n' + ' - 17\n' + ': 18\n' + '[119, 219]: 19\n' + '? a: 20\n' + ' "b": 21\n' + ': 22\n' + '{a: 123, "b": 223}: 23\n' + # Multiline strings + '? |\n' + ' line 1\n' + ' line 2\n' + ': 27\n' + '? >\n' + ' line 1\n' + ' line 2\n' + ': 31\n' + '?\n' + ' line 1\n' + ' line 2\n' + ': 35\n' + '?\n' + ' "line 1\\\n' + ' line 2"\n' + ': 39\n') + self.check(key_strings, conf, + problem1=(5, 1), problem2=(6, 1), problem3=(7, 1), + problem4=(21, 3), problem5=(23, 10), problem6=(37, 3)) + + def test_only_when_needed(self): + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' required: only-when-needed\n') + + key_strings = ('---\n' + 'true: 2\n' + '123: 3\n' + 'foo1: 4\n' + '"foo2": 5\n' + '"false": 6\n' + '"234": 7\n' + '\'bar\': 8\n' + '!!str generic_string: 9\n' + '!!str 456: 10\n' + '!!str "quoted_generic_string": 11\n' + '!!binary binstring: 12\n' + '!!int int_string: 13\n' + '!!bool bool_string: 14\n' + '!!bool "quoted_bool_string": 15\n' + # Sequences and mappings + '? - 16\n' + ' - 17\n' + ': 18\n' + '[119, 219]: 19\n' + '? a: 20\n' + ' "b": 21\n' + ': 22\n' + '{a: 123, "b": 223}: 23\n' + # Multiline strings + '? |\n' + ' line 1\n' + ' line 2\n' + ': 27\n' + '? >\n' + ' line 1\n' + ' line 2\n' + ': 31\n' + '?\n' + ' line 1\n' + ' line 2\n' + ': 35\n' + '?\n' + ' "line 1\\\n' + ' line 2"\n' + ': 39\n') + self.check(key_strings, conf, + problem1=(5, 1), problem2=(8, 1), problem3=(21, 3), + problem4=(23, 10), problem5=(37, 3)) + + def test_only_when_needed_single_quotes(self): + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: single\n' + ' required: only-when-needed\n') + + key_strings = ('---\n' + 'true: 2\n' + '123: 3\n' + 'foo1: 4\n' + '"foo2": 5\n' + '"false": 6\n' + '"234": 7\n' + '\'bar\': 8\n' + '!!str generic_string: 9\n' + '!!str 456: 10\n' + '!!str "quoted_generic_string": 11\n' + '!!binary binstring: 12\n' + '!!int int_string: 13\n' + '!!bool bool_string: 14\n' + '!!bool "quoted_bool_string": 15\n' + # Sequences and mappings + '? - 16\n' + ' - 17\n' + ': 18\n' + '[119, 219]: 19\n' + '? a: 20\n' + ' "b": 21\n' + ': 22\n' + '{a: 123, "b": 223}: 23\n' + # Multiline strings + '? |\n' + ' line 1\n' + ' line 2\n' + ': 27\n' + '? >\n' + ' line 1\n' + ' line 2\n' + ': 31\n' + '?\n' + ' line 1\n' + ' line 2\n' + ': 35\n' + '?\n' + ' "line 1\\\n' + ' line 2"\n' + ': 39\n') + self.check(key_strings, conf, + problem1=(5, 1), problem2=(6, 1), problem3=(7, 1), + problem4=(8, 1), problem5=(21, 3), problem6=(23, 10), + problem7=(37, 3)) + + def test_only_when_needed_corner_cases(self): + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' required: only-when-needed\n') + + self.check('---\n' + '"": 2\n' + '"- item": 3\n' + '"key: value": 4\n' + '"%H:%M:%S": 5\n' + '"%wheel ALL=(ALL) NOPASSWD: ALL": 6\n' + '\'"quoted"\': 7\n' + '"\'foo\' == \'bar\'": 8\n' + '"\'Mac\' in ansible_facts.product_name": 9\n' + '\'foo # bar\': 10\n', + conf) + self.check('---\n' + '"": 2\n' + '"- item": 3\n' + '"key: value": 4\n' + '"%H:%M:%S": 5\n' + '"%wheel ALL=(ALL) NOPASSWD: ALL": 6\n' + '\'"quoted"\': 7\n' + '"\'foo\' == \'bar\'": 8\n' + '"\'Mac\' in ansible_facts.product_name": 9\n', + conf) + + self.check('---\n' + '---: 2\n' + '"----": 3\n' # fails + '---------: 4\n' + '"----------": 5\n' # fails + ':wq: 6\n' + '":cw": 7\n', # fails + conf, problem1=(3, 1), problem2=(5, 1), problem3=(7, 1)) + + def test_only_when_needed_extras(self): + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' required: true\n' + ' extra-allowed: [^http://]\n') + self.assertRaises(config.YamlLintConfigError, self.check, '', conf) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' required: true\n' + ' extra-required: [^http://]\n') + self.assertRaises(config.YamlLintConfigError, self.check, '', conf) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' required: false\n' + ' extra-allowed: [^http://]\n') + self.assertRaises(config.YamlLintConfigError, self.check, '', conf) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' required: true\n') + self.check('---\n' + '123: 2\n' + '"234": 3\n' + 'localhost: 4\n' # fails + '"host.local": 5\n' + 'http://localhost: 6\n' # fails + '"http://host.local": 7\n' + 'ftp://localhost: 8\n' # fails + '"ftp://host.local": 9\n', + conf, problem1=(4, 1), problem2=(6, 1), problem3=(8, 1)) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' required: only-when-needed\n' + ' extra-allowed: [^ftp://]\n' + ' extra-required: [^http://]\n') + self.check('---\n' + '123: 2\n' + '"234": 3\n' + 'localhost: 4\n' + '"host.local": 5\n' # fails + 'http://localhost: 6\n' # fails + '"http://host.local": 7\n' + 'ftp://localhost: 8\n' + '"ftp://host.local": 9\n', + conf, problem1=(5, 1), problem2=(6, 1)) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' required: false\n' + ' extra-required: [^http://, ^ftp://]\n') + self.check('---\n' + '123: 2\n' + '"234": 3\n' + 'localhost: 4\n' + '"host.local": 5\n' + 'http://localhost: 6\n' # fails + '"http://host.local": 7\n' + 'ftp://localhost: 8\n' # fails + '"ftp://host.local": 9\n', + conf, problem1=(6, 1), problem2=(8, 1)) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' required: only-when-needed\n' + ' extra-allowed: [^ftp://, ";$", " "]\n') + self.check('---\n' + 'localhost: 2\n' + '"host.local": 3\n' # fails + 'ftp://localhost: 4\n' + '"ftp://host.local": 5\n' + 'i=i+1: 6\n' + '"i=i+2": 7\n' # fails + 'i=i+3;: 8\n' + '"i=i+4;": 9\n' + 'foo1: 10\n' + '"foo2": 11\n' # fails + 'foo bar1: 12\n' + '"foo bar2": 13\n', + conf, problem1=(3, 1), problem2=(7, 1), problem3=(11, 1)) + + def test_octal_values(self): + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' required: true\n') + + self.check('---\n' + '100: 2\n' + '0100: 3\n' + '0o100: 4\n' + '777: 5\n' + '0777: 6\n' + '0o777: 7\n' + '800: 8\n' + '0800: 9\n' # fails + '0o800: 10\n' # fails + '"0900": 11\n' + '"0o900": 12\n', + conf, + problem1=(9, 1), problem2=(10, 1)) + + def test_allow_quoted_quotes(self): + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: single\n' + ' required: false\n' + ' allow-quoted-quotes: false\n') + self.check('---\n' + '"[barbaz]": 2\n' # fails + '"[bar\'baz]": 3\n', # fails + conf, problem1=(2, 1), problem2=(3, 1)) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: single\n' + ' required: false\n' + ' allow-quoted-quotes: true\n') + self.check('---\n' + '"[barbaz]": 2\n' # fails + '"[bar\'baz]": 3\n', + conf, problem1=(2, 1)) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: single\n' + ' required: true\n' + ' allow-quoted-quotes: false\n') + self.check('---\n' + '"[barbaz]": 2\n' # fails + '"[bar\'baz]": 3\n', # fails + conf, problem1=(2, 1), problem2=(3, 1)) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: single\n' + ' required: true\n' + ' allow-quoted-quotes: true\n') + self.check('---\n' + '"[barbaz]": 2\n' # fails + '"[bar\'baz]": 3\n', + conf, problem1=(2, 1)) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: single\n' + ' required: only-when-needed\n' + ' allow-quoted-quotes: false\n') + self.check('---\n' + '"[barbaz]": 2\n' # fails + '"[bar\'baz]": 3\n', # fails + conf, problem1=(2, 1), problem2=(3, 1)) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: single\n' + ' required: only-when-needed\n' + ' allow-quoted-quotes: true\n') + self.check('---\n' + '"[barbaz]": 2\n' # fails + '"[bar\'baz]": 3\n', + conf, problem1=(2, 1)) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: double\n' + ' required: false\n' + ' allow-quoted-quotes: false\n') + self.check("---\n" + "'[barbaz]': 2\n" # fails + "'[bar\"baz]': 3\n", # fails + conf, problem1=(2, 1), problem2=(3, 1)) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: double\n' + ' required: false\n' + ' allow-quoted-quotes: true\n') + self.check("---\n" + "'[barbaz]': 2\n" # fails + "'[bar\"baz]': 3\n", + conf, problem1=(2, 1)) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: double\n' + ' required: true\n' + ' allow-quoted-quotes: false\n') + self.check("---\n" + "'[barbaz]': 2\n" # fails + "'[bar\"baz]': 3\n", # fails + conf, problem1=(2, 1), problem2=(3, 1)) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: double\n' + ' required: true\n' + ' allow-quoted-quotes: true\n') + self.check("---\n" + "'[barbaz]': 2\n" # fails + "'[bar\"baz]': 3\n", + conf, problem1=(2, 1)) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: double\n' + ' required: only-when-needed\n' + ' allow-quoted-quotes: false\n') + self.check("---\n" + "'[barbaz]': 2\n" # fails + "'[bar\"baz]': 3\n", # fails + conf, problem1=(2, 1), problem2=(3, 1)) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: double\n' + ' required: only-when-needed\n' + ' allow-quoted-quotes: true\n') + self.check("---\n" + "'[barbaz]': 2\n" # fails + "'[bar\"baz]': 3\n", + conf, problem1=(2, 1)) + + conf = ('quoted-strings:\n' + ' check-keys: true\n' + ' quote-type: any\n') + self.check("---\n" + "'[barbaz]': 2\n" + "'[bar\"baz]': 3\n", + conf) diff --git a/yamllint/rules/quoted_strings.py b/yamllint/rules/quoted_strings.py index 86b825e..5bfbd7a 100644 --- a/yamllint/rules/quoted_strings.py +++ b/yamllint/rules/quoted_strings.py @@ -32,6 +32,9 @@ used. even if ``required: only-when-needed`` is set. * ``allow-quoted-quotes`` allows (``true``) using disallowed quotes for strings with allowed quotes inside. Default ``false``. +* ``check-keys`` defines whether to apply the rules to keys in mappings. By + default, ``quoted-strings`` rules apply only to values. Set this option to + ``true`` to apply the rules to keys as well. **Note**: Multi-line strings (with ``|`` or ``>``) will not be checked. @@ -46,6 +49,7 @@ used. extra-required: [] extra-allowed: [] allow-quoted-quotes: false + check-keys: false .. rubric:: Examples @@ -135,6 +139,18 @@ used. foo: 'bar"baz' +#. With ``quoted-strings: {required: only-when-needed, check-keys: true, + extra-required: ["[:]"]}`` + + the following code snippet would **FAIL**: + :: + + foo:bar: baz + + the following code snippet would **PASS**: + :: + + "foo:bar": baz """ import re @@ -149,12 +165,14 @@ CONF = {'quote-type': ('any', 'single', 'double'), 'required': (True, False, 'only-when-needed'), 'extra-required': [str], 'extra-allowed': [str], - 'allow-quoted-quotes': bool} + 'allow-quoted-quotes': bool, + 'check-keys': bool} DEFAULT = {'quote-type': 'any', 'required': True, 'extra-required': [], 'extra-allowed': [], - 'allow-quoted-quotes': False} + 'allow-quoted-quotes': False, + 'check-keys': False} def VALIDATE(conf): @@ -226,10 +244,14 @@ def check(conf, token, prev, next, nextnext, context): if not (isinstance(token, yaml.tokens.ScalarToken) and isinstance(prev, (yaml.BlockEntryToken, yaml.FlowEntryToken, yaml.FlowSequenceStartToken, yaml.TagToken, - yaml.ValueToken))): + yaml.ValueToken, yaml.KeyToken))): return + node = 'key' if isinstance(prev, yaml.KeyToken) else 'value' + if node == 'key' and not conf['check-keys']: + return + # Ignore explicit types, e.g. !!str testtest or !!int 42 if (prev and isinstance(prev, yaml.tokens.TagToken) and prev.value[0] == '!!'): @@ -254,7 +276,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 = f"string value is not quoted with {quote_type} quotes" + msg = f"string {node} is not quoted with {quote_type} quotes" elif conf['required'] is False: @@ -263,13 +285,13 @@ 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 = f"string value is not quoted with {quote_type} quotes" + msg = f"string {node} is not quoted with {quote_type} quotes" elif not token.style: is_extra_required = any(re.search(r, token.value) for r in conf['extra-required']) if is_extra_required: - msg = "string value is not quoted" + msg = f"string {node} is not quoted" elif conf['required'] == 'only-when-needed': @@ -282,20 +304,20 @@ 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 = f"string value is redundantly quoted with " \ + msg = f"string {node} 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 = f"string value is not quoted with {quote_type} quotes" + msg = f"string {node} is not quoted with {quote_type} quotes" elif not token.style: is_extra_required = len(conf['extra-required']) and any( re.search(r, token.value) for r in conf['extra-required']) if is_extra_required: - msg = "string value is not quoted" + msg = f"string {node} is not quoted" if msg is not None: yield LintProblem(