mirror of
https://github.com/adrienverge/yamllint.git
synced 2025-02-25 18:55:20 -06:00
quoted-strings: Add check-keys option
This commit is contained in:
parent
e5fdfd2ae5
commit
3288d0596e
@ -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)
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user