mirror of
https://github.com/pre-commit/pre-commit-hooks.git
synced 2026-04-05 11:36:54 +00:00
Pretty yaml
This commit is contained in:
parent
63142f2d4e
commit
97a00d0324
12 changed files with 271 additions and 0 deletions
|
|
@ -49,6 +49,12 @@
|
|||
entry: pretty-format-json
|
||||
language: python
|
||||
files: \.json$
|
||||
- id: pretty-format-yaml
|
||||
name: Pretty format YAML
|
||||
description: This hook sets a standard for formatting YAML files.
|
||||
entry: pretty-format-yaml
|
||||
language: python
|
||||
files: \.(yaml|yml|eyaml)$
|
||||
- id: check-merge-conflict
|
||||
name: Check for merge conflicts
|
||||
description: Check for files that contain merge conflict strings.
|
||||
|
|
|
|||
|
|
@ -64,6 +64,12 @@ Add this to your `.pre-commit-config.yaml`
|
|||
- `--indent ...` - Control the indentation (either a number for a number of spaces or a string of whitespace). Defaults to 4 spaces.
|
||||
- `--no-sort-keys` - when autofixing, retain the original key ordering (instead of sorting the keys)
|
||||
- `--top-keys comma,separated,keys` - Keys to keep at the top of mappings.
|
||||
- `pretty-format-yaml` - Checks that all your YAML files are pretty. "Pretty"
|
||||
here means that keys are sorted and indented. You can configure this with
|
||||
the following commandline options:
|
||||
- `--autofix` - automatically format yaml files
|
||||
- `--default_style`, `--default_flow_style`, `--canonical`, `--indent`, `--width`, `--allow_unicode`, `--line_break`, `--encoding`, `--explicit_start`, `--explicit_end`, `--version`, `--tags` - define how a pretty YAML file looks like.
|
||||
The parameters are passed as kwargs into yaml.safe_dump method provided by [pyyaml package](http://pyyaml.org/wiki/PyYAMLDocumentation). Our suggestion of pretty YAML file is `-indent=4 --default_flow_style=False`.
|
||||
- `requirements-txt-fixer` - Sorts entries in requirements.txt
|
||||
- `trailing-whitespace` - Trims trailing whitespace.
|
||||
- Markdown linebreak trailing spaces preserved for `.md` and`.markdown`;
|
||||
|
|
|
|||
|
|
@ -49,6 +49,12 @@
|
|||
entry: pretty-format-json
|
||||
language: python
|
||||
files: \.json$
|
||||
- id: pretty-format-yaml
|
||||
name: Pretty format YAML
|
||||
description: This hook sets a standard for formatting YAML files.
|
||||
entry: pretty-format-yaml
|
||||
language: python
|
||||
files: \.(yaml|yml|eyaml)$
|
||||
- id: check-merge-conflict
|
||||
name: Check for merge conflicts
|
||||
description: Check for files that contain merge conflict strings.
|
||||
|
|
|
|||
127
pre_commit_hooks/pretty_format_yaml.py
Normal file
127
pre_commit_hooks/pretty_format_yaml.py
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
def _get_pretty_format(content, **kwargs):
|
||||
return yaml.safe_dump(yaml.safe_load(content), **kwargs)
|
||||
|
||||
|
||||
def _autofix(filename, new_contents):
|
||||
print("Fixing file {0}".format(filename))
|
||||
with open(filename, 'w') as f:
|
||||
f.write(new_contents)
|
||||
|
||||
|
||||
def filter_argument(accepted_values):
|
||||
def _validate(s):
|
||||
try:
|
||||
return {str(v): v for v in accepted_values}[s]
|
||||
except:
|
||||
raise argparse.ArgumentTypeError('Accepted values are: {}'.format(accepted_values))
|
||||
return _validate
|
||||
|
||||
|
||||
def none_or_boolean_argument(s):
|
||||
return filter_argument([None, True, False])(s)
|
||||
|
||||
|
||||
def pretty_format_yaml(argv=None):
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument(
|
||||
'--autofix',
|
||||
action='store_true',
|
||||
dest='autofix',
|
||||
help='Automatically fixes encountered not-pretty-formatted files',
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--default_style',
|
||||
help='PyYAML dump parameter. More info on http://pyyaml.org/wiki/PyYAMLDocumentation#Dumper'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--default_flow_style', type=none_or_boolean_argument,
|
||||
help='PyYAML dump parameter. More info on http://pyyaml.org/wiki/PyYAMLDocumentation#Dumper'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--canonical', type=none_or_boolean_argument,
|
||||
help='PyYAML dump parameter. More info on http://pyyaml.org/wiki/PyYAMLDocumentation#Dumper'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--indent', type=int,
|
||||
help='PyYAML dump parameter. More info on http://pyyaml.org/wiki/PyYAMLDocumentation#Dumper'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--width', type=int,
|
||||
help='PyYAML dump parameter. More info on http://pyyaml.org/wiki/PyYAMLDocumentation#Dumper'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--allow_unicode', type=none_or_boolean_argument,
|
||||
help='PyYAML dump parameter. More info on http://pyyaml.org/wiki/PyYAMLDocumentation#Dumper'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--line_break', type=none_or_boolean_argument,
|
||||
help='PyYAML dump parameter. More info on http://pyyaml.org/wiki/PyYAMLDocumentation#Dumper'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--encoding',
|
||||
help='PyYAML dump parameter. More info on http://pyyaml.org/wiki/PyYAMLDocumentation#Dumper'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--explicit_start', type=none_or_boolean_argument,
|
||||
help='PyYAML dump parameter. More info on http://pyyaml.org/wiki/PyYAMLDocumentation#Dumper'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--explicit_end', type=none_or_boolean_argument,
|
||||
help='PyYAML dump parameter. More info on http://pyyaml.org/wiki/PyYAMLDocumentation#Dumper'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--version',
|
||||
help='PyYAML dump parameter. More info on http://pyyaml.org/wiki/PyYAMLDocumentation#Dumper'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--tags',
|
||||
help='PyYAML dump parameter. More info on http://pyyaml.org/wiki/PyYAMLDocumentation#Dumper'
|
||||
)
|
||||
parser.add_argument('filenames', nargs='*', help='Filenames to fix')
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
pyyaml_kwargs = {
|
||||
key: value
|
||||
for key, value in args._get_kwargs()
|
||||
if key != 'autofix' and key != 'filenames'
|
||||
}
|
||||
|
||||
status = 0
|
||||
|
||||
for yaml_file in args.filenames:
|
||||
with open(yaml_file) as f:
|
||||
contents = f.read()
|
||||
|
||||
try:
|
||||
pretty_contents = _get_pretty_format(contents, **pyyaml_kwargs)
|
||||
|
||||
if contents != pretty_contents:
|
||||
print("File {0} is not pretty-formatted".format(yaml_file))
|
||||
|
||||
if args.autofix:
|
||||
_autofix(yaml_file, pretty_contents)
|
||||
|
||||
status = 1
|
||||
|
||||
except yaml.YAMLError:
|
||||
print(
|
||||
"Input File {0} is not a valid YAML, consider using check-yaml"
|
||||
.format(yaml_file)
|
||||
)
|
||||
return 1
|
||||
|
||||
return status
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(pretty_format_yaml(sys.argv[1:]))
|
||||
1
setup.py
1
setup.py
|
|
@ -53,6 +53,7 @@ setup(
|
|||
'forbid-new-submodules = pre_commit_hooks.forbid_new_submodules:main',
|
||||
'name-tests-test = pre_commit_hooks.tests_should_end_in_test:validate_files',
|
||||
'pretty-format-json = pre_commit_hooks.pretty_format_json:pretty_format_json',
|
||||
'pretty-format-yaml = pre_commit_hooks.pretty_format_yaml:pretty_format_yaml',
|
||||
'requirements-txt-fixer = pre_commit_hooks.requirements_txt_fixer:fix_requirements_txt',
|
||||
'trailing-whitespace-fixer = pre_commit_hooks.trailing_whitespace_fixer:fix_trailing_whitespace',
|
||||
],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
foo: "bar"
|
||||
alist:
|
||||
- 2
|
||||
- 34
|
||||
- 234
|
||||
blah: null
|
||||
3
testing/resources/yaml_files/pretty_formatted_yaml.yaml
Normal file
3
testing/resources/yaml_files/pretty_formatted_yaml.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
alist: [2, 34, 234]
|
||||
blah: null
|
||||
foo: bar
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
!!map {
|
||||
? !!str "array"
|
||||
: !!seq [
|
||||
!!int "2",
|
||||
!!int "34",
|
||||
!!int "234",
|
||||
],
|
||||
? !!str "null_items"
|
||||
: !!null "null",
|
||||
? !!str "object"
|
||||
: !!map {
|
||||
? !!str "inner_object"
|
||||
: !!map {
|
||||
? !!str "attribute"
|
||||
: !!bool "true",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
array:
|
||||
- 2
|
||||
- 34
|
||||
- 234
|
||||
null_items: null
|
||||
object:
|
||||
inner_object:
|
||||
attribute: true
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
"array":
|
||||
- !!int "2"
|
||||
- !!int "34"
|
||||
- !!int "234"
|
||||
"null_items": !!null "null"
|
||||
"object":
|
||||
"inner_object":
|
||||
"attribute": !!bool "true"
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
array: [2, 34, 234]
|
||||
null_items: null
|
||||
object:
|
||||
inner_object: {attribute: true}
|
||||
77
tests/pretty_format_yaml_test.py
Normal file
77
tests/pretty_format_yaml_test.py
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import os
|
||||
import shutil
|
||||
|
||||
import pytest
|
||||
|
||||
from pre_commit_hooks.pretty_format_yaml import pretty_format_yaml
|
||||
from testing.util import get_resource_path
|
||||
|
||||
|
||||
def get_yaml_resource_path(path):
|
||||
return get_resource_path(os.path.join('yaml_files', path))
|
||||
|
||||
|
||||
@pytest.mark.parametrize(('filename', 'expected_retval'), (
|
||||
('pretty_formatted_yaml.yaml', 0),
|
||||
('not_pretty_formatted_yaml.yaml', 1),
|
||||
))
|
||||
def test_pretty_format_yaml(filename, expected_retval):
|
||||
ret = pretty_format_yaml([get_yaml_resource_path(filename)])
|
||||
assert ret == expected_retval
|
||||
|
||||
|
||||
@pytest.mark.parametrize(('filename', 'arguments'), (
|
||||
('pretty_formatted_yaml_default_style_True.yaml', '--default_style=True'),
|
||||
('pretty_formatted_yaml_default_flow_style_False.yaml', '--default_flow_style=False'),
|
||||
('pretty_formatted_yaml_canonical_True.yaml', '--canonical=True'),
|
||||
('pretty_formatted_yaml_indent_4.yaml', '--indent=4'),
|
||||
))
|
||||
def test_pretty_format_yaml_arguments_success(filename, arguments):
|
||||
assert pretty_format_yaml(arguments.split() + [get_yaml_resource_path(filename)]) == 0
|
||||
|
||||
|
||||
def test_autofix_pretty_format_yaml(tmpdir):
|
||||
srcfile = tmpdir.join('to_be_yaml_formatted.yaml')
|
||||
shutil.copyfile(
|
||||
get_yaml_resource_path('not_pretty_formatted_yaml.yaml'),
|
||||
srcfile.strpath,
|
||||
)
|
||||
|
||||
# now launch the autofix on that file
|
||||
ret = pretty_format_yaml(['--autofix', srcfile.strpath])
|
||||
# it should have formatted it
|
||||
assert ret == 1
|
||||
|
||||
# file was formatted (shouldn't trigger linter again)
|
||||
ret = pretty_format_yaml([srcfile.strpath])
|
||||
assert ret == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(('argument', 'value'), (
|
||||
('--default_flow_style', 1),
|
||||
('--canonical', 'wrong_value'),
|
||||
('--indent', 'casual string'),
|
||||
('--width', 'casual string'),
|
||||
('--allow_unicode', 'no'),
|
||||
('--line_break', 'nein'),
|
||||
('--explicit_start', 'y'),
|
||||
('--explicit_end', 'n'),
|
||||
|
||||
))
|
||||
def test_pretty_format_yaml_wrong_arguments(argument, value):
|
||||
with pytest.raises(SystemExit):
|
||||
pretty_format_yaml([argument + '=' + str(value), get_yaml_resource_path('pretty_formatted_yaml')])
|
||||
|
||||
|
||||
def test_pretty_format_yaml_invalid_yaml_file(tmpdir):
|
||||
invalid_yaml_file = tmpdir.join('invalid.yaml')
|
||||
with open(invalid_yaml_file.strpath, 'w') as invalid_yaml:
|
||||
invalid_yaml.write("""
|
||||
foo: "bar"
|
||||
alist:
|
||||
2
|
||||
34
|
||||
234
|
||||
blah: null
|
||||
""")
|
||||
assert pretty_format_yaml([invalid_yaml_file.strpath]) == 1
|
||||
Loading…
Add table
Add a link
Reference in a new issue