Compare commits

...

323 Commits

Author SHA1 Message Date
Adrien Vergé
85ccd625a3 yamllint version 1.26.1 2021-04-06 16:02:55 +02:00
Patryk Małek
e53ea093e2 line_length: skip all hash signs starting comment 2021-03-24 18:04:48 +01:00
Adrien Vergé
5d8ef2ea23 CI: Simplify 'pip' commands 2021-03-24 17:16:57 +01:00
Adrien Vergé
4515269233 CI: Fix failing 'coverage' command because of $PATH
Very probably due to:
https://github.com/actions/virtual-environments/issues/2455#issuecomment-787511010
2021-03-24 17:16:57 +01:00
Adrien Vergé
66bf76a362 CI: Switch to GitHub Actions
Because Travis CI is dead.
2021-03-16 16:13:01 +01:00
Daniel M. Capella
8f682481c7 Remove runtime dep 'setuptools' for Python < 3.8
> In recent versions of setuptools and Python, console-script entry
points are using stdlib importlib by default, thus setuptools is no
longer needed as a runtime dependency.

https://github.com/pypa/setuptools/pull/2197
https://github.com/pypa/setuptools/blob/main/CHANGES.rst#v4730
https://docs.python.org/3/library/importlib.metadata.html
2021-02-11 08:55:08 +01:00
Adrien Vergé
0fff4e29e4 yamllint version 1.26.0 2021-01-29 18:10:35 +01:00
Adrien Vergé
1b378ed5b9 quoted-strings: Fix explicit octal recognition
PyYAML implements YAML spec version 1.1, not 1.2. Hence, values starting
with `0o` are not considered as numbers: they are just strings, so they
need quotes when `quoted-strings: {required: true}`.

>>> import yaml
>>> yaml.resolver.Resolver().resolve(yaml.nodes.ScalarNode, '100', (True, False))
'tag:yaml.org,2002:int'
>>> yaml.resolver.Resolver().resolve(yaml.nodes.ScalarNode, '0100', (True, False))
'tag:yaml.org,2002:int'
>>> yaml.resolver.Resolver().resolve(yaml.nodes.ScalarNode, '0o100', (True, False))
'tag:yaml.org,2002:str'

Let's try to prevent that.

Fixes https://github.com/adrienverge/yamllint/issues/351.
2021-01-11 16:38:29 +01:00
Adrien Vergé
a3fc64d134 End support for Python 2
As planned and advertized, yamllint drops support for Python 2 on 2021.
2021-01-06 07:55:10 +01:00
Rusty Geldmacher
ee4d163ff8 Allow only non-empty brackets/braces
We'd like to disallow brackets and braces in our YAML, but there's a
catch: the only way to describe an empty array or hash in YAML is to
supply an empty one (`[]` or `{}`). Otherwise, the value will be null.

This commit adds a `non-empty` option to `forbid` for brackets and
braces. When it is set, all flow and sequence mappings will cause errors
_except_ for empty ones.
2020-12-15 11:52:21 +01:00
Jason Mobarak
22335b294d Add support for Python 3.9, drop Python 3.4
Add support for Python 3.9 since it was officially released in October
and drop support for Python 3.4 since it is end-of-life (EOL).
2020-12-04 10:10:10 +01:00
Rex Ledesma
0f9dffde23 docs: Add configuration for integration with Arcanist 2020-10-24 13:24:55 +02:00
Mathieu Couette
cef0b48993 tests: Add unittest aliases to Python 2.7 2020-10-12 11:24:01 +02:00
Mathieu Couette
11b1f1c14e tests: Fix indentation issues 2020-10-12 11:24:01 +02:00
Mathieu Couette
9ee8c27ac9 tests: Replace deprecated aliases
https://docs.python.org/3/library/unittest.html#deprecated-aliases
2020-10-12 11:24:01 +02:00
Florian Bruhin
8eebab68ab Fix typo in changelog 2020-10-05 09:42:42 +02:00
Per Lundberg
2103bd73de README.rst: fix typo 2020-10-02 12:51:01 +02:00
Adrien Vergé
85c8631183 tests: Stop using deprecated 'python setup.py test'
Using `python setup.py test` is now deprecated [1], users are encouraged
to be explicit about the test command.

Running yamllint tests using the Python standard library (`unittest`)
can be done using:

    python -m unittest discover

Why not nose, tox or pytest? Because they would add a dependency, make
tests running more complicated and verbose for new users, and their
benefit is not worth for this simple project (only 2 runtime
dependencies: PyYAML and pathspec).

Resolves https://github.com/adrienverge/yamllint/issues/328.

[1]: https://github.com/pypa/setuptools/pull/1878
2020-09-30 09:43:31 +02:00
Adrien Vergé
16e0f9d7b2 yamllint version 1.25.0 2020-09-29 08:52:34 +02:00
Mathieu Couette
1a4f9fe00f gitignore: Add /.eggs
Quick PR to ignore the `/.eggs` folder, which appears to be generated every
time the `python setup.py test` command is run.

The content of the `./.eggs/README.txt` file:

> This directory contains eggs that were downloaded by setuptools to build,
> test, and run plug-ins.
> 
> This directory caches those eggs to prevent repeated downloads.
> 
> However, it is safe to delete this directory.
2020-09-27 10:06:33 +02:00
Mathieu Couette
027d1b0a9a directives: Fix DOS lines messing with rule IDs
Fixes #325

The linter allows a directive to contain trailing whitespace characters like
\r, but does not trim them before iterating on the rules. As a result, the last
rule in the list contains the trailing whitespace characters and never matches
any existing rule.

I added the necessary trimming, as well as a test with 2 checks to go along
with it.
2020-09-26 11:12:26 +02:00
Andrew Imeson
67cb4eb24d Auto-change output format if GitHub Actions detected 2020-09-23 15:41:25 +02:00
Andrew Imeson
50c7453824 Add support for GitHub Annotations output format
Support the format used by GitHub Actions to annotate pull
requests with linter failures
2020-09-23 15:41:25 +02:00
Satoru SATOH
549b136a04 fix: add runtime dependency to setuptools
yamllint depends on pkg_resources.load_entry_point from setuptools to
make its command working, so this runtime dependency to setuptools is
necessary to be listed.
2020-09-14 10:14:10 +02:00
Satoru SATOH
333ae52c78 Add 'forbid' configurations to the braces and brackets rules
Add 'forbid' configuration parameters to the braces and brackets rules
to allow users to forbid the use of flow style collections, flow
mappings and flow sequences.
2020-09-09 20:01:25 +02:00
Julien Falque
0a88c55194 quoted-strings: Fix detecting strings with hashtag as requiring quotes 2020-09-08 11:53:06 +02:00
Julien Falque
ac19d1e427 octal-values: Prevent detection of 8 and 9 as octal values 2020-09-08 09:53:54 +02:00
Adrien Vergé
597e88bb7b docs: Make 'yaml-file' config documentation clearer
Related to https://github.com/adrienverge/yamllint/issues/311.
2020-09-02 18:23:51 +02:00
Satoru SATOH
29d2b50d50 enhancement: add some metadata to provide extra info in its PyPI page
Add some metadata (project_urls) to provide extra info in its PyPI page.

Signed-off-by: Satoru SATOH <satoru.satoh@gmail.com>
2020-09-02 18:02:27 +02:00
Satoru SATOH
4171cdafc9 Move setuptools' packaging configuration from setup.py to setup.cfg
Move setuptools' packaging configuration from setup.py to setup.cfg to
simplify setup.py and make its packaging more dedeclarative.

Signed-off-by: Satoru SATOH <satoru.satoh@gmail.com>
2020-09-02 18:02:27 +02:00
Sorin Sbarnea
d274543b72 docs: Add Python API usage example
Fixes: #297
2020-08-25 20:10:32 +02:00
Kirill Deyko
8da98f2122 commas: Fix example in documentation
Error in the example snippet, it would NOT pass otherwise actually:
```
$ cat test.yml
strange var:
  [10, 20,30, {x: 1, y: 2}]

$ yamllint -d "{extends: default, rules: {commas: {min-spaces-after: 1, max-spaces-after: 1}}}" test.yml
test.yml
  1:1       warning  missing document start "---"  (document-start)
  2:11      error    too few spaces after comma  (commas)
```
2020-08-18 20:07:54 +02:00
Benjamin Wuethrich
b65769c9d2 docs: Add default values to rules with options 2020-07-22 11:54:05 +02:00
Wolfgang Walther
b80997eba6 CI: Add build environment without UTF-8 locales to travis-ci
Preventing regressions like #285
2020-07-20 13:57:06 +02:00
Adrien Vergé
8b758d4e7e yamllint version 1.24.2 2020-07-16 09:35:08 +02:00
Wolfgang Walther
b5b436a3a4 Add global "locale" config option and make key-ordering rule locale-aware
Support sorting by locale with strcoll(). Properly handle case and accents.

Note: this is a second implementation, for context see:
https://github.com/adrienverge/yamllint/pull/280
https://github.com/adrienverge/yamllint/issues/285
https://github.com/adrienverge/yamllint/pull/288
2020-07-16 09:34:13 +02:00
Adrien Vergé
0fceca2354 yamllint version 1.24.1 2020-07-15 14:49:51 +02:00
Adrien Vergé
9403f1f3ec Revert "Add global "locale" config option"
This reverts commit 9e90c77, because it caused a bug that affected
different people just after being released:
https://github.com/adrienverge/yamllint/issues/285
https://github.com/adrienverge/yamllint/issues/286
2020-07-15 14:48:48 +02:00
Adrien Vergé
0016390e78 yamllint version 1.24.0 2020-07-15 11:50:36 +02:00
Wolfgang Walther
9e90c777cb Add global "locale" config option and make key-ordering rule locale-aware
Support sorting by locale with strcoll(). Properly handle case and accents.
2020-07-15 11:46:05 +02:00
Jonathan Sokolowski
a2218988ee config: Do no match directories that look like YAML files
Fixes #279
2020-07-10 09:27:34 +02:00
Adrien Vergé
954fdd5e8f style: Fix 'noqa' for flake8 3.8.0
There was a change in behavior of E402, see:
https://gitlab.com/pycqa/flake8/-/issues/638#note_345108633
2020-07-08 16:27:08 +02:00
Sorin Sbarnea
bbcad943b6 style: Ignore flake8 warnings W503 and W504
Avoid W503/W504 with current code as the current code not compliant
and they are contradictory.
2020-05-03 16:55:57 +02:00
Adrien Vergé
30c90dbf70 Add contribution instructions in CONTRIBUTING.rst
Closes https://github.com/adrienverge/yamllint/issues/263.
2020-05-03 16:51:22 +02:00
Brad Solomon
512fe17047 Fix bug with CRLF in new-lines and require-starting-space
Pound-signs followed by a lone CRLF should not
raise if require-starting-space is specified.

If require-starting-space is true, *and* either:
- new-lines: disbale, or
- newlines: type: dos
is specified, a line with `#\r` or `#\r\n` should
not raise a false positive.

This commit also uses a Set for O(1) membership testing
and uses the correct escape sequence for the nul byte.

If we find a CRLF when looking for Unix newlines, yamllint
should always raise, regardless of logic with
require-starting-space.

Closes: Issue #171.
2020-04-30 16:38:19 +02:00
Will Badart
278a79f093 Mention YAMLLINT_CONFIG_FILE in the documentation 2020-04-29 09:43:16 +02:00
Brad Solomon
e98aacf62c Add Python 3.8 to PyPI/trove classifier data
3.8 is now formally supported in .travis.yml
as of this commit.
2020-04-29 09:39:50 +02:00
Will Badart
94c0416f6b Specify config with environment variable YAMLLINT_CONFIG_FILE
Add option to specify config file with environment variable.
Add test case.
2020-04-28 11:13:32 +02:00
Adrien Vergé
a54cbce1b6 yamllint version 1.23.0 2020-04-17 10:31:52 +02:00
Adrien Vergé
b711fd993e quoted-strings: Add options extra-required and extra-allowed
Add ability to:
- require strings to be quoted if they match a pattern (PCRE regex)
- allow quoted strings if they match a pattern, while `require:
  only-when-needed` is enforced.

