添加 Lint
Lint 是分析源代码并查找、报告出有关编程风格、潜在错误和编码标准等问题的工具。术语 "lint" 源自一个名为 "lint" 的 Unix 实用工具,它用于识别 C 代码中的错误和缺陷。
在 Python 项目中使用 linting 工具是一种最佳实践,它有助于保证代码质量并保持代码一致性。Python 中比较流行的两个 linting 工具是 flake8
和 pylint
。在本项目中,我们将使用 flake8
。
如下命令安装:
pip install flake8 # Or pip3 install flake8
项目根目录中创建 .flake8
空文件。
执行如下命令:
flake8
得到问题列表:
./grepy/grep.py:7:1: E302 expected 2 blank lines, found 1
./grepy/grep.py:7:80: E501 line too long (97 > 79 characters)
./grepy/grep.py:8:80: E501 line too long (133 > 79 characters)
./grepy/grep.py:10:1: E302 expected 2 blank lines, found 1
./grepy/grep.py:10:77: E252 missing whitespace around parameter equals
./grepy/grep.py:10:78: E252 missing whitespace around parameter equals
./grepy/grep.py:10:80: E501 line too long (81 > 79 characters)
./grepy/grep.py:14:35: E261 at least two spaces before inline comment
./grepy/grep.py:29:1: E302 expected 2 blank lines, found 1
./grepy/grep.py:32:1: E302 expected 2 blank lines, found 1
./grepy/grep.py:32:80: E501 line too long (96 > 79 characters)
./grepy/grep.py:32:92: E252 missing whitespace around parameter equals
./grepy/grep.py:32:93: E252 missing whitespace around parameter equals
./grepy_cli.py:6:1: E302 expected 2 blank lines, found 1
./grepy_cli.py:7:80: E501 line too long (99 > 79 characters)
./grepy_cli.py:7:100: W291 trailing whitespace
./grepy_cli.py:8:80: E501 line too long (82 > 79 characters)
./grepy_cli.py:10:80: E501 line too long (88 > 79 characters)
./grepy_cli.py:13:80: E501 line too long (131 > 79 characters)
./grepy_cli.py:14:80: E501 line too long (144 > 79 characters)
./grepy_cli.py:15:80: E501 line too long (208 > 79 characters)
./grepy_cli.py:16:80: E501 line too long (115 > 79 characters)
./grepy_cli.py:17:80: E501 line too long (145 > 79 characters)
./grepy_cli.py:22:80: E501 line too long (80 > 79 characters)
./grepy_cli.py:31:1: E302 expected 2 blank lines, found 1
./grepy_cli.py:39:1: E302 expected 2 blank lines, found 1
./grepy_cli.py:52:1: E305 expected 2 blank lines after class or function definition, found 1
./tests/test_grep.py:8:1: E302 expected 2 blank lines, found 1
./tests/test_grep.py:57:80: E501 line too long (86 > 79 characters)
./tests/test_grep.py:66:1: E305 expected 2 blank lines after class or function definition, found 1
尝试修复如上问题并再次执行 flake8
。
flake8
如果没有新的问题蹦出来,那么表明你的代码处于“良好”状态。
grepy/grep.py 的更改:
@@ -4,14 +4,22 @@ import os
MatchResults = List[Tuple[int, str]]
-def _filter_lines(pattern: Union[str, re.Pattern], lines: List[str], flag: bool) -> MatchResults:
- return [(line_number, line.strip()) for line_number, line in enumerate(lines, start=1) if bool(re.search(pattern, line)) == flag]
-def grep(pattern: Union[str, re.Pattern], file_path: str, options: List[str]=[]):
+def _filter_lines(pattern: Union[str, re.Pattern],
+ lines: List[str], flag: bool) -> MatchResults:
+ return [
+ (line_number, line.strip())
+ for line_number, line in enumerate(lines, start=1)
+ if bool(re.search(pattern, line)) == flag
+ ]
+
+
+def grep(pattern: Union[str, re.Pattern],
+ file_path: str, options: List[str] = []):
with open(file_path, 'r') as file:
try:
lines = file.readlines()
- except UnicodeDecodeError: # filter out binary files
+ except UnicodeDecodeError: # filter out binary files
return {file_path: []}
if options:
@@ -26,10 +34,13 @@ def grep(pattern: Union[str, re.Pattern], file_path: str, options: List[str]=[])
return {file_path: matching_lines}
+
def grep_count(result: Dict[str, MatchResults]):
return sum([len(v) for v in result.values()])
-def grep_recursive(pattern: Union[str, re.Pattern], directory_path: str, options: List[str]=[]):
+
+def grep_recursive(pattern: Union[str, re.Pattern],
+ directory_path: str, options: List[str] = []):
results = {}
for root, _, files in os.walk(directory_path):
for file in files:
grepy_cli.py 的更改:
@@ -3,23 +3,37 @@ from typing import List, Dict
from grepy.grep import grep, grep_recursive, grep_count, MatchResults
+
def main():
- parser = argparse.ArgumentParser(description='''A grep-like command-line utility from LiteRank,
- see https://literank.com/tutorial/9/intro''')
+ parser = argparse.ArgumentParser(description='''
+ A grep-like command-line utility from LiteRank,
+ see https://literank.com/tutorial/9/intro''')
parser.add_argument('pattern', type=str, help='The pattern to search for')
- parser.add_argument('file_path', type=str, help='The path to the file to search in')
+ parser.add_argument('file_path', type=str,
+ help='The path to the file to search in')
# Optional arguments
- parser.add_argument('-c', '--count', action='store_true', help='Only a count of selected lines is written to standard output.')
- parser.add_argument('-i', '--ignore-case', action='store_true', help='Perform case insensitive matching. By default, it is case sensitive.')
- parser.add_argument('-n', '--line-number', action='store_true', help='Each output line is preceded by its relative line number in the file, starting at line 1. This option is ignored if -c is specified.')
- parser.add_argument('-r', '--recursive', action='store_true', help='Recursively search subdirectories listed.')
- parser.add_argument('-v', '--invert-match', action='store_true', help='Selected lines are those not matching any of the specified patterns.')
+ parser.add_argument('-c', '--count', action='store_true',
+ help='Only a count of selected lines is written to \
+ standard output.')
+ parser.add_argument('-i', '--ignore-case', action='store_true',
+ help='Perform case insensitive matching. By default, \
+ it is case sensitive.')
+ parser.add_argument('-n', '--line-number', action='store_true',
+ help='Each output line is preceded by its relative \
+ line number in the file, starting at line 1. This \
+ option is ignored if -c is specified.')
+ parser.add_argument('-r', '--recursive', action='store_true',
+ help='Recursively search subdirectories listed.')
+ parser.add_argument('-v', '--invert-match', action='store_true',
+ help='Selected lines are those not matching any of \
+ the specified patterns.')
args = parser.parse_args()
if args.recursive:
- result = grep_recursive(args.pattern, args.file_path, get_options(args))
+ result = grep_recursive(args.pattern,
+ args.file_path, get_options(args))
else:
result = grep(args.pattern, args.file_path, get_options(args))
@@ -28,6 +42,7 @@ def main():
else:
print_result(result, args.line_number)
+
def get_options(args: argparse.Namespace) -> List[str]:
options = []
if args.ignore_case:
@@ -36,6 +51,7 @@ def get_options(args: argparse.Namespace) -> List[str]:
options.append('v')
return options
+
def print_result(result: Dict[str, MatchResults], line_number_option: bool):
current_file = None
file_count = len(result)
@@ -49,5 +65,6 @@ def print_result(result: Dict[str, MatchResults], line_number_option: bool):
else:
print(line)
+
if __name__ == '__main__':
main()