mirror of
https://github.com/pre-commit/pre-commit-hooks.git
synced 2026-04-05 11:36:54 +00:00
Add missing init hook
http://python-notes.curiousefficiency.org/en/latest/python_concepts/import_traps.html#the-init-py-trap
This commit is contained in:
parent
31853d6c43
commit
513a24cde9
5 changed files with 103 additions and 0 deletions
|
|
@ -64,6 +64,20 @@
|
|||
entry: check-merge-conflict
|
||||
language: python
|
||||
types: [text]
|
||||
- id: check-missing-inits
|
||||
name: Find directories with missing __init__ files
|
||||
description: |-
|
||||
Verify that all Python directories contain an __init__.py
|
||||
|
||||
Although __init__.py files are not required on Python 3.3+, omitting them in
|
||||
one directory while having them in another directory will break in confusing
|
||||
and unexpected ways:
|
||||
|
||||
http://python-notes.curiousefficiency.org/en/latest/python_concepts/import_traps.html#the-init-py-trap
|
||||
entry: check-missing-inits
|
||||
language: python
|
||||
require_serial: true
|
||||
files: .*\.py$
|
||||
- id: check-symlinks
|
||||
name: Check for broken symlinks
|
||||
description: Checks for symlinks which do not point to anything.
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ Add this to your `.pre-commit-config.yaml`
|
|||
proper shebang.
|
||||
- `check-json` - Attempts to load all json files to verify syntax.
|
||||
- `check-merge-conflict` - Check for files that contain merge conflict strings.
|
||||
- `check-missing-inits` - Checks for missing `__init__.py` files in any directory containing Python files.
|
||||
- `check-symlinks` - Checks for symlinks which do not point to anything.
|
||||
- `check-toml` - Attempts to load all TOML files to verify syntax.
|
||||
- `check-vcs-permalinks` - Ensures that links to vcs websites are permalinks.
|
||||
|
|
|
|||
25
pre_commit_hooks/check_missing_inits.py
Normal file
25
pre_commit_hooks/check_missing_inits.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import os
|
||||
from argparse import ArgumentParser
|
||||
from typing import Optional
|
||||
from typing import Sequence
|
||||
|
||||
|
||||
def main(argv=None): # type: (Optional[Sequence[str]]) -> int
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('filenames', nargs='*', help='Filenames to check')
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
directories = {os.path.dirname(f) for f in args.filenames}
|
||||
missing_dirs = set()
|
||||
for d in directories:
|
||||
if not os.path.exists(os.path.join(d, '__init__.py')):
|
||||
missing_dirs.add(d)
|
||||
|
||||
for d in sorted(missing_dirs):
|
||||
print('No __init__.py file found in: {}'.format(d))
|
||||
|
||||
return 1 if len(missing_dirs) else 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
||||
|
|
@ -43,6 +43,7 @@ console_scripts =
|
|||
check-executables-have-shebangs = pre_commit_hooks.check_executables_have_shebangs:main
|
||||
check-json = pre_commit_hooks.check_json:main
|
||||
check-merge-conflict = pre_commit_hooks.check_merge_conflict:main
|
||||
check-missing-inits = pre_commit_hooks.check_missing_inits:main
|
||||
check-symlinks = pre_commit_hooks.check_symlinks:main
|
||||
check-toml = pre_commit_hooks.check_toml:main
|
||||
check-vcs-permalinks = pre_commit_hooks.check_vcs_permalinks:main
|
||||
|
|
|
|||
62
tests/check_missing_inits_test.py
Normal file
62
tests/check_missing_inits_test.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from pre_commit_hooks.check_missing_inits import main
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def filepaths(tmpdir):
|
||||
dirs = ['a', 'b']
|
||||
files = ['a.py', 'b.py', '__init__.py']
|
||||
paths = []
|
||||
for d in dirs:
|
||||
directory = tmpdir / d
|
||||
os.mkdir(str(directory))
|
||||
for f in files:
|
||||
path = (directory / f)
|
||||
paths.append(str(path))
|
||||
# Nested directory
|
||||
if d == 'b':
|
||||
directory = directory / 'c'
|
||||
os.mkdir(str(directory))
|
||||
for f in files:
|
||||
path = (directory / f)
|
||||
paths.append(str(path))
|
||||
return paths
|
||||
|
||||
|
||||
def test_has_inits(filepaths):
|
||||
for f in filepaths:
|
||||
with open(f, 'w'):
|
||||
pass
|
||||
|
||||
assert main(argv=filepaths) == 0
|
||||
|
||||
|
||||
def test_missing_inits(filepaths):
|
||||
remove = ''
|
||||
for f in filepaths:
|
||||
# Remove the init py file from the b directory
|
||||
if os.path.join('b', '__init__.py') in f:
|
||||
remove = str(f)
|
||||
continue
|
||||
with open(f, 'w'):
|
||||
pass
|
||||
filepaths.remove(remove)
|
||||
|
||||
assert main(argv=filepaths) == 1
|
||||
|
||||
|
||||
def test_nested_dirs_missing_inits(filepaths):
|
||||
remove = ''
|
||||
for f in filepaths:
|
||||
# Remove the init py file from a nested directory
|
||||
if os.path.join('b', 'c', '__init__.py') in f:
|
||||
remove = str(f)
|
||||
continue
|
||||
with open(f, 'w'):
|
||||
pass
|
||||
filepaths.remove(remove)
|
||||
|
||||
assert main(argv=filepaths) == 1
|
||||
Loading…
Add table
Add a link
Reference in a new issue