2025-02-09 21:33:11 +01:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2025-02-09 21:25:27 +01:00
|
|
|
import os.path
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
2025-02-09 21:33:11 +01:00
|
|
|
from pre_commit import envcontext
|
2025-02-09 21:25:27 +01:00
|
|
|
from pre_commit.languages import r
|
|
|
|
from testing.fixtures import make_config_from_repo
|
|
|
|
from testing.fixtures import make_repo
|
|
|
|
from tests.repository_test import _get_hook_no_install
|
|
|
|
|
|
|
|
|
|
|
|
def _test_r_parsing(
|
|
|
|
tempdir_factory,
|
|
|
|
store,
|
|
|
|
hook_id,
|
|
|
|
expected_hook_expr={},
|
|
|
|
expected_args={},
|
2025-02-09 21:28:21 +01:00
|
|
|
config={},
|
|
|
|
expect_path_prefix=True,
|
2025-02-09 21:25:27 +01:00
|
|
|
):
|
|
|
|
repo_path = 'r_hooks_repo'
|
|
|
|
path = make_repo(tempdir_factory, repo_path)
|
2025-02-09 21:28:21 +01:00
|
|
|
config = config or make_config_from_repo(path)
|
2025-02-09 21:25:27 +01:00
|
|
|
hook = _get_hook_no_install(config, store, hook_id)
|
|
|
|
ret = r._cmd_from_hook(hook)
|
|
|
|
expected_cmd = 'Rscript'
|
|
|
|
expected_opts = (
|
|
|
|
'--no-save', '--no-restore', '--no-site-file', '--no-environ',
|
|
|
|
)
|
|
|
|
expected_path = os.path.join(
|
2025-02-09 21:28:21 +01:00
|
|
|
hook.prefix.prefix_dir if expect_path_prefix else '',
|
|
|
|
f'{hook_id}.R',
|
2025-02-09 21:25:27 +01:00
|
|
|
)
|
|
|
|
expected = (
|
|
|
|
expected_cmd,
|
|
|
|
*expected_opts,
|
|
|
|
*(expected_hook_expr or (expected_path,)),
|
|
|
|
*expected_args,
|
|
|
|
)
|
|
|
|
assert ret == expected
|
|
|
|
|
|
|
|
|
|
|
|
def test_r_parsing_file_no_opts_no_args(tempdir_factory, store):
|
|
|
|
hook_id = 'parse-file-no-opts-no-args'
|
|
|
|
_test_r_parsing(tempdir_factory, store, hook_id)
|
|
|
|
|
|
|
|
|
|
|
|
def test_r_parsing_file_opts_no_args(tempdir_factory, store):
|
|
|
|
with pytest.raises(ValueError) as excinfo:
|
|
|
|
r._entry_validate(['Rscript', '--no-init', '/path/to/file'])
|
|
|
|
|
|
|
|
msg = excinfo.value.args
|
|
|
|
assert msg == (
|
|
|
|
'The only valid syntax is `Rscript -e {expr}`',
|
|
|
|
'or `Rscript path/to/hook/script`',
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def test_r_parsing_file_no_opts_args(tempdir_factory, store):
|
|
|
|
hook_id = 'parse-file-no-opts-args'
|
|
|
|
expected_args = ['--no-cache']
|
|
|
|
_test_r_parsing(
|
|
|
|
tempdir_factory, store, hook_id, expected_args=expected_args,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def test_r_parsing_expr_no_opts_no_args1(tempdir_factory, store):
|
|
|
|
hook_id = 'parse-expr-no-opts-no-args-1'
|
|
|
|
_test_r_parsing(
|
|
|
|
tempdir_factory, store, hook_id, expected_hook_expr=('-e', '1+1'),
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def test_r_parsing_expr_no_opts_no_args2(tempdir_factory, store):
|
|
|
|
with pytest.raises(ValueError) as execinfo:
|
|
|
|
r._entry_validate(['Rscript', '-e', '1+1', '-e', 'letters'])
|
|
|
|
msg = execinfo.value.args
|
|
|
|
assert msg == ('You can supply at most one expression.',)
|
|
|
|
|
|
|
|
|
|
|
|
def test_r_parsing_expr_opts_no_args2(tempdir_factory, store):
|
|
|
|
with pytest.raises(ValueError) as execinfo:
|
|
|
|
r._entry_validate(
|
|
|
|
[
|
|
|
|
'Rscript', '--vanilla', '-e', '1+1', '-e', 'letters',
|
|
|
|
],
|
|
|
|
)
|
|
|
|
msg = execinfo.value.args
|
|
|
|
assert msg == (
|
|
|
|
'The only valid syntax is `Rscript -e {expr}`',
|
|
|
|
'or `Rscript path/to/hook/script`',
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def test_r_parsing_expr_args_in_entry2(tempdir_factory, store):
|
|
|
|
with pytest.raises(ValueError) as execinfo:
|
|
|
|
r._entry_validate(['Rscript', '-e', 'expr1', '--another-arg'])
|
|
|
|
|
|
|
|
msg = execinfo.value.args
|
|
|
|
assert msg == ('You can supply at most one expression.',)
|
|
|
|
|
|
|
|
|
|
|
|
def test_r_parsing_expr_non_Rscirpt(tempdir_factory, store):
|
|
|
|
with pytest.raises(ValueError) as execinfo:
|
|
|
|
r._entry_validate(['AnotherScript', '-e', '{{}}'])
|
|
|
|
|
|
|
|
msg = execinfo.value.args
|
|
|
|
assert msg == ('entry must start with `Rscript`.',)
|
2025-02-09 21:28:21 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_r_parsing_file_local(tempdir_factory, store):
|
|
|
|
path = 'path/to/script.R'
|
|
|
|
hook_id = 'local-r'
|
|
|
|
config = {
|
|
|
|
'repo': 'local',
|
|
|
|
'hooks': [{
|
|
|
|
'id': hook_id,
|
|
|
|
'name': 'local-r',
|
|
|
|
'entry': f'Rscript {path}',
|
|
|
|
'language': 'r',
|
|
|
|
}],
|
|
|
|
}
|
|
|
|
_test_r_parsing(
|
|
|
|
tempdir_factory,
|
|
|
|
store,
|
|
|
|
hook_id=hook_id,
|
|
|
|
expected_hook_expr=(path,),
|
|
|
|
config=config,
|
|
|
|
expect_path_prefix=False,
|
|
|
|
)
|
2025-02-09 21:33:11 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_rscript_exec_relative_to_r_home():
|
|
|
|
expected = os.path.join('r_home_dir', 'bin', 'Rscript')
|
|
|
|
with envcontext.envcontext((('R_HOME', 'r_home_dir'),)):
|
|
|
|
assert r._rscript_exec() == expected
|
|
|
|
|
|
|
|
|
|
|
|
def test_path_rscript_exec_no_r_home_set():
|
|
|
|
with envcontext.envcontext((('R_HOME', envcontext.UNSET),)):
|
|
|
|
assert r._rscript_exec() == 'Rscript'
|