Compare commits

..

47 Commits

Author SHA1 Message Date
Adrien Vergé
9cce294041 yamllint version 1.28.0 2022-09-12 14:37:48 +02:00
andrewnaguib
2f8ad7003a config: Implement for ignore-from-file option
Closes https://github.com/adrienverge/yamllint/issues/360
Co-authored-by: Adrien Vergé <@adrienverge>
2022-08-10 08:35:40 +02:00
Roman Geraskin
fb0c0a5247 quoted-strings: fix docs example 2022-08-07 20:13:48 +02:00
Roman Geraskin
352e1a975e quoted-strings: Add allow-quoted-quotes option
Allows strings like `'foo"bar'` on `quote-type: double` and vice versa.
2022-08-07 13:47:35 +02:00
Dimitri Papadopoulos
e319a17344 octal values: simpler test for match objects
From the Python 3 documentation:
	Match objects always have a boolean value of True.
	Since match() and search() return None when there is no match,
	you can test whether there was a match with a simple if statement:
		match = re.search(pattern, string)
		if match:
		    process(match)
2022-08-06 15:23:23 +02:00
Dimitri Papadopoulos
6b6fdba3bf linter: pre-compile disable/enable rules regexes
Not only this should improve performance, but I find the code more
readable.
2022-08-06 15:23:23 +02:00
Dimitri Papadopoulos Orfanos
868350681a License: Update to latest version of GPLv3
http:// → https://
2022-08-06 15:14:57 +02:00
Andrew Imeson
94c1c2bcf2 docs: Update ALE vim plugin link 2022-08-05 18:57:21 +02:00
Andrew Imeson
0130e15c8c docs: Simplify GitHub Actions example 2022-08-05 18:57:21 +02:00
Dimitri Papadopoulos
ae3158cd1f No need to inherit from object in Python 3 2022-08-05 08:49:56 +02:00
Dimitri Papadopoulos
4c7b47daf3 Most __future__ imports are specific to Python 2 2022-08-05 08:49:56 +02:00
Dimitri Papadopoulos Orfanos
3346843edc docs: Better compress PNG image 2022-08-05 08:43:55 +02:00
Dimitri Papadopoulos Orfanos
ea70520216 Changelog: Fix typo found by codespell 2022-08-05 08:42:10 +02:00
Adrien Vergé
a09ad89268 yamllint version 1.27.1 2022-07-08 18:06:54 +02:00
Adrien Vergé
8d543a4b9c key-duplicates: Fix failing test for missing space after colon
Commit c268a82 "key-duplicates: Don't crash on redundant closing
brackets or braces" fixed a problem but introduced another one: it
crashes on systems with (I guess) an old version of PyYAML. This is
probably linked to the "Allow colon in a plain scalar in a flow context"
issue on PyYAML [1].
For example, this problem happens on CentOS 8:

    FAIL: test_disabled (tests.rules.test_key_duplicates.KeyDuplicatesTestCase)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "…/tests/rules/test_key_duplicates.py", line 90, in test_disabled
        '{a:1, b:2}}\n', conf, problem=(2, 11, 'syntax'))
      File "…/tests/common.py", line 54, in check
        self.assertEqual(real_problems, expected_problems)
    AssertionError: Lists differ: …
    - [2:3: syntax error: found unexpected ':' (syntax)]
    + [2:11: <no description>]

I propose to simply fix the *space following a colon* problem, since
it's not related to what the original author @tamere-allo-peter tried to
fix.

[1]: https://github.com/yaml/pyyaml/pull/45
2022-07-08 18:05:21 +02:00
Adrien Vergé
8a364e2fde yamllint version 1.27.0 2022-07-08 17:32:19 +02:00
Adrien Vergé
dc2d0991e0 float-values: Refactor tests to be less verbose
The goal is to be more concise thus more readable, as well as consistent
with most other tests.
2022-07-08 17:21:22 +02:00
Adrien Vergé
e6af957131 float-values: Add missing quotes in problems messages
To be consistent with other existing messages, e.g.:
- forbidden not a number value ".NaN"
- found forbidden document start "---"
- missing document start "---"
- truthy value should be one of ["true"]
- forbidden implicit octal value "0777"
2022-07-08 17:21:22 +02:00
Derek Brown
8ac7d58693 float-values: Add a new rule to check floating-point numbers 2022-07-08 17:21:22 +02:00
Andrew Imeson
40cab7f999 docs: Bump application copyright year 2022-06-24 17:15:21 +02:00
Andrew Imeson
34a4f76e8b docs: Remove repeated word 'copyright'
Fixes #476 - credit to @chrillep and @adrienverge
2022-06-24 17:15:21 +02:00
Jan Wille
7d9c824b83 new-lines: add type: platform config option
The new option infers the correct newline character(s) from the
operating system running yamllint.
2022-06-23 08:19:30 +02:00
Jan Wille
157b06871d new-lines: refactor to reduce duplicate code
Both options where using identical code.  Now the newline character
is determined beforehand depending on the selected option and then
the same code can be used for all options
2022-06-23 08:19:30 +02:00
Jan Wille
af843b675a new-lines: explicitly check \n for type: unix
To be more consistent with the other types, unix now also checks against
the expected newline character (`\n`) instead of checking if a wrong
character (`\r`) is present
2022-06-23 08:19:30 +02:00
Christian Widlund
695fc5f1f1 docs: Add plugin section for Visual Studio Code 2022-06-22 18:12:56 +02:00
Christian Widlund
632665c3e6 docs: Add plugin section for IntelliJ 2022-06-20 14:47:43 +02:00
Derek Brown
5658cf7f42 octal-values: Pre-compile regex for performance 2022-06-11 12:03:44 +02:00
Matt Clay
bdbec7dc4d linter: Remove redundant conditional
Remove the redundant conditional used when reporting a syntax error
at the same location as a cosmetic problem. Also reword the comment
explaining the logic to more accurately describe the situation.

This eliminates an unreachable `syntax_error = None` assignment.
2022-06-10 11:19:59 +02:00
Matt Clay
9700525496 linter: Remove unreachable exception handler
Remove two `try/except UnicodeError` exception handlers which were
added in commit c8ba8f7e99 for
Python 2.x compatibility. Now that Python 2.x is no longer
supported, the `except` is unreachable and is no longer needed.
2022-06-10 08:39:50 +02:00
Matt Clay
327f92e472 tests: Increase test coverage
- Add a `temp_workspace` context manager to simplify writing new tests.
- Add `# pragma: no cover` to unit test code paths used for skipping tests.
  These code paths are only covered when tests are skipped.
  That makes it impractical to reach full code coverage on the unit test code.
  Having full coverage of unit tests is helpful for identifying unused tests.
- Test the `octal-values` rule with a custom tag.
- Test the cli `-d` option with the `default` config.
- Test support for the `XDG_CONFIG_HOME` env var.
- Test warning message output.
- Test support for `.yamllint.yml` config files.
- Test support for `.yamllint.yaml` config files.
- Test error handling of a rule with a non-enable|disable|dict value.
- Test error handling of `ignore` with a non-pattern value.
- Test error handling of a rule `ignore` with a non-pattern value.
- Test error handling of `locale` with a non-string value.
- Test error handling of `yaml-files` with a non-list value.
- Test extending config containing `ignore`.
- Test `LintProblem.__repr__` without a rule.
- Test `LintProblem.__repr__` with a rule.
2022-06-09 10:03:08 +02:00
Adrien Vergé
89b75b7c05 refactor: Remove UTF-8 headers in Python files
The `# -*- coding: utf-8 -*-` headers were useful for Python 2, and
aren't needed for Python 3 where UTF-8 is the default.

yamllint support of Python 2 was dropped in early 2021, see commit
a3fc64d "End support for Python 2".

Let's drop these headers.
2022-06-09 09:40:06 +02:00
Andrew Imeson
e49a101160 Add rstcheck to CI to lint docs 2022-06-08 09:21:44 +02:00
Jérôme Alet
c268a82c5a key-duplicates: Don't crash on redundant closing brackets or braces
Don't break on empty `context` stack when invalid YAML:

    [ a, b, c ] ]
    {a: 1, b: 2} }
