quoted-strings: Fix broken rule

Original implementation was completely broken. Documentation and actual
behavior were different. Numbers and booleans were detected as wrong, as
well as explicit types.

Fixes #136 and #130.
pull/140/head
Adrien Vergé 6 years ago
parent 524d721f0d
commit 8354d50016

@ -34,19 +34,19 @@ class QuotedTestCase(RuleTestCase):
def test_quote_type_any(self): def test_quote_type_any(self):
conf = 'quoted-strings: {quote-type: any}\n' conf = 'quoted-strings: {quote-type: any}\n'
self.check('---\n' self.check('---\n'
'string1: "foo"\n' 'boolean1: true\n'
'number1: 123\n' # fails 'number1: 123\n'
'string2: foo\n' # fails 'string1: foo\n' # fails
'string2: "foo"\n'
'string3: \'bar\'\n' 'string3: \'bar\'\n'
'string4: !!str genericstring\n' # fails 'string4: !!str genericstring\n'
'string5: !!str 456\n' # fails 'string5: !!str 456\n'
'string6: !!str "quotedgenericstring"\n' 'string6: !!str "quotedgenericstring"\n'
'binary: !!binary binstring\n' 'binary: !!binary binstring\n'
'integer: !!int intstring\n' 'integer: !!int intstring\n'
'boolean1: !!bool boolstring\n' 'boolean2: !!bool boolstring\n'
'boolean2: !!bool "quotedboolstring"\n', 'boolean3: !!bool "quotedboolstring"\n',
conf, problem1=(3, 10), problem2=(4, 10), conf, problem=(4, 10))
problem3=(6, 16), problem4=(7, 16))
self.check('---\n' self.check('---\n'
'multiline string 1: |\n' 'multiline string 1: |\n'
' line 1\n' ' line 1\n'
@ -65,19 +65,19 @@ class QuotedTestCase(RuleTestCase):
def test_quote_type_single(self): def test_quote_type_single(self):
conf = 'quoted-strings: {quote-type: single}\n' conf = 'quoted-strings: {quote-type: single}\n'
self.check('---\n' self.check('---\n'
'string1: "foo"\n' # fails 'boolean1: true\n'
'number1: 123\n' # fails 'number1: 123\n'
'string2: foo\n' # fails 'string1: foo\n' # fails
'string2: "foo"\n' # fails
'string3: \'bar\'\n' 'string3: \'bar\'\n'
'string4: !!str genericstring\n' # fails 'string4: !!str genericstring\n'
'string5: !!str 456\n' # fails 'string5: !!str 456\n'
'string6: !!str "quotedgenericstring"\n' # fails 'string6: !!str "quotedgenericstring"\n'
'binary: !!binary binstring\n' 'binary: !!binary binstring\n'
'integer: !!int intstring\n' 'integer: !!int intstring\n'
'boolean1: !!bool boolstring\n' 'boolean2: !!bool boolstring\n'
'boolean2: !!bool "quotedboolstring"\n', 'boolean3: !!bool "quotedboolstring"\n',
conf, problem1=(2, 10), problem2=(3, 10), problem3=(4, 10), conf, problem1=(4, 10), problem2=(5, 10))
problem4=(6, 16), problem5=(7, 16), problem6=(8, 16))
self.check('---\n' self.check('---\n'
'multiline string 1: |\n' 'multiline string 1: |\n'
' line 1\n' ' line 1\n'
@ -96,19 +96,19 @@ class QuotedTestCase(RuleTestCase):
def test_quote_type_double(self): def test_quote_type_double(self):
conf = 'quoted-strings: {quote-type: double}\n' conf = 'quoted-strings: {quote-type: double}\n'
self.check('---\n' self.check('---\n'
'string1: "foo"\n' 'boolean1: true\n'
'number1: 123\n' # fails 'number1: 123\n'
'string2: foo\n' # fails 'string1: foo\n' # fails
'string2: "foo"\n'
'string3: \'bar\'\n' # fails 'string3: \'bar\'\n' # fails
'string4: !!str genericstring\n' # fails 'string4: !!str genericstring\n'
'string5: !!str 456\n' # fails 'string5: !!str 456\n'
'string6: !!str "quotedgenericstring"\n' 'string6: !!str "quotedgenericstring"\n'
'binary: !!binary binstring\n' 'binary: !!binary binstring\n'
'integer: !!int intstring\n' 'integer: !!int intstring\n'
'boolean1: !!bool boolstring\n' 'boolean2: !!bool boolstring\n'
'boolean2: !!bool "quotedboolstring"\n', 'boolean3: !!bool "quotedboolstring"\n',
conf, problem1=(3, 10), problem2=(4, 10), problem3=(5, 10), conf, problem1=(4, 10), problem2=(6, 10))
problem4=(6, 16), problem5=(7, 16))
self.check('---\n' self.check('---\n'
'multiline string 1: |\n' 'multiline string 1: |\n'
' line 1\n' ' line 1\n'

@ -16,8 +16,8 @@
""" """
Use this rule to forbid any string values that are not quoted. Use this rule to forbid any string values that are not quoted.
You can also enforce the type of the quote used - single or double - using the You can also enforce the type of the quote used using the ``quote-type`` option
``quote-type`` option. (``single``, ``double`` or ``any``).
**Note**: Multi-line strings (with ``|`` or ``>``) will not be checked. **Note**: Multi-line strings (with ``|`` or ``>``) will not be checked.
@ -51,24 +51,27 @@ CONF = {'quote-type': ('any', 'single', 'double')}
def check(conf, token, prev, next, nextnext, context): def check(conf, token, prev, next, nextnext, context):
quote_type = conf['quote-type'] quote_type = conf['quote-type']
if prev and isinstance(prev, yaml.tokens.TagToken): if (isinstance(token, yaml.tokens.ScalarToken) and
if prev.value[1] != "str": isinstance(prev, (yaml.ValueToken, yaml.TagToken))):
# we ignore generic strings, e.g. somestring: !!str testtest # Ignore explicit types, e.g. !!str testtest or !!int 42
if (prev and isinstance(prev, yaml.tokens.TagToken) and
prev.value[0] == '!!'):
return return
if isinstance(token, yaml.tokens.ScalarToken): # Ignore numbers, booleans, etc.
if isinstance(prev, yaml.tokens.ValueToken) or \ resolver = yaml.resolver.Resolver()
isinstance(prev, yaml.tokens.TagToken): if resolver.resolve(yaml.nodes.ScalarNode, token.value,
if ((not token.plain) and (True, False)) != 'tag:yaml.org,2002:str':
((token.style == "|") or (token.style == ">"))): return
# we ignore multi-line strings
return # Ignore multi-line strings
if (not token.plain) and (token.style == "|" or token.style == ">"):
if ((quote_type == 'single' and token.style != "'") or return
(quote_type == 'double' and token.style != '"') or
(quote_type == 'any' and token.style is None)): if ((quote_type == 'single' and token.style != "'") or
yield LintProblem( (quote_type == 'double' and token.style != '"') or
token.start_mark.line + 1, (quote_type == 'any' and token.style is None)):
token.start_mark.column + 1, yield LintProblem(
"string value is not quoted with %s quotes" % (quote_type) token.start_mark.line + 1,
) token.start_mark.column + 1,
"string value is not quoted with %s quotes" % (quote_type))

Loading…
Cancel
Save