Co-Authored-By: Leo Feyer (https://github.com/adrienverge/yamllint/pull/246)
2020-04-17 10:29:55 +02:00
Adrien Vergé
d68022b846 config: Allow generic types inside lists
For example it's possible to define a conf like:

    rule:
      foo: [str],
      bar: [int, bool, 'magic'],
2020-04-17 10:29:55 +02:00
Adrien Vergé
851d34b9fd config: Allow rules to validate their configuration 2020-04-17 10:29:55 +02:00
Adrien Vergé
483a8d89a5 yamllint version 1.22.1 2020-04-15 07:55:57 +02:00
Adrien Vergé
fa87913566 quoted-strings: Fix only-when-needed on corner cases
Change implementation of `required: only-when-needed`, because
maintaining a list of `START_TOKENS` and just looking at the first
character of string values has proven to be partially broken.

Cf. discussion at
https://github.com/adrienverge/yamllint/pull/246#issuecomment-612354097.

Fixes https://github.com/adrienverge/yamllint/issues/242 and
https://github.com/adrienverge/yamllint/pull/244.
2020-04-15 07:48:59 +02:00
Adrien Vergé
961c496b4f yamllint version 1.22.0 2020-04-13 14:32:08 +02:00
Adrien Vergé
ce7d3fcc7b quoted-strings: Remove test_quotes_required()
It is exactly the same tests as `test_quote_type_any()`.
2020-04-13 14:28:02 +02:00
Adrien Vergé
0bffba1e13 quoted-strings: Remove test_single_quotes_required()
It is exactly the same tests as `test_quote_type_single()`.
2020-04-13 14:28:02 +02:00
Adrien Vergé
2d8639c3a1 quoted-strings: Fix broken rule for list items
The rule worked for values like:

    flow-map: {a: foo, b: "bar"}
    block-map:
      a: foo
      b: "bar"

But not for:

    flow-seq: [foo, "bar"]
    block-seq:
      - foo
      - "bar"

Also add tests to make sure there will be no regression.

Fixes: #208.
2020-04-13 14:15:29 +02:00
Adrien Vergé
e284d74be1 quoted-strings: Rename tests names for clarity
And move only-when-needed tests at the end for readability.
2020-04-13 14:15:29 +02:00
Adrien Vergé
1a13837e84 docs: Sunset Python 2
Keep supporting Python 2.7 for one extra year after upstream dropped it:
https://www.python.org/doc/sunset-python-2/
2020-04-09 16:29:43 +02:00
Adrien Vergé
46ed0c02be truthy: Add missing test removed from PR
See https://github.com/adrienverge/yamllint/pull/247#discussion_r405421376.
2020-04-08 12:31:12 +02:00
ilyam8
6ce11dedb4 truthy: add check-keys option 2020-04-08 12:26:21 +02:00
Adrien Vergé
542ae758f5 yamllint version 1.21.0 2020-03-24 07:53:14 +01:00
Rui Pinge
3a6a09b7b6 Add support for redundant quotes in quoted-strings rule
Co-Authored-By: Adrien Vergé
2020-03-24 07:44:07 +01:00
Rui Pinge
15aea73fbe Fix quoted-strings rules not working for string values matching scalars 2020-03-14 14:22:29 +01:00
Martin Packman
91763f5476 Fix new-lines rule on Python 3
Use io.open() when reading files in cli which has the same behaviour
in Python 2 and Python 3, and supply the newline='' parameter which
handles but does not translate line endings.

Add dos.yml test file with windows newlines.

Also add to file finding test expected output.

Add test for new-lines rule through the cli.

Validates files are read with the correct universal newlines setting.

Fixes adrienverge/yamllint#228
2020-02-13 12:02:45 +01:00
Martin Packman
5b049e4229 Add RunContext helper for cli tests
Single context manager that includes exit code and output streams.

Use new RunContext throughout test_cli.

Largely non-functional change, saving some repetition of setup.

Also improve some failures by bundling multiple assertions into one.
2020-02-13 12:02:45 +01:00
Adrien Vergé
044c7f0248 cli: Test unicode chars in paths too 2020-01-17 16:01:05 +01:00
Adrien Vergé
734d5d5f73 CI: Run tests on Python 3.8
Python 3.8 was released in October 2019.
2020-01-03 09:33:35 +01:00
dhutty
fd86455076 CI: Disable building on Python 3.4
As can be seen in https://travis-ci.org/adrienverge/yamllint/builds/631325436?utm_source=github_status&utm_medium=notification
The dependency, pathspec, requires Python '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*' but the running Python is 3.4.8

This commit stops Travis building yamllint against 3.4 so that CI can pass again.
2020-01-03 09:29:33 +01:00
Adrien Vergé
13a0f11e7c yamllint version 1.20.0 2019-12-26 16:06:29 +01:00
Sylvestre Ledru
43b95e99d1 Use 'syntax' as rule name upon syntax errors 2019-12-17 19:29:49 +01:00
ffapitalle
8fa9eb3ced Add --no-warnings option to suppress warning messages
Use `--no-warnings` option to hide warning messages. It only shows
problems marked as errors.
2019-12-12 09:12:53 +01:00
Adrien Vergé
da3788e95a yamllint version 1.19.0 2019-11-19 11:28:21 +01:00
Joel Baranick
fb400dc64b Allow disabling all checks for a file
Allow disabling of a file, even if it is invalid YAML (syntax error) by
including `# yamllint disable-file` in the first line.
2019-11-19 11:26:31 +01:00
Adrien Vergé
92324ae730 yamllint version 1.18.0 2019-10-15 09:49:20 +02:00
Imran Iqbal
7359785ea0 fix(default.yaml): disable empty-values & octal-values by default
* Close #204
2019-10-15 09:41:32 +02:00
Hossein Zolfi
579a975b70 docs: Fix pre-commit config file
* pre-commit show warning for unsupported key (sha)
* Demonstrate how to use custom yamllint
2019-10-01 11:36:07 +02:00
Imran Iqbal
f3d9196aa0 docs(configuration): improve yaml-files code example
* A straight copy/paste of the existing example into the `.yamllint` file results in a `yamllint` error!
2019-09-10 19:47:25 +02:00
Ibrahim AshShohail
881d301883 feat: Support reading config from .yamllint.yml and .yamllint.yaml
Signed-off-by: Ibrahim AshShohail <me@ibrasho.com>
2019-08-27 09:49:09 +02:00
Adrien Vergé
b62b424dd4 feat: Lint .yamllint by default 2019-08-26 10:01:40 +02:00
Adrien Vergé
ce0336e430 yamllint version 1.17.0 2019-08-12 16:54:51 +02:00
grzesuav
063c854658 feat: Make YAML file extensions configurable 2019-08-12 16:53:30 +02:00
xatier
673bdbd324 fix(truthy): Fix extra whitespace 2019-08-11 14:50:11 +02:00
Remi Pointel
cb5fe2c050 add OpenBSD installation instructions. 2019-07-09 10:04:48 +02:00
Adrien Vergé
930c8eea94 docs: Simplify installation instruction in the README 2019-07-07 18:13:43 +02:00
Adrien Vergé
f6a24552d9 yamllint version 1.16.0 2019-06-07 10:04:55 +02:00
Adrien Vergé
0ba193331b truthy: Validate options passed to 'allowed-values'
Make sure values passed in allowed values are correct ones. This is
possible thanks to previous commit, and should prevent users from
writing incorrect configurations.
2019-06-07 09:59:26 +02:00
Adrien Vergé
f65553c4f7 config: Validate config options with list of enums
Allow rules to declare a list of valid values for an option.

For example, a rule like:

    CONF = {'allowed-values': list}

... allowed any value to be passed in the list (including bad ones).

It is now possible to declare:

    CONF = {'allowed-values': ['value1', 'value2', 'value3']}

... so that the list passed to the options must contain only values in
`['value1', 'value2', 'value3']`.
2019-06-07 09:59:26 +02:00
Adrien Vergé
0fef4c14e7 truthy: Try to make docs on allowed-values more explicit
Edit documentation for the `truthy` rule, in order to:
- add quotes to examples (`'yes'` instead of `yes`) to avoid
  misconfigurations,
- group truthy values in the `allowed-values` option paragraph, for
  easier reading.
2019-06-07 09:59:10 +02:00
Ondrej Vaško
4ef7e05f3a truthy: Add allowed-values configuration option
Allows using key `allowed-values` for `truthy` section in configuration file (#150).

This allows to use configuration `truthy: allowed-values: ["yes", "no",
"..."]`, to set custom allowed truthy values.

This is especially useful for people using ansible, where values like
`yes` or `no` are valid and officially supported, but yamllint reports
them as illegal.

Implemented by difference of set of TRUTHY constants and configured
allowed values.

Signed-off-by: Ondrej Vasko <ondrej.vaskoo@gmail.com>
2019-06-06 09:59:00 +02:00
xatier
43c50379e0 Sort import orders 2019-05-27 11:10:30 +02:00
Adrien Vergé
fec2c2fba7 fix(parser): Correctly handle DOS new lines in 'line' rules
Do not consider the trailing `\r` of a line a part of it.
2019-04-09 16:48:00 +02:00
Mateusz Piotrowski
2a66ec2e5e Add FreeBSD installation instructions 2019-03-21 18:40:28 +01:00
Adrien Vergé
37700ab3e6 yamllint version 1.15.0 2019-02-11 14:18:11 +01:00
Adrien Vergé
f66661e36d docs(cli): Add a paragraph about standard input
See commit 05dfcbc "cli: Add command line option - to read from standard
input", cc @miguelbarao.
2019-02-11 14:16:33 +01:00
Adrien Vergé
d6b89e94e4 chore(docs): Fix conf.py styling 2019-02-11 14:09:20 +01:00
Miguel Barao
05dfcbc109 cli: Add command line option - to read from standard input
If YAML files are given as arguments, parses these files.
If yamllint is run with - option, stdin.
If no arguments are given, just fail.
2019-02-11 14:04:48 +01:00
Adrien Vergé
16b939958d yamllint version 1.14.0 2019-01-14 09:47:07 +01:00
Adrien Vergé
b4740dc1fb comments: Fix ignore-shebangs option on corner cases 2019-01-14 09:40:31 +01:00
Mattias Bengtsson
b77f78f677 Support ignoring shebangs
Some usages of YAML (like Ansible) supports running the file as a script.

Support (by default) an ignore-shebangs setting for the comments module.

Fixes #116 - comments rule with require-starting-space: true should special case shebang
2019-01-14 09:40:31 +01:00
Adrien Vergé
0f073f7a09 config: Do not require all rule options to be set
Before, it was required to specify all the options when customizing a
rule. For instance, one could use `empty-lines: enable` or `empty-lines:
{max: 1, max-start: 2, max-end: 2}`, but not just `empty-lines: {max:
1}` (it would fail with *invalid config: missing option "max-start" for
rule "empty-lines"*).

This was a minor problem for users, but it prevented the addition of new
options to existing rules, see [1] for an example. If a new option was
added, updating yamllint for all users that customize the rule would
produce a crash (*invalid config: missing option ...*).

To avoid that, let's embed default values inside the rules themselves,
instead of keeping them in `conf/default.yaml`.

This refactor should not have any impact on existing projects. I've
manually checked that it did not change the output of tests, on
different projects:
- ansible/ansible: `test/runner/ansible-test sanity --python 3.7 --test yamllint`
- ansible/molecule: `yamllint -s test/ molecule/`
- Neo23x0/sigma: `make test-yaml`
- markstory/lint-review: `yamllint .`

[1]: https://github.com/adrienverge/yamllint/pull/151
2019-01-10 10:01:31 +01:00
cclauss
bc7ac81707 Travis CI: Add Python 3.7 and 3.8a
* Adds Python 3.7.1 and a current nightly build of Python 3.8 alpha.
* Python 3.3 reached its end of life in 2017 https://devguide.python.org/#branchstatus
2018-12-10 17:12:50 +01:00
Adrien Vergé
a56a1015f0 style(docs): Fix RST lint errors reported by doc8 2018-12-08 11:21:02 +01:00
Adrien Vergé
6cf5eecdac chore(CI): Lint RST (reStructuredText) files 2018-12-08 11:21:02 +01:00
Hugo
f4c56b8216 Upgrade Python syntax with pyupgrade
https://github.com/asottile/pyupgrade
2018-11-26 19:09:47 +01:00
Hugo
5852566ff0 Upgrade unit tests to use more useful asserts 2018-11-26 19:09:47 +01:00
Hugo
4a7986b4cf Remove redundant parentheses 2018-11-26 19:09:47 +01:00
Hugo
3d1ad9a176 Add explicit Trove classifers for PyPI 2018-11-26 19:09:47 +01:00
Hugo
8da6e36bf1 Add python_requires to help pip 2018-11-26 19:09:47 +01:00
Hugo
c281d48507 Drop support for EOL Python 2.6 2018-11-26 19:09:47 +01:00
Adrien Vergé
8bdddf6e89 docs: Warn about Python 2 and problems with line-length
Closes #146.
2018-11-23 14:19:55 +01:00
Adrien Vergé
c8032c086b line-length: Add tests for lines containing unicode characters
Some unicode characters span accross multiple bytes. Python 3 is OK with
that, but Python 2 reports an incorrect number of characters.

Related to https://github.com/adrienverge/yamllint/issues/146
2018-11-23 14:19:55 +01:00
Adrien Vergé
ea045c41b7 CI: Drop Python 3.3 support
The `pkg_resources` package inside `setuptools` explicitly [disallows
Python 3.3](7392f01ffc (diff-81de4a30a55fcc3fb944f8387ea9ec94)):

    if (3, 0) < sys.version_info < (3, 4):
        raise RuntimeError("Python 3.4 or later is required")

It's time to drop support for 3.3.
2018-11-23 14:10:00 +01:00
Adrien Vergé
c803dd5f6d docs(CHANGELOG): Fix RST format for code snippets 2018-11-14 19:08:39 +01:00
Adrien Vergé
318a12bbe6 yamllint version 1.13.0 2018-11-14 19:04:58 +01:00
Adrien Vergé
66adaee66c docs: Add documentation on the new -f colored option 2018-11-14 19:02:52 +01:00
sedrubal
5062b91cac cli: Add -f colored to force colors
`-f standard` shows non-colored output,
`-f colored` shows colored output,
`-f auto` is the new default, it chooses `standard` or `colored`
depending on terminal capabilities.
2018-10-22 10:35:35 +02:00
sedrubal
3ef85739e3 Use isinstance(x, y) instead of type(x) == y
Fixes pylint C0123.
2018-10-20 10:02:16 +02:00
Adrien Vergé
dc4a9f4fff yamllint version 1.12.1 2018-10-17 10:22:32 +02:00
Adrien Vergé
8354d50016 quoted-strings: Fix broken rule
Original implementation was completely broken. Documentation and actual
behavior were different. Numbers and booleans were detected as wrong, as
well as explicit types.

Fixes #136 and #130.
2018-10-17 10:18:25 +02:00
Adrien Vergé
524d721f0d Update .gitignore to exclude build/ 2018-10-11 15:35:26 +02:00
Adrien Vergé
e864f57d37 docs: Fix missing quoted-strings module in documentation 2018-10-11 15:27:58 +02:00
Adrien Vergé
d41b64aa97 yamllint version 1.12.0 2018-10-04 16:10:56 +02:00
Guido Wischrop (mgm tp)
aaa8777f1d Add quoted-strings rule
* taken from https://github.com/adrienverge/yamllint/pull/110 (submitted by @jurajseffer)
* small fixes for generic and multi-line strings
* fixes for comments from @adrienverge
2018-10-04 16:09:56 +02:00
Adrien Vergé
479f580202 CI: Fix tests failing on Travis for Python 2.6
Because installing dependencies for `coveralls` now fails with:

    Collecting pycparser (from cffi>=1.7->cryptography>=1.3.4; python_version <= "2.7" and extra == "secure"->urllib3[secure]; python_version < "3"->coveralls)
    [...]
    pycparser requires Python '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*' but the running Python is 2.6.9
2018-10-02 19:27:54 +02:00
Justin Foreman
e4e99f0aba docs: Update README for CentOS dependency 2018-05-31 11:06:22 +02:00
Adrien Vergé
203cfc20f0 docs: Remove sudo from pip installation instructions 2018-05-09 20:20:18 +02:00
Adrien Vergé
51c30505b5 docs: Add Mac OS installation instructions
See https://github.com/adrienverge/yamllint/issues/91 and
https://github.com/Homebrew/homebrew-core/blob/af2bbe9/Formula/yamllint.rb
2018-05-09 20:19:03 +02:00
Adrien Vergé
ff9ebde608 docs: Remove old Debian / Ubuntu installation instructions 2018-05-09 20:19:03 +02:00
Adrien Vergé
506e066410 yamllint version 1.11.1 2018-04-06 11:11:32 +02:00
Adrien Vergé
54f21c0514 parser: Fix crash with latest PyYAML
There is a backwards-incompatible change in PyYAML that induces a crash
if `check_token()` is not called before `peek_token()`. See commit
a02d17a in PyYAML or https://github.com/yaml/pyyaml/pull/150.

Closes #105.
2018-04-06 11:07:55 +02:00
Adam Johnson
36b4776778 Clarify documentation on the 'truthy' rule
I like the 'truthy' rule but its documentation and message have confused several of my colleagues. I've tried rewriting it to be clearer.
2018-04-06 11:07:46 +02:00
Adrien Vergé
3bdc1b6e1b CI: Don't install Sphinx if Python 2
Recently builds started to fail with:

    Collecting sphinx
      Downloading Sphinx-1.7.2-py2.py3-none-any.whl (1.9MB)
        100% |████████████████████████████████| 1.9MB 731kB/s
    Sphinx requires Python '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
    but the running Python is 2.6.9
2018-04-06 09:39:53 +02:00
Adrien Vergé
c16934117b CI: Remove Travis hack for enum34 crashing on Python 3.6
Revert commit 8b9eab3, it is not needed anymore.
2018-04-06 09:39:53 +02:00
Eimert
8ab680635b docs: Make ignore examples clearer
[Solved](https://github.com/metacloud/molecule/issues/1228), when
yamllint is used by molecule.
2018-04-02 20:06:17 +02:00
Anthony Sottile
503bde9e70 pre-commit is now served over https! 2018-03-03 08:01:24 +01:00
Nick Burke
1b379628d7 key-duplicates: Handle merge keys (<<)
Merge keys are described here: http://yaml.org/type/merge.html
They shouldn't be considered as duplicated keys.

Fixes https://github.com/adrienverge/yamllint/issues/88
2018-02-28 23:12:43 +01:00
Adrien Vergé
6a842229fd yamllint version 1.11.0 2018-02-21 13:42:06 +01:00
Adrien Vergé
8b9eab33bf CI: Fix failing tests for Python 3.6 because of flake8-import-order
See issue https://github.com/PyCQA/flake8-import-order/issues/149
2018-02-21 13:40:21 +01:00
xieenlong
22e792a433 Feature: checking octal numbers 2017-12-07 18:29:05 +01:00
Adrien Vergé
f713dc8be2 style: Fix E100 and E202 errors reported by pycodestyle 2017-12-07 18:28:53 +01:00
Adrien Vergé
a92743c8ca yamllint version 1.10.0 2017-11-05 10:17:55 +01:00
Adrien Vergé
501def327d tests: Use sys.executable instead of hard-coded 'python'
To test yamllint as a module, tests run commands like
`python -m yamllint`. But some environments (like continuous integration
of Debian or CentOS) don't always include the `python` executable (they
use `python3` instead).

Let's dynamically detect the Python executable path.
2017-11-05 10:06:46 +01:00
Adrien Vergé
ed5d319df8 tests: Use en_US.UTF-8 locale when C.UTF-8 not available
Some operating systems don't have the `C.UTF-8` locale installed yet
(for instance, CentOS 7). In such a case, fallback to `en_US.UTF-8` so
that tests can be run.

This follows commit 92ff315.
2017-11-05 10:02:22 +01:00
Adrien Vergé
6ec1e7b54a Distribution: Include tests in dist file
Since commit e948509 ("setup.py - don't distribute tests"), tests files
are not included in the `.tar.gz` bundle on a fresh repo clone. (On old
repos they were still included, because listed in
`yamllint.egg-info/SOURCES.txt`.)

Let's explicitly include them.
2017-11-05 09:50:46 +01:00
Adrien Vergé
c4475ece34 empty-values: Add forbid-in-flow-mappings conf
This allows preventing implicit `null` from empty values in flow
mappings.

For example:

    {a:}

    {a:, b: 2}

    {
      a: {
        b: ,
        c: {
          d: 4,
          e:
        }
      },
      f:
    }
2017-11-05 09:29:03 +01:00
Greg Dubicki
8537b0a164 Add rule: empty-values, to forbid implicit nulls
only in block mappings for now
2017-11-04 16:22:29 +01:00
Adrien Vergé
83ea74e2f8 CI: Compile documentation on Travis 2017-11-04 16:02:43 +01:00
Waylan Limberg
e43768f203 Better color support check.
Not all systems have `isatty` attribute on `sys.stdout` so check for
existance of attribute before checking value. Also don't use color in
Windows unless environ indicates support. Apparently, Windows can indicate
support by either the presence of `ANSICON` environ variable or if the
`TERM` environ variable is set to `ANSI`. Fixes #79.

No additional tests added, as the relevant tests use fcntl, which is a
Unix only lib. In fact, the tests won't even run in Windows.
2017-10-27 20:06:34 +02:00
Adrien Vergé
d422274563 style: Fix E722 errors reported by pycodestyle
Since a few days ago pycodestyle (formerly called pep8) has a new check:
E722 warning for bare except clauses.

Let's fix our code.
2017-10-27 17:22:35 +02:00
Adrien Vergé
2d931b5a81 yamllint version 1.9.0 2017-10-16 22:52:06 +02:00
Adrien Vergé
773bfc0f3c key-ordering: Add more test cases and documentation 2017-10-16 22:49:39 +02:00
Johannes F. Knauf
1543d0e435 New rule key-ordering
closes #67
2017-10-16 22:49:39 +02:00
Adrien Vergé
f82346dac7 indentation: Add more test cases for key following empty list 2017-10-16 22:17:58 +02:00
Tim Wade
ca540c113b Fix indentation rule for key following empty list
If a key-value pair follows an empty list, i.e.:

```yaml
a:
-
b: c
```

yamllint will complain:

```
warning  wrong indentation: expected 2 but found 0  (indentation)
```

This is because it is expecting the second key to be a continuation of
the block entry above:

```yaml
a:
-
  b: c
```

However, both are perfectly valid, though structurally different.
2017-10-16 22:17:58 +02:00
Adrien Vergé
c8fc170ff0 yamllint version 1.8.2 2017-10-10 12:30:00 +02:00
Adrien Vergé
c4a3e15ff0 docs(readthedocs): Fix builds on yamllint.readthedocs.io
Documentation builds on readthedocs.io partly fail because some modules
imported by yammlint cannot be imported in Sphinx automodule.

This commit fixes that using the tip at [1].

Closes #66

[1]: http://docs.readthedocs.io/en/latest/faq.html#i-get-import-errors-on-libraries-that-depend-on-c-modules
2017-09-03 16:08:42 +02:00
Sebastian Finke
db57127971 docs(integration): Fix pre-commit config file 2017-08-17 12:07:23 +02:00
blackillzone
c8e516be2f Add documentation for pre-commit 2017-07-19 14:56:21 +02:00
blackillzone
1c0dd48ccd Update pre-commit hook file 2017-07-19 14:56:21 +02:00
Adrien Vergé
f4edb85a04 fix(config): Be clearer about the ignore conf type 2017-07-19 09:48:00 +02:00
Adrien Vergé
d99bb9fec3 yamllint version 1.8.1 2017-07-04 22:23:02 +02:00
Adrien Vergé
3c4013fda1 docs(CHANGELOG): Add a changelog
Closes #57
2017-07-04 22:20:57 +02:00
Adrien Vergé
1a961bd4b0 chore(tests): Also run tests on Python 2.6 2017-07-04 22:07:32 +02:00
Adrien Vergé
7a8cfeed6d chore(deps): Require pathspec >= 0.5.3
This new version adds support for Python 2.6.
2017-07-04 22:07:21 +02:00
Adrien Vergé
f9709bc6e6 yamllint version 1.8.0 2017-06-28 15:30:39 +02:00
Adrien Vergé
5060917e40 style(cli): Space import sections 2017-06-28 15:20:24 +02:00
Adrien Vergé
a052cf7dba chore(tests): Add flake8-import-order linter plugin 2017-06-28 15:18:40 +02:00
Adrien Vergé
ae33716529 chore(tests): Also run tests on Python 3.6 2017-06-28 15:14:46 +02:00
Adrien Vergé
df26cc0438 feat(config): Add support to ignore paths on per-rule basis
Example of configuration to use this feature:

    # For all rules
    ignore: |
      *.dont-lint-me.yaml
      /bin/
      !/bin/*.lint-me-anyway.yaml

    rules:
      key-duplicates:
        ignore: |
          generated
          *.template.yaml
      trailing-spaces:
        ignore: |
          *.ignore-trailing-spaces.yaml
          /ascii-art/*

Closes #43.
2017-06-28 15:14:46 +02:00
Adrien Vergé
342d7b49dd tests(cli): Create a temp test workspace only once
Do not re-create it for every test in the class.
2017-06-28 15:11:24 +02:00
Adrien Vergé
7d638d47b9 tests(cli): Refactor temp test workspace recreation
Make it simpler and re-usable.
2017-06-28 15:11:24 +02:00
Adrien Vergé
db116eaaaf Merge pull request #51 from sedrubal/feature_use-argparse-mutually_exclusive_group
Use argparse mutually_exclusive_group for --config-file and --config-data
2017-05-31 22:43:44 +02:00
sedrubal
30dfa78923 Use argparse mutually_exclusive_group for --config-file and --config-data
This does the same as your solution 😉
2017-05-28 22:59:33 +02:00
Adrien Vergé
4ae829c062 yamllint version 1.7.0 2017-04-25 17:09:50 +02:00
Adrien Vergé
400aa084da Merge pull request #46 from krzysztof-magosa/master
Add information about Emacs integration
2017-03-26 19:49:50 +02:00
Krzysztof Magosa
a825645cbe Add information about Emacs integration 2017-03-25 18:53:09 +01:00
Adrien Vergé
1764e32def Merge pull request #45 from jayvdb/add-__main__
Add __main__
2017-03-21 11:36:58 +01:00
Adrien Vergé
d6a81f1b23 Add tests for python -m yamllint 2017-03-21 11:34:52 +01:00
John Vandenberg
38d14c7314 Add __main__
Allows execution using python -m yamllint
2017-03-21 16:00:58 +07:00
Adrien Vergé
ff1c9ad221 Merge pull request #38 from jhriggs/feature/empty_braces_brackets
Add min-spaces-inside-empty, max-spaces-inside-empty to braces and brackets
2017-03-13 13:38:16 +01:00
Jim Riggs
4b2b57aa32 Rules: Add min-spaces-inside-empty and max-spaces-inside-empty
Add min-spaces-inside-empty and max-spaces-inside-empty to braces and
brackets to allow separate handling for empty and non-empty objects.
2017-03-13 13:36:55 +01:00
Adrien Vergé
51b6d8377f Merge pull request #42 from polyzen/doc-ALE.vim
Doc: Add ALE Vim plugin
2017-02-28 20:42:35 +01:00
Daniel M. Capella
f507319419 Doc: Add ALE Vim plugin 2017-02-28 14:01:25 -05:00
Adrien Vergé
c0c8534501 Merge pull request #40 from jwilk/spelling
Fix typos
2017-02-28 07:59:06 +01:00
Jakub Wilk
2b26cbc56b Fix typos 2017-02-28 00:22:49 +01:00
Adrien Vergé
c037d3e586 yamllint version 1.6.1 2017-02-25 22:43:55 +01:00
Adrien Vergé
228c47ab77 fix(indentation): Fix seq indent detection with consistent spaces
In the case when the conf is as follows:

    indentation:
      spaces: consistent
      indent-sequences: true

and there is no indented block before the first block sequence, and this
block sequence is not indented, then the spaces number is computed as
zero (while it obviously shouldn't be).

This causes such a document to fail on 4th line, instead of 2nd:

    a:
    - b
    c:
      - d

This commit fixes that, and adds corresponding tests.

Fixes: #39
2017-02-25 22:43:55 +01:00
Adrien Vergé
413d7a8e4e Merge pull request #32 from mtnbikenc/typo-fix
Minor cosmetic typo
2017-01-11 21:04:02 +01:00
Russell Teague
c332c8e3d4 Minor cosmetic typo 2017-01-11 13:52:19 -05:00
Adrien Vergé
ea67ba3394 Merge pull request #31 from bootswithdefer/master
support for pre-commit from yelp
2016-12-28 19:13:39 +01:00
bootswithdefer
a7dbfb08b3 support for pre-commit from yelp 2016-12-28 19:11:32 +01:00
Adrien Vergé
42eda54014 yamllint version 1.6.0 2016-11-30 09:37:52 +01:00
Adrien Vergé
e909692f88 docs(truthy): Fix typo 2016-11-18 14:28:46 +01:00
Adrien Vergé
3bc72d4c40 feat(CI): Enforce strict checking of YAML files
Use the `--strict` flag to check all rules on local YAML files, to
prevent all problems (including warnings). This includes the newly added
`truthy` rule.
2016-11-18 12:02:30 +01:00
Adrien Vergé
21e81b6435 fix(rules): Use true/false, not yes/no
Although `yes` and `no` are recognized as booleans by the pyyaml parser,
the correct keywords are `true` and `false` (as highlighted by the newly
added `truthy` rule).

This commit replaces the use of `yes`/`no` by `true`/`false` and
advertise it in the docs, but also makes sure this change is
backward-compatible (so that `yes` and `no` still work).
2016-11-18 12:02:02 +01:00
Adrien Vergé
b97b6ad19b style(tests): Fix new flake8 errors
This change fixes new errors detected by the last version of pycodestyle
(2.2.0), which is a dependency of flake8:

    ./tests/test_spec_examples.py:51:1: E305 expected 2 blank lines
    after class or function definition, found 1
    ./tests/test_spec_examples.py:139:1: E305 expected 2 blank lines
    after class or function definition, found 1

See pycodestyle changelog at 2.2.0 and
https://github.com/PyCQA/pycodestyle/pull/593.
2016-11-17 12:24:38 +01:00
Adrien Vergé
2b7f5c5e72 docs(install): Update Debian version
yamllint is now backported in Debian 8 (Jessie):
https://tracker.debian.org/pkg/yamllint
https://packages.debian.org/source/jessie-backports/yamllint
2016-11-16 18:50:13 +01:00
Adrien Vergé
64369db9a2 docs(configuration): Fix typo 2016-11-07 18:11:33 +01:00
Adrien Vergé
2428f6eeaf Merge pull request #27 from jsok/strict-mode
Strict mode
2016-11-07 18:10:57 +01:00
Jonathan Sokolowski
bf386b3c90 docs: Explain strict mode return codes 2016-10-24 14:15:23 +11:00
Jonathan Sokolowski
03e0f5aa6b Add strict mode argument to CLI 2016-10-24 14:08:46 +11:00
Adrien Vergé
3b2a73d224 Merge pull request #25 from adamchainz/universal_wheels
Release as a universal wheel
2016-10-14 09:38:10 +02:00
Adam Chainz
3c525ab743 Release as a universal wheel
By releasing as a [Python wheel](http://pythonwheels.com/) as well as a
source distribution, you can speed up end user’s installs. After merging
this command, to release you just need to run `python setup.py clean
sdist bdist_wheel upload`.
2016-10-14 09:37:38 +02:00
Adrien Vergé
559ad5574b yamllint version 1.5.0 2016-10-08 11:56:46 +02:00
Adrien Vergé
adcb2d2953 Merge pull request #24 from adamchainz/dont_package_tests
setup.py - don't distribute tests
2016-10-08 11:54:46 +02:00
Adam Chainz
e948509fe5 setup.py - don't distribute tests
Found them installed in my `site-packages`, importable as `import tests` 😱

Tested with:

```
In [2]: find_packages()
Out[2]: ['tests', 'yamllint', 'tests.rules', 'yamllint.rules']

In [3]: find_packages(exclude=['tests', 'tests.*'])
Out[3]: ['yamllint', 'yamllint.rules']
```
2016-10-07 10:52:48 +01:00
Adrien Vergé
6dae8f5b6e feat(truthy): Allow explicit types
With this change, we don't require quotes for truthy values that are
explicitly typed. For instance, the following examples are all
considered valid:

    string1: !!str True
    string2: !!str yes
    string3: !!str off
    encoded: !!binary |
               True
               OFF
               pad==  # this decodes as 'N\xbb\x9e8Qii'
    boolean1: !!bool true
    boolean2: !!bool "false"
    boolean3: !!bool FALSE
    boolean4: !!bool True
    boolean5: !!bool off
    boolean6: !!bool NO
2016-10-02 08:15:53 +02:00
Adrien Vergé
073462a87d docs(rules): Fix missing truthy rule in index 2016-10-01 10:00:23 +02:00
Adrien Vergé
4b9ba9e201 docs(truthy): Enhance rule documentation 2016-10-01 10:00:23 +02:00
Peter Ericson
5294ff5552 truthy: Add tests for explicit booleans
From @adrienverge
2016-10-01 09:04:37 +02:00
Peter Ericson
1f472bc144 Add rule: truthy, to forbid truthy values that are not quoted 2016-10-01 09:03:59 +02:00
Adrien Vergé
c163135ee5 yamllint version 1.4.1 2016-09-27 09:46:40 +02:00
Adrien Vergé
f656cf42d2 fix(line-length): Wrap token scanning securely
With `allow-non-breakable-inline-mappings` enabled, every long line is
passed through `loader.peek_token()`. Even lines that are not valid
YAML. For this reason, this code must be wrapped in a `try`/`except`
block.

Closes: #21
2016-09-27 09:27:43 +02:00
Adrien Vergé
9b72a2d29a Merge branch 'adamchainz-readthedocs.io' 2016-09-21 10:47:01 +02:00
Adam Chainz
d7c17c7e7c Doc: Convert readthedocs links from .org to .io
As per [their blog post of the 27th
April](https://blog.readthedocs.com/securing-subdomains/) ‘Securing
subdomains’:

> Starting today, Read the Docs will start hosting projects from
> subdomains on the domain readthedocs.io, instead of on
> readthedocs.org. This change addresses some security concerns around
> site cookies while hosting user generated data on the same domain as
> our dashboard.

Test Plan: Manually visited all the links I’ve modified.
2016-09-21 10:36:00 +02:00
Adrien Vergé
60b72daad4 yamllint version 1.4.0 2016-09-19 13:53:03 +02:00
Adrien Vergé
773bb8a648 Merge pull request #17 from allanlewis/improve-unbreakable
line_length: Allow mapping values with long unbreakable lines
2016-09-19 13:51:44 +02:00
Adrien Vergé
d3cd8ba332 line-length: Generalize ...-inline-mappings for corner cases
This commit refactors the `allow-non-breakable-inline-mappings` logic to
use YAML tokens and avoid crashes or erroneous reports on cases like:

```yaml
- {a: "http://localhost/very/very/very/very/very/very/long/url"
   }
```

```yaml
dict:
  {a: long long long long long long long, b: nospace}
```

```yaml
- long_line: http://localhost/very/very/long/url
```

```yaml
long_line: and+some+space+at+the+end       <-- extra spaces
```

For reference see:
https://github.com/adrienverge/yamllint/pull/17#issuecomment-247805799
2016-09-19 12:39:52 +01:00
Allan Lewis
e56a7c788c line_length: Extract inline logic to new config option
This commit extracts the inline mappings logic defined in the previous
commit to a separate config option, as suggested by @adrienverge. I'll
squash this into the previous commit if the change is accepted. (I named
the option slightly differently to what was suggested as I think my
proposal reads better without consulting the docs: I'd be happy to
reconsider this.)
2016-09-19 12:39:52 +01:00
Allan Lewis
d017631aff line_length: Allow mapping values with long unbreakable lines 2016-09-12 16:31:58 +01:00
Adrien Vergé
5b98cd2053 feat(comments): Allow comments with multiple hash chars
This change make the `comments` rule accept comments that start with
multiple pound signs, e.g.:

    ##############################
    ## This is some documentation

Closes: #12
2016-08-12 11:58:57 +02:00
Adrien Vergé
82dd7dbf16 Merge pull request #16 from adrienverge/coloured_output_on_tty
feat(cli): Colour output only on TTY
2016-08-12 11:58:00 +02:00
Adrien Vergé
4533b8ae49 doc(config): Show relaxed conf contents
Closes: #15
2016-08-12 11:17:18 +02:00
Adrien Vergé
a2c68fdf9b feat(cli): Colour output only on TTY
When piping yamllint output to a file, "coloured" characters aren't
interpreted and pollute text formatting with glyphs like:

  �[4m./global.yaml�[0m
    �[2m1439:52�[0m   �[31merror�[0m    no new line character...

With this commit, stdout is checked: if it's a TTY then output is
coloured, otherwise output is simple text.

Closes: #14
2016-08-12 11:03:41 +02:00
Adrien Vergé
82ed191bc9 yamllint version 1.3.2 2016-06-28 12:06:58 +02:00
Adrien Vergé
92ff315fb4 Tests: Set proper LC_ALL when decoding UTF-8 is needed
Make sure the default localization conditions on the "test system"
support UTF-8 encoding.
2016-06-28 12:06:55 +02:00
Adrien Vergé
f4cebdc054 Tests: Run with LC_ALL=C for uniform tests
Use default (C) locale in all tests to make sure the localization
conditions are the same wherever tests are run.
2016-06-28 11:04:50 +02:00
Adrien Vergé
d174f9e3e3 yamllint version 1.3.1 2016-06-28 10:10:34 +02:00
Adrien Vergé
c8ba8f7e99 linter: Fix UnicodeError when parsing comments
And add tests when reading non-ASCII strings and comments (both from
Python strings and from files).

Fixes: #10
2016-06-28 09:58:23 +02:00
Adrien Vergé
63dd8313f8 yamllint version 1.3.0 2016-06-27 21:54:29 +02:00
Adrien Vergé
7be5867675 linter: Remove dead code
There is *always* a `Line` element at the end of file, even if the
newline character (`\n`) is missing.
2016-06-27 21:45:21 +02:00
Adrien Vergé
6061a2c4cc Rules: common: Remove dead code 2016-06-27 21:37:31 +02:00
Adrien Vergé
09118e417c Doc: Add license information on README page 2016-06-27 21:32:55 +02:00
Adrien Vergé
71b90ae208 Doc: Add new features in README 2016-06-27 21:32:55 +02:00
Adrien Vergé
8844855353 Doc: Remove old Debian install commands from README 2016-06-27 21:15:55 +02:00
Adrien Vergé
0eb310e102 Allow disabling yamllint checks using comments
Implement problem report disabling with comments in YAML source, for
instance:

    # The following mapping contains the same key twice,
    # but I know what I'm doing:
    key: value 1
    key: value 2  # yamllint disable-line rule:key-duplicates

or:

    # yamllint disable rule:colons
    - Lorem       : ipsum
      dolor       : sit amet,
      consectetur : adipiscing elit
    # yamllint enable rule:colons

Closes: #8
2016-06-27 17:53:23 +02:00
Adrien Vergé
cdd094220c parser: Add tests for Comment.is_inline() 2016-06-27 17:47:13 +02:00
Adrien Vergé
7a7d98c96a parser: Iterate over lines + tokens + comments
Instead of iterating over lines and tokens (and find comments between
tokens in the comment rules), add a new `Comment` type and set rules
with `type = 'comment'`.
2016-06-27 17:47:13 +02:00
Adrien Vergé
9f99f25db5 linter: Assert that _run() is called with a buffer 2016-06-25 13:50:24 +02:00
Adrien Vergé
8c839a20c2 Config: Detect user config using os.path.expanduser()
Instead of `$HOME`, since the former works when `$HOME` is not set.

[1]: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=828033#10
2016-06-24 18:41:45 +02:00
Adrien Vergé
8e6e851c5b yamllint version 1.2.2 2016-06-24 08:40:45 +02:00
Adrien Vergé
edd4cca02f Merge pull request #9 from michelebariani/master
Patch allow-non-breakable-words on '-'
2016-06-15 20:06:04 +02:00
Michele Bariani
867970258e Patch allow-non-breakable-words on '-' 2016-06-15 18:07:42 +02:00
Adrien Vergé
d0cb5998c4 Merge pull request #7 from jwilk/spelling
Fix typos
2016-05-13 16:19:58 +02:00
Jakub Wilk
a5c97220e7 Fix typos 2016-05-13 15:47:56 +02:00
Adrien Vergé
598e5e4370 Doc: Fix typo on configuration page intro 2016-04-21 22:39:46 +02:00
Adrien Vergé
03076ee214 Doc: Add a pointer to rules on configuration page intro 2016-04-21 22:37:48 +02:00
Adrien Vergé
eabd349902 Config: Allow a user-global configuration file
Instead of just looking for `.yamllint` in the current working
directory, also look for `~/.config/yamllint/config` (using
`$XDG_CONFIG_HOME` or `$HOME`, see [1] and [2] for information).

[1]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-0.6.html
[2]: https://wiki.archlinux.org/index.php/XDG_Base_Directory_support

Closes: #6
2016-04-21 22:24:24 +02:00
Adrien Vergé
1f1757ced4 yamllint version 1.2.1 2016-03-25 13:55:19 +01:00
Adrien Vergé
59d5bffbec Tests: cli: Detect and handle the -d '' case 2016-03-25 13:46:19 +01:00
Adrien Vergé
53da21934d Tests: Add many cli.run test cases 2016-03-25 13:46:19 +01:00
Adrien Vergé
0c36d0175c cli: Print EnvironmentErrors on stderr
Errors such as "no such file or directory" should not be printed on
standard output.
2016-03-25 13:46:19 +01:00
Adrien Vergé
20545febe5 CI: Lint project's *.yaml files as well as *.yml 2016-03-25 13:46:19 +01:00
Adrien Vergé
88ebcbbb93 Tests: Test cli.find_files_recursively 2016-03-25 13:46:19 +01:00
Adrien Vergé
08615ec4f8 Tests: config: Check the non-valid-yaml-config case 2016-03-25 13:46:19 +01:00
Adrien Vergé
29aceb430a Tests: indentation: Increase coverage 2016-03-25 13:46:19 +01:00
Adrien Vergé
159e29ea6a Rules: indentation: Remove non-existing case
A BlockMappingStartToken should always be followed by a KeyToken, on the
same line.
2016-03-25 13:46:19 +01:00
Adrien Vergé
f9198b7a9b Rules: indentation: Fix B_SEQ instead of B_ENT
For example in this case, the scalar's parent is a B_ENT (only its
grandparent is a B_SEQ):

    - >
        multi
        line
2016-03-25 13:46:19 +01:00
Adrien Vergé
44236077dd Merge pull request #4 from adrienverge/indentation-imbricated-flows
Indentation: imbricated flows
2016-03-25 13:45:05 +01:00
Adrien Vergé
76f47e91ca Rules: indentation: Handle imbricated flows correctly
The following source -- although not loadable by pyyaml -- is valid
YAML:

    {{key}}: value

This was processed badly by yamllint. The same for `[[value]]`,
`{{{{{moustaches}}}}}` or:

    {[val,
      {{key: val,
        key2}}]}

This patch corrects it and add corresponding test cases.

Related-to: #3
2016-03-22 14:34:07 +01:00
Adrien Vergé
f98bed1085 Rules: indentation: Do not crash on unexpected token
Previously, when the indentation rule blocked on an unexpected token,
the program crashed with something like:

    File "/usr/lib/python3/dist-packages/yamllint/rules/indentation.py",
    line 434, in check
      assert context['stack'][-1].type == KEY
    AssertionError

Instead, we prefer report the error as a regular `LintProblem` and
continue processing.

Fixes: #3
2016-03-22 14:34:07 +01:00
Adrien Vergé
a483524b63 Doc: Update installing section
Packages are now also available in Debian and Ubuntu.
2016-03-15 10:04:24 +01:00
Adrien Vergé
3a017a5a22 Doc: Update Neovim integration documentation
Since it has been merged into Neomake:
https://github.com/benekastah/neomake/commit/45dfc5
https://github.com/benekastah/neomake/pull/289
2016-03-10 08:59:31 +01:00
Adrien Vergé
bab8137e2b Update .gitignore 2016-03-08 09:48:17 +01:00
Adrien Vergé
41733fc7a5 Use '.yaml' extension as default, not '.yml'
As someone said [1] on the internet:

    Say ".yaml" not ".yml".
    This is not MS-DOS, and YML is a Yahoo XML dialect.

Similarly, we use '.json', not '.jsn'.

[1]: https://github.com/ceph/s3-tests/commit/e17c56a
2016-03-07 11:15:04 +01:00
Adrien Vergé
688858e639 Doc: Reference Fedora and Ubuntu packages 2016-03-07 11:05:29 +01:00
Adrien Vergé
dca3a54e63 yamllint version 1.2.0 2016-03-06 17:04:05 +01:00
Adrien Vergé
2dcfbd7e0d Conf: relaxed: Remove unneeded lines 2016-03-06 17:04:05 +01:00
Adrien Vergé
73d7a608e8 Conf: relaxed: Re-enable hyphens (in warning) 2016-03-06 17:04:05 +01:00
Adrien Vergé
1c0f164fbf Conf: relaxed: Set indentation's indent-sequences=consistent 2016-03-06 17:01:18 +01:00
Adrien Vergé
46e9108419 Rules: indentation: Add 'consistent' option for 'indent-sequences'
Using `indent-sequences: consistent` allows block sequences to be
indented or not to be, as long as it remains the same within the file.
2016-03-06 15:42:16 +01:00
Adrien Vergé
2f9e3cc71b Conf: relaxed: Set indentation to warning level 2016-03-06 08:26:09 +01:00
Adrien Vergé
b13a03815a Conf: default: Use spaces: consistent for indentation 2016-03-06 08:26:09 +01:00
Adrien Vergé
9a7eec34b1 Rules: indentation: Fix spaces: consitent with broken flows 2016-03-06 08:26:09 +01:00
Adrien Vergé
5b62548ece Tests: indentation: Use 'spaces: consistent' by default 2016-03-06 08:26:09 +01:00
Adrien Vergé
8fca8a7a33 Config: Allow 'enable' keyword for rules
In the same manner as 'disable', 'enable' allows setting a rule on
without worrying about its options.
2016-03-06 08:00:25 +01:00
Adrien Vergé
69ef9a7272 Conf: relaxed: Set max line-length back to 80
Because 80 has been the default for years. But keep it as a warning, not
an error.
2016-03-06 07:42:49 +01:00
Adrien Vergé
d8d1d92545 yamllint version 1.1.0 2016-03-04 17:03:38 +01:00
Adrien Vergé
7688567faa cli: Add the -d option to provide inline conf 2016-03-04 16:53:26 +01:00
Adrien Vergé
4e188f8801 Conf: Add a new pre-defined conf 'relaxed'
It is more tolerant than 'default'.
2016-03-04 16:50:40 +01:00
Adrien Vergé
5693b1dddf Rules: indentation: Add 'consistent' option for 'spaces'
Using `spaces: consistent` allows any number of spaces, as long as it
remains the same within the file.
2016-03-04 16:03:53 +01:00
Adrien Vergé
fa420499c7 Config: Allow types in multiple choices
For instance, allow rules with:

    CONF = {'choice': (int, 'hardcoded-string'),
            'string-or-bool': (str, bool)}
2016-03-04 16:03:46 +01:00
Adrien Vergé
adefe38a0d yamllint version 1.0.4 2016-03-04 12:48:31 +01:00
Adrien Vergé
7e11082353 Distribution: Restore spec examples in package_data
Put `tests/yaml-1.2-spec-examples/*` back in `setup.py`'s `package_data`
because they need to be installed when running `python setup.py build`,
so Debian packaging script `dh_auto_test -O--buildsystem=pybuild`
doesn't fail.

See also commit e6dc67f.
2016-03-04 12:33:56 +01:00
Adrien Vergé
29c1c60143 Tests: Use absolute path to spec examples 2016-03-04 12:15:26 +01:00
Adrien Vergé
b879e9a98f Distribution: Add LICENSE and README to manifest 2016-02-26 09:57:06 +01:00
Adrien Vergé
5956b20545 yamllint version 1.0.3 2016-02-25 14:48:13 +01:00
Adrien Vergé
10ad302e2f Tests: Explicit encoding for spec examples
YAML specification examples contain unusual characters, let's explicit
`encoding='utf-8'` to prevent bugs.
2016-02-25 10:44:05 +01:00
Adrien Vergé
73d9322813 linter: Test run on str, unicode, bytes and stream
Previously it was not tested, and broke on Python 2 `unicode` inputs.
2016-02-25 10:41:17 +01:00
Adrien Vergé
ca0ebe4583 yamllint version 1.0.2 2016-02-24 21:21:02 +01:00
Adrien Vergé
e6dc67fd0a Distribution: Add MANIFEST.in
`yamllint/conf/*.yml` remains in `setup.py`'s `package_data` because it
needs to be installed when running `pip install .`.

`docs/*` and `tests/yaml-1.2-spec-examples/*` just need to be packaged,
they can go in the manifest.
2016-02-24 21:18:48 +01:00
Adrien Vergé
611a560082 yamllint version 1.0.1 2016-02-19 19:39:52 +01:00
Adrien Vergé
83384fa4cf Doc: Fix man page redundant description 2016-02-19 19:34:20 +01:00
Adrien Vergé
3ab3784a75 cli: Remove shebang
A shebang is present at the beginning of file, it dates from the time
when `yamllint/cli.py` was `bin/yamllint`, i.e. an executable launcher.
Since this is not the case anymore (see `entry_points` section in
`setup.py`), let's remove it.
2016-02-19 19:17:49 +01:00
Adrien Vergé
2f75e92a66 Doc: Add a configuration example in README 2016-02-19 10:37:52 +01:00
Adrien Vergé
64caa95b6a yamllint version 1.0.0 2016-02-19 10:15:23 +01:00
Adrien Vergé
fff09fa2df Distribution: Ship example files from spec in sdist
Closes: #1
2016-02-19 10:14:59 +01:00
Adrien Vergé
316bee8c98 yamllint version 0.7.2 2016-02-05 11:28:15 +01:00
Adrien Vergé
6c8af97a40 Tests: unblacklist remaining spec examples
Since !!tags are now supported.
2016-02-05 11:14:37 +01:00
Adrien Vergé
647d84ff94 Rules: indentation: Handle tags 2016-02-05 11:13:44 +01:00
Adrien Vergé
8eb0d0ad74 Tests: unblacklist spec example 7.16
As is it supported -- it just lacks some indentation.
2016-02-05 09:52:09 +01:00
Adrien Vergé
4bc3d5a01c Rules: indentation: Handle anchors 2016-02-04 22:10:40 +01:00
Adrien Vergé
48c7d65c54 parser: Provide nextnext for token rules
Because the indentation rule sometimes needs to look two tokens forward
(in case of anchors for instance).
2016-02-04 22:10:40 +01:00
Adrien Vergé
62fa4cbe39 Tests: indentation: Test the indent stack
The "indentation stack" is iteratively built by the `check()` function
of the indentation rule. It is important, since everything in the rule
relies on it.

This patch adds tests to make sure the stack is correctly built for some
known structures.
2016-02-04 22:10:40 +01:00
Adrien Vergé
8d38d349ac Rules: indentation: Rewrite stack generation
"Indentation stack" generation was not done properly, hence did not work
in all cases. This commit does a cleaner rewriting.
2016-02-04 21:47:08 +01:00
Adrien Vergé
3f264806b9 yamllint version 0.7.1 2016-02-03 14:43:09 +01:00
Adrien Vergé
9a82b99d4b Rules: indentation: Fix multi-line flows
To detect this as correct indentations:

    top:
      rules: [
        {
          foo: 1
        },
        {
          foo: 2
          bar: [
            a, b, c
          ],
        },
      ]
2016-02-03 12:05:22 +01:00
Adrien Vergé
ba140ad42c Tests: Remove ghost character from YAML spec example 2016-02-01 23:27:49 +01:00
Adrien Vergé
0e04ee29e6 Doc: Update description 2016-02-01 23:03:25 +01:00
Adrien Vergé
ba9d86d645 yamllint version 0.7.0 2016-02-01 22:43:42 +01:00
Adrien Vergé
3f4f13e848 Doc: Update screenshot to include 'key-duplicates' 2016-02-01 22:41:56 +01:00
Adrien Vergé
f6bab05e8a Rules: Add the 'key-duplicates' rule 2016-02-01 22:26:18 +01:00
Adrien Vergé
c16eec4681 Style: Fix indentation not multiple of four 2016-02-01 21:36:35 +01:00
Adrien Vergé
68618be4cc Rules: indentation: Handle sets
Sets are like mappings, that do not contain values. Example:

    set:
      ? key one
      ? key two
      ? [non, scalar, key]
2016-02-01 17:52:46 +01:00
Adrien Vergé
431a379c81 Tests: Add tests from YAML 1.2 specification
Write all examples from http://www.yaml.org/spec/1.2/spec.html in
independent files in tests/yaml-1.2-spec-examples; and test them with
yamllint.
2016-02-01 17:05:22 +01:00
Adrien Vergé
6b5948c06b Tests: Reorganize common and global tests 2016-02-01 16:56:32 +01:00
Adrien Vergé
dd163ed551 Rules: indentation: Fix flow sequences with multi-line scalars
Typically sequences like this:

    ["multi
      line 1", "multi
                line 2"]
2016-02-01 16:56:32 +01:00
Adrien Vergé
14c99da2bb Tests: Add test cases for empty flows 2016-02-01 16:56:32 +01:00
Adrien Vergé
cae100071a Rules: indentation: Add support for cleared sequence entries
The following construction is valid YAML, and its indentation should be
correctly handled:

    - this is
    -
      a
    -
      sequence:
        with cleared entries
2016-02-01 14:59:52 +01:00
Adrien Vergé
7cb7b4f669 Rules: commas: Add 'min-spaces-after'
Since such constructions are allowed and valid YAML:

    - [one,two, three,four]

this commit adds a `min-spaces-after` option that defaults to 1.
2016-02-01 12:13:10 +01:00
Adrien Vergé
d2b5f69309 Doc: Update Vim integration documentation
Since it has been merged into Syntastic:
https://github.com/scrooloose/syntastic/commit/8c4dadc
https://github.com/scrooloose/syntastic/pull/1675
2016-01-26 17:20:22 +01:00
214 changed files with 9329 additions and 775 deletions

54
.github/workflows/ci.yaml vendored Normal file
View File

@@ -0,0 +1,54 @@
---
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
with:
python-version: 3.9
- 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:
matrix:
python-version:
- 3.5
- 3.6
- 3.7
- 3.8
- 3.9
- nightly
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python ${{ matrix.pyver }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.pyver }}
- name: Fix GitHub Actions path
run: echo /home/runner/.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

4
.gitignore vendored
View File

@@ -1,3 +1,7 @@
__pycache__
*.py[cod]
/docs/_build
/dist
/yamllint.egg-info
/build
/.eggs

11
.pre-commit-hooks.yaml Normal file
View File

@@ -0,0 +1,11 @@
---
# For use with pre-commit.
# See usage instructions at https://pre-commit.com
- id: yamllint
name: yamllint
description: This hook runs yamllint.
entry: yamllint
language: python
types: [file, yaml]

View File

@@ -1,17 +0,0 @@
---
language: python
python:
- 2.7
- 3.3
- 3.4
- 3.5
- nightly
install:
- pip install pyyaml flake8 coveralls
- pip install .
script:
- flake8 .
- yamllint $(git ls-files '*.yml')
- coverage run --source=yamllint setup.py test
after_success:
coveralls

196
CHANGELOG.rst Normal file
View File

@@ -0,0 +1,196 @@
Changelog
=========
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)
-------------------
- Run tests on Travis both with and without UTF-8 locales
- Improve documentation with default values to rules with options
- Improve documentation with a Python API usage example
- Fix documentation on ``commas`` examples
- Packaging: move setuptools' configuration from ``setup.py`` to ``setup.cfg``
- Packaging: add extra info in PyPI metadata
- Improve documentation on ``yaml-files``
- Fix ``octal-values`` to prevent detection of ``8`` and ``9`` as octal values
- Fix ``quoted-strings`` Fix detecting strings with hashtag as requiring quotes
- Add ``forbid`` configuration to the ``braces`` and ``brackets`` rules
- Fix runtime dependencies missing ``setuptools``
- Add a new output format for GitHub Annotations (``--format github``)
- Fix DOS lines messing with rule IDs in directives
1.24.2 (2020-07-16)
-------------------
- Add ``locale`` config option and make ``key-ordering`` locale-aware
1.24.1 (2020-07-15)
-------------------
- Revert ``locale`` config option from version 1.24.0 because of a bug
1.24.0 (2020-07-15)
-------------------
- Specify config with environment variable ``YAMLLINT_CONFIG_FILE``
- Fix bug with CRLF in ``new-lines`` and ``require-starting-space``
- Do not run linter on directories whose names look like YAML files
- Add ``locale`` config option and make ``key-ordering`` locale-aware
1.23.0 (2020-04-17)
-------------------
- Allow rules to validate their configuration
- Add options ``extra-required`` and ``extra-allowed`` to ``quoted-strings``
1.22.1 (2020-04-15)
-------------------
- Fix ``quoted-strings`` rule with ``only-when-needed`` on corner cases
1.22.0 (2020-04-13)
-------------------
- Add ``check-keys`` option to the ``truthy`` rule
- Fix ``quoted-strings`` rule not working on sequences items
- Sunset Python 2
1.21.0 (2020-03-24)
-------------------
- Fix ``new-lines`` rule on Python 3 with DOS line endings
- Fix ``quoted-strings`` rule not working for string values matching scalars
- Add ``required: only-when-needed`` option to the ``quoted-strings`` rule
1.20.0 (2019-12-26)
-------------------
- Add --no-warnings option to suppress warning messages
- Use 'syntax' as rule name upon syntax errors
1.19.0 (2019-11-19)
-------------------
- Allow disabling all checks for a file with ``# yamllint disable-file``
1.18.0 (2019-10-15)
-------------------
- Lint ``.yamllint`` config file by default
- Also read config from ``.yamllint.yml`` and ``.yamllint.yaml``
- Improve documentation for ``yaml-files``
- Update documentation for ``pre-commit``
- Explicitly disable ``empty-values`` and ``octal-values`` rules
1.17.0 (2019-08-12)
-------------------
- Simplify installation instructions in the README
- Add OpenBSD installation instructions
- Make YAML file extensions configurable
1.16.0 (2019-06-07)
-------------------
- Add FreeBSD installation instructions
- Fix the ``line`` rule to correctly handle DOS new lines
- Add the ``allowed-values`` option to the ``truthy`` rule
- Allow configuration options to be a list of enums
1.15.0 (2019-02-11)
-------------------
- Allow linting from standard input with ``yamllint -``
1.14.0 (2019-01-14)
-------------------
- Fix documentation code snippets
- Drop Python 2.6 and 3.3 support, add Python 3.7 support
- Update documentation and tests for ``line-length`` + Unicode + Python 2
- Allow rule configurations to lack options
- Add a new ``ignore-shebangs`` option for the ``comments`` rule
1.13.0 (2018-11-14)
-------------------
- Use ``isinstance(x, y)`` instead of ``type(x) == y``
- Add a new ``-f colored`` option
- Update documentation about colored output when run from CLI
1.12.1 (2018-10-17)
-------------------
- Fix the ``quoted-strings`` rule, broken implementation
- Fix missing documentation for the ``quoted-strings`` rule
1.12.0 (2018-10-04)
-------------------
- Add a new ``quoted-strings`` rule
- Update installation documentation for pip, CentOS, Debian, Ubuntu, Mac OS
1.11.1 (2018-04-06)
-------------------
- Handle merge keys (``<<``) in the ``key-duplicates`` rule
- Update documentation about pre-commit
- Make examples for ``ignore`` rule clearer
- Clarify documentation on the 'truthy' rule
- Fix crash in parser due to a change in PyYAML > 3.12
1.11.0 (2018-02-21)
-------------------
- Add a new ``octal-values`` rule
1.10.0 (2017-11-05)
-------------------
- Fix colored output on Windows
- Check documentation compilation on continuous integration
- Add a new ``empty-values`` rule
- Make sure test files are included in dist bundle
- Tests: Use en_US.UTF-8 locale when C.UTF-8 not available
- Tests: Dynamically detect Python executable path
1.9.0 (2017-10-16)
------------------
- Add a new ``key-ordering`` rule
- Fix indentation rule for key following empty list
1.8.2 (2017-10-10)
------------------
- Be clearer about the ``ignore`` conf type
- Update pre-commit hook file
- Add documentation for pre-commit
1.8.1 (2017-07-04)
------------------
- Require pathspec >= 0.5.3
- Support Python 2.6
- Add a changelog
1.8.0 (2017-06-28)
------------------
- Refactor argparse with mutually_exclusive_group
- Add support to ignore paths in configuration

46
CONTRIBUTING.rst Normal file
View File

@@ -0,0 +1,46 @@
Contributing
============
Pull requests are the best way to propose changes to the codebase.
Contributions are welcome, but they have to meet some criteria.
Pull Request Process
--------------------
1. Fork this Git repository and create your branch from ``master``.
2. Make sure the tests pass:
.. code:: bash
pip install --user .
python -m unittest discover # all tests...
python -m unittest tests/rules/test_commas.py # or just some tests (faster)
3. If you add code that should be tested, add tests.
4. Make sure the linters pass:
.. code:: bash
flake8 .
If you added/modified documentation:
.. code:: bash
doc8 $(git ls-files '*.rst')
If you touched YAML files:
.. code:: bash
yamllint --strict $(git ls-files '*.yaml' '*.yml')
5. If relevant, update documentation (either in ``docs`` directly or in rules
files themselves).
6. Write a `good commit message
<http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html>`_.
7. Then, open a pull request.

4
MANIFEST.in Normal file
View File

@@ -0,0 +1,4 @@
include LICENSE
include README.rst
include docs/*
include tests/*.py tests/rules/*.py tests/yaml-1.2-spec-examples/*

View File

@@ -3,8 +3,9 @@ yamllint
A linter for YAML files.
yamllint does not only check for syntax validity, but for common cosmetic
conventions such as lines length, trailing spaces, indentation, etc.
yamllint does not only check for syntax validity, but for weirdnesses like key
repetition and cosmetic problems such as lines length, trailing spaces,
indentation, etc.
.. image::
https://travis-ci.org/adrienverge/yamllint.svg?branch=master
@@ -15,18 +16,18 @@ conventions such as lines length, trailing spaces, indentation, etc.
:target: https://coveralls.io/github/adrienverge/yamllint?branch=master
:alt: Code coverage status
.. image:: https://readthedocs.org/projects/yamllint/badge/?version=latest
:target: http://yamllint.readthedocs.org/en/latest/?badge=latest
:target: https://yamllint.readthedocs.io/en/latest/?badge=latest
:alt: Documentation status
Written in Python (compatible with Python 2 & 3).
Written in Python (compatible with Python 3 only).
Documentation
-------------
http://yamllint.readthedocs.org/
https://yamllint.readthedocs.io/
Short overview
--------------
Overview
--------
Screenshot
^^^^^^^^^^
@@ -37,9 +38,15 @@ Screenshot
Installation
^^^^^^^^^^^^
Using pip, the Python package manager:
.. code:: bash
sudo pip install yamllint
pip install --user yamllint
yamllint is also packaged for all major operating systems, see installation
examples (``dnf``, ``apt-get``...) `in the documentation
<https://yamllint.readthedocs.io/en/stable/quickstart.html>`_.
Usage
^^^^^
@@ -56,10 +63,78 @@ Usage
.. code:: bash
# Use a pre-defined lint configuration
yamllint -d relaxed file.yaml
# Use a custom lint configuration
yamllint -c ~/myconfig file.yml
yamllint -c /path/to/myconfig file-to-lint.yaml
.. code:: bash
# Output a parsable format (for syntax checking in editors like Vim, emacs...)
yamllint -f parsable file.yml
yamllint -f parsable file.yaml
`Read more in the complete documentation! <https://yamllint.readthedocs.io/>`_
Features
^^^^^^^^
Here is a yamllint configuration file example:
.. code:: yaml
extends: default
rules:
# 80 chars should be enough, but don't fail if a line is longer
line-length:
max: 80
level: warning
# don't bother me with this rule
indentation: disable
Within a YAML file, special comments can be used to disable checks for a single
line:
.. code:: yaml
This line is waaaaaaaaaay too long # yamllint disable-line
or for a whole block:
.. code:: yaml
# yamllint disable rule:colons
- Lorem : ipsum
dolor : sit amet,
consectetur : adipiscing elit
# yamllint enable
Specific files can be ignored (totally or for some rules only) using a
``.gitignore``-style pattern:
.. code:: yaml
# For all rules
ignore: |
*.dont-lint-me.yaml
/bin/
!/bin/*.lint-me-anyway.yaml
rules:
key-duplicates:
ignore: |
generated
*.template.yaml
trailing-spaces:
ignore: |
*.ignore-trailing-spaces.yaml
/ascii-art/*
`Read more in the complete documentation! <https://yamllint.readthedocs.io/>`_
License
-------
`GPL version 3 <LICENSE>`_

View File

@@ -4,10 +4,11 @@
import sys
import os
from unittest.mock import MagicMock
sys.path.insert(0, os.path.abspath('..')) # noqa
sys.path.insert(0, os.path.abspath('..'))
from yamllint import __copyright__, APP_NAME, APP_VERSION
from yamllint import __copyright__, APP_NAME, APP_VERSION # noqa
# -- General configuration ------------------------------------------------
@@ -38,6 +39,17 @@ htmlhelp_basename = 'yamllintdoc'
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'yamllint', u'yamllint Documentation',
[u'Adrien Vergé'], 1)
('index', 'yamllint', '', [u'Adrien Vergé'], 1)
]
# -- Build with sphinx automodule without needing to install third-party libs
class Mock(MagicMock):
@classmethod
def __getattr__(cls, name):
return MagicMock()
MOCK_MODULES = ['pathspec', 'yaml']
sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES)

View File

@@ -1,33 +1,55 @@
Configuration
=============
yamllint uses a set of *rules* to check sources files for problems. Each rule is
independent from the others, and can be enabled, disabled or tweaked. All these
settings can be gathered in a configuration file.
yamllint uses a set of :doc:`rules <rules>` to check source files for problems.
Each rule is independent from the others, and can be enabled, disabled or
tweaked. All these settings can be gathered in a configuration file.
To use a custom configuration file, either name it ``.yamllint`` in your working
directory, or use the ``-c`` option:
To use a custom configuration file, use the ``-c`` option:
::
.. code:: bash
yamllint -c ~/myconfig file.yml
yamllint -c /path/to/myconfig file-to-lint.yaml
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``
Finally if no config file is found, the default configuration is applied.
Default configuration
---------------------
Unless told otherwise, yamllint uses its ``default`` configuration:
.. literalinclude:: ../yamllint/conf/default.yml
.. literalinclude:: ../yamllint/conf/default.yaml
:language: yaml
Details on rules can be found on :doc:`the rules page <rules>`.
There is another pre-defined configuration named ``relaxed``. As its name
suggests, it is more tolerant:
.. literalinclude:: ../yamllint/conf/relaxed.yaml
:language: yaml
It can be chosen using:
.. code:: bash
yamllint -d relaxed file.yml
Extending the default configuration
-----------------------------------
When writing a custom configuration file, you don't need to redefine every rule.
Just extend the ``default`` configuration (or any already-existing configuration
file).
When writing a custom configuration file, you don't need to redefine every
rule. Just extend the ``default`` configuration (or any already-existing
configuration file).
For instance, if you just want to disable the ``comments-indentation`` rule,
your file could look like this:
@@ -50,7 +72,7 @@ strict on block sequences indentation:
extends: default
rules:
# 80 should be enough, but don't fail if a line is longer
# 80 chars should be enough, but don't fail if a line is longer
line-length:
max: 80
level: warning
@@ -63,12 +85,126 @@ strict on block sequences indentation:
indentation:
indent-sequences: whatever
Custom configuration without a config file
------------------------------------------
It is possible -- although not recommended -- to pass custom configuration
options to yamllint with the ``-d`` (short for ``--config-data``) option.
Its content can either be the name of a pre-defined conf (example: ``default``
or ``relaxed``) or a serialized YAML object describing the configuration.
For instance:
.. code:: bash
yamllint -d "{extends: relaxed, rules: {line-length: {max: 120}}}" file.yaml
Errors and warnings
-------------------
Problems detected by yamllint can be raised either as errors or as warnings.
The CLI will output them (with different colors when using the ``colored``
output format, or ``auto`` when run from a terminal).
In both cases, the script will output them (with different colors when using the
``standard`` output format), but the exit code can be different. More precisely,
the script will exit will a failure code *only when* there is one or more
error(s).
By default the script will exit with a return code ``1`` *only when* there is
one or more error(s).
However if strict mode is enabled with the ``-s`` (or ``--strict``) option, the
return code will be:
* ``0`` if no errors or warnings occur
* ``1`` if one or more errors occur
* ``2`` if no errors occur, but one or more warnings occur
If the script is invoked with the ``--no-warnings`` option, it won't output
warning level problems, only error level ones.
YAML files extensions
---------------------
To configure what yamllint should consider as YAML files when listing
directories, set ``yaml-files`` configuration option. The default is:
.. code-block:: yaml
yaml-files:
- '*.yaml'
- '*.yml'
- '.yamllint'
The same rules as for ignoring paths apply (``.gitignore``-style path pattern,
see below).
Ignoring paths
--------------
It is possible to exclude specific files or directories, so that the linter
doesn't process them.
You can either totally ignore files (they won't be looked at):
.. code-block:: yaml
extends: default
ignore: |
/this/specific/file.yaml
all/this/directory/
*.template.yaml
or ignore paths only for specific rules:
.. code-block:: yaml
extends: default
rules:
trailing-spaces:
ignore: |
/this-file-has-trailing-spaces-but-it-is-OK.yaml
/generated/*.yaml
Note that this ``.gitignore``-style path pattern allows complex path
exclusion/inclusion, see the `pathspec README file
<https://pypi.python.org/pypi/pathspec>`_ for more details.
Here is a more complex example:
.. code-block:: yaml
# For all rules
ignore: |
*.dont-lint-me.yaml
/bin/
!/bin/*.lint-me-anyway.yaml
extends: default
rules:
key-duplicates:
ignore: |
generated
*.template.yaml
trailing-spaces:
ignore: |
*.ignore-trailing-spaces.yaml
ascii-art/*
Setting the locale
------------------
It is possible to set the ``locale`` option globally. This is passed to Python's
`locale.setlocale
<https://docs.python.org/3/library/locale.html#locale.setlocale>`_,
so an empty string ``""`` will use the system default locale, while e.g.
``"en_US.UTF-8"`` will use that.
Currently this only affects the ``key-ordering`` rule. The default will order
by Unicode code point number, while locales will sort case and accents
properly as well.
.. code-block:: yaml
extends: default
locale: en_US.UTF-8

View File

@@ -2,7 +2,17 @@ Development
===========
yamllint provides both a script and a Python module. The latter can be used to
write your own linting tools:
write your own linting tools.
Basic example of running the linter from Python:
.. code-block:: python
import yamllint
yaml_config = yamllint.config.YamlLintConfig("extends: default")
for p in yamllint.linter.run("example.yaml", yaml_config):
print(p.desc, p.line, p.rule)
.. automodule:: yamllint.linter
:members:

View File

@@ -0,0 +1,103 @@
Disable with comments
=====================
Disabling checks for a specific line
------------------------------------
To prevent yamllint from reporting problems for a specific line, add a
directive comment (``# yamllint disable-line ...``) on that line, or on the
line above. For instance:
.. code-block:: yaml
# The following mapping contains the same key twice,
# but I know what I'm doing:
key: value 1
key: value 2 # yamllint disable-line rule:key-duplicates
- This line is waaaaaaaaaay too long but yamllint will not report anything about it. # yamllint disable-line rule:line-length
This line will be checked by yamllint.
or:
.. code-block:: yaml
# The following mapping contains the same key twice,
# but I know what I'm doing:
key: value 1
# yamllint disable-line rule:key-duplicates
key: value 2
# yamllint disable-line rule:line-length
- This line is waaaaaaaaaay too long but yamllint will not report anything about it.
This line will be checked by yamllint.
It is possible, although not recommend, to disabled **all** rules for a
specific line:
.. code-block:: yaml
# yamllint disable-line
- { all : rules ,are disabled for this line}
If you need to disable multiple rules, it is allowed to chain rules like this:
``# yamllint disable-line rule:hyphens rule:commas rule:indentation``.
Disabling checks for all (or part of) the file
----------------------------------------------
To prevent yamllint from reporting problems for the whole file, or for a block
of lines within the file, use ``# yamllint disable ...`` and ``# yamllint
enable ...`` directive comments. For instance:
.. code-block:: yaml
# yamllint disable rule:colons
- Lorem : ipsum
dolor : sit amet,
consectetur : adipiscing elit
# yamllint enable rule:colons
- rest of the document...
It is possible, although not recommend, to disabled **all** rules:
.. code-block:: yaml
# yamllint disable
- Lorem :
ipsum:
dolor : [ sit,amet]
- consectetur : adipiscing elit
# yamllint enable
If you need to disable multiple rules, it is allowed to chain rules like this:
``# yamllint disable rule:hyphens rule:commas rule:indentation``.
Disabling all checks for a file
-------------------------------
To prevent yamllint from reporting problems for a specific file, add the
directive comment ``# yamllint disable-file`` as the first line of the file.
For instance:
.. code-block:: yaml
# yamllint disable-file
# The following mapping contains the same key twice, but I know what I'm doing:
key: value 1
key: value 2
- This line is waaaaaaaaaay too long but yamllint will not report anything about it.
This line will be checked by yamllint.
or:
.. code-block:: jinja
# yamllint disable-file
# This file is not valid YAML because it is a Jinja template
{% if extra_info %}
key1: value1
{% endif %}
key2: value2

View File

@@ -1,10 +1,7 @@
yamllint documentation
======================
A linter for YAML files.
yamllint does not only check for syntax validity, but for common cosmetic
conventions such as lines length, trailing spaces, indentation, etc.
.. automodule:: yamllint
Screenshot
----------
@@ -26,5 +23,7 @@ Table of contents
quickstart
configuration
rules
disable_with_comments
development
text_editors
integration

72
docs/integration.rst Normal file
View File

@@ -0,0 +1,72 @@
Integration with other software
===============================
Integration with pre-commit
---------------------------
You can integrate yamllint in `pre-commit <http://pre-commit.com/>`_ tool.
Here is an example, to add in your .pre-commit-config.yaml
.. code:: yaml
---
# Update the rev variable with the release version that you want, from the yamllint repo
# You can pass your custom .yamllint with args attribute.
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.17.0
hooks:
- id: yamllint
args: [-c=/path/to/.yamllint]
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``.
An example workflow using GitHub Actions:
.. code:: yaml
---
name: yamllint test
on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Install yamllint
run: pip install yamllint
- 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)$)"
}
}
}

View File

@@ -4,49 +4,92 @@ Quickstart
Installing yamllint
-------------------
First, install yamllint. The easiest way is to use pip, the Python package
manager:
On Fedora / CentOS (note: `EPEL <https://fedoraproject.org/wiki/EPEL>`_ is
required on CentOS):
::
.. code:: bash
sudo pip install yamllint
sudo dnf install yamllint
On Debian 8+ / Ubuntu 16.04+:
.. code:: bash
sudo apt-get install yamllint
On Mac OS 10.11+:
.. code:: bash
brew install yamllint
On FreeBSD:
.. code:: sh
pkg install py36-yamllint
On OpenBSD:
.. code:: sh
doas pkg_add py3-yamllint
Alternatively using pip, the Python package manager:
.. code:: bash
pip install --user yamllint
If you prefer installing from source, you can run, from the source directory:
::
.. code:: bash
python setup.py sdist
sudo pip install dist/yamllint-*.tar.gz
pip install --user dist/yamllint-*.tar.gz
Running yamllint
----------------
Basic usage:
::
.. code:: bash
yamllint file.yml other-file.yaml
You can also lint all YAML files in a whole directory:
::
.. code:: bash
yamllint .
Or lint a YAML stream from standard input:
.. code:: bash
echo -e 'this: is\nvalid: YAML' | yamllint -
The output will look like (colors are not displayed here):
::
file.yml
6:2 warning missing starting space in comment (comments)
57:1 error trailing spaces (trailing-spaces)
60:3 error wrong indentation: expected 4 but found 2 (indentation)
1:4 error trailing spaces (trailing-spaces)
4:4 error wrong indentation: expected 4 but found 3 (indentation)
5:4 error duplication of key "id-00042" in mapping (key-duplicates)
6:6 warning comment not indented like content (comments-indentation)
12:6 error too many spaces after hyphen (hyphens)
15:12 error too many spaces before comma (commas)
other-file.yml
other-file.yaml
1:1 warning missing document start "---" (document-start)
9:81 error line too long (84 > 80 characters) (line-length)
31:1 error too many blank lines (4 > 2) (empty-lines)
37:12 error too many spaces inside braces (braces)
6:81 error line too long (87 > 80 characters) (line-length)
10:1 error too many blank lines (4 > 2) (empty-lines)
11:4 error too many spaces inside braces (braces)
By default, the output of yamllint is colored when run from a terminal, and
pure text in other cases. Add the ``-f standard`` arguments to force
non-colored output. Use the ``-f colored`` arguments to force colored output.
Add the ``-f parsable`` arguments if you need an output format parsable by a
machine (for instance for :doc:`syntax highlighting in text editors
@@ -62,9 +105,9 @@ If you have a custom linting configuration file (see :doc:`how to configure
yamllint <configuration>`), it can be passed to yamllint using the ``-c``
option:
::
.. code:: bash
yamllint -c ~/myconfig file.yml
yamllint -c ~/myconfig file.yaml
.. note::

View File

@@ -59,6 +59,11 @@ empty-lines
.. automodule:: yamllint.rules.empty_lines
empty-values
------------
.. automodule:: yamllint.rules.empty_values
hyphens
-------
@@ -69,6 +74,16 @@ indentation
.. automodule:: yamllint.rules.indentation
key-duplicates
--------------
.. automodule:: yamllint.rules.key_duplicates
key-ordering
--------------
.. automodule:: yamllint.rules.key_ordering
line-length
-----------
@@ -84,7 +99,22 @@ new-lines
.. automodule:: yamllint.rules.new_lines
octal-values
------------
.. automodule:: yamllint.rules.octal_values
quoted-strings
--------------
.. automodule:: yamllint.rules.quoted_strings
trailing-spaces
---------------
.. automodule:: yamllint.rules.trailing_spaces
truthy
---------------
.. automodule:: yamllint.rules.truthy

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -9,27 +9,29 @@ text editor.
Vim
---
Assuming that the `syntastic <https://github.com/scrooloose/syntastic>`_ plugin
is installed, add to your ``.vimrc``:
Assuming that the `ALE <https://github.com/w0rp/ale>`_ plugin is
installed, yamllint is supported by default. It is automatically enabled when
editing YAML files.
If you instead use the `syntastic <https://github.com/scrooloose/syntastic>`_
plugin, add this to your ``.vimrc``:
::
TODO
let g:syntastic_yaml_checkers = ['yamllint']
Neovim
------
Assuming that the `neomake <https://github.com/benekastah/neomake>`_ plugin is
installed, add to your ``.config/nvim/init.vim``:
installed, yamllint is supported by default. It is automatically enabled when
editing YAML files.
::
Emacs
-----
if executable('yamllint')
let g:neomake_yaml_yamllint_maker = {
\ 'args': ['-f', 'parsable'],
\ 'errorformat': '%E%f:%l:%c: [error] %m,%W%f:%l:%c: [warning] %m' }
let g:neomake_yaml_enabled_makers = ['yamllint']
endif
If you are `flycheck <https://github.com/flycheck/flycheck>`_ user, you can use
`flycheck-yamllint <https://github.com/krzysztof-magosa/flycheck-yamllint>`_ integration.
Other text editors
------------------

72
setup.cfg Normal file
View File

@@ -0,0 +1,72 @@
[bdist_wheel]
universal = 1
[flake8]
import-order-style = pep8
application-import-names = yamllint
ignore = W503,W504
[build_sphinx]
all-files = 1
source-dir = docs
build-dir = docs/_build
warning-is-error = 1
[metadata]
keywords =
yaml
lint
linter
syntax
checker
url = https://github.com/adrienverge/yamllint
classifiers =
Development Status :: 5 - Production/Stable
Environment :: Console
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
Topic :: Software Development
Topic :: Software Development :: Debuggers
Topic :: Software Development :: Quality Assurance
Topic :: Software Development :: Testing
project_urls =
Documentation = https://yamllint.readthedocs.io
Download = https://pypi.org/project/yamllint/#files
Bug Tracker = https://github.com/adrienverge/yamllint/issues
Source Code = https://github.com/adrienverge/yamllint
[options]
packages = find:
python_requires = >=3.5.*
include_package_data = True
install_requires =
pathspec >= 0.5.3
pyyaml
setuptools; python_version < "3.8"
test_suite = tests
[options.packages.find]
exclude =
tests
tests.*
[options.package_data]
yamllint = conf/*.yaml
[options.entry_points]
console_scripts =
yamllint = yamllint.cli:run
[coverage:run]
relative_files = True

View File

@@ -14,7 +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/>.
from setuptools import setup, find_packages
from setuptools import setup
from yamllint import (__author__, __license__,
APP_NAME, APP_VERSION, APP_DESCRIPTION)
@@ -27,25 +27,4 @@ setup(
description=APP_DESCRIPTION.split('\n')[0],
long_description=APP_DESCRIPTION,
license=__license__,
keywords=['yaml', 'lint', 'linter', 'syntax', 'checker'],
url='https://github.com/adrienverge/yamllint',
classifiers=[
'Development Status :: 4 - Beta',
'Environment :: Console',
'Intended Audience :: Developers',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3',
'Topic :: Software Development',
'Topic :: Software Development :: Debuggers',
'Topic :: Software Development :: Quality Assurance',
'Topic :: Software Development :: Testing',
],
packages=find_packages(),
entry_points={'console_scripts': ['yamllint=yamllint.cli:run']},
package_data={'yamllint': ['conf/*.yml']},
install_requires=['pyyaml'],
tests_require=['nose'],
test_suite='nose.collector',
)

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# 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/>.
import locale
locale.setlocale(locale.LC_ALL, 'C')

View File

@@ -14,6 +14,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/>.
import os
import tempfile
import unittest
import yaml
@@ -49,3 +51,21 @@ class RuleTestCase(unittest.TestCase):
real_problems = list(linter.run(source, self.build_fake_config(conf)))
self.assertEqual(real_problems, expected_problems)
def build_temp_workspace(files):
tempdir = tempfile.mkdtemp(prefix='yamllint-tests-')
for path, content in files.items():
path = os.path.join(tempdir, path).encode('utf-8')
if not os.path.exists(os.path.dirname(path)):
os.makedirs(os.path.dirname(path))
if type(content) is list:
os.mkdir(path)
else:
mode = 'wb' if isinstance(content, bytes) else 'w'
with open(path, mode) as f:
f.write(content)
return tempdir

View File

@@ -14,7 +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/>.
from tests.rules.common import RuleTestCase
from tests.common import RuleTestCase
class ColonTestCase(RuleTestCase):
@@ -31,12 +31,74 @@ class ColonTestCase(RuleTestCase):
'dict6: { a: 1, b, c: 3 }\n'
'dict7: { a: 1, b, c: 3 }\n', conf)
def test_forbid(self):
conf = ('braces:\n'
' forbid: false\n')
self.check('---\n'
'dict: {}\n', conf)
self.check('---\n'
'dict: {a}\n', conf)
self.check('---\n'
'dict: {a: 1}\n', conf)
self.check('---\n'
'dict: {\n'
' a: 1\n'
'}\n', conf)
conf = ('braces:\n'
' forbid: true\n')
self.check('---\n'
'dict:\n'
' a: 1\n', conf)
self.check('---\n'
'dict: {}\n', conf, problem=(2, 8))
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))
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: {max-spaces-inside: -1, min-spaces-inside: 0}'
conf = ('braces:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: 0\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'dict: {}\n', conf)
conf = 'braces: {max-spaces-inside: -1, min-spaces-inside: 1}'
conf = ('braces:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: 1\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'dict: {}\n', conf, problem=(2, 8))
self.check('---\n'
@@ -52,7 +114,11 @@ class ColonTestCase(RuleTestCase):
' b\n'
'}\n', conf)
conf = 'braces: {max-spaces-inside: -1, min-spaces-inside: 3}'
conf = ('braces:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: 3\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'dict: { a: 1, b }\n', conf,
problem1=(2, 9), problem2=(2, 17))
@@ -60,7 +126,11 @@ class ColonTestCase(RuleTestCase):
'dict: { a: 1, b }\n', conf)
def test_max_spaces(self):
conf = 'braces: {max-spaces-inside: 0, min-spaces-inside: -1}'
conf = ('braces:\n'
' max-spaces-inside: 0\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'dict: {}\n', conf)
self.check('---\n'
@@ -79,7 +149,11 @@ class ColonTestCase(RuleTestCase):
' b\n'
'}\n', conf)
conf = 'braces: {max-spaces-inside: 3, min-spaces-inside: -1}'
conf = ('braces:\n'
' max-spaces-inside: 3\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'dict: { a: 1, b }\n', conf)
self.check('---\n'
@@ -87,7 +161,11 @@ class ColonTestCase(RuleTestCase):
problem1=(2, 11), problem2=(2, 23))
def test_min_and_max_spaces(self):
conf = 'braces: {max-spaces-inside: 0, min-spaces-inside: 0}'
conf = ('braces:\n'
' max-spaces-inside: 0\n'
' min-spaces-inside: 0\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'dict: {}\n', conf)
self.check('---\n'
@@ -95,14 +173,169 @@ class ColonTestCase(RuleTestCase):
self.check('---\n'
'dict: { a: 1, b}\n', conf, problem=(2, 10))
conf = 'braces: {max-spaces-inside: 1, min-spaces-inside: 1}'
conf = ('braces:\n'
' max-spaces-inside: 1\n'
' min-spaces-inside: 1\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'dict: {a: 1, b, c: 3 }\n', conf, problem=(2, 8))
conf = 'braces: {max-spaces-inside: 2, min-spaces-inside: 0}'
conf = ('braces:\n'
' max-spaces-inside: 2\n'
' min-spaces-inside: 0\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'dict: {a: 1, b, c: 3 }\n', conf)
self.check('---\n'
'dict: { a: 1, b, c: 3 }\n', conf)
self.check('---\n'
'dict: { a: 1, b, c: 3 }\n', conf, problem=(2, 10))
def test_min_spaces_empty(self):
conf = ('braces:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: 0\n'
' min-spaces-inside-empty: 0\n')
self.check('---\n'
'array: {}\n', conf)
conf = ('braces:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: 1\n')
self.check('---\n'
'array: {}\n', conf, problem=(2, 9))
self.check('---\n'
'array: { }\n', conf)
conf = ('braces:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: 3\n')
self.check('---\n'
'array: {}\n', conf, problem=(2, 9))
self.check('---\n'
'array: { }\n', conf)
def test_max_spaces_empty(self):
conf = ('braces:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: 0\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'array: {}\n', conf)
self.check('---\n'
'array: { }\n', conf, problem=(2, 9))
conf = ('braces:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: 1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'array: {}\n', conf)
self.check('---\n'
'array: { }\n', conf)
self.check('---\n'
'array: { }\n', conf, problem=(2, 10))
conf = ('braces:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: 3\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'array: {}\n', conf)
self.check('---\n'
'array: { }\n', conf)
self.check('---\n'
'array: { }\n', conf, problem=(2, 12))
def test_min_and_max_spaces_empty(self):
conf = ('braces:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: 2\n'
' min-spaces-inside-empty: 1\n')
self.check('---\n'
'array: {}\n', conf, problem=(2, 9))
self.check('---\n'
'array: { }\n', conf)
self.check('---\n'
'array: { }\n', conf)
self.check('---\n'
'array: { }\n', conf, problem=(2, 11))
def test_mixed_empty_nonempty(self):
conf = ('braces:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: 1\n'
' max-spaces-inside-empty: 0\n'
' min-spaces-inside-empty: 0\n')
self.check('---\n'
'array: { a: 1, b }\n', conf)
self.check('---\n'
'array: {a: 1, b}\n', conf,
problem1=(2, 9), problem2=(2, 16))
self.check('---\n'
'array: {}\n', conf)
self.check('---\n'
'array: { }\n', conf,
problem1=(2, 9))
conf = ('braces:\n'
' max-spaces-inside: 0\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: 1\n'
' min-spaces-inside-empty: 1\n')
self.check('---\n'
'array: { a: 1, b }\n', conf,
problem1=(2, 9), problem2=(2, 17))
self.check('---\n'
'array: {a: 1, b}\n', conf)
self.check('---\n'
'array: {}\n', conf,
problem1=(2, 9))
self.check('---\n'
'array: { }\n', conf)
conf = ('braces:\n'
' max-spaces-inside: 2\n'
' min-spaces-inside: 1\n'
' max-spaces-inside-empty: 1\n'
' min-spaces-inside-empty: 1\n')
self.check('---\n'
'array: { a: 1, b }\n', conf)
self.check('---\n'
'array: {a: 1, b }\n', conf,
problem1=(2, 9), problem2=(2, 18))
self.check('---\n'
'array: {}\n', conf,
problem1=(2, 9))
self.check('---\n'
'array: { }\n', conf)
self.check('---\n'
'array: { }\n', conf,
problem1=(2, 11))
conf = ('braces:\n'
' max-spaces-inside: 1\n'
' min-spaces-inside: 1\n'
' max-spaces-inside-empty: 1\n'
' min-spaces-inside-empty: 1\n')
self.check('---\n'
'array: { a: 1, b }\n', conf)
self.check('---\n'
'array: {a: 1, b}\n', conf,
problem1=(2, 9), problem2=(2, 16))
self.check('---\n'
'array: {}\n', conf,
problem1=(2, 9))
self.check('---\n'
'array: { }\n', conf)

View File

@@ -14,7 +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/>.
from tests.rules.common import RuleTestCase
from tests.common import RuleTestCase
class ColonTestCase(RuleTestCase):
@@ -31,12 +31,72 @@ class ColonTestCase(RuleTestCase):
'array6: [ a, b, c ]\n'
'array7: [ a, b, c ]\n', conf)
def test_forbid(self):
conf = ('brackets:\n'
' forbid: false\n')
self.check('---\n'
'array: []\n', conf)
self.check('---\n'
'array: [a, b]\n', conf)
self.check('---\n'
'array: [\n'
' a,\n'
' b\n'
']\n', conf)
conf = ('brackets:\n'
' forbid: true\n')
self.check('---\n'
'array:\n'
' - a\n'
' - b\n', conf)
self.check('---\n'
'array: []\n', conf, problem=(2, 9))
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))
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: {max-spaces-inside: -1, min-spaces-inside: 0}'
conf = ('brackets:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: 0\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'array: []\n', conf)
conf = 'brackets: {max-spaces-inside: -1, min-spaces-inside: 1}'
conf = ('brackets:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: 1\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'array: []\n', conf, problem=(2, 9))
self.check('---\n'
@@ -51,7 +111,11 @@ class ColonTestCase(RuleTestCase):
' b\n'
']\n', conf)
conf = 'brackets: {max-spaces-inside: -1, min-spaces-inside: 3}'
conf = ('brackets:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: 3\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'array: [ a, b ]\n', conf,
problem1=(2, 10), problem2=(2, 15))
@@ -59,7 +123,11 @@ class ColonTestCase(RuleTestCase):
'array: [ a, b ]\n', conf)
def test_max_spaces(self):
conf = 'brackets: {max-spaces-inside: 0, min-spaces-inside: -1}'
conf = ('brackets:\n'
' max-spaces-inside: 0\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'array: []\n', conf)
self.check('---\n'
@@ -78,7 +146,11 @@ class ColonTestCase(RuleTestCase):
' b\n'
']\n', conf)
conf = 'brackets: {max-spaces-inside: 3, min-spaces-inside: -1}'
conf = ('brackets:\n'
' max-spaces-inside: 3\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'array: [ a, b ]\n', conf)
self.check('---\n'
@@ -86,7 +158,11 @@ class ColonTestCase(RuleTestCase):
problem1=(2, 12), problem2=(2, 21))
def test_min_and_max_spaces(self):
conf = 'brackets: {max-spaces-inside: 0, min-spaces-inside: 0}'
conf = ('brackets:\n'
' max-spaces-inside: 0\n'
' min-spaces-inside: 0\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'array: []\n', conf)
self.check('---\n'
@@ -94,14 +170,169 @@ class ColonTestCase(RuleTestCase):
self.check('---\n'
'array: [ a, b]\n', conf, problem=(2, 11))
conf = 'brackets: {max-spaces-inside: 1, min-spaces-inside: 1}'
conf = ('brackets:\n'
' max-spaces-inside: 1\n'
' min-spaces-inside: 1\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'array: [a, b, c ]\n', conf, problem=(2, 9))
conf = 'brackets: {max-spaces-inside: 2, min-spaces-inside: 0}'
conf = ('brackets:\n'
' max-spaces-inside: 2\n'
' min-spaces-inside: 0\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'array: [a, b, c ]\n', conf)
self.check('---\n'
'array: [ a, b, c ]\n', conf)
self.check('---\n'
'array: [ a, b, c ]\n', conf, problem=(2, 11))
def test_min_spaces_empty(self):
conf = ('brackets:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: 0\n'
' min-spaces-inside-empty: 0\n')
self.check('---\n'
'array: []\n', conf)
conf = ('brackets:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: 1\n')
self.check('---\n'
'array: []\n', conf, problem=(2, 9))
self.check('---\n'
'array: [ ]\n', conf)
conf = ('brackets:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: -1\n'
' min-spaces-inside-empty: 3\n')
self.check('---\n'
'array: []\n', conf, problem=(2, 9))
self.check('---\n'
'array: [ ]\n', conf)
def test_max_spaces_empty(self):
conf = ('brackets:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: 0\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'array: []\n', conf)
self.check('---\n'
'array: [ ]\n', conf, problem=(2, 9))
conf = ('brackets:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: 1\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'array: []\n', conf)
self.check('---\n'
'array: [ ]\n', conf)
self.check('---\n'
'array: [ ]\n', conf, problem=(2, 10))
conf = ('brackets:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: 3\n'
' min-spaces-inside-empty: -1\n')
self.check('---\n'
'array: []\n', conf)
self.check('---\n'
'array: [ ]\n', conf)
self.check('---\n'
'array: [ ]\n', conf, problem=(2, 12))
def test_min_and_max_spaces_empty(self):
conf = ('brackets:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: 2\n'
' min-spaces-inside-empty: 1\n')
self.check('---\n'
'array: []\n', conf, problem=(2, 9))
self.check('---\n'
'array: [ ]\n', conf)
self.check('---\n'
'array: [ ]\n', conf)
self.check('---\n'
'array: [ ]\n', conf, problem=(2, 11))
def test_mixed_empty_nonempty(self):
conf = ('brackets:\n'
' max-spaces-inside: -1\n'
' min-spaces-inside: 1\n'
' max-spaces-inside-empty: 0\n'
' min-spaces-inside-empty: 0\n')
self.check('---\n'
'array: [ a, b ]\n', conf)
self.check('---\n'
'array: [a, b]\n', conf,
problem1=(2, 9), problem2=(2, 13))
self.check('---\n'
'array: []\n', conf)
self.check('---\n'
'array: [ ]\n', conf,
problem1=(2, 9))
conf = ('brackets:\n'
' max-spaces-inside: 0\n'
' min-spaces-inside: -1\n'
' max-spaces-inside-empty: 1\n'
' min-spaces-inside-empty: 1\n')
self.check('---\n'
'array: [ a, b ]\n', conf,
problem1=(2, 9), problem2=(2, 14))
self.check('---\n'
'array: [a, b]\n', conf)
self.check('---\n'
'array: []\n', conf,
problem1=(2, 9))
self.check('---\n'
'array: [ ]\n', conf)
conf = ('brackets:\n'
' max-spaces-inside: 2\n'
' min-spaces-inside: 1\n'
' max-spaces-inside-empty: 1\n'
' min-spaces-inside-empty: 1\n')
self.check('---\n'
'array: [ a, b ]\n', conf)
self.check('---\n'
'array: [a, b ]\n', conf,
problem1=(2, 9), problem2=(2, 15))
self.check('---\n'
'array: []\n', conf,
problem1=(2, 9))
self.check('---\n'
'array: [ ]\n', conf)
self.check('---\n'
'array: [ ]\n', conf,
problem1=(2, 11))
conf = ('brackets:\n'
' max-spaces-inside: 1\n'
' min-spaces-inside: 1\n'
' max-spaces-inside-empty: 1\n'
' min-spaces-inside-empty: 1\n')
self.check('---\n'
'array: [ a, b ]\n', conf)
self.check('---\n'
'array: [a, b]\n', conf,
problem1=(2, 9), problem2=(2, 13))
self.check('---\n'
'array: []\n', conf,
problem1=(2, 9))
self.check('---\n'
'array: [ ]\n', conf)

View File

@@ -14,7 +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/>.
from tests.rules.common import RuleTestCase
from tests.common import RuleTestCase
class ColonTestCase(RuleTestCase):

View File

@@ -14,7 +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/>.
from tests.rules.common import RuleTestCase
from tests.common import RuleTestCase
class CommaTestCase(RuleTestCase):
@@ -33,9 +33,25 @@ class CommaTestCase(RuleTestCase):
' key2: val2,\n'
'}\n'
'...\n', conf)
self.check('---\n'
'- [one, two , three,four]\n'
'- {five,six , seven, eight}\n'
'- [\n'
' nine, ten\n'
' , eleven\n'
' ,twelve\n'
']\n'
'- {\n'
' thirteen: 13, fourteen\n'
' , fifteen: 15\n'
' ,sixteen: 16\n'
'}\n', conf)
def test_before_enabled(self):
conf = 'commas: {max-spaces-before: 0, max-spaces-after: -1}'
def test_before_max(self):
conf = ('commas:\n'
' max-spaces-before: 0\n'
' min-spaces-after: 0\n'
' max-spaces-after: -1\n')
self.check('---\n'
'array: [1, 2, 3, 4]\n'
'...\n', conf)
@@ -75,8 +91,51 @@ class CommaTestCase(RuleTestCase):
' key2: val2 ,\n'
'}\n', conf, problem=(4, 13))
def test_before_max(self):
conf = 'commas: {max-spaces-before: 3, max-spaces-after: -1}'
def test_before_max_with_comma_on_new_line(self):
conf = ('commas:\n'
' max-spaces-before: 0\n'
' min-spaces-after: 0\n'
' max-spaces-after: -1\n')
self.check('---\n'
'flow-seq: [1, 2, 3\n'
' , 4, 5, 6]\n'
'...\n', conf, problem=(3, 11))
self.check('---\n'
'flow-map: {a: 1, b: 2\n'
' , c: 3}\n'
'...\n', conf, problem=(3, 11))
conf = ('commas:\n'
' max-spaces-before: 0\n'
' min-spaces-after: 0\n'
' max-spaces-after: -1\n'
'indentation: disable\n')
self.check('---\n'
'flow-seq: [1, 2, 3\n'
' , 4, 5, 6]\n'
'...\n', conf, problem=(3, 9))
self.check('---\n'
'flow-map: {a: 1, b: 2\n'
' , c: 3}\n'
'...\n', conf, problem=(3, 9))
self.check('---\n'
'[\n'
'1,\n'
'2\n'
', 3\n'
']\n', conf, problem=(5, 1))
self.check('---\n'
'{\n'
'a: 1,\n'
'b: 2\n'
', c: 3\n'
'}\n', conf, problem=(5, 1))
def test_before_max_3(self):
conf = ('commas:\n'
' max-spaces-before: 3\n'
' min-spaces-after: 0\n'
' max-spaces-after: -1\n')
self.check('---\n'
'array: [1 , 2, 3 , 4]\n'
'...\n', conf)
@@ -90,8 +149,32 @@ class CommaTestCase(RuleTestCase):
' key: val,\n'
']\n', conf, problem=(4, 11))
def test_after_enabled(self):
conf = 'commas: {max-spaces-before: -1, max-spaces-after: 1}'
def test_after_min(self):
conf = ('commas:\n'
' max-spaces-before: -1\n'
' min-spaces-after: 1\n'
' max-spaces-after: -1\n')
self.check('---\n'
'- [one, two , three,four]\n'
'- {five,six , seven, eight}\n'
'- [\n'
' nine, ten\n'
' , eleven\n'
' ,twelve\n'
']\n'
'- {\n'
' thirteen: 13, fourteen\n'
' , fifteen: 15\n'
' ,sixteen: 16\n'
'}\n', conf,
problem1=(2, 21), problem2=(3, 9),
problem3=(7, 4), problem4=(12, 4))
def test_after_max(self):
conf = ('commas:\n'
' max-spaces-before: -1\n'
' min-spaces-after: 0\n'
' max-spaces-after: 1\n')
self.check('---\n'
'array: [1, 2, 3, 4]\n'
'...\n', conf)
@@ -124,8 +207,11 @@ class CommaTestCase(RuleTestCase):
' key1: val1, key2: [val2, val3]\n'
'}\n', conf, problem1=(3, 16), problem2=(3, 30))
def test_after_max(self):
conf = 'commas: {max-spaces-before: -1, max-spaces-after: 3}'
def test_after_max_3(self):
conf = ('commas:\n'
' max-spaces-before: -1\n'
' min-spaces-after: 1\n'
' max-spaces-after: 3\n')
self.check('---\n'
'array: [1, 2, 3, 4]\n'
'...\n', conf)
@@ -137,7 +223,10 @@ class CommaTestCase(RuleTestCase):
'...\n', conf, problem1=(2, 31), problem2=(2, 49))
def test_both_before_and_after(self):
conf = 'commas: {max-spaces-before: 0, max-spaces-after: 1}'
conf = ('commas:\n'
' max-spaces-before: 0\n'
' min-spaces-after: 1\n'
' max-spaces-after: 1\n')
self.check('---\n'
'dict: {a: b , c: "1 2 3", d: e , f: [g, h]}\n'
'array: [\n'
@@ -152,36 +241,25 @@ class CommaTestCase(RuleTestCase):
problem1=(2, 12), problem2=(2, 16), problem3=(2, 31),
problem4=(2, 36), problem5=(2, 50), problem6=(4, 8),
problem7=(5, 11), problem8=(8, 13))
def test_comma_on_new_line(self):
conf = 'commas: {max-spaces-before: 0, max-spaces-after: 1}'
self.check('---\n'
'flow-seq: [1, 2, 3\n'
' , 4, 5, 6]\n'
'...\n', conf, problem=(3, 11))
self.check('---\n'
'flow-map: {a: 1, b: 2\n'
' , c: 3}\n'
'...\n', conf, problem=(3, 11))
conf = ('commas: {max-spaces-before: 0, max-spaces-after: 1}\n'
conf = ('commas:\n'
' max-spaces-before: 0\n'
' min-spaces-after: 1\n'
' max-spaces-after: 1\n'
'indentation: disable\n')
self.check('---\n'
'flow-seq: [1, 2, 3\n'
' , 4, 5, 6]\n'
'...\n', conf, problem=(3, 9))
self.check('---\n'
'flow-map: {a: 1, b: 2\n'
' , c: 3}\n'
'...\n', conf, problem=(3, 9))
self.check('---\n'
'[\n'
'1,\n'
'2\n'
', 3\n'
']\n', conf, problem=(5, 1))
self.check('---\n'
'{\n'
'a: 1,\n'
'b: 2\n'
', c: 3\n'
'}\n', conf, problem=(5, 1))
'- [one, two , three,four]\n'
'- {five,six , seven, eight}\n'
'- [\n'
' nine, ten\n'
' , eleven\n'
' ,twelve\n'
']\n'
'- {\n'
' thirteen: 13, fourteen\n'
' , fifteen: 15\n'
' ,sixteen: 16\n'
'}\n', conf,
problem1=(2, 12), problem2=(2, 21), problem3=(3, 9),
problem4=(3, 12), problem5=(5, 9), problem6=(6, 2),
problem7=(7, 2), problem8=(7, 4), problem9=(10, 17),
problem10=(11, 2), problem11=(12, 2), problem12=(12, 4))

View File

@@ -14,7 +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/>.
from tests.rules.common import RuleTestCase
from tests.common import RuleTestCase
class CommentsTestCase(RuleTestCase):
@@ -35,11 +35,15 @@ class CommentsTestCase(RuleTestCase):
' #comment 3 bis\n'
' # comment 3 ter\n'
'\n'
'################################\n'
'## comment 4\n'
'##comment 5\n'
'\n'
'string: "Une longue phrase." # this is French\n', conf)
def test_starting_space(self):
conf = ('comments:\n'
' require-starting-space: yes\n'
' require-starting-space: true\n'
' min-spaces-from-content: -1\n'
'comments-indentation: disable\n')
self.check('---\n'
@@ -52,7 +56,11 @@ class CommentsTestCase(RuleTestCase):
'# comment 2\n'
'# comment 3\n'
' # comment 3 bis\n'
' # comment 3 ter\n', conf)
' # comment 3 ter\n'
'\n'
'################################\n'
'## comment 4\n'
'## comment 5\n', conf)
self.check('---\n'
'#comment\n'
'\n'
@@ -63,13 +71,60 @@ class CommentsTestCase(RuleTestCase):
'# comment 2\n'
'#comment 3\n'
' #comment 3 bis\n'
' # comment 3 ter\n', conf,
' # comment 3 ter\n'
'\n'
'################################\n'
'## comment 4\n'
'##comment 5\n', conf,
problem1=(2, 2), problem2=(6, 13),
problem4=(9, 2), problem5=(10, 4))
problem3=(9, 2), problem4=(10, 4),
problem5=(15, 3))
def test_shebang(self):
conf = ('comments:\n'
' require-starting-space: true\n'
' ignore-shebangs: false\n'
'comments-indentation: disable\n'
'document-start: disable\n')
self.check('#!/bin/env my-interpreter\n',
conf, problem1=(1, 2))
self.check('# comment\n'
'#!/bin/env my-interpreter\n', conf,
problem1=(2, 2))
self.check('#!/bin/env my-interpreter\n'
'---\n'
'#comment\n'
'#!/bin/env my-interpreter\n'
'', conf,
problem1=(1, 2), problem2=(3, 2), problem3=(4, 2))
self.check('#! not a shebang\n',
conf, problem1=(1, 2))
self.check('key: #!/not/a/shebang\n',
conf, problem1=(1, 8))
def test_ignore_shebang(self):
conf = ('comments:\n'
' require-starting-space: true\n'
' ignore-shebangs: true\n'
'comments-indentation: disable\n'
'document-start: disable\n')
self.check('#!/bin/env my-interpreter\n', conf)
self.check('# comment\n'
'#!/bin/env my-interpreter\n', conf,
problem1=(2, 2))
self.check('#!/bin/env my-interpreter\n'
'---\n'
'#comment\n'
'#!/bin/env my-interpreter\n', conf,
problem2=(3, 2), problem3=(4, 2))
self.check('#! not a shebang\n',
conf, problem1=(1, 2))
self.check('key: #!/not/a/shebang\n',
conf, problem1=(1, 8))
def test_spaces_from_content(self):
conf = ('comments:\n'
' require-starting-space: no\n'
' require-starting-space: false\n'
' min-spaces-from-content: 2\n')
self.check('---\n'
'# comment\n'
@@ -91,7 +146,7 @@ class CommentsTestCase(RuleTestCase):
def test_both(self):
conf = ('comments:\n'
' require-starting-space: yes\n'
' require-starting-space: true\n'
' min-spaces-from-content: 2\n'
'comments-indentation: disable\n')
self.check('---\n'
@@ -106,17 +161,22 @@ class CommentsTestCase(RuleTestCase):
' #comment 3 bis\n'
' # comment 3 ter\n'
'\n'
'################################\n'
'## comment 4\n'
'##comment 5\n'
'\n'
'string: "Une longue phrase." # this is French\n', conf,
problem1=(2, 2),
problem2=(4, 7),
problem3=(6, 11), problem4=(6, 12),
problem5=(9, 2),
problem6=(10, 4),
problem7=(13, 30))
problem7=(15, 3),
problem8=(17, 30))
def test_empty_comment(self):
conf = ('comments:\n'
' require-starting-space: yes\n'
' require-starting-space: true\n'
' min-spaces-from-content: 2\n')
self.check('---\n'
'# This is paragraph 1.\n'
@@ -126,15 +186,44 @@ class CommentsTestCase(RuleTestCase):
'inline: comment #\n'
'foo: bar\n', conf)
def test_empty_comment_crlf_dos_newlines(self):
conf = ('comments:\n'
' require-starting-space: true\n'
' min-spaces-from-content: 2\n'
'new-lines:\n'
' type: dos\n')
self.check('---\r\n'
'# This is paragraph 1.\r\n'
'#\r\n'
'# This is paragraph 2.\r\n', conf)
def test_empty_comment_crlf_disabled_newlines(self):
conf = ('comments:\n'
' require-starting-space: true\n'
' min-spaces-from-content: 2\n'
'new-lines: disable\n')
self.check('---\r\n'
'# This is paragraph 1.\r\n'
'#\r\n'
'# This is paragraph 2.\r\n', conf)
def test_first_line(self):
conf = ('comments:\n'
' require-starting-space: yes\n'
' require-starting-space: true\n'
' min-spaces-from-content: 2\n')
self.check('# comment\n', conf)
def test_last_line(self):
conf = ('comments:\n'
' require-starting-space: true\n'
' min-spaces-from-content: 2\n'
'new-line-at-end-of-file: disable\n')
self.check('# comment with no newline char:\n'
'#', conf)
def test_multi_line_scalar(self):
conf = ('comments:\n'
' require-starting-space: yes\n'
' require-starting-space: true\n'
' min-spaces-from-content: 2\n'
'trailing-spaces: disable\n')
self.check('---\n'

View File

@@ -14,7 +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/>.
from tests.rules.common import RuleTestCase
from tests.common import RuleTestCase
class CommentsIndentationTestCase(RuleTestCase):
@@ -49,7 +49,7 @@ class CommentsIndentationTestCase(RuleTestCase):
'...\n', conf)
def test_enabled(self):
conf = 'comments-indentation: {}'
conf = 'comments-indentation: enable'
self.check('---\n'
'# line 1\n'
'# line 2\n', conf)
@@ -58,7 +58,7 @@ class CommentsIndentationTestCase(RuleTestCase):
'# line 2\n', conf, problem=(2, 2))
self.check('---\n'
' # line 1\n'
' # line 2\n', conf, problem1=(2, 3), problem2=(3, 3))
' # line 2\n', conf, problem1=(2, 3))
self.check('---\n'
'obj:\n'
' # normal\n'
@@ -102,13 +102,13 @@ class CommentsIndentationTestCase(RuleTestCase):
' a: 1\n'
' # b: 2\n'
'# this object is useless\n'
'obj2: no\n', conf)
'obj2: "no"\n', conf)
self.check('---\n'
'obj1:\n'
' a: 1\n'
'# this object is useless\n'
' # b: 2\n'
'obj2: no\n', conf, problem=(5, 3))
'obj2: "no"\n', conf, problem=(5, 3))
self.check('---\n'
'obj1:\n'
' a: 1\n'
@@ -123,18 +123,18 @@ class CommentsIndentationTestCase(RuleTestCase):
'...\n', conf)
def test_first_line(self):
conf = 'comments-indentation: {}'
conf = 'comments-indentation: enable'
self.check('# comment\n', conf)
self.check(' # comment\n', conf, problem=(1, 3))
def test_no_newline_at_end(self):
conf = ('comments-indentation: {}\n'
conf = ('comments-indentation: enable\n'
'new-line-at-end-of-file: disable\n')
self.check('# comment', conf)
self.check(' # comment', conf, problem=(1, 3))
def test_empty_comment(self):
conf = 'comments-indentation: {}'
conf = 'comments-indentation: enable'
self.check('---\n'
'# hey\n'
'# normal\n'
@@ -143,3 +143,15 @@ class CommentsIndentationTestCase(RuleTestCase):
'# hey\n'
'# normal\n'
' #\n', conf, problem=(4, 2))
def test_inline_comment(self):
conf = 'comments-indentation: enable'
self.check('---\n'
'- a # inline\n'
'# ok\n', conf)
self.check('---\n'
'- a # inline\n'
' # not ok\n', conf, problem=(3, 2))
self.check('---\n'
' # not ok\n'
'- a # inline\n', conf, problem=(2, 2))

View File

@@ -18,8 +18,7 @@ import unittest
import yaml
from yamllint.rules.common import (Comment, get_line_indent,
get_comments_between_tokens)
from yamllint.rules.common import get_line_indent
class CommonTestCase(unittest.TestCase):
@@ -43,54 +42,3 @@ class CommonTestCase(unittest.TestCase):
self.assertEqual(get_line_indent(tokens[i]), 0)
for i in (13, 16, 18, 22, 24):
self.assertEqual(get_line_indent(tokens[i]), 2)
def check_comments(self, buffer, *expected):
yaml_loader = yaml.BaseLoader(buffer)
comments = []
next = yaml_loader.peek_token()
while next is not None:
curr = yaml_loader.get_token()
next = yaml_loader.peek_token()
for comment in get_comments_between_tokens(curr, next):
comments.append(comment)
self.assertEqual(comments, list(expected))
def test_get_comments_between_tokens(self):
self.check_comments('# comment\n',
Comment(1, 1, '# comment', 0))
self.check_comments('---\n'
'# comment\n'
'...\n',
Comment(2, 1, '# comment', 0))
self.check_comments('---\n'
'# no newline char',
Comment(2, 1, '# no newline char', 0))
self.check_comments('# just comment',
Comment(1, 1, '# just comment', 0))
self.check_comments('\n'
' # indented comment\n',
Comment(2, 4, '# indented comment', 0))
self.check_comments('\n'
'# trailing spaces \n',
Comment(2, 1, '# trailing spaces ', 0))
self.check_comments('# comment one\n'
'\n'
'key: val # key=val\n'
'\n'
'# this is\n'
'# a block \n'
'# comment\n'
'\n'
'other:\n'
' - foo # equals\n'
' # bar\n',
Comment(1, 1, '# comment one', 0),
Comment(3, 11, '# key=val', 0),
Comment(5, 1, '# this is', 0),
Comment(6, 1, '# a block ', 0),
Comment(7, 1, '# comment', 0),
Comment(10, 10, '# equals', 0),
Comment(11, 10, '# bar', 0))

View File

@@ -14,7 +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/>.
from tests.rules.common import RuleTestCase
from tests.common import RuleTestCase
class DocumentEndTestCase(RuleTestCase):
@@ -31,7 +31,7 @@ class DocumentEndTestCase(RuleTestCase):
' document: end\n', conf)
def test_required(self):
conf = 'document-end: {present: yes}'
conf = 'document-end: {present: true}'
self.check('', conf)
self.check('\n', conf)
self.check('---\n'
@@ -43,7 +43,7 @@ class DocumentEndTestCase(RuleTestCase):
' document: end\n', conf, problem=(3, 1))
def test_forbidden(self):
conf = 'document-end: {present: no}'
conf = 'document-end: {present: false}'
self.check('---\n'
'with:\n'
' document: end\n'
@@ -53,7 +53,7 @@ class DocumentEndTestCase(RuleTestCase):
' document: end\n', conf)
def test_multiple_documents(self):
conf = ('document-end: {present: yes}\n'
conf = ('document-end: {present: true}\n'
'document-start: disable\n')
self.check('---\n'
'first: document\n'

View File

@@ -14,7 +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/>.
from tests.rules.common import RuleTestCase
from tests.common import RuleTestCase
class DocumentStartTestCase(RuleTestCase):
@@ -28,7 +28,7 @@ class DocumentStartTestCase(RuleTestCase):
'key: val\n', conf)
def test_required(self):
conf = ('document-start: {present: yes}\n'
conf = ('document-start: {present: true}\n'
'empty-lines: disable\n')
self.check('', conf)
self.check('\n', conf)
@@ -44,7 +44,7 @@ class DocumentStartTestCase(RuleTestCase):
'key: val\n', conf)
def test_forbidden(self):
conf = ('document-start: {present: no}\n'
conf = ('document-start: {present: false}\n'
'empty-lines: disable\n')
self.check('', conf)
self.check('key: val\n', conf)
@@ -62,7 +62,7 @@ class DocumentStartTestCase(RuleTestCase):
'key: val\n', conf, problem=(2, 1))
def test_multiple_documents(self):
conf = 'document-start: {present: yes}'
conf = 'document-start: {present: true}'
self.check('---\n'
'first: document\n'
'...\n'
@@ -85,7 +85,7 @@ class DocumentStartTestCase(RuleTestCase):
'third: document\n', conf, problem=(4, 1, 'syntax'))
def test_directives(self):
conf = 'document-start: {present: yes}'
conf = 'document-start: {present: true}'
self.check('%YAML 1.2\n'
'---\n'
'doc: ument\n'

View File

@@ -14,7 +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/>.
from tests.rules.common import RuleTestCase
from tests.common import RuleTestCase
class EmptyLinesTestCase(RuleTestCase):
@@ -78,3 +78,22 @@ class EmptyLinesTestCase(RuleTestCase):
'document-start: disable\n')
self.check('non empty\n', conf)
self.check('non empty\n\n', conf, problem=(2, 1))
def test_with_dos_newlines(self):
conf = ('empty-lines: {max: 2, max-start: 0, max-end: 0}\n'
'new-lines: {type: dos}\n'
'document-start: disable\n')
self.check('---\r\n', conf)
self.check('---\r\ntext\r\n\r\ntext\r\n', conf)
self.check('\r\n---\r\ntext\r\n\r\ntext\r\n', conf,
problem=(1, 1))
self.check('\r\n\r\n\r\n---\r\ntext\r\n\r\ntext\r\n', conf,
problem=(3, 1))
self.check('---\r\ntext\r\n\r\n\r\n\r\ntext\r\n', conf,
problem=(5, 1))
self.check('---\r\ntext\r\n\r\n\r\n\r\n\r\n\r\n\r\ntext\r\n', conf,
problem=(8, 1))
self.check('---\r\ntext\r\n\r\ntext\r\n\r\n', conf,
problem=(5, 1))
self.check('---\r\ntext\r\n\r\ntext\r\n\r\n\r\n\r\n', conf,
problem=(7, 1))

View File

@@ -0,0 +1,261 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2017 Greg Dubicki
#
# 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 EmptyValuesTestCase(RuleTestCase):
rule_id = 'empty-values'
def test_disabled(self):
conf = ('empty-values: disable\n'
'braces: disable\n'
'commas: disable\n')
self.check('---\n'
'foo:\n', conf)
self.check('---\n'
'foo:\n'
' bar:\n', conf)
self.check('---\n'
'{a:}\n', conf)
self.check('---\n'
'foo: {a:}\n', conf)
self.check('---\n'
'- {a:}\n'
'- {a:, b: 2}\n'
'- {a: 1, b:}\n'
'- {a: 1, b: , }\n', conf)
self.check('---\n'
'{a: {b: , c: {d: 4, e:}}, f:}\n', conf)
def test_in_block_mappings_disabled(self):
conf = ('empty-values: {forbid-in-block-mappings: false,\n'
' forbid-in-flow-mappings: false}\n')
self.check('---\n'
'foo:\n', conf)
self.check('---\n'
'foo:\n'
'bar: aaa\n', conf)
def test_in_block_mappings_single_line(self):
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
' forbid-in-flow-mappings: false}\n')
self.check('---\n'
'implicitly-null:\n', conf, problem1=(2, 17))
self.check('---\n'
'implicitly-null:with-colons:in-key:\n', conf,
problem1=(2, 36))
self.check('---\n'
'implicitly-null:with-colons:in-key2:\n', conf,
problem1=(2, 37))
def test_in_block_mappings_all_lines(self):
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
' forbid-in-flow-mappings: false}\n')
self.check('---\n'
'foo:\n'
'bar:\n'
'foobar:\n', conf, problem1=(2, 5),
problem2=(3, 5), problem3=(4, 8))
def test_in_block_mappings_explicit_end_of_document(self):
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
' forbid-in-flow-mappings: false}\n')
self.check('---\n'
'foo:\n'
'...\n', conf, problem1=(2, 5))
def test_in_block_mappings_not_end_of_document(self):
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
' forbid-in-flow-mappings: false}\n')
self.check('---\n'
'foo:\n'
'bar:\n'
' aaa\n', conf, problem1=(2, 5))
def test_in_block_mappings_different_level(self):
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
' forbid-in-flow-mappings: false}\n')
self.check('---\n'
'foo:\n'
' bar:\n'
'aaa: bbb\n', conf, problem1=(3, 6))
def test_in_block_mappings_empty_flow_mapping(self):
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
' forbid-in-flow-mappings: false}\n'
'braces: disable\n'
'commas: disable\n')
self.check('---\n'
'foo: {a:}\n', conf)
self.check('---\n'
'- {a:, b: 2}\n'
'- {a: 1, b:}\n'
'- {a: 1, b: , }\n', conf)
def test_in_block_mappings_empty_block_sequence(self):
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
' forbid-in-flow-mappings: false}\n')
self.check('---\n'
'foo:\n'
' -\n', conf)
def test_in_block_mappings_not_empty_or_explicit_null(self):
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
' forbid-in-flow-mappings: false}\n')
self.check('---\n'
'foo:\n'
' bar:\n'
' aaa\n', conf)
self.check('---\n'
'explicitly-null: null\n', conf)
self.check('---\n'
'explicitly-null:with-colons:in-key: null\n', conf)
self.check('---\n'
'false-null: nulL\n', conf)
self.check('---\n'
'empty-string: \'\'\n', conf)
self.check('---\n'
'nullable-boolean: false\n', conf)
self.check('---\n'
'nullable-int: 0\n', conf)
self.check('---\n'
'First occurrence: &anchor Foo\n'
'Second occurrence: *anchor\n', conf)
def test_in_block_mappings_various_explicit_null(self):
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
' forbid-in-flow-mappings: false}\n')
self.check('---\n'
'null-alias: ~\n', conf)
self.check('---\n'
'null-key1: {?: val}\n', conf)
self.check('---\n'
'null-key2: {? !!null "": val}\n', conf)
def test_in_block_mappings_comments(self):
conf = ('empty-values: {forbid-in-block-mappings: true,\n'
' forbid-in-flow-mappings: false}\n'
'comments: disable\n')
self.check('---\n'
'empty: # comment\n'
'foo:\n'
' bar: # comment\n', conf,
problem1=(2, 7),
problem2=(4, 7))
def test_in_flow_mappings_disabled(self):
conf = ('empty-values: {forbid-in-block-mappings: false,\n'
' forbid-in-flow-mappings: false}\n'
'braces: disable\n'
'commas: disable\n')
self.check('---\n'
'{a:}\n', conf)
self.check('---\n'
'foo: {a:}\n', conf)
self.check('---\n'
'- {a:}\n'
'- {a:, b: 2}\n'
'- {a: 1, b:}\n'
'- {a: 1, b: , }\n', conf)
self.check('---\n'
'{a: {b: , c: {d: 4, e:}}, f:}\n', conf)
def test_in_flow_mappings_single_line(self):
conf = ('empty-values: {forbid-in-block-mappings: false,\n'
' forbid-in-flow-mappings: true}\n'
'braces: disable\n'
'commas: disable\n')
self.check('---\n'
'{a:}\n', conf,
problem=(2, 4))
self.check('---\n'
'foo: {a:}\n', conf,
problem=(2, 9))
self.check('---\n'
'- {a:}\n'
'- {a:, b: 2}\n'
'- {a: 1, b:}\n'
'- {a: 1, b: , }\n', conf,
problem1=(2, 6),
problem2=(3, 6),
problem3=(4, 12),
problem4=(5, 12))
self.check('---\n'
'{a: {b: , c: {d: 4, e:}}, f:}\n', conf,
problem1=(2, 8),
problem2=(2, 23),
problem3=(2, 29))
def test_in_flow_mappings_multi_line(self):
conf = ('empty-values: {forbid-in-block-mappings: false,\n'
' forbid-in-flow-mappings: true}\n'
'braces: disable\n'
'commas: disable\n')
self.check('---\n'
'foo: {\n'
' a:\n'
'}\n', conf,
problem=(3, 5))
self.check('---\n'
'{\n'
' a: {\n'
' b: ,\n'
' c: {\n'
' d: 4,\n'
' e:\n'
' }\n'
' },\n'
' f:\n'
'}\n', conf,
problem1=(4, 7),
problem2=(7, 9),
problem3=(10, 5))
def test_in_flow_mappings_various_explicit_null(self):
conf = ('empty-values: {forbid-in-block-mappings: false,\n'
' forbid-in-flow-mappings: true}\n'
'braces: disable\n'
'commas: disable\n')
self.check('---\n'
'{explicit-null: null}\n', conf)
self.check('---\n'
'{null-alias: ~}\n', conf)
self.check('---\n'
'null-key1: {?: val}\n', conf)
self.check('---\n'
'null-key2: {? !!null "": val}\n', conf)
def test_in_flow_mappings_comments(self):
conf = ('empty-values: {forbid-in-block-mappings: false,\n'
' forbid-in-flow-mappings: true}\n'
'braces: disable\n'
'commas: disable\n'
'comments: disable\n')
self.check('---\n'
'{\n'
' a: {\n'
' b: , # comment\n'
' c: {\n'
' d: 4, # comment\n'
' e: # comment\n'
' }\n'
' },\n'
' f: # comment\n'
'}\n', conf,
problem1=(4, 7),
problem2=(7, 9),
problem3=(10, 5))

View File

@@ -14,7 +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/>.
from tests.rules.common import RuleTestCase
from tests.common import RuleTestCase
class HyphenTestCase(RuleTestCase):

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,174 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# 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 KeyDuplicatesTestCase(RuleTestCase):
rule_id = 'key-duplicates'
def test_disabled(self):
conf = 'key-duplicates: disable'
self.check('---\n'
'block mapping:\n'
' key: a\n'
' otherkey: b\n'
' key: c\n', conf)
self.check('---\n'
'flow mapping:\n'
' {key: a, otherkey: b, key: c}\n', conf)
self.check('---\n'
'duplicated twice:\n'
' - k: a\n'
' ok: b\n'
' k: c\n'
' k: d\n', conf)
self.check('---\n'
'duplicated twice:\n'
' - {k: a, ok: b, k: c, k: d}\n', conf)
self.check('---\n'
'multiple duplicates:\n'
' a: 1\n'
' b: 2\n'
' c: 3\n'
' d: 4\n'
' d: 5\n'
' b: 6\n', conf)
self.check('---\n'
'multiple duplicates:\n'
' {a: 1, b: 2, c: 3, d: 4, d: 5, b: 6}\n', conf)
self.check('---\n'
'at: root\n'
'multiple: times\n'
'at: root\n', conf)
self.check('---\n'
'nested but OK:\n'
' a: {a: {a: 1}}\n'
' b:\n'
' b: 2\n'
' c: 3\n', conf)
self.check('---\n'
'nested duplicates:\n'
' a: {a: 1, a: 1}\n'
' b:\n'
' c: 3\n'
' d: 4\n'
' d: 4\n'
' b: 2\n', conf)
self.check('---\n'
'duplicates with many styles: 1\n'
'"duplicates with many styles": 1\n'
'\'duplicates with many styles\': 1\n'
'? duplicates with many styles\n'
': 1\n'
'? >-\n'
' duplicates with\n'
' many styles\n'
': 1\n', conf)
self.check('---\n'
'Merge Keys are OK:\n'
'anchor_one: &anchor_one\n'
' one: one\n'
'anchor_two: &anchor_two\n'
' two: two\n'
'anchor_reference:\n'
' <<: *anchor_one\n'
' <<: *anchor_two\n', conf)
def test_enabled(self):
conf = 'key-duplicates: enable'
self.check('---\n'
'block mapping:\n'
' key: a\n'
' otherkey: b\n'
' key: c\n', conf,
problem=(5, 3))
self.check('---\n'
'flow mapping:\n'
' {key: a, otherkey: b, key: c}\n', conf,
problem=(3, 25))
self.check('---\n'
'duplicated twice:\n'
' - k: a\n'
' ok: b\n'
' k: c\n'
' k: d\n', conf,
problem1=(5, 5), problem2=(6, 5))
self.check('---\n'
'duplicated twice:\n'
' - {k: a, ok: b, k: c, k: d}\n', conf,
problem1=(3, 19), problem2=(3, 25))
self.check('---\n'
'multiple duplicates:\n'
' a: 1\n'
' b: 2\n'
' c: 3\n'
' d: 4\n'
' d: 5\n'
' b: 6\n', conf,
problem1=(7, 3), problem2=(8, 3))
self.check('---\n'
'multiple duplicates:\n'
' {a: 1, b: 2, c: 3, d: 4, d: 5, b: 6}\n', conf,
problem1=(3, 28), problem2=(3, 34))
self.check('---\n'
'at: root\n'
'multiple: times\n'
'at: root\n', conf,
problem=(4, 1))
self.check('---\n'
'nested but OK:\n'
' a: {a: {a: 1}}\n'
' b:\n'
' b: 2\n'
' c: 3\n', conf)
self.check('---\n'
'nested duplicates:\n'
' a: {a: 1, a: 1}\n'
' b:\n'
' c: 3\n'
' d: 4\n'
' d: 4\n'
' b: 2\n', conf,
problem1=(3, 13), problem2=(7, 5), problem3=(8, 3))
self.check('---\n'
'duplicates with many styles: 1\n'
'"duplicates with many styles": 1\n'
'\'duplicates with many styles\': 1\n'
'? duplicates with many styles\n'
': 1\n'
'? >-\n'
' duplicates with\n'
' many styles\n'
': 1\n', conf,
problem1=(3, 1), problem2=(4, 1), problem3=(5, 3),
problem4=(7, 3))
self.check('---\n'
'Merge Keys are OK:\n'
'anchor_one: &anchor_one\n'
' one: one\n'
'anchor_two: &anchor_two\n'
' two: two\n'
'anchor_reference:\n'
' <<: *anchor_one\n'
' <<: *anchor_two\n', conf)
def test_key_tokens_in_flow_sequences(self):
conf = 'key-duplicates: enable'
self.check('---\n'
'[\n'
' flow: sequence, with, key: value, mappings\n'
']\n', conf)

View File

@@ -0,0 +1,150 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2017 Johannes F. Knauf
#
# 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/>.
import locale
from tests.common import RuleTestCase
class KeyOrderingTestCase(RuleTestCase):
rule_id = 'key-ordering'
def test_disabled(self):
conf = 'key-ordering: disable'
self.check('---\n'
'block mapping:\n'
' secondkey: a\n'
' firstkey: b\n', conf)
self.check('---\n'
'flow mapping:\n'
' {secondkey: a, firstkey: b}\n', conf)
self.check('---\n'
'second: before_first\n'
'at: root\n', conf)
self.check('---\n'
'nested but OK:\n'
' second: {first: 1}\n'
' third:\n'
' second: 2\n', conf)
def test_enabled(self):
conf = 'key-ordering: enable'
self.check('---\n'
'block mapping:\n'
' secondkey: a\n'
' firstkey: b\n', conf,
problem=(4, 3))
self.check('---\n'
'flow mapping:\n'
' {secondkey: a, firstkey: b}\n', conf,
problem=(3, 18))
self.check('---\n'
'second: before_first\n'
'at: root\n', conf,
problem=(3, 1))
self.check('---\n'
'nested but OK:\n'
' second: {first: 1}\n'
' third:\n'
' second: 2\n', conf)
def test_word_length(self):
conf = 'key-ordering: enable'
self.check('---\n'
'a: 1\n'
'ab: 1\n'
'abc: 1\n', conf)
self.check('---\n'
'a: 1\n'
'abc: 1\n'
'ab: 1\n', conf,
problem=(4, 1))
def test_key_duplicates(self):
conf = ('key-duplicates: disable\n'
'key-ordering: enable')
self.check('---\n'
'key: 1\n'
'key: 2\n', conf)
def test_case(self):
conf = 'key-ordering: enable'
self.check('---\n'
'T-shirt: 1\n'
'T-shirts: 2\n'
't-shirt: 3\n'
't-shirts: 4\n', conf)
self.check('---\n'
'T-shirt: 1\n'
't-shirt: 2\n'
'T-shirts: 3\n'
't-shirts: 4\n', conf,
problem=(4, 1))
def test_accents(self):
conf = 'key-ordering: enable'
self.check('---\n'
'hair: true\n'
'hais: true\n'
'haïr: true\n'
'haïssable: true\n', conf)
self.check('---\n'
'haïr: true\n'
'hais: true\n', conf,
problem=(3, 1))
def test_key_tokens_in_flow_sequences(self):
conf = 'key-ordering: enable'
self.check('---\n'
'[\n'
' key: value, mappings, in, flow: sequence\n'
']\n', conf)
def test_locale_case(self):
self.addCleanup(locale.setlocale, locale.LC_ALL, (None, None))
try:
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
except locale.Error:
self.skipTest('locale en_US.UTF-8 not available')
conf = ('key-ordering: enable')
self.check('---\n'
't-shirt: 1\n'
'T-shirt: 2\n'
't-shirts: 3\n'
'T-shirts: 4\n', conf)
self.check('---\n'
't-shirt: 1\n'
't-shirts: 2\n'
'T-shirt: 3\n'
'T-shirts: 4\n', conf,
problem=(4, 1))
def test_locale_accents(self):
self.addCleanup(locale.setlocale, locale.LC_ALL, (None, None))
try:
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
except locale.Error:
self.skipTest('locale en_US.UTF-8 not available')
conf = ('key-ordering: enable')
self.check('---\n'
'hair: true\n'
'haïr: true\n'
'hais: true\n'
'haïssable: true\n', conf)
self.check('---\n'
'hais: true\n'
'haïr: true\n', conf,
problem=(3, 1))

View File

@@ -14,7 +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/>.
from tests.rules.common import RuleTestCase
from tests.common import RuleTestCase
class LineLengthTestCase(RuleTestCase):
@@ -32,6 +32,9 @@ class LineLengthTestCase(RuleTestCase):
self.check('---\n' + 81 * 'a' + '\n', conf)
self.check(1000 * 'b', conf)
self.check('---\n' + 1000 * 'b' + '\n', conf)
self.check('content: |\n'
' {% this line is' + 99 * ' really' + ' long %}\n',
conf)
def test_default(self):
conf = ('line-length: {max: 80}\n'
@@ -63,7 +66,7 @@ class LineLengthTestCase(RuleTestCase):
self.check('---\n' + 81 * ' ' + '\n', conf, problem=(2, 81))
def test_non_breakable_word(self):
conf = 'line-length: {max: 20, allow-non-breakable-words: yes}'
conf = 'line-length: {max: 20, allow-non-breakable-words: true}'
self.check('---\n' + 30 * 'A' + '\n', conf)
self.check('---\n'
'this:\n'
@@ -78,8 +81,17 @@ class LineLengthTestCase(RuleTestCase):
' # http://localhost/very/long/url\n'
' comment\n'
'...\n', conf)
self.check('---\n'
'this:\n'
'is:\n'
'another:\n'
' - https://localhost/very/very/long/url\n'
'...\n', conf)
self.check('---\n'
'long_line: http://localhost/very/very/long/url\n', conf,
problem=(2, 21))
conf = 'line-length: {max: 20, allow-non-breakable-words: no}'
conf = 'line-length: {max: 20, allow-non-breakable-words: false}'
self.check('---\n' + 30 * 'A' + '\n', conf, problem=(2, 21))
self.check('---\n'
'this:\n'
@@ -94,3 +106,94 @@ class LineLengthTestCase(RuleTestCase):
' # http://localhost/very/long/url\n'
' comment\n'
'...\n', conf, problem=(5, 21))
self.check('---\n'
'this:\n'
'is:\n'
'another:\n'
' - https://localhost/very/very/long/url\n'
'...\n', conf, problem=(5, 21))
self.check('---\n'
'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'
'loooooooooong+word+and+some+space+at+the+end \n',
conf, problem=(2, 21))
def test_non_breakable_inline_mappings(self):
conf = 'line-length: {max: 20, ' \
'allow-non-breakable-inline-mappings: true}'
self.check('---\n'
'long_line: http://localhost/very/very/long/url\n'
'long line: http://localhost/very/very/long/url\n', conf)
self.check('---\n'
'- long line: http://localhost/very/very/long/url\n', conf)
self.check('---\n'
'long_line: http://localhost/short/url + word\n'
'long line: http://localhost/short/url + word\n',
conf, problem1=(2, 21), problem2=(3, 21))
conf = ('line-length: {max: 20,'
' allow-non-breakable-inline-mappings: true}\n'
'trailing-spaces: disable')
self.check('---\n'
'long_line: and+some+space+at+the+end \n',
conf, problem=(2, 21))
self.check('---\n'
'long line: and+some+space+at+the+end \n',
conf, problem=(2, 21))
self.check('---\n'
'- long line: and+some+space+at+the+end \n',
conf, problem=(2, 21))
# See https://github.com/adrienverge/yamllint/issues/21
conf = 'line-length: {allow-non-breakable-inline-mappings: true}'
self.check('---\n'
'content: |\n'
' {% this line is' + 99 * ' really' + ' long %}\n',
conf, problem=(3, 81))
def test_unicode(self):
conf = 'line-length: {max: 53}'
self.check('---\n'
'# This is a test to check if “line-length” works nice\n'
'with: “unicode characters” that span accross bytes! ↺\n',
conf)
conf = 'line-length: {max: 52}'
self.check('---\n'
'# This is a test to check if “line-length” works nice\n'
'with: “unicode characters” that span accross bytes! ↺\n',
conf, problem1=(2, 53), problem2=(3, 53))
def test_with_dos_newlines(self):
conf = ('line-length: {max: 10}\n'
'new-lines: {type: dos}\n'
'new-line-at-end-of-file: disable\n')
self.check('---\r\nABCD EFGHI', conf)
self.check('---\r\nABCD EFGHI\r\n', conf)
self.check('---\r\nABCD EFGHIJ', conf, problem=(2, 11))
self.check('---\r\nABCD EFGHIJ\r\n', conf, problem=(2, 11))

View File

@@ -14,7 +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/>.
from tests.rules.common import RuleTestCase
from tests.common import RuleTestCase
class NewLineAtEndOfFileTestCase(RuleTestCase):
@@ -30,7 +30,7 @@ class NewLineAtEndOfFileTestCase(RuleTestCase):
self.check('Sentence.\n', conf)
def test_enabled(self):
conf = ('new-line-at-end-of-file: {}\n'
conf = ('new-line-at-end-of-file: enable\n'
'empty-lines: disable\n'
'document-start: disable\n')
self.check('', conf)

View File

@@ -14,7 +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/>.
from tests.rules.common import RuleTestCase
from tests.common import RuleTestCase
class NewLinesTestCase(RuleTestCase):
@@ -31,16 +31,30 @@ class NewLinesTestCase(RuleTestCase):
self.check('---\r\ntext\r\n', conf)
def test_unix_type(self):
conf = 'new-lines: {type: unix}'
conf = ('new-line-at-end-of-file: disable\n'
'new-lines: {type: unix}\n')
self.check('', conf)
self.check('\r', conf)
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))
def test_unix_type_required_st_sp(self):
# If we find a CRLF when looking for Unix newlines, yamllint
# should always raise, regardless of logic with
# require-starting-space.
conf = ('new-line-at-end-of-file: disable\n'
'new-lines: {type: unix}\n'
'comments:\n'
' require-starting-space: true\n')
self.check('---\r\n#\r\n', conf, problem=(1, 4))
def test_dos_type(self):
conf = 'new-lines: {type: dos}\n'
conf = ('new-line-at-end-of-file: disable\n'
'new-lines: {type: dos}\n')
self.check('', conf)
self.check('\r', conf)
self.check('\n', conf, problem=(1, 1))
self.check('\r\n', conf)
self.check('---\ntext\n', conf, problem=(1, 4))

View File

@@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# 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 OctalValuesTestCase(RuleTestCase):
rule_id = 'octal-values'
def test_disabled(self):
conf = ('octal-values: disable\n'
'new-line-at-end-of-file: disable\n'
'document-start: disable\n')
self.check('user-city: 010', conf)
self.check('user-city: 0o10', conf)
def test_implicit_octal_values(self):
conf = ('octal-values:\n'
' forbid-implicit-octal: true\n'
' forbid-explicit-octal: false\n'
'new-line-at-end-of-file: disable\n'
'document-start: disable\n')
self.check('user-city: 010', conf, problem=(1, 15))
self.check('user-city: abc', conf)
self.check('user-city: 010,0571', conf)
self.check("user-city: '010'", conf)
self.check('user-city: "010"', conf)
self.check('user-city:\n'
' - 010', conf, problem=(2, 8))
self.check('user-city: [010]', conf, problem=(1, 16))
self.check('user-city: {beijing: 010}', conf, problem=(1, 25))
self.check('explicit-octal: 0o10', conf)
self.check('not-number: 0abc', conf)
self.check('zero: 0', conf)
self.check('hex-value: 0x10', conf)
self.check('number-values:\n'
' - 0.10\n'
' - .01\n'
' - 0e3\n', conf)
self.check('with-decimal-digits: 012345678', conf)
self.check('with-decimal-digits: 012345679', conf)
def test_explicit_octal_values(self):
conf = ('octal-values:\n'
' forbid-implicit-octal: false\n'
' forbid-explicit-octal: true\n'
'new-line-at-end-of-file: disable\n'
'document-start: disable\n')
self.check('user-city: 0o10', conf, problem=(1, 16))
self.check('user-city: abc', conf)
self.check('user-city: 0o10,0571', conf)
self.check("user-city: '0o10'", conf)
self.check('user-city:\n'
' - 0o10', conf, problem=(2, 9))
self.check('user-city: [0o10]', conf, problem=(1, 17))
self.check('user-city: {beijing: 0o10}', conf, problem=(1, 26))
self.check('implicit-octal: 010', conf)
self.check('not-number: 0oabc', conf)
self.check('zero: 0', conf)
self.check('hex-value: 0x10', conf)
self.check('number-values:\n'
' - 0.10\n'
' - .01\n'
' - 0e3\n', conf)
self.check('user-city: "010"', conf)
self.check('with-decimal-digits: 0o012345678', conf)
self.check('with-decimal-digits: 0o012345679', conf)

View File

@@ -0,0 +1,456 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2018 ClearScore
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from tests.common import RuleTestCase
from yamllint import config
class QuotedTestCase(RuleTestCase):
rule_id = 'quoted-strings'
def test_disabled(self):
conf = 'quoted-strings: disable'
self.check('---\n'
'foo: bar\n', conf)
self.check('---\n'
'foo: "bar"\n', conf)
self.check('---\n'
'foo: \'bar\'\n', conf)
self.check('---\n'
'bar: 123\n', conf)
self.check('---\n'
'bar: "123"\n', conf)
def test_quote_type_any(self):
conf = 'quoted-strings: {quote-type: any}\n'
self.check('---\n'
'boolean1: true\n'
'number1: 123\n'
'string1: foo\n' # fails
'string2: "foo"\n'
'string3: "true"\n'
'string4: "123"\n'
'string5: \'bar\'\n'
'string6: !!str genericstring\n'
'string7: !!str 456\n'
'string8: !!str "quotedgenericstring"\n'
'binary: !!binary binstring\n'
'integer: !!int intstring\n'
'boolean2: !!bool boolstring\n'
'boolean3: !!bool "quotedboolstring"\n'
'block-seq:\n'
' - foo\n' # fails
' - "foo"\n'
'flow-seq: [foo, "foo"]\n' # fails
'flow-map: {a: foo, b: "foo"}\n', # fails
conf, problem1=(4, 10), problem2=(17, 5),
problem3=(19, 12), problem4=(20, 15))
self.check('---\n'
'multiline string 1: |\n'
' line 1\n'
' line 2\n'
'multiline string 2: >\n'
' word 1\n'
' word 2\n'
'multiline string 3:\n'
' word 1\n' # fails
' word 2\n'
'multiline string 4:\n'
' "word 1\\\n'
' word 2"\n',
conf, problem1=(9, 3))
def test_quote_type_single(self):
conf = 'quoted-strings: {quote-type: single}\n'
self.check('---\n'
'boolean1: true\n'
'number1: 123\n'
'string1: foo\n' # fails
'string2: "foo"\n' # fails
'string3: "true"\n' # fails
'string4: "123"\n' # fails
'string5: \'bar\'\n'
'string6: !!str genericstring\n'
'string7: !!str 456\n'
'string8: !!str "quotedgenericstring"\n'
'binary: !!binary binstring\n'
'integer: !!int intstring\n'
'boolean2: !!bool boolstring\n'
'boolean3: !!bool "quotedboolstring"\n'
'block-seq:\n'
' - foo\n' # fails
' - "foo"\n' # fails
'flow-seq: [foo, "foo"]\n' # fails
'flow-map: {a: foo, b: "foo"}\n', # fails
conf, problem1=(4, 10), problem2=(5, 10), problem3=(6, 10),
problem4=(7, 10), problem5=(17, 5), problem6=(18, 5),
problem7=(19, 12), problem8=(19, 17), problem9=(20, 15),
problem10=(20, 23))
self.check('---\n'
'multiline string 1: |\n'
' line 1\n'
' line 2\n'
'multiline string 2: >\n'
' word 1\n'
' word 2\n'
'multiline string 3:\n'
' word 1\n' # fails
' word 2\n'
'multiline string 4:\n'
' "word 1\\\n'
' word 2"\n',
conf, problem1=(9, 3), problem2=(12, 3))
def test_quote_type_double(self):
conf = 'quoted-strings: {quote-type: double}\n'
self.check('---\n'
'boolean1: true\n'
'number1: 123\n'
'string1: foo\n' # fails
'string2: "foo"\n'
'string3: "true"\n'
'string4: "123"\n'
'string5: \'bar\'\n' # fails
'string6: !!str genericstring\n'
'string7: !!str 456\n'
'string8: !!str "quotedgenericstring"\n'
'binary: !!binary binstring\n'
'integer: !!int intstring\n'
'boolean2: !!bool boolstring\n'
'boolean3: !!bool "quotedboolstring"\n'
'block-seq:\n'
' - foo\n' # fails
' - "foo"\n'
'flow-seq: [foo, "foo"]\n' # fails
'flow-map: {a: foo, b: "foo"}\n', # fails
conf, problem1=(4, 10), problem2=(8, 10), problem3=(17, 5),
problem4=(19, 12), problem5=(20, 15))
self.check('---\n'
'multiline string 1: |\n'
' line 1\n'
' line 2\n'
'multiline string 2: >\n'
' word 1\n'
' word 2\n'
'multiline string 3:\n'
' word 1\n' # fails
' word 2\n'
'multiline string 4:\n'
' "word 1\\\n'
' word 2"\n',
conf, problem1=(9, 3))
def test_any_quotes_not_required(self):
conf = 'quoted-strings: {quote-type: any, required: false}\n'
self.check('---\n'
'boolean1: true\n'
'number1: 123\n'
'string1: foo\n'
'string2: "foo"\n'
'string3: "true"\n'
'string4: "123"\n'
'string5: \'bar\'\n'
'string6: !!str genericstring\n'
'string7: !!str 456\n'
'string8: !!str "quotedgenericstring"\n'
'binary: !!binary binstring\n'
'integer: !!int intstring\n'
'boolean2: !!bool boolstring\n'
'boolean3: !!bool "quotedboolstring"\n'
'block-seq:\n'
' - foo\n' # fails
' - "foo"\n'
'flow-seq: [foo, "foo"]\n' # fails
'flow-map: {a: foo, b: "foo"}\n', # fails
conf)
self.check('---\n'
'multiline string 1: |\n'
' line 1\n'
' line 2\n'
'multiline string 2: >\n'
' word 1\n'
' word 2\n'
'multiline string 3:\n'
' word 1\n'
' word 2\n'
'multiline string 4:\n'
' "word 1\\\n'
' word 2"\n',
conf)
def test_single_quotes_not_required(self):
conf = 'quoted-strings: {quote-type: single, required: false}\n'
self.check('---\n'
'boolean1: true\n'
'number1: 123\n'
'string1: foo\n'
'string2: "foo"\n' # fails
'string3: "true"\n' # fails
'string4: "123"\n' # fails
'string5: \'bar\'\n'
'string6: !!str genericstring\n'
'string7: !!str 456\n'
'string8: !!str "quotedgenericstring"\n'
'binary: !!binary binstring\n'
'integer: !!int intstring\n'
'boolean2: !!bool boolstring\n'
'boolean3: !!bool "quotedboolstring"\n'
'block-seq:\n'
' - foo\n' # fails
' - "foo"\n'
'flow-seq: [foo, "foo"]\n' # fails
'flow-map: {a: foo, b: "foo"}\n', # fails
conf, problem1=(5, 10), problem2=(6, 10), problem3=(7, 10),
problem4=(18, 5), problem5=(19, 17), problem6=(20, 23))
self.check('---\n'
'multiline string 1: |\n'
' line 1\n'
' line 2\n'
'multiline string 2: >\n'
' word 1\n'
' word 2\n'
'multiline string 3:\n'
' word 1\n'
' word 2\n'
'multiline string 4:\n'
' "word 1\\\n' # fails
' word 2"\n',
conf, problem1=(12, 3))
def test_only_when_needed(self):
conf = 'quoted-strings: {required: only-when-needed}\n'
self.check('---\n'
'boolean1: true\n'
'number1: 123\n'
'string1: foo\n'
'string2: "foo"\n' # fails
'string3: "true"\n'
'string4: "123"\n'
'string5: \'bar\'\n' # fails
'string6: !!str genericstring\n'
'string7: !!str 456\n'
'string8: !!str "quotedgenericstring"\n'
'binary: !!binary binstring\n'
'integer: !!int intstring\n'
'boolean2: !!bool boolstring\n'
'boolean3: !!bool "quotedboolstring"\n'
'block-seq:\n'
' - foo\n'
' - "foo"\n' # fails
'flow-seq: [foo, "foo"]\n' # fails
'flow-map: {a: foo, b: "foo"}\n', # fails
conf, problem1=(5, 10), problem2=(8, 10), problem3=(18, 5),
problem4=(19, 17), problem5=(20, 23))
self.check('---\n'
'multiline string 1: |\n'
' line 1\n'
' line 2\n'
'multiline string 2: >\n'
' word 1\n'
' word 2\n'
'multiline string 3:\n'
' word 1\n'
' word 2\n'
'multiline string 4:\n'
' "word 1\\\n' # fails
' word 2"\n',
conf, problem1=(12, 3))
def test_only_when_needed_single_quotes(self):
conf = ('quoted-strings: {quote-type: single,\n'
' required: only-when-needed}\n')
self.check('---\n'
'boolean1: true\n'
'number1: 123\n'
'string1: foo\n'
'string2: "foo"\n' # fails
'string3: "true"\n' # fails
'string4: "123"\n' # fails
'string5: \'bar\'\n' # fails
'string6: !!str genericstring\n'
'string7: !!str 456\n'
'string8: !!str "quotedgenericstring"\n'
'binary: !!binary binstring\n'
'integer: !!int intstring\n'
'boolean2: !!bool boolstring\n'
'boolean3: !!bool "quotedboolstring"\n'
'block-seq:\n'
' - foo\n'
' - "foo"\n' # fails
'flow-seq: [foo, "foo"]\n' # fails
'flow-map: {a: foo, b: "foo"}\n', # fails
conf, problem1=(5, 10), problem2=(6, 10), problem3=(7, 10),
problem4=(8, 10), problem5=(18, 5), problem6=(19, 17),
problem7=(20, 23))
self.check('---\n'
'multiline string 1: |\n'
' line 1\n'
' line 2\n'
'multiline string 2: >\n'
' word 1\n'
' word 2\n'
'multiline string 3:\n'
' word 1\n'
' word 2\n'
'multiline string 4:\n'
' "word 1\\\n' # fails
' word 2"\n',
conf, problem1=(12, 3))
def test_only_when_needed_corner_cases(self):
conf = 'quoted-strings: {required: only-when-needed}\n'
self.check('---\n'
'- ""\n'
'- "- item"\n'
'- "key: value"\n'
'- "%H:%M:%S"\n'
'- "%wheel ALL=(ALL) NOPASSWD: ALL"\n'
'- \'"quoted"\'\n'
'- "\'foo\' == \'bar\'"\n'
'- "\'Mac\' in ansible_facts.product_name"\n'
'- \'foo # bar\'\n',
conf)
self.check('---\n'
'k1: ""\n'
'k2: "- item"\n'
'k3: "key: value"\n'
'k4: "%H:%M:%S"\n'
'k5: "%wheel ALL=(ALL) NOPASSWD: ALL"\n'
'k6: \'"quoted"\'\n'
'k7: "\'foo\' == \'bar\'"\n'
'k8: "\'Mac\' in ansible_facts.product_name"\n',
conf)
self.check('---\n'
'- ---\n'
'- "---"\n' # fails
'- ----------\n'
'- "----------"\n' # fails
'- :wq\n'
'- ":wq"\n', # fails
conf, problem1=(3, 3), problem2=(5, 3), problem3=(7, 3))
self.check('---\n'
'k1: ---\n'
'k2: "---"\n' # fails
'k3: ----------\n'
'k4: "----------"\n' # fails
'k5: :wq\n'
'k6: ":wq"\n', # fails
conf, problem1=(3, 5), problem2=(5, 5), problem3=(7, 5))
def test_only_when_needed_extras(self):
conf = ('quoted-strings:\n'
' required: true\n'
' extra-allowed: [^http://]\n')
self.assertRaises(config.YamlLintConfigError, self.check, '', conf)
conf = ('quoted-strings:\n'
' required: true\n'
' extra-required: [^http://]\n')
self.assertRaises(config.YamlLintConfigError, self.check, '', conf)
conf = ('quoted-strings:\n'
' required: false\n'
' extra-allowed: [^http://]\n')
self.assertRaises(config.YamlLintConfigError, self.check, '', conf)
conf = ('quoted-strings:\n'
' required: true\n')
self.check('---\n'
'- 123\n'
'- "123"\n'
'- localhost\n' # fails
'- "localhost"\n'
'- http://localhost\n' # fails
'- "http://localhost"\n'
'- ftp://localhost\n' # fails
'- "ftp://localhost"\n',
conf, problem1=(4, 3), problem2=(6, 3), problem3=(8, 3))
conf = ('quoted-strings:\n'
' required: only-when-needed\n'
' extra-allowed: [^ftp://]\n'
' extra-required: [^http://]\n')
self.check('---\n'
'- 123\n'
'- "123"\n'
'- localhost\n'
'- "localhost"\n' # fails
'- http://localhost\n' # fails
'- "http://localhost"\n'
'- ftp://localhost\n'
'- "ftp://localhost"\n',
conf, problem1=(5, 3), problem2=(6, 3))
conf = ('quoted-strings:\n'
' required: false\n'
' extra-required: [^http://, ^ftp://]\n')
self.check('---\n'
'- 123\n'
'- "123"\n'
'- localhost\n'
'- "localhost"\n'
'- http://localhost\n' # fails
'- "http://localhost"\n'
'- ftp://localhost\n' # fails
'- "ftp://localhost"\n',
conf, problem1=(6, 3), problem2=(8, 3))
conf = ('quoted-strings:\n'
' required: only-when-needed\n'
' extra-allowed: [^ftp://, ";$", " "]\n')
self.check('---\n'
'- localhost\n'
'- "localhost"\n' # fails
'- ftp://localhost\n'
'- "ftp://localhost"\n'
'- i=i+1\n'
'- "i=i+1"\n' # fails
'- i=i+2;\n'
'- "i=i+2;"\n'
'- foo\n'
'- "foo"\n' # fails
'- 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))

View File

@@ -14,7 +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/>.
from tests.rules.common import RuleTestCase
from tests.common import RuleTestCase
class TrailingSpacesTestCase(RuleTestCase):
@@ -29,7 +29,7 @@ class TrailingSpacesTestCase(RuleTestCase):
'some: text \n', conf)
def test_enabled(self):
conf = 'trailing-spaces: {}'
conf = 'trailing-spaces: enable'
self.check('', conf)
self.check('\n', conf)
self.check(' \n', conf, problem=(1, 1))
@@ -40,7 +40,7 @@ class TrailingSpacesTestCase(RuleTestCase):
'some: text\t\n', conf, problem=(2, 11, 'syntax'))
def test_with_dos_new_lines(self):
conf = ('trailing-spaces: {}\n'
conf = ('trailing-spaces: enable\n'
'new-lines: {type: dos}\n')
self.check('---\r\n'
'some: text\r\n', conf)

146
tests/rules/test_truthy.py Normal file
View File

@@ -0,0 +1,146 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Peter Ericson
#
# 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 TruthyTestCase(RuleTestCase):
rule_id = 'truthy'
def test_disabled(self):
conf = 'truthy: disable'
self.check('---\n'
'1: True\n', conf)
self.check('---\n'
'True: 1\n', conf)
def test_enabled(self):
conf = 'truthy: enable\n'
self.check('---\n'
'1: True\n'
'True: 1\n',
conf, problem1=(2, 4), problem2=(3, 1))
self.check('---\n'
'1: "True"\n'
'"True": 1\n', conf)
self.check('---\n'
'[\n'
' true, false,\n'
' "false", "FALSE",\n'
' "true", "True",\n'
' True, FALSE,\n'
' on, OFF,\n'
' NO, Yes\n'
']\n', conf,
problem1=(6, 3), problem2=(6, 9),
problem3=(7, 3), problem4=(7, 7),
problem5=(8, 3), problem6=(8, 7))
def test_different_allowed_values(self):
conf = ('truthy:\n'
' allowed-values: ["yes", "no"]\n')
self.check('---\n'
'key1: foo\n'
'key2: yes\n'
'key3: bar\n'
'key4: no\n', conf)
self.check('---\n'
'key1: true\n'
'key2: Yes\n'
'key3: false\n'
'key4: no\n'
'key5: yes\n',
conf,
problem1=(2, 7), problem2=(3, 7),
problem3=(4, 7))
def test_combined_allowed_values(self):
conf = ('truthy:\n'
' allowed-values: ["yes", "no", "true", "false"]\n')
self.check('---\n'
'key1: foo\n'
'key2: yes\n'
'key3: bar\n'
'key4: no\n', conf)
self.check('---\n'
'key1: true\n'
'key2: Yes\n'
'key3: false\n'
'key4: no\n'
'key5: yes\n',
conf, problem1=(3, 7))
def test_no_allowed_values(self):
conf = ('truthy:\n'
' allowed-values: []\n')
self.check('---\n'
'key1: foo\n'
'key2: bar\n', conf)
self.check('---\n'
'key1: true\n'
'key2: yes\n'
'key3: false\n'
'key4: no\n', conf,
problem1=(2, 7), problem2=(3, 7),
problem3=(4, 7), problem4=(5, 7))
def test_explicit_types(self):
conf = 'truthy: enable\n'
self.check('---\n'
'string1: !!str True\n'
'string2: !!str yes\n'
'string3: !!str off\n'
'encoded: !!binary |\n'
' True\n'
' OFF\n'
' pad==\n' # this decodes as 'N\xbb\x9e8Qii'
'boolean1: !!bool true\n'
'boolean2: !!bool "false"\n'
'boolean3: !!bool FALSE\n'
'boolean4: !!bool True\n'
'boolean5: !!bool off\n'
'boolean6: !!bool NO\n',
conf)
def test_check_keys_disabled(self):
conf = ('truthy:\n'
' allowed-values: []\n'
' check-keys: false\n'
'key-duplicates: disable\n')
self.check('---\n'
'YES: 0\n'
'Yes: 0\n'
'yes: 0\n'
'No: 0\n'
'No: 0\n'
'no: 0\n'
'TRUE: 0\n'
'True: 0\n'
'true: 0\n'
'FALSE: 0\n'
'False: 0\n'
'false: 0\n'
'ON: 0\n'
'On: 0\n'
'on: 0\n'
'OFF: 0\n'
'Off: 0\n'
'off: 0\n'
'YES:\n'
' Yes:\n'
' yes:\n'
' on: 0\n',
conf)

640
tests/test_cli.py Normal file
View File

@@ -0,0 +1,640 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# 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 io import StringIO
import fcntl
import locale
import os
import pty
import shutil
import sys
import tempfile
import unittest
from tests.common import build_temp_workspace
from yamllint import cli
from yamllint import config
class RunContext(object):
"""Context manager for ``cli.run()`` to capture exit code and streams."""
def __init__(self, case):
self.stdout = self.stderr = None
self._raises_ctx = case.assertRaises(SystemExit)
def __enter__(self):
self._raises_ctx.__enter__()
sys.stdout = self.outstream = StringIO()
sys.stderr = self.errstream = StringIO()
return self
def __exit__(self, *exc_info):
self.stdout, sys.stdout = self.outstream.getvalue(), sys.__stdout__
self.stderr, sys.stderr = self.errstream.getvalue(), sys.__stderr__
return self._raises_ctx.__exit__(*exc_info)
@property
def returncode(self):
return self._raises_ctx.exception.code
# Check system's UTF-8 availability
def utf8_available():
try:
locale.setlocale(locale.LC_ALL, 'C.UTF-8')
locale.setlocale(locale.LC_ALL, (None, None))
return True
except locale.Error:
return False
class CommandLineTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
super(CommandLineTestCase, cls).setUpClass()
cls.wd = build_temp_workspace({
# .yaml file at root
'a.yaml': '---\n'
'- 1 \n'
'- 2',
# file with only one warning
'warn.yaml': 'key: value\n',
# .yml file at root
'empty.yml': '',
# file in dir
'sub/ok.yaml': '---\n'
'key: value\n',
# directory that looks like a yaml file
'sub/directory.yaml/not-yaml.txt': '',
'sub/directory.yaml/empty.yml': '',
# file in very nested dir
's/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml': '---\n'
'key: value\n'
'key: other value\n',
# empty dir
'empty-dir': [],
# non-YAML file
'no-yaml.json': '---\n'
'key: value\n',
# non-ASCII chars
u'non-ascii/éçäγλνπ¥/utf-8': (
u'---\n'
u'- hétérogénéité\n'
u'# 19.99 €\n'
u'- お早う御座います。\n'
u'# الأَبْجَدِيَّة العَرَبِيَّة\n').encode('utf-8'),
# dos line endings yaml
'dos.yml': '---\r\n'
'dos: true',
# different key-ordering by locale
'c.yaml': '---\n'
'A: true\n'
'a: true',
'en.yaml': '---\n'
'a: true\n'
'A: true'
})
@classmethod
def tearDownClass(cls):
super(CommandLineTestCase, cls).tearDownClass()
shutil.rmtree(cls.wd)
@unittest.skipIf(not utf8_available() and sys.version_info < (3, 7),
'UTF-8 paths not supported')
def test_find_files_recursively(self):
conf = config.YamlLintConfig('extends: default')
self.assertEqual(
sorted(cli.find_files_recursively([self.wd], conf)),
[os.path.join(self.wd, 'a.yaml'),
os.path.join(self.wd, 'c.yaml'),
os.path.join(self.wd, 'dos.yml'),
os.path.join(self.wd, 'empty.yml'),
os.path.join(self.wd, 'en.yaml'),
os.path.join(self.wd, 's/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml'),
os.path.join(self.wd, 'sub/directory.yaml/empty.yml'),
os.path.join(self.wd, 'sub/ok.yaml'),
os.path.join(self.wd, 'warn.yaml')],
)
items = [os.path.join(self.wd, 'sub/ok.yaml'),
os.path.join(self.wd, 'empty-dir')]
self.assertEqual(
sorted(cli.find_files_recursively(items, conf)),
[os.path.join(self.wd, 'sub/ok.yaml')],
)
items = [os.path.join(self.wd, 'empty.yml'),
os.path.join(self.wd, 's')]
self.assertEqual(
sorted(cli.find_files_recursively(items, conf)),
[os.path.join(self.wd, 'empty.yml'),
os.path.join(self.wd, 's/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml')],
)
items = [os.path.join(self.wd, 'sub'),
os.path.join(self.wd, '/etc/another/file')]
self.assertEqual(
sorted(cli.find_files_recursively(items, conf)),
[os.path.join(self.wd, '/etc/another/file'),
os.path.join(self.wd, 'sub/directory.yaml/empty.yml'),
os.path.join(self.wd, 'sub/ok.yaml')],
)
conf = config.YamlLintConfig('extends: default\n'
'yaml-files:\n'
' - \'*.yaml\' \n')
self.assertEqual(
sorted(cli.find_files_recursively([self.wd], conf)),
[os.path.join(self.wd, 'a.yaml'),
os.path.join(self.wd, 'c.yaml'),
os.path.join(self.wd, 'en.yaml'),
os.path.join(self.wd, 's/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml'),
os.path.join(self.wd, 'sub/ok.yaml'),
os.path.join(self.wd, 'warn.yaml')]
)
conf = config.YamlLintConfig('extends: default\n'
'yaml-files:\n'
' - \'*.yml\'\n')
self.assertEqual(
sorted(cli.find_files_recursively([self.wd], conf)),
[os.path.join(self.wd, 'dos.yml'),
os.path.join(self.wd, 'empty.yml'),
os.path.join(self.wd, 'sub/directory.yaml/empty.yml')]
)
conf = config.YamlLintConfig('extends: default\n'
'yaml-files:\n'
' - \'*.json\'\n')
self.assertEqual(
sorted(cli.find_files_recursively([self.wd], conf)),
[os.path.join(self.wd, 'no-yaml.json')]
)
conf = config.YamlLintConfig('extends: default\n'
'yaml-files:\n'
' - \'*\'\n')
self.assertEqual(
sorted(cli.find_files_recursively([self.wd], conf)),
[os.path.join(self.wd, 'a.yaml'),
os.path.join(self.wd, 'c.yaml'),
os.path.join(self.wd, 'dos.yml'),
os.path.join(self.wd, 'empty.yml'),
os.path.join(self.wd, 'en.yaml'),
os.path.join(self.wd, 'no-yaml.json'),
os.path.join(self.wd, 'non-ascii/éçäγλνπ¥/utf-8'),
os.path.join(self.wd, 's/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml'),
os.path.join(self.wd, 'sub/directory.yaml/empty.yml'),
os.path.join(self.wd, 'sub/directory.yaml/not-yaml.txt'),
os.path.join(self.wd, 'sub/ok.yaml'),
os.path.join(self.wd, 'warn.yaml')]
)
conf = config.YamlLintConfig('extends: default\n'
'yaml-files:\n'
' - \'*.yaml\'\n'
' - \'*\'\n'
' - \'**\'\n')
self.assertEqual(
sorted(cli.find_files_recursively([self.wd], conf)),
[os.path.join(self.wd, 'a.yaml'),
os.path.join(self.wd, 'c.yaml'),
os.path.join(self.wd, 'dos.yml'),
os.path.join(self.wd, 'empty.yml'),
os.path.join(self.wd, 'en.yaml'),
os.path.join(self.wd, 'no-yaml.json'),
os.path.join(self.wd, 'non-ascii/éçäγλνπ¥/utf-8'),
os.path.join(self.wd, 's/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml'),
os.path.join(self.wd, 'sub/directory.yaml/empty.yml'),
os.path.join(self.wd, 'sub/directory.yaml/not-yaml.txt'),
os.path.join(self.wd, 'sub/ok.yaml'),
os.path.join(self.wd, 'warn.yaml')]
)
conf = config.YamlLintConfig('extends: default\n'
'yaml-files:\n'
' - \'s/**\'\n'
' - \'**/utf-8\'\n')
self.assertEqual(
sorted(cli.find_files_recursively([self.wd], conf)),
[os.path.join(self.wd, 'non-ascii/éçäγλνπ¥/utf-8')]
)
def test_run_with_bad_arguments(self):
with RunContext(self) as ctx:
cli.run(())
self.assertNotEqual(ctx.returncode, 0)
self.assertEqual(ctx.stdout, '')
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.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.assertRegex(
ctx.stderr.splitlines()[-1],
r'^yamllint: error: argument -d\/--config-data: '
r'not allowed with argument -c\/--config-file$'
)
# checks if reading from stdin and files are mutually exclusive
with RunContext(self) as ctx:
cli.run(('-', 'file'))
self.assertNotEqual(ctx.returncode, 0)
self.assertEqual(ctx.stdout, '')
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.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.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:
f.write('rules: {trailing-spaces: disable}')
with RunContext(self) as ctx:
cli.run(('-c', f.name, os.path.join(self.wd, 'a.yaml')))
self.assertEqual(ctx.returncode, 0)
with open(os.path.join(self.wd, 'config'), 'w') as f:
f.write('rules: {trailing-spaces: enable}')
with RunContext(self) as ctx:
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')
os.makedirs(dir)
config = os.path.join(dir, 'config')
self.addCleanup(os.environ.update, HOME=os.environ['HOME'])
os.environ['HOME'] = home
with open(config, 'w') as f:
f.write('rules: {trailing-spaces: disable}')
with RunContext(self) as ctx:
cli.run((os.path.join(self.wd, 'a.yaml'), ))
self.assertEqual(ctx.returncode, 0)
with open(config, 'w') as f:
f.write('rules: {trailing-spaces: enable}')
with RunContext(self) as ctx:
cli.run((os.path.join(self.wd, 'a.yaml'), ))
self.assertEqual(ctx.returncode, 1)
def test_run_with_user_yamllint_config_file_in_env(self):
self.addCleanup(os.environ.__delitem__, 'YAMLLINT_CONFIG_FILE')
with tempfile.NamedTemporaryFile('w') as f:
os.environ['YAMLLINT_CONFIG_FILE'] = f.name
f.write('rules: {trailing-spaces: disable}')
f.flush()
with RunContext(self) as ctx:
cli.run((os.path.join(self.wd, 'a.yaml'), ))
self.assertEqual(ctx.returncode, 0)
with tempfile.NamedTemporaryFile('w') as f:
os.environ['YAMLLINT_CONFIG_FILE'] = f.name
f.write('rules: {trailing-spaces: enable}')
f.flush()
with RunContext(self) as ctx:
cli.run((os.path.join(self.wd, 'a.yaml'), ))
self.assertEqual(ctx.returncode, 1)
def test_run_with_locale(self):
# check for availability of locale, otherwise skip the test
# reset to default before running the test,
# as the first two runs don't use setlocale()
try:
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
except locale.Error:
self.skipTest('locale en_US.UTF-8 not available')
locale.setlocale(locale.LC_ALL, (None, None))
# C + en.yaml should fail
with RunContext(self) as ctx:
cli.run(('-d', 'rules: { key-ordering: enable }',
os.path.join(self.wd, 'en.yaml')))
self.assertEqual(ctx.returncode, 1)
# C + c.yaml should pass
with RunContext(self) as ctx:
cli.run(('-d', 'rules: { key-ordering: enable }',
os.path.join(self.wd, 'c.yaml')))
self.assertEqual(ctx.returncode, 0)
# the next two runs use setlocale() inside,
# so we need to clean up afterwards
self.addCleanup(locale.setlocale, locale.LC_ALL, (None, None))
# en_US + en.yaml should pass
with RunContext(self) as ctx:
cli.run(('-d', 'locale: en_US.UTF-8\n'
'rules: { key-ordering: enable }',
os.path.join(self.wd, 'en.yaml')))
self.assertEqual(ctx.returncode, 0)
# en_US + c.yaml should fail
with RunContext(self) as ctx:
cli.run(('-d', 'locale: en_US.UTF-8\n'
'rules: { key-ordering: enable }',
os.path.join(self.wd, 'c.yaml')))
self.assertEqual(ctx.returncode, 1)
def test_run_version(self):
with RunContext(self) as ctx:
cli.run(('--version', ))
self.assertEqual(ctx.returncode, 0)
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')
with RunContext(self) as ctx:
cli.run(('-f', 'parsable', path))
self.assertEqual(ctx.returncode, -1)
self.assertEqual(ctx.stdout, '')
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')
with RunContext(self) as ctx:
cli.run(('-f', 'parsable', path))
self.assertEqual(ctx.returncode, 1)
self.assertEqual(ctx.stdout, (
'%s:2:4: [error] trailing spaces (trailing-spaces)\n'
'%s:3:4: [error] no new line character at the end of file '
'(new-line-at-end-of-file)\n' % (path, path)))
self.assertEqual(ctx.stderr, '')
def test_run_one_warning(self):
path = os.path.join(self.wd, 'warn.yaml')
with RunContext(self) as ctx:
cli.run(('-f', 'parsable', path))
self.assertEqual(ctx.returncode, 0)
def test_run_warning_in_strict_mode(self):
path = os.path.join(self.wd, 'warn.yaml')
with RunContext(self) as ctx:
cli.run(('-f', 'parsable', '--strict', path))
self.assertEqual(ctx.returncode, 2)
def test_run_one_ok_file(self):
path = os.path.join(self.wd, 'sub', 'ok.yaml')
with RunContext(self) as ctx:
cli.run(('-f', 'parsable', path))
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr), (0, '', ''))
def test_run_empty_file(self):
path = os.path.join(self.wd, 'empty.yml')
with RunContext(self) as ctx:
cli.run(('-f', 'parsable', path))
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr), (0, '', ''))
@unittest.skipIf(not utf8_available(), 'C.UTF-8 not available')
def test_run_non_ascii_file(self):
locale.setlocale(locale.LC_ALL, 'C.UTF-8')
self.addCleanup(locale.setlocale, locale.LC_ALL, (None, None))
path = os.path.join(self.wd, 'non-ascii', 'éçäγλνπ¥', 'utf-8')
with RunContext(self) as ctx:
cli.run(('-f', 'parsable', path))
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr), (0, '', ''))
def test_run_multiple_files(self):
items = [os.path.join(self.wd, 'empty.yml'),
os.path.join(self.wd, 's')]
path = items[1] + '/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml'
with RunContext(self) as ctx:
cli.run(['-f', 'parsable'] + items)
self.assertEqual((ctx.returncode, ctx.stderr), (1, ''))
self.assertEqual(ctx.stdout, (
'%s:3:1: [error] duplication of key "key" in mapping '
'(key-duplicates)\n') % path)
def test_run_piped_output_nocolor(self):
path = os.path.join(self.wd, 'a.yaml')
with RunContext(self) as ctx:
cli.run((path, ))
self.assertEqual((ctx.returncode, ctx.stderr), (1, ''))
self.assertEqual(ctx.stdout, (
'%s\n'
' 2:4 error trailing spaces (trailing-spaces)\n'
' 3:4 error no new line character at the end of file '
'(new-line-at-end-of-file)\n'
'\n' % path))
def test_run_default_format_output_in_tty(self):
path = os.path.join(self.wd, 'a.yaml')
# Create a pseudo-TTY and redirect stdout to it
master, slave = pty.openpty()
sys.stdout = sys.stderr = os.fdopen(slave, 'w')
with self.assertRaises(SystemExit) as ctx:
cli.run((path, ))
sys.stdout.flush()
self.assertEqual(ctx.exception.code, 1)
# Read output from TTY
output = os.fdopen(master, 'r')
flag = fcntl.fcntl(master, fcntl.F_GETFD)
fcntl.fcntl(master, fcntl.F_SETFL, flag | os.O_NONBLOCK)
out = output.read().replace('\r\n', '\n')
sys.stdout.close()
sys.stderr.close()
output.close()
self.assertEqual(out, (
'\033[4m%s\033[0m\n'
' \033[2m2:4\033[0m \033[31merror\033[0m '
'trailing spaces \033[2m(trailing-spaces)\033[0m\n'
' \033[2m3:4\033[0m \033[31merror\033[0m '
'no new line character at the end of file '
'\033[2m(new-line-at-end-of-file)\033[0m\n'
'\n' % path))
def test_run_default_format_output_without_tty(self):
path = os.path.join(self.wd, 'a.yaml')
with RunContext(self) as ctx:
cli.run((path, ))
expected_out = (
'%s\n'
' 2:4 error trailing spaces (trailing-spaces)\n'
' 3:4 error no new line character at the end of file '
'(new-line-at-end-of-file)\n'
'\n' % path)
self.assertEqual(
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
def test_run_auto_output_without_tty_output(self):
path = os.path.join(self.wd, 'a.yaml')
with RunContext(self) as ctx:
cli.run((path, '--format', 'auto'))
expected_out = (
'%s\n'
' 2:4 error trailing spaces (trailing-spaces)\n'
' 3:4 error no new line character at the end of file '
'(new-line-at-end-of-file)\n'
'\n' % path)
self.assertEqual(
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
def test_run_format_colored(self):
path = os.path.join(self.wd, 'a.yaml')
with RunContext(self) as ctx:
cli.run((path, '--format', 'colored'))
expected_out = (
'\033[4m%s\033[0m\n'
' \033[2m2:4\033[0m \033[31merror\033[0m '
'trailing spaces \033[2m(trailing-spaces)\033[0m\n'
' \033[2m3:4\033[0m \033[31merror\033[0m '
'no new line character at the end of file '
'\033[2m(new-line-at-end-of-file)\033[0m\n'
'\n' % path)
self.assertEqual(
(ctx.returncode, ctx.stdout, ctx.stderr), (1, 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'
' spaces\n'
'::error file=%s,line=3,col=4::[new-line-at-end-of-file] no'
' new line character at the end of file\n'
% (path, path))
self.assertEqual(
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
def test_github_actions_detection(self):
path = os.path.join(self.wd, 'a.yaml')
self.addCleanup(os.environ.__delitem__, 'GITHUB_ACTIONS')
self.addCleanup(os.environ.__delitem__, 'GITHUB_WORKFLOW')
with RunContext(self) as ctx:
os.environ['GITHUB_ACTIONS'] = 'something'
os.environ['GITHUB_WORKFLOW'] = 'something'
cli.run((path, ))
expected_out = (
'::error file=%s,line=2,col=4::[trailing-spaces] trailing'
' spaces\n'
'::error file=%s,line=3,col=4::[new-line-at-end-of-file] no'
' new line character at the end of file\n'
% (path, path))
self.assertEqual(
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
def test_run_read_from_stdin(self):
# prepares stdin with an invalid yaml string so that we can check
# for its specific error, and be assured that stdin was read
self.addCleanup(setattr, sys, 'stdin', sys.__stdin__)
sys.stdin = StringIO(
'I am a string\n'
'therefore: I am an error\n')
with RunContext(self) as ctx:
cli.run(('-', '-f', 'parsable'))
expected_out = (
'stdin:2:10: [error] syntax error: '
'mapping values are not allowed here (syntax)\n')
self.assertEqual(
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
def test_run_no_warnings(self):
path = os.path.join(self.wd, 'a.yaml')
with RunContext(self) as ctx:
cli.run((path, '--no-warnings', '-f', 'auto'))
expected_out = (
'%s\n'
' 2:4 error trailing spaces (trailing-spaces)\n'
' 3:4 error no new line character at the end of file '
'(new-line-at-end-of-file)\n'
'\n' % path)
self.assertEqual(
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
path = os.path.join(self.wd, 'warn.yaml')
with RunContext(self) as ctx:
cli.run((path, '--no-warnings', '-f', 'auto'))
self.assertEqual(ctx.returncode, 0)
def test_run_no_warnings_and_strict(self):
path = os.path.join(self.wd, 'warn.yaml')
with RunContext(self) as ctx:
cli.run((path, '--no-warnings', '-s'))
self.assertEqual(ctx.returncode, 2)
def test_run_non_universal_newline(self):
path = os.path.join(self.wd, 'dos.yml')
with RunContext(self) as ctx:
cli.run(('-d', 'rules:\n new-lines:\n type: dos', path))
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr), (0, '', ''))
with RunContext(self) as ctx:
cli.run(('-d', 'rules:\n new-lines:\n type: unix', path))
expected_out = (
'%s\n'
' 1:4 error wrong new line character: expected \\n'
' (new-lines)\n'
'\n' % path)
self.assertEqual(
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))

View File

@@ -14,8 +14,16 @@
# 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 io import StringIO
import os
import shutil
import sys
import tempfile
import unittest
from tests.common import build_temp_workspace
from yamllint import cli
from yamllint import config
@@ -30,26 +38,33 @@ class SimpleConfigTestCase(unittest.TestCase):
self.assertEqual(new.rules['colons']['max-spaces-before'], 0)
self.assertEqual(new.rules['colons']['max-spaces-after'], 1)
self.assertEqual(len(new.enabled_rules()), 1)
self.assertEqual(len(new.enabled_rules(None)), 1)
def test_invalid_conf(self):
with self.assertRaises(config.YamlLintConfigError):
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'
' this-one-does-not-exist: {}\n')
' this-one-does-not-exist: enable\n')
def test_missing_option(self):
with self.assertRaisesRegexp(
config.YamlLintConfigError,
'invalid config: missing option "max-spaces-before" '
'for rule "colons"'):
config.YamlLintConfig('rules:\n'
c = config.YamlLintConfig('rules:\n'
' colons: enable\n')
self.assertEqual(c.rules['colons']['max-spaces-before'], 0)
self.assertEqual(c.rules['colons']['max-spaces-after'], 1)
c = config.YamlLintConfig('rules:\n'
' colons:\n'
' max-spaces-after: 1\n')
' max-spaces-before: 9\n')
self.assertEqual(c.rules['colons']['max-spaces-before'], 9)
self.assertEqual(c.rules['colons']['max-spaces-after'], 1)
def test_unknown_option(self):
with self.assertRaisesRegexp(
with self.assertRaisesRegex(
config.YamlLintConfigError,
'invalid config: unknown option "abcdef" for rule "colons"'):
config.YamlLintConfig('rules:\n'
@@ -58,9 +73,126 @@ class SimpleConfigTestCase(unittest.TestCase):
' max-spaces-after: 1\n'
' abcdef: yes\n')
def test_yes_no_for_booleans(self):
c = config.YamlLintConfig('rules:\n'
' indentation:\n'
' spaces: 2\n'
' indent-sequences: true\n'
' check-multi-line-strings: false\n')
self.assertTrue(c.rules['indentation']['indent-sequences'])
self.assertEqual(c.rules['indentation']['check-multi-line-strings'],
False)
c = config.YamlLintConfig('rules:\n'
' indentation:\n'
' spaces: 2\n'
' indent-sequences: yes\n'
' check-multi-line-strings: false\n')
self.assertTrue(c.rules['indentation']['indent-sequences'])
self.assertEqual(c.rules['indentation']['check-multi-line-strings'],
False)
c = config.YamlLintConfig('rules:\n'
' indentation:\n'
' spaces: 2\n'
' indent-sequences: whatever\n'
' check-multi-line-strings: false\n')
self.assertEqual(c.rules['indentation']['indent-sequences'],
'whatever')
self.assertEqual(c.rules['indentation']['check-multi-line-strings'],
False)
with self.assertRaisesRegex(
config.YamlLintConfigError,
'invalid config: option "indent-sequences" of "indentation" '
'should be in '):
c = config.YamlLintConfig('rules:\n'
' indentation:\n'
' spaces: 2\n'
' indent-sequences: YES!\n'
' check-multi-line-strings: false\n')
def test_enable_disable_keywords(self):
c = config.YamlLintConfig('rules:\n'
' colons: enable\n'
' hyphens: disable\n')
self.assertEqual(c.rules['colons'], {'level': 'error',
'max-spaces-after': 1,
'max-spaces-before': 0})
self.assertEqual(c.rules['hyphens'], False)
def test_validate_rule_conf(self):
class Rule(object):
ID = 'fake'
self.assertFalse(config.validate_rule_conf(Rule, False))
self.assertEqual(config.validate_rule_conf(Rule, {}),
{'level': 'error'})
config.validate_rule_conf(Rule, {'level': 'error'})
config.validate_rule_conf(Rule, {'level': 'warning'})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {'level': 'warn'})
Rule.CONF = {'length': int}
Rule.DEFAULT = {'length': 80}
config.validate_rule_conf(Rule, {'length': 8})
config.validate_rule_conf(Rule, {})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {'height': 8})
Rule.CONF = {'a': bool, 'b': int}
Rule.DEFAULT = {'a': True, 'b': -42}
config.validate_rule_conf(Rule, {'a': True, 'b': 0})
config.validate_rule_conf(Rule, {'a': True})
config.validate_rule_conf(Rule, {'b': 0})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {'a': 1, 'b': 0})
Rule.CONF = {'choice': (True, 88, 'str')}
Rule.DEFAULT = {'choice': 88}
config.validate_rule_conf(Rule, {'choice': True})
config.validate_rule_conf(Rule, {'choice': 88})
config.validate_rule_conf(Rule, {'choice': 'str'})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {'choice': False})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {'choice': 99})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {'choice': 'abc'})
Rule.CONF = {'choice': (int, 'hardcoded')}
Rule.DEFAULT = {'choice': 1337}
config.validate_rule_conf(Rule, {'choice': 42})
config.validate_rule_conf(Rule, {'choice': 'hardcoded'})
config.validate_rule_conf(Rule, {})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {'choice': False})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {'choice': 'abc'})
Rule.CONF = {'multiple': ['item1', 'item2', 'item3']}
Rule.DEFAULT = {'multiple': ['item1']}
config.validate_rule_conf(Rule, {'multiple': []})
config.validate_rule_conf(Rule, {'multiple': ['item2']})
config.validate_rule_conf(Rule, {'multiple': ['item2', 'item3']})
config.validate_rule_conf(Rule, {})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule,
{'multiple': 'item1'})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule,
{'multiple': ['']})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule,
{'multiple': ['item1', 4]})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule,
{'multiple': ['item4']})
class ExtendedConfigTestCase(unittest.TestCase):
def test_extend_add_rule(self):
def test_extend_on_object(self):
old = config.YamlLintConfig('rules:\n'
' colons:\n'
' max-spaces-before: 0\n'
@@ -75,62 +207,132 @@ class ExtendedConfigTestCase(unittest.TestCase):
self.assertEqual(new.rules['colons']['max-spaces-after'], 1)
self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2)
self.assertEqual(len(new.enabled_rules()), 2)
self.assertEqual(len(new.enabled_rules(None)), 2)
def test_extend_on_file(self):
with tempfile.NamedTemporaryFile('w') as f:
f.write('rules:\n'
' colons:\n'
' max-spaces-before: 0\n'
' max-spaces-after: 1\n')
f.flush()
c = config.YamlLintConfig('extends: ' + f.name + '\n'
'rules:\n'
' hyphens:\n'
' max-spaces-after: 2\n')
self.assertEqual(sorted(c.rules.keys()), ['colons', 'hyphens'])
self.assertEqual(c.rules['colons']['max-spaces-before'], 0)
self.assertEqual(c.rules['colons']['max-spaces-after'], 1)
self.assertEqual(c.rules['hyphens']['max-spaces-after'], 2)
self.assertEqual(len(c.enabled_rules(None)), 2)
def test_extend_remove_rule(self):
old = config.YamlLintConfig('rules:\n'
' colons:\n'
' max-spaces-before: 0\n'
' max-spaces-after: 1\n'
' hyphens:\n'
' max-spaces-after: 2\n')
new = config.YamlLintConfig('rules:\n'
' colons: disable\n')
new.extend(old)
with tempfile.NamedTemporaryFile('w') as f:
f.write('rules:\n'
' colons:\n'
' max-spaces-before: 0\n'
' max-spaces-after: 1\n'
' hyphens:\n'
' max-spaces-after: 2\n')
f.flush()
c = config.YamlLintConfig('extends: ' + f.name + '\n'
'rules:\n'
' colons: disable\n')
self.assertEqual(sorted(new.rules.keys()), ['colons', 'hyphens'])
self.assertEqual(new.rules['colons'], False)
self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2)
self.assertEqual(sorted(c.rules.keys()), ['colons', 'hyphens'])
self.assertFalse(c.rules['colons'])
self.assertEqual(c.rules['hyphens']['max-spaces-after'], 2)
self.assertEqual(len(new.enabled_rules()), 1)
self.assertEqual(len(c.enabled_rules(None)), 1)
def test_extend_edit_rule(self):
old = config.YamlLintConfig('rules:\n'
' colons:\n'
' max-spaces-before: 0\n'
' max-spaces-after: 1\n'
' hyphens:\n'
' max-spaces-after: 2\n')
new = config.YamlLintConfig('rules:\n'
' colons:\n'
' max-spaces-before: 3\n'
' max-spaces-after: 4\n')
new.extend(old)
with tempfile.NamedTemporaryFile('w') as f:
f.write('rules:\n'
' colons:\n'
' max-spaces-before: 0\n'
' max-spaces-after: 1\n'
' hyphens:\n'
' max-spaces-after: 2\n')
f.flush()
c = config.YamlLintConfig('extends: ' + f.name + '\n'
'rules:\n'
' colons:\n'
' max-spaces-before: 3\n'
' max-spaces-after: 4\n')
self.assertEqual(sorted(new.rules.keys()), ['colons', 'hyphens'])
self.assertEqual(new.rules['colons']['max-spaces-before'], 3)
self.assertEqual(new.rules['colons']['max-spaces-after'], 4)
self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2)
self.assertEqual(sorted(c.rules.keys()), ['colons', 'hyphens'])
self.assertEqual(c.rules['colons']['max-spaces-before'], 3)
self.assertEqual(c.rules['colons']['max-spaces-after'], 4)
self.assertEqual(c.rules['hyphens']['max-spaces-after'], 2)
self.assertEqual(len(new.enabled_rules()), 2)
self.assertEqual(len(c.enabled_rules(None)), 2)
def test_extend_reenable_rule(self):
old = config.YamlLintConfig('rules:\n'
' colons:\n'
' max-spaces-before: 0\n'
' max-spaces-after: 1\n'
' hyphens: disable\n')
new = config.YamlLintConfig('rules:\n'
' hyphens:\n'
' max-spaces-after: 2\n')
new.extend(old)
with tempfile.NamedTemporaryFile('w') as f:
f.write('rules:\n'
' colons:\n'
' max-spaces-before: 0\n'
' max-spaces-after: 1\n'
' hyphens: disable\n')
f.flush()
c = config.YamlLintConfig('extends: ' + f.name + '\n'
'rules:\n'
' hyphens:\n'
' max-spaces-after: 2\n')
self.assertEqual(sorted(new.rules.keys()), ['colons', 'hyphens'])
self.assertEqual(new.rules['colons']['max-spaces-before'], 0)
self.assertEqual(new.rules['colons']['max-spaces-after'], 1)
self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2)
self.assertEqual(sorted(c.rules.keys()), ['colons', 'hyphens'])
self.assertEqual(c.rules['colons']['max-spaces-before'], 0)
self.assertEqual(c.rules['colons']['max-spaces-after'], 1)
self.assertEqual(c.rules['hyphens']['max-spaces-after'], 2)
self.assertEqual(len(new.enabled_rules()), 2)
self.assertEqual(len(c.enabled_rules(None)), 2)
def test_extend_recursive_default_values(self):
with tempfile.NamedTemporaryFile('w') as f:
f.write('rules:\n'
' braces:\n'
' max-spaces-inside: 1248\n')
f.flush()
c = config.YamlLintConfig('extends: ' + f.name + '\n'
'rules:\n'
' braces:\n'
' min-spaces-inside-empty: 2357\n')
self.assertEqual(c.rules['braces']['min-spaces-inside'], 0)
self.assertEqual(c.rules['braces']['max-spaces-inside'], 1248)
self.assertEqual(c.rules['braces']['min-spaces-inside-empty'], 2357)
self.assertEqual(c.rules['braces']['max-spaces-inside-empty'], -1)
with tempfile.NamedTemporaryFile('w') as f:
f.write('rules:\n'
' colons:\n'
' max-spaces-before: 1337\n')
f.flush()
c = config.YamlLintConfig('extends: ' + f.name + '\n'
'rules:\n'
' colons: enable\n')
self.assertEqual(c.rules['colons']['max-spaces-before'], 1337)
self.assertEqual(c.rules['colons']['max-spaces-after'], 1)
with tempfile.NamedTemporaryFile('w') as f1, \
tempfile.NamedTemporaryFile('w') as f2:
f1.write('rules:\n'
' colons:\n'
' max-spaces-before: 1337\n')
f1.flush()
f2.write('extends: ' + f1.name + '\n'
'rules:\n'
' colons: disable\n')
f2.flush()
c = config.YamlLintConfig('extends: ' + f2.name + '\n'
'rules:\n'
' colons: enable\n')
self.assertEqual(c.rules['colons']['max-spaces-before'], 0)
self.assertEqual(c.rules['colons']['max-spaces-after'], 1)
class ExtendedLibraryConfigTestCase(unittest.TestCase):
@@ -162,6 +364,9 @@ class ExtendedLibraryConfigTestCase(unittest.TestCase):
self.assertEqual(sorted(new.rules.keys()), sorted(old.rules.keys()))
for rule in new.rules:
self.assertEqual(new.rules[rule], old.rules[rule])
self.assertEqual(new.rules['empty-lines']['max'], 42)
self.assertEqual(new.rules['empty-lines']['max-start'], 43)
self.assertEqual(new.rules['empty-lines']['max-end'], 44)
def test_extend_config_override_rule_partly(self):
old = config.YamlLintConfig('extends: default')
@@ -175,3 +380,98 @@ class ExtendedLibraryConfigTestCase(unittest.TestCase):
self.assertEqual(sorted(new.rules.keys()), sorted(old.rules.keys()))
for rule in new.rules:
self.assertEqual(new.rules[rule], old.rules[rule])
self.assertEqual(new.rules['empty-lines']['max'], 2)
self.assertEqual(new.rules['empty-lines']['max-start'], 42)
self.assertEqual(new.rules['empty-lines']['max-end'], 0)
class IgnorePathConfigTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
super(IgnorePathConfigTestCase, cls).setUpClass()
bad_yaml = ('---\n'
'- key: val1\n'
' key: val2\n'
'- trailing space \n'
'- lonely hyphen\n')
cls.wd = build_temp_workspace({
'bin/file.lint-me-anyway.yaml': bad_yaml,
'bin/file.yaml': bad_yaml,
'file-at-root.yaml': bad_yaml,
'file.dont-lint-me.yaml': bad_yaml,
'ign-dup/file.yaml': bad_yaml,
'ign-dup/sub/dir/file.yaml': bad_yaml,
'ign-trail/file.yaml': bad_yaml,
'include/ign-dup/sub/dir/file.yaml': bad_yaml,
'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()
os.chdir(cls.wd)
@classmethod
def tearDownClass(cls):
super(IgnorePathConfigTestCase, cls).tearDownClass()
os.chdir(cls.backup_wd)
shutil.rmtree(cls.wd)
def test_run_with_ignored_path(self):
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:4:17: ' + trailing,
'./ign-dup/file.yaml:5:5: ' + hyphen,
'./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: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:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file.yaml:3:3: ' + keydup,
'./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,
)))

