From ebe5132576b9f84859e018b2430fa9a21e307716 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 14 Oct 2018 12:24:59 -0700 Subject: [PATCH 1/3] Replace pkg_resources.get_distribution with importlib-metadata --- pre_commit/constants.py | 5 ++--- pre_commit/repository.py | 8 ++++---- pre_commit/util.py | 5 +++++ setup.py | 2 ++ tests/util_test.py | 7 +++++++ 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/pre_commit/constants.py b/pre_commit/constants.py index 48ba2cb9..a8cdc2e5 100644 --- a/pre_commit/constants.py +++ b/pre_commit/constants.py @@ -1,7 +1,7 @@ from __future__ import absolute_import from __future__ import unicode_literals -import pkg_resources +import importlib_metadata # TODO: importlib.metadata py38? CONFIG_FILE = '.pre-commit-config.yaml' MANIFEST_FILE = '.pre-commit-hooks.yaml' @@ -18,8 +18,7 @@ INSTALLED_STATE_VERSION = '1' # Bump when modifying `empty_template` LOCAL_REPO_VERSION = '1' -VERSION = pkg_resources.get_distribution('pre-commit').version -VERSION_PARSED = pkg_resources.parse_version(VERSION) +VERSION = importlib_metadata.version('pre_commit') # `manual` is not invoked by any installed git hook. See #719 STAGES = ('commit', 'commit-msg', 'manual', 'push') diff --git a/pre_commit/repository.py b/pre_commit/repository.py index 278f31a2..d718c2ff 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -8,7 +8,6 @@ import pipes import shutil import sys -import pkg_resources from cached_property import cached_property from cfgv import apply_defaults from cfgv import validate @@ -23,6 +22,7 @@ from pre_commit.clientlib import MANIFEST_HOOK_DICT from pre_commit.languages.all import languages from pre_commit.languages.helpers import environment_dir from pre_commit.prefix import Prefix +from pre_commit.util import parse_version logger = logging.getLogger('pre_commit') @@ -110,13 +110,13 @@ def _hook(*hook_dicts): for dct in rest: ret.update(dct) - version = pkg_resources.parse_version(ret['minimum_pre_commit_version']) - if version > C.VERSION_PARSED: + version = ret['minimum_pre_commit_version'] + if parse_version(version) > parse_version(C.VERSION): logger.error( 'The hook `{}` requires pre-commit version {} but version {} ' 'is installed. ' 'Perhaps run `pip install --upgrade pre-commit`.'.format( - ret['id'], version, C.VERSION_PARSED, + ret['id'], version, C.VERSION, ), ) exit(1) diff --git a/pre_commit/util.py b/pre_commit/util.py index bcb47c3f..55210f10 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -211,3 +211,8 @@ def copy_tree_to_path(src_dir, dest_dir): shutil.copytree(srcname, destname) else: shutil.copy(srcname, destname) + + +def parse_version(s): + """poor man's version comparison""" + return tuple(int(p) for p in s.split('.')) diff --git a/setup.py b/setup.py index 3eb04d8a..82a70371 100644 --- a/setup.py +++ b/setup.py @@ -40,6 +40,8 @@ setup( 'cached-property', 'cfgv>=1.0.0', 'identify>=1.0.0', + # if this makes it into python3.8 move to extras_require + 'importlib-metadata', 'nodeenv>=0.11.1', 'pyyaml', 'six', diff --git a/tests/util_test.py b/tests/util_test.py index 967163e4..56eb5aaa 100644 --- a/tests/util_test.py +++ b/tests/util_test.py @@ -9,6 +9,7 @@ from pre_commit.util import CalledProcessError from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output from pre_commit.util import memoize_by_cwd +from pre_commit.util import parse_version from pre_commit.util import tmpdir from testing.util import cwd @@ -117,3 +118,9 @@ def test_cmd_output_exe_not_found(): ret, out, _ = cmd_output('i-dont-exist', retcode=None) assert ret == 1 assert out == 'Executable `i-dont-exist` not found' + + +def test_parse_version(): + assert parse_version('0.0') == parse_version('0.0') + assert parse_version('0.1') > parse_version('0.0') + assert parse_version('2.1') >= parse_version('2') From 9f60561d6f5038cf58d3cd1dd6f2baccfc630f0d Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 14 Oct 2018 13:17:38 -0700 Subject: [PATCH 2/3] Replace resources with importlib_resources --- pre_commit/commands/install_uninstall.py | 5 +-- pre_commit/languages/ruby.py | 21 ++++++----- pre_commit/make_archives.py | 3 +- pre_commit/resources/__init__.py | 0 .../.npmignore => empty_template_.npmignore} | 0 .../Cargo.toml => empty_template_Cargo.toml} | 0 .../main.go => empty_template_main.go} | 0 .../main.rs => empty_template_main.rs} | 0 ...ckage.json => empty_template_package.json} | 0 ...template_pre_commit_dummy_package.gemspec} | 0 .../setup.py => empty_template_setup.py} | 0 pre_commit/store.py | 13 +++++-- pre_commit/util.py | 37 +++++++------------ setup.py | 6 +-- testing/fixtures.py | 20 +++++++++- tests/commands/install_uninstall_test.py | 7 ++-- tests/store_test.py | 9 +++++ 17 files changed, 72 insertions(+), 49 deletions(-) create mode 100644 pre_commit/resources/__init__.py rename pre_commit/resources/{empty_template/.npmignore => empty_template_.npmignore} (100%) rename pre_commit/resources/{empty_template/Cargo.toml => empty_template_Cargo.toml} (100%) rename pre_commit/resources/{empty_template/main.go => empty_template_main.go} (100%) rename pre_commit/resources/{empty_template/main.rs => empty_template_main.rs} (100%) rename pre_commit/resources/{empty_template/package.json => empty_template_package.json} (100%) rename pre_commit/resources/{empty_template/pre_commit_dummy_package.gemspec => empty_template_pre_commit_dummy_package.gemspec} (100%) rename pre_commit/resources/{empty_template/setup.py => empty_template_setup.py} (100%) diff --git a/pre_commit/commands/install_uninstall.py b/pre_commit/commands/install_uninstall.py index d76a6c1a..d3133060 100644 --- a/pre_commit/commands/install_uninstall.py +++ b/pre_commit/commands/install_uninstall.py @@ -12,7 +12,7 @@ from pre_commit.repository import repositories from pre_commit.util import cmd_output from pre_commit.util import make_executable from pre_commit.util import mkdirp -from pre_commit.util import resource_filename +from pre_commit.util import resource_text logger = logging.getLogger(__name__) @@ -80,8 +80,7 @@ def install( } with io.open(hook_path, 'w') as hook_file: - with io.open(resource_filename('hook-tmpl')) as f: - contents = f.read() + contents = resource_text('hook-tmpl') before, rest = contents.split(TEMPLATE_START) to_template, after = rest.split(TEMPLATE_END) diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index 3bd7130d..bef3fe38 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -11,7 +11,7 @@ from pre_commit.envcontext import Var from pre_commit.languages import helpers from pre_commit.util import CalledProcessError from pre_commit.util import clean_path_on_failure -from pre_commit.util import resource_filename +from pre_commit.util import resource_bytesio from pre_commit.xargs import xargs @@ -47,22 +47,23 @@ def in_env(prefix, language_version): # pragma: windows no cover yield +def _extract_resource(filename, dest): + with resource_bytesio(filename) as bio: + with tarfile.open(fileobj=bio) as tf: + tf.extractall(dest) + + def _install_rbenv(prefix, version='default'): # pragma: windows no cover directory = helpers.environment_dir(ENVIRONMENT_DIR, version) - with tarfile.open(resource_filename('rbenv.tar.gz')) as tf: - tf.extractall(prefix.path('.')) + _extract_resource('rbenv.tar.gz', prefix.path('.')) shutil.move(prefix.path('rbenv'), prefix.path(directory)) # Only install ruby-build if the version is specified if version != 'default': - # ruby-download - with tarfile.open(resource_filename('ruby-download.tar.gz')) as tf: - tf.extractall(prefix.path(directory, 'plugins')) - - # ruby-build - with tarfile.open(resource_filename('ruby-build.tar.gz')) as tf: - tf.extractall(prefix.path(directory, 'plugins')) + plugins_dir = prefix.path(directory, 'plugins') + _extract_resource('ruby-download.tar.gz', plugins_dir) + _extract_resource('ruby-build.tar.gz', plugins_dir) activate_path = prefix.path(directory, 'bin', 'activate') with io.open(activate_path, 'w') as activate_file: diff --git a/pre_commit/make_archives.py b/pre_commit/make_archives.py index e85a8f4a..865ef061 100644 --- a/pre_commit/make_archives.py +++ b/pre_commit/make_archives.py @@ -8,7 +8,6 @@ import tarfile from pre_commit import output from pre_commit.util import cmd_output -from pre_commit.util import resource_filename from pre_commit.util import rmtree from pre_commit.util import tmpdir @@ -56,7 +55,7 @@ def make_archive(name, repo, ref, destdir): def main(argv=None): parser = argparse.ArgumentParser() - parser.add_argument('--dest', default=resource_filename()) + parser.add_argument('--dest', default='pre_commit/resources') args = parser.parse_args(argv) for archive_name, repo, ref in REPOS: output.write_line('Making {}.tar.gz for {}@{}'.format( diff --git a/pre_commit/resources/__init__.py b/pre_commit/resources/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pre_commit/resources/empty_template/.npmignore b/pre_commit/resources/empty_template_.npmignore similarity index 100% rename from pre_commit/resources/empty_template/.npmignore rename to pre_commit/resources/empty_template_.npmignore diff --git a/pre_commit/resources/empty_template/Cargo.toml b/pre_commit/resources/empty_template_Cargo.toml similarity index 100% rename from pre_commit/resources/empty_template/Cargo.toml rename to pre_commit/resources/empty_template_Cargo.toml diff --git a/pre_commit/resources/empty_template/main.go b/pre_commit/resources/empty_template_main.go similarity index 100% rename from pre_commit/resources/empty_template/main.go rename to pre_commit/resources/empty_template_main.go diff --git a/pre_commit/resources/empty_template/main.rs b/pre_commit/resources/empty_template_main.rs similarity index 100% rename from pre_commit/resources/empty_template/main.rs rename to pre_commit/resources/empty_template_main.rs diff --git a/pre_commit/resources/empty_template/package.json b/pre_commit/resources/empty_template_package.json similarity index 100% rename from pre_commit/resources/empty_template/package.json rename to pre_commit/resources/empty_template_package.json diff --git a/pre_commit/resources/empty_template/pre_commit_dummy_package.gemspec b/pre_commit/resources/empty_template_pre_commit_dummy_package.gemspec similarity index 100% rename from pre_commit/resources/empty_template/pre_commit_dummy_package.gemspec rename to pre_commit/resources/empty_template_pre_commit_dummy_package.gemspec diff --git a/pre_commit/resources/empty_template/setup.py b/pre_commit/resources/empty_template_setup.py similarity index 100% rename from pre_commit/resources/empty_template/setup.py rename to pre_commit/resources/empty_template_setup.py diff --git a/pre_commit/store.py b/pre_commit/store.py index 07702fb5..f3096fcd 100644 --- a/pre_commit/store.py +++ b/pre_commit/store.py @@ -11,9 +11,8 @@ import pre_commit.constants as C from pre_commit import file_lock from pre_commit.util import clean_path_on_failure from pre_commit.util import cmd_output -from pre_commit.util import copy_tree_to_path from pre_commit.util import no_git_env -from pre_commit.util import resource_filename +from pre_commit.util import resource_text logger = logging.getLogger('pre_commit') @@ -149,9 +148,17 @@ class Store(object): return self._new_repo(repo, ref, deps, clone_strategy) + LOCAL_RESOURCES = ( + 'Cargo.toml', 'main.go', 'main.rs', '.npmignore', 'package.json', + 'pre_commit_dummy_package.gemspec', 'setup.py', + ) + def make_local(self, deps): def make_local_strategy(directory): - copy_tree_to_path(resource_filename('empty_template'), directory) + for resource in self.LOCAL_RESOURCES: + contents = resource_text('empty_template_{}'.format(resource)) + with io.open(os.path.join(directory, resource), 'w') as f: + f.write(contents) env = no_git_env() name, email = 'pre-commit', 'asottile+pre-commit@umich.edu' diff --git a/pre_commit/util.py b/pre_commit/util.py index 55210f10..963461d1 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -7,14 +7,21 @@ import os.path import shutil import stat import subprocess +import sys import tempfile -import pkg_resources import six from pre_commit import five from pre_commit import parse_shebang +if sys.version_info >= (3, 7): # pragma: no cover (PY37+) + from importlib.resources import open_binary + from importlib.resources import read_text +else: # pragma: no cover ( Date: Sun, 14 Oct 2018 13:41:59 -0700 Subject: [PATCH 3/3] Exclude coverage in the template file --- .coveragerc | 1 + 1 file changed, 1 insertion(+) diff --git a/.coveragerc b/.coveragerc index 2dca7634..d7a24812 100644 --- a/.coveragerc +++ b/.coveragerc @@ -8,6 +8,7 @@ omit = # Don't complain if non-runnable code isn't run */__main__.py pre_commit/color_windows.py + pre_commit/resources/* [report] show_missing = True