1
|
|
|
# Copyright (c) 2018 Alexander Todorov <[email protected]> |
2
|
|
|
|
3
|
|
|
# Licensed under the GPL 2.0: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
4
|
|
|
|
5
|
|
|
import os |
6
|
|
|
|
7
|
|
|
import astroid |
8
|
|
|
|
9
|
|
|
from pylint import interfaces |
10
|
|
|
from pylint import checkers |
11
|
|
|
from pylint.checkers import utils |
12
|
|
|
|
13
|
|
|
|
14
|
|
|
class EmptyModuleChecker(checkers.BaseChecker): |
15
|
|
|
__implements__ = (interfaces.IAstroidChecker,) |
16
|
|
|
|
17
|
|
|
name = 'empty-module-checker' |
18
|
|
|
|
19
|
|
|
msgs = {'E4481': ("Remove empty module from git!", |
20
|
|
|
'remove-empty-module', |
21
|
|
|
"Kiwi TCMS doesn't need to carry around modules which are empty. " |
22
|
|
|
"They must be removed from the source code!")} |
23
|
|
|
|
24
|
|
|
@utils.check_messages('remove-empty-module') |
25
|
|
|
def visit_module(self, node): |
26
|
|
|
if not node.body and not node.path[0].endswith('__init__.py'): |
27
|
|
|
self.add_message('remove-empty-module', node=node) |
28
|
|
|
|
29
|
|
|
|
30
|
|
|
class ModuleInDirectoryWithoutInitChecker(checkers.BaseChecker): |
31
|
|
|
__implements__ = (interfaces.IAstroidChecker,) |
32
|
|
|
|
33
|
|
|
name = 'dir-without-init-checker' |
34
|
|
|
|
35
|
|
|
msgs = {'R4482': ("File '%s' is in directory without __init__.py", |
36
|
|
|
'module-in-directory-without-init', |
37
|
|
|
"Python module is found inside a directory which is " |
38
|
|
|
"missing __init__.py! This will lead to missing packages when " |
39
|
|
|
"tarball is built for distribution on PyPI! See " |
40
|
|
|
"https://github.com/kiwitcms/Kiwi/issues/790")} |
41
|
|
|
|
42
|
|
|
project_root = os.path.abspath( |
43
|
|
|
os.path.join(os.path.dirname(__file__), '..', 'tcms')) |
44
|
|
|
|
45
|
|
|
# NOTE: this works against tcms/ directory and will not take into account |
46
|
|
|
# if we want to examine only a sub-dir or a few files |
47
|
|
|
# all files found by os.walk |
48
|
|
|
all_python_files = set() |
49
|
|
|
# all modules found by pylint, which conveniently skips files/dirs |
50
|
|
|
# with missing __init__.py |
51
|
|
|
discovered_python_files = set() |
52
|
|
|
|
53
|
|
|
def open(self): |
54
|
|
|
for root, _dirs, files in os.walk(self.project_root, topdown=False): |
55
|
|
|
# skip migrations |
56
|
|
|
if root.find('migrations') > -1: |
57
|
|
|
continue |
58
|
|
|
|
59
|
|
|
for file_name in files: |
60
|
|
|
if file_name.endswith('.py'): |
61
|
|
|
self.all_python_files.add( |
62
|
|
|
os.path.join(self.project_root, root, file_name)) |
63
|
|
|
|
64
|
|
|
def visit_module(self, node): |
65
|
|
|
for file_name in node.path: |
66
|
|
|
self.discovered_python_files.add(file_name) |
67
|
|
|
|
68
|
|
|
@utils.check_messages('module-in-directory-without-init') |
69
|
|
|
def close(self): |
70
|
|
|
diff = self.all_python_files - self.discovered_python_files |
71
|
|
|
diff = list(diff) |
72
|
|
|
diff.sort() |
73
|
|
|
|
74
|
|
|
dir_prefix = os.path.dirname(self.project_root) + '/' |
75
|
|
|
for fname in diff: |
76
|
|
|
fname = fname.replace(dir_prefix, '') |
77
|
|
|
self.add_message('module-in-directory-without-init', args=(fname,)) |
78
|
|
|
|
79
|
|
|
|
80
|
|
|
class EmptyClassChecker(checkers.BaseChecker): |
81
|
|
|
__implements__ = (interfaces.IAstroidChecker,) |
82
|
|
|
|
83
|
|
|
name = 'empty-class-checker' |
84
|
|
|
|
85
|
|
|
msgs = {'E4483': ("Remove empty class from git!", |
86
|
|
|
'remove-empty-class', |
87
|
|
|
"Kiwi TCMS doesn't need to carry around classes which are empty. " |
88
|
|
|
"They must be removed from the source code!")} |
89
|
|
|
|
90
|
|
|
@utils.check_messages('remove-empty-class') |
91
|
|
|
def visit_classdef(self, node): |
92
|
|
|
if not node.body: |
93
|
|
|
self.add_message('remove-empty-class', node=node) |
94
|
|
|
|
95
|
|
|
for child in node.body: |
96
|
|
|
if isinstance(child, astroid.Pass): |
97
|
|
|
self.add_message('remove-empty-class', node=node) |
98
|
|
|
|