2022-04-20 11:00:08 +02:00
Andrew Imeson
2f423117c1 docs: Attempt to clarify configuration file location
Closes #96, Closes #212
2022-03-24 10:23:39 +01:00
Andrew Imeson
f58448cb21 Fix spelling of "across" in test output 2022-03-21 13:48:34 +01:00
Andrew Imeson
7974d518cd Fix grammar in key_ordering docs to make Lintian happy
Fixes part of #76
2022-03-21 13:48:34 +01:00
Andrew Imeson
8a320aaf2c Make man page show up in apropos
Set the 'description' attribute so that Sphinx builds the manpage with
the 'NAME' section. This is necessary for `apropos` to be able to find
yamllint

Fixes part of #76
2022-03-21 13:48:34 +01:00
Andrew Imeson
c34c962691 Remove the repeated word "automatically" in GHA doc 2022-03-21 13:48:34 +01:00
Madison Swain-Bowden
4f1bbc33dc docs: Fix link syntax on integration.rst 2021-12-24 09:34:15 +01:00
Jérôme Alet
bb567ba395 comments: Allow whitespace after the shebang marker
Basically, any character is now allowed after the shebang marker.

Closes #428.

Whitespace after the #! marker on shebang lines is authorized and
optional, as explained on Wikipedia's entry for shebang line as can be
seen from the extracts below :

> White space after #! is optional

and

> It has been claimed[20] that some old versions of Unix expect the
> normal shebang to be followed by a space and a slash (#! /), but this
> appears to be untrue;[21] rather, blanks after the shebang have
> traditionally been allowed, and sometimes documented with a space
2021-12-19 22:02:56 +01:00
Trevor Royer
d0392b34ca github format: Update output to utilize groups
Resolves #421

Update the github formatting to utilize groups in the output and provide
the line/column number for the error in the output log.
2021-12-01 08:52:59 +01:00
Trevor Royer
7246a0c800 cli: Separate --format=auto logic
Moved the auto arg_format selection out of the main if block into a
separate logic section to improve readability.

No logic changes.
2021-11-24 14:38:26 +01:00
Dmytro Bondar
9e6dfacceb Fix github actions workflow
- install correct python version
- set `fail-fast: false` to run all jobs
- remove hard-coded value for HOME directory
2021-11-17 16:43:46 +01:00
Dmytro Bondar
11e8d8ff37 Add support for Python 3.10, drop Python 3.5
- Add support for Python 3.10 released on 2021-10-04
- Drop support for Python 3.5 since it has reached end-of-life
2021-11-17 16:43:46 +01:00
Adrien Vergé
f2e2e0c366 docs: Update CONTRIBUTING.rst
Be more precise in contributing instructions.
2021-10-20 09:40:59 +02:00
Adrien Vergé
058fef7559 yamllint version 1.26.3 2021-08-21 19:26:15 +02:00
Adrien Vergé
f47d5318cf Restore setuptools requirement for Python < 3.8
This reverts commit 8f68248 "Remove runtime dep 'setuptools' for Python
< 3.8". It looks like removing setuptools induces problems on some
systems, see for example the linked discussion.

Fixes https://github.com/adrienverge/yamllint/issues/380.
2021-08-21 19:25:27 +02:00
76 changed files with 1017 additions and 208 deletions

View File

@@ -17,12 +17,13 @@ jobs:
uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
- run: python -m pip install flake8 flake8-import-order doc8 sphinx
- run:
python -m pip install flake8 flake8-import-order doc8 sphinx
rstcheck[sphinx]
- run: python -m pip install .
- run: flake8 .
- run: doc8 $(git ls-files '*.rst')
- run: rstcheck --ignore-directives automodule $(git ls-files '*.rst')
- run: yamllint --strict $(git ls-files '*.yaml' '*.yml')
- run: python setup.py build_sphinx
@@ -30,23 +31,23 @@ jobs:
name: Tests
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version:
- 3.5
- 3.6
- 3.7
- 3.8
- 3.9
- nightly
- '3.6'
- '3.7'
- '3.8'
- '3.9'
- '3.10'
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python ${{ matrix.pyver }}
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.pyver }}
- name: Fix GitHub Actions path
run: echo /home/runner/.local/bin >>$GITHUB_PATH
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

View File

@@ -1,6 +1,49 @@
Changelog
=========
1.28.0 (2022-09-12)
-------------------
- Better compress PNG image in documentation
- Remove ``__future__`` imports specific to Python 2
- Remove inheritance from ``object`` specific to Python 2
- Simplify GitHub Actions example in documentation
- Update ALE vim plugin link in documentation
- Update license to latest version of GPLv3
- Pre-compile disable/enable rules regexes
- Rule ``quoted-strings``: add ``allow-quoted-quotes`` option
- Add option ``ignore-from-file`` in config
1.27.1 (2022-07-08)
-------------------
- Fix failing test on ``key-duplicates`` for old PyYAML versions
1.27.0 (2022-07-08)
-------------------
- Add support for Python 3.10, drop Python 3.5
- Fix GitHub Actions workflow
- Refactor ``--format=auto`` logic
- Update GitHub format output to use groups
- Rule ``comments``: allow whitespace after the shebang marker
- Multiple minor fixes in documentation
- Configure Sphinx to make man page show up in apropos
- Attempt to clarify configuration file location in documentation
- Rule ``key-duplicates``: don't crash on redundant closing brackets or braces
- Use ``rstcheck`` to lint documentation on the CI
- Remove UTF-8 headers in Python files, since Python 2 isn't supported
- Add various tests to increase coverage
- Rule ``octal-values``: pre-compile regex for performance
- Add sections for Visual Studio Code and IntelliJ in documentation
- Rule ``new-lines``: add the ``type: platform`` config option
- Add the new rule ``float-values``
1.26.3 (2021-08-21)
-------------------
- Restore runtime dependency ``setuptools`` for Python < 3.8
1.26.2 (2021-08-03)
-------------------

View File

@@ -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.

View File

@@ -1,7 +1,7 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
@@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View File

