8000 Support for conda as a language by xhochy · Pull Request #1232 · pre-commit/pre-commit · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ jobs:
COVERAGE_IGNORE_WINDOWS: '# pragma: windows no cover'
TOX_TESTENV_PASSENV: COVERAGE_IGNORE_WINDOWS
TEMP: C:\Temp # remove when dropping python2
pre_test:
- powershell: Write-Host "##vso[task.prependpath]$env:CONDA\Scripts"
displayName: Add conda to PATH
- template: job--python-tox.yml@asottile
parameters:
toxenvs: [py37]
Expand Down
2 changes: 2 additions & 0 deletions pre_commit/languages/all.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import unicode_literals

from pre_commit.languages import conda
from pre_commit.languages import docker
from pre_commit.languages import docker_image
from pre_commit.languages import fail
Expand Down Expand Up @@ -52,6 +53,7 @@
# """

languages = {
'conda': conda,
'docker': docker,
'docker_image': docker_image,
'fail': fail,
Expand Down
66 changes: 66 additions & 0 deletions pre_commit/languages/conda.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import contextlib
import os

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.util import clean_path_on_failure
from pre_commit.util import cmd_output_b

ENVIRONMENT_DIR = 'conda'
get_default_version = helpers.basic_get_default_version
healthy = helpers.basic_healthy


def get_env_patch(env):
# On non-windows systems executable live in $CONDA_PREFIX/bin, on Windows
# they can be in $CONDA_PREFIX/bin, $CONDA_PREFIX/Library/bin,
# $CONDA_PREFIX/Scripts and $CONDA_PREFIX. Whereas the latter only
# seems to be used for python.exe.
path = (os.path.join(env, 'bin'), os.pathsep, Var('PATH'))
if os.name == 'nt': # pragma: no cover (platform specific)
path = (env, os.pathsep) + path
path = (os.path.join(env, 'Scripts'), os.pathsep) + path
path = (os.path.join(env, 'Library', 'bin'), os.pathsep) + path

return (
('PYTHONHOME', UNSET),
('VIRTUAL_ENV', UNSET),
('CONDA_PREFIX', env),
('PATH', path),
)


@contextlib.contextmanager
def in_env(prefix, language_version):
directory = helpers.environment_dir(ENVIRONMENT_DIR, language_version)
envdir = prefix.path(directory)
with envcontext(get_env_patch(envdir)):
yield


def install_environment(prefix, version, additional_dependencies):
helpers.assert_version_default('conda', version)
directory = helpers.environment_dir(ENVIRONMENT_DIR, version)

env_dir = prefix.path(directory)
with clean_path_on_failure(env_dir):
cmd_output_b(
'conda', 'env', 'create', '-p', env_dir, '--file',
'environment.yml', cwd=prefix.prefix 8000 _dir,
)
if additional_dependencies:
cmd_output_b(
'conda', 'install', '-p', env_dir, *additional_dependencies,
cwd=prefix.prefix_dir
)


def run_hook(hook, file_args, color):
# TODO: Some rare commands need to be run using `conda run` but mostly we
# can run them withot which is much quicker and produces a better
# output.
# cmd = ('conda', 'run', '-p', env_dir) + hook.cmd
with in_env(hook.prefix, hook.language_version):
return helpers.run_xargs(hook, hook.cmd, file_args, color=color)
9 changes: 9 additions & 0 deletions pre_commit/resources/empty_template_environment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
channels:
- conda-forge
- defaults
dependencies:
# This cannot be empty as otherwise no environment will be created.
# We're using openssl here as it is available on all system and will
# most likely be always installed anyways.
# See https://github.com/conda/conda/issues/9487
- openssl
2 changes: 1 addition & 1 deletion pre_commit/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def _git_cmd(*args):

LOCAL_RESOURCES = (
'Cargo.toml', 'main.go', 'main.rs', '.npmignore', 'package.json',
'pre_commit_dummy_package.gemspec', 'setup.py',
'pre_commit_dummy_package.gemspec', 'setup.py', 'environment.yml',
)

def make_local(self, deps):
Expand Down
10 changes: 10 additions & 0 deletions testing/resources/conda_hooks_repo/.pre-commit-hooks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
- id: sys-exec
name: sys-exec
entry: python -c 'import os; import sys; print(sys.executable.split(os.path.sep)[-2]) if os.name == "nt" else print(sys.executable.split(os.path.sep)[-3])'
language: conda
files: \.py$
- id: additional-deps
name: additional-deps
entry: python
language: conda
files: \.py$
6 changes: 6 additions & 0 deletions testing/resources/conda_hooks_repo/environment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
channels:
- conda-forge
- defaults< B94A /span>
dependencies:
- python
- pip
40 changes: 40 additions & 0 deletions tests/repository_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,46 @@ def _test_hook_repo(
assert _norm_out(out) == expected


def test_conda_hook(tempdir_factory, store):
_test_hook_repo(
tempdir_factory, store, 'conda_hooks_repo',
'sys-exec', [os.devnull],
b'conda-default\n',
)


def test_conda_with_additional_dependencies_hook(tempdir_factory, store):
_test_hook_repo(
tempdir_factory, store, 'conda_hooks_repo',
'additional-deps', [os.devnull],
b'OK\n',
config_kwargs={
'hooks': [{
'id': 'additional-deps',
'args': ['-c', 'import mccabe; print("OK")'],
'additional_dependencies': ['mccabe'],
}],
},
)


def test_local_conda_additional_dependencies(store):
config = {
'repo': 'local',
'hooks': [{
'id': 'local-conda',
'name': 'local-conda',
'entry': 'python',
'language': 'conda',
'args': ['-c', 'import mccabe; print("OK")'],
'additional_dependencies': ['mccabe'],
}],
}
ret, out = _get_hook(config, store, 'local-conda').run((), color=False)
assert ret == 0
assert _norm_out(out) == b'OK\n'


def test_python_hook(tempdir_factory, store):
_test_hook_repo(
tempdir_factory, store, 'python_hooks_repo',
Expand Down
0