Merge branch 'master' into master

pull/262/head
Sorin Sbarnea 3 years ago committed by GitHub
commit dd09ea250d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,52 @@
---
name: CI
on: # yamllint disable-line rule:truthy
push:
pull_request:
branches:
- master
jobs:
lint:
name: Linters
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
- run: python -m pip install flake8 flake8-import-order doc8 sphinx
- run: python -m pip install .
- run: flake8 .
- run: doc8 $(git ls-files '*.rst')
- run: yamllint --strict $(git ls-files '*.yaml' '*.yml')
- run: python setup.py build_sphinx
test:
name: Tests
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version:
- '3.6'
- '3.7'
- '3.8'
- '3.9'
- '3.10'
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Append GitHub Actions system path
run: echo "$HOME/.local/bin" >> $GITHUB_PATH
- run: pip install coveralls
- run: pip install .
- run: coverage run --source=yamllint -m unittest discover
- name: Coveralls
uses: AndreMiras/coveralls-python-action@develop

@ -1,28 +0,0 @@
---
dist: xenial # required for Python >= 3.7 (travis-ci/travis-ci#9069)
language: python
python:
- 2.7
- 3.5
- 3.6
- 3.7
- 3.8
- nightly
env:
- REMOVE_LOCALES=false
- REMOVE_LOCALES=true
install:
- pip install pyyaml coveralls flake8 flake8-import-order doc8
- if [[ $TRAVIS_PYTHON_VERSION != 2* ]]; then pip install sphinx; fi
- pip install .
- if [[ $REMOVE_LOCALES = "true" ]]; then sudo rm -rf /usr/lib/locale/*; fi
script:
- 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 -m unittest discover
- if [[ $TRAVIS_PYTHON_VERSION != 2* ]]; then
python setup.py build_sphinx;
fi
after_success:
coveralls

@ -1,6 +1,32 @@
Changelog
=========
1.26.3 (2021-08-21)
-------------------
- Restore runtime dependency ``setuptools`` for Python < 3.8
1.26.2 (2021-08-03)
-------------------
- Fix ``python_requires`` to comply with PEP 345 and PEP 440
1.26.1 (2021-04-06)
-------------------
- Remove runtime dependency ``setuptools`` for Python < 3.8
- Fix ``line_length`` to skip all hash signs starting comment
1.26.0 (2021-01-29)
-------------------
- End support for Python 2 and Python 3.4, add support for Python 3.9
- Add ``forbid: non-empty`` option to ``braces`` and ``brackets`` rules
- Fix ``quoted-strings`` for explicit octal recognition
- Add documentation for integration with Arcanist
- Fix typos in changelog and README
- Stop using deprecated ``python setup.py test`` in tests
1.25.0 (2020-09-29)
-------------------

@ -42,5 +42,7 @@ Pull Request Process
6. Write a `good commit message
<http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html>`_.
If the pull request has multiple commits, each must be atomic (single
irreducible change that makes sense on its own).
7. Then, open a pull request.

@ -19,11 +19,7 @@ indentation, etc.
:target: https://yamllint.readthedocs.io/en/latest/?badge=latest
:alt: Documentation status
Written in Python (compatible with Python 2 & 3).
⚠ Python 2 upstream support stopped on January 1, 2020. yamllint will keep
best-effort support for Python 2.7 until January 1, 2021. Past that date,
yamllint will drop all Python 2-related code.
Written in Python (compatible with Python 3 only).
Documentation
-------------

@ -39,7 +39,7 @@ htmlhelp_basename = 'yamllintdoc'
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'yamllint', '', [u'Adrien Vergé'], 1)
('index', 'yamllint', 'Linter for YAML files', [u'Adrien Vergé'], 1)
]
# -- Build with sphinx automodule without needing to install third-party libs

@ -14,11 +14,11 @@ To use a custom configuration file, use the ``-c`` option:
If ``-c`` is not provided, yamllint will look for a configuration file in the
following locations (by order of preference):
- ``.yamllint``, ``.yamllint.yaml`` or ``.yamllint.yml`` in the current working
directory
- the file referenced by ``$YAMLLINT_CONFIG_FILE``, if set
- ``$XDG_CONFIG_HOME/yamllint/config``
- ``~/.config/yamllint/config``
- a file named ``.yamllint``, ``.yamllint.yaml``, or ``.yamllint.yml`` in the
current working directory
- a filename referenced by ``$YAMLLINT_CONFIG_FILE``, if set
- a file named ``$XDG_CONFIG_HOME/yamllint/config`` or
``~/.config/yamllint/config``, if present
Finally if no config file is found, the default configuration is applied.

@ -22,9 +22,9 @@ Integration with GitHub Actions
-------------------------------
yamllint auto-detects when it's running inside of `GitHub
Actions<https://github.com/features/actions>` and automatically uses the suited
output format to decorate code with linting errors automatically. You can also
force the GitHub Actions output with ``yamllint --format github``.
Actions <https://github.com/features/actions>`_ and automatically uses the suited
output format to decorate code with linting errors. You can also force the
GitHub Actions output with ``yamllint --format github``.
An example workflow using GitHub Actions:
@ -51,3 +51,22 @@ An example workflow using GitHub Actions:
- name: Lint YAML files
run: yamllint .
Integration with Arcanist
-------------------------
You can configure yamllint to run on ``arc lint``. Here is an example
``.arclint`` file that makes use of this configuration.
.. code:: json
{
"linters": {
"yamllint": {
"type": "script-and-regex",
"script-and-regex.script": "yamllint",
"script-and-regex.regex": "/^(?P<line>\\d+):(?P<offset>\\d+) +(?P<severity>warning|error) +(?P<message>.*) +\\((?P<name>.*)\\)$/m",
"include": "(\\.(yml|yaml)$)"
}
}
}

@ -26,14 +26,12 @@ classifiers =
Environment :: Console
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
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Topic :: Software Development
Topic :: Software Development :: Debuggers
Topic :: Software Development :: Quality Assurance
@ -48,7 +46,7 @@ project_urls =
[options]
packages = find:
python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
python_requires = >=3.6
include_package_data = True
install_requires =
@ -69,3 +67,6 @@ yamllint = conf/*.yaml
[options.entry_points]
console_scripts =
yamllint = yamllint.cli:run
[coverage:run]
relative_files = True

@ -61,6 +61,30 @@ class ColonTestCase(RuleTestCase):
' a: 1\n'
'}\n', conf, problem=(2, 8))
conf = ('braces:\n'
' forbid: non-empty\n')
self.check('---\n'
'dict:\n'
' a: 1\n', conf)
self.check('---\n'
'dict: {}\n', conf)
self.check('---\n'
'dict: {\n'
'}\n', conf)
self.check('---\n'
'dict: {\n'
'# commented: value\n'
'# another: value2\n'
'}\n', conf)
self.check('---\n'
'dict: {a}\n', conf, problem=(2, 8))
self.check('---\n'
'dict: {a: 1}\n', conf, problem=(2, 8))
self.check('---\n'
'dict: {\n'
' a: 1\n'
'}\n', conf, problem=(2, 8))
def test_min_spaces(self):
conf = ('braces:\n'
' max-spaces-inside: -1\n'

@ -60,6 +60,29 @@ class ColonTestCase(RuleTestCase):
' b\n'
']\n', conf, problem=(2, 9))
conf = ('brackets:\n'
' forbid: non-empty\n')
self.check('---\n'
'array:\n'
' - a\n'
' - b\n', conf)
self.check('---\n'
'array: []\n', conf)
self.check('---\n'
'array: [\n\n'
']\n', conf)
self.check('---\n'
'array: [\n'
'# a comment\n'
']\n', conf)
self.check('---\n'
'array: [a, b]\n', conf, problem=(2, 9))
self.check('---\n'
'array: [\n'
' a,\n'
' b\n'
']\n', conf, problem=(2, 9))
def test_min_spaces(self):
conf = ('brackets:\n'
' max-spaces-inside: -1\n'

@ -97,7 +97,7 @@ class CommentsTestCase(RuleTestCase):
'#!/bin/env my-interpreter\n'
'', conf,
problem1=(1, 2), problem2=(3, 2), problem3=(4, 2))
self.check('#! not a shebang\n',
self.check('#! is a valid shebang too\n',
conf, problem1=(1, 2))
self.check('key: #!/not/a/shebang\n',
conf, problem1=(1, 8))
@ -117,8 +117,7 @@ class CommentsTestCase(RuleTestCase):
'#comment\n'
'#!/bin/env my-interpreter\n', conf,
problem2=(3, 2), problem3=(4, 2))
self.check('#! not a shebang\n',
conf, problem1=(1, 2))
self.check('#! is a valid shebang too\n', conf)
self.check('key: #!/not/a/shebang\n',
conf, problem1=(1, 8))

@ -14,9 +14,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import unittest
from tests.common import RuleTestCase
@ -119,6 +116,27 @@ class LineLengthTestCase(RuleTestCase):
'long_line: http://localhost/very/very/long/url\n'
'...\n', conf, problem=(2, 21))
conf = 'line-length: {max: 20, allow-non-breakable-words: true}'
self.check('---\n'
'# http://www.verylongurlurlurlurlurlurlurlurl.com\n'
'key:\n'
' subkey: value\n', conf)
self.check('---\n'
'## http://www.verylongurlurlurlurlurlurlurlurl.com\n'
'key:\n'
' subkey: value\n', conf)
self.check('---\n'
'# # http://www.verylongurlurlurlurlurlurlurlurl.com\n'
'key:\n'
' subkey: value\n', conf,
problem=(2, 21))
self.check('---\n'
'#A http://www.verylongurlurlurlurlurlurlurlurl.com\n'
'key:\n'
' subkey: value\n', conf,
problem1=(2, 2, 'comments'),
problem2=(2, 21, 'line-length'))
conf = ('line-length: {max: 20, allow-non-breakable-words: true}\n'
'trailing-spaces: disable')
self.check('---\n'
@ -159,18 +177,17 @@ class LineLengthTestCase(RuleTestCase):
' {% 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',
'with: “unicode characters” that span across bytes! ↺\n',
conf)
conf = 'line-length: {max: 52}'
conf = 'line-length: {max: 51}'
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))
'with: “unicode characters” that span across bytes! ↺\n',
conf, problem1=(2, 52), problem2=(3, 52))
def test_with_dos_newlines(self):
conf = ('line-length: {max: 10}\n'

@ -436,3 +436,21 @@ class QuotedTestCase(RuleTestCase):
'- foo bar\n'
'- "foo bar"\n',
conf, problem1=(3, 3), problem2=(7, 3), problem3=(11, 3))
def test_octal_values(self):
conf = 'quoted-strings: {required: true}\n'
self.check('---\n'
'- 100\n'
'- 0100\n'
'- 0o100\n'
'- 777\n'
'- 0777\n'
'- 0o777\n'
'- 800\n'
'- 0800\n'
'- 0o800\n'
'- "0800"\n'
'- "0o800"\n',
conf,
problem1=(9, 3), problem2=(10, 3))

@ -14,10 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
from io import StringIO
import fcntl
import locale
import os
@ -246,19 +243,19 @@ class CommandLineTestCase(unittest.TestCase):
cli.run(())
self.assertNotEqual(ctx.returncode, 0)
self.assertEqual(ctx.stdout, '')
self.assertRegexpMatches(ctx.stderr, r'^usage')
self.assertRegex(ctx.stderr, r'^usage')
with RunContext(self) as ctx:
cli.run(('--unknown-arg', ))
self.assertNotEqual(ctx.returncode, 0)
self.assertEqual(ctx.stdout, '')
self.assertRegexpMatches(ctx.stderr, r'^usage')
self.assertRegex(ctx.stderr, r'^usage')
with RunContext(self) as ctx:
cli.run(('-c', './conf.yaml', '-d', 'relaxed', 'file'))
self.assertNotEqual(ctx.returncode, 0)
self.assertEqual(ctx.stdout, '')
self.assertRegexpMatches(
self.assertRegex(
ctx.stderr.splitlines()[-1],
r'^yamllint: error: argument -d\/--config-data: '
r'not allowed with argument -c\/--config-file$'
@ -269,21 +266,21 @@ class CommandLineTestCase(unittest.TestCase):
cli.run(('-', 'file'))
self.assertNotEqual(ctx.returncode, 0)
self.assertEqual(ctx.stdout, '')
self.assertRegexpMatches(ctx.stderr, r'^usage')
self.assertRegex(ctx.stderr, r'^usage')
def test_run_with_bad_config(self):
with RunContext(self) as ctx:
cli.run(('-d', 'rules: {a: b}', 'file'))
self.assertEqual(ctx.returncode, -1)
self.assertEqual(ctx.stdout, '')
self.assertRegexpMatches(ctx.stderr, r'^invalid config: no such rule')
self.assertRegex(ctx.stderr, r'^invalid config: no such rule')
def test_run_with_empty_config(self):
with RunContext(self) as ctx:
cli.run(('-d', '', 'file'))
self.assertEqual(ctx.returncode, -1)
self.assertEqual(ctx.stdout, '')
self.assertRegexpMatches(ctx.stderr, r'^invalid config: not a dict')
self.assertRegex(ctx.stderr, r'^invalid config: not a dict')
def test_run_with_config_file(self):
with open(os.path.join(self.wd, 'config'), 'w') as f:
@ -300,6 +297,7 @@ class CommandLineTestCase(unittest.TestCase):
cli.run(('-c', f.name, os.path.join(self.wd, 'a.yaml')))
self.assertEqual(ctx.returncode, 1)
@unittest.skipIf(os.environ.get('GITHUB_RUN_ID'), '$HOME not overridable')
def test_run_with_user_global_config_file(self):
home = os.path.join(self.wd, 'fake-home')
dir = os.path.join(home, '.config', 'yamllint')
@ -386,7 +384,7 @@ class CommandLineTestCase(unittest.TestCase):
with RunContext(self) as ctx:
cli.run(('--version', ))
self.assertEqual(ctx.returncode, 0)
self.assertRegexpMatches(ctx.stdout + ctx.stderr, r'yamllint \d+\.\d+')
self.assertRegex(ctx.stdout + ctx.stderr, r'yamllint \d+\.\d+')
def test_run_non_existing_file(self):
path = os.path.join(self.wd, 'i-do-not-exist.yaml')
@ -395,7 +393,7 @@ class CommandLineTestCase(unittest.TestCase):
cli.run(('-f', 'parsable', path))
self.assertEqual(ctx.returncode, -1)
self.assertEqual(ctx.stdout, '')
self.assertRegexpMatches(ctx.stderr, r'No such file or directory')
self.assertRegex(ctx.stderr, r'No such file or directory')
def test_run_one_problem_file(self):
path = os.path.join(self.wd, 'a.yaml')
@ -555,11 +553,13 @@ class CommandLineTestCase(unittest.TestCase):
with RunContext(self) as ctx:
cli.run((path, '--format', 'github'))
expected_out = (
'::error file=%s,line=2,col=4::[trailing-spaces] trailing'
'::group::%s\n'
'::error file=%s,line=2,col=4::2:4 [trailing-spaces] trailing'
' spaces\n'
'::error file=%s,line=3,col=4::[new-line-at-end-of-file] no'
'::error file=%s,line=3,col=4::3:4 [new-line-at-end-of-file] no'
' new line character at the end of file\n'
% (path, path))
'::endgroup::\n\n'
% (path, path, path))
self.assertEqual(
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
@ -573,11 +573,13 @@ class CommandLineTestCase(unittest.TestCase):
os.environ['GITHUB_WORKFLOW'] = 'something'
cli.run((path, ))
expected_out = (
'::error file=%s,line=2,col=4::[trailing-spaces] trailing'
'::group::%s\n'
'::error file=%s,line=2,col=4::2:4 [trailing-spaces] trailing'
' spaces\n'
'::error file=%s,line=3,col=4::[new-line-at-end-of-file] no'
'::error file=%s,line=3,col=4::3:4 [new-line-at-end-of-file] no'
' new line character at the end of file\n'
% (path, path))
'::endgroup::\n\n'
% (path, path, path))
self.assertEqual(
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))

@ -14,10 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
from io import StringIO
import os
import shutil
import sys
@ -48,7 +45,7 @@ class SimpleConfigTestCase(unittest.TestCase):
config.YamlLintConfig('not: valid: yaml')
def test_unknown_rule(self):
with self.assertRaisesRegexp(
with self.assertRaisesRegex(
config.YamlLintConfigError,
'invalid config: no such rule: "this-one-does-not-exist"'):
config.YamlLintConfig('rules:\n'
@ -67,7 +64,7 @@ class SimpleConfigTestCase(unittest.TestCase):
self.assertEqual(c.rules['colons']['max-spaces-after'], 1)
def test_unknown_option(self):
with self.assertRaisesRegexp(
with self.assertRaisesRegex(
config.YamlLintConfigError,
'invalid config: unknown option "abcdef" for rule "colons"'):
config.YamlLintConfig('rules:\n'
@ -105,7 +102,7 @@ class SimpleConfigTestCase(unittest.TestCase):
self.assertEqual(c.rules['indentation']['check-multi-line-strings'],
False)
with self.assertRaisesRegexp(
with self.assertRaisesRegex(
config.YamlLintConfigError,
'invalid config: option "indent-sequences" of "indentation" '
'should be in '):

@ -47,16 +47,15 @@ class ModuleTestCase(unittest.TestCase):
subprocess.check_output([PYTHON, '-m', 'yamllint'],
stderr=subprocess.STDOUT)
self.assertEqual(ctx.exception.returncode, 2)
self.assertRegexpMatches(ctx.exception.output.decode(),
r'^usage: yamllint')
self.assertRegex(ctx.exception.output.decode(), r'^usage: yamllint')
def test_run_module_on_bad_dir(self):
with self.assertRaises(subprocess.CalledProcessError) as ctx:
subprocess.check_output([PYTHON, '-m', 'yamllint',
'/does/not/exist'],
stderr=subprocess.STDOUT)
self.assertRegexpMatches(ctx.exception.output.decode(),
r'No such file or directory')
self.assertRegex(ctx.exception.output.decode(),
r'No such file or directory')
def test_run_module_on_file(self):
out = subprocess.check_output(

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

@ -93,6 +93,10 @@ class Format(object):
line += 'line=' + format(problem.line) + ','
line += 'col=' + format(problem.column)
line += '::'
line += format(problem.line)
line += ':'
line += format(problem.column)
line += ' '
if problem.rule:
line += '[' + problem.rule + '] '
line += problem.desc
@ -103,18 +107,25 @@ def show_problems(problems, file, args_format, no_warn):
max_level = 0
first = True
if args_format == 'auto':
if ('GITHUB_ACTIONS' in os.environ and
'GITHUB_WORKFLOW' in os.environ):
args_format = 'github'
elif supports_color():
args_format = 'colored'
for problem in problems:
max_level = max(max_level, PROBLEM_LEVELS[problem.level])
if no_warn and (problem.level != 'error'):
continue
if args_format == 'parsable':
print(Format.parsable(problem, file))
elif args_format == 'github' or (args_format == 'auto' and
'GITHUB_ACTIONS' in os.environ and
'GITHUB_WORKFLOW' in os.environ):
elif args_format == 'github':
if first:
print('::group::%s' % file)
first = False
print(Format.github(problem, file))
elif args_format == 'colored' or \
(args_format == 'auto' and supports_color()):
elif args_format == 'colored':
if first:
print('\033[4m%s\033[0m' % file)
first = False
@ -125,6 +136,9 @@ def show_problems(problems, file, args_format, no_warn):
first = False
print(Format.standard(problem, file))
if not first and args_format == 'github':
print('::endgroup::')
if not first and args_format != 'parsable':
print('')

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

@ -22,7 +22,8 @@ braces (``{`` and ``}``).
* ``forbid`` is used to forbid the use of flow mappings which are denoted by
surrounding braces (``{`` and ``}``). Use ``true`` to forbid the use of flow
mappings completely.
mappings completely. Use ``non-empty`` to forbid the use of all flow
mappings except for empty ones.
* ``min-spaces-inside`` defines the minimal number of spaces required inside
braces.
* ``max-spaces-inside`` defines the maximal number of spaces allowed inside
@ -60,6 +61,18 @@ braces (``{`` and ``}``).
object: { key1: 4, key2: 8 }
#. With ``braces: {forbid: non-empty}``
the following code snippet would **PASS**:
::
object: {}
the following code snippet would **FAIL**:
::
object: { key1: 4, key2: 8 }
#. With ``braces: {min-spaces-inside: 0, max-spaces-inside: 0}``
the following code snippet would **PASS**:
@ -128,7 +141,7 @@ from yamllint.rules.common import spaces_after, spaces_before
ID = 'braces'
TYPE = 'token'
CONF = {'forbid': bool,
CONF = {'forbid': (bool, 'non-empty'),
'min-spaces-inside': int,
'max-spaces-inside': int,
'min-spaces-inside-empty': int,
@ -141,7 +154,15 @@ DEFAULT = {'forbid': False,
def check(conf, token, prev, next, nextnext, context):
if conf['forbid'] and isinstance(token, yaml.FlowMappingStartToken):
if (conf['forbid'] is True and
isinstance(token, yaml.FlowMappingStartToken)):
yield LintProblem(token.start_mark.line + 1,
token.end_mark.column + 1,
'forbidden flow mapping')
elif (conf['forbid'] == 'non-empty' and
isinstance(token, yaml.FlowMappingStartToken) and
not isinstance(next, yaml.FlowMappingEndToken)):
yield LintProblem(token.start_mark.line + 1,
token.end_mark.column + 1,
'forbidden flow mapping')

@ -22,7 +22,8 @@ inside brackets (``[`` and ``]``).
* ``forbid`` is used to forbid the use of flow sequences which are denoted by
surrounding brackets (``[`` and ``]``). Use ``true`` to forbid the use of
flow sequences completely.
flow sequences completely. Use ``non-empty`` to forbid the use of all flow
sequences except for empty ones.
* ``min-spaces-inside`` defines the minimal number of spaces required inside
brackets.
* ``max-spaces-inside`` defines the maximal number of spaces allowed inside
@ -61,6 +62,18 @@ inside brackets (``[`` and ``]``).
object: [ 1, 2, abc ]
#. With ``brackets: {forbid: non-empty}``
the following code snippet would **PASS**:
::
object: []
the following code snippet would **FAIL**:
::
object: [ 1, 2, abc ]
#. With ``brackets: {min-spaces-inside: 0, max-spaces-inside: 0}``
the following code snippet would **PASS**:
@ -129,7 +142,7 @@ from yamllint.rules.common import spaces_after, spaces_before
ID = 'brackets'
TYPE = 'token'
CONF = {'forbid': bool,
CONF = {'forbid': (bool, 'non-empty'),
'min-spaces-inside': int,
'max-spaces-inside': int,
'min-spaces-inside-empty': int,
@ -142,7 +155,15 @@ DEFAULT = {'forbid': False,
def check(conf, token, prev, next, nextnext, context):
if conf['forbid'] and isinstance(token, yaml.FlowSequenceStartToken):
if (conf['forbid'] is True and
isinstance(token, yaml.FlowSequenceStartToken)):
yield LintProblem(token.start_mark.line + 1,
token.end_mark.column + 1,
'forbidden flow sequence')
elif (conf['forbid'] == 'non-empty' and
isinstance(token, yaml.FlowSequenceStartToken) and
not isinstance(next, yaml.FlowSequenceEndToken)):
yield LintProblem(token.start_mark.line + 1,
token.end_mark.column + 1,
'forbidden flow sequence')

@ -74,8 +74,6 @@ Use this rule to control the position and formatting of comments.
"""
import re
from yamllint.linter import LintProblem
@ -105,7 +103,7 @@ def check(conf, comment):
if (conf['ignore-shebangs'] and
comment.line_no == 1 and
comment.column_no == 1 and
re.match(r'^!\S', comment.buffer[text_start:])):
comment.buffer[text_start] == '!'):
return
# We can test for both \r and \r\n just by checking first char
# \r itself is a valid newline on some older OS.

@ -18,8 +18,8 @@
Use this rule to enforce alphabetical ordering of keys in mappings. The sorting
order uses the Unicode code point number as a default. As a result, the
ordering is case-sensitive and not accent-friendly (see examples below).
This can be changed by setting the global ``locale`` option. This allows to
sort case and accents properly.
This can be changed by setting the global ``locale`` option. This allows one
to sort case and accents properly.
.. rubric:: Examples

@ -17,10 +17,6 @@
"""
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.
@ -144,7 +140,11 @@ def check(conf, line):
start += 1
if start != line.end:
if line.buffer[start] in ('#', '-'):
if line.buffer[start] == '#':
while line.buffer[start] == '#':
start += 1
start += 1
elif line.buffer[start] == '-':
start += 2
if line.buffer.find(' ', start, line.end) == -1:

@ -144,6 +144,17 @@ def VALIDATE(conf):
DEFAULT_SCALAR_TAG = u'tag:yaml.org,2002:str'
# https://stackoverflow.com/a/36514274
yaml.resolver.Resolver.add_implicit_resolver(
'tag:yaml.org,2002:int',
re.compile(r'''^(?:[-+]?0b[0-1_]+
|[-+]?0o?[0-7_]+
|[-+]?0[0-7_]+
|[-+]?(?:0|[1-9][0-9_]*)
|[-+]?0x[0-9a-fA-F_]+
|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$''', re.X),
list('-+0123456789'))
def _quote_match(quote_type, token_style):
return ((quote_type == 'any') or

Loading…
Cancel
Save