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
|
from yamllint import config
|
||||||
|
|
||||||
|
|
||||||
class QuotedTestCase(RuleTestCase):
|
class QuotedValuesTestCase(RuleTestCase):
|
||||||
rule_id = 'quoted-strings'
|
rule_id = 'quoted-strings'
|
||||||
|
|
||||||
def test_disabled(self):
|
def test_disabled(self):
|
||||||
@ -595,3 +595,722 @@ class QuotedTestCase(RuleTestCase):
|
|||||||
"foo1: '[barbaz]'\n"
|
"foo1: '[barbaz]'\n"
|
||||||
"foo2: '[bar\"baz]'\n",
|
"foo2: '[bar\"baz]'\n",
|
||||||
conf)
|
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.
|
even if ``required: only-when-needed`` is set.
|
||||||
* ``allow-quoted-quotes`` allows (``true``) using disallowed quotes for strings
|
* ``allow-quoted-quotes`` allows (``true``) using disallowed quotes for strings
|
||||||
with allowed quotes inside. Default ``false``.
|
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.
|
**Note**: Multi-line strings (with ``|`` or ``>``) will not be checked.
|
||||||
|
|
||||||
@ -46,6 +49,7 @@ used.
|
|||||||
extra-required: []
|
extra-required: []
|
||||||
extra-allowed: []
|
extra-allowed: []
|
||||||
allow-quoted-quotes: false
|
allow-quoted-quotes: false
|
||||||
|
check-keys: false
|
||||||
|
|
||||||
.. rubric:: Examples
|
.. rubric:: Examples
|
||||||
|
|
||||||
@ -135,6 +139,18 @@ used.
|
|||||||
|
|
||||||
foo: 'bar"baz'
|
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
|
import re
|
||||||
@ -149,12 +165,14 @@ CONF = {'quote-type': ('any', 'single', 'double'),
|
|||||||
'required': (True, False, 'only-when-needed'),
|
'required': (True, False, 'only-when-needed'),
|
||||||
'extra-required': [str],
|
'extra-required': [str],
|
||||||
'extra-allowed': [str],
|
'extra-allowed': [str],
|
||||||
'allow-quoted-quotes': bool}
|
'allow-quoted-quotes': bool,
|
||||||
|
'check-keys': bool}
|
||||||
DEFAULT = {'quote-type': 'any',
|
DEFAULT = {'quote-type': 'any',
|
||||||
'required': True,
|
'required': True,
|
||||||
'extra-required': [],
|
'extra-required': [],
|
||||||
'extra-allowed': [],
|
'extra-allowed': [],
|
||||||
'allow-quoted-quotes': False}
|
'allow-quoted-quotes': False,
|
||||||
|
'check-keys': False}
|
||||||
|
|
||||||
|
|
||||||
def VALIDATE(conf):
|
def VALIDATE(conf):
|
||||||
@ -226,10 +244,14 @@ def check(conf, token, prev, next, nextnext, context):
|
|||||||
if not (isinstance(token, yaml.tokens.ScalarToken) and
|
if not (isinstance(token, yaml.tokens.ScalarToken) and
|
||||||
isinstance(prev, (yaml.BlockEntryToken, yaml.FlowEntryToken,
|
isinstance(prev, (yaml.BlockEntryToken, yaml.FlowEntryToken,
|
||||||
yaml.FlowSequenceStartToken, yaml.TagToken,
|
yaml.FlowSequenceStartToken, yaml.TagToken,
|
||||||
yaml.ValueToken))):
|
yaml.ValueToken, yaml.KeyToken))):
|
||||||
|
|
||||||
return
|
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
|
# Ignore explicit types, e.g. !!str testtest or !!int 42
|
||||||
if (prev and isinstance(prev, yaml.tokens.TagToken) and
|
if (prev and isinstance(prev, yaml.tokens.TagToken) and
|
||||||
prev.value[0] == '!!'):
|
prev.value[0] == '!!'):
|
||||||
@ -254,7 +276,7 @@ def check(conf, token, prev, next, nextnext, context):
|
|||||||
if (token.style is None or
|
if (token.style is None or
|
||||||
not (_quote_match(quote_type, token.style) or
|
not (_quote_match(quote_type, token.style) or
|
||||||
(conf['allow-quoted-quotes'] and _has_quoted_quotes(token)))):
|
(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:
|
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 _quote_match(quote_type, token.style) and
|
||||||
not (conf['allow-quoted-quotes'] and
|
not (conf['allow-quoted-quotes'] and
|
||||||
_has_quoted_quotes(token))):
|
_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:
|
elif not token.style:
|
||||||
is_extra_required = any(re.search(r, token.value)
|
is_extra_required = any(re.search(r, token.value)
|
||||||
for r in conf['extra-required'])
|
for r in conf['extra-required'])
|
||||||
if is_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':
|
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)
|
is_extra_allowed = any(re.search(r, token.value)
|
||||||
for r in conf['extra-allowed'])
|
for r in conf['extra-allowed'])
|
||||||
if not (is_extra_required or is_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"
|
f"{quote_type} quotes"
|
||||||
|
|
||||||
# But when used need to match config
|
# But when used need to match config
|
||||||
elif (token.style and
|
elif (token.style and
|
||||||
not _quote_match(quote_type, token.style) and
|
not _quote_match(quote_type, token.style) and
|
||||||
not (conf['allow-quoted-quotes'] and _has_quoted_quotes(token))):
|
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:
|
elif not token.style:
|
||||||
is_extra_required = len(conf['extra-required']) and any(
|
is_extra_required = len(conf['extra-required']) and any(
|
||||||
re.search(r, token.value) for r in conf['extra-required'])
|
re.search(r, token.value) for r in conf['extra-required'])
|
||||||
if is_extra_required:
|
if is_extra_required:
|
||||||
msg = "string value is not quoted"
|
msg = f"string {node} is not quoted"
|
||||||
|
|
||||||
if msg is not None:
|
if msg is not None:
|
||||||
yield LintProblem(
|
yield LintProblem(
|
||||||
|
Loading…
Reference in New Issue
Block a user