Compare commits

...

15 Commits

Author SHA1 Message Date
Adrien Vergé
318a12bbe6 yamllint version 1.13.0 2018-11-14 19:04:58 +01:00
Adrien Vergé
66adaee66c docs: Add documentation on the new -f colored option 2018-11-14 19:02:52 +01:00
sedrubal
5062b91cac cli: Add -f colored to force colors
`-f standard` shows non-colored output,
`-f colored` shows colored output,
`-f auto` is the new default, it chooses `standard` or `colored`
depending on terminal capabilities.
2018-10-22 10:35:35 +02:00
sedrubal
3ef85739e3 Use isinstance(x, y) instead of type(x) == y
Fixes pylint C0123.
2018-10-20 10:02:16 +02:00
Adrien Vergé
dc4a9f4fff yamllint version 1.12.1 2018-10-17 10:22:32 +02:00
Adrien Vergé
8354d50016 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.
2018-10-17 10:18:25 +02:00
Adrien Vergé
524d721f0d Update .gitignore to exclude build/ 2018-10-11 15:35:26 +02:00
Adrien Vergé
e864f57d37 docs: Fix missing quoted-strings module in documentation 2018-10-11 15:27:58 +02:00
Adrien Vergé
d41b64aa97 yamllint version 1.12.0 2018-10-04 16:10:56 +02:00
Guido Wischrop (mgm tp)
aaa8777f1d 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
2018-10-04 16:09:56 +02:00
Adrien Vergé
479f580202 CI: Fix tests failing on Travis for Python 2.6
Because installing dependencies for `coveralls` now fails with:

    Collecting pycparser (from cffi>=1.7->cryptography>=1.3.4; python_version <= "2.7" and extra == "secure"->urllib3[secure]; python_version < "3"->coveralls)
    [...]
    pycparser requires Python '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*' but the running Python is 2.6.9
2018-10-02 19:27:54 +02:00
Justin Foreman
e4e99f0aba docs: Update README for CentOS dependency 2018-05-31 11:06:22 +02:00
Adrien Vergé
203cfc20f0 docs: Remove sudo from pip installation instructions 2018-05-09 20:20:18 +02:00
Adrien Vergé
51c30505b5 docs: Add Mac OS installation instructions
See https://github.com/adrienverge/yamllint/issues/91 and
https://github.com/Homebrew/homebrew-core/blob/af2bbe9/Formula/yamllint.rb
2018-05-09 20:19:03 +02:00
Adrien Vergé
ff9ebde608 docs: Remove old Debian / Ubuntu installation instructions 2018-05-09 20:19:03 +02:00
18 changed files with 337 additions and 33 deletions

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@ __pycache__
/docs/_build /docs/_build
/dist /dist
/yamllint.egg-info /yamllint.egg-info
/build

View File

@@ -9,14 +9,19 @@ python:
- 3.6 - 3.6
- nightly - nightly
install: install:
- pip install pyyaml flake8 flake8-import-order coveralls - pip install pyyaml flake8 flake8-import-order
- if [[ $TRAVIS_PYTHON_VERSION == 2.6 ]]; then pip install unittest2; fi - if [[ $TRAVIS_PYTHON_VERSION == 2.6 ]]; then pip install unittest2; fi
- if [[ $TRAVIS_PYTHON_VERSION != 2.6 ]]; then pip install coveralls; fi
- if [[ $TRAVIS_PYTHON_VERSION != 2* ]]; then pip install sphinx; fi - if [[ $TRAVIS_PYTHON_VERSION != 2* ]]; then pip install sphinx; fi
- pip install . - pip install .
script: script:
- if [[ $TRAVIS_PYTHON_VERSION != 2.6 ]]; then flake8 .; fi - if [[ $TRAVIS_PYTHON_VERSION != 2.6 ]]; then flake8 .; fi
- yamllint --strict $(git ls-files '*.yaml' '*.yml') - yamllint --strict $(git ls-files '*.yaml' '*.yml')
- coverage run --source=yamllint setup.py test - if [[ $TRAVIS_PYTHON_VERSION != 2.6 ]]; then
coverage run --source=yamllint setup.py test;
else
python setup.py test;
fi
- if [[ $TRAVIS_PYTHON_VERSION != 2* ]]; then - if [[ $TRAVIS_PYTHON_VERSION != 2* ]]; then
python setup.py build_sphinx; python setup.py build_sphinx;
fi fi

View File