57
tests/test_linter.py Normal file
View File

@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# 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/>.
import io
import unittest
from yamllint.config import YamlLintConfig
from yamllint import linter
class LinterTestCase(unittest.TestCase):
def fake_config(self):
return YamlLintConfig('extends: default')
def test_run_on_string(self):
linter.run('test: document', self.fake_config())
def test_run_on_bytes(self):
linter.run(b'test: document', self.fake_config())
def test_run_on_unicode(self):
linter.run(u'test: document', self.fake_config())
def test_run_on_stream(self):
linter.run(io.StringIO(u'hello'), self.fake_config())
def test_run_on_int(self):
self.assertRaises(TypeError, linter.run, 42, self.fake_config())
def test_run_on_list(self):
self.assertRaises(TypeError, linter.run,
['h', 'e', 'l', 'l', 'o'], self.fake_config())
def test_run_on_non_ascii_chars(self):
s = (u'- hétérogénéité\n'
u'# 19.99 €\n')
linter.run(s, self.fake_config())
linter.run(s.encode('utf-8'), self.fake_config())
linter.run(s.encode('iso-8859-15'), self.fake_config())
s = (u'- お早う御座います。\n'
u'# الأَبْجَدِيَّة العَرَبِيَّة\n')
linter.run(s, self.fake_config())
linter.run(s.encode('utf-8'), self.fake_config())

