This commit is contained in:
Samuele Maci 2017-06-08 08:44:22 +00:00 committed by GitHub
commit e271a21735
12 changed files with 271 additions and 0 deletions

View file

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

View file

@ -66,6 +66,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`;

View file

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

View 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:]))

View file

@ -54,6 +54,7 @@ setup(
'name-tests-test = pre_commit_hooks.tests_should_end_in_test:validate_files',
'no-commit-to-branch = pre_commit_hooks.no_commit_to_branch:main',
'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',
],

View file

@ -0,0 +1,6 @@
foo: "bar"
alist:
- 2
- 34
- 234
blah: null

View file

@ -0,0 +1,3 @@
alist: [2, 34, 234]
blah: null
foo: bar

View file

@ -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",
},
},
}

View file

@ -0,0 +1,8 @@
array:
- 2
- 34
- 234
null_items: null
object:
inner_object:
attribute: true

View file

@ -0,0 +1,8 @@
"array":
- !!int "2"
- !!int "34"
- !!int "234"
"null_items": !!null "null"
"object":
"inner_object":
"attribute": !!bool "true"

View file

@ -0,0 +1,4 @@
array: [2, 34, 234]
null_items: null
object:
inner_object: {attribute: true}

View 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