In #1309 I shared a config:
repos:
...
- repo: local
hooks:
- id: pylint
args: [--ignore=version.py]
name: pylint
entry: .tox/pre-commit/bin/pylint
language: system
types: [python]
...
The Config works fine on my linux machine but on windows the entry is a problem and I need to change it to .tox/pre-commit/Scripts/pylint.exe. So I need to change binto Scripts and append .exe.
Is there a way to use the same config for both OS without the need to change it every time I change the machine? Like:
repos:
...
- repo: local
hooks:
- id: pylint
args: [--ignore=version.py]
name: pylint
entry-win: .tox/pre-commit/Scripts/pylint.exe
entry-linux: .tox/pre-commit/bin/pylint
language: system
types: [python]
...
If not I would like to propose it as a feature request. :)
using repo: local and especially language: system is all-bets-off at-your-own-support territory as these are both escape hatches from the normal golden-path way to accomplish things in the framework
that said, it's easy for you to accomplish this without needing special features from pre-commit by writing a small script to do your platform-specific logic:
- id: pylint
entry: ./.pre-commit-scripts/run-pylint
...
#!/usr/bin/env python3
import subprocess
import sys
def main():
if sys.platform == 'win32':
cmd = (r'.tox\pre-commit\Scripts\pylint.exe', *sys.argv[1:])
else:
cmd = ('.tox/pre-commit/bin/pylint', *sys.argv[1:])
return subprocess.call(cmd)
if __name__ == '__main__':
exit(main())
It would have reduced the amount of additional files but I understand what you are saying.
I did not think that far. Thanks for the idea and snippet though. :)
I use tox to mange almost all the stuff. For usage of pre-commit I run tox -e pre-commit which creates an venv with the needed dependencies etc. and runs pre-commit.
So I came up with another solution:
Let tox handle the pylint call. So pre-commit calls a special tox venv, which itself calls then pylint.
.pre-commit-config.yaml:
repos:
...
- repo: local
hooks:
- id: pylint
args: [--ignore=version.py]
name: pylint
entry: tox -e pylint --
language: system
types: [python]
...
tox.ini:
...
[testenv:pylint]
deps = pylint>=2.4,<3
commands = pylint {posargs}
...
I think there are more elegant ways to do this, but this works for me without additional files.
EDIT: Fixed broken config.
EDIT2: After further testing I like the script method above more because it seems overall cleaner.
EDIT3: I created a general script based on https://github.com/pre-commit/pre-commit/issues/1455#issuecomment-628019565
Set entrypoint to something like this ./pre_commit_runner pylint pre-commit,dev
#!/usr/bin/env python3
"""Script to call executables in `tox` envs
The script takes two mandatory arguments:
1. the executable to call like e.g. `pylint`
2. a string with comma separated `tox` envs to check for the executable
All other arguments after are passed to the tool on call.
The script considers OS and calls the tool accordingly.
"""
import subprocess
import sys
from pathlib import Path
def main():
"""Call given `tool` form given `tox` env"""
tool = sys.argv[1]
if sys.platform == "win32":
exe = Path("Scripts/" + tool + ".exe")
else:
exe = Path("bin/" + tool)
tox = Path(".tox")
envs = sys.argv[2].split(",")
cmd = None
for env in envs:
path = Path(tox / env / exe)
if path.is_file():
cmd = (str(path), *sys.argv[3:])
if cmd is None:
print(
"No '{}' executable found. Make sure one of the "
"following `tox` envs is accessible: {}".format(tool, envs)
)
return 1
return subprocess.call(cmd)
if __name__ == "__main__":
sys.exit(main())