diff --git a/pre_commit/languages/all.py b/pre_commit/languages/all.py index a56f7e79..504c28a0 100644 --- a/pre_commit/languages/all.py +++ b/pre_commit/languages/all.py @@ -7,6 +7,7 @@ from pre_commit.languages import node from pre_commit.languages import pcre from pre_commit.languages import pygrep from pre_commit.languages import python +from pre_commit.languages import python_venv from pre_commit.languages import ruby from pre_commit.languages import script from pre_commit.languages import swift @@ -57,6 +58,7 @@ languages = { 'pcre': pcre, 'pygrep': pygrep, 'python': python, + 'python_venv': python_venv, 'ruby': ruby, 'script': script, 'swift': swift, diff --git a/pre_commit/languages/python_venv.py b/pre_commit/languages/python_venv.py new file mode 100644 index 00000000..26389c65 --- /dev/null +++ b/pre_commit/languages/python_venv.py @@ -0,0 +1,73 @@ +from __future__ import unicode_literals + +import contextlib +import os +import sys + +from pre_commit.envcontext import envcontext +from pre_commit.envcontext import UNSET +from pre_commit.envcontext import Var +from pre_commit.languages import helpers +from pre_commit.languages.python import get_default_version # noqa: F401 +from pre_commit.languages.python import norm_version +from pre_commit.util import clean_path_on_failure +from pre_commit.util import cmd_output +from pre_commit.xargs import xargs + + +ENVIRONMENT_DIR = 'py_venv' + + +def bin_dir(venv): + """On windows there's a different directory for the virtualenv""" + bin_part = 'Scripts' if os.name == 'nt' else 'bin' + return os.path.join(venv, bin_part) + + +def get_env_patch(venv): + return ( + ('PYTHONHOME', UNSET), + ('VIRTUAL_ENV', venv), + ('PATH', (bin_dir(venv), os.pathsep, Var('PATH'))), + ) + + +@contextlib.contextmanager +def in_env(prefix, language_version): + envdir = prefix.path( + helpers.environment_dir(ENVIRONMENT_DIR, language_version), + ) + with envcontext(get_env_patch(envdir)): + yield + + +def healthy(prefix, language_version): + with in_env(prefix, language_version): + retcode, _, _ = cmd_output( + 'python', '-c', 'import ctypes, datetime, io, os, ssl, weakref', + retcode=None, + ) + return retcode == 0 + + +def install_environment(prefix, version, additional_dependencies): + additional_dependencies = tuple(additional_dependencies) + directory = helpers.environment_dir(ENVIRONMENT_DIR, version) + + # Install a virtualenv + env_dir = prefix.path(directory) + with clean_path_on_failure(env_dir): + if version != 'default': + executable = norm_version(version) + else: + executable = os.path.realpath(sys.executable) + cmd_output(executable, '-m', 'venv', env_dir, cwd='/') + with in_env(prefix, version): + helpers.run_setup_cmd( + prefix, ('pip', 'install', '.') + additional_dependencies, + ) + + +def run_hook(prefix, hook, file_args): + with in_env(prefix, hook['language_version']): + return xargs(helpers.to_cmd(hook), file_args)