running pytest as a pre-commit hook // no such file or directory issue
Asked Answered
E

2

19

in my Python project I use pytest as a pre-commit hook. Some tests create and delete temporary files, everything works fine when I run pytest <test directory>. However, when I run git commit and pre-commit hook triggers pytest, some tests fail because of FileNotFoundError: [Errno 2] No such file or directory: '<file name>'. I have an impression this happens when many files have been changed and are in the staging area (with 1-2 files I do not observe this issue). Here is my pytest section from .pre-commit-config.yaml:

  - repo: local
    hooks:
      - id: pytest-check
        name: pytest-check
        entry: bash -c 'pytest'
        language: system

the output looks as follows:

pytest-check.............................................................Failed
- hook id: pytest-check
- exit code: 1

tests/utils/test_application.py F                                        [ 91%]
tests/utils/test_image_io.py .FFF.........                               [100%]

==================================== ERRORS ====================================
_ ERROR at teardown of test_calling_with_nonexisting_parameter[--non_existing 1337-hm] _

    def teardown_module() -> None:
>       os.remove(OUTPUT_FILE)
E       FileNotFoundError: [Errno 2] No such file or directory: 'output.png'

tests/bdd/step_defs/test_runner_steps.py:98: FileNotFoundError

this does not happen when I run pytest from the console.

with pass_filenames: false and always_run: true the error does not show up any more:

  - repo: local
    hooks:
      - id: pytest-check
        name: pytest-check
        entry: pytest
        language: system
        pass_filenames: false
        always_run: true

with respect to wrapping things in bash, I'm still doing this for pylint:

  - repo: local
    hooks:
      - id: pylint-check
        name: pylint-check
        entry: bash -c 'find . -name "*.py" | xargs pylint'
        language: system
        types: [python]
        pass_filenames: false
        always_run: true

is there any better solution for this? pylint does not support recursion of an unlimited depth, thus I need a bash command there.

Thanks!

Best, Alexey

Ebeneser answered 22/9, 2020 at 13:55 Comment(0)
E
99

show your output, we can only guess at the problem otherwise

that said, you probably want to use always_run: true and pass_filenames: false -- also your entry is bogus, no need to wrap things in bash, just call the executable directly. Putting all that together:

  - repo: local
    hooks:
      - id: pytest-check
        name: pytest-check
        entry: pytest
        language: system
        pass_filenames: false
        always_run: true

disclaimer: I am the author of pre-commit

Empyreal answered 22/9, 2020 at 16:54 Comment(3)
thanks for the quick response! I will post my output below. Btw when is wrapping in bash needed? For example, mypy and pylint do not work properly as pre-commit hooks when calling without a bash wrapper.Ebeneser
please see my output on this page.Ebeneser
"do not work" is not a useful bug report, show what you're seeing -- you should never need bash. don't post as an answer, edit your original questionEmpyreal
G
8

If you are running various kinds of files through pre-commit or using hooks before you commit, you'll need to add another parameter to the .pre-commit-config.yaml file or it will fail with an exit code of 5 (no tests ran):

    - repo: local
      hooks:
      - id: pytest-check
        name: pytest-check
        stages: [commit]
        types: [python]
        entry: pytest
        language: system
        pass_filenames: false
        always_run: true

The addition of the types parameter will allow you to pass pre-commit even if no tests ran or there are no Python files.

Gerge answered 15/11, 2021 at 19:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.