Compare commits

..

183 Commits

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

    Blaise Pascal: Je vous écris une longue lettre parce que
      je n'ai pas le temps d'en écrire une courte.
2016-01-25 11:01:42 +01:00
Adrien Vergé
97c446907c Rules: line-length: Add option allow-non-breakable-words 2016-01-24 22:46:10 +01:00
Adrien Vergé
376a6ed484 Doc: Enhance short description 2016-01-24 18:40:48 +01:00
Adrien Vergé
a1eb9d7d2f yamllint version 0.5.2 2016-01-24 18:07:36 +01:00
Adrien Vergé
45538fb08a Doc: Explicit installation by adding sudo in README 2016-01-24 18:05:27 +01:00
Adrien Vergé
be998593dd Distribution: Create script with setup.py 2016-01-24 18:02:42 +01:00
Adrien Vergé
5ed496f471 Distribution: Remove unneeded setup_requires
With the new project layout, `pyyaml` is not needed anymore for parsing
setup.py.
2016-01-24 17:57:11 +01:00
Adrien Vergé
dbbecb5875 Refactor project layout to import yamllint alone
Currently importing yamllint recursively imports its submodules, which
finally requires having pyyaml installed. This is a problem when you
just want to import APP_VERSION from yamllint. For instance, setup.py
imports yamllint to know the version, but doesn't know yet that pyyaml
is to be installed, because it is stated in setup.py itself.

To solve this, yamllint/__init__.py will only contain constants. The
linting functions will be in yamllint/linter.py.
2016-01-24 17:48:20 +01:00
Adrien Vergé
7b147cb411 Tests: Remove Python 2.6 from CI tests
Because:

1. It is old. VERY old.

2. Some useful methods (`assertRaisesRegexp`, `assertIsInstance`) are
   only available from Python 2.7.
2016-01-24 17:39:36 +01:00
Adrien Vergé
fc108e7cee Config: Refactor to use YamlLintConfig objects 2016-01-24 17:39:27 +01:00
Adrien Vergé
792bdf99b4 yamllint version 0.5.1 2016-01-24 15:03:38 +01:00
Adrien Vergé
92798dbda9 Distribution: Add new keywords 2016-01-24 15:03:38 +01:00
Adrien Vergé
e3ebea6033 Distribution: Fix broken setup_requires
The `pyyaml` dependency is needed in `install_requires` but also in
`setup_requires`, because running `setup.py` requires importing
`yamllint`, which itself imports `yaml`.
2016-01-24 14:59:32 +01:00
Adrien Vergé
7983c66093 Doc: Clarify Python compatibility in README 2016-01-23 14:32:02 +01:00
Adrien Vergé
fee72d484e Doc: Add a screenshot 2016-01-23 14:30:24 +01:00
Adrien Vergé
387d14f816 yamllint version 0.5.0 2016-01-22 19:10:05 +01:00
Adrien Vergé
ba8a9d0ba1 Doc: Give an explicit link from configuration to rules 2016-01-22 18:42:03 +01:00
Adrien Vergé
26b5364be4 Doc: Add Read The Docs status badge in README 2016-01-22 18:20:31 +01:00
Adrien Vergé
47d6534e75 Doc: Write the configuration page 2016-01-22 18:20:31 +01:00
Adrien Vergé
237db5aeef Doc: Document how to use the yamllint Python module 2016-01-22 18:20:31 +01:00
Adrien Vergé
6e9de02eac Doc: Update index
Add a brief description and remove unused links.
2016-01-22 18:20:31 +01:00
Adrien Vergé
044c049462 Doc: Document rules 2016-01-22 18:20:31 +01:00
Adrien Vergé
48589176c7 Doc: Convert README.md to README.rst 2016-01-22 18:20:31 +01:00
Adrien Vergé
38234a1d3c Doc: Generate documentation with Sphinx
HTML documentation should be built with sphinx. This enables easy
integration with Read The Docs [1]. It can also be generated manually by
running:

    make -C docs html

A man page can be generated by running:

    make -C docs man

[1]: http://yamllint.readthedocs.org/
2016-01-22 18:20:28 +01:00
Adrien Vergé
1bfd18097a Rules: indentation: Add 'check-multi-line-strings' option
This options allows the user to control whether to lint indentation
inside multi-line scalars or not.

When enabled, such YAML source will be detected as a problem:

    - C code: void main() {
                  printf("foo");
              }

whereas this one would not:

    - C code: void main() {
              printf("foo");
              }
2016-01-22 14:23:37 +01:00
Adrien Vergé
08f99ccc19 Rules: new-lines: Force type to be in ('unix', 'dos') 2016-01-21 21:59:53 +01:00
Adrien Vergé
7b6f024448 yamllint version 0.4.0 2016-01-20 18:18:35 +01:00
Adrien Vergé
75b4758c95 cli: 'standard' format: Print filename only when error 2016-01-20 17:55:54 +01:00
Adrien Vergé
0e98df2643 cli: Allow passing directories as arguments
For instance:

    yamllint .
    yamllint file.yml ../my-other-dir
2016-01-20 17:55:54 +01:00
Adrien Vergé
d4189083d0 Introduce the 'cli' module and call it from the script 2016-01-20 17:39:26 +01:00
Adrien Vergé
67d13d60ae Rules: indentation: Check multi-line scalars 2016-01-20 17:39:11 +01:00
Adrien Vergé
96465008ab Rules: Fix spaces_before when prev is multi-line scalar
YAML content like the following one produced an error, because the
multi-line ScalarToken ends at the beginning of the 4th line (the one
with the value):

    ? >
        multi-line
        key
    : value
2016-01-20 17:38:48 +01:00
Adrien Vergé
847f7e3fff Rules: comments: Fix bug when multi-line scalar
YAML content like the following one produced an error, because the
ScalarToken associated whose value is "this is plain text" ends at the
beginning of the 5th line (the one with the comment):

    ---
    string: >
      this is plain text

    # comment
2016-01-20 10:45:59 +01:00
Adrien Vergé
6a24781f96 Tests: indentation: Add explicit keys test cases 2016-01-20 10:45:52 +01:00
Adrien Vergé
33224a04e4 yamllint version 0.3.0 2016-01-19 22:58:59 +01:00
Adrien Vergé
fd9d2a00ff Doc: Update README with examples 2016-01-19 22:57:12 +01:00
Adrien Vergé
0b0251bacc Rules: indentation: Add the 'indent-sequences' option
Using either 'yes', 'no' or 'whatever', the user will be able to choose
whether to force block sequence items to be indented, to force them not
to be indented, or don't care, respectively.
2016-01-19 22:37:58 +01:00
Adrien Vergé
ad5cec9c6c Config: Allow overriding only one option when extending 2016-01-19 21:49:58 +01:00
Adrien Vergé
fb14cbdbd9 Config: Allow options to be in a pre-defined list 2016-01-19 21:12:11 +01:00
Adrien Vergé
8288a6f331 Rules: colons: Apply to '?' also 2016-01-19 19:45:13 +01:00
Adrien Vergé
9d8b0d4d2c Rules: commas: Don't allow a comma on a new line
Forbid such constructions:

    [ a, b, c
      , d, e ]
2016-01-19 19:42:56 +01:00
Adrien Vergé
39c878c819 Rules: indentation: Rewrite the algorithm (again)
Use a new, better thought algorithm that keeps an history stack with all
the parents indentations.
2016-01-19 19:42:56 +01:00
Adrien Vergé
222f7a27c1 Make syntax errors prevail over all yamllint problems 2016-01-19 17:18:57 +01:00
Adrien Vergé
effb4db3b4 Tests: Rules: Remove unused line and column args
Now that every test case use the `problem=(x, y)` syntax.
2016-01-19 17:18:57 +01:00
Adrien Vergé
d617eb70ae Rules: Keep a persistent context for token rules
This will be needed to build a clean indentation checking algorithm.
2016-01-19 17:18:57 +01:00
Adrien Vergé
f09aef4f89 Rules: comments-indentation: Allow two levels
Previously only comments that were indented like the following content
line were allowed, e.g.:

    prev: line:
      # commented line
      current: line

With this change, such new cases are also allowed:

      prev: line
      # commented line 1
    # commented line 2
    current: line
2016-01-19 17:18:57 +01:00
Adrien Vergé
01c12f2462 Syntax errors: Use the BaseLoader for safety 2016-01-19 16:35:57 +01:00
Adrien Vergé
918f15b68d Make syntax errors prevail over yamllint 'warnings'
When both a syntax error (unability to parse a document) and a cosmetic
yamllint problem are found at the same place, the yamllint problem had
the priority -- and the syntax error was not displayed.

This had the following problem: if a rule is at the 'warning' level, its
problems will not make the `yamllint` script return a failure return
code (`!= 0`), even when it should (because there was a syntax error,
precisely).

This commit changes this behavior by preferring yamllint problems only
when they have the 'error' level.
2016-01-15 18:46:49 +01:00
Adrien Vergé
97e2210ec9 Don't treat non-importable YAML as syntax error
`yaml.load()` exceptions are not necessarily syntax errors. For
instance, the following YAML source cannot be `load()`ed into a Python
object, but is valid nonetheless:

    ? - Detroit Tigers
      - Chicago cubs
    :
      - 2001-07-23

    ? [ New York Yankees,
        Atlanta Braves ]
    : [ 2001-07-02, 2001-08-12,
        2001-08-14 ]