85
tests/test_module.py Normal file
View File

@@ -0,0 +1,85 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2017 Adrien Vergé
#
# 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/>.
import os
import shutil
import subprocess
import tempfile
import sys
import unittest
PYTHON = sys.executable or 'python'
class ModuleTestCase(unittest.TestCase):
def setUp(self):
self.wd = tempfile.mkdtemp(prefix='yamllint-tests-')
# file with only one warning
with open(os.path.join(self.wd, 'warn.yaml'), 'w') as f:
f.write('key: value\n')
# file in dir
os.mkdir(os.path.join(self.wd, 'sub'))
with open(os.path.join(self.wd, 'sub', 'nok.yaml'), 'w') as f:
f.write('---\n'
'list: [ 1, 1, 2, 3, 5, 8] \n')
def tearDown(self):
shutil.rmtree(self.wd)
def test_run_module_no_args(self):
with self.assertRaises(subprocess.CalledProcessError) as ctx:
subprocess.check_output([PYTHON, '-m', 'yamllint'],
stderr=subprocess.STDOUT)
self.assertEqual(ctx.exception.returncode, 2)
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.assertRegex(ctx.exception.output.decode(),
r'No such file or directory')
def test_run_module_on_file(self):
out = subprocess.check_output(
[PYTHON, '-m', 'yamllint', os.path.join(self.wd, 'warn.yaml')])
lines = out.decode().splitlines()
self.assertIn('/warn.yaml', lines[0])
self.assertEqual('\n'.join(lines[1:]),
' 1:1 warning missing document start "---"'
' (document-start)\n')
def test_run_module_on_dir(self):
with self.assertRaises(subprocess.CalledProcessError) as ctx:
subprocess.check_output([PYTHON, '-m', 'yamllint', self.wd])
self.assertEqual(ctx.exception.returncode, 1)
files = ctx.exception.output.decode().split('\n\n')
self.assertIn(
'/warn.yaml\n'
' 1:1 warning missing document start "---"'
' (document-start)',
files[0])
self.assertIn(
'/sub/nok.yaml\n'
' 2:9 error too many spaces inside brackets'
' (brackets)\n'
' 2:27 error trailing spaces (trailing-spaces)',
files[1])