@@ -1,6 +1,25 @@
Changelog Changelog
========= =========
1.13.0 (2018-11-14)
-------------------
- Use `isinstance(x, y)` instead of `type(x) == y`
- Add a new `-f colored` option
- Update documentation about colored output when run from CLI
1.12.1 (2018-10-17)
-------------------
- Fix the `quoted-strings` rule, broken implementation
- Fix missing documentation for the `quoted-strings` rule
1.12.0 (2018-10-04)
-------------------
- Add a new `quoted-strings` rule
- Update installation documentation for pip, CentOS, Debian, Ubuntu, Mac OS
1.11.1 (2018-04-06) 1.11.1 (2018-04-06)
------------------- -------------------

View File

@@ -38,7 +38,8 @@ Screenshot
Installation Installation
^^^^^^^^^^^^ ^^^^^^^^^^^^
On Fedora / CentOS: On Fedora / CentOS (note: `EPEL <https://fedoraproject.org/wiki/EPEL>`_ is
required on CentOS):
.. code:: bash .. code:: bash
@@ -50,11 +51,17 @@ On Debian 8+ / Ubuntu 16.04+:
sudo apt-get install yamllint sudo apt-get install yamllint
On Mac OS 10.11+:
.. code:: bash
brew install yamllint
Alternatively using pip, the Python package manager: Alternatively using pip, the Python package manager:
.. code:: bash .. code:: bash
sudo pip install yamllint pip install --user yamllint
Usage Usage
^^^^^ ^^^^^

View File

@@ -102,8 +102,8 @@ Errors and warnings
------------------- -------------------
Problems detected by yamllint can be raised either as errors or as warnings. Problems detected by yamllint can be raised either as errors or as warnings.
The CLI will output them (with different colors when using the ``standard`` The CLI will output them (with different colors when using the ``colored``
output format). output format, or ``auto`` when run from a terminal).
By default the script will exit with a return code ``1`` *only when* there is one or By default the script will exit with a return code ``1`` *only when* there is one or
more error(s). more error(s).

View File

@@ -16,25 +16,24 @@ On Debian 8+ / Ubuntu 16.04+:
sudo apt-get install yamllint sudo apt-get install yamllint
On older Debian / Ubuntu versions: On Mac OS 10.11+:
.. code:: bash .. code:: bash
sudo add-apt-repository -y ppa:adrienverge/ppa && sudo apt-get update brew install yamllint
sudo apt-get install yamllint
Alternatively using pip, the Python package manager: Alternatively using pip, the Python package manager:
.. code:: bash .. code:: bash
sudo pip install yamllint pip install --user yamllint
If you prefer installing from source, you can run, from the source directory: If you prefer installing from source, you can run, from the source directory:
.. code:: bash .. code:: bash
python setup.py sdist python setup.py sdist
sudo pip install dist/yamllint-*.tar.gz pip install --user dist/yamllint-*.tar.gz
Running yamllint Running yamllint
---------------- ----------------
@@ -69,6 +68,10 @@ The output will look like (colors are not displayed here):
10:1 error too many blank lines (4 > 2) (empty-lines) 10:1 error too many blank lines (4 > 2) (empty-lines)
11:4 error too many spaces inside braces (braces) 11:4 error too many spaces inside braces (braces)
By default, the output of yamllint is colored when run from a terminal, and pure
text in other cases. Add the ``-f standard`` arguments to force non-colored output.
Use the ``-f colored`` arguments to force colored output.
Add the ``-f parsable`` arguments if you need an output format parsable by a Add the ``-f parsable`` arguments if you need an output format parsable by a
machine (for instance for :doc:`syntax highlighting in text editors machine (for instance for :doc:`syntax highlighting in text editors
<text_editors>`). The output will then look like: <text_editors>`). The output will then look like:

View File

@@ -104,6 +104,11 @@ octal-values
.. automodule:: yamllint.rules.octal_values .. automodule:: yamllint.rules.octal_values
quoted-strings
--------------
.. automodule:: yamllint.rules.quoted_strings
trailing-spaces trailing-spaces
--------------- ---------------

View File

