Compare commits

...

4 Commits

Author SHA1 Message Date
Adrien Vergé
a7d39b5492 yamllint version 0.6.0 2016-01-25 11:03:00 +01:00
Adrien Vergé
4410bc3e23 Rules: indentation: Fix check-multi-line-strings
For strings that continue on next line at a lower indentation level:

    Blaise Pascal: Je vous écris une longue lettre parce que
      je n'ai pas le temps d'en écrire une courte.
2016-01-25 11:01:42 +01:00
Adrien Vergé
97c446907c Rules: line-length: Add option allow-non-breakable-words 2016-01-24 22:46:10 +01:00
Adrien Vergé
376a6ed484 Doc: Enhance short description 2016-01-24 18:40:48 +01:00
9 changed files with 129 additions and 29 deletions

View File

@@ -3,6 +3,9 @@ yamllint
A linter for YAML files. A linter for YAML files.
yamllint does not only check for syntax validity, but for common cosmetic
conventions such as lines length, trailing spaces, indentation, etc.
.. image:: .. image::
https://travis-ci.org/adrienverge/yamllint.svg?branch=master https://travis-ci.org/adrienverge/yamllint.svg?branch=master
:target: https://travis-ci.org/adrienverge/yamllint :target: https://travis-ci.org/adrienverge/yamllint

View File

@@ -3,6 +3,9 @@ yamllint documentation
A linter for YAML files. A linter for YAML files.
yamllint does not only check for syntax validity, but for common cosmetic
conventions such as lines length, trailing spaces, indentation, etc.
Screenshot Screenshot
---------- ----------

View File