View File

@@ -18,8 +18,9 @@ import unittest
import yaml
from yamllint.parser import (line_generator, token_generator,
token_or_line_generator, Line, Token)
from yamllint.parser import (line_generator, token_or_comment_generator,
token_or_comment_or_line_generator,
Line, Token, Comment)
class ParserTestCase(unittest.TestCase):
@@ -61,26 +62,84 @@ class ParserTestCase(unittest.TestCase):
self.assertEqual(e[2].line_no, 3)
self.assertEqual(e[2].content, 'at the end')
def test_token_generator(self):
e = list(token_generator(''))
def test_token_or_comment_generator(self):
e = list(token_or_comment_generator(''))
self.assertEqual(len(e), 2)
self.assertEqual(e[0].prev, None)
self.assertIsNone(e[0].prev)
self.assertIsInstance(e[0].curr, yaml.Token)
self.assertIsInstance(e[0].next, yaml.Token)
self.assertEqual(e[1].prev, e[0].curr)
self.assertEqual(e[1].curr, e[0].next)
self.assertEqual(e[1].next, None)
self.assertIsNone(e[1].next)
e = list(token_generator('---\n'
'k: v\n'))
e = list(token_or_comment_generator('---\n'
'k: v\n'))
self.assertEqual(len(e), 9)
self.assertIsInstance(e[3].curr, yaml.KeyToken)
self.assertIsInstance(e[5].curr, yaml.ValueToken)
def test_token_or_line_generator(self):
e = list(token_or_line_generator('---\n'
'k: v\n'))
self.assertEqual(len(e), 12)
e = list(token_or_comment_generator('# start comment\n'
'- a\n'
'- key: val # key=val\n'
'# this is\n'
'# a block \n'
'# comment\n'
'- c\n'
'# end comment\n'))
self.assertEqual(len(e), 21)
self.assertIsInstance(e[1], Comment)
self.assertEqual(e[1], Comment(1, 1, '# start comment', 0))
self.assertEqual(e[11], Comment(3, 13, '# key=val', 0))
self.assertEqual(e[12], Comment(4, 1, '# this is', 0))
self.assertEqual(e[13], Comment(5, 1, '# a block ', 0))
self.assertEqual(e[14], Comment(6, 1, '# comment', 0))
self.assertEqual(e[18], Comment(8, 1, '# end comment', 0))
e = list(token_or_comment_generator('---\n'
'# no newline char'))
self.assertEqual(e[2], Comment(2, 1, '# no newline char', 0))
e = list(token_or_comment_generator('# just comment'))
self.assertEqual(e[1], Comment(1, 1, '# just comment', 0))
e = list(token_or_comment_generator('\n'
' # indented comment\n'))
self.assertEqual(e[1], Comment(2, 4, '# indented comment', 0))
e = list(token_or_comment_generator('\n'
'# trailing spaces \n'))
self.assertEqual(e[1], Comment(2, 1, '# trailing spaces ', 0))
e = [c for c in
token_or_comment_generator('# block\n'
'# comment\n'
'- data # inline comment\n'
'# block\n'
'# comment\n'
'- k: v # inline comment\n'
'- [ l, ist\n'
'] # inline comment\n'
'- { m: ap\n'
'} # inline comment\n'
'# block comment\n'
'- data # inline comment\n')
if isinstance(c, Comment)]
self.assertEqual(len(e), 10)
self.assertFalse(e[0].is_inline())
self.assertFalse(e[1].is_inline())
self.assertTrue(e[2].is_inline())
self.assertFalse(e[3].is_inline())
self.assertFalse(e[4].is_inline())
self.assertTrue(e[5].is_inline())
self.assertTrue(e[6].is_inline())
self.assertTrue(e[7].is_inline())
self.assertFalse(e[8].is_inline())
self.assertTrue(e[9].is_inline())
def test_token_or_comment_or_line_generator(self):
e = list(token_or_comment_or_line_generator('---\n'
'k: v # k=v\n'))
self.assertEqual(len(e), 13)
self.assertIsInstance(e[0], Token)
self.assertIsInstance(e[0].curr, yaml.StreamStartToken)
self.assertIsInstance(e[1], Token)
@@ -89,5 +148,6 @@ class ParserTestCase(unittest.TestCase):
self.assertIsInstance(e[3].curr, yaml.BlockMappingStartToken)
self.assertIsInstance(e[4].curr, yaml.KeyToken)
self.assertIsInstance(e[6].curr, yaml.ValueToken)
self.assertIsInstance(e[8], Line)
self.assertIsInstance(e[11], Line)
self.assertIsInstance(e[8], Comment)
self.assertIsInstance(e[9], Line)
self.assertIsInstance(e[12], Line)

