Provide pre-commit hooks for running problematic linters in pdm's development environment
This is as much an offer as it is a request. I recently began using pdm. I usually configure mypy as a pre-commit hook, and the annoyance I wanted to address was that mypy really needs access to dependencies in order to fully check the project code for type consistency. There's more detail about the problem at the bottom of the README at mikenerone/pdm-pre-commit, but you probably know what I'm referring to. That repo also contains my solution, which is just a pdm-specific hook that runs mypy from the development environment via pdm instead.
Personally, I'd rather see it under pdm-project where people will find it. If you like, I'd be more than happy to transfer the entire repo to you and let you take ownership of it (though I'd be happy to pitch in on maintaining it, as well - I suspect that at least a few other tools with similar problems will come up). Alternatively, if you're not bothered by "separation of concerns" and would rather that I make a pull request to add the hook to the existing .pre-commit-hook.yaml in the pdm repository, I'd be happy to do that, as well. Of course, if you hate the whole thing, that's ok, too. :P
Your pre-commit hook is indeed more convenient, but I have a small concern that this hook seems to assume that mypy has already been installed in the project. It also enforces a PDM available from PATH. However, in services such as pre-commit.ci, this may not be applicable. Thus, it would be more efficient to integrate the hook into the PDM project and have it installed with the PDM. Though it still looks a little awkward to me, I do not object to adding an item to the hook list of the project.
@frostming I hear ya. To support running mypy from any different environment would require passing the --python-executable argument for mypy to know the "right" environment to inspect for dependencies (which is really the core of the original problem). Of course that location is highly variable, but the pre-commit config does't provide any way to derive values like that, and I was just trying to keep it pretty trivial. It can certainly be done by implementing the hook in Python, instead, though. This also clears the way for including mypy itself as a dependency of the hook, so no external installation of mypy would be needed at all. I'll try to find some time to make that change soon and get back to you.
In principle, I should also be able to make pdm itself a dependency within the hook, addressing your pre-commit.ci concern. My only worry with the potential for an incompatibility between the pdm version used by the project developers and the (probably latest) version that would be selected for the hook, but this seems pretty minor.
I've solved this problem by having separate "lint" step that I run manually before commits. This also works as a commit hook because I use a virtual environment (hence the language: system). Through a PEP 582 aware hook that doesn't requirement me to install mypy and pre-commit in each project will certainly be a welcome improvement.
While @mikenerone is working on a more general solution to these hooks, for those curious how I got mine to work reliably, here are the relevant snippets.
pre-commit-config.yaml
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.1.1
hooks:
- id: mypy
language: system
always_run: true
args: [.]
pass_filenames: false
# Need various MyPy plugins, thus using system python. Run "pdm install --dev --group lint" first
pyproject.toml
[tool.pdm.dev-dependencies]
lint = [
"mypy==1.1.1",
"pre-commit~=2.2",
<put in here any stub or type packages you need>
]
[tool.pdm.scripts.mypy]
cmd = "mypy ."
help = "Run mypy against the code"
site_packages = true
[tool.pdm.scripts.lint]
cmd = "pre-commit run --all-files"
help = "Check code style against linters using pre-commit"
site_packages = true
[tool.pdm.scripts.pre_lint]
composite = [
"pdm install --dev --group lint",
]
help = "pre_lint hook: Installs the paackages needed to perform linting"
[tool.pdm.scripts.pre_publish]
composite = [
"lint",
]
help = "pre_publish hook: Ensure that linting and testing is performed before publishing"
[tool.mypy]
python_version = "3.10"
explicit_package_bases = true
check_untyped_defs = true
warn_unused_configs = true
show_error_codes = true
color_output = true
pretty = true
mypy_path = "src"
exclude = [
'^__pypackages__/',
'^.venv/'
]
[[tool.mypy.overrides]]
module = <package(s)-without-type-hints>
ignore_missing_imports = true
I just wanted to let folks know that they shouldn't hold their breath on this. I ended up switching to Pyright, and there was already an existing pre-commit hook that works quite nicely and accomplishes the same semantics as what I was going to go for here (except with Pyright).