From c803dd5f6df8d6adad5e4be18fa70b85e09cdca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Verg=C3=A9?= Date: Wed, 14 Nov 2018 19:08:39 +0100 Subject: [PATCH 01/17] docs(CHANGELOG): Fix RST format for code snippets --- CHANGELOG.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bf71899..6008deb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,42 +4,42 @@ Changelog 1.13.0 (2018-11-14) ------------------- -- Use `isinstance(x, y)` instead of `type(x) == y` -- Add a new `-f colored` option +- 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 +- 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 +- Add a new ``quoted-strings`` rule - Update installation documentation for pip, CentOS, Debian, Ubuntu, Mac OS 1.11.1 (2018-04-06) ------------------- -- Handle merge keys (`<<`) in the `key-duplicates` rule +- Handle merge keys (``<<``) in the ``key-duplicates`` rule - Update documentation about pre-commit -- Make examples for `ignore` rule clearer +- Make examples for ``ignore`` rule clearer - Clarify documentation on the 'truthy' rule - Fix crash in parser due to a change in PyYAML > 3.12 1.11.0 (2018-02-21) ------------------- -- Add a new `octal-values` rule +- Add a new ``octal-values`` rule 1.10.0 (2017-11-05) ------------------- - Fix colored output on Windows - Check documentation compilation on continuous integration -- Add a new `empty-values` rule +- Add a new ``empty-values`` rule - Make sure test files are included in dist bundle - Tests: Use en_US.UTF-8 locale when C.UTF-8 not available - Tests: Dynamically detect Python executable path @@ -47,13 +47,13 @@ Changelog 1.9.0 (2017-10-16) ------------------ -- Add a new `key-ordering` rule +- Add a new ``key-ordering`` rule - Fix indentation rule for key following empty list 1.8.2 (2017-10-10) ------------------ -- Be clearer about the `ignore` conf type +- Be clearer about the ``ignore`` conf type - Update pre-commit hook file - Add documentation for pre-commit From ea045c41b7231e0f7096ca091fe943a67a77cecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Verg=C3=A9?= Date: Fri, 23 Nov 2018 14:03:11 +0100 Subject: [PATCH 02/17] CI: Drop Python 3.3 support The `pkg_resources` package inside `setuptools` explicitly [disallows Python 3.3](https://github.com/pypa/setuptools/commit/7392f01ffced3acfdef25b0b2d55cefdc6ee468a#diff-81de4a30a55fcc3fb944f8387ea9ec94): if (3, 0) < sys.version_info < (3, 4): raise RuntimeError("Python 3.4 or later is required") It's time to drop support for 3.3. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 39f7a27..94cf9c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ language: python python: - 2.6 - 2.7 - - 3.3 - 3.4 - 3.5 - 3.6 From c8032c086b7a5057a6daa9a0648317cae5d4f413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Verg=C3=A9?= Date: Fri, 23 Nov 2018 09:58:40 +0100 Subject: [PATCH 03/17] line-length: Add tests for lines containing unicode characters Some unicode characters span accross multiple bytes. Python 3 is OK with that, but Python 2 reports an incorrect number of characters. Related to https://github.com/adrienverge/yamllint/issues/146 --- tests/rules/test_line_length.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/rules/test_line_length.py b/tests/rules/test_line_length.py index cab3e18..d052483 100644 --- a/tests/rules/test_line_length.py +++ b/tests/rules/test_line_length.py @@ -14,6 +14,13 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import sys +try: + assert sys.version_info >= (2, 7) + import unittest +except AssertionError: + import unittest2 as unittest + from tests.common import RuleTestCase @@ -155,3 +162,16 @@ class LineLengthTestCase(RuleTestCase): 'content: |\n' ' {% this line is' + 99 * ' really' + ' long %}\n', conf, problem=(3, 81)) + + @unittest.skipIf(sys.version_info < (3, 0), 'Python 2 not supported') + def test_unicode(self): + conf = 'line-length: {max: 53}' + self.check('---\n' + '# This is a test to check if “line-length” works nice\n' + 'with: “unicode characters” that span accross bytes! ↺\n', + conf) + conf = 'line-length: {max: 52}' + self.check('---\n' + '# This is a test to check if “line-length” works nice\n' + 'with: “unicode characters” that span accross bytes! ↺\n', + conf, problem1=(2, 53), problem2=(3, 53)) From 8bdddf6e89d9e232b0e67463a34f2926b0acfc6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Verg=C3=A9?= Date: Fri, 23 Nov 2018 14:13:04 +0100 Subject: [PATCH 04/17] docs: Warn about Python 2 and problems with line-length Closes #146. --- yamllint/rules/line_length.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/yamllint/rules/line_length.py b/yamllint/rules/line_length.py index e87972e..f7a2f2f 100644 --- a/yamllint/rules/line_length.py +++ b/yamllint/rules/line_length.py @@ -17,6 +17,10 @@ """ Use this rule to set a limit to lines length. +Note: with Python 2, the ``line-length`` rule may not work properly with +unicode characters because of the way strings are represented in bytes. We +recommend running yamllint with Python 3. + .. rubric:: Options * ``max`` defines the maximal (inclusive) length of lines. From c281d4850772ad318449c40d9257889e2d7c42f5 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 24 Nov 2018 11:29:07 +0200 Subject: [PATCH 05/17] Drop support for EOL Python 2.6 --- .travis.yml | 13 +++---------- tests/common.py | 7 +------ tests/rules/test_line_length.py | 6 +----- tests/test_cli.py | 7 +------ tests/test_config.py | 7 +------ tests/test_linter.py | 7 +------ tests/test_module.py | 7 +------ tests/test_parser.py | 7 +------ 8 files changed, 10 insertions(+), 51 deletions(-) diff --git a/.travis.yml b/.travis.yml index 94cf9c2..c8980bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,26 +1,19 @@ --- language: python python: - - 2.6 - 2.7 - 3.4 - 3.5 - 3.6 - nightly install: - - 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 coveralls; fi + - pip install pyyaml coveralls flake8 flake8-import-order - if [[ $TRAVIS_PYTHON_VERSION != 2* ]]; then pip install sphinx; fi - pip install . script: - - if [[ $TRAVIS_PYTHON_VERSION != 2.6 ]]; then flake8 .; fi + - flake8 . - yamllint --strict $(git ls-files '*.yaml' '*.yml') - - if [[ $TRAVIS_PYTHON_VERSION != 2.6 ]]; then - coverage run --source=yamllint setup.py test; - else - python setup.py test; - fi + - coverage run --source=yamllint setup.py test - if [[ $TRAVIS_PYTHON_VERSION != 2* ]]; then python setup.py build_sphinx; fi diff --git a/tests/common.py b/tests/common.py index ddeb867..b5ba469 100644 --- a/tests/common.py +++ b/tests/common.py @@ -16,12 +16,7 @@ import os import tempfile -import sys -try: - assert sys.version_info >= (2, 7) - import unittest -except AssertionError: - import unittest2 as unittest +import unittest import yaml diff --git a/tests/rules/test_line_length.py b/tests/rules/test_line_length.py index d052483..216317c 100644 --- a/tests/rules/test_line_length.py +++ b/tests/rules/test_line_length.py @@ -15,11 +15,7 @@ # along with this program. If not, see . import sys -try: - assert sys.version_info >= (2, 7) - import unittest -except AssertionError: - import unittest2 as unittest +import unittest from tests.common import RuleTestCase diff --git a/tests/test_cli.py b/tests/test_cli.py index 6d570f3..29feb1a 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -24,18 +24,13 @@ import os import pty import shutil import sys -try: - assert sys.version_info >= (2, 7) - import unittest -except AssertionError: - import unittest2 as unittest +import unittest from tests.common import build_temp_workspace from yamllint import cli -@unittest.skipIf(sys.version_info < (2, 7), 'Python 2.6 not supported') class CommandLineTestCase(unittest.TestCase): @classmethod def setUpClass(cls): diff --git a/tests/test_config.py b/tests/test_config.py index 3b6b9c2..b5af3aa 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -21,11 +21,7 @@ except ImportError: import os import shutil import sys -try: - assert sys.version_info >= (2, 7) - import unittest -except AssertionError: - import unittest2 as unittest +import unittest from tests.common import build_temp_workspace @@ -338,7 +334,6 @@ class IgnorePathConfigTestCase(unittest.TestCase): shutil.rmtree(cls.wd) - @unittest.skipIf(sys.version_info < (2, 7), 'Python 2.6 not supported') def test_run_with_ignored_path(self): sys.stdout = StringIO() with self.assertRaises(SystemExit): diff --git a/tests/test_linter.py b/tests/test_linter.py index 6c7ae62..859a1e5 100644 --- a/tests/test_linter.py +++ b/tests/test_linter.py @@ -15,12 +15,7 @@ # along with this program. If not, see . import io -import sys -try: - assert sys.version_info >= (2, 7) - import unittest -except AssertionError: - import unittest2 as unittest +import unittest from yamllint.config import YamlLintConfig from yamllint import linter diff --git a/tests/test_module.py b/tests/test_module.py index 8bdffcc..e1bf066 100644 --- a/tests/test_module.py +++ b/tests/test_module.py @@ -19,17 +19,12 @@ import shutil import subprocess import tempfile import sys -try: - assert sys.version_info >= (2, 7) - import unittest -except AssertionError: - import unittest2 as unittest +import unittest PYTHON = sys.executable or 'python' -@unittest.skipIf(sys.version_info < (2, 7), 'Python 2.6 not supported') class ModuleTestCase(unittest.TestCase): def setUp(self): self.wd = tempfile.mkdtemp(prefix='yamllint-tests-') diff --git a/tests/test_parser.py b/tests/test_parser.py index 7ed1f98..e40b9ac 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -14,12 +14,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import sys -try: - assert sys.version_info >= (2, 7) - import unittest -except AssertionError: - import unittest2 as unittest +import unittest import yaml From 8da6e36bf1076f247655669c5f86e262b3390521 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 24 Nov 2018 11:32:26 +0200 Subject: [PATCH 06/17] Add python_requires to help pip --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 0c61d01..1ae7c5d 100644 --- a/setup.py +++ b/setup.py @@ -29,6 +29,7 @@ setup( license=__license__, keywords=['yaml', 'lint', 'linter', 'syntax', 'checker'], url='https://github.com/adrienverge/yamllint', + python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', From 3d1ad9a176d882e43a2b84071960ce5fe1aafc5b Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 24 Nov 2018 11:33:02 +0200 Subject: [PATCH 07/17] Add explicit Trove classifers for PyPI --- setup.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/setup.py b/setup.py index 1ae7c5d..1b93008 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,12 @@ setup( 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Topic :: Software Development', 'Topic :: Software Development :: Debuggers', 'Topic :: Software Development :: Quality Assurance', From 4a7986b4cfaee9e02989f86d4f23d665a6d40f46 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 24 Nov 2018 11:34:35 +0200 Subject: [PATCH 08/17] Remove redundant parentheses --- tests/test_spec_examples.py | 74 ++++++++++++++++++------------------- yamllint/linter.py | 2 +- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/tests/test_spec_examples.py b/tests/test_spec_examples.py index f3e9239..5d41c26 100644 --- a/tests/test_spec_examples.py +++ b/tests/test_spec_examples.py @@ -54,8 +54,8 @@ conf_general = ('document-start: disable\n' 'braces: {min-spaces-inside: 1, max-spaces-inside: 1}\n' 'brackets: {min-spaces-inside: 1, max-spaces-inside: 1}\n') conf_overrides = { - 'example-2.2': ('colons: {max-spaces-after: 2}\n'), - 'example-2.4': ('colons: {max-spaces-after: 3}\n'), + 'example-2.2': 'colons: {max-spaces-after: 2}\n', + 'example-2.4': 'colons: {max-spaces-after: 3}\n', 'example-2.5': ('empty-lines: {max-end: 2}\n' 'brackets: {min-spaces-inside: 0, max-spaces-inside: 2}\n' 'commas: {max-spaces-before: -1}\n'), @@ -63,65 +63,65 @@ conf_overrides = { 'indentation: disable\n'), 'example-2.12': ('empty-lines: {max-end: 1}\n' 'colons: {max-spaces-before: -1}\n'), - 'example-2.16': ('empty-lines: {max-end: 1}\n'), - 'example-2.18': ('empty-lines: {max-end: 1}\n'), - 'example-2.19': ('empty-lines: {max-end: 1}\n'), - 'example-2.28': ('empty-lines: {max-end: 3}\n'), + 'example-2.16': 'empty-lines: {max-end: 1}\n', + 'example-2.18': 'empty-lines: {max-end: 1}\n', + 'example-2.19': 'empty-lines: {max-end: 1}\n', + 'example-2.28': 'empty-lines: {max-end: 3}\n', 'example-5.3': ('indentation: {indent-sequences: false}\n' 'colons: {max-spaces-before: 1}\n'), - 'example-6.4': ('trailing-spaces: disable\n'), - 'example-6.5': ('trailing-spaces: disable\n'), - 'example-6.6': ('trailing-spaces: disable\n'), - 'example-6.7': ('trailing-spaces: disable\n'), - 'example-6.8': ('trailing-spaces: disable\n'), + 'example-6.4': 'trailing-spaces: disable\n', + 'example-6.5': 'trailing-spaces: disable\n', + 'example-6.6': 'trailing-spaces: disable\n', + 'example-6.7': 'trailing-spaces: disable\n', + 'example-6.8': 'trailing-spaces: disable\n', 'example-6.10': ('empty-lines: {max-end: 2}\n' 'trailing-spaces: disable\n' 'comments-indentation: disable\n'), 'example-6.11': ('empty-lines: {max-end: 1}\n' 'comments-indentation: disable\n'), - 'example-6.13': ('comments-indentation: disable\n'), - 'example-6.14': ('comments-indentation: disable\n'), - 'example-6.23': ('colons: {max-spaces-before: 1}\n'), + 'example-6.13': 'comments-indentation: disable\n', + 'example-6.14': 'comments-indentation: disable\n', + 'example-6.23': 'colons: {max-spaces-before: 1}\n', 'example-7.4': ('colons: {max-spaces-before: 1}\n' 'indentation: disable\n'), - 'example-7.5': ('trailing-spaces: disable\n'), - 'example-7.6': ('trailing-spaces: disable\n'), - 'example-7.7': ('indentation: disable\n'), + 'example-7.5': 'trailing-spaces: disable\n', + 'example-7.6': 'trailing-spaces: disable\n', + 'example-7.7': 'indentation: disable\n', 'example-7.8': ('colons: {max-spaces-before: 1}\n' 'indentation: disable\n'), - 'example-7.9': ('trailing-spaces: disable\n'), + 'example-7.9': 'trailing-spaces: disable\n', 'example-7.11': ('colons: {max-spaces-before: 1}\n' 'indentation: disable\n'), 'example-7.13': ('brackets: {min-spaces-inside: 0, max-spaces-inside: 1}\n' 'commas: {max-spaces-before: 1, min-spaces-after: 0}\n'), - 'example-7.14': ('indentation: disable\n'), + 'example-7.14': 'indentation: disable\n', 'example-7.15': ('braces: {min-spaces-inside: 0, max-spaces-inside: 1}\n' 'commas: {max-spaces-before: 1, min-spaces-after: 0}\n' 'colons: {max-spaces-before: 1}\n'), - 'example-7.16': ('indentation: disable\n'), - 'example-7.17': ('indentation: disable\n'), - 'example-7.18': ('indentation: disable\n'), - 'example-7.19': ('indentation: disable\n'), + 'example-7.16': 'indentation: disable\n', + 'example-7.17': 'indentation: disable\n', + 'example-7.18': 'indentation: disable\n', + 'example-7.19': 'indentation: disable\n', 'example-7.20': ('colons: {max-spaces-before: 1}\n' 'indentation: disable\n'), - 'example-8.1': ('empty-lines: {max-end: 1}\n'), - 'example-8.2': ('trailing-spaces: disable\n'), + 'example-8.1': 'empty-lines: {max-end: 1}\n', + 'example-8.2': 'trailing-spaces: disable\n', 'example-8.5': ('comments-indentation: disable\n' 'trailing-spaces: disable\n'), - 'example-8.6': ('empty-lines: {max-end: 1}\n'), - 'example-8.7': ('empty-lines: {max-end: 1}\n'), - 'example-8.8': ('trailing-spaces: disable\n'), - 'example-8.9': ('empty-lines: {max-end: 1}\n'), - 'example-8.14': ('colons: {max-spaces-before: 1}\n'), - 'example-8.16': ('indentation: {spaces: 1}\n'), - 'example-8.17': ('indentation: disable\n'), + 'example-8.6': 'empty-lines: {max-end: 1}\n', + 'example-8.7': 'empty-lines: {max-end: 1}\n', + 'example-8.8': 'trailing-spaces: disable\n', + 'example-8.9': 'empty-lines: {max-end: 1}\n', + 'example-8.14': 'colons: {max-spaces-before: 1}\n', + 'example-8.16': 'indentation: {spaces: 1}\n', + 'example-8.17': 'indentation: disable\n', 'example-8.20': ('indentation: {indent-sequences: false}\n' 'colons: {max-spaces-before: 1}\n'), - 'example-8.22': ('indentation: disable\n'), - 'example-10.1': ('colons: {max-spaces-before: 2}\n'), - 'example-10.2': ('indentation: {indent-sequences: false}\n'), - 'example-10.8': ('truthy: disable\n'), - 'example-10.9': ('truthy: disable\n'), + 'example-8.22': 'indentation: disable\n', + 'example-10.1': 'colons: {max-spaces-before: 2}\n', + 'example-10.2': 'indentation: {indent-sequences: false}\n', + 'example-10.8': 'truthy: disable\n', + 'example-10.9': 'truthy: disable\n', } files = os.listdir(os.path.join(os.path.dirname(os.path.realpath(__file__)), diff --git a/yamllint/linter.py b/yamllint/linter.py index aaf43e5..9ee40a0 100644 --- a/yamllint/linter.py +++ b/yamllint/linter.py @@ -75,7 +75,7 @@ def get_cosmetic_problems(buffer, conf, filepath): for rule in token_rules: context[rule.ID] = {} - class DisableDirective(): + class DisableDirective: def __init__(self): self.rules = set() self.all_rules = set([r.ID for r in rules]) From 5852566ff0084043c8efb9ad7c9ca77795448abd Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 24 Nov 2018 11:40:56 +0200 Subject: [PATCH 09/17] Upgrade unit tests to use more useful asserts --- tests/test_config.py | 10 +++++----- tests/test_parser.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_config.py b/tests/test_config.py index b5af3aa..1c4a3d9 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -78,7 +78,7 @@ class SimpleConfigTestCase(unittest.TestCase): ' spaces: 2\n' ' indent-sequences: true\n' ' check-multi-line-strings: false\n') - self.assertEqual(c.rules['indentation']['indent-sequences'], True) + self.assertTrue(c.rules['indentation']['indent-sequences']) self.assertEqual(c.rules['indentation']['check-multi-line-strings'], False) @@ -87,7 +87,7 @@ class SimpleConfigTestCase(unittest.TestCase): ' spaces: 2\n' ' indent-sequences: yes\n' ' check-multi-line-strings: false\n') - self.assertEqual(c.rules['indentation']['indent-sequences'], True) + self.assertTrue(c.rules['indentation']['indent-sequences']) self.assertEqual(c.rules['indentation']['check-multi-line-strings'], False) @@ -115,8 +115,8 @@ class SimpleConfigTestCase(unittest.TestCase): class Rule(object): ID = 'fake' - self.assertEqual(config.validate_rule_conf(Rule, False), False) - self.assertEqual(config.validate_rule_conf(Rule, 'disable'), False) + self.assertFalse(config.validate_rule_conf(Rule, False)) + self.assertFalse(config.validate_rule_conf(Rule, 'disable')) self.assertEqual(config.validate_rule_conf(Rule, {}), {'level': 'error'}) @@ -194,7 +194,7 @@ class ExtendedConfigTestCase(unittest.TestCase): new.extend(old) self.assertEqual(sorted(new.rules.keys()), ['colons', 'hyphens']) - self.assertEqual(new.rules['colons'], False) + self.assertFalse(new.rules['colons']) self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2) self.assertEqual(len(new.enabled_rules(None)), 1) diff --git a/tests/test_parser.py b/tests/test_parser.py index e40b9ac..22145a8 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -65,12 +65,12 @@ class ParserTestCase(unittest.TestCase): def test_token_or_comment_generator(self): e = list(token_or_comment_generator('')) self.assertEqual(len(e), 2) - self.assertEqual(e[0].prev, None) + self.assertIsNone(e[0].prev) self.assertIsInstance(e[0].curr, yaml.Token) self.assertIsInstance(e[0].next, yaml.Token) self.assertEqual(e[1].prev, e[0].curr) self.assertEqual(e[1].curr, e[0].next) - self.assertEqual(e[1].next, None) + self.assertIsNone(e[1].next) e = list(token_or_comment_generator('---\n' 'k: v\n')) From f4c56b82167f879781bec128addabff88e385b91 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sun, 25 Nov 2018 11:36:03 +0200 Subject: [PATCH 10/17] Upgrade Python syntax with pyupgrade https://github.com/asottile/pyupgrade --- tests/rules/test_indentation.py | 4 ++-- yamllint/cli.py | 2 +- yamllint/linter.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/rules/test_indentation.py b/tests/rules/test_indentation.py index 3632a25..6fc68aa 100644 --- a/tests/rules/test_indentation.py +++ b/tests/rules/test_indentation.py @@ -51,8 +51,8 @@ class IndentationStackTestCase(RuleTestCase): .replace('Mapping', 'Map')) if token_type in ('StreamStart', 'StreamEnd'): continue - output += '%9s %s\n' % (token_type, - self.format_stack(context['stack'])) + output += '{:>9} {}\n'.format(token_type, + self.format_stack(context['stack'])) return output def test_simple_mapping(self): diff --git a/yamllint/cli.py b/yamllint/cli.py index 5cb84fc..8529fb7 100644 --- a/yamllint/cli.py +++ b/yamllint/cli.py @@ -103,7 +103,7 @@ def run(argv=None): help='return non-zero exit code on warnings ' 'as well as errors') parser.add_argument('-v', '--version', action='version', - version='%s %s' % (APP_NAME, APP_VERSION)) + version='{} {}'.format(APP_NAME, APP_VERSION)) # TODO: read from stdin when no filename? diff --git a/yamllint/linter.py b/yamllint/linter.py index 9ee40a0..ab46dca 100644 --- a/yamllint/linter.py +++ b/yamllint/linter.py @@ -47,7 +47,7 @@ class LintProblem(object): @property def message(self): if self.rule is not None: - return '%s (%s)' % (self.desc, self.rule) + return '{} ({})'.format(self.desc, self.rule) return self.desc def __eq__(self, other): @@ -78,7 +78,7 @@ def get_cosmetic_problems(buffer, conf, filepath): class DisableDirective: def __init__(self): self.rules = set() - self.all_rules = set([r.ID for r in rules]) + self.all_rules = {r.ID for r in rules} def process_comment(self, comment): try: From 6cf5eecdac3ed5ee601cfdd9dc5dbcf2f2a3e195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Verg=C3=A9?= Date: Sat, 8 Dec 2018 10:55:15 +0100 Subject: [PATCH 11/17] chore(CI): Lint RST (reStructuredText) files --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c8980bb..8dc047d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,11 +7,12 @@ python: - 3.6 - nightly install: - - pip install pyyaml coveralls flake8 flake8-import-order + - pip install pyyaml coveralls flake8 flake8-import-order doc8 - if [[ $TRAVIS_PYTHON_VERSION != 2* ]]; then pip install sphinx; fi - pip install . script: - flake8 . + - if [[ $TRAVIS_PYTHON_VERSION != 2* ]]; then doc8 $(git ls-files '*.rst'); fi - yamllint --strict $(git ls-files '*.yaml' '*.yml') - coverage run --source=yamllint setup.py test - if [[ $TRAVIS_PYTHON_VERSION != 2* ]]; then From a56a1015f097b2322f39f02adabced7512c0f290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Verg=C3=A9?= Date: Sat, 8 Dec 2018 11:04:32 +0100 Subject: [PATCH 12/17] style(docs): Fix RST lint errors reported by doc8 --- docs/configuration.rst | 10 +++++----- docs/disable_with_comments.rst | 12 ++++++------ docs/quickstart.rst | 6 +++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index 2557a4f..817a16d 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -45,9 +45,9 @@ It can be chosen using: Extending the default configuration ----------------------------------- -When writing a custom configuration file, you don't need to redefine every rule. -Just extend the ``default`` configuration (or any already-existing configuration -file). +When writing a custom configuration file, you don't need to redefine every +rule. Just extend the ``default`` configuration (or any already-existing +configuration file). For instance, if you just want to disable the ``comments-indentation`` rule, your file could look like this: @@ -105,8 +105,8 @@ Problems detected by yamllint can be raised either as errors or as warnings. The CLI will output them (with different colors when using the ``colored`` 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 -more error(s). +By default the script will exit with a return code ``1`` *only when* there is +one or more error(s). However if strict mode is enabled with the ``-s`` (or ``--strict``) option, the return code will be: diff --git a/docs/disable_with_comments.rst b/docs/disable_with_comments.rst index 34d6987..d50a372 100644 --- a/docs/disable_with_comments.rst +++ b/docs/disable_with_comments.rst @@ -4,9 +4,9 @@ Disable with comments Disabling checks for a specific line ------------------------------------ -To prevent yamllint from reporting problems for a specific line, add a directive -comment (``# yamllint disable-line ...``) on that line, or on the line above. -For instance: +To prevent yamllint from reporting problems for a specific line, add a +directive comment (``# yamllint disable-line ...``) on that line, or on the +line above. For instance: .. code-block:: yaml @@ -46,9 +46,9 @@ If you need to disable multiple rules, it is allowed to chain rules like this: Disabling checks for all (or part of) the file ---------------------------------------------- -To prevent yamllint from reporting problems for the whole file, or for a block of -lines within the file, use ``# yamllint disable ...`` and ``# yamllint enable -...`` directive comments. For instance: +To prevent yamllint from reporting problems for the whole file, or for a block +of lines within the file, use ``# yamllint disable ...`` and ``# yamllint +enable ...`` directive comments. For instance: .. code-block:: yaml diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 4d7692e..6165f30 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -68,9 +68,9 @@ The output will look like (colors are not displayed here): 10:1 error too many blank lines (4 > 2) (empty-lines) 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. +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 machine (for instance for :doc:`syntax highlighting in text editors From bc7ac817072318a5b15e575db15b379ffde81ea9 Mon Sep 17 00:00:00 2001 From: cclauss Date: Mon, 10 Dec 2018 17:06:14 +0100 Subject: [PATCH 13/17] Travis CI: Add Python 3.7 and 3.8a * Adds Python 3.7.1 and a current nightly build of Python 3.8 alpha. * Python 3.3 reached its end of life in 2017 https://devguide.python.org/#branchstatus --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8dc047d..58dd54a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,19 @@ --- +dist: xenial # required for Python >= 3.7 (travis-ci/travis-ci#9069) language: python python: - 2.7 - 3.4 - 3.5 - 3.6 + - 3.7 - nightly install: - pip install pyyaml coveralls flake8 flake8-import-order doc8 - if [[ $TRAVIS_PYTHON_VERSION != 2* ]]; then pip install sphinx; fi - pip install . script: - - flake8 . + - if [[ $TRAVIS_PYTHON_VERSION != nightly ]]; then flake8 .; fi - if [[ $TRAVIS_PYTHON_VERSION != 2* ]]; then doc8 $(git ls-files '*.rst'); fi - yamllint --strict $(git ls-files '*.yaml' '*.yml') - coverage run --source=yamllint setup.py test From 0f073f7a09d29ceb85a1aaf388bdbe5f4145f869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Verg=C3=A9?= Date: Wed, 9 Jan 2019 21:53:07 +0100 Subject: [PATCH 14/17] config: Do not require all rule options to be set Before, it was required to specify all the options when customizing a rule. For instance, one could use `empty-lines: enable` or `empty-lines: {max: 1, max-start: 2, max-end: 2}`, but not just `empty-lines: {max: 1}` (it would fail with *invalid config: missing option "max-start" for rule "empty-lines"*). This was a minor problem for users, but it prevented the addition of new options to existing rules, see [1] for an example. If a new option was added, updating yamllint for all users that customize the rule would produce a crash (*invalid config: missing option ...*). To avoid that, let's embed default values inside the rules themselves, instead of keeping them in `conf/default.yaml`. This refactor should not have any impact on existing projects. I've manually checked that it did not change the output of tests, on different projects: - ansible/ansible: `test/runner/ansible-test sanity --python 3.7 --test yamllint` - ansible/molecule: `yamllint -s test/ molecule/` - Neo23x0/sigma: `make test-yaml` - markstory/lint-review: `yamllint .` [1]: https://github.com/adrienverge/yamllint/pull/151 --- tests/test_config.py | 219 +++++++++++++++++++++---------- yamllint/conf/default.yaml | 55 ++------ yamllint/config.py | 14 +- yamllint/rules/braces.py | 4 + yamllint/rules/brackets.py | 4 + yamllint/rules/colons.py | 2 + yamllint/rules/commas.py | 3 + yamllint/rules/comments.py | 2 + yamllint/rules/document_end.py | 1 + yamllint/rules/document_start.py | 1 + yamllint/rules/empty_lines.py | 3 + yamllint/rules/empty_values.py | 2 + yamllint/rules/hyphens.py | 1 + yamllint/rules/indentation.py | 3 + yamllint/rules/key_duplicates.py | 1 - yamllint/rules/key_ordering.py | 1 - yamllint/rules/line_length.py | 3 + yamllint/rules/new_lines.py | 1 + yamllint/rules/octal_values.py | 2 + yamllint/rules/quoted_strings.py | 1 + yamllint/rules/truthy.py | 1 - 21 files changed, 206 insertions(+), 118 deletions(-) diff --git a/tests/test_config.py b/tests/test_config.py index 1c4a3d9..f5d9402 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -21,6 +21,7 @@ except ImportError: import os import shutil import sys +import tempfile import unittest from tests.common import build_temp_workspace @@ -54,13 +55,16 @@ class SimpleConfigTestCase(unittest.TestCase): ' this-one-does-not-exist: enable\n') def test_missing_option(self): - with self.assertRaisesRegexp( - config.YamlLintConfigError, - 'invalid config: missing option "max-spaces-before" ' - 'for rule "colons"'): - config.YamlLintConfig('rules:\n' + c = config.YamlLintConfig('rules:\n' + ' colons: enable\n') + self.assertEqual(c.rules['colons']['max-spaces-before'], 0) + self.assertEqual(c.rules['colons']['max-spaces-after'], 1) + + c = config.YamlLintConfig('rules:\n' ' colons:\n' - ' max-spaces-after: 1\n') + ' max-spaces-before: 9\n') + self.assertEqual(c.rules['colons']['max-spaces-before'], 9) + self.assertEqual(c.rules['colons']['max-spaces-after'], 1) def test_unknown_option(self): with self.assertRaisesRegexp( @@ -111,17 +115,22 @@ class SimpleConfigTestCase(unittest.TestCase): ' indent-sequences: YES!\n' ' check-multi-line-strings: false\n') + def test_enable_disable_keywords(self): + c = config.YamlLintConfig('rules:\n' + ' colons: enable\n' + ' hyphens: disable\n') + self.assertEqual(c.rules['colons'], {'level': 'error', + 'max-spaces-after': 1, + 'max-spaces-before': 0}) + self.assertEqual(c.rules['hyphens'], False) + def test_validate_rule_conf(self): class Rule(object): ID = 'fake' self.assertFalse(config.validate_rule_conf(Rule, False)) - self.assertFalse(config.validate_rule_conf(Rule, 'disable')) - self.assertEqual(config.validate_rule_conf(Rule, {}), {'level': 'error'}) - self.assertEqual(config.validate_rule_conf(Rule, 'enable'), - {'level': 'error'}) config.validate_rule_conf(Rule, {'level': 'error'}) config.validate_rule_conf(Rule, {'level': 'warning'}) @@ -129,22 +138,22 @@ class SimpleConfigTestCase(unittest.TestCase): config.validate_rule_conf, Rule, {'level': 'warn'}) Rule.CONF = {'length': int} + Rule.DEFAULT = {'length': 80} config.validate_rule_conf(Rule, {'length': 8}) - self.assertRaises(config.YamlLintConfigError, - config.validate_rule_conf, Rule, {}) + config.validate_rule_conf(Rule, {}) self.assertRaises(config.YamlLintConfigError, config.validate_rule_conf, Rule, {'height': 8}) Rule.CONF = {'a': bool, 'b': int} + Rule.DEFAULT = {'a': True, 'b': -42} config.validate_rule_conf(Rule, {'a': True, 'b': 0}) - self.assertRaises(config.YamlLintConfigError, - config.validate_rule_conf, Rule, {'a': True}) - self.assertRaises(config.YamlLintConfigError, - config.validate_rule_conf, Rule, {'b': 0}) + config.validate_rule_conf(Rule, {'a': True}) + config.validate_rule_conf(Rule, {'b': 0}) self.assertRaises(config.YamlLintConfigError, config.validate_rule_conf, Rule, {'a': 1, 'b': 0}) Rule.CONF = {'choice': (True, 88, 'str')} + Rule.DEFAULT = {'choice': 88} config.validate_rule_conf(Rule, {'choice': True}) config.validate_rule_conf(Rule, {'choice': 88}) config.validate_rule_conf(Rule, {'choice': 'str'}) @@ -156,8 +165,10 @@ class SimpleConfigTestCase(unittest.TestCase): config.validate_rule_conf, Rule, {'choice': 'abc'}) Rule.CONF = {'choice': (int, 'hardcoded')} + Rule.DEFAULT = {'choice': 1337} config.validate_rule_conf(Rule, {'choice': 42}) config.validate_rule_conf(Rule, {'choice': 'hardcoded'}) + config.validate_rule_conf(Rule, {}) self.assertRaises(config.YamlLintConfigError, config.validate_rule_conf, Rule, {'choice': False}) self.assertRaises(config.YamlLintConfigError, @@ -165,7 +176,7 @@ class SimpleConfigTestCase(unittest.TestCase): class ExtendedConfigTestCase(unittest.TestCase): - def test_extend_add_rule(self): + def test_extend_on_object(self): old = config.YamlLintConfig('rules:\n' ' colons:\n' ' max-spaces-before: 0\n' @@ -182,60 +193,130 @@ class ExtendedConfigTestCase(unittest.TestCase): self.assertEqual(len(new.enabled_rules(None)), 2) - def test_extend_remove_rule(self): - old = config.YamlLintConfig('rules:\n' - ' colons:\n' - ' max-spaces-before: 0\n' - ' max-spaces-after: 1\n' - ' hyphens:\n' - ' max-spaces-after: 2\n') - new = config.YamlLintConfig('rules:\n' - ' colons: disable\n') - new.extend(old) + def test_extend_on_file(self): + with tempfile.NamedTemporaryFile('w') as f: + f.write('rules:\n' + ' colons:\n' + ' max-spaces-before: 0\n' + ' max-spaces-after: 1\n') + f.flush() + c = config.YamlLintConfig('extends: ' + f.name + '\n' + 'rules:\n' + ' hyphens:\n' + ' max-spaces-after: 2\n') + + self.assertEqual(sorted(c.rules.keys()), ['colons', 'hyphens']) + self.assertEqual(c.rules['colons']['max-spaces-before'], 0) + self.assertEqual(c.rules['colons']['max-spaces-after'], 1) + self.assertEqual(c.rules['hyphens']['max-spaces-after'], 2) + + self.assertEqual(len(c.enabled_rules(None)), 2) - self.assertEqual(sorted(new.rules.keys()), ['colons', 'hyphens']) - self.assertFalse(new.rules['colons']) - self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2) - - self.assertEqual(len(new.enabled_rules(None)), 1) + def test_extend_remove_rule(self): + with tempfile.NamedTemporaryFile('w') as f: + f.write('rules:\n' + ' colons:\n' + ' max-spaces-before: 0\n' + ' max-spaces-after: 1\n' + ' hyphens:\n' + ' max-spaces-after: 2\n') + f.flush() + c = config.YamlLintConfig('extends: ' + f.name + '\n' + 'rules:\n' + ' colons: disable\n') + + self.assertEqual(sorted(c.rules.keys()), ['colons', 'hyphens']) + self.assertFalse(c.rules['colons']) + self.assertEqual(c.rules['hyphens']['max-spaces-after'], 2) + + self.assertEqual(len(c.enabled_rules(None)), 1) def test_extend_edit_rule(self): - old = config.YamlLintConfig('rules:\n' - ' colons:\n' - ' max-spaces-before: 0\n' - ' max-spaces-after: 1\n' - ' hyphens:\n' - ' max-spaces-after: 2\n') - new = config.YamlLintConfig('rules:\n' - ' colons:\n' - ' max-spaces-before: 3\n' - ' max-spaces-after: 4\n') - new.extend(old) - - self.assertEqual(sorted(new.rules.keys()), ['colons', 'hyphens']) - self.assertEqual(new.rules['colons']['max-spaces-before'], 3) - self.assertEqual(new.rules['colons']['max-spaces-after'], 4) - self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2) - - self.assertEqual(len(new.enabled_rules(None)), 2) + with tempfile.NamedTemporaryFile('w') as f: + f.write('rules:\n' + ' colons:\n' + ' max-spaces-before: 0\n' + ' max-spaces-after: 1\n' + ' hyphens:\n' + ' max-spaces-after: 2\n') + f.flush() + c = config.YamlLintConfig('extends: ' + f.name + '\n' + 'rules:\n' + ' colons:\n' + ' max-spaces-before: 3\n' + ' max-spaces-after: 4\n') + + self.assertEqual(sorted(c.rules.keys()), ['colons', 'hyphens']) + self.assertEqual(c.rules['colons']['max-spaces-before'], 3) + self.assertEqual(c.rules['colons']['max-spaces-after'], 4) + self.assertEqual(c.rules['hyphens']['max-spaces-after'], 2) + + self.assertEqual(len(c.enabled_rules(None)), 2) def test_extend_reenable_rule(self): - old = config.YamlLintConfig('rules:\n' - ' colons:\n' - ' max-spaces-before: 0\n' - ' max-spaces-after: 1\n' - ' hyphens: disable\n') - new = config.YamlLintConfig('rules:\n' - ' hyphens:\n' - ' max-spaces-after: 2\n') - new.extend(old) - - self.assertEqual(sorted(new.rules.keys()), ['colons', 'hyphens']) - self.assertEqual(new.rules['colons']['max-spaces-before'], 0) - self.assertEqual(new.rules['colons']['max-spaces-after'], 1) - self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2) - - self.assertEqual(len(new.enabled_rules(None)), 2) + with tempfile.NamedTemporaryFile('w') as f: + f.write('rules:\n' + ' colons:\n' + ' max-spaces-before: 0\n' + ' max-spaces-after: 1\n' + ' hyphens: disable\n') + f.flush() + c = config.YamlLintConfig('extends: ' + f.name + '\n' + 'rules:\n' + ' hyphens:\n' + ' max-spaces-after: 2\n') + + self.assertEqual(sorted(c.rules.keys()), ['colons', 'hyphens']) + self.assertEqual(c.rules['colons']['max-spaces-before'], 0) + self.assertEqual(c.rules['colons']['max-spaces-after'], 1) + self.assertEqual(c.rules['hyphens']['max-spaces-after'], 2) + + self.assertEqual(len(c.enabled_rules(None)), 2) + + def test_extend_recursive_default_values(self): + with tempfile.NamedTemporaryFile('w') as f: + f.write('rules:\n' + ' braces:\n' + ' max-spaces-inside: 1248\n') + f.flush() + c = config.YamlLintConfig('extends: ' + f.name + '\n' + 'rules:\n' + ' braces:\n' + ' min-spaces-inside-empty: 2357\n') + + self.assertEqual(c.rules['braces']['min-spaces-inside'], 0) + self.assertEqual(c.rules['braces']['max-spaces-inside'], 1248) + self.assertEqual(c.rules['braces']['min-spaces-inside-empty'], 2357) + self.assertEqual(c.rules['braces']['max-spaces-inside-empty'], -1) + + with tempfile.NamedTemporaryFile('w') as f: + f.write('rules:\n' + ' colons:\n' + ' max-spaces-before: 1337\n') + f.flush() + c = config.YamlLintConfig('extends: ' + f.name + '\n' + 'rules:\n' + ' colons: enable\n') + + self.assertEqual(c.rules['colons']['max-spaces-before'], 1337) + self.assertEqual(c.rules['colons']['max-spaces-after'], 1) + + with tempfile.NamedTemporaryFile('w') as f1, \ + tempfile.NamedTemporaryFile('w') as f2: + f1.write('rules:\n' + ' colons:\n' + ' max-spaces-before: 1337\n') + f1.flush() + f2.write('extends: ' + f1.name + '\n' + 'rules:\n' + ' colons: disable\n') + f2.flush() + c = config.YamlLintConfig('extends: ' + f2.name + '\n' + 'rules:\n' + ' colons: enable\n') + + self.assertEqual(c.rules['colons']['max-spaces-before'], 0) + self.assertEqual(c.rules['colons']['max-spaces-after'], 1) class ExtendedLibraryConfigTestCase(unittest.TestCase): @@ -267,6 +348,9 @@ class ExtendedLibraryConfigTestCase(unittest.TestCase): self.assertEqual(sorted(new.rules.keys()), sorted(old.rules.keys())) for rule in new.rules: self.assertEqual(new.rules[rule], old.rules[rule]) + self.assertEqual(new.rules['empty-lines']['max'], 42) + self.assertEqual(new.rules['empty-lines']['max-start'], 43) + self.assertEqual(new.rules['empty-lines']['max-end'], 44) def test_extend_config_override_rule_partly(self): old = config.YamlLintConfig('extends: default') @@ -280,6 +364,9 @@ class ExtendedLibraryConfigTestCase(unittest.TestCase): self.assertEqual(sorted(new.rules.keys()), sorted(old.rules.keys())) for rule in new.rules: self.assertEqual(new.rules[rule], old.rules[rule]) + self.assertEqual(new.rules['empty-lines']['max'], 2) + self.assertEqual(new.rules['empty-lines']['max-start'], 42) + self.assertEqual(new.rules['empty-lines']['max-end'], 0) class IgnorePathConfigTestCase(unittest.TestCase): diff --git a/yamllint/conf/default.yaml b/yamllint/conf/default.yaml index fcece4d..da9701e 100644 --- a/yamllint/conf/default.yaml +++ b/yamllint/conf/default.yaml @@ -1,59 +1,28 @@ --- rules: - braces: - min-spaces-inside: 0 - max-spaces-inside: 0 - min-spaces-inside-empty: -1 - max-spaces-inside-empty: -1 - brackets: - min-spaces-inside: 0 - max-spaces-inside: 0 - min-spaces-inside-empty: -1 - max-spaces-inside-empty: -1 - colons: - max-spaces-before: 0 - max-spaces-after: 1 - commas: - max-spaces-before: 0 - min-spaces-after: 1 - max-spaces-after: 1 + braces: enable + brackets: enable + colons: enable + commas: enable comments: level: warning - require-starting-space: true - min-spaces-from-content: 2 comments-indentation: level: warning document-end: disable document-start: level: warning - present: true - empty-lines: - max: 2 - max-start: 0 - max-end: 0 - quoted-strings: disable - empty-values: - forbid-in-block-mappings: false - forbid-in-flow-mappings: false - hyphens: - max-spaces-after: 1 - indentation: - spaces: consistent - indent-sequences: true - check-multi-line-strings: false + empty-lines: enable + empty-values: enable + hyphens: enable + indentation: enable key-duplicates: enable key-ordering: disable - line-length: - max: 80 - allow-non-breakable-words: true - allow-non-breakable-inline-mappings: false + line-length: enable new-line-at-end-of-file: enable - new-lines: - type: unix - octal-values: - forbid-implicit-octal: false - forbid-explicit-octal: false + new-lines: enable + octal-values: enable + quoted-strings: disable trailing-spaces: enable truthy: level: warning diff --git a/yamllint/config.py b/yamllint/config.py index 3a3f3c7..b4a7c1d 100644 --- a/yamllint/config.py +++ b/yamllint/config.py @@ -74,6 +74,11 @@ class YamlLintConfig(object): raise YamlLintConfigError('invalid config: not a dict') self.rules = conf.get('rules', {}) + for rule in self.rules: + if self.rules[rule] == 'enable': + self.rules[rule] = {} + elif self.rules[rule] == 'disable': + self.rules[rule] = False # Does this conf override another conf that we need to load? if 'extends' in conf: @@ -102,10 +107,8 @@ class YamlLintConfig(object): def validate_rule_conf(rule, conf): - if conf is False or conf == 'disable': + if conf is False: # disable return False - elif conf == 'enable': - conf = {} if isinstance(conf, dict): if ('ignore' in conf and @@ -123,6 +126,7 @@ def validate_rule_conf(rule, conf): 'invalid config: level should be "error" or "warning"') options = getattr(rule, 'CONF', {}) + options_default = getattr(rule, 'DEFAULT', {}) for optkey in conf: if optkey in ('ignore', 'level'): continue @@ -143,9 +147,7 @@ def validate_rule_conf(rule, conf): % (optkey, rule.ID, options[optkey].__name__)) for optkey in options: if optkey not in conf: - raise YamlLintConfigError( - 'invalid config: missing option "%s" for rule "%s"' % - (optkey, rule.ID)) + conf[optkey] = options_default[optkey] else: raise YamlLintConfigError(('invalid config: rule "%s": should be ' 'either "enable", "disable" or a dict') diff --git a/yamllint/rules/braces.py b/yamllint/rules/braces.py index 59d9558..654b36d 100644 --- a/yamllint/rules/braces.py +++ b/yamllint/rules/braces.py @@ -101,6 +101,10 @@ CONF = {'min-spaces-inside': int, 'max-spaces-inside': int, 'min-spaces-inside-empty': int, 'max-spaces-inside-empty': int} +DEFAULT = {'min-spaces-inside': 0, + 'max-spaces-inside': 0, + 'min-spaces-inside-empty': -1, + 'max-spaces-inside-empty': -1} def check(conf, token, prev, next, nextnext, context): diff --git a/yamllint/rules/brackets.py b/yamllint/rules/brackets.py index 33bdaa9..b54c515 100644 --- a/yamllint/rules/brackets.py +++ b/yamllint/rules/brackets.py @@ -102,6 +102,10 @@ CONF = {'min-spaces-inside': int, 'max-spaces-inside': int, 'min-spaces-inside-empty': int, 'max-spaces-inside-empty': int} +DEFAULT = {'min-spaces-inside': 0, + 'max-spaces-inside': 0, + 'min-spaces-inside-empty': -1, + 'max-spaces-inside-empty': -1} def check(conf, token, prev, next, nextnext, context): diff --git a/yamllint/rules/colons.py b/yamllint/rules/colons.py index 8d386b8..fd46bef 100644 --- a/yamllint/rules/colons.py +++ b/yamllint/rules/colons.py @@ -79,6 +79,8 @@ ID = 'colons' TYPE = 'token' CONF = {'max-spaces-before': int, 'max-spaces-after': int} +DEFAULT = {'max-spaces-before': 0, + 'max-spaces-after': 1} def check(conf, token, prev, next, nextnext, context): diff --git a/yamllint/rules/commas.py b/yamllint/rules/commas.py index ba42373..bb73044 100644 --- a/yamllint/rules/commas.py +++ b/yamllint/rules/commas.py @@ -103,6 +103,9 @@ TYPE = 'token' CONF = {'max-spaces-before': int, 'min-spaces-after': int, 'max-spaces-after': int} +DEFAULT = {'max-spaces-before': 0, + 'min-spaces-after': 1, + 'max-spaces-after': 1} def check(conf, token, prev, next, nextnext, context): diff --git a/yamllint/rules/comments.py b/yamllint/rules/comments.py index 69da045..7ecce39 100644 --- a/yamllint/rules/comments.py +++ b/yamllint/rules/comments.py @@ -68,6 +68,8 @@ ID = 'comments' TYPE = 'comment' CONF = {'require-starting-space': bool, 'min-spaces-from-content': int} +DEFAULT = {'require-starting-space': True, + 'min-spaces-from-content': 2} def check(conf, comment): diff --git a/yamllint/rules/document_end.py b/yamllint/rules/document_end.py index 8335a05..e98aac1 100644 --- a/yamllint/rules/document_end.py +++ b/yamllint/rules/document_end.py @@ -82,6 +82,7 @@ from yamllint.linter import LintProblem ID = 'document-end' TYPE = 'token' CONF = {'present': bool} +DEFAULT = {'present': True} def check(conf, token, prev, next, nextnext, context): diff --git a/yamllint/rules/document_start.py b/yamllint/rules/document_start.py index 090260a..36c3d8e 100644 --- a/yamllint/rules/document_start.py +++ b/yamllint/rules/document_start.py @@ -72,6 +72,7 @@ from yamllint.linter import LintProblem ID = 'document-start' TYPE = 'token' CONF = {'present': bool} +DEFAULT = {'present': True} def check(conf, token, prev, next, nextnext, context): diff --git a/yamllint/rules/empty_lines.py b/yamllint/rules/empty_lines.py index 93f4df4..335b125 100644 --- a/yamllint/rules/empty_lines.py +++ b/yamllint/rules/empty_lines.py @@ -58,6 +58,9 @@ TYPE = 'line' CONF = {'max': int, 'max-start': int, 'max-end': int} +DEFAULT = {'max': 2, + 'max-start': 0, + 'max-end': 0} def check(conf, line): diff --git a/yamllint/rules/empty_values.py b/yamllint/rules/empty_values.py index daa62b2..14bd0e0 100644 --- a/yamllint/rules/empty_values.py +++ b/yamllint/rules/empty_values.py @@ -75,6 +75,8 @@ ID = 'empty-values' TYPE = 'token' CONF = {'forbid-in-block-mappings': bool, 'forbid-in-flow-mappings': bool} +DEFAULT = {'forbid-in-block-mappings': False, + 'forbid-in-flow-mappings': False} def check(conf, token, prev, next, nextnext, context): diff --git a/yamllint/rules/hyphens.py b/yamllint/rules/hyphens.py index 1d5a1a4..df38b4c 100644 --- a/yamllint/rules/hyphens.py +++ b/yamllint/rules/hyphens.py @@ -76,6 +76,7 @@ from yamllint.rules.common import spaces_after ID = 'hyphens' TYPE = 'token' CONF = {'max-spaces-after': int} +DEFAULT = {'max-spaces-after': 1} def check(conf, token, prev, next, nextnext, context): diff --git a/yamllint/rules/indentation.py b/yamllint/rules/indentation.py index cf4ebc5..8bb7175 100644 --- a/yamllint/rules/indentation.py +++ b/yamllint/rules/indentation.py @@ -201,6 +201,9 @@ TYPE = 'token' CONF = {'spaces': (int, 'consistent'), 'indent-sequences': (bool, 'whatever', 'consistent'), 'check-multi-line-strings': bool} +DEFAULT = {'spaces': 'consistent', + 'indent-sequences': True, + 'check-multi-line-strings': False} ROOT, B_MAP, F_MAP, B_SEQ, F_SEQ, B_ENT, KEY, VAL = range(8) labels = ('ROOT', 'B_MAP', 'F_MAP', 'B_SEQ', 'F_SEQ', 'B_ENT', 'KEY', 'VAL') diff --git a/yamllint/rules/key_duplicates.py b/yamllint/rules/key_duplicates.py index fc9c5a3..bd38b14 100644 --- a/yamllint/rules/key_duplicates.py +++ b/yamllint/rules/key_duplicates.py @@ -61,7 +61,6 @@ from yamllint.linter import LintProblem ID = 'key-duplicates' TYPE = 'token' -CONF = {} MAP, SEQ = range(2) diff --git a/yamllint/rules/key_ordering.py b/yamllint/rules/key_ordering.py index 3bd93c7..1ca992b 100644 --- a/yamllint/rules/key_ordering.py +++ b/yamllint/rules/key_ordering.py @@ -72,7 +72,6 @@ from yamllint.linter import LintProblem ID = 'key-ordering' TYPE = 'token' -CONF = {} MAP, SEQ = range(2) diff --git a/yamllint/rules/line_length.py b/yamllint/rules/line_length.py index f7a2f2f..9b5a1ab 100644 --- a/yamllint/rules/line_length.py +++ b/yamllint/rules/line_length.py @@ -102,6 +102,9 @@ TYPE = 'line' CONF = {'max': int, 'allow-non-breakable-words': bool, 'allow-non-breakable-inline-mappings': bool} +DEFAULT = {'max': 80, + 'allow-non-breakable-words': True, + 'allow-non-breakable-inline-mappings': False} def check_inline_mapping(line): diff --git a/yamllint/rules/new_lines.py b/yamllint/rules/new_lines.py index 91adb4e..3aae90f 100644 --- a/yamllint/rules/new_lines.py +++ b/yamllint/rules/new_lines.py @@ -30,6 +30,7 @@ from yamllint.linter import LintProblem ID = 'new-lines' TYPE = 'line' CONF = {'type': ('unix', 'dos')} +DEFAULT = {'type': 'unix'} def check(conf, line): diff --git a/yamllint/rules/octal_values.py b/yamllint/rules/octal_values.py index 33c0793..40de39a 100644 --- a/yamllint/rules/octal_values.py +++ b/yamllint/rules/octal_values.py @@ -66,6 +66,8 @@ ID = 'octal-values' TYPE = 'token' CONF = {'forbid-implicit-octal': bool, 'forbid-explicit-octal': bool} +DEFAULT = {'forbid-implicit-octal': False, + 'forbid-explicit-octal': False} def check(conf, token, prev, next, nextnext, context): diff --git a/yamllint/rules/quoted_strings.py b/yamllint/rules/quoted_strings.py index 711a627..b019261 100644 --- a/yamllint/rules/quoted_strings.py +++ b/yamllint/rules/quoted_strings.py @@ -46,6 +46,7 @@ from yamllint.linter import LintProblem ID = 'quoted-strings' TYPE = 'token' CONF = {'quote-type': ('any', 'single', 'double')} +DEFAULT = {'quote-type': 'any'} def check(conf, token, prev, next, nextnext, context): diff --git a/yamllint/rules/truthy.py b/yamllint/rules/truthy.py index c14b06a..b738dc2 100644 --- a/yamllint/rules/truthy.py +++ b/yamllint/rules/truthy.py @@ -71,7 +71,6 @@ from yamllint.linter import LintProblem ID = 'truthy' TYPE = 'token' -CONF = {} TRUTHY = ['YES', 'Yes', 'yes', 'NO', 'No', 'no', From b77f78f677f2714269cc8957fd0c85df9cc0c391 Mon Sep 17 00:00:00 2001 From: Mattias Bengtsson Date: Thu, 6 Dec 2018 13:50:24 +0100 Subject: [PATCH 15/17] Support ignoring shebangs Some usages of YAML (like Ansible) supports running the file as a script. Support (by default) an ignore-shebangs setting for the comments module. Fixes #116 - comments rule with require-starting-space: true should special case shebang --- tests/rules/test_comments.py | 27 +++++++++++++++++++++++++++ yamllint/rules/comments.py | 20 +++++++++++++++----- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/tests/rules/test_comments.py b/tests/rules/test_comments.py index ded31fa..742650b 100644 --- a/tests/rules/test_comments.py +++ b/tests/rules/test_comments.py @@ -80,6 +80,33 @@ class CommentsTestCase(RuleTestCase): problem3=(9, 2), problem4=(10, 4), problem5=(15, 3)) + def test_shebang(self): + conf = ('comments:\n' + ' require-starting-space: true\n' + ' ignore-shebangs: false\n' + 'comments-indentation: disable\n') + self.check('#!/bin/env my-interpreter\n', + conf, problem1=(1, 2)) + self.check('#!/bin/env my-interpreter\n' + '---\n' + '#comment\n' + '#!/bin/env my-interpreter\n' + '', conf, + problem1=(1, 2), problem2=(3, 2), problem3=(4, 2)) + + def test_ignore_shebang(self): + conf = ('comments:\n' + ' require-starting-space: true\n' + ' ignore-shebangs: true\n' + 'comments-indentation: disable\n') + self.check('#!/bin/env my-interpreter\n', conf) + self.check('#!/bin/env my-interpreter\n' + '---\n' + '#comment\n' + '#!/bin/env my-interpreter\n' + '', conf, + problem2=(3, 2), problem3=(4, 2)) + def test_spaces_from_content(self): conf = ('comments:\n' ' require-starting-space: false\n' diff --git a/yamllint/rules/comments.py b/yamllint/rules/comments.py index 7ecce39..4777d02 100644 --- a/yamllint/rules/comments.py +++ b/yamllint/rules/comments.py @@ -21,6 +21,9 @@ Use this rule to control the position and formatting of comments. * Use ``require-starting-space`` to require a space character right after the ``#``. Set to ``true`` to enable, ``false`` to disable. +* Use ``ignore-shebangs`` to ignore a + `shebang `_ at the beginning of + the file when ``require-starting-space`` is set. * ``min-spaces-from-content`` is used to visually separate inline comments from content. It defines the minimal required number of spaces between a comment and its preceding content. @@ -67,8 +70,10 @@ from yamllint.linter import LintProblem ID = 'comments' TYPE = 'comment' CONF = {'require-starting-space': bool, + 'ignore-shebangs': bool, 'min-spaces-from-content': int} DEFAULT = {'require-starting-space': True, + 'ignore-shebangs': True, 'min-spaces-from-content': 2} @@ -84,8 +89,13 @@ def check(conf, comment): while (comment.buffer[text_start] == '#' and text_start < len(comment.buffer)): text_start += 1 - if (text_start < len(comment.buffer) and - comment.buffer[text_start] not in (' ', '\n', '\0')): - yield LintProblem(comment.line_no, - comment.column_no + text_start - comment.pointer, - 'missing starting space in comment') + if text_start < len(comment.buffer): + if (conf['ignore-shebangs'] and + comment.line_no == 1 and + comment.buffer[text_start] == '!'): + return + elif comment.buffer[text_start] not in (' ', '\n', '\0'): + column = comment.column_no + text_start - comment.pointer + yield LintProblem(comment.line_no, + column, + 'missing starting space in comment') From b4740dc1fb75a23c12b9c08101d45d6a3c7684f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Verg=C3=A9?= Date: Fri, 11 Jan 2019 12:19:06 +0100 Subject: [PATCH 16/17] comments: Fix ignore-shebangs option on corner cases --- tests/rules/test_comments.py | 23 +++++++++++++++++++---- yamllint/rules/comments.py | 5 ++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/tests/rules/test_comments.py b/tests/rules/test_comments.py index 742650b..ad18a0e 100644 --- a/tests/rules/test_comments.py +++ b/tests/rules/test_comments.py @@ -84,28 +84,43 @@ class CommentsTestCase(RuleTestCase): conf = ('comments:\n' ' require-starting-space: true\n' ' ignore-shebangs: false\n' - 'comments-indentation: disable\n') + 'comments-indentation: disable\n' + 'document-start: disable\n') self.check('#!/bin/env my-interpreter\n', conf, problem1=(1, 2)) + self.check('# comment\n' + '#!/bin/env my-interpreter\n', conf, + problem1=(2, 2)) self.check('#!/bin/env my-interpreter\n' '---\n' '#comment\n' '#!/bin/env my-interpreter\n' '', conf, problem1=(1, 2), problem2=(3, 2), problem3=(4, 2)) + self.check('#! not a shebang\n', + conf, problem1=(1, 2)) + self.check('key: #!/not/a/shebang\n', + conf, problem1=(1, 8)) def test_ignore_shebang(self): conf = ('comments:\n' ' require-starting-space: true\n' ' ignore-shebangs: true\n' - 'comments-indentation: disable\n') + 'comments-indentation: disable\n' + 'document-start: disable\n') self.check('#!/bin/env my-interpreter\n', conf) + self.check('# comment\n' + '#!/bin/env my-interpreter\n', conf, + problem1=(2, 2)) self.check('#!/bin/env my-interpreter\n' '---\n' '#comment\n' - '#!/bin/env my-interpreter\n' - '', conf, + '#!/bin/env my-interpreter\n', conf, problem2=(3, 2), problem3=(4, 2)) + self.check('#! not a shebang\n', + conf, problem1=(1, 2)) + self.check('key: #!/not/a/shebang\n', + conf, problem1=(1, 8)) def test_spaces_from_content(self): conf = ('comments:\n' diff --git a/yamllint/rules/comments.py b/yamllint/rules/comments.py index 4777d02..0122838 100644 --- a/yamllint/rules/comments.py +++ b/yamllint/rules/comments.py @@ -64,6 +64,8 @@ Use this rule to control the position and formatting of comments. """ +import re + from yamllint.linter import LintProblem @@ -92,7 +94,8 @@ def check(conf, comment): if text_start < len(comment.buffer): if (conf['ignore-shebangs'] and comment.line_no == 1 and - comment.buffer[text_start] == '!'): + comment.column_no == 1 and + re.match(r'^!\S', comment.buffer[text_start:])): return elif comment.buffer[text_start] not in (' ', '\n', '\0'): column = comment.column_no + text_start - comment.pointer From 16b939958d3cbfa168957a03dc82e50f9cd566e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Verg=C3=A9?= Date: Mon, 14 Jan 2019 09:47:07 +0100 Subject: [PATCH 17/17] yamllint version 1.14.0 --- CHANGELOG.rst | 9 +++++++++ yamllint/__init__.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6008deb..5b7de4c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,15 @@ Changelog ========= +1.14.0 (2019-01-14) +------------------- + +- Fix documentation code snippets +- Drop Python 2.6 and 3.3 support, add Python 3.7 support +- Update documentation and tests for ``line-length`` + Unicode + Python 2 +- Allow rule configurations to lack options +- Add a new ``ignore-shebangs`` option for the ``comments`` rule + 1.13.0 (2018-11-14) ------------------- diff --git a/yamllint/__init__.py b/yamllint/__init__.py index ba6780a..3c200a7 100644 --- a/yamllint/__init__.py +++ b/yamllint/__init__.py @@ -22,7 +22,7 @@ indentation, etc.""" APP_NAME = 'yamllint' -APP_VERSION = '1.13.0' +APP_VERSION = '1.14.0' APP_DESCRIPTION = __doc__ __author__ = u'Adrien Vergé'