Skip to content

Commit

Permalink
[ADD] hooks: New unused python file check
Browse files Browse the repository at this point in the history
Unused python files are considered python files not imported in
their corresponding __init__.py file. This only applies to
actual files that need to be imported, and automatically excludes
folders like migration or __manifest__.py files
  • Loading branch information
antonag32 committed Nov 11, 2022
1 parent fb2252d commit faeb201
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .pre-commit-hooks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,9 @@
types_or: ["text"]
files: \.(po|pot)$
require_serial: false
- id: oca-check-unused-python-file
name: Check unused python files
entry: oca-check-unused-python-file
language: python
types: [python]
files: (controllers|models|report|wizard)\.py$|tests\/test_.*\.py$
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ def generage_long_description():
"console_scripts": [
"oca-checks-odoo-module = oca_pre_commit_hooks.cli:main",
"oca-checks-po = oca_pre_commit_hooks.cli_po:main",
"oca-check-unused-python-file = oca_pre_commit_hooks.check_unused_python_file:main",
]
},
)
39 changes: 39 additions & 0 deletions src/oca_pre_commit_hooks/check_unused_python_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import argparse
import ast
import functools
import os
from typing import Set, Union


@functools.lru_cache()
def get_imported_files(dirname: str) -> Set[str]:
imported_files = set()
init_file = os.path.join(dirname, "__init__.py")
if os.path.exists(init_file):
with open(init_file, encoding="utf-8") as init_fd:
init_ast = ast.parse(init_fd.read())

if isinstance(init_ast.body, list):
for module in filter(lambda elem: isinstance(elem, ast.ImportFrom), init_ast.body):
for name in module.names:
imported_files.add(name.name)

return imported_files


def check_unused_python_file(filenames: list[str]) -> int:
status = 0
for filename in filenames:
if os.path.basename(filename)[:-3] not in get_imported_files(os.path.dirname(filename)):
print(f"{filename}: not imported")
status = -1

return status


def main(argv: Union[list[str], None] = None) -> int:
parser = argparse.ArgumentParser()
parser.add_argument("filenames", nargs="*")
args = parser.parse_args(argv)

return check_unused_python_file(args.filenames)
59 changes: 59 additions & 0 deletions tests/test_check_unused_python_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import os
from pathlib import Path

from oca_pre_commit_hooks.check_unused_python_file import main

FILE_NAMES = ["res_partner", "project_task", "helpdesk_ticket"]


def _gen_filepaths(filenames: list[str], basedir) -> list[str]:
return [f"{os.path.join(basedir, filename)}.py" for filename in filenames]


def test_all_used_files(tmpdir):
filepaths = _gen_filepaths(FILE_NAMES, tmpdir)
init_file = os.path.join(tmpdir, "__init__.py")
with open(init_file, "w", encoding="utf-8") as init_fd:
init_fd.writelines([f"from . import {filename}\n" for filename in FILE_NAMES])

for filepath in filepaths:
Path(filepath).touch()

assert main(filepaths) == 0

Path(init_file).unlink()
with open(init_file, "w", encoding="utf-8") as init_fd:
init_fd.write(f"from . import {','.join(FILE_NAMES)}")

assert main(filepaths) == 0


def test_all_unused_files(tmpdir):
filepaths = _gen_filepaths(FILE_NAMES, tmpdir)
init_file = os.path.join(tmpdir, "__init__.py")

Path(init_file).touch()
for filepath in filepaths:
Path(filepath).touch()

assert main(filepaths) == -1


def test_complex_init(tmpdir):
filepaths = _gen_filepaths(FILE_NAMES, tmpdir)
init_file = os.path.join(tmpdir, "__init__.py")
with open(init_file, "w", encoding="utf-8") as init_fd:
init_fd.writelines(
["def hello(cr):\n", "\treturn cr.commit()\n"] + [f"from . import {filename}\n" for filename in FILE_NAMES]
)

for filepath in filepaths:
Path(filepath).touch()

assert main(filepaths) == 0

extra_file = os.path.join(tmpdir, "extrafile.py")
Path(extra_file).touch()
filepaths.append(extra_file)

assert main(filepaths) == -1

0 comments on commit faeb201

Please sign in to comment.