@@ -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 <http://www.gnu.org/licenses/>.
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'
'boolean1: true\n'
'number1: 123\n'
'string1: foo\n' # fails
'string2: "foo"\n'
'string3: \'bar\'\n'
'string4: !!str genericstring\n'
'string5: !!str 456\n'
'string6: !!str "quotedgenericstring"\n'
'binary: !!binary binstring\n'
'integer: !!int intstring\n'
'boolean2: !!bool boolstring\n'
'boolean3: !!bool "quotedboolstring"\n',
conf, problem=(4, 10))
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'
'boolean1: true\n'
'number1: 123\n'
'string1: foo\n' # fails
'string2: "foo"\n' # fails
'string3: \'bar\'\n'
'string4: !!str genericstring\n'
'string5: !!str 456\n'
'string6: !!str "quotedgenericstring"\n'
'binary: !!binary binstring\n'
'integer: !!int intstring\n'
'boolean2: !!bool boolstring\n'
'boolean3: !!bool "quotedboolstring"\n',
conf, problem1=(4, 10), problem2=(5, 10))
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'
'boolean1: true\n'
'number1: 123\n'
'string1: foo\n' # fails
'string2: "foo"\n'
'string3: \'bar\'\n' # fails
'string4: !!str genericstring\n'
'string5: !!str 456\n'
'string6: !!str "quotedgenericstring"\n'
'binary: !!binary binstring\n'
'integer: !!int intstring\n'
'boolean2: !!bool boolstring\n'
'boolean3: !!bool "quotedboolstring"\n',
conf, problem1=(4, 10), problem2=(6, 10))
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))

View File

@@ -351,7 +351,7 @@ class CommandLineTestCase(unittest.TestCase):
'\n' % file)) '\n' % file))
self.assertEqual(err, '') self.assertEqual(err, '')
def test_run_colored_output(self): def test_run_default_format_output_in_tty(self):
file = os.path.join(self.wd, 'a.yaml') file = os.path.join(self.wd, 'a.yaml')
# Create a pseudo-TTY and redirect stdout to it # Create a pseudo-TTY and redirect stdout to it
@@ -383,3 +383,59 @@ class CommandLineTestCase(unittest.TestCase):
'no new line character at the end of file ' 'no new line character at the end of file '
'\033[2m(new-line-at-end-of-file)\033[0m\n' '\033[2m(new-line-at-end-of-file)\033[0m\n'
'\n' % file)) '\n' % file))
def test_run_default_format_output_without_tty(self):
file = os.path.join(self.wd, 'a.yaml')
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run((file, ))
self.assertEqual(ctx.exception.code, 1)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(out, (
'%s\n'
' 2:4 error trailing spaces (trailing-spaces)\n'
' 3:4 error no new line character at the end of file '
'(new-line-at-end-of-file)\n'
'\n' % file))
self.assertEqual(err, '')
def test_run_auto_output_without_tty_output(self):
file = os.path.join(self.wd, 'a.yaml')
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run((file, '--format', 'auto'))
self.assertEqual(ctx.exception.code, 1)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(out, (
'%s\n'
' 2:4 error trailing spaces (trailing-spaces)\n'
' 3:4 error no new line character at the end of file '
'(new-line-at-end-of-file)\n'
'\n' % file))
self.assertEqual(err, '')
def test_run_format_colored(self):
file = os.path.join(self.wd, 'a.yaml')
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run((file, '--format', 'colored'))
self.assertEqual(ctx.exception.code, 1)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(out, (
'\033[4m%s\033[0m\n'
' \033[2m2:4\033[0m \033[31merror\033[0m '
'trailing spaces \033[2m(trailing-spaces)\033[0m\n'
' \033[2m3:4\033[0m \033[31merror\033[0m '
'no new line character at the end of file '
'\033[2m(new-line-at-end-of-file)\033[0m\n'
'\n' % file))
self.assertEqual(err, '')

View File