@@ -24,7 +24,8 @@ setup(
name=APP_NAME, name=APP_NAME,
version=APP_VERSION, version=APP_VERSION,
author=__author__, author=__author__,
description=APP_DESCRIPTION, description=APP_DESCRIPTION.split('\n')[0],
long_description=APP_DESCRIPTION,
license=__license__, license=__license__,
keywords=['yaml', 'lint', 'linter', 'syntax', 'checker'], keywords=['yaml', 'lint', 'linter', 'syntax', 'checker'],
url='https://github.com/adrienverge/yamllint', url='https://github.com/adrienverge/yamllint',

View File

@@ -507,7 +507,7 @@ class ScalarIndentationTestCase(RuleTestCase):
self.check('a key: multi\n' self.check('a key: multi\n'
' line\n', conf) ' line\n', conf)
self.check('a key: multi\n' self.check('a key: multi\n'
' line\n', conf, problem=(2, 3)) ' line\n', conf)
self.check('a key: multi\n' self.check('a key: multi\n'
' line\n', conf) ' line\n', conf)
self.check('a key:\n' self.check('a key:\n'
@@ -528,6 +528,8 @@ class ScalarIndentationTestCase(RuleTestCase):
' line\n', conf, problem=(2, 2)) ' line\n', conf, problem=(2, 2))
self.check('- multi\n' self.check('- multi\n'
' line\n', conf, problem=(2, 4)) ' line\n', conf, problem=(2, 4))
self.check('a key: multi\n'
' line\n', conf, problem=(2, 3))
self.check('a key: multi\n' self.check('a key: multi\n'
' line\n', conf, problem=(2, 9)) ' line\n', conf, problem=(2, 9))
self.check('a key:\n' self.check('a key:\n'
@@ -546,24 +548,13 @@ class ScalarIndentationTestCase(RuleTestCase):
'document-start: disable\n') 'document-start: disable\n')
self.check('"multi\n' self.check('"multi\n'
' line"\n', conf) ' line"\n', conf)
self.check('"multi\n'
'line"\n', conf, problem=(2, 1))
self.check('- "multi\n' self.check('- "multi\n'
' line"\n', conf) ' line"\n', conf)
self.check('- "multi\n'
' line"\n', conf, problem=(2, 3))
self.check('a key: "multi\n' self.check('a key: "multi\n'
' line"\n', conf) ' line"\n', conf)
self.check('a key: "multi\n'
' line"\n', conf, problem=(2, 3))
self.check('a key: "multi\n'
' line"\n', conf, problem=(2, 8))
self.check('a key:\n' self.check('a key:\n'
' "multi\n' ' "multi\n'
' line"\n', conf) ' line"\n', conf)
self.check('a key:\n'
' "multi\n'
' line"\n', conf, problem=(3, 3))
self.check('- jinja2: "{% if ansible is defined %}\n' self.check('- jinja2: "{% if ansible is defined %}\n'
' {{ ansible }}\n' ' {{ ansible }}\n'
' {% else %}\n' ' {% else %}\n'
@@ -580,11 +571,22 @@ class ScalarIndentationTestCase(RuleTestCase):
conf = ('indentation: {spaces: 2, check-multi-line-strings: yes}\n' conf = ('indentation: {spaces: 2, check-multi-line-strings: yes}\n'
'document-start: disable\n') 'document-start: disable\n')
self.check('"multi\n' self.check('"multi\n'
'line"\n', conf, problem=(2, 1))
self.check('"multi\n'
' line"\n', conf, problem=(2, 3))
self.check('- "multi\n'
' line"\n', conf, problem=(2, 3)) ' line"\n', conf, problem=(2, 3))
self.check('- "multi\n' self.check('- "multi\n'
' line"\n', conf, problem=(2, 5)) ' line"\n', conf, problem=(2, 5))
self.check('a key: "multi\n'
' line"\n', conf, problem=(2, 3))
self.check('a key: "multi\n'
' line"\n', conf, problem=(2, 8))
self.check('a key: "multi\n' self.check('a key: "multi\n'
' line"\n', conf, problem=(2, 10)) ' line"\n', conf, problem=(2, 10))
self.check('a key:\n'
' "multi\n'
' line"\n', conf, problem=(3, 3))
self.check('a key:\n' self.check('a key:\n'
' "multi\n' ' "multi\n'
' line"\n', conf, problem=(3, 5)) ' line"\n', conf, problem=(3, 5))

View File

@@ -43,17 +43,17 @@ class LineLengthTestCase(RuleTestCase):
self.check('---\n', conf) self.check('---\n', conf)
self.check(80 * 'a', conf) self.check(80 * 'a', conf)
self.check('---\n' + 80 * 'a' + '\n', conf) self.check('---\n' + 80 * 'a' + '\n', conf)
self.check(81 * 'a', conf, problem=(1, 81)) self.check(16 * 'aaaa ' + 'z', conf, problem=(1, 81))
self.check('---\n' + 81 * 'a' + '\n', conf, problem=(2, 81)) self.check('---\n' + 16 * 'aaaa ' + 'z' + '\n', conf, problem=(2, 81))
self.check(1000 * 'b', conf, problem=(1, 81)) self.check(1000 * 'word ' + 'end', conf, problem=(1, 81))
self.check('---\n' + 1000 * 'b' + '\n', conf, problem=(2, 81)) self.check('---\n' + 1000 * 'word ' + 'end\n', conf, problem=(2, 81))
def test_max_length_10(self): def test_max_length_10(self):
conf = ('line-length: {max: 10}\n' conf = ('line-length: {max: 10}\n'
'new-line-at-end-of-file: disable\n') 'new-line-at-end-of-file: disable\n')
self.check('---\nABCDEFGHIJ', conf) self.check('---\nABCD EFGHI', conf)
self.check('---\nABCDEFGHIJK', conf, problem=(2, 11)) self.check('---\nABCD EFGHIJ', conf, problem=(2, 11))
self.check('---\nABCDEFGHIJK\n', conf, problem=(2, 11)) self.check('---\nABCD EFGHIJ\n', conf, problem=(2, 11))
def test_spaces(self): def test_spaces(self):
conf = ('line-length: {max: 80}\n' conf = ('line-length: {max: 80}\n'
@@ -61,3 +61,36 @@ class LineLengthTestCase(RuleTestCase):
'trailing-spaces: disable\n') 'trailing-spaces: disable\n')
self.check('---\n' + 81 * ' ', conf, problem=(2, 81)) self.check('---\n' + 81 * ' ', conf, problem=(2, 81))
self.check('---\n' + 81 * ' ' + '\n', conf, problem=(2, 81)) self.check('---\n' + 81 * ' ' + '\n', conf, problem=(2, 81))
def test_non_breakable_word(self):
conf = 'line-length: {max: 20, allow-non-breakable-words: yes}'
self.check('---\n' + 30 * 'A' + '\n', conf)
self.check('---\n'
'this:\n'
' is:\n'
' - a:\n'
' http://localhost/very/long/url\n'
'...\n', conf)
self.check('---\n'
'this:\n'
' is:\n'
' - a:\n'
' # http://localhost/very/long/url\n'
' comment\n'
'...\n', conf)
conf = 'line-length: {max: 20, allow-non-breakable-words: no}'
self.check('---\n' + 30 * 'A' + '\n', conf, problem=(2, 21))
self.check('---\n'
'this:\n'
' is:\n'
' - a:\n'
' http://localhost/very/long/url\n'
'...\n', conf, problem=(5, 21))
self.check('---\n'
'this:\n'
' is:\n'
' - a:\n'
' # http://localhost/very/long/url\n'
' comment\n'
'...\n', conf, problem=(5, 21))

View File

@@ -15,8 +15,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
APP_NAME = 'yamllint' APP_NAME = 'yamllint'
APP_VERSION = '0.5.2' APP_VERSION = '0.6.0'
APP_DESCRIPTION = 'A linter for YAML files.' APP_DESCRIPTION = """A linter for YAML files.
yamllint does not only check for syntax validity, but for common cosmetic
conventions such as lines length, trailing spaces, indentation, etc."""
__author__ = u'Adrien Vergé' __author__ = u'Adrien Vergé'
__copyright__ = u'Copyright 2016, Adrien Vergé' __copyright__ = u'Copyright 2016, Adrien Vergé'

View File

@@ -35,6 +35,7 @@ rules:
check-multi-line-strings: no check-multi-line-strings: no
line-length: line-length:
max: 80 max: 80
allow-non-breakable-words: yes
new-line-at-end-of-file: {level: error} new-line-at-end-of-file: {level: error}
new-lines: new-lines:
type: unix type: unix

View File

@@ -113,6 +113,18 @@ Use this rule to control the indentation.
Je vous écris une longue lettre parce que Je vous écris une longue lettre parce que
je n'ai pas le temps d'en écrire une courte. je n'ai pas le temps d'en écrire une courte.
the following code snippet would **PASS**:
::
Blaise Pascal: Je vous écris une longue lettre parce que
je n'ai pas le temps d'en écrire une courte.
the following code snippet would **FAIL**:
::
Blaise Pascal: Je vous écris une longue lettre parce que
je n'ai pas le temps d'en écrire une courte.
the following code snippet would **FAIL**: the following code snippet would **FAIL**:
:: ::
@@ -212,11 +224,7 @@ def check_scalar_indentation(conf, token, context):
if token.start_mark.buffer[line_start + indent] == '\n': if token.start_mark.buffer[line_start + indent] == '\n':
continue continue
if indent < expected_indent: if indent != expected_indent:
yield LintProblem(line_no, indent + 1,
('wrong indentation: expected at least %d but '
'found %d') % (expected_indent, indent))
elif conf['check-multi-line-strings'] and indent > expected_indent:
yield LintProblem(line_no, indent + 1, yield LintProblem(line_no, indent + 1,
'wrong indentation: expected %d but found %d' % 'wrong indentation: expected %d but found %d' %
(expected_indent, indent)) (expected_indent, indent))
@@ -252,7 +260,8 @@ def check(conf, token, prev, next, context):
'wrong indentation: expected %d but found %d' % 'wrong indentation: expected %d but found %d' %
(expected, found_indentation)) (expected, found_indentation))
if isinstance(token, yaml.ScalarToken): if (isinstance(token, yaml.ScalarToken) and
conf['check-multi-line-strings']):
for problem in check_scalar_indentation(conf, token, context): for problem in check_scalar_indentation(conf, token, context):
yield problem yield problem

View File

@@ -20,6 +20,9 @@ Use this rule to set a limit to lines length.
.. rubric:: Options .. rubric:: Options
* ``max`` defines the maximal (inclusive) length of lines. * ``max`` defines the maximal (inclusive) length of lines.
* ``allow-non-breakable-words`` is used to allow non breakable words (without
spaces inside) to overflow the limit. This is useful for long URLs, for
instance. Use ``yes`` to allow, ``no`` to forbid.
.. rubric:: Examples .. rubric:: Examples
@@ -38,6 +41,35 @@ Use this rule to set a limit to lines length.
long sentence: long sentence:
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. tempor incididunt ut labore et dolore magna aliqua.
#. With ``line-length: {max: 60, allow-non-breakable-words: yes}``
the following code snippet would **PASS**:
::
this:
is:
- a:
http://localhost/very/very/very/very/very/very/very/very/long/url
# this comment is too long,
# but hard to split:
# http://localhost/another/very/very/very/very/very/very/very/very/long/url
the following code snippet would **FAIL**:
::
- this line is waaaaaaaaaaaaaay too long but could be easily splitted...
#. With ``line-length: {max: 60, allow-non-breakable-words: no}``
the following code snippet would **FAIL**:
::
this:
is:
- a:
http://localhost/very/very/very/very/very/very/very/very/long/url
""" """
@@ -46,11 +78,24 @@ from yamllint.linter import LintProblem
ID = 'line-length' ID = 'line-length'
TYPE = 'line' TYPE = 'line'
CONF = {'max': int} CONF = {'max': int,
'allow-non-breakable-words': bool}
def check(conf, line): def check(conf, line):
if line.end - line.start > conf['max']: if line.end - line.start > conf['max']:
if conf['allow-non-breakable-words']:
start = line.start
while start < line.end and line.buffer[start] == ' ':
start += 1
if start != line.end:
if line.buffer[start] == '#':
start += 2
if line.buffer.find(' ', start, line.end) == -1:
return
yield LintProblem(line.line_no, conf['max'] + 1, yield LintProblem(line.line_no, conf['max'] + 1,
'line too long (%d > %d characters)' % 'line too long (%d > %d characters)' %
(line.end - line.start, conf['max'])) (line.end - line.start, conf['max']))