» Python创建命令行程序grep » 2. 开发 » 2.6 添加 Lint

添加 Lint

Lint 是分析源代码并查找、报告出有关编程风格、潜在错误和编码标准等问题的工具。术语 "lint" 源自一个名为 "lint" 的 Unix 实用工具,它用于识别 C 代码中的错误和缺陷。

在 Python 项目中使用 linting 工具是一种最佳实践,它有助于保证代码质量并保持代码一致性。Python 中比较流行的两个 linting 工具是 flake8pylint。在本项目中,我们将使用 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()
上页下页