diff --git a/pre_commit/clientlib/validate_base.py b/pre_commit/clientlib/validate_base.py index ce0c932e..35ae126a 100644 --- a/pre_commit/clientlib/validate_base.py +++ b/pre_commit/clientlib/validate_base.py @@ -9,9 +9,9 @@ import sys import jsonschema import jsonschema.exceptions import pkg_resources -import yaml from pre_commit.jsonschema_extensions import apply_defaults +from pre_commit.yaml import yaml_load def is_regex_valid(regex): @@ -36,7 +36,7 @@ def get_validator( the object read from the file. The function should either raise exception_type on failure. """ - def validate(filename, load_strategy=yaml.load): + def validate(filename, load_strategy=yaml_load): if not os.path.exists(filename): raise exception_type('File {} does not exist'.format(filename)) diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py index 53055a8d..a47eb8d0 100644 --- a/pre_commit/commands/autoupdate.py +++ b/pre_commit/commands/autoupdate.py @@ -4,9 +4,6 @@ from __future__ import unicode_literals import logging import sys -from aspy.yaml import ordered_dump -from aspy.yaml import ordered_load - import pre_commit.constants as C from pre_commit.clientlib.validate_config import CONFIG_JSON_SCHEMA from pre_commit.clientlib.validate_config import is_local_hooks @@ -18,6 +15,8 @@ from pre_commit.repository import Repository from pre_commit.util import CalledProcessError from pre_commit.util import cmd_output from pre_commit.util import cwd +from pre_commit.yaml import yaml_dump +from pre_commit.yaml import yaml_load logger = logging.getLogger('pre_commit') @@ -79,7 +78,7 @@ def autoupdate(runner): input_configs = load_config( runner.config_file_path, - load_strategy=ordered_load, + load_strategy=yaml_load, ) for repo_config in input_configs: @@ -111,7 +110,7 @@ def autoupdate(runner): if changed: with open(runner.config_file_path, 'w') as config_file: config_file.write( - ordered_dump( + yaml_dump( remove_defaults(output_configs, CONFIG_JSON_SCHEMA), **C.YAML_DUMP_KWARGS ) diff --git a/pre_commit/yaml.py b/pre_commit/yaml.py new file mode 100755 index 00000000..9ddbbfe6 --- /dev/null +++ b/pre_commit/yaml.py @@ -0,0 +1,11 @@ +from ruamel import yaml + + +def yaml_dump(obj, **kwargs): + "Ensure order & comments preservation" + return yaml.dump(obj, Dumper=yaml.RoundTripDumper, **kwargs) + + +def yaml_load(content): + "Ensure order & comments preservation" + return yaml.load(content, Loader=yaml.RoundTripLoader) diff --git a/setup.py b/setup.py index dc73b524..c1da8efe 100644 --- a/setup.py +++ b/setup.py @@ -37,12 +37,12 @@ setup( ] }, install_requires=[ - 'aspy.yaml', 'cached-property', 'jsonschema', 'nodeenv>=0.11.1', 'pyterminalsize', 'pyyaml', + 'ruamel.yaml', 'virtualenv', ], entry_points={ diff --git a/testing/fixtures.py b/testing/fixtures.py index 36c7400c..ae5d950e 100644 --- a/testing/fixtures.py +++ b/testing/fixtures.py @@ -5,9 +5,6 @@ import contextlib import io import os.path -from aspy.yaml import ordered_dump -from aspy.yaml import ordered_load - import pre_commit.constants as C from pre_commit.clientlib.validate_config import CONFIG_JSON_SCHEMA from pre_commit.clientlib.validate_config import validate_config_extra @@ -16,6 +13,8 @@ from pre_commit.jsonschema_extensions import apply_defaults from pre_commit.ordereddict import OrderedDict from pre_commit.util import cmd_output from pre_commit.util import cwd +from pre_commit.yaml import yaml_dump +from pre_commit.yaml import yaml_load from testing.util import copy_tree_to_path from testing.util import get_head_sha from testing.util import get_resource_path @@ -41,10 +40,10 @@ def make_repo(tempdir_factory, repo_source): def modify_manifest(path): """Modify the manifest yielded by this context to write to hooks.yaml.""" manifest_path = os.path.join(path, C.MANIFEST_FILE) - manifest = ordered_load(io.open(manifest_path).read()) + manifest = yaml_load(io.open(manifest_path).read()) yield manifest with io.open(manifest_path, 'w') as manifest_file: - manifest_file.write(ordered_dump(manifest, **C.YAML_DUMP_KWARGS)) + manifest_file.write(yaml_dump(manifest, **C.YAML_DUMP_KWARGS)) cmd_output('git', 'commit', '-am', 'update hooks.yaml', cwd=path) @@ -54,10 +53,10 @@ def modify_config(path='.', commit=True): .pre-commit-config.yaml """ config_path = os.path.join(path, C.CONFIG_FILE) - config = ordered_load(io.open(config_path).read()) + config = yaml_load(io.open(config_path).read()) yield config with io.open(config_path, 'w', encoding='UTF-8') as config_file: - config_file.write(ordered_dump(config, **C.YAML_DUMP_KWARGS)) + config_file.write(yaml_dump(config, **C.YAML_DUMP_KWARGS)) if commit: cmd_output('git', 'commit', '-am', 'update config', cwd=path) @@ -99,7 +98,7 @@ def write_config(directory, config): assert type(config) is OrderedDict config = [config] with io.open(os.path.join(directory, C.CONFIG_FILE), 'w') as config_file: - config_file.write(ordered_dump(config, **C.YAML_DUMP_KWARGS)) + config_file.write(yaml_dump(config, **C.YAML_DUMP_KWARGS)) def add_config_to_repo(git_path, config): diff --git a/tests/clientlib/validate_base_test.py b/tests/clientlib/validate_base_test.py index 5c44ab51..618b631b 100644 --- a/tests/clientlib/validate_base_test.py +++ b/tests/clientlib/validate_base_test.py @@ -1,10 +1,12 @@ from __future__ import unicode_literals +import sys + import pytest -from aspy.yaml import ordered_load from pre_commit.clientlib.validate_base import get_validator from pre_commit.ordereddict import OrderedDict +from pre_commit.yaml import yaml_load from testing.util import get_resource_path @@ -68,6 +70,11 @@ def test_returns_object_after_validating(noop_validator): def test_load_strategy(noop_validator): ret = noop_validator( get_resource_path('ordering_data_test.yaml'), - load_strategy=ordered_load, + load_strategy=yaml_load, ) - assert type(ret) is OrderedDict + if sys.version_info[0] < 3: + # ruamel.yaml uses a different implementation for Python < 3 + from ruamel.yaml.compat import ordereddict + assert isinstance(ret, ordereddict) + else: + assert isinstance(ret, OrderedDict)