» Make grep CLI App in Python » 2. Development » 2.4 Add Type Annotations

Add Type Annotations

Type annotations in Python are a way to indicate the expected types of variables, function parameters, and return values. They were introduced in PEP 484 and are commonly used in medium-size or large projects.

Changes in grepy/grep.py:

@@ -1,10 +1,13 @@
 import re
+from typing import List, Dict, Tuple, Union
 import os
 
-def _filter_lines(pattern, lines, flag):
+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, file_path, options=None):
+def grep(pattern: Union[str, re.Pattern], file_path: str, options: List[str]=[]):
     with open(file_path, 'r') as file:
         try:
             lines = file.readlines()
@@ -23,15 +26,13 @@ def grep(pattern, file_path, options=None):
 
     return {file_path: matching_lines}
 
-def grep_count(result):
+def grep_count(result: Dict[str, MatchResults]):
     return sum([len(v) for v in result.values()])
 
-def grep_recursive(pattern, directory_path, options=None):
+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:
             file_path = os.path.join(root, file)
             results.update(grep(pattern, file_path, options))
-
     return results

MatchResults is an alias of type List[Tuple[int, str]], which represents something like this:

[(22, 'result = grep_recursive(args.pattern, args.file_path, get_options(args))'), (24, 'result = grep(args.pattern, args.file_path, get_options(args))'), (27, 'print(grep_count(result))'), (29, 'print_result(result, args.line_number)'), (39, 'def print_result(result: Dict[str, MatchResults], line_number_option: bool):'), (41, 'file_count = len(result)'), (42, 'for file_path, lines in result.items():')]

Changes in grepy/grep.py:

 import argparse
+from typing import List, Dict
 
-from grepy.grep import grep, grep_recursive, grep_count
+from grepy.grep import grep, grep_recursive, grep_count, MatchResults
 
 def main():
     parser = argparse.ArgumentParser(description='''A grep-like command-line utility from LiteRank, 
@@ -27,7 +28,7 @@ def main():
     else:
         print_result(result, args.line_number)
 
-def get_options(args):
+def get_options(args: argparse.Namespace) -> List[str]:
     options = []
     if args.ignore_case:
         options.append('i')
@@ -35,10 +36,11 @@ def get_options(args):
         options.append('v')
     return options
 
-def print_result(result, line_number_option):
+def print_result(result: Dict[str, MatchResults], line_number_option: bool):
     current_file = None
     file_count = len(result)
     for file_path, lines in result.items():
         for (line_number, line) in lines:
             if file_count > 1 and file_path != current_file:
                 current_file = file_path
PrevNext