Missing type errors by only running on changed files by default
See original GitHub issuemirrors-mypy passes just the list of staged changed files to Mypy (this is the default Pre-commit behaviour). This behaviour misses type errors resulting from but not occurring in the staged changes.
For example, when a function def’s parameter types are changed in one file but a usage of that function in another file is not changed (so not type-checked), a type error may be introduced but undetected by mirrors-mypy.
A concrete example:
Commit 1:
.
├── .pre-commit-config.yaml
└── src
└── example_package
├── __init__.py
├── cool.py
└── main.py
# cool.py
def cool_function(x: int) -> str:
return f"cool, you gave me {x}"
# main.py
from example_package.cool import cool_function
if __name__ == '__main__':
print(cool_function(42))
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/mirrors-mypy
rev: 'v0.790'
hooks:
- id: mypy
All is currently well. mypy src
will succeed, as will pre-commit run -a
Commit 2:
Just change the input_type of cool_function but don’t update it’s usage in main.py
# cool.py
def cool_function(x: str) -> str:
return f"cool, you gave me {x}"
Pre-commit will allow this commit through because it has only passed cool.py for type-checking. This may be surprising to some users. Running mypy src
or pre-commit run -a
will show us we have introduced a type error in main.py
src/example_package/main.py:4: error: Argument 1 to "cool_function" has incompatible type "int"; expected "str"
Found 1 error in 1 file (checked 3 source files)
In my case, I am later running pre-commit run -a
in a CI pipeline so the error does ultimately get caught and fixed, but this can result in some rebasing to keep history tidy and commits self-contained.
Users who wish to catch such cross-file type errors may wish to use pass_filenames: false
, so that no filenames are passed to Mypy and it can use its default Incremental Mode to decide which files to re-check. You will also have to use args
to pass it whatever directory, package or files you want it to check:
repos:
- repo: https://github.com/pre-commit/mirrors-mypy
rev: 'v0.790'
hooks:
- id: mypy
verbose: true
pass_filenames: false
args: ["src"] # This part may differ depending on your project structure
In the absence of an obvious one-size-fits-all solution, I’d like to suggest that an extra note explaining this caveat be added to the README for newcomers.
Thanks for your time
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (2 by maintainers)
Top GitHub Comments
Okay. The main dupe I see is #13. I mostly wanted to open this for visibility. Of course, there are many other similar but distinct issues that arise from passing filenames directly, but this hasn’t so far earnt it a note in the README.
I know you hold the view that commits should be fast even at the cost of false positives. My argument would be that if someone is adding Mypy in a pre-commit hook, it may surprise them that this hook silently ignores errors like this, at least enough to warrant a sentence or two in the README.
you’re free to run
pre-commit run mypy --all-files
at your leisure