This commit detects syntax errors from `yaml.parse()` exceptions rather
than `yaml.load_all()`.
2016-01-15 18:46:49 +01:00
Adrien Vergé
1934206cef Rules: comments-indentation: Fix typo 2016-01-15 18:46:40 +01:00
Adrien Vergé
1235eba94e yamllint version 0.2.0 2016-01-15 09:39:50 +01:00
Adrien Vergé
11a14d4df8 Distribution: Update program description 2016-01-14 21:08:10 +01:00
Adrien Vergé
233a70adb3 Rules: Add the 'comments-indentation' rule 2016-01-14 21:04:41 +01:00
Adrien Vergé
e81b73c111 Rules: indentation: Rewrite algorithm 2016-01-14 20:57:35 +01:00
Adrien Vergé
3989a09d32 Rules: comments: Allow empty comments 2016-01-14 19:58:35 +01:00
Adrien Vergé
5cc900f2a8 Rules: document-start: Allow directives 2016-01-14 19:58:05 +01:00
Adrien Vergé
851b9ac42c Rules: Add the 'comments' rule 2016-01-14 11:17:01 +01:00
Adrien Vergé
5c4c208b98 Rules: Add the 'braces' rule 2016-01-14 10:46:16 +01:00
Adrien Vergé
d08eb22081 Rules: Add the 'brackets' rule 2016-01-14 10:46:16 +01:00
Adrien Vergé
a5b384ab21 Rules: Add the 'commas' rule 2016-01-14 10:46:16 +01:00
Adrien Vergé
cfea0661ed Rules: Make max-spaces-* generic
The goal being to use them in the 'colons', 'hyphens', 'commas', etc.
rules.
2016-01-14 10:46:16 +01:00
Adrien Vergé
07c5b4177c Rewrite syntax errors handling and test them
If a syntax errors occurs at the same place than a regular yamllint rule
error, only the yamllint one is issued.
2016-01-14 10:46:16 +01:00
Adrien Vergé
bf96bdde01 Tests: Remove assertIsInstance to support Python 2.6 2016-01-14 10:46:16 +01:00
Adrien Vergé
e2d68dac14 Tests: Travis and Coveralls integration 2016-01-14 10:46:16 +01:00
206 changed files with 8488 additions and 551 deletions

3
.gitignore vendored
View File

@@ -1,2 +1,5 @@
__pycache__ __pycache__
*.py[cod] *.py[cod]
/docs/_build
/dist
/yamllint.egg-info

17
.travis.yml Normal file
View File

@@ -0,0 +1,17 @@
---
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 '*.yaml' '*.yml')
- coverage run --source=yamllint setup.py test
after_success:
coveralls

3
MANIFEST.in Normal file
View File