190
tests/test_spec_examples.py Normal file
View File

@@ -0,0 +1,190 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# 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 io import open
import os
from tests.common import RuleTestCase
# This file checks examples from YAML 1.2 specification [1] against yamllint.
#
# [1]: http://www.yaml.org/spec/1.2/spec.html
#
# Example files generated with:
#
# from bs4 import BeautifulSoup
# with open('spec.html', encoding='iso-8859-1') as f:
# soup = BeautifulSoup(f, 'lxml')
# for ex in soup.find_all('div', class_='example'):
# title = ex.find('p', class_='title').find('b').get_text()
# id = '-'.join(title.split('\xa0')[:2])[:-1].lower()
# span = ex.find('span', class_='database')
# for br in span.find_all("br"):
# br.replace_with("\n")
# text = text.replace('\u2193', '') # downwards arrow
# text = text.replace('\u21d3', '') # double downwards arrow
# text = text.replace('\u00b7', ' ') # visible space
# text = text.replace('\u21d4', '') # byte order mark
# text = text.replace('\u2192', '\t') # right arrow
# text = text.replace('\u00b0', '') # empty scalar
# with open('tests/yaml-1.2-spec-examples/%s' % id, 'w',
# encoding='utf-8') as g:
# g.write(text)
class SpecificationTestCase(RuleTestCase):
rule_id = None
conf_general = ('document-start: disable\n'
'comments: {min-spaces-from-content: 1}\n'
'braces: {min-spaces-inside: 1, max-spaces-inside: 1}\n'
'brackets: {min-spaces-inside: 1, max-spaces-inside: 1}\n')
conf_overrides = {
'example-2.2': 'colons: {max-spaces-after: 2}\n',
'example-2.4': 'colons: {max-spaces-after: 3}\n',
'example-2.5': ('empty-lines: {max-end: 2}\n'
'brackets: {min-spaces-inside: 0, max-spaces-inside: 2}\n'
'commas: {max-spaces-before: -1}\n'),
'example-2.6': ('braces: {min-spaces-inside: 0, max-spaces-inside: 0}\n'
'indentation: disable\n'),
'example-2.12': ('empty-lines: {max-end: 1}\n'
'colons: {max-spaces-before: -1}\n'),
'example-2.16': 'empty-lines: {max-end: 1}\n',
'example-2.18': 'empty-lines: {max-end: 1}\n',
'example-2.19': 'empty-lines: {max-end: 1}\n',
'example-2.28': 'empty-lines: {max-end: 3}\n',
'example-5.3': ('indentation: {indent-sequences: false}\n'
'colons: {max-spaces-before: 1}\n'),
'example-6.4': 'trailing-spaces: disable\n',
'example-6.5': 'trailing-spaces: disable\n',
'example-6.6': 'trailing-spaces: disable\n',
'example-6.7': 'trailing-spaces: disable\n',
'example-6.8': 'trailing-spaces: disable\n',
'example-6.10': ('empty-lines: {max-end: 2}\n'
'trailing-spaces: disable\n'
'comments-indentation: disable\n'),
'example-6.11': ('empty-lines: {max-end: 1}\n'
'comments-indentation: disable\n'),
'example-6.13': 'comments-indentation: disable\n',
'example-6.14': 'comments-indentation: disable\n',
'example-6.23': 'colons: {max-spaces-before: 1}\n',
'example-7.4': ('colons: {max-spaces-before: 1}\n'
'indentation: disable\n'),
'example-7.5': 'trailing-spaces: disable\n',
'example-7.6': 'trailing-spaces: disable\n',
'example-7.7': 'indentation: disable\n',
'example-7.8': ('colons: {max-spaces-before: 1}\n'
'indentation: disable\n'),
'example-7.9': 'trailing-spaces: disable\n',
'example-7.11': ('colons: {max-spaces-before: 1}\n'
'indentation: disable\n'),
'example-7.13': ('brackets: {min-spaces-inside: 0, max-spaces-inside: 1}\n'
'commas: {max-spaces-before: 1, min-spaces-after: 0}\n'),
'example-7.14': 'indentation: disable\n',
'example-7.15': ('braces: {min-spaces-inside: 0, max-spaces-inside: 1}\n'
'commas: {max-spaces-before: 1, min-spaces-after: 0}\n'
'colons: {max-spaces-before: 1}\n'),
'example-7.16': 'indentation: disable\n',
'example-7.17': 'indentation: disable\n',
'example-7.18': 'indentation: disable\n',
'example-7.19': 'indentation: disable\n',
'example-7.20': ('colons: {max-spaces-before: 1}\n'
'indentation: disable\n'),
'example-8.1': 'empty-lines: {max-end: 1}\n',
'example-8.2': 'trailing-spaces: disable\n',
'example-8.5': ('comments-indentation: disable\n'
'trailing-spaces: disable\n'),
'example-8.6': 'empty-lines: {max-end: 1}\n',
'example-8.7': 'empty-lines: {max-end: 1}\n',
'example-8.8': 'trailing-spaces: disable\n',
'example-8.9': 'empty-lines: {max-end: 1}\n',
'example-8.14': 'colons: {max-spaces-before: 1}\n',
'example-8.16': 'indentation: {spaces: 1}\n',
'example-8.17': 'indentation: disable\n',
'example-8.20': ('indentation: {indent-sequences: false}\n'
'colons: {max-spaces-before: 1}\n'),
'example-8.22': 'indentation: disable\n',
'example-10.1': 'colons: {max-spaces-before: 2}\n',
'example-10.2': 'indentation: {indent-sequences: false}\n',
'example-10.8': 'truthy: disable\n',
'example-10.9': 'truthy: disable\n',
}
files = os.listdir(os.path.join(os.path.dirname(os.path.realpath(__file__)),
'yaml-1.2-spec-examples'))
assert len(files) == 132
def _gen_test(buffer, conf):
def test(self):
self.check(buffer, conf)
return test
# The following tests are blacklisted (i.e. will not be checked against
# yamllint), because pyyaml is currently not able to parse the contents
# (using yaml.parse()).
pyyaml_blacklist = (
'example-2.11',
'example-2.23',
'example-2.24',
'example-2.27',
'example-5.10',
'example-5.12',
'example-5.13',
'example-5.14',
'example-5.6',
'example-6.1',
'example-6.12',
'example-6.15',
'example-6.17',
'example-6.18',
'example-6.19',
'example-6.2',
'example-6.20',
'example-6.21',
'example-6.22',
'example-6.24',
'example-6.25',
'example-6.26',
'example-6.27',
'example-6.3',
'example-7.1',
'example-7.10',
'example-7.12',
'example-7.17',
'example-7.2',
'example-7.21',
'example-7.22',
'example-7.3',
'example-8.18',
'example-8.19',
'example-8.21',
'example-8.3',
'example-9.3',
'example-9.4',
'example-9.5',
)
for file in files:
if file in pyyaml_blacklist:
continue
with open('tests/yaml-1.2-spec-examples/' + file, encoding='utf-8') as f:
conf = conf_general + conf_overrides.get(file, '')
setattr(SpecificationTestCase, 'test_' + file,
_gen_test(f.read(), conf))

