From aaa8777f1d6ce6eb321c1cb17599293ca5361b59 Mon Sep 17 00:00:00 2001
From: "Guido Wischrop (mgm tp)" <43027257+mgmgwi@users.noreply.github.com>
Date: Thu, 4 Oct 2018 16:04:54 +0200
Subject: [PATCH] Add quoted-strings rule
* taken from https://github.com/adrienverge/yamllint/pull/110 (submitted by @jurajseffer)
* small fixes for generic and multi-line strings
* fixes for comments from @adrienverge
---
tests/rules/test_quoted_strings.py | 125 +++++++++++++++++++++++++++++
yamllint/conf/default.yaml | 1 +
yamllint/rules/__init__.py | 2 +
yamllint/rules/quoted_strings.py | 74 +++++++++++++++++
4 files changed, 202 insertions(+)
create mode 100644 tests/rules/test_quoted_strings.py
create mode 100644 yamllint/rules/quoted_strings.py
diff --git a/tests/rules/test_quoted_strings.py b/tests/rules/test_quoted_strings.py
new file mode 100644
index 0000000..d848639
--- /dev/null
+++ b/tests/rules/test_quoted_strings.py
@@ -0,0 +1,125 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2018 ClearScore
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+from tests.common import RuleTestCase
+
+
+class QuotedTestCase(RuleTestCase):
+ rule_id = 'quoted-strings'
+
+ def test_disabled(self):
+ conf = 'quoted-strings: disable'
+ self.check('---\n'
+ 'foo: bar\n', conf)
+ self.check('---\n'
+ 'foo: "bar"\n', conf)
+ self.check('---\n'
+ 'foo: \'bar\'\n', conf)
+ self.check('---\n'
+ 'bar: 123\n', conf)
+
+ def test_quote_type_any(self):
+ conf = 'quoted-strings: {quote-type: any}\n'
+ self.check('---\n'
+ 'string1: "foo"\n'
+ 'number1: 123\n' # fails
+ 'string2: foo\n' # fails
+ 'string3: \'bar\'\n'
+ 'string4: !!str genericstring\n' # fails
+ 'string5: !!str 456\n' # fails
+ 'string6: !!str "quotedgenericstring"\n'
+ 'binary: !!binary binstring\n'
+ 'integer: !!int intstring\n'
+ 'boolean1: !!bool boolstring\n'
+ 'boolean2: !!bool "quotedboolstring"\n',
+ conf, problem1=(3, 10), problem2=(4, 10),
+ problem3=(6, 16), problem4=(7, 16))
+ self.check('---\n'
+ 'multiline string 1: |\n'
+ ' line 1\n'
+ ' line 2\n'
+ 'multiline string 2: >\n'
+ ' word 1\n'
+ ' word 2\n'
+ 'multiline string 3:\n'
+ ' word 1\n'
+ ' word 2\n'
+ 'multiline string 4:\n'
+ ' "word 1\\\n'
+ ' word 2"\n',
+ conf, problem1=(9, 3))
+
+ def test_quote_type_single(self):
+ conf = 'quoted-strings: {quote-type: single}\n'
+ self.check('---\n'
+ 'string1: "foo"\n' # fails
+ 'number1: 123\n' # fails
+ 'string2: foo\n' # fails
+ 'string3: \'bar\'\n'
+ 'string4: !!str genericstring\n' # fails
+ 'string5: !!str 456\n' # fails
+ 'string6: !!str "quotedgenericstring"\n' # fails
+ 'binary: !!binary binstring\n'
+ 'integer: !!int intstring\n'
+ 'boolean1: !!bool boolstring\n'
+ 'boolean2: !!bool "quotedboolstring"\n',
+ conf, problem1=(2, 10), problem2=(3, 10), problem3=(4, 10),
+ problem4=(6, 16), problem5=(7, 16), problem6=(8, 16))
+ self.check('---\n'
+ 'multiline string 1: |\n'
+ ' line 1\n'
+ ' line 2\n'
+ 'multiline string 2: >\n'
+ ' word 1\n'
+ ' word 2\n'
+ 'multiline string 3:\n'
+ ' word 1\n'
+ ' word 2\n'
+ 'multiline string 4:\n'
+ ' "word 1\\\n'
+ ' word 2"\n',
+ conf, problem1=(9, 3), problem2=(12, 3))
+
+ def test_quote_type_double(self):
+ conf = 'quoted-strings: {quote-type: double}\n'
+ self.check('---\n'
+ 'string1: "foo"\n'
+ 'number1: 123\n' # fails
+ 'string2: foo\n' # fails
+ 'string3: \'bar\'\n' # fails
+ 'string4: !!str genericstring\n' # fails
+ 'string5: !!str 456\n' # fails
+ 'string6: !!str "quotedgenericstring"\n'
+ 'binary: !!binary binstring\n'
+ 'integer: !!int intstring\n'
+ 'boolean1: !!bool boolstring\n'
+ 'boolean2: !!bool "quotedboolstring"\n',
+ conf, problem1=(3, 10), problem2=(4, 10), problem3=(5, 10),
+ problem4=(6, 16), problem5=(7, 16))
+ self.check('---\n'
+ 'multiline string 1: |\n'
+ ' line 1\n'
+ ' line 2\n'
+ 'multiline string 2: >\n'
+ ' word 1\n'
+ ' word 2\n'
+ 'multiline string 3:\n'
+ ' word 1\n'
+ ' word 2\n'
+ 'multiline string 4:\n'
+ ' "word 1\\\n'
+ ' word 2"\n',
+ conf, problem1=(9, 3))
diff --git a/yamllint/conf/default.yaml b/yamllint/conf/default.yaml
index 8432c9a..fcece4d 100644
--- a/yamllint/conf/default.yaml
+++ b/yamllint/conf/default.yaml
@@ -32,6 +32,7 @@ rules:
max: 2
max-start: 0
max-end: 0
+ quoted-strings: disable
empty-values:
forbid-in-block-mappings: false
forbid-in-flow-mappings: false
diff --git a/yamllint/rules/__init__.py b/yamllint/rules/__init__.py
index d08a326..a084d6e 100644
--- a/yamllint/rules/__init__.py
+++ b/yamllint/rules/__init__.py
@@ -33,6 +33,7 @@ from yamllint.rules import (
new_line_at_end_of_file,
new_lines,
octal_values,
+ quoted_strings,
trailing_spaces,
truthy,
)
@@ -56,6 +57,7 @@ _RULES = {
new_line_at_end_of_file.ID: new_line_at_end_of_file,
new_lines.ID: new_lines,
octal_values.ID: octal_values,
+ quoted_strings.ID: quoted_strings,
trailing_spaces.ID: trailing_spaces,
truthy.ID: truthy,
}
diff --git a/yamllint/rules/quoted_strings.py b/yamllint/rules/quoted_strings.py
new file mode 100644
index 0000000..2380898
--- /dev/null
+++ b/yamllint/rules/quoted_strings.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2018 ClearScore
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""
+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
+``quote-type`` option.
+
+**Note**: Multi-line strings (with ``|`` or ``>``) will not be checked.
+
+.. rubric:: Examples
+
+#. With ``quoted-strings: {quote-type: any}``
+
+ the following code snippet would **PASS**:
+ ::
+
+ foo: "bar"
+ bar: 'foo'
+ number: 123
+ boolean: true
+
+ the following code snippet would **FAIL**:
+ ::
+
+ foo: bar
+"""
+
+import yaml
+
+from yamllint.linter import LintProblem
+
+ID = 'quoted-strings'
+TYPE = 'token'
+CONF = {'quote-type': ('any', 'single', 'double')}
+
+
+def check(conf, token, prev, next, nextnext, context):
+ quote_type = conf['quote-type']
+
+ if prev and isinstance(prev, yaml.tokens.TagToken):
+ if prev.value[1] != "str":
+ # we ignore generic strings, e.g. somestring: !!str testtest
+ return
+
+ if isinstance(token, yaml.tokens.ScalarToken):
+ if isinstance(prev, yaml.tokens.ValueToken) or \
+ isinstance(prev, yaml.tokens.TagToken):
+ if ((not token.plain) and
+ ((token.style == "|") or (token.style == ">"))):
+ # we ignore multi-line strings
+ return
+
+ if ((quote_type == 'single' and token.style != "'") or
+ (quote_type == 'double' and token.style != '"') or
+ (quote_type == 'any' and token.style is None)):
+ yield LintProblem(
+ token.start_mark.line + 1,
+ token.start_mark.column + 1,
+ "string value is not quoted with %s quotes" % (quote_type)
+ )