@@ -74,7 +74,7 @@ Usage
# Output a parsable format (for syntax checking in editors like Vim, emacs...)
yamllint -f parsable file.yaml
`Read more in the complete documentation! <https://yamllint.readthedocs.io/>`_
`Read more in the complete documentation! <https://yamllint.readthedocs.io/>`__
Features
^^^^^^^^
@@ -132,7 +132,7 @@ Specific files can be ignored (totally or for some rules only) using a
*.ignore-trailing-spaces.yaml
/ascii-art/*
`Read more in the complete documentation! <https://yamllint.readthedocs.io/>`_
`Read more in the complete documentation! <https://yamllint.readthedocs.io/>`__
License
-------

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# yamllint documentation build configuration file, created by
# sphinx-quickstart on Thu Jan 21 21:18:52 2016.
@@ -21,7 +20,7 @@ source_suffix = '.rst'
master_doc = 'index'
project = APP_NAME
copyright = __copyright__
copyright = __copyright__.lstrip('Copyright ')
version = APP_VERSION
release = APP_VERSION
@@ -39,7 +38,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

View File

@@ -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.
@@ -190,6 +190,20 @@ Here is a more complex example:
*.ignore-trailing-spaces.yaml
ascii-art/*
You can also use the ``.gitignore`` file (or any list of files) through:
.. code-block:: yaml
ignore-from-file: .gitignore
or:
.. code-block:: yaml
ignore-from-file: [.gitignore, .yamlignore]
.. note:: However, this is mutually exclusive with the ``ignore`` key.
Setting the locale
------------------

View File

@@ -22,29 +22,22 @@ 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:
An minimal example workflow using GitHub Actions:
.. code:: yaml
---
name: yamllint test
on: push
on: push # yamllint disable-line rule:truthy
jobs:
test:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.8
- uses: actions/checkout@v3
- name: Install yamllint
run: pip install yamllint

View File

@@ -64,6 +64,12 @@ empty-values
.. automodule:: yamllint.rules.empty_values
float-values
------------
.. automodule:: yamllint.rules.float_values
hyphens
-------

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -9,7 +9,7 @@ text editor.
Vim
---
Assuming that the `ALE <https://github.com/w0rp/ale>`_ plugin is
Assuming that the `ALE <https://github.com/dense-analysis/ale>`_ plugin is
installed, yamllint is supported by default. It is automatically enabled when
editing YAML files.
@@ -33,6 +33,16 @@ Emacs
If you are `flycheck <https://github.com/flycheck/flycheck>`_ user, you can use
`flycheck-yamllint <https://github.com/krzysztof-magosa/flycheck-yamllint>`_ integration.
Visual Studio Code
------------------
https://marketplace.visualstudio.com/items?itemName=fnando.linter
IntelliJ
--------
https://plugins.jetbrains.com/plugin/15349-yamllint
Other text editors
------------------

View File

@@ -27,11 +27,11 @@ classifiers =
Intended Audience :: Developers
License :: OSI Approved :: GNU General Public License v3 (GPLv3)
Programming Language :: Python :: 3
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
@@ -46,13 +46,13 @@ project_urls =
[options]
packages = find:
python_requires = >=3.5
python_requires = >=3.6
include_package_data = True
install_requires =
pathspec >= 0.5.3
pyyaml
setuptools; python_version < "3.8"
setuptools
test_suite = tests

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -14,7 +13,9 @@
# 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 contextlib
import os
import shutil
import tempfile
import unittest
@@ -69,3 +70,17 @@ def build_temp_workspace(files):
f.write(content)
return tempdir
@contextlib.contextmanager
def temp_workspace(files):
"""Provide a temporary workspace that is automatically cleaned up."""
backup_wd = os.getcwd()
wd = build_temp_workspace(files)
try:
os.chdir(wd)
yield
finally:
os.chdir(backup_wd)
shutil.rmtree(wd)

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -97,7 +96,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 +116,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))

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2017 Greg Dubicki
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -0,0 +1,120 @@
# Copyright (C) 2022 the yamllint contributors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from tests.common import RuleTestCase
class FloatValuesTestCase(RuleTestCase):
rule_id = 'float-values'
def test_disabled(self):
conf = 'float-values: disable\n'
self.check('---\n'
'- 0.0\n'
'- .NaN\n'
'- .INF\n'
'- .1\n'
'- 10e-6\n',
conf)
def test_numeral_before_decimal(self):
conf = (
'float-values:\n'
' require-numeral-before-decimal: true\n'
' forbid-scientific-notation: false\n'
' forbid-nan: false\n'
' forbid-inf: false\n')
self.check('---\n'
'- 0.0\n'
'- .1\n'
'- \'.1\'\n'
'- !custom_tag .2\n'
'- &angle1 0.0\n'
'- *angle1\n'
'- &angle2 .3\n'
'- *angle2\n',
conf,
problem1=(3, 3),
problem2=(8, 11))
def test_scientific_notation(self):
conf = (
'float-values:\n'
' require-numeral-before-decimal: false\n'
' forbid-scientific-notation: true\n'
' forbid-nan: false\n'
' forbid-inf: false\n')
self.check('---\n'
'- 10e6\n'
'- 10e-6\n'
'- 0.00001\n'
'- \'10e-6\'\n'
'- !custom_tag 10e-6\n'
'- &angle1 0.000001\n'
'- *angle1\n'
'- &angle2 10e-6\n'
'- *angle2\n'
'- &angle3 10e6\n'
'- *angle3\n',
conf,
problem1=(2, 3),
problem2=(3, 3),
problem3=(9, 11),
problem4=(11, 11))
def test_nan(self):
conf = (
'float-values:\n'
' require-numeral-before-decimal: false\n'
' forbid-scientific-notation: false\n'
' forbid-nan: true\n'
' forbid-inf: false\n')
self.check('---\n'
'- .NaN\n'
'- .NAN\n'
'- \'.NaN\'\n'
'- !custom_tag .NaN\n'
'- &angle .nan\n'
'- *angle\n',
conf,
problem1=(2, 3),
problem2=(3, 3),
problem3=(6, 10))
def test_inf(self):
conf = (
'float-values:\n'
' require-numeral-before-decimal: false\n'
' forbid-scientific-notation: false\n'
' forbid-nan: false\n'
' forbid-inf: true\n')
self.check('---\n'
'- .inf\n'
'- .INF\n'
'- -.inf\n'
'- -.INF\n'
'- \'.inf\'\n'
'- !custom_tag .inf\n'
'- &angle .inf\n'
'- *angle\n'
'- &angle -.inf\n'
'- *angle\n',
conf,
problem1=(2, 3),
problem2=(3, 3),
problem3=(4, 3),
problem4=(5, 3),
problem5=(8, 10),
problem6=(10, 10))

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -87,6 +86,10 @@ class KeyDuplicatesTestCase(RuleTestCase):
'anchor_reference:\n'
' <<: *anchor_one\n'
' <<: *anchor_two\n', conf)
self.check('---\n'
'{a: 1, b: 2}}\n', conf, problem=(2, 13, 'syntax'))
self.check('---\n'
'[a, b, c]]\n', conf, problem=(2, 10, 'syntax'))
def test_enabled(self):
conf = 'key-duplicates: enable'
@@ -165,6 +168,10 @@ class KeyDuplicatesTestCase(RuleTestCase):
'anchor_reference:\n'
' <<: *anchor_one\n'
' <<: *anchor_two\n', conf)
self.check('---\n'
'{a: 1, b: 2}}\n', conf, problem=(2, 13, 'syntax'))
self.check('---\n'
'[a, b, c]]\n', conf, problem=(2, 10, 'syntax'))
def test_key_tokens_in_flow_sequences(self):
conf = 'key-duplicates: enable'

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2017 Johannes F. Knauf
#
# This program is free software: you can redistribute it and/or modify
@@ -117,7 +116,7 @@ class KeyOrderingTestCase(RuleTestCase):
self.addCleanup(locale.setlocale, locale.LC_ALL, (None, None))
try:
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
except locale.Error:
except locale.Error: # pragma: no cover
self.skipTest('locale en_US.UTF-8 not available')
conf = ('key-ordering: enable')
self.check('---\n'
@@ -136,7 +135,7 @@ class KeyOrderingTestCase(RuleTestCase):
self.addCleanup(locale.setlocale, locale.LC_ALL, (None, None))
try:
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
except locale.Error:
except locale.Error: # pragma: no cover
self.skipTest('locale en_US.UTF-8 not available')
conf = ('key-ordering: enable')
self.check('---\n'

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -181,13 +180,13 @@ class LineLengthTestCase(RuleTestCase):
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'

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -14,6 +13,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from unittest import mock
from tests.common import RuleTestCase
@@ -59,3 +60,37 @@ class NewLinesTestCase(RuleTestCase):
self.check('\r\n', conf)
self.check('---\ntext\n', conf, problem=(1, 4))
self.check('---\r\ntext\r\n', conf)
def test_platform_type(self):
conf = ('new-line-at-end-of-file: disable\n'
'new-lines: {type: platform}\n')
self.check('', conf)
# mock the Linux new-line-character
with mock.patch('yamllint.rules.new_lines.linesep', '\n'):
self.check('\n', conf)
self.check('\r\n', conf, problem=(1, 1))
self.check('---\ntext\n', conf)
self.check('---\r\ntext\r\n', conf, problem=(1, 4))
self.check('---\r\ntext\n', conf, problem=(1, 4))
# FIXME: the following tests currently don't work
# because only the first line is checked for line-endings
# see: issue #475
# ---
# self.check('---\ntext\r\nfoo\n', conf, problem=(2, 4))
# self.check('---\ntext\r\n', conf, problem=(2, 4))
# mock the Windows new-line-character
with mock.patch('yamllint.rules.new_lines.linesep', '\r\n'):
self.check('\r\n', conf)
self.check('\n', conf, problem=(1, 1))
self.check('---\r\ntext\r\n', conf)
self.check('---\ntext\n', conf, problem=(1, 4))
self.check('---\ntext\r\n', conf, problem=(1, 4))
# FIXME: the following tests currently don't work
# because only the first line is checked for line-endings
# see: issue #475
# ---
# self.check('---\r\ntext\nfoo\r\n', conf, problem=(2, 4))
# self.check('---\r\ntext\n', conf, problem=(2, 4))

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -33,6 +32,7 @@ class OctalValuesTestCase(RuleTestCase):
' forbid-explicit-octal: false\n'
'new-line-at-end-of-file: disable\n'
'document-start: disable\n')
self.check('after-tag: !custom_tag 010', conf)
self.check('user-city: 010', conf, problem=(1, 15))
self.check('user-city: abc', conf)
self.check('user-city: 010,0571', conf)

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2018 ClearScore
#
# This program is free software: you can redistribute it and/or modify
@@ -454,3 +453,106 @@ class QuotedTestCase(RuleTestCase):
'- "0o800"\n',
conf,
problem1=(9, 3), problem2=(10, 3))
def test_allow_quoted_quotes(self):
conf = ('quoted-strings: {quote-type: single,\n'
' required: false,\n'
' allow-quoted-quotes: false}\n')
self.check('---\n'
'foo1: "[barbaz]"\n' # fails
'foo2: "[bar\'baz]"\n', # fails
conf, problem1=(2, 7), problem2=(3, 7))
conf = ('quoted-strings: {quote-type: single,\n'
' required: false,\n'
' allow-quoted-quotes: true}\n')
self.check('---\n'
'foo1: "[barbaz]"\n' # fails
'foo2: "[bar\'baz]"\n',
conf, problem1=(2, 7))
conf = ('quoted-strings: {quote-type: single,\n'
' required: true,\n'
' allow-quoted-quotes: false}\n')
self.check('---\n'
'foo1: "[barbaz]"\n' # fails
'foo2: "[bar\'baz]"\n', # fails
conf, problem1=(2, 7), problem2=(3, 7))
conf = ('quoted-strings: {quote-type: single,\n'
' required: true,\n'
' allow-quoted-quotes: true}\n')
self.check('---\n'
'foo1: "[barbaz]"\n' # fails
'foo2: "[bar\'baz]"\n',
conf, problem1=(2, 7))
conf = ('quoted-strings: {quote-type: single,\n'
' required: only-when-needed,\n'
' allow-quoted-quotes: false}\n')
self.check('---\n'
'foo1: "[barbaz]"\n' # fails
'foo2: "[bar\'baz]"\n', # fails
conf, problem1=(2, 7), problem2=(3, 7))
conf = ('quoted-strings: {quote-type: single,\n'
' required: only-when-needed,\n'
' allow-quoted-quotes: true}\n')
self.check('---\n'
'foo1: "[barbaz]"\n' # fails
'foo2: "[bar\'baz]"\n',
conf, problem1=(2, 7))
conf = ('quoted-strings: {quote-type: double,\n'
' required: false,\n'
' allow-quoted-quotes: false}\n')
self.check("---\n"
"foo1: '[barbaz]'\n" # fails
"foo2: '[bar\"baz]'\n", # fails
conf, problem1=(2, 7), problem2=(3, 7))
conf = ('quoted-strings: {quote-type: double,\n'
' required: false,\n'
' allow-quoted-quotes: true}\n')
self.check("---\n"
"foo1: '[barbaz]'\n" # fails
"foo2: '[bar\"baz]'\n",
conf, problem1=(2, 7))
conf = ('quoted-strings: {quote-type: double,\n'
' required: true,\n'
' allow-quoted-quotes: false}\n')
self.check("---\n"
"foo1: '[barbaz]'\n" # fails
"foo2: '[bar\"baz]'\n", # fails
conf, problem1=(2, 7), problem2=(3, 7))
conf = ('quoted-strings: {quote-type: double,\n'
' required: true,\n'
' allow-quoted-quotes: true}\n')
self.check("---\n"
"foo1: '[barbaz]'\n" # fails
"foo2: '[bar\"baz]'\n",
conf, problem1=(2, 7))
conf = ('quoted-strings: {quote-type: double,\n'
' required: only-when-needed,\n'
' allow-quoted-quotes: false}\n')
self.check("---\n"
"foo1: '[barbaz]'\n" # fails
"foo2: '[bar\"baz]'\n", # fails
conf, problem1=(2, 7), problem2=(3, 7))
conf = ('quoted-strings: {quote-type: double,\n'
' required: only-when-needed,\n'
' allow-quoted-quotes: true}\n')
self.check("---\n"
"foo1: '[barbaz]'\n" # fails
"foo2: '[bar\"baz]'\n",
conf, problem1=(2, 7))
conf = ('quoted-strings: {quote-type: any}\n')
self.check("---\n"
"foo1: '[barbaz]'\n"
"foo2: '[bar\"baz]'\n",
conf)

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Peter Ericson
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -24,13 +23,13 @@ import sys
import tempfile
import unittest
from tests.common import build_temp_workspace
from tests.common import build_temp_workspace, temp_workspace
from yamllint import cli
from yamllint import config
class RunContext(object):
class RunContext:
"""Context manager for ``cli.run()`` to capture exit code and streams."""
def __init__(self, case):
@@ -59,7 +58,7 @@ def utf8_available():
locale.setlocale(locale.LC_ALL, 'C.UTF-8')
locale.setlocale(locale.LC_ALL, (None, None))
return True
except locale.Error:
except locale.Error: # pragma: no cover
return False
@@ -282,6 +281,16 @@ class CommandLineTestCase(unittest.TestCase):
self.assertEqual(ctx.stdout, '')
self.assertRegex(ctx.stderr, r'^invalid config: not a dict')
def test_run_with_implicit_extends_config(self):
path = os.path.join(self.wd, 'warn.yaml')
with RunContext(self) as ctx:
cli.run(('-d', 'default', '-f', 'parsable', path))
expected_out = ('%s:1:1: [warning] missing document start "---" '
'(document-start)\n' % path)
self.assertEqual(
(ctx.returncode, ctx.stdout, ctx.stderr), (0, expected_out, ''))
def test_run_with_config_file(self):
with open(os.path.join(self.wd, 'config'), 'w') as f:
f.write('rules: {trailing-spaces: disable}')
@@ -321,6 +330,19 @@ class CommandLineTestCase(unittest.TestCase):
cli.run((os.path.join(self.wd, 'a.yaml'), ))
self.assertEqual(ctx.returncode, 1)
def test_run_with_user_xdg_config_home_in_env(self):
self.addCleanup(os.environ.__delitem__, 'XDG_CONFIG_HOME')
with tempfile.TemporaryDirectory('w') as d:
os.environ['XDG_CONFIG_HOME'] = d
os.makedirs(os.path.join(d, 'yamllint'))
with open(os.path.join(d, 'yamllint', 'config'), 'w') as f:
f.write('extends: relaxed')
with RunContext(self) as ctx:
cli.run(('-f', 'parsable', os.path.join(self.wd, 'warn.yaml')))
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr), (0, '', ''))
def test_run_with_user_yamllint_config_file_in_env(self):
self.addCleanup(os.environ.__delitem__, 'YAMLLINT_CONFIG_FILE')
@@ -346,7 +368,7 @@ class CommandLineTestCase(unittest.TestCase):
# as the first two runs don't use setlocale()
try:
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
except locale.Error:
except locale.Error: # pragma: no cover
self.skipTest('locale en_US.UTF-8 not available')
locale.setlocale(locale.LC_ALL, (None, None))
@@ -547,17 +569,32 @@ class CommandLineTestCase(unittest.TestCase):
self.assertEqual(
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
def test_run_format_colored_warning(self):
path = os.path.join(self.wd, 'warn.yaml')
with RunContext(self) as ctx:
cli.run((path, '--format', 'colored'))
expected_out = (
'\033[4m%s\033[0m\n'
' \033[2m1:1\033[0m \033[33mwarning\033[0m '
'missing document start "---" \033[2m(document-start)\033[0m\n'
'\n' % path)
self.assertEqual(
(ctx.returncode, ctx.stdout, ctx.stderr), (0, expected_out, ''))
def test_run_format_github(self):
path = os.path.join(self.wd, 'a.yaml')
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, ''))
@@ -571,11 +608,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, ''))
@@ -638,3 +677,27 @@ class CommandLineTestCase(unittest.TestCase):
'\n' % path)
self.assertEqual(
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
class CommandLineConfigTestCase(unittest.TestCase):
def test_config_file(self):
workspace = {'a.yml': 'hello: world\n'}
conf = ('---\n'
'extends: relaxed\n')
for conf_file in ('.yamllint', '.yamllint.yml', '.yamllint.yaml'):
with self.subTest(conf_file):
with temp_workspace(workspace):
with RunContext(self) as ctx:
cli.run(('-f', 'parsable', '.'))
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr),
(0, './a.yml:1:1: [warning] missing document '
'start "---" (document-start)\n', ''))
with temp_workspace({**workspace, **{conf_file: conf}}):
with RunContext(self) as ctx:
cli.run(('-f', 'parsable', '.'))
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr),
(0, '', ''))

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -23,6 +22,7 @@ import unittest
from tests.common import build_temp_workspace
from yamllint.config import YamlLintConfigError
from yamllint import cli
from yamllint import config
@@ -122,7 +122,7 @@ class SimpleConfigTestCase(unittest.TestCase):
self.assertEqual(c.rules['hyphens'], False)
def test_validate_rule_conf(self):
class Rule(object):
class Rule:
ID = 'fake'
self.assertFalse(config.validate_rule_conf(Rule, False))
@@ -190,6 +190,41 @@ class SimpleConfigTestCase(unittest.TestCase):
config.validate_rule_conf, Rule,
{'multiple': ['item4']})
def test_invalid_rule(self):
with self.assertRaisesRegex(
config.YamlLintConfigError,
'invalid config: rule "colons": should be either '
'"enable", "disable" or a dict'):
config.YamlLintConfig('rules:\n'
' colons: invalid\n')
def test_invalid_ignore(self):
with self.assertRaisesRegex(
config.YamlLintConfigError,
'invalid config: ignore should contain file patterns'):
config.YamlLintConfig('ignore: yes\n')
def test_invalid_rule_ignore(self):
with self.assertRaisesRegex(
config.YamlLintConfigError,
'invalid config: ignore should contain file patterns'):
config.YamlLintConfig('rules:\n'
' colons:\n'
' ignore: yes\n')
def test_invalid_locale(self):
with self.assertRaisesRegex(
config.YamlLintConfigError,
'invalid config: locale should be a string'):
config.YamlLintConfig('locale: yes\n')
def test_invalid_yaml_files(self):
with self.assertRaisesRegex(
config.YamlLintConfigError,
'invalid config: yaml-files should be a list of file '
'patterns'):
config.YamlLintConfig('yaml-files: yes\n')
class ExtendedConfigTestCase(unittest.TestCase):
def test_extend_on_object(self):
@@ -334,6 +369,16 @@ class ExtendedConfigTestCase(unittest.TestCase):
self.assertEqual(c.rules['colons']['max-spaces-before'], 0)
self.assertEqual(c.rules['colons']['max-spaces-after'], 1)
def test_extended_ignore(self):
with tempfile.NamedTemporaryFile('w') as f:
f.write('ignore: |\n'
' *.template.yaml\n')
f.flush()
c = config.YamlLintConfig('extends: ' + f.name + '\n')
self.assertEqual(c.ignore.match_file('test.template.yaml'), True)
self.assertEqual(c.ignore.match_file('test.yaml'), False)
class ExtendedLibraryConfigTestCase(unittest.TestCase):
def test_extend_config_disable_rule(self):
@@ -385,10 +430,10 @@ class ExtendedLibraryConfigTestCase(unittest.TestCase):
self.assertEqual(new.rules['empty-lines']['max-end'], 0)
class IgnorePathConfigTestCase(unittest.TestCase):
class IgnoreConfigTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
super(IgnorePathConfigTestCase, cls).setUpClass()
super().setUpClass()
bad_yaml = ('---\n'
'- key: val1\n'
@@ -408,22 +453,6 @@ class IgnorePathConfigTestCase(unittest.TestCase):
's/s/ign-trail/file.yaml': bad_yaml,
's/s/ign-trail/s/s/file.yaml': bad_yaml,
's/s/ign-trail/s/s/file2.lint-me-anyway.yaml': bad_yaml,
'.yamllint': 'ignore: |\n'
' *.dont-lint-me.yaml\n'
' /bin/\n'
' !/bin/*.lint-me-anyway.yaml\n'
'\n'
'extends: default\n'
'\n'
'rules:\n'
' key-duplicates:\n'
' ignore: |\n'
' /ign-dup\n'
' trailing-spaces:\n'
' ignore: |\n'
' ign-trail\n'
' !*.lint-me-anyway.yaml\n',
})
cls.backup_wd = os.getcwd()
@@ -431,13 +460,101 @@ class IgnorePathConfigTestCase(unittest.TestCase):
@classmethod
def tearDownClass(cls):
super(IgnorePathConfigTestCase, cls).tearDownClass()
super().tearDownClass()
os.chdir(cls.backup_wd)
shutil.rmtree(cls.wd)
def test_run_with_ignored_path(self):
def test_mutually_exclusive_ignore_keys(self):
self.assertRaises(
YamlLintConfigError,
config.YamlLintConfig, 'extends: default\n'
'ignore-from-file: .gitignore\n'
'ignore: |\n'
' *.dont-lint-me.yaml\n'
' /bin/\n')
def test_ignore_from_file_not_exist(self):
self.assertRaises(
FileNotFoundError,
config.YamlLintConfig, 'extends: default\n'
'ignore-from-file: not_found_file\n')
def test_ignore_from_file_incorrect_type(self):
self.assertRaises(
YamlLintConfigError,
config.YamlLintConfig, 'extends: default\n'
'ignore-from-file: 0\n')
self.assertRaises(
YamlLintConfigError,
config.YamlLintConfig, 'extends: default\n'
'ignore-from-file: [0]\n')
def test_no_ignore(self):
sys.stdout = StringIO()
with self.assertRaises(SystemExit):
cli.run(('-f', 'parsable', '.'))
out = sys.stdout.getvalue()
out = '\n'.join(sorted(out.splitlines()))
keydup = '[error] duplication of key "key" in mapping (key-duplicates)'
trailing = '[error] trailing spaces (trailing-spaces)'
hyphen = '[error] too many spaces after hyphen (hyphens)'
self.assertEqual(out, '\n'.join((
'./bin/file.lint-me-anyway.yaml:3:3: ' + keydup,
'./bin/file.lint-me-anyway.yaml:4:17: ' + trailing,
'./bin/file.lint-me-anyway.yaml:5:5: ' + hyphen,
'./bin/file.yaml:3:3: ' + keydup,
'./bin/file.yaml:4:17: ' + trailing,
'./bin/file.yaml:5:5: ' + hyphen,
'./file-at-root.yaml:3:3: ' + keydup,
'./file-at-root.yaml:4:17: ' + trailing,
'./file-at-root.yaml:5:5: ' + hyphen,
'./file.dont-lint-me.yaml:3:3: ' + keydup,
'./file.dont-lint-me.yaml:4:17: ' + trailing,
'./file.dont-lint-me.yaml:5:5: ' + hyphen,
'./ign-dup/file.yaml:3:3: ' + keydup,
'./ign-dup/file.yaml:4:17: ' + trailing,
'./ign-dup/file.yaml:5:5: ' + hyphen,
'./ign-dup/sub/dir/file.yaml:3:3: ' + keydup,
'./ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./ign-trail/file.yaml:3:3: ' + keydup,
'./ign-trail/file.yaml:4:17: ' + trailing,
'./ign-trail/file.yaml:5:5: ' + hyphen,
'./include/ign-dup/sub/dir/file.yaml:3:3: ' + keydup,
'./include/ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./include/ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/file.yaml:4:17: ' + trailing,
'./s/s/ign-trail/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file.yaml:4:17: ' + trailing,
'./s/s/ign-trail/s/s/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:4:17: ' + trailing,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:5:5: ' + hyphen,
)))
def test_run_with_ignore(self):
with open(os.path.join(self.wd, '.yamllint'), 'w') as f:
f.write('extends: default\n'
'ignore: |\n'
' *.dont-lint-me.yaml\n'
' /bin/\n'
' !/bin/*.lint-me-anyway.yaml\n'
'rules:\n'
' key-duplicates:\n'
' ignore: |\n'
' /ign-dup\n'
' trailing-spaces:\n'
' ignore: |\n'
' ign-trail\n'
' !*.lint-me-anyway.yaml\n')
sys.stdout = StringIO()
with self.assertRaises(SystemExit):
cli.run(('-f', 'parsable', '.'))
@@ -475,3 +592,108 @@ class IgnorePathConfigTestCase(unittest.TestCase):
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:4:17: ' + trailing,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:5:5: ' + hyphen,
)))
def test_run_with_ignore_from_file(self):
with open(os.path.join(self.wd, '.yamllint'), 'w') as f:
f.write('extends: default\n'
'ignore-from-file: .gitignore\n')
with open(os.path.join(self.wd, '.gitignore'), 'w') as f:
f.write('*.dont-lint-me.yaml\n'
'/bin/\n'
'!/bin/*.lint-me-anyway.yaml\n')
sys.stdout = StringIO()
with self.assertRaises(SystemExit):
cli.run(('-f', 'parsable', '.'))
out = sys.stdout.getvalue()
out = '\n'.join(sorted(out.splitlines()))
docstart = '[warning] missing document start "---" (document-start)'
keydup = '[error] duplication of key "key" in mapping (key-duplicates)'
trailing = '[error] trailing spaces (trailing-spaces)'
hyphen = '[error] too many spaces after hyphen (hyphens)'
self.assertEqual(out, '\n'.join((
'./.yamllint:1:1: ' + docstart,
'./bin/file.lint-me-anyway.yaml:3:3: ' + keydup,
'./bin/file.lint-me-anyway.yaml:4:17: ' + trailing,
'./bin/file.lint-me-anyway.yaml:5:5: ' + hyphen,
'./file-at-root.yaml:3:3: ' + keydup,
'./file-at-root.yaml:4:17: ' + trailing,
'./file-at-root.yaml:5:5: ' + hyphen,
'./ign-dup/file.yaml:3:3: ' + keydup,
'./ign-dup/file.yaml:4:17: ' + trailing,
'./ign-dup/file.yaml:5:5: ' + hyphen,
'./ign-dup/sub/dir/file.yaml:3:3: ' + keydup,
'./ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./ign-trail/file.yaml:3:3: ' + keydup,
'./ign-trail/file.yaml:4:17: ' + trailing,
'./ign-trail/file.yaml:5:5: ' + hyphen,
'./include/ign-dup/sub/dir/file.yaml:3:3: ' + keydup,
'./include/ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./include/ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/file.yaml:4:17: ' + trailing,
'./s/s/ign-trail/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file.yaml:4:17: ' + trailing,
'./s/s/ign-trail/s/s/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:4:17: ' + trailing,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:5:5: ' + hyphen,
)))
def test_run_with_ignored_from_file(self):
with open(os.path.join(self.wd, '.yamllint'), 'w') as f:
f.write('ignore-from-file: [.gitignore, .yamlignore]\n'
'extends: default\n')
with open(os.path.join(self.wd, '.gitignore'), 'w') as f:
f.write('*.dont-lint-me.yaml\n'
'/bin/\n')
with open(os.path.join(self.wd, '.yamlignore'), 'w') as f:
f.write('!/bin/*.lint-me-anyway.yaml\n')
sys.stdout = StringIO()
with self.assertRaises(SystemExit):
cli.run(('-f', 'parsable', '.'))
out = sys.stdout.getvalue()
out = '\n'.join(sorted(out.splitlines()))
docstart = '[warning] missing document start "---" (document-start)'
keydup = '[error] duplication of key "key" in mapping (key-duplicates)'
trailing = '[error] trailing spaces (trailing-spaces)'
hyphen = '[error] too many spaces after hyphen (hyphens)'
self.assertEqual(out, '\n'.join((
'./.yamllint:1:1: ' + docstart,
'./bin/file.lint-me-anyway.yaml:3:3: ' + keydup,
'./bin/file.lint-me-anyway.yaml:4:17: ' + trailing,
'./bin/file.lint-me-anyway.yaml:5:5: ' + hyphen,
'./file-at-root.yaml:3:3: ' + keydup,
'./file-at-root.yaml:4:17: ' + trailing,
'./file-at-root.yaml:5:5: ' + hyphen,
'./ign-dup/file.yaml:3:3: ' + keydup,
'./ign-dup/file.yaml:4:17: ' + trailing,
'./ign-dup/file.yaml:5:5: ' + hyphen,
'./ign-dup/sub/dir/file.yaml:3:3: ' + keydup,
'./ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./ign-trail/file.yaml:3:3: ' + keydup,
'./ign-trail/file.yaml:4:17: ' + trailing,
'./ign-trail/file.yaml:5:5: ' + hyphen,
'./include/ign-dup/sub/dir/file.yaml:3:3: ' + keydup,
'./include/ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./include/ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/file.yaml:4:17: ' + trailing,
'./s/s/ign-trail/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file.yaml:4:17: ' + trailing,
'./s/s/ign-trail/s/s/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:4:17: ' + trailing,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:5:5: ' + hyphen,
)))

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -55,3 +54,13 @@ class LinterTestCase(unittest.TestCase):
u'# الأَبْجَدِيَّة العَرَبِيَّة\n')
linter.run(s, self.fake_config())
linter.run(s.encode('utf-8'), self.fake_config())
def test_linter_problem_repr_without_rule(self):
problem = linter.LintProblem(1, 2, 'problem')
self.assertEqual(str(problem), '1:2: problem')
def test_linter_problem_repr_with_rule(self):
problem = linter.LintProblem(1, 2, 'problem', 'rule-id')
self.assertEqual(str(problem), '1:2: problem (rule-id)')

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2017 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -22,10 +21,10 @@ indentation, etc."""
APP_NAME = 'yamllint'
APP_VERSION = '1.26.2'
APP_VERSION = '1.28.0'
APP_DESCRIPTION = __doc__
__author__ = u'Adrien Vergé'
__copyright__ = u'Copyright 2016, Adrien Vergé'
__copyright__ = u'Copyright 2022, Adrien Vergé'
__license__ = 'GPLv3'
__version__ = APP_VERSION

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -14,8 +13,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/>.
from __future__ import print_function
import argparse
import io
import locale
@@ -93,6 +90,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 +104,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 +133,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('')

View File

@@ -19,6 +19,7 @@ rules:
level: warning
empty-lines: enable
empty-values: disable
float-values: disable
hyphens: enable
indentation: enable
key-duplicates: enable

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -14,6 +13,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/>.
import fileinput
import os.path
import pathspec
@@ -26,7 +26,7 @@ class YamlLintConfigError(Exception):
pass
class YamlLintConfig(object):
class YamlLintConfig:
def __init__(self, content=None, file=None):
assert (content is None) ^ (file is None)
@@ -97,7 +97,21 @@ class YamlLintConfig(object):
except Exception as e:
raise YamlLintConfigError('invalid config: %s' % e)
if 'ignore' in conf:
if 'ignore' in conf and 'ignore-from-file' in conf:
raise YamlLintConfigError(
'invalid config: ignore and ignore-from-file keys cannot be '
'used together')
elif 'ignore-from-file' in conf:
if isinstance(conf['ignore-from-file'], str):
conf['ignore-from-file'] = [conf['ignore-from-file']]
if not (isinstance(conf['ignore-from-file'], list) and all(
isinstance(ln, str) for ln in conf['ignore-from-file'])):
raise YamlLintConfigError(
'invalid config: ignore-from-file should contain '
'filename(s), either as a list or string')
with fileinput.input(conf['ignore-from-file']) as f:
self.ignore = pathspec.PathSpec.from_lines('gitwildmatch', f)
elif 'ignore' in conf:
if not isinstance(conf['ignore'], str):
raise YamlLintConfigError(
'invalid config: ignore should contain file patterns')
@@ -151,7 +165,7 @@ def validate_rule_conf(rule, conf):
options = getattr(rule, 'CONF', {})
options_default = getattr(rule, 'DEFAULT', {})
for optkey in conf:
if optkey in ('ignore', 'level'):
if optkey in ('ignore', 'ignore-from-file', 'level'):
continue
if optkey not in options:
raise YamlLintConfigError(

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -30,6 +29,9 @@ PROBLEM_LEVELS = {
'error': 2,
}
DISABLE_RULE_PATTERN = re.compile(r'^# yamllint disable( rule:\S+)*\s*$')
ENABLE_RULE_PATTERN = re.compile(r'^# yamllint enable( rule:\S+)*\s*$')
class LintProblem(object):
"""Represents a linting problem found by yamllint."""
@@ -81,12 +83,9 @@ def get_cosmetic_problems(buffer, conf, filepath):
self.all_rules = {r.ID for r in rules}
def process_comment(self, comment):
try:
comment = str(comment)
except UnicodeError:
return # this certainly wasn't a yamllint directive comment
comment = str(comment)
if re.match(r'^# yamllint disable( rule:\S+)*\s*$', comment):
if DISABLE_RULE_PATTERN.match(comment):
items = comment[18:].rstrip().split(' ')
rules = [item[5:] for item in items][1:]
if len(rules) == 0:
@@ -96,7 +95,7 @@ def get_cosmetic_problems(buffer, conf, filepath):
if id in self.all_rules:
self.rules.add(id)
elif re.match(r'^# yamllint enable( rule:\S+)*\s*$', comment):
elif ENABLE_RULE_PATTERN.match(comment):
items = comment[17:].rstrip().split(' ')
rules = [item[5:] for item in items][1:]
if len(rules) == 0:
@@ -110,10 +109,7 @@ def get_cosmetic_problems(buffer, conf, filepath):
class DisableLineDirective(DisableDirective):
def process_comment(self, comment):
try:
comment = str(comment)
except UnicodeError:
return # this certainly wasn't a yamllint directive comment
comment = str(comment)
if re.match(r'^# yamllint disable-line( rule:\S+)*\s*$', comment):
items = comment[23:].rstrip().split(' ')
@@ -206,15 +202,11 @@ def _run(buffer, conf, filepath):
syntax_error.column <= problem.column):
yield syntax_error
# If there is already a yamllint error at the same place, discard
# it as it is probably redundant (and maybe it's just a 'warning',
# Discard the problem since it is at the same place as the syntax
# error and is probably redundant (and maybe it's just a 'warning',
# in which case the script won't even exit with a failure status).
if (syntax_error.line == problem.line and
syntax_error.column == problem.column):
syntax_error = None
continue
syntax_error = None
continue
yield problem

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -17,7 +16,7 @@
import yaml
class Line(object):
class Line:
def __init__(self, line_no, buffer, start, end):
self.line_no = line_no
self.start = start
@@ -29,7 +28,7 @@ class Line(object):
return self.buffer[self.start:self.end]
class Token(object):
class Token:
def __init__(self, line_no, curr, prev, next, nextnext):
self.line_no = line_no
self.curr = curr
@@ -38,7 +37,7 @@ class Token(object):
self.nextnext = nextnext
class Comment(object):
class Comment:
def __init__(self, line_no, column_no, buffer, pointer,
token_before=None, token_after=None, comment_before=None):
self.line_no = line_no

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -33,6 +32,7 @@ from yamllint.rules import (
new_line_at_end_of_file,
new_lines,
octal_values,
float_values,
quoted_strings,
trailing_spaces,
truthy,
@@ -49,6 +49,7 @@ _RULES = {
document_start.ID: document_start,
empty_lines.ID: empty_lines,
empty_values.ID: empty_values,
float_values.ID: float_values,
hyphens.ID: hyphens,
indentation.ID: indentation,
key_duplicates.ID: key_duplicates,

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -74,8 +73,6 @@ Use this rule to control the position and formatting of comments.
"""
import re
from yamllint.linter import LintProblem
@@ -105,7 +102,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.

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2017 Greg Dubicki
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -0,0 +1,158 @@
# Copyright (C) 2022 the yamllint contributors
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Use this rule to limit the permitted values for floating-point numbers.
YAML permits three classes of float expressions: approximation to real numbers,
positive and negative infinity and "not a number".
.. rubric:: Options
* Use ``require-numeral-before-decimal`` to require floats to start
with a numeral (ex ``0.0`` instead of ``.0``).
* Use ``forbid-scientific-notation`` to forbid scientific notation.
* Use ``forbid-nan`` to forbid NaN (not a number) values.
* Use ``forbid-inf`` to forbid infinite values.
.. rubric:: Default values (when enabled)
.. code-block:: yaml
rules:
float-values:
forbid-inf: false
forbid-nan: false
forbid-scientific-notation: false
require-numeral-before-decimal: false
.. rubric:: Examples
#. With ``float-values: {require-numeral-before-decimal: true}``
the following code snippets would **PASS**:
::
anemometer:
angle: 0.0
the following code snippets would **FAIL**:
::
anemometer:
angle: .0
#. With ``float-values: {forbid-scientific-notation: true}``
the following code snippets would **PASS**:
::
anemometer:
angle: 0.00001
the following code snippets would **FAIL**:
::
anemometer:
angle: 10e-6
#. With ``float-values: {forbid-nan: true}``
the following code snippets would **FAIL**:
::
anemometer:
angle: .NaN
#. With ``float-values: {forbid-inf: true}``
the following code snippets would **FAIL**:
::
anemometer:
angle: .inf
"""
import re
import yaml
from yamllint.linter import LintProblem
ID = 'float-values'
TYPE = 'token'
CONF = {
'require-numeral-before-decimal': bool,
'forbid-scientific-notation': bool,
'forbid-nan': bool,
'forbid-inf': bool,
}
DEFAULT = {
'require-numeral-before-decimal': False,
'forbid-scientific-notation': False,
'forbid-nan': False,
'forbid-inf': False,
}
IS_NUMERAL_BEFORE_DECIMAL_PATTERN = (
re.compile('[-+]?(\\.[0-9]+)([eE][-+]?[0-9]+)?')
)
IS_SCIENTIFIC_NOTATION_PATTERN = re.compile(
'[-+]?(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)'
)
IS_INF_PATTERN = re.compile('[-+]?(\\.inf|\\.Inf|\\.INF)')
IS_NAN_PATTERN = re.compile('\\.nan|\\.NaN|\\.NAN')
def check(conf, token, prev, next, nextnext, context):
if prev and isinstance(prev, yaml.tokens.TagToken):
return
if not isinstance(token, yaml.tokens.ScalarToken):
return
if token.style:
return
val = token.value
if conf['forbid-nan'] and IS_NAN_PATTERN.match(val):
yield LintProblem(
token.start_mark.line + 1,
token.start_mark.column + 1,
f'forbidden not a number value "{token.value}"',
)
if conf['forbid-inf'] and IS_INF_PATTERN.match(val):
yield LintProblem(
token.start_mark.line + 1,
token.start_mark.column + 1,
f'forbidden infinite value "{token.value}"',
)
if conf[
'forbid-scientific-notation'
] and IS_SCIENTIFIC_NOTATION_PATTERN.match(val):
yield LintProblem(
token.start_mark.line + 1,
token.start_mark.column + 1,
f'forbidden scientific notation "{token.value}"',
)
if conf[
'require-numeral-before-decimal'
] and IS_NUMERAL_BEFORE_DECIMAL_PATTERN.match(val):
yield LintProblem(
token.start_mark.line + 1,
token.start_mark.column + 1,
f'forbidden decimal missing 0 prefix "{token.value}"',
)

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -219,7 +218,7 @@ 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')
class Parent(object):
class Parent:
def __init__(self, type, indent, line_indent=None):
self.type = type
self.indent = indent

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -65,7 +64,7 @@ TYPE = 'token'
MAP, SEQ = range(2)
class Parent(object):
class Parent:
def __init__(self, type):
self.type = type
self.keys = []
@@ -84,7 +83,8 @@ def check(conf, token, prev, next, nextnext, context):
elif isinstance(token, (yaml.BlockEndToken,
yaml.FlowMappingEndToken,
yaml.FlowSequenceEndToken)):
context['stack'].pop()
if len(context['stack']) > 0:
context['stack'].pop()
elif (isinstance(token, yaml.KeyToken) and
isinstance(next, yaml.ScalarToken)):
# This check is done because KeyTokens can be found inside flow

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2017 Johannes F. Knauf
#
# This program is free software: you can redistribute it and/or modify
@@ -18,8 +17,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

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify
@@ -19,8 +18,11 @@ Use this rule to force the type of new line characters.
.. rubric:: Options
* Set ``type`` to ``unix`` to use UNIX-typed new line characters (``\\n``), or
``dos`` to use DOS-typed new line characters (``\\r\\n``).
* Set ``type`` to ``unix`` to enforce UNIX-typed new line characters (``\\n``),
set ``type`` to ``dos`` to enforce DOS-typed new line characters
(``\\r\\n``), or set ``type`` to ``platform`` to infer the type from the
system running yamllint (``\\n`` on POSIX / UNIX / Linux / Mac OS systems or
``\\r\\n`` on DOS / Windows systems).
.. rubric:: Default values (when enabled)
@@ -31,24 +33,27 @@ Use this rule to force the type of new line characters.
type: unix
"""
from os import linesep
from yamllint.linter import LintProblem
ID = 'new-lines'
TYPE = 'line'
CONF = {'type': ('unix', 'dos')}
CONF = {'type': ('unix', 'dos', 'platform')}
DEFAULT = {'type': 'unix'}
def check(conf, line):
if conf['type'] == 'unix':
newline_char = '\n'
elif conf['type'] == 'platform':
newline_char = linesep
elif conf['type'] == 'dos':
newline_char = '\r\n'
if line.start == 0 and len(line.buffer) > line.end:
if conf['type'] == 'dos':
if (line.end + 2 > len(line.buffer) or
line.buffer[line.end:line.end + 2] != '\r\n'):
yield LintProblem(1, line.end - line.start + 1,
'wrong new line character: expected \\r\\n')
else:
if line.buffer[line.end] == '\r':
yield LintProblem(1, line.end - line.start + 1,
'wrong new line character: expected \\n')
if line.buffer[line.end:line.end + len(newline_char)] != newline_char:
yield LintProblem(1, line.end - line.start + 1,
'wrong new line character: expected {}'
.format(repr(newline_char).strip('\'')))

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2017 ScienJus
#
# This program is free software: you can redistribute it and/or modify
@@ -85,9 +84,7 @@ CONF = {'forbid-implicit-octal': bool,
DEFAULT = {'forbid-implicit-octal': True,
'forbid-explicit-octal': True}
def _is_octal_number(string):
return re.match(r'^[0-7]+$', string) is not None
IS_OCTAL_NUMBER_PATTERN = re.compile(r'^[0-7]+$')
def check(conf, token, prev, next, nextnext, context):
@@ -99,7 +96,7 @@ def check(conf, token, prev, next, nextnext, context):
if not token.style:
val = token.value
if (val.isdigit() and len(val) > 1 and val[0] == '0' and
_is_octal_number(val[1:])):
IS_OCTAL_NUMBER_PATTERN.match(val[1:])):
yield LintProblem(
token.start_mark.line + 1, token.end_mark.column + 1,
'forbidden implicit octal value "%s"' %
@@ -110,7 +107,7 @@ def check(conf, token, prev, next, nextnext, context):
if not token.style:
val = token.value
if (len(val) > 2 and val[:2] == '0o' and
_is_octal_number(val[2:])):
IS_OCTAL_NUMBER_PATTERN.match(val[2:])):
yield LintProblem(
token.start_mark.line + 1, token.end_mark.column + 1,
'forbidden explicit octal value "%s"' %

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2018 ClearScore
#
# This program is free software: you can redistribute it and/or modify
@@ -31,6 +30,8 @@ used.
``required: false`` and ``required: only-when-needed``.
* ``extra-allowed`` is a list of PCRE regexes to allow quoted string values,
even if ``required: only-when-needed`` is set.
* ``allow-quoted-quotes`` allows (``true``) using disallowed quotes for strings
with allowed quotes inside. Default ``false``.
**Note**: Multi-line strings (with ``|`` or ``>``) will not be checked.
@@ -44,6 +45,7 @@ used.
required: true
extra-required: []
extra-allowed: []
allow-quoted-quotes: false
.. rubric:: Examples
@@ -113,6 +115,26 @@ used.
- "localhost"
- this is a string that needs to be QUOTED
#. With ``quoted-strings: {quote-type: double, allow-quoted-quotes: false}``
the following code snippet would **PASS**:
::
foo: "bar\\"baz"
the following code snippet would **FAIL**:
::
foo: 'bar"baz'
#. With ``quoted-strings: {quote-type: double, allow-quoted-quotes: true}``
the following code snippet would **PASS**:
::
foo: 'bar"baz'
"""
import re
@@ -126,11 +148,13 @@ TYPE = 'token'
CONF = {'quote-type': ('any', 'single', 'double'),
'required': (True, False, 'only-when-needed'),
'extra-required': [str],
'extra-allowed': [str]}
'extra-allowed': [str],
'allow-quoted-quotes': bool}
DEFAULT = {'quote-type': 'any',
'required': True,
'extra-required': [],
'extra-allowed': []}
'extra-allowed': [],
'allow-quoted-quotes': False}
def VALIDATE(conf):
@@ -178,6 +202,12 @@ def _quotes_are_needed(string):
return True
def _has_quoted_quotes(token):
return ((not token.plain) and
((token.style == "'" and '"' in token.value) or
(token.style == '"' and "'" in token.value)))
def check(conf, token, prev, next, nextnext, context):
if not (isinstance(token, yaml.tokens.ScalarToken) and
isinstance(prev, (yaml.BlockEntryToken, yaml.FlowEntryToken,
@@ -207,13 +237,18 @@ def check(conf, token, prev, next, nextnext, context):
if conf['required'] is True:
# Quotes are mandatory and need to match config
if token.style is None or not _quote_match(quote_type, token.style):
if (token.style is None or
not (_quote_match(quote_type, token.style) or
(conf['allow-quoted-quotes'] and _has_quoted_quotes(token)))):
msg = "string value is not quoted with %s quotes" % quote_type
elif conf['required'] is False:
# Quotes are not mandatory but when used need to match config
if token.style and not _quote_match(quote_type, token.style):
if (token.style and
not _quote_match(quote_type, token.style) and
not (conf['allow-quoted-quotes'] and
_has_quoted_quotes(token))):
msg = "string value is not quoted with %s quotes" % quote_type
elif not token.style:
@@ -236,7 +271,9 @@ def check(conf, token, prev, next, nextnext, context):
quote_type)
# But when used need to match config
elif token.style and not _quote_match(quote_type, token.style):
elif (token.style and
not _quote_match(quote_type, token.style) and
not (conf['allow-quoted-quotes'] and _has_quoted_quotes(token))):
msg = "string value is not quoted with %s quotes" % quote_type
elif not token.style:

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# This program is free software: you can redistribute it and/or modify

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Peter Ericson
#
# This program is free software: you can redistribute it and/or modify