View File

@@ -14,13 +14,13 @@
# 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.rules.common import RuleTestCase
from tests.common import RuleTestCase
class YamlLintTestCase(RuleTestCase):
rule_id = None # syntax error
def test_lint(self):
def test_syntax_errors(self):
self.check('---\n'
'this is not: valid: YAML\n', None, problem=(2, 19))
self.check('---\n'
@@ -29,13 +29,21 @@ class YamlLintTestCase(RuleTestCase):
'this is an error: [\n'
'\n'
'...\n', None, problem=(6, 1))
def test_directives(self):
self.check('%YAML 1.2\n'
'%TAG ! tag:clarkevans.com,2002:\n'
'doc: ument\n'
'...\n', None, problem=(3, 1))
def test_empty_flows(self):
self.check('---\n'
'- []\n'
'- {}\n'
'- [\n'
']\n'
'- {\n'
'}\n'
'...\n', None)
def test_explicit_mapping(self):
self.check('---\n'
'? key\n'
@@ -67,3 +75,20 @@ class YamlLintTestCase(RuleTestCase):
' Atlanta Braves]\n'
': [2001-07-02, 2001-08-12,\n'
' 2001-08-14]\n', None)
def test_sets(self):
self.check('---\n'
'? key one\n'
'? key two\n'
'? [non, scalar, key]\n'
'? key with value\n'
': value\n'
'...\n', None)
self.check('---\n'
'? - multi\n'
' - line\n'
' - keys\n'
'? in:\n'
' a:\n'
' set\n'
'...\n', None)