@@ -22,7 +22,7 @@ indentation, etc."""
APP_NAME = 'yamllint' APP_NAME = 'yamllint'
APP_VERSION = '1.11.1' APP_VERSION = '1.13.0'
APP_DESCRIPTION = __doc__ APP_DESCRIPTION = __doc__
__author__ = u'Adrien Vergé' __author__ = u'Adrien Vergé'

View File

@@ -96,8 +96,8 @@ def run(argv=None):
action='store', action='store',
help='custom configuration (as YAML source)') help='custom configuration (as YAML source)')
parser.add_argument('-f', '--format', parser.add_argument('-f', '--format',
choices=('parsable', 'standard'), default='standard', choices=('parsable', 'standard', 'colored', 'auto'),
help='format for parsing output') default='auto', help='format for parsing output')
parser.add_argument('-s', '--strict', parser.add_argument('-s', '--strict',
action='store_true', action='store_true',
help='return non-zero exit code on warnings ' help='return non-zero exit code on warnings '
@@ -143,7 +143,8 @@ def run(argv=None):
for problem in linter.run(f, conf, filepath): for problem in linter.run(f, conf, filepath):
if args.format == 'parsable': if args.format == 'parsable':
print(Format.parsable(problem, file)) print(Format.parsable(problem, file))
elif supports_color(): elif args.format == 'colored' or \
(args.format == 'auto' and supports_color()):
if first: if first:
print('\033[4m%s\033[0m' % file) print('\033[4m%s\033[0m' % file)
first = False first = False

View File

@@ -32,6 +32,7 @@ rules:
max: 2 max: 2
max-start: 0 max-start: 0
max-end: 0 max-end: 0
quoted-strings: disable
empty-values: empty-values:
forbid-in-block-mappings: false forbid-in-block-mappings: false
forbid-in-flow-mappings: false forbid-in-flow-mappings: false

View File

@@ -52,7 +52,7 @@ class YamlLintConfig(object):
assert isinstance(base_config, YamlLintConfig) assert isinstance(base_config, YamlLintConfig)
for rule in self.rules: for rule in self.rules:
if (type(self.rules[rule]) == dict and if (isinstance(self.rules[rule], dict) and
rule in base_config.rules and rule in base_config.rules and
base_config.rules[rule] is not False): base_config.rules[rule] is not False):
base_config.rules[rule].update(self.rules[rule]) base_config.rules[rule].update(self.rules[rule])
@@ -70,7 +70,7 @@ class YamlLintConfig(object):
except Exception as e: except Exception as e:
raise YamlLintConfigError('invalid config: %s' % e) raise YamlLintConfigError('invalid config: %s' % e)
if type(conf) != dict: if not isinstance(conf, dict):
raise YamlLintConfigError('invalid config: not a dict') raise YamlLintConfigError('invalid config: not a dict')
self.rules = conf.get('rules', {}) self.rules = conf.get('rules', {})
@@ -85,7 +85,7 @@ class YamlLintConfig(object):
raise YamlLintConfigError('invalid config: %s' % e) raise YamlLintConfigError('invalid config: %s' % e)
if 'ignore' in conf: if 'ignore' in conf:
if type(conf['ignore']) != str: if not isinstance(conf['ignore'], str):
raise YamlLintConfigError( raise YamlLintConfigError(
'invalid config: ignore should contain file patterns') 'invalid config: ignore should contain file patterns')
self.ignore = pathspec.PathSpec.from_lines( self.ignore = pathspec.PathSpec.from_lines(
@@ -107,10 +107,10 @@ def validate_rule_conf(rule, conf):
elif conf == 'enable': elif conf == 'enable':
conf = {} conf = {}
if type(conf) == dict: if isinstance(conf, dict):
if ('ignore' in conf and if ('ignore' in conf and
type(conf['ignore']) != pathspec.pathspec.PathSpec): not isinstance(conf['ignore'], pathspec.pathspec.PathSpec)):
if type(conf['ignore']) != str: if not isinstance(conf['ignore'], str):
raise YamlLintConfigError( raise YamlLintConfigError(
'invalid config: ignore should contain file patterns') 'invalid config: ignore should contain file patterns')
conf['ignore'] = pathspec.PathSpec.from_lines( conf['ignore'] = pathspec.PathSpec.from_lines(
@@ -130,14 +130,14 @@ def validate_rule_conf(rule, conf):
raise YamlLintConfigError( raise YamlLintConfigError(
'invalid config: unknown option "%s" for rule "%s"' % 'invalid config: unknown option "%s" for rule "%s"' %
(optkey, rule.ID)) (optkey, rule.ID))
if type(options[optkey]) == tuple: if isinstance(options[optkey], tuple):
if (conf[optkey] not in options[optkey] and if (conf[optkey] not in options[optkey] and
type(conf[optkey]) not in options[optkey]): type(conf[optkey]) not in options[optkey]):
raise YamlLintConfigError( raise YamlLintConfigError(
'invalid config: option "%s" of "%s" should be in %s' 'invalid config: option "%s" of "%s" should be in %s'
% (optkey, rule.ID, options[optkey])) % (optkey, rule.ID, options[optkey]))
else: else:
if type(conf[optkey]) != options[optkey]: if not isinstance(conf[optkey], options[optkey]):
raise YamlLintConfigError( raise YamlLintConfigError(
'invalid config: option "%s" of "%s" should be %s' 'invalid config: option "%s" of "%s" should be %s'
% (optkey, rule.ID, options[optkey].__name__)) % (optkey, rule.ID, options[optkey].__name__))

View File

@@ -226,7 +226,7 @@ def run(input, conf, filepath=None):
if conf.is_file_ignored(filepath): if conf.is_file_ignored(filepath):
return () return ()
if type(input) in (type(b''), type(u'')): # compat with Python 2 & 3 if isinstance(input, (type(b''), type(u''))): # compat with Python 2 & 3
return _run(input, conf, filepath) return _run(input, conf, filepath)
elif hasattr(input, 'read'): # Python 2's file or Python 3's io.IOBase elif hasattr(input, 'read'): # Python 2's file or Python 3's io.IOBase
# We need to have everything in memory to parse correctly # We need to have everything in memory to parse correctly

View File

@@ -33,6 +33,7 @@ from yamllint.rules import (
new_line_at_end_of_file, new_line_at_end_of_file,
new_lines, new_lines,
octal_values, octal_values,
quoted_strings,
trailing_spaces, trailing_spaces,
truthy, truthy,
) )
@@ -56,6 +57,7 @@ _RULES = {
new_line_at_end_of_file.ID: new_line_at_end_of_file, new_line_at_end_of_file.ID: new_line_at_end_of_file,
new_lines.ID: new_lines, new_lines.ID: new_lines,
octal_values.ID: octal_values, octal_values.ID: octal_values,
quoted_strings.ID: quoted_strings,
trailing_spaces.ID: trailing_spaces, trailing_spaces.ID: trailing_spaces,
truthy.ID: truthy, truthy.ID: truthy,
} }

View File

@@ -86,14 +86,16 @@ CONF = {'present': bool}
def check(conf, token, prev, next, nextnext, context): def check(conf, token, prev, next, nextnext, context):
if conf['present']: if conf['present']:
if (isinstance(token, yaml.StreamEndToken) and is_stream_end = isinstance(token, yaml.StreamEndToken)
not (isinstance(prev, yaml.DocumentEndToken) or is_start = isinstance(token, yaml.DocumentStartToken)
isinstance(prev, yaml.StreamStartToken))): prev_is_end_or_stream_start = isinstance(
prev, (yaml.DocumentEndToken, yaml.StreamStartToken)
)
if is_stream_end and not prev_is_end_or_stream_start:
yield LintProblem(token.start_mark.line, 1, yield LintProblem(token.start_mark.line, 1,
'missing document end "..."') 'missing document end "..."')
elif (isinstance(token, yaml.DocumentStartToken) and elif is_start and not prev_is_end_or_stream_start:
not (isinstance(prev, yaml.DocumentEndToken) or
isinstance(prev, yaml.StreamStartToken))):
yield LintProblem(token.start_mark.line + 1, 1, yield LintProblem(token.start_mark.line + 1, 1,
'missing document end "..."') 'missing document end "..."')

View File

@@ -224,7 +224,7 @@ def check_scalar_indentation(conf, token, context):
def compute_expected_indent(found_indent): def compute_expected_indent(found_indent):
def detect_indent(base_indent): def detect_indent(base_indent):
if type(context['spaces']) is not int: if not isinstance(context['spaces'], int):
context['spaces'] = found_indent - base_indent context['spaces'] = found_indent - base_indent
return base_indent + context['spaces'] return base_indent + context['spaces']
@@ -312,7 +312,7 @@ def _check(conf, token, prev, next, nextnext, context):
token.start_mark.line + 1 > context['cur_line']) token.start_mark.line + 1 > context['cur_line'])
def detect_indent(base_indent, next): def detect_indent(base_indent, next):
if type(context['spaces']) is not int: if not isinstance(context['spaces'], int):
context['spaces'] = next.start_mark.column - base_indent context['spaces'] = next.start_mark.column - base_indent
return base_indent + context['spaces'] return base_indent + context['spaces']

View File

@@ -0,0 +1,77 @@
# -*- 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 <http://www.gnu.org/licenses/>.
"""
Use this rule to forbid any string values that are not quoted.
You can also enforce the type of the quote used using the ``quote-type`` option
(``single``, ``double`` or ``any``).
**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 (isinstance(token, yaml.tokens.ScalarToken) and
isinstance(prev, (yaml.ValueToken, yaml.TagToken))):
# Ignore explicit types, e.g. !!str testtest or !!int 42
if (prev and isinstance(prev, yaml.tokens.TagToken) and
prev.value[0] == '!!'):
return
# Ignore numbers, booleans, etc.
resolver = yaml.resolver.Resolver()
if resolver.resolve(yaml.nodes.ScalarNode, token.value,
(True, False)) != 'tag:yaml.org,2002:str':
return
# Ignore multi-line strings
if (not token.plain) and (token.style == "|" or token.style == ">"):
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))