@@ -0,0 +1,3 @@
include LICENSE
include README.rst
include docs/*

View File

@@ -1,3 +0,0 @@
.PHONY: tests
tests:
python -m unittest discover

View File

@@ -1 +0,0 @@
# yamllint

127
README.rst Normal file
View File

@@ -0,0 +1,127 @@
yamllint
========
A linter for YAML files.
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
:target: https://travis-ci.org/adrienverge/yamllint
:alt: CI tests status
.. image::
https://coveralls.io/repos/github/adrienverge/yamllint/badge.svg?branch=master
:target: https://coveralls.io/github/adrienverge/yamllint?branch=master
:alt: Code coverage status
.. image:: https://readthedocs.org/projects/yamllint/badge/?version=latest
:target: https://yamllint.readthedocs.io/en/latest/?badge=latest
:alt: Documentation status
Written in Python (compatible with Python 2 & 3).
Documentation
-------------
https://yamllint.readthedocs.io/
Overview
--------
Screenshot
^^^^^^^^^^
.. image:: docs/screenshot.png
:alt: yamllint screenshot
Installation
^^^^^^^^^^^^
On Fedora / CentOS:
.. code:: bash
sudo dnf install yamllint
On Debian 9+ / Ubuntu 16.04+:
.. code:: bash
sudo apt-get install yamllint
Alternatively using pip, the Python package manager:
.. code:: bash
sudo pip install yamllint
Usage
^^^^^
.. code:: bash
# Lint one or more files
yamllint my_file.yml my_other_file.yaml ...
.. code:: bash
# Lint all YAML files in a directory
yamllint .
.. code:: bash
# Use a pre-defined lint configuration
yamllint -d relaxed file.yaml
# Use a custom lint configuration
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.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
`Read more in the complete documentation! <https://yamllint.readthedocs.io/>`_
License
-------
`GPL version 3 <LICENSE>`_

View File

@@ -1,82 +0,0 @@
#!/usr/bin/env python
# -*- 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 __future__ import print_function
import os.path
import sys
import argparse
from yamllint import APP_DESCRIPTION, APP_NAME, APP_VERSION
from yamllint import config
from yamllint.errors import YamlLintConfigError
from yamllint import lint
from yamllint import output
if __name__ == '__main__':
parser = argparse.ArgumentParser(prog=APP_NAME,
description=APP_DESCRIPTION)
parser.add_argument('files', metavar='FILES', nargs='+',
help='files to check')
parser.add_argument('-c', '--config', dest='config_file', action='store',
help='path to a custom configuration')
parser.add_argument('-f', '--format',
choices=('parsable', 'standard'), default='standard',
help='format for parsing output')
parser.add_argument('-v', '--version', action='version',
version='%s %s' % (APP_NAME, APP_VERSION))
# TODO: read from stdin when no filename?
args = parser.parse_args()
try:
if args.config_file is not None:
conf = config.parse_config_from_file(args.config_file)
elif os.path.isfile('.yamllint'):
conf = config.parse_config_from_file('.yamllint')
else:
conf = config.parse_config('extends: default')
except YamlLintConfigError as e:
print(e, file=sys.stderr)
sys.exit(-1)
return_code = 0
for file in args.files:
if args.format != 'parsable':
print('\033[4m%s\033[0m' % file)
try:
with open(file) as f:
for problem in lint(f, conf):
if args.format == 'parsable':
print(output.parsable_format(problem, file))
else:
print(output.standard_format(problem, file))
if return_code == 0 and problem.level == 'error':
return_code = 1
except EnvironmentError as e:
print(e)
return_code = -1
if args.format != 'parsable':
print('')
sys.exit(return_code)

177
docs/Makefile Normal file
View File

@@ -0,0 +1,177 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/yamllint.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/yamllint.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/yamllint"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/yamllint"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

42
docs/conf.py Normal file
View File

@@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
# yamllint documentation build configuration file, created by
# sphinx-quickstart on Thu Jan 21 21:18:52 2016.
import sys
import os
sys.path.insert(0, os.path.abspath('..')) # noqa
from yamllint import __copyright__, APP_NAME, APP_VERSION
# -- General configuration ------------------------------------------------
extensions = [
'sphinx.ext.autodoc',
]
source_suffix = '.rst'
master_doc = 'index'
project = APP_NAME
copyright = __copyright__
version = APP_VERSION
release = APP_VERSION
pygments_style = 'sphinx'
# -- Options for HTML output ----------------------------------------------
html_theme = 'default'
htmlhelp_basename = 'yamllintdoc'
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'yamllint', '', [u'Adrien Vergé'], 1)
]

109
docs/configuration.rst Normal file
View File

@@ -0,0 +1,109 @@
Configuration
=============
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, use the ``-c`` option:
.. code:: bash
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`` in the current working directory
- ``$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.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).
For instance, if you just want to disable the ``comments-indentation`` rule,
your file could look like this:
.. code-block:: yaml
# This is my first, very own configuration file for yamllint!
# It extends the default conf by adjusting some options.
extends: default
rules:
comments-indentation: disable # don't bother me with this rule
Similarly, if you want to set the ``line-length`` rule as a warning and be less
strict on block sequences indentation:
.. code-block:: yaml
extends: default
rules:
# 80 chars should be enough, but don't fail if a line is longer
line-length:
max: 80
level: warning
# accept both key:
# - item
#
# and key:
# - item
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.
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).

8
docs/development.rst Normal file
View File

@@ -0,0 +1,8 @@
Development
===========
yamllint provides both a script and a Python module. The latter can be used to
write your own linting tools:
.. automodule:: yamllint.linter
:members:

View File

@@ -0,0 +1,75 @@
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 it 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 whoe 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 it 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``.

28
docs/index.rst Normal file
View File

@@ -0,0 +1,28 @@
yamllint documentation
======================
.. automodule:: yamllint
Screenshot
----------
.. image:: screenshot.png
:alt: yamllint screenshot
.. note::
The default output format is inspired by `eslint <http://eslint.org/>`_, a
great linting tool for Javascript.
Table of contents
-----------------
.. toctree::
:maxdepth: 2
quickstart
configuration
rules
disable_with_comments
development
text_editors

93
docs/quickstart.rst Normal file
View File

@@ -0,0 +1,93 @@
Quickstart
==========
Installing yamllint
-------------------
On Fedora / CentOS:
.. code:: bash
sudo dnf install yamllint
On Debian 9+ / Ubuntu 16.04+:
.. code:: bash
sudo apt-get install yamllint
On older Debian / Ubuntu versions:
.. code:: bash
sudo add-apt-repository -y ppa:adrienverge/ppa && sudo apt-get update
sudo apt-get install yamllint
Alternatively using pip, the Python package manager:
.. code:: bash
sudo pip install 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
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 .
The output will look like (colors are not displayed here):
::
file.yml
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.yaml
1:1 warning missing document start "---" (document-start)
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)
Add the ``-f parsable`` arguments if you need an output format parsable by a
machine (for instance for :doc:`syntax highlighting in text editors
<text_editors>`). The output will then look like:
::
file.yml:6:2: [warning] missing starting space in comment (comments)
file.yml:57:1: [error] trailing spaces (trailing-spaces)
file.yml:60:3: [error] wrong indentation: expected 4 but found 2 (indentation)
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.yaml
.. note::
If you have a ``.yamllint`` file in your working directory, it will be
automatically loaded as configuration by yamllint.

100
docs/rules.rst Normal file
View File

@@ -0,0 +1,100 @@
Rules
=====
When linting a document with yamllint, a series of rules (such as
``line-length``, ``trailing-spaces``, etc.) are checked against.
A :doc:`configuration file <configuration>` can be used to enable or disable
these rules, to set their level (*error* or *warning*), but also to tweak their
options.
This page describes the rules and their options.
.. contents:: List of rules
:local:
:depth: 1
braces
------
.. automodule:: yamllint.rules.braces
brackets
--------
.. automodule:: yamllint.rules.brackets
colons
------
.. automodule:: yamllint.rules.colons
commas
------
.. automodule:: yamllint.rules.commas
comments
--------
.. automodule:: yamllint.rules.comments
comments-indentation
--------------------
.. automodule:: yamllint.rules.comments_indentation
document-end
------------
.. automodule:: yamllint.rules.document_end
document-start
--------------
.. automodule:: yamllint.rules.document_start
empty-lines
-----------
.. automodule:: yamllint.rules.empty_lines
hyphens
-------
.. automodule:: yamllint.rules.hyphens
indentation
-----------
.. automodule:: yamllint.rules.indentation
key-duplicates
--------------
.. automodule:: yamllint.rules.key_duplicates
line-length
-----------
.. automodule:: yamllint.rules.line_length
new-line-at-end-of-file
-----------------------
.. automodule:: yamllint.rules.new_line_at_end_of_file
new-lines
---------
.. automodule:: yamllint.rules.new_lines
trailing-spaces
---------------
.. automodule:: yamllint.rules.trailing_spaces
truthy
---------------
.. automodule:: yamllint.rules.truthy

BIN
docs/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

32
docs/text_editors.rst Normal file
View File

@@ -0,0 +1,32 @@
Integration with text editors
=============================
Most text editors support syntax checking and highlighting, to visually report
syntax errors and warnings to the user. yamllint can be used to syntax-check
YAML source, but a bit of configuration is required depending on your favorite
text editor.
Vim
---
Assuming that the `syntastic <https://github.com/scrooloose/syntastic>`_ plugin
is installed, add to your ``.vimrc``:
::
let g:syntastic_yaml_checkers = ['yamllint']
Neovim
------
Assuming that the `neomake <https://github.com/benekastah/neomake>`_ plugin is
installed, yamllint is supported by default. It is automatically enabled when
editing YAML files.
Other text editors
------------------
.. rubric:: Help wanted!
Your favorite text editor is not listed here? Help us improve by adding a
section (by opening a pull-request or issue on GitHub).

View File

@@ -24,12 +24,13 @@ setup(
name=APP_NAME, name=APP_NAME,
version=APP_VERSION, version=APP_VERSION,
author=__author__, author=__author__,
description=APP_DESCRIPTION, description=APP_DESCRIPTION.split('\n')[0],
long_description=APP_DESCRIPTION,
license=__license__, license=__license__,
keywords=['yaml', 'lint', 'linter'], keywords=['yaml', 'lint', 'linter', 'syntax', 'checker'],
url='https://github.com/adrienverge/yamllint', url='https://github.com/adrienverge/yamllint',
classifiers=[ classifiers=[
'Development Status :: 4 - Beta', 'Development Status :: 5 - Production/Stable',
'Environment :: Console', 'Environment :: Console',
'Intended Audience :: Developers', 'Intended Audience :: Developers',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
@@ -41,10 +42,11 @@ setup(
'Topic :: Software Development :: Testing', 'Topic :: Software Development :: Testing',
], ],
packages=find_packages(), packages=find_packages(exclude=['tests', 'tests.*']),
scripts=['bin/yamllint'], entry_points={'console_scripts': ['yamllint=yamllint.cli:run']},
package_data={'yamllint': ['conf/*.yml']}, package_data={'yamllint': ['conf/*.yaml'],
install_requires=[ 'tests': ['yaml-1.2-spec-examples/*']},
'pyyaml>=3' 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

@@ -18,9 +18,8 @@ import unittest
import yaml import yaml
from yamllint.config import parse_config from yamllint.config import YamlLintConfig
from yamllint.errors import LintProblem from yamllint import linter
from yamllint import lint
class RuleTestCase(unittest.TestCase): class RuleTestCase(unittest.TestCase):
@@ -31,15 +30,22 @@ class RuleTestCase(unittest.TestCase):
conf = yaml.safe_load(conf) conf = yaml.safe_load(conf)
conf = {'extends': 'default', conf = {'extends': 'default',
'rules': conf} 'rules': conf}
return parse_config(yaml.safe_dump(conf)) return YamlLintConfig(yaml.safe_dump(conf))
def check(self, source, conf, line=None, column=None, **kwargs): def check(self, source, conf, **kwargs):
expected_problems = [] expected_problems = []
for key in kwargs: for key in kwargs:
assert key.startswith('problem') assert key.startswith('problem')
expected_problems.append( if len(kwargs[key]) > 2:
LintProblem(kwargs[key][0], kwargs[key][1], rule=self.rule_id)) if kwargs[key][2] == 'syntax':
rule_id = None
else:
rule_id = kwargs[key][2]
else:
rule_id = self.rule_id
expected_problems.append(linter.LintProblem(
kwargs[key][0], kwargs[key][1], rule=rule_id))
expected_problems.sort() expected_problems.sort()
real_problems = list(lint(source, self.build_fake_config(conf))) real_problems = list(linter.run(source, self.build_fake_config(conf)))
self.assertEqual(real_problems, expected_problems) self.assertEqual(real_problems, expected_problems)

108
tests/rules/test_braces.py Normal file
View File

@@ -0,0 +1,108 @@
# -*- 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 ColonTestCase(RuleTestCase):
rule_id = 'braces'
def test_disabled(self):
conf = 'braces: disable'
self.check('---\n'
'dict1: {}\n'
'dict2: { }\n'
'dict3: { a: 1, b}\n'
'dict4: {a: 1, b, c: 3 }\n'
'dict5: {a: 1, b, c: 3 }\n'
'dict6: { a: 1, b, c: 3 }\n'
'dict7: { a: 1, b, c: 3 }\n', conf)
def test_min_spaces(self):
conf = 'braces: {max-spaces-inside: -1, min-spaces-inside: 0}'
self.check('---\n'
'dict: {}\n', conf)
conf = 'braces: {max-spaces-inside: -1, min-spaces-inside: 1}'
self.check('---\n'
'dict: {}\n', conf, problem=(2, 8))
self.check('---\n'
'dict: { }\n', conf)
self.check('---\n'
'dict: {a: 1, b}\n', conf,
problem1=(2, 8), problem2=(2, 15))
self.check('---\n'
'dict: { a: 1, b }\n', conf)
self.check('---\n'
'dict: {\n'
' a: 1,\n'
' b\n'
'}\n', conf)
conf = 'braces: {max-spaces-inside: -1, min-spaces-inside: 3}'
self.check('---\n'
'dict: { a: 1, b }\n', conf,
problem1=(2, 9), problem2=(2, 17))
self.check('---\n'
'dict: { a: 1, b }\n', conf)
def test_max_spaces(self):
conf = 'braces: {max-spaces-inside: 0, min-spaces-inside: -1}'
self.check('---\n'
'dict: {}\n', conf)
self.check('---\n'
'dict: { }\n', conf, problem=(2, 8))
self.check('---\n'
'dict: {a: 1, b}\n', conf)
self.check('---\n'
'dict: { a: 1, b }\n', conf,
problem1=(2, 8), problem2=(2, 16))
self.check('---\n'
'dict: { a: 1, b }\n', conf,
problem1=(2, 10), problem2=(2, 20))
self.check('---\n'
'dict: {\n'
' a: 1,\n'
' b\n'
'}\n', conf)
conf = 'braces: {max-spaces-inside: 3, min-spaces-inside: -1}'
self.check('---\n'
'dict: { a: 1, b }\n', conf)
self.check('---\n'
'dict: { a: 1, b }\n', conf,
problem1=(2, 11), problem2=(2, 23))
def test_min_and_max_spaces(self):
conf = 'braces: {max-spaces-inside: 0, min-spaces-inside: 0}'
self.check('---\n'
'dict: {}\n', conf)
self.check('---\n'
'dict: { }\n', conf, problem=(2, 8))
self.check('---\n'
'dict: { a: 1, b}\n', conf, problem=(2, 10))
conf = 'braces: {max-spaces-inside: 1, min-spaces-inside: 1}'
self.check('---\n'
'dict: {a: 1, b, c: 3 }\n', conf, problem=(2, 8))
conf = 'braces: {max-spaces-inside: 2, min-spaces-inside: 0}'
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))

View File

@@ -0,0 +1,107 @@
# -*- 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 ColonTestCase(RuleTestCase):
rule_id = 'brackets'
def test_disabled(self):
conf = 'brackets: disable'
self.check('---\n'
'array1: []\n'
'array2: [ ]\n'
'array3: [ a, b]\n'
'array4: [a, b, c ]\n'
'array5: [a, b, c ]\n'
'array6: [ a, b, c ]\n'
'array7: [ a, b, c ]\n', conf)
def test_min_spaces(self):
conf = 'brackets: {max-spaces-inside: -1, min-spaces-inside: 0}'
self.check('---\n'
'array: []\n', conf)
conf = 'brackets: {max-spaces-inside: -1, min-spaces-inside: 1}'
self.check('---\n'
'array: []\n', conf, problem=(2, 9))
self.check('---\n'
'array: [ ]\n', conf)
self.check('---\n'
'array: [a, b]\n', conf, problem1=(2, 9), problem2=(2, 13))
self.check('---\n'
'array: [ a, b ]\n', conf)
self.check('---\n'
'array: [\n'
' a,\n'
' b\n'
']\n', conf)
conf = 'brackets: {max-spaces-inside: -1, min-spaces-inside: 3}'
self.check('---\n'
'array: [ a, b ]\n', conf,
problem1=(2, 10), problem2=(2, 15))
self.check('---\n'
'array: [ a, b ]\n', conf)
def test_max_spaces(self):
conf = 'brackets: {max-spaces-inside: 0, min-spaces-inside: -1}'
self.check('---\n'
'array: []\n', conf)
self.check('---\n'
'array: [ ]\n', conf, problem=(2, 9))
self.check('---\n'
'array: [a, b]\n', conf)
self.check('---\n'
'array: [ a, b ]\n', conf,
problem1=(2, 9), problem2=(2, 14))
self.check('---\n'
'array: [ a, b ]\n', conf,
problem1=(2, 11), problem2=(2, 18))
self.check('---\n'
'array: [\n'
' a,\n'
' b\n'
']\n', conf)
conf = 'brackets: {max-spaces-inside: 3, min-spaces-inside: -1}'
self.check('---\n'
'array: [ a, b ]\n', conf)
self.check('---\n'
'array: [ a, b ]\n', conf,
problem1=(2, 12), problem2=(2, 21))
def test_min_and_max_spaces(self):
conf = 'brackets: {max-spaces-inside: 0, min-spaces-inside: 0}'
self.check('---\n'
'array: []\n', conf)
self.check('---\n'
'array: [ ]\n', conf, problem=(2, 9))
self.check('---\n'
'array: [ a, b]\n', conf, problem=(2, 11))
conf = 'brackets: {max-spaces-inside: 1, min-spaces-inside: 1}'
self.check('---\n'
'array: [a, b, c ]\n', conf, problem=(2, 9))
conf = 'brackets: {max-spaces-inside: 2, min-spaces-inside: 0}'
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))

View File

@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from tests.rules.common import RuleTestCase from tests.common import RuleTestCase
class ColonTestCase(RuleTestCase): class ColonTestCase(RuleTestCase):
@@ -32,16 +32,16 @@ class ColonTestCase(RuleTestCase):
' val\n' ' val\n'
' property : value\n' ' property : value\n'
' prop2 : val2\n' ' prop2 : val2\n'
' propriété : [ valeur ]\n' ' propriété : [valeur]\n'
' o:\n' ' o:\n'
' k1: [v1, v2]\n' ' k1: [v1, v2]\n'
' p:\n' ' p:\n'
' - k3: >\n' ' - k3: >\n'
' val\n' ' val\n'
' - o: { k1: v1 }\n' ' - o: {k1: v1}\n'
' - p: kdjf\n' ' - p: kdjf\n'
' - q: val0\n' ' - q: val0\n'
' q2:\n' ' - q2:\n'
' - val1\n' ' - val1\n'
'...\n', conf) '...\n', conf)
self.check('---\n' self.check('---\n'
@@ -54,7 +54,7 @@ class ColonTestCase(RuleTestCase):
' val\n' ' val\n'
' property: value\n' ' property: value\n'
' prop2: val2\n' ' prop2: val2\n'
' propriété: [ valeur ]\n' ' propriété: [valeur]\n'
' o:\n' ' o:\n'
' k1: [v1, v2]\n', conf) ' k1: [v1, v2]\n', conf)
self.check('---\n' self.check('---\n'
@@ -64,9 +64,9 @@ class ColonTestCase(RuleTestCase):
' val\n' ' val\n'
' - k3: >\n' ' - k3: >\n'
' val\n' ' val\n'
' - o: { k1: v1 }\n' ' - o: {k1: v1}\n'
' - o: { k1: v1 }\n' ' - o: {k1: v1}\n'
' q2:\n' ' - q2:\n'
' - val1\n' ' - val1\n'
'...\n', conf) '...\n', conf)
self.check('---\n' self.check('---\n'
@@ -94,7 +94,7 @@ class ColonTestCase(RuleTestCase):
'...\n', conf, problem=(2, 4)) '...\n', conf, problem=(2, 4))
self.check('---\n' self.check('---\n'
'- lib :\n' '- lib :\n'
' - var\n' ' - var\n'
'...\n', conf, problem=(2, 6)) '...\n', conf, problem=(2, 6))
self.check('---\n' self.check('---\n'
'a: {b: {c : d, e : f}}\n', conf, 'a: {b: {c : d, e : f}}\n', conf,
@@ -118,7 +118,7 @@ class ColonTestCase(RuleTestCase):
'...\n', conf, problem=(3, 8)) '...\n', conf, problem=(3, 8))
def test_before_with_explicit_block_mappings(self): def test_before_with_explicit_block_mappings(self):
conf = 'colons: {max-spaces-before: 0, max-spaces-after: -1}' conf = 'colons: {max-spaces-before: 0, max-spaces-after: 1}'
self.check('---\n' self.check('---\n'
'object:\n' 'object:\n'
' ? key\n' ' ? key\n'
@@ -129,6 +129,30 @@ class ColonTestCase(RuleTestCase):
' ? key\n' ' ? key\n'
' : value\n' ' : value\n'
'...\n', conf, problem=(2, 7)) '...\n', conf, problem=(2, 7))
self.check('---\n'
'? >\n'
' multi-line\n'
' key\n'
': >\n'
' multi-line\n'
' value\n'
'...\n', conf)
self.check('---\n'
'- ? >\n'
' multi-line\n'
' key\n'
' : >\n'
' multi-line\n'
' value\n'
'...\n', conf)
self.check('---\n'
'- ? >\n'
' multi-line\n'
' key\n'
' : >\n'
' multi-line\n'
' value\n'
'...\n', conf, problem=(5, 5))
def test_after_enabled(self): def test_after_enabled(self):
conf = 'colons: {max-spaces-before: -1, max-spaces-after: 1}' conf = 'colons: {max-spaces-before: -1, max-spaces-after: 1}'
@@ -152,6 +176,21 @@ class ColonTestCase(RuleTestCase):
'a: {b: {c: d, e : f}}\n', conf, 'a: {b: {c: d, e : f}}\n', conf,
problem1=(2, 12), problem2=(2, 20)) problem1=(2, 12), problem2=(2, 20))
def test_after_enabled_question_mark(self):
conf = 'colons: {max-spaces-before: -1, max-spaces-after: 1}'
self.check('---\n'
'? key\n'
': value\n', conf)
self.check('---\n'
'? key\n'
': value\n', conf, problem=(2, 3))
self.check('---\n'
'? key\n'
': value\n', conf, problem1=(2, 3), problem2=(3, 3))
self.check('---\n'
'- ? key\n'
' : value\n', conf, problem1=(2, 5), problem2=(3, 5))
def test_after_max(self): def test_after_max(self):
conf = 'colons: {max-spaces-before: -1, max-spaces-after: 3}' conf = 'colons: {max-spaces-before: -1, max-spaces-after: 3}'
self.check('---\n' self.check('---\n'

265
tests/rules/test_commas.py Normal file
View File

@@ -0,0 +1,265 @@
# -*- 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 CommaTestCase(RuleTestCase):
rule_id = 'commas'
def test_disabled(self):
conf = 'commas: disable'
self.check('---\n'
'dict: {a: b , c: "1 2 3", d: e , f: [g, h]}\n'
'array: [\n'
' elem ,\n'
' key: val ,\n'
']\n'
'map: {\n'
' key1: val1 ,\n'
' 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_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)
self.check('---\n'
'array: [1, 2 , 3, 4]\n'
'...\n', conf, problem=(2, 13))
self.check('---\n'
'array: [1 , 2, 3 , 4]\n'
'...\n', conf, problem1=(2, 10), problem2=(2, 23))
self.check('---\n'
'dict: {a: b, c: "1 2 3", d: e, f: [g, h]}\n'
'...\n', conf)
self.check('---\n'
'dict: {a: b, c: "1 2 3" , d: e, f: [g, h]}\n'
'...\n', conf, problem=(2, 24))
self.check('---\n'
'dict: {a: b , c: "1 2 3", d: e, f: [g , h]}\n'
'...\n', conf, problem1=(2, 12), problem2=(2, 42))
self.check('---\n'
'array: [\n'
' elem,\n'
' key: val,\n'
']\n', conf)
self.check('---\n'
'array: [\n'
' elem ,\n'
' key: val,\n'
']\n', conf, problem=(3, 7))
self.check('---\n'
'map: {\n'
' key1: val1,\n'
' key2: val2,\n'
'}\n', conf)
self.check('---\n'
'map: {\n'
' key1: val1,\n'
' key2: val2 ,\n'
'}\n', conf, problem=(4, 13))
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)
self.check('---\n'
'array: [1 , 2, 3 , 4]\n'
'...\n', conf, problem=(2, 20))
self.check('---\n'
'array: [\n'
' elem1 ,\n'
' elem2 ,\n'
' key: val,\n'
']\n', conf, problem=(4, 11))
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)
self.check('---\n'
'array: [1, 2, 3, 4]\n'
'...\n', conf, problem=(2, 15))
self.check('---\n'
'array: [1, 2, 3, 4]\n'
'...\n', conf, problem1=(2, 12), problem2=(2, 22))
self.check('---\n'
'dict: {a: b , c: "1 2 3", d: e, f: [g, h]}\n'
'...\n', conf)
self.check('---\n'
'dict: {a: b , c: "1 2 3", d: e, f: [g, h]}\n'
'...\n', conf, problem=(2, 27))
self.check('---\n'
'dict: {a: b , c: "1 2 3", d: e, f: [g, h]}\n'
'...\n', conf, problem1=(2, 15), problem2=(2, 44))
self.check('---\n'
'array: [\n'
' elem,\n'
' key: val,\n'
']\n', conf)
self.check('---\n'
'array: [\n'
' elem, key: val,\n'
']\n', conf, problem=(3, 9))
self.check('---\n'
'map: {\n'
' key1: val1, key2: [val2, val3]\n'
'}\n', conf, problem1=(3, 16), problem2=(3, 30))
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)
self.check('---\n'
'array: [1, 2, 3, 4]\n'
'...\n', conf, problem=(2, 21))
self.check('---\n'
'dict: {a: b , c: "1 2 3", d: e, f: [g, h]}\n'
'...\n', conf, problem1=(2, 31), problem2=(2, 49))
def test_both_before_and_after(self):
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'
' elem ,\n'
' key: val ,\n'
']\n'
'map: {\n'
' key1: val1 ,\n'
' key2: val2,\n'
'}\n'
'...\n', conf,
problem1=(2, 12), problem2=(2, 16), problem3=(2, 31),
problem4=(2, 36), problem5=(2, 50), problem6=(4, 8),
problem7=(5, 11), problem8=(8, 13))
conf = ('commas:\n'
' max-spaces-before: 0\n'
' min-spaces-after: 1\n'
' max-spaces-after: 1\n'
'indentation: disable\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, 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

@@ -0,0 +1,175 @@
# -*- 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 CommentsTestCase(RuleTestCase):
rule_id = 'comments'
def test_disabled(self):
conf = ('comments: disable\n'
'comments-indentation: disable\n')
self.check('---\n'
'#comment\n'
'\n'
'test: # description\n'
' - foo # bar\n'
' - hello #world\n'
'\n'
'# comment 2\n'
'#comment 3\n'
' #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'
' min-spaces-from-content: -1\n'
'comments-indentation: disable\n')
self.check('---\n'
'# comment\n'
'\n'
'test: # description\n'
' - foo # bar\n'
' - hello # world\n'
'\n'
'# comment 2\n'
'# comment 3\n'
' # comment 3 bis\n'
' # comment 3 ter\n'
'\n'
'################################\n'
'## comment 4\n'
'## comment 5\n', conf)
self.check('---\n'
'#comment\n'
'\n'
'test: # description\n'
' - foo # bar\n'
' - hello #world\n'
'\n'
'# comment 2\n'
'#comment 3\n'
' #comment 3 bis\n'
' # comment 3 ter\n'
'\n'
'################################\n'
'## comment 4\n'
'##comment 5\n', conf,
problem1=(2, 2), problem2=(6, 13),
problem3=(9, 2), problem4=(10, 4),
problem5=(15, 3))
def test_spaces_from_content(self):
conf = ('comments:\n'
' require-starting-space: no\n'
' min-spaces-from-content: 2\n')
self.check('---\n'
'# comment\n'
'\n'
'test: # description\n'
' - foo # bar\n'
' - hello #world\n'
'\n'
'string: "Une longue phrase." # this is French\n', conf)
self.check('---\n'
'# comment\n'
'\n'
'test: # description\n'
' - foo # bar\n'
' - hello #world\n'
'\n'
'string: "Une longue phrase." # this is French\n', conf,
problem1=(4, 7), problem2=(6, 11), problem3=(8, 30))
def test_both(self):
conf = ('comments:\n'
' require-starting-space: yes\n'
' min-spaces-from-content: 2\n'
'comments-indentation: disable\n')
self.check('---\n'
'#comment\n'
'\n'
'test: # description\n'
' - foo # bar\n'
' - hello #world\n'
'\n'
'# comment 2\n'
'#comment 3\n'
' #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=(15, 3),
problem8=(17, 30))
def test_empty_comment(self):
conf = ('comments:\n'
' require-starting-space: yes\n'
' min-spaces-from-content: 2\n')
self.check('---\n'
'# This is paragraph 1.\n'
'#\n'
'# This is paragraph 2.\n', conf)
self.check('---\n'
'inline: comment #\n'
'foo: bar\n', conf)
def test_first_line(self):
conf = ('comments:\n'
' require-starting-space: yes\n'
' min-spaces-from-content: 2\n')
self.check('# comment\n', conf)
def test_last_line(self):
conf = ('comments:\n'
' require-starting-space: yes\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'
' min-spaces-from-content: 2\n'
'trailing-spaces: disable\n')
self.check('---\n'
'string: >\n'
' this is plain text\n'
'\n'
'# comment\n', conf)
self.check('---\n'
'- string: >\n'
' this is plain text\n'
' \n'
' # comment\n', conf)

View File

@@ -0,0 +1,157 @@
# -*- 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 CommentsIndentationTestCase(RuleTestCase):
rule_id = 'comments-indentation'
def test_disable(self):
conf = 'comments-indentation: disable'
self.check('---\n'
' # line 1\n'
'# line 2\n'
' # line 3\n'
' # line 4\n'
'\n'
'obj:\n'
' # these\n'
' # are\n'
' # [good]\n'
'# bad\n'
' # comments\n'
' a: b\n'
'\n'
'obj1:\n'
' a: 1\n'
' # comments\n'
'\n'
'obj2:\n'
' b: 2\n'
'\n'
'# empty\n'
'#\n'
'# comment\n'
'...\n', conf)
def test_enabled(self):
conf = 'comments-indentation: enable'
self.check('---\n'
'# line 1\n'
'# line 2\n', conf)
self.check('---\n'
' # line 1\n'
'# line 2\n', conf, problem=(2, 2))
self.check('---\n'
' # line 1\n'
' # line 2\n', conf, problem1=(2, 3))
self.check('---\n'
'obj:\n'
' # normal\n'
' a: b\n', conf)
self.check('---\n'
'obj:\n'
' # bad\n'
' a: b\n', conf, problem=(3, 2))
self.check('---\n'
'obj:\n'
'# bad\n'
' a: b\n', conf, problem=(3, 1))
self.check('---\n'
'obj:\n'
' # bad\n'
' a: b\n', conf, problem=(3, 4))
self.check('---\n'
'obj:\n'
' # these\n'
' # are\n'
' # [good]\n'
'# bad\n'
' # comments\n'
' a: b\n', conf,
problem1=(3, 2), problem2=(4, 4),
problem3=(6, 1), problem4=(7, 7))
self.check('---\n'
'obj1:\n'
' a: 1\n'
' # the following line is disabled\n'
' # b: 2\n', conf)
self.check('---\n'
'obj1:\n'
' a: 1\n'
' # b: 2\n'
'\n'
'obj2:\n'
' b: 2\n', conf)
self.check('---\n'
'obj1:\n'
' a: 1\n'
' # b: 2\n'
'# this object is useless\n'
'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))
self.check('---\n'
'obj1:\n'
' a: 1\n'
' # comments\n'
' b: 2\n', conf)
self.check('---\n'
'my list for today:\n'
' - todo 1\n'
' - todo 2\n'
' # commented for now\n'
' # - todo 3\n'
'...\n', conf)
def test_first_line(self):
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: 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: enable'
self.check('---\n'
'# hey\n'
'# normal\n'
'#\n', conf)
self.check('---\n'
'# 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

@@ -0,0 +1,44 @@
# -*- 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 unittest
import yaml
from yamllint.rules.common import get_line_indent
class CommonTestCase(unittest.TestCase):
def test_get_line_indent(self):
tokens = list(yaml.scan('a: 1\n'
'b:\n'
' - c: [2, 3, {d: 4}]\n'))
self.assertEqual(tokens[3].value, 'a')
self.assertEqual(tokens[5].value, '1')
self.assertEqual(tokens[7].value, 'b')
self.assertEqual(tokens[13].value, 'c')
self.assertEqual(tokens[16].value, '2')
self.assertEqual(tokens[18].value, '3')
self.assertEqual(tokens[22].value, 'd')
self.assertEqual(tokens[24].value, '4')
for i in (3, 5):
self.assertEqual(get_line_indent(tokens[i]), 0)
for i in (7,):
self.assertEqual(get_line_indent(tokens[i]), 0)
for i in (13, 16, 18, 22, 24):
self.assertEqual(get_line_indent(tokens[i]), 2)

View File

@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from tests.rules.common import RuleTestCase from tests.common import RuleTestCase
class DocumentEndTestCase(RuleTestCase): class DocumentEndTestCase(RuleTestCase):
@@ -64,12 +64,6 @@ class DocumentEndTestCase(RuleTestCase):
'---\n' '---\n'
'third: document\n' 'third: document\n'
'...\n', conf) '...\n', conf)
self.check('first: document\n'
'...\n'
'second: document\n'
'...\n'
'third: document\n'
'...\n', conf)
self.check('---\n' self.check('---\n'
'first: document\n' 'first: document\n'
'...\n' '...\n'

View File

@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from tests.rules.common import RuleTestCase from tests.common import RuleTestCase
class DocumentStartTestCase(RuleTestCase): class DocumentStartTestCase(RuleTestCase):
@@ -82,9 +82,23 @@ class DocumentStartTestCase(RuleTestCase):
'...\n' '...\n'
'second: document\n' 'second: document\n'
'---\n' '---\n'
'third: document\n', conf, problem=(4, 1)) 'third: document\n', conf, problem=(4, 1, 'syntax'))
def test_directives(self): def test_directives(self):
# TODO conf = 'document-start: {present: yes}'
# %YAML 1.2 self.check('%YAML 1.2\n'
pass '---\n'
'doc: ument\n'
'...\n', conf)
self.check('%YAML 1.2\n'
'%TAG ! tag:clarkevans.com,2002:\n'
'---\n'
'doc: ument\n'
'...\n', conf)
self.check('---\n'
'doc: 1\n'
'...\n'
'%YAML 1.2\n'
'---\n'
'doc: 2\n'
'...\n', conf)

View File

@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from tests.rules.common import RuleTestCase from tests.common import RuleTestCase
class EmptyLinesTestCase(RuleTestCase): class EmptyLinesTestCase(RuleTestCase):

View File

@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from tests.rules.common import RuleTestCase from tests.common import RuleTestCase
class HyphenTestCase(RuleTestCase): class HyphenTestCase(RuleTestCase):
@@ -36,12 +36,12 @@ class HyphenTestCase(RuleTestCase):
'- elem2\n', conf) '- elem2\n', conf)
self.check('---\n' self.check('---\n'
'object:\n' 'object:\n'
'- elem1\n' ' - elem1\n'
'- elem2\n', conf) ' - elem2\n', conf)
self.check('---\n' self.check('---\n'
'object:\n' 'object:\n'
'- elem1\n' ' - elem1\n'
'- elem2\n', conf) ' - elem2\n', conf)
self.check('---\n' self.check('---\n'
'object:\n' 'object:\n'
' subobject:\n' ' subobject:\n'
@@ -69,12 +69,12 @@ class HyphenTestCase(RuleTestCase):
'- elem2\n', conf, problem=(2, 3)) '- elem2\n', conf, problem=(2, 3))
self.check('---\n' self.check('---\n'
'object:\n' 'object:\n'
'- elem1\n' ' - elem1\n'
'- elem2\n', conf, problem=(4, 3)) ' - elem2\n', conf, problem=(4, 5))
self.check('---\n' self.check('---\n'
'object:\n' 'object:\n'
'- elem1\n' ' - elem1\n'
'- elem2\n', conf, problem1=(3, 3), problem2=(4, 3)) ' - elem2\n', conf, problem1=(3, 5), problem2=(4, 5))
self.check('---\n' self.check('---\n'
'object:\n' 'object:\n'
' subobject:\n' ' subobject:\n'

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,156 @@
# -*- 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)
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))
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

@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from tests.rules.common import RuleTestCase from tests.common import RuleTestCase
class LineLengthTestCase(RuleTestCase): class LineLengthTestCase(RuleTestCase):
@@ -32,6 +32,9 @@ class LineLengthTestCase(RuleTestCase):
self.check('---\n' + 81 * 'a' + '\n', conf) self.check('---\n' + 81 * 'a' + '\n', conf)
self.check(1000 * 'b', conf) self.check(1000 * 'b', conf)
self.check('---\n' + 1000 * 'b' + '\n', conf) self.check('---\n' + 1000 * 'b' + '\n', conf)
self.check('content: |\n'
' {% this line is' + 99 * ' really' + ' long %}\n',
conf)
def test_default(self): def test_default(self):
conf = ('line-length: {max: 80}\n' conf = ('line-length: {max: 80}\n'
@@ -43,17 +46,17 @@ class LineLengthTestCase(RuleTestCase):
self.check('---\n', conf) self.check('---\n', conf)
self.check(80 * 'a', conf) self.check(80 * 'a', conf)
self.check('---\n' + 80 * 'a' + '\n', conf) self.check('---\n' + 80 * 'a' + '\n', conf)
self.check(81 * 'a', conf, problem=(1, 81)) self.check(16 * 'aaaa ' + 'z', conf, problem=(1, 81))
self.check('---\n' + 81 * 'a' + '\n', conf, problem=(2, 81)) self.check('---\n' + 16 * 'aaaa ' + 'z' + '\n', conf, problem=(2, 81))
self.check(1000 * 'b', conf, problem=(1, 81)) self.check(1000 * 'word ' + 'end', conf, problem=(1, 81))
self.check('---\n' + 1000 * 'b' + '\n', conf, problem=(2, 81)) self.check('---\n' + 1000 * 'word ' + 'end\n', conf, problem=(2, 81))
def test_max_length_10(self): def test_max_length_10(self):
conf = ('line-length: {max: 10}\n' conf = ('line-length: {max: 10}\n'
'new-line-at-end-of-file: disable\n') 'new-line-at-end-of-file: disable\n')
self.check('---\nABCDEFGHIJ', conf) self.check('---\nABCD EFGHI', conf)
self.check('---\nABCDEFGHIJK', conf, problem=(2, 11)) self.check('---\nABCD EFGHIJ', conf, problem=(2, 11))
self.check('---\nABCDEFGHIJK\n', conf, problem=(2, 11)) self.check('---\nABCD EFGHIJ\n', conf, problem=(2, 11))
def test_spaces(self): def test_spaces(self):
conf = ('line-length: {max: 80}\n' conf = ('line-length: {max: 80}\n'
@@ -61,3 +64,94 @@ class LineLengthTestCase(RuleTestCase):
'trailing-spaces: disable\n') 'trailing-spaces: disable\n')
self.check('---\n' + 81 * ' ', conf, problem=(2, 81)) self.check('---\n' + 81 * ' ', conf, problem=(2, 81))
self.check('---\n' + 81 * ' ' + '\n', conf, problem=(2, 81)) self.check('---\n' + 81 * ' ' + '\n', conf, problem=(2, 81))
def test_non_breakable_word(self):
conf = 'line-length: {max: 20, allow-non-breakable-words: yes}'
self.check('---\n' + 30 * 'A' + '\n', conf)
self.check('---\n'
'this:\n'
' is:\n'
' - a:\n'
' http://localhost/very/long/url\n'
'...\n', conf)
self.check('---\n'
'this:\n'
' is:\n'
' - a:\n'
' # http://localhost/very/long/url\n'
' comment\n'
'...\n', conf)
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}'
self.check('---\n' + 30 * 'A' + '\n', conf, problem=(2, 21))
self.check('---\n'
'this:\n'
' is:\n'
' - a:\n'
' http://localhost/very/long/url\n'
'...\n', conf, problem=(5, 21))
self.check('---\n'
'this:\n'
' is:\n'
' - a:\n'
' # http://localhost/very/long/url\n'
' comment\n'
'...\n', conf, problem=(5, 21))
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: yes}\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: yes}'
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: yes}\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: yes}'
self.check('---\n'
'content: |\n'
' {% this line is' + 99 * ' really' + ' long %}\n',
conf, problem=(3, 81))

View File

@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from tests.rules.common import RuleTestCase from tests.common import RuleTestCase
class NewLineAtEndOfFileTestCase(RuleTestCase): class NewLineAtEndOfFileTestCase(RuleTestCase):
@@ -30,7 +30,7 @@ class NewLineAtEndOfFileTestCase(RuleTestCase):
self.check('Sentence.\n', conf) self.check('Sentence.\n', conf)
def test_enabled(self): 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' 'empty-lines: disable\n'
'document-start: disable\n') 'document-start: disable\n')
self.check('', conf) self.check('', conf)

View File

@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from tests.rules.common import RuleTestCase from tests.common import RuleTestCase
class NewLinesTestCase(RuleTestCase): class NewLinesTestCase(RuleTestCase):

View File

@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from tests.rules.common import RuleTestCase from tests.common import RuleTestCase
class TrailingSpacesTestCase(RuleTestCase): class TrailingSpacesTestCase(RuleTestCase):
@@ -29,18 +29,18 @@ class TrailingSpacesTestCase(RuleTestCase):
'some: text \n', conf) 'some: text \n', conf)
def test_enabled(self): def test_enabled(self):
conf = 'trailing-spaces: {}' conf = 'trailing-spaces: enable'
self.check('', conf) self.check('', conf)
self.check('\n', conf) self.check('\n', conf)
self.check(' \n', conf, problem=(1, 1)) self.check(' \n', conf, problem=(1, 1))
self.check('\t\t\t\n', conf, problem=(1, 1)) self.check('\t\t\t\n', conf, problem=(1, 1, 'syntax'))
self.check('---\n' self.check('---\n'
'some: text \n', conf, problem=(2, 11)) 'some: text \n', conf, problem=(2, 11))
self.check('---\n' self.check('---\n'
'some: text\t\n', conf, problem=(2, 11)) 'some: text\t\n', conf, problem=(2, 11, 'syntax'))
def test_with_dos_new_lines(self): def test_with_dos_new_lines(self):
conf = ('trailing-spaces: {}\n' conf = ('trailing-spaces: enable\n'
'new-lines: {type: dos}\n') 'new-lines: {type: dos}\n')
self.check('---\r\n' self.check('---\r\n'
'some: text\r\n', conf) 'some: text\r\n', conf)

View File

@@ -0,0 +1,68 @@
# -*- 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_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)

362
tests/test_cli.py Normal file
View File

@@ -0,0 +1,362 @@
# -*- 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/>.
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
import fcntl
import locale
import os
import pty
import shutil
import tempfile
import unittest
import sys
from yamllint import cli
class CommandLineTestCase(unittest.TestCase):
def setUp(self):
self.wd = tempfile.mkdtemp(prefix='yamllint-tests-')
# .yaml file at root
with open(os.path.join(self.wd, 'a.yaml'), 'w') as f:
f.write('---\n'
'- 1 \n'
'- 2')
# .yml file at root
open(os.path.join(self.wd, 'empty.yml'), 'w').close()
# file in dir
os.mkdir(os.path.join(self.wd, 'sub'))
with open(os.path.join(self.wd, 'sub', 'ok.yaml'), 'w') as f:
f.write('---\n'
'key: value\n')
# file in very nested dir
dir = self.wd
for i in range(15):
dir = os.path.join(dir, 's')
os.mkdir(dir)
with open(os.path.join(dir, 'file.yaml'), 'w') as f:
f.write('---\n'
'key: value\n'
'key: other value\n')
# empty dir
os.mkdir(os.path.join(self.wd, 'empty-dir'))
# non-YAML file
with open(os.path.join(self.wd, 'no-yaml.json'), 'w') as f:
f.write('---\n'
'key: value\n')
# non-ASCII chars
os.mkdir(os.path.join(self.wd, 'non-ascii'))
with open(os.path.join(self.wd, 'non-ascii', 'utf-8'), 'wb') as f:
f.write((u'---\n'
u'- hétérogénéité\n'
u'# 19.99 €\n'
u'- お早う御座います。\n'
u'# الأَبْجَدِيَّة العَرَبِيَّة\n').encode('utf-8'))
def tearDown(self):
shutil.rmtree(self.wd)
def test_find_files_recursively(self):
self.assertEqual(
sorted(cli.find_files_recursively([self.wd])),
[os.path.join(self.wd, 'a.yaml'),
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'),
os.path.join(self.wd, 'sub/ok.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)),
[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)),
[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)),
[os.path.join(self.wd, '/etc/another/file'),
os.path.join(self.wd, 'sub/ok.yaml')],
)
def test_run_with_bad_arguments(self):
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run(())
self.assertNotEqual(ctx.exception.code, 0)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(out, '')
self.assertRegexpMatches(err, r'^usage')
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run(('--unknown-arg', ))
self.assertNotEqual(ctx.exception.code, 0)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(out, '')
self.assertRegexpMatches(err, r'^usage')
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run(('-c', './conf.yaml', '-d', 'relaxed', 'file'))
self.assertNotEqual(ctx.exception.code, 0)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(out, '')
self.assertRegexpMatches(err, r'^Options --config-file and '
r'--config-data cannot be used')
def test_run_with_bad_config(self):
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run(('-d', 'rules: {a: b}', 'file'))
self.assertEqual(ctx.exception.code, -1)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(out, '')
self.assertRegexpMatches(err, r'^invalid config: no such rule')
def test_run_with_empty_config(self):
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run(('-d', '', 'file'))
self.assertEqual(ctx.exception.code, -1)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(out, '')
self.assertRegexpMatches(err, 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 self.assertRaises(SystemExit) as ctx:
cli.run(('-c', f.name, os.path.join(self.wd, 'a.yaml')))
self.assertEqual(ctx.exception.code, 0)
with open(os.path.join(self.wd, 'config'), 'w') as f:
f.write('rules: {trailing-spaces: enable}')
with self.assertRaises(SystemExit) as ctx:
cli.run(('-c', f.name, os.path.join(self.wd, 'a.yaml')))
self.assertEqual(ctx.exception.code, 1)
def test_run_with_user_global_config_file(self):
home = os.path.join(self.wd, 'fake-home')
os.mkdir(home)
dir = os.path.join(home, '.config')
os.mkdir(dir)
dir = os.path.join(dir, 'yamllint')
os.mkdir(dir)
config = os.path.join(dir, 'config')
temp = os.environ['HOME']
os.environ['HOME'] = home
with open(config, 'w') as f:
f.write('rules: {trailing-spaces: disable}')
with self.assertRaises(SystemExit) as ctx:
cli.run((os.path.join(self.wd, 'a.yaml'), ))
self.assertEqual(ctx.exception.code, 0)
with open(config, 'w') as f:
f.write('rules: {trailing-spaces: enable}')
with self.assertRaises(SystemExit) as ctx:
cli.run((os.path.join(self.wd, 'a.yaml'), ))
self.assertEqual(ctx.exception.code, 1)
os.environ['HOME'] = temp
def test_run_version(self):
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run(('--version', ))
self.assertEqual(ctx.exception.code, 0)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertRegexpMatches(out + err, r'yamllint \d+\.\d+')
def test_run_non_existing_file(self):
file = os.path.join(self.wd, 'i-do-not-exist.yaml')
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run(('-f', 'parsable', file))
self.assertEqual(ctx.exception.code, -1)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(out, '')
self.assertRegexpMatches(err, r'No such file or directory')
def test_run_one_problem_file(self):
file = os.path.join(self.wd, 'a.yaml')
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run(('-f', 'parsable', file))
self.assertEqual(ctx.exception.code, 1)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(out, (
'%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') % (file, file))
self.assertEqual(err, '')
def test_run_one_ok_file(self):
file = os.path.join(self.wd, 'sub', 'ok.yaml')
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run(('-f', 'parsable', file))
self.assertEqual(ctx.exception.code, 0)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(out, '')
self.assertEqual(err, '')
def test_run_empty_file(self):
file = os.path.join(self.wd, 'empty.yml')
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run(('-f', 'parsable', file))
self.assertEqual(ctx.exception.code, 0)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(out, '')
self.assertEqual(err, '')
def test_run_non_ascii_file(self):
file = os.path.join(self.wd, 'non-ascii', 'utf-8')
# Make sure the default localization conditions on this "system"
# support UTF-8 encoding.
loc = locale.getlocale()
locale.setlocale(locale.LC_ALL, 'C.UTF-8')
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run(('-f', 'parsable', file))
locale.setlocale(locale.LC_ALL, loc)
self.assertEqual(ctx.exception.code, 0)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(out, '')
self.assertEqual(err, '')
def test_run_multiple_files(self):
items = [os.path.join(self.wd, 'empty.yml'),
os.path.join(self.wd, 's')]
file = items[1] + '/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml'
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run(['-f', 'parsable'] + items)
self.assertEqual(ctx.exception.code, 1)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(out, (
'%s:3:1: [error] duplication of key "key" in mapping '
'(key-duplicates)\n') % file)
self.assertEqual(err, '')
def test_run_piped_output_nocolor(self):
file = os.path.join(self.wd, 'a.yaml')
sys.stdout, sys.stderr = StringIO(), StringIO()
with self.assertRaises(SystemExit) as ctx:
cli.run((file, ))
self.assertEqual(ctx.exception.code, 1)
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
self.assertEqual(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' % file))
self.assertEqual(err, '')
def test_run_colored_output(self):
file = 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((file, ))
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' % file))

233
tests/test_config.py Normal file
View File

@@ -0,0 +1,233 @@
# -*- 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 unittest
from yamllint import config
class SimpleConfigTestCase(unittest.TestCase):
def test_parse_config(self):
new = config.YamlLintConfig('rules:\n'
' colons:\n'
' max-spaces-before: 0\n'
' max-spaces-after: 1\n')
self.assertEqual(list(new.rules.keys()), ['colons'])
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)
def test_invalid_conf(self):
with self.assertRaises(config.YamlLintConfigError):
config.YamlLintConfig('not: valid: yaml')
def test_unknown_rule(self):
with self.assertRaisesRegexp(
config.YamlLintConfigError,
'invalid config: no such rule: "this-one-does-not-exist"'):
config.YamlLintConfig('rules:\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'
' colons:\n'
' max-spaces-after: 1\n')
def test_unknown_option(self):
with self.assertRaisesRegexp(
config.YamlLintConfigError,
'invalid config: unknown option "abcdef" for rule "colons"'):
config.YamlLintConfig('rules:\n'
' colons:\n'
' max-spaces-before: 0\n'
' max-spaces-after: 1\n'
' abcdef: yes\n')
def test_validate_rule_conf(self):
class Rule(object):
ID = 'fake'
self.assertEqual(config.validate_rule_conf(Rule, False), False)
self.assertEqual(config.validate_rule_conf(Rule, 'disable'), False)
self.assertEqual(config.validate_rule_conf(Rule, {}),
{'level': 'error'})
self.assertEqual(config.validate_rule_conf(Rule, 'enable'),
{'level': 'error'})
config.validate_rule_conf(Rule, {'level': 'error'})
config.validate_rule_conf(Rule, {'level': 'warning'})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {'level': 'warn'})
Rule.CONF = {'length': int}
config.validate_rule_conf(Rule, {'length': 8})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {'height': 8})
Rule.CONF = {'a': bool, 'b': int}
config.validate_rule_conf(Rule, {'a': True, 'b': 0})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {'a': True})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {'b': 0})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {'a': 1, 'b': 0})
Rule.CONF = {'choice': (True, 88, 'str')}
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')}
config.validate_rule_conf(Rule, {'choice': 42})
config.validate_rule_conf(Rule, {'choice': 'hardcoded'})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {'choice': False})
self.assertRaises(config.YamlLintConfigError,
config.validate_rule_conf, Rule, {'choice': 'abc'})
class ExtendedConfigTestCase(unittest.TestCase):
def test_extend_add_rule(self):
old = config.YamlLintConfig('rules:\n'
' colons:\n'
' max-spaces-before: 0\n'
' max-spaces-after: 1\n')
new = config.YamlLintConfig('rules:\n'
' hyphens:\n'
' max-spaces-after: 2\n')
new.extend(old)
self.assertEqual(sorted(new.rules.keys()), ['colons', 'hyphens'])
self.assertEqual(new.rules['colons']['max-spaces-before'], 0)
self.assertEqual(new.rules['colons']['max-spaces-after'], 1)
self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2)
self.assertEqual(len(new.enabled_rules()), 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)
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(len(new.enabled_rules()), 1)
def test_extend_edit_rule(self):
old = config.YamlLintConfig('rules:\n'
' colons:\n'
' max-spaces-before: 0\n'
' max-spaces-after: 1\n'
' hyphens:\n'
' max-spaces-after: 2\n')
new = config.YamlLintConfig('rules:\n'
' colons:\n'
' max-spaces-before: 3\n'
' max-spaces-after: 4\n')
new.extend(old)
self.assertEqual(sorted(new.rules.keys()), ['colons', 'hyphens'])
self.assertEqual(new.rules['colons']['max-spaces-before'], 3)
self.assertEqual(new.rules['colons']['max-spaces-after'], 4)
self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2)
self.assertEqual(len(new.enabled_rules()), 2)
def test_extend_reenable_rule(self):
old = config.YamlLintConfig('rules:\n'
' colons:\n'
' max-spaces-before: 0\n'
' max-spaces-after: 1\n'
' hyphens: disable\n')
new = config.YamlLintConfig('rules:\n'
' hyphens:\n'
' max-spaces-after: 2\n')
new.extend(old)
self.assertEqual(sorted(new.rules.keys()), ['colons', 'hyphens'])
self.assertEqual(new.rules['colons']['max-spaces-before'], 0)
self.assertEqual(new.rules['colons']['max-spaces-after'], 1)
self.assertEqual(new.rules['hyphens']['max-spaces-after'], 2)
self.assertEqual(len(new.enabled_rules()), 2)
class ExtendedLibraryConfigTestCase(unittest.TestCase):
def test_extend_config_disable_rule(self):
old = config.YamlLintConfig('extends: default')
new = config.YamlLintConfig('extends: default\n'
'rules:\n'
' trailing-spaces: disable\n')
old.rules['trailing-spaces'] = False
self.assertEqual(sorted(new.rules.keys()), sorted(old.rules.keys()))
for rule in new.rules:
self.assertEqual(new.rules[rule], old.rules[rule])
def test_extend_config_override_whole_rule(self):
old = config.YamlLintConfig('extends: default')
new = config.YamlLintConfig('extends: default\n'
'rules:\n'
' empty-lines:\n'
' max: 42\n'
' max-start: 43\n'
' max-end: 44\n')
old.rules['empty-lines']['max'] = 42
old.rules['empty-lines']['max-start'] = 43
old.rules['empty-lines']['max-end'] = 44
self.assertEqual(sorted(new.rules.keys()), sorted(old.rules.keys()))
for rule in new.rules:
self.assertEqual(new.rules[rule], old.rules[rule])
def test_extend_config_override_rule_partly(self):
old = config.YamlLintConfig('extends: default')
new = config.YamlLintConfig('extends: default\n'
'rules:\n'
' empty-lines:\n'
' max-start: 42\n')
old.rules['empty-lines']['max-start'] = 42
self.assertEqual(sorted(new.rules.keys()), sorted(old.rules.keys()))
for rule in new.rules:
self.assertEqual(new.rules[rule], old.rules[rule])

58
tests/test_linter.py Normal file
View File

@@ -0,0 +1,58 @@
# -*- 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())

View File

@@ -18,8 +18,9 @@ import unittest
import yaml import yaml
from yamllint.parser import (line_generator, token_generator, from yamllint.parser import (line_generator, token_or_comment_generator,
token_or_line_generator, Line, Token) token_or_comment_or_line_generator,
Line, Token, Comment)
class ParserTestCase(unittest.TestCase): class ParserTestCase(unittest.TestCase):
@@ -61,8 +62,8 @@ class ParserTestCase(unittest.TestCase):
self.assertEqual(e[2].line_no, 3) self.assertEqual(e[2].line_no, 3)
self.assertEqual(e[2].content, 'at the end') self.assertEqual(e[2].content, 'at the end')
def test_token_generator(self): def test_token_or_comment_generator(self):
e = list(token_generator('')) e = list(token_or_comment_generator(''))
self.assertEqual(len(e), 2) self.assertEqual(len(e), 2)
self.assertEqual(e[0].prev, None) self.assertEqual(e[0].prev, None)
self.assertIsInstance(e[0].curr, yaml.Token) self.assertIsInstance(e[0].curr, yaml.Token)
@@ -71,16 +72,74 @@ class ParserTestCase(unittest.TestCase):
self.assertEqual(e[1].curr, e[0].next) self.assertEqual(e[1].curr, e[0].next)
self.assertEqual(e[1].next, None) self.assertEqual(e[1].next, None)
e = list(token_generator('---\n' e = list(token_or_comment_generator('---\n'
'k: v\n')) 'k: v\n'))
self.assertEqual(len(e), 9) self.assertEqual(len(e), 9)
self.assertIsInstance(e[3].curr, yaml.KeyToken) self.assertIsInstance(e[3].curr, yaml.KeyToken)
self.assertIsInstance(e[5].curr, yaml.ValueToken) self.assertIsInstance(e[5].curr, yaml.ValueToken)
def test_token_or_line_generator(self): e = list(token_or_comment_generator('# start comment\n'
e = list(token_or_line_generator('---\n' '- a\n'
'k: v\n')) '- key: val # key=val\n'
self.assertEqual(len(e), 12) '# 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], Token)
self.assertIsInstance(e[0].curr, yaml.StreamStartToken) self.assertIsInstance(e[0].curr, yaml.StreamStartToken)
self.assertIsInstance(e[1], Token) self.assertIsInstance(e[1], Token)
@@ -89,5 +148,6 @@ class ParserTestCase(unittest.TestCase):
self.assertIsInstance(e[3].curr, yaml.BlockMappingStartToken) self.assertIsInstance(e[3].curr, yaml.BlockMappingStartToken)
self.assertIsInstance(e[4].curr, yaml.KeyToken) self.assertIsInstance(e[4].curr, yaml.KeyToken)
self.assertIsInstance(e[6].curr, yaml.ValueToken) self.assertIsInstance(e[6].curr, yaml.ValueToken)
self.assertIsInstance(e[8], Line) self.assertIsInstance(e[8], Comment)
self.assertIsInstance(e[11], Line) self.assertIsInstance(e[9], Line)
self.assertIsInstance(e[12], Line)

188
tests/test_spec_examples.py Normal file
View File

@@ -0,0 +1,188 @@
# -*- 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: no}\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: no}\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: no}\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

@@ -0,0 +1,94 @@
# -*- 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 YamlLintTestCase(RuleTestCase):
rule_id = None # syntax error
def test_syntax_errors(self):
self.check('---\n'
'this is not: valid: YAML\n', None, problem=(2, 19))
self.check('---\n'
'this is: valid YAML\n'
'\n'
'this is an error: [\n'
'\n'
'...\n', None, problem=(6, 1))
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'
': - value 1\n'
' - value 2\n'
'...\n', None)
self.check('---\n'
'?\n'
' key\n'
': {a: 1}\n'
'...\n', None)
self.check('---\n'
'?\n'
' key\n'
':\n'
' val\n'
'...\n', None)
def test_mapping_between_sequences(self):
# This is valid YAML. See http://www.yaml.org/spec/1.2/spec.html,
# example 2.11
self.check('---\n'
'? - Detroit Tigers\n'
' - Chicago cubs\n'
':\n'
' - 2001-07-23\n'
'\n'
'? [New York Yankees,\n'
' 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,304 @@
# -*- 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_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'))

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

View File

@@ -0,0 +1,6 @@
literal: |
some
text
folded: >
some
text

View File

@@ -0,0 +1,2 @@
single: 'text'
double: "text"

View File

@@ -0,0 +1,2 @@
%YAML 1.2
--- text

View File

@@ -0,0 +1,12 @@
# Leading comment line spaces are
# neither content nor indentation.
Not indented:
By one space: |
By four
spaces
Flow style: [ # Leading spaces
By two, # in flow style
Also by two, # are neither
Still by two # content nor
] # indentation.

View File

@@ -0,0 +1,3 @@
# Comment

View File

@@ -0,0 +1,4 @@
key: # Comment
# lines
value

View File

@@ -0,0 +1,6 @@
{ first: Sammy, last: Sosa }:
# Statistics:
hr: # Home runs
65
avg: # Average
0.278

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