View File

@@ -0,0 +1,433 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 Adrien Vergé
#
# 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 YamllintDirectivesTestCase(RuleTestCase):
conf = ('commas: disable\n'
'trailing-spaces: {}\n'
'colons: {max-spaces-before: 1}\n')
def test_disable_directive(self):
self.check('---\n'
'- [valid , YAML]\n'
'- trailing spaces \n'
'- bad : colon\n'
'- [valid , YAML]\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem1=(3, 18, 'trailing-spaces'),
problem2=(4, 8, 'colons'),
problem3=(6, 7, 'colons'),
problem4=(6, 26, 'trailing-spaces'))
self.check('---\n'
'- [valid , YAML]\n'
'- trailing spaces \n'
'# yamllint disable\n'
'- bad : colon\n'
'- [valid , YAML]\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem=(3, 18, 'trailing-spaces'))
self.check('---\n'
'- [valid , YAML]\n'
'# yamllint disable\n'
'- trailing spaces \n'
'- bad : colon\n'
'- [valid , YAML]\n'
'# yamllint enable\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem1=(8, 7, 'colons'),
problem2=(8, 26, 'trailing-spaces'))
def test_disable_directive_with_rules(self):
self.check('---\n'
'- [valid , YAML]\n'
'- trailing spaces \n'
'# yamllint disable rule:trailing-spaces\n'
'- bad : colon\n'
'- [valid , YAML]\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem1=(3, 18, 'trailing-spaces'),
problem2=(5, 8, 'colons'),
problem3=(7, 7, 'colons'))
self.check('---\n'
'- [valid , YAML]\n'
'# yamllint disable rule:trailing-spaces\n'
'- trailing spaces \n'
'- bad : colon\n'
'- [valid , YAML]\n'
'# yamllint enable rule:trailing-spaces\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem1=(5, 8, 'colons'),
problem2=(8, 7, 'colons'),
problem3=(8, 26, 'trailing-spaces'))
self.check('---\n'
'- [valid , YAML]\n'
'# yamllint disable rule:trailing-spaces\n'
'- trailing spaces \n'
'- bad : colon\n'
'- [valid , YAML]\n'
'# yamllint enable\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem1=(5, 8, 'colons'),
problem2=(8, 7, 'colons'),
problem3=(8, 26, 'trailing-spaces'))
self.check('---\n'
'- [valid , YAML]\n'
'# yamllint disable\n'
'- trailing spaces \n'
'- bad : colon\n'
'- [valid , YAML]\n'
'# yamllint enable rule:trailing-spaces\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem=(8, 26, 'trailing-spaces'))
self.check('---\n'
'- [valid , YAML]\n'
'# yamllint disable rule:colons\n'
'- trailing spaces \n'
'# yamllint disable rule:trailing-spaces\n'
'- bad : colon\n'
'- [valid , YAML]\n'
'# yamllint enable rule:colons\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem1=(4, 18, 'trailing-spaces'),
problem2=(9, 7, 'colons'))
def test_disable_line_directive(self):
self.check('---\n'
'- [valid , YAML]\n'
'- trailing spaces \n'
'# yamllint disable-line\n'
'- bad : colon\n'
'- [valid , YAML]\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem1=(3, 18, 'trailing-spaces'),
problem2=(7, 7, 'colons'),
problem3=(7, 26, 'trailing-spaces'))
self.check('---\n'
'- [valid , YAML]\n'
'- trailing spaces \n'
'- bad : colon # yamllint disable-line\n'
'- [valid , YAML]\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem1=(3, 18, 'trailing-spaces'),
problem2=(6, 7, 'colons'),
problem3=(6, 26, 'trailing-spaces'))
self.check('---\n'
'- [valid , YAML]\n'
'- trailing spaces \n'
'- bad : colon\n'
'- [valid , YAML] # yamllint disable-line\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem1=(3, 18, 'trailing-spaces'),
problem2=(4, 8, 'colons'),
problem3=(6, 7, 'colons'),
problem4=(6, 26, 'trailing-spaces'))
def test_disable_line_directive_with_rules(self):
self.check('---\n'
'- [valid , YAML]\n'
'# yamllint disable-line rule:colons\n'
'- trailing spaces \n'
'- bad : colon\n'
'- [valid , YAML]\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem1=(4, 18, 'trailing-spaces'),
problem2=(5, 8, 'colons'),
problem3=(7, 7, 'colons'),
problem4=(7, 26, 'trailing-spaces'))
self.check('---\n'
'- [valid , YAML]\n'
'- trailing spaces # yamllint disable-line rule:colons \n'
'- bad : colon\n'
'- [valid , YAML]\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem1=(3, 55, 'trailing-spaces'),
problem2=(4, 8, 'colons'),
problem3=(6, 7, 'colons'),
problem4=(6, 26, 'trailing-spaces'))
self.check('---\n'
'- [valid , YAML]\n'
'- trailing spaces \n'
'# yamllint disable-line rule:colons\n'
'- bad : colon\n'
'- [valid , YAML]\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem1=(3, 18, 'trailing-spaces'),
problem2=(7, 7, 'colons'),
problem3=(7, 26, 'trailing-spaces'))
self.check('---\n'
'- [valid , YAML]\n'
'- trailing spaces \n'
'- bad : colon # yamllint disable-line rule:colons\n'
'- [valid , YAML]\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem1=(3, 18, 'trailing-spaces'),
problem2=(6, 7, 'colons'),
problem3=(6, 26, 'trailing-spaces'))
self.check('---\n'
'- [valid , YAML]\n'
'- trailing spaces \n'
'- bad : colon\n'
'- [valid , YAML]\n'
'# yamllint disable-line rule:colons\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem1=(3, 18, 'trailing-spaces'),
problem2=(4, 8, 'colons'),
problem3=(7, 26, 'trailing-spaces'))
self.check('---\n'
'- [valid , YAML]\n'
'- trailing spaces \n'
'- bad : colon\n'
'- [valid , YAML]\n'
'# yamllint disable-line rule:colons rule:trailing-spaces\n'
'- bad : colon and spaces \n'
'- [valid , YAML]\n',
self.conf,
problem1=(3, 18, 'trailing-spaces'),
problem2=(4, 8, 'colons'))
def test_disable_directive_with_rules_and_dos_lines(self):
conf = self.conf + 'new-lines: {type: dos}\n'
self.check('---\r\n'
'- [valid , YAML]\r\n'
'# yamllint disable rule:trailing-spaces\r\n'
'- trailing spaces \r\n'
'- bad : colon\r\n'
'- [valid , YAML]\r\n'
'# yamllint enable rule:trailing-spaces\r\n'
'- bad : colon and spaces \r\n'
'- [valid , YAML]\r\n',
conf,
problem1=(5, 8, 'colons'),
problem2=(8, 7, 'colons'),
problem3=(8, 26, 'trailing-spaces'))
self.check('---\r\n'
'- [valid , YAML]\r\n'
'- trailing spaces \r\n'
'- bad : colon\r\n'
'- [valid , YAML]\r\n'
'# yamllint disable-line rule:colons\r\n'
'- bad : colon and spaces \r\n'
'- [valid , YAML]\r\n',
conf,
problem1=(3, 18, 'trailing-spaces'),
problem2=(4, 8, 'colons'),
problem3=(7, 26, 'trailing-spaces'))
def test_directive_on_last_line(self):
conf = 'new-line-at-end-of-file: {}'
self.check('---\n'
'no new line',
conf,
problem=(2, 12, 'new-line-at-end-of-file'))
self.check('---\n'
'# yamllint disable\n'
'no new line',
conf)
self.check('---\n'
'no new line # yamllint disable',
conf)
def test_indented_directive(self):
conf = 'brackets: {min-spaces-inside: 0, max-spaces-inside: 0}'
self.check('---\n'
'- a: 1\n'
' b:\n'
' c: [ x]\n',
conf,
problem=(4, 12, 'brackets'))
self.check('---\n'
'- a: 1\n'
' b:\n'
' # yamllint disable-line rule:brackets\n'
' c: [ x]\n',
conf)
def test_directive_on_itself(self):
conf = ('comments: {min-spaces-from-content: 2}\n'
'comments-indentation: {}\n')
self.check('---\n'
'- a: 1 # comment too close\n'
' b:\n'
' # wrong indentation\n'
' c: [x]\n',
conf,
problem1=(2, 8, 'comments'),
problem2=(4, 2, 'comments-indentation'))
self.check('---\n'
'# yamllint disable\n'
'- a: 1 # comment too close\n'
' b:\n'
' # wrong indentation\n'
' c: [x]\n',
conf)
self.check('---\n'
'- a: 1 # yamllint disable-line\n'
' b:\n'
' # yamllint disable-line\n'
' # wrong indentation\n'
' c: [x]\n',
conf)
self.check('---\n'
'- a: 1 # yamllint disable-line rule:comments\n'
' b:\n'
' # yamllint disable-line rule:comments-indentation\n'
' # wrong indentation\n'
' c: [x]\n',
conf)
self.check('---\n'
'# yamllint disable\n'
'- a: 1 # comment too close\n'
' # yamllint enable rule:comments-indentation\n'
' b:\n'
' # wrong indentation\n'
' c: [x]\n',
conf,
problem=(6, 2, 'comments-indentation'))
def test_disable_file_directive(self):
conf = ('comments: {min-spaces-from-content: 2}\n'
'comments-indentation: {}\n')
self.check('# yamllint disable-file\n'
'---\n'
'- a: 1 # comment too close\n'
' b:\n'
' # wrong indentation\n'
' c: [x]\n',
conf)
self.check('# yamllint disable-file\n'
'---\n'
'- a: 1 # comment too close\n'
' b:\n'
' # wrong indentation\n'
' c: [x]\n',
conf)
self.check('#yamllint disable-file\n'
'---\n'
'- a: 1 # comment too close\n'
' b:\n'
' # wrong indentation\n'
' c: [x]\n',
conf)
self.check('#yamllint disable-file \n'
'---\n'
'- a: 1 # comment too close\n'
' b:\n'
' # wrong indentation\n'
' c: [x]\n',
conf)
self.check('---\n'
'# yamllint disable-file\n'
'- a: 1 # comment too close\n'
' b:\n'
' # wrong indentation\n'
' c: [x]\n',
conf,
problem1=(3, 8, 'comments'),
problem2=(5, 2, 'comments-indentation'))
self.check('# yamllint disable-file: rules cannot be specified\n'
'---\n'
'- a: 1 # comment too close\n'
' b:\n'
' # wrong indentation\n'
' c: [x]\n',
conf,
problem1=(3, 8, 'comments'),
problem2=(5, 2, 'comments-indentation'))
self.check('AAAA yamllint disable-file\n'
'---\n'
'- a: 1 # comment too close\n'
' b:\n'
' # wrong indentation\n'
' c: [x]\n',
conf,
problem1=(1, 1, 'document-start'),
problem2=(3, 8, 'comments'),
problem3=(5, 2, 'comments-indentation'))
def test_disable_file_directive_not_at_first_position(self):
self.check('# yamllint disable-file\n'
'---\n'
'- bad : colon and spaces \n',
self.conf)
self.check('---\n'
'# yamllint disable-file\n'
'- bad : colon and spaces \n',
self.conf,
problem1=(3, 7, 'colons'),
problem2=(3, 26, 'trailing-spaces'))
def test_disable_file_directive_with_syntax_error(self):
self.check('# This file is not valid YAML (it is a Jinja template)\n'
'{% if extra_info %}\n'
'key1: value1\n'
'{% endif %}\n'
'key2: value2\n',
self.conf,
problem=(2, 2, 'syntax'))
self.check('# yamllint disable-file\n'
'# This file is not valid YAML (it is a Jinja template)\n'
'{% if extra_info %}\n'
'key1: value1\n'
'{% endif %}\n'
'key2: value2\n',
self.conf)
def test_disable_file_directive_with_dos_lines(self):
self.check('# yamllint disable-file\r\n'
'---\r\n'
'- bad : colon and spaces \r\n',
self.conf)
self.check('# yamllint disable-file\r\n'
'# This file is not valid YAML (it is a Jinja template)\r\n'
'{% if extra_info %}\r\n'
'key1: value1\r\n'
'{% endif %}\r\n'
'key2: value2\r\n',
self.conf)

View File

@@ -0,0 +1,6 @@
Block style: !!map
Clark : Evans
Ingy : döt Net
Oren : Ben-Kiki
Flow style: !!map { Clark: Evans, Ingy: döt Net, Oren: Ben-Kiki }

View File

@@ -0,0 +1,6 @@
Block style: !!seq
- Clark Evans
- Ingy döt Net
- Oren Ben-Kiki
Flow style: !!seq [ Clark Evans, Ingy döt Net, Oren Ben-Kiki ]

View File

@@ -0,0 +1,4 @@
Block style: !!str |-
String: just a theory.
Flow style: !!str "String: just a theory."

View File

@@ -0,0 +1,2 @@
!!null null: value for null key
key with null value: !!null null

View File

@@ -0,0 +1,2 @@
YAML is a superset of JSON: !!bool true
Pluto is a planet: !!bool false

View File

@@ -0,0 +1,3 @@
negative: !!int -12
zero: !!int 0
positive: !!int 34

View File

@@ -0,0 +1,5 @@
negative: !!float -1
zero: !!float 0
positive: !!float 2.3e4
infinity: !!float .inf
not a number: !!float .nan

View File

@@ -0,0 +1,5 @@
A null: null
Booleans: [ true, false ]
Integers: [ 0, -0, 3, -19 ]
Floats: [ 0., -0.0, 12e03, -2E+05 ]
Invalid: [ True, Null, 0o7, 0x3A, +12.3 ]

View File

@@ -0,0 +1,7 @@
A null: null
Also a null: # Empty
Not a null: ""
Booleans: [ true, True, false, FALSE ]
Integers: [ 0, 0o7, 0x3A, -19 ]
Floats: [ 0., -0.0, .5, +12e03, -2E+05 ]
Also floats: [ .inf, -.Inf, +.INF, .NAN ]

View File

@@ -0,0 +1,3 @@
- Mark McGwire
- Sammy Sosa
- Ken Griffey

View File

@@ -0,0 +1,8 @@
---
hr:
- Mark McGwire
# Following node labeled SS
- &SS Sammy Sosa
rbi:
- *SS # Subsequent occurrence
- Ken Griffey

View File

@@ -0,0 +1,9 @@
? - Detroit Tigers
- Chicago cubs
:
- 2001-07-23
? [ New York Yankees,
Atlanta Braves ]
: [ 2001-07-02, 2001-08-12,
2001-08-14 ]

View File

@@ -0,0 +1,9 @@
---
# Products purchased
- item : Super Hoop
quantity: 1
- item : Basketball
quantity: 4
- item : Big Shoes
quantity: 1

View File

@@ -0,0 +1,4 @@
# ASCII Art
--- |
\//||\/||
// || ||__

View File

@@ -0,0 +1,4 @@
--- >
Mark McGwire's
year was crippled
by a knee injury.

View File

@@ -0,0 +1,8 @@
>
Sammy Sosa completed another
fine season with great stats.
63 Home Runs
0.288 Batting Average
What a year!

View File

@@ -0,0 +1,8 @@
name: Mark McGwire
accomplishment: >
Mark set a major league
home run record in 1998.
stats: |
65 Home Runs
0.278 Batting Average

View File

@@ -0,0 +1,7 @@
unicode: "Sosa did fine.\u263A"
control: "\b1998\t1999\t2000\n"
hex esc: "\x0d\x0a is \r\n"
single: '"Howdy!" he cried.'
quoted: ' # Not a ''comment''.'
tie-fighter: '|\-*-/|'

View File

@@ -0,0 +1,7 @@
plain:
This unquoted scalar
spans many lines.
quoted: "So does this
quoted scalar.\n"

View File

@@ -0,0 +1,5 @@
canonical: 12345
decimal: +12345
octal: 0o14
hexadecimal: 0xC

View File

@@ -0,0 +1,3 @@
hr: 65 # Home runs
avg: 0.278 # Batting average
rbi: 147 # Runs Batted In

View File

@@ -0,0 +1,5 @@
canonical: 1.23015e+3
exponential: 12.3015e+02
fixed: 1230.15
negative infinity: -.inf
not a number: .NaN

View File

@@ -0,0 +1,3 @@
null:
booleans: [ true, false ]
string: '012345'

View File

@@ -0,0 +1,4 @@
canonical: 2001-12-15T02:59:43.1Z
iso8601: 2001-12-14t21:59:43.10-05:00
spaced: 2001-12-14 21:59:43.10 -5
date: 2002-12-14

View File

@@ -0,0 +1,14 @@
---
not-date: !!str 2002-04-28
picture: !!binary |
R0lGODlhDAAMAIQAAP//9/X
17unp5WZmZgAAAOfn515eXv
Pz7Y6OjuDg4J+fn5OTk6enp
56enmleECcgggoBADs=
application specific tag: !something |
The semantics of the tag
above may be different for
different documents.

View File

@@ -0,0 +1,14 @@
%TAG ! tag:clarkevans.com,2002:
--- !shape
# Use the ! handle for presenting
# tag:clarkevans.com,2002:circle
- !circle
center: &ORIGIN {x: 73, y: 129}
radius: 7
- !line
start: *ORIGIN
finish: { x: 89, y: 102 }
- !label
start: *ORIGIN
color: 0xFFEEBB
text: Pretty vector drawing.

View File

@@ -0,0 +1,7 @@
# Sets are represented as a
# Mapping where each key is
# associated with a null value
--- !!set
? Mark McGwire
? Sammy Sosa
? Ken Griff

View File

@@ -0,0 +1,7 @@
# Ordered maps are represented as
# A sequence of mappings, with
# each mapping having one key
--- !!omap
- Mark McGwire: 65
- Sammy Sosa: 63
- Ken Griffy: 58

View File

@@ -0,0 +1,29 @@
--- !<tag:clarkevans.com,2002:invoice>
invoice: 34843
date : 2001-01-23
bill-to: &id001
given : Chris
family : Dumars
address:
lines: |
458 Walkman Dr.
Suite #292
city : Royal Oak
state : MI
postal : 48046
ship-to: *id001
product:
- sku : BL394D
quantity : 4
description : Basketball
price : 450.00
- sku : BL4438H
quantity : 1
description : Super Hoop
price : 2392.00
tax : 251.42
total: 4443.52
comments:
Late afternoon is best.
Backup contact is Nancy
Billsmer @ 338-4338.

View File

@@ -0,0 +1,29 @@
---
Time: 2001-11-23 15:01:42 -5
User: ed
Warning:
This is an error message
for the log file
---
Time: 2001-11-23 15:02:31 -5
User: ed
Warning:
A slightly different error
message.
---
Date: 2001-11-23 15:03:17 -5
User: ed
Fatal:
Unknown variable "bar"
Stack:
- file: TopClass.py
line: 23
code: |
x = MoreObject("345\n")
- file: MoreClass.py
line: 58
code: |-
foo = bar

View File

@@ -0,0 +1,8 @@
american:
- Boston Red Sox
- Detroit Tigers
- New York Yankees
national:
- New York Mets
- Chicago Cubs
- Atlanta Braves

View File

@@ -0,0 +1,8 @@
-
name: Mark McGwire
hr: 65
avg: 0.278
-
name: Sammy Sosa
hr: 63
avg: 0.288

View File

@@ -0,0 +1,5 @@
- [name , hr, avg ]
- [Mark McGwire, 65, 0.278]
- [Sammy Sosa , 63, 0.288]

View File

@@ -0,0 +1,5 @@
Mark McGwire: {hr: 65, avg: 0.278}
Sammy Sosa: {
hr: 63,
avg: 0.288
}

View File

@@ -0,0 +1,10 @@
# Ranking of 1998 home runs
---
- Mark McGwire
- Sammy Sosa
- Ken Griffey
# Team ranking
---
- Chicago Cubs
- St Louis Cardinals

View File

@@ -0,0 +1,10 @@
---
time: 20:03:20
player: Sammy Sosa
action: strike (miss)
...
---
time: 20:03:47
player: Sammy Sosa
action: grand slam
...

View File

@@ -0,0 +1,8 @@
---
hr: # 1998 hr ranking
- Mark McGwire
- Sammy Sosa
rbi:
# 1998 rbi ranking
- Sammy Sosa
- Ken Griffey

View File

@@ -0,0 +1 @@
# Comment only.

View File

@@ -0,0 +1,2 @@
commercial-at: @text
grave-accent: `text

View File

@@ -0,0 +1,3 @@
|
Line break (no glyph)
Line break (glyphed)

View File

@@ -0,0 +1,6 @@
# Tabs and spaces
quoted: "Quoted "
block: |
void main() {
printf("Hello, world!\n");
}

View File

@@ -0,0 +1,5 @@
"Fun with \\
\" \a \b \e \f \
\n \r \t \v \0 \
\  \_ \N \L \P \
\x41 \u0041 \U00000041"

View File

@@ -0,0 +1,3 @@
Bad escapes:
"\c
\xq-"

View File

@@ -0,0 +1,3 @@
- Invalid use of BOM
- Inside a document.

View File

@@ -0,0 +1,7 @@
sequence:
- one
- two
mapping:
? sky
: blue
sea : green

View File

@@ -0,0 +1,2 @@
sequence: [ one, two, ]
mapping: { sky: blue, sea: green }

View File

@@ -0,0 +1 @@
# Comment only.

View File

@@ -0,0 +1,2 @@
anchored: !local &anchor value
alias: *anchor

Some files were not shown because too many files have changed in this diff Show More