todonotifier.todo_notifier
This module contains the core logic of the application
1"""This module contains the core logic of the application 2""" 3 4import logging 5import os 6import re 7from typing import Dict, List 8 9from todonotifier.constants import UNKNOWN_USER_NAME 10from todonotifier.models import POSITION, TODO, USER 11from todonotifier.utils import ( 12 compute_file_line_no_to_chars_map, 13 compute_line_and_pos_given_span, 14) 15 16# logging configuration 17logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(process)d - %(name)s - %(levelname)s - %(message)s") 18logger = logging.getLogger(__name__) 19 20TODO_REGEX_PATTERN = r"TODO\s*(\{.*\})?\s*(@[^\s]*)?\s*(.*)?" 21 22 23def parse_files_for_todo_items(project_parent_dir: str, files: List[str], ignore_todo_case: bool) -> Dict[str, List[TODO]]: 24 """Parses the list of `files` one by one to collect all todo items 25 26 Args: 27 project_parent_dir (str): Parent directory of the project folder (required to get relative path of files and avoid exposing temporary paths) 28 files (List[str]): List of all files that need to be parsed 29 ignore_todo_case (bool): Boolean whether to look for case insensitive todo items like todo, Todo etc. 30 31 Returns: 32 Dict[str, List[TODO]]: Returns a key-value pair where key is relative path of file parsed and value is list of todo objects in that file 33 """ 34 all_todos_objs = {} 35 for file in files: 36 try: 37 rel_file_path = os.path.relpath(file, project_parent_dir) 38 all_todos_objs[rel_file_path] = [] 39 line_no_to_chars_map = compute_file_line_no_to_chars_map(file) 40 with open(file, "r") as f: 41 file_content = f.read() 42 43 flags = re.MULTILINE 44 if ignore_todo_case: 45 flags |= re.IGNORECASE 46 47 todo_items = re.finditer(r"TODO.*", file_content, flags=flags) 48 for todo_item_idx, todo_item in enumerate(todo_items): 49 try: 50 todo_item_group = todo_item.group() 51 todo_date_username = re.findall(TODO_REGEX_PATTERN, todo_item_group, flags=flags) 52 53 if todo_date_username: 54 todo_date_username = todo_date_username[0] 55 56 msg = "" 57 if len(todo_date_username) > 2: 58 msg = todo_date_username[2] 59 60 user = USER(UNKNOWN_USER_NAME) # By default we assume an unknown user 61 if len(todo_date_username) > 1: 62 user = USER(todo_date_username[1][1:] or UNKNOWN_USER_NAME) # handle empty string 63 64 completion_date_str = "" 65 if len(todo_date_username) > 0: 66 completion_date_str = todo_date_username[0] 67 if completion_date_str: 68 completion_date_str = completion_date_str[1:-1] 69 70 module = rel_file_path 71 todo_position = todo_item.span() 72 73 line = compute_line_and_pos_given_span(line_no_to_chars_map, todo_position) 74 position = POSITION(line) 75 76 todo = TODO(msg, user, completion_date_str, module, position) 77 78 all_todos_objs[rel_file_path].append(todo) 79 except Exception: 80 logger.exception(f"Error in parsing todo item: {todo_item}, idx: {todo_item_idx}, all_todos: {all_todos_objs}") 81 except Exception: 82 logger.exception(f"Error in parsing todo items in file: {file}") 83 84 return all_todos_objs
logger =
<Logger todonotifier.todo_notifier (INFO)>
TODO_REGEX_PATTERN =
'TODO\\s*(\\{.*\\})?\\s*(@[^\\s]*)?\\s*(.*)?'
def
parse_files_for_todo_items( project_parent_dir: str, files: List[str], ignore_todo_case: bool) -> Dict[str, List[todonotifier.models.TODO]]:
24def parse_files_for_todo_items(project_parent_dir: str, files: List[str], ignore_todo_case: bool) -> Dict[str, List[TODO]]: 25 """Parses the list of `files` one by one to collect all todo items 26 27 Args: 28 project_parent_dir (str): Parent directory of the project folder (required to get relative path of files and avoid exposing temporary paths) 29 files (List[str]): List of all files that need to be parsed 30 ignore_todo_case (bool): Boolean whether to look for case insensitive todo items like todo, Todo etc. 31 32 Returns: 33 Dict[str, List[TODO]]: Returns a key-value pair where key is relative path of file parsed and value is list of todo objects in that file 34 """ 35 all_todos_objs = {} 36 for file in files: 37 try: 38 rel_file_path = os.path.relpath(file, project_parent_dir) 39 all_todos_objs[rel_file_path] = [] 40 line_no_to_chars_map = compute_file_line_no_to_chars_map(file) 41 with open(file, "r") as f: 42 file_content = f.read() 43 44 flags = re.MULTILINE 45 if ignore_todo_case: 46 flags |= re.IGNORECASE 47 48 todo_items = re.finditer(r"TODO.*", file_content, flags=flags) 49 for todo_item_idx, todo_item in enumerate(todo_items): 50 try: 51 todo_item_group = todo_item.group() 52 todo_date_username = re.findall(TODO_REGEX_PATTERN, todo_item_group, flags=flags) 53 54 if todo_date_username: 55 todo_date_username = todo_date_username[0] 56 57 msg = "" 58 if len(todo_date_username) > 2: 59 msg = todo_date_username[2] 60 61 user = USER(UNKNOWN_USER_NAME) # By default we assume an unknown user 62 if len(todo_date_username) > 1: 63 user = USER(todo_date_username[1][1:] or UNKNOWN_USER_NAME) # handle empty string 64 65 completion_date_str = "" 66 if len(todo_date_username) > 0: 67 completion_date_str = todo_date_username[0] 68 if completion_date_str: 69 completion_date_str = completion_date_str[1:-1] 70 71 module = rel_file_path 72 todo_position = todo_item.span() 73 74 line = compute_line_and_pos_given_span(line_no_to_chars_map, todo_position) 75 position = POSITION(line) 76 77 todo = TODO(msg, user, completion_date_str, module, position) 78 79 all_todos_objs[rel_file_path].append(todo) 80 except Exception: 81 logger.exception(f"Error in parsing todo item: {todo_item}, idx: {todo_item_idx}, all_todos: {all_todos_objs}") 82 except Exception: 83 logger.exception(f"Error in parsing todo items in file: {file}") 84 85 return all_todos_objs
Parses the list of files
one by one to collect all todo items
Arguments:
- project_parent_dir (str): Parent directory of the project folder (required to get relative path of files and avoid exposing temporary paths)
- files (List[str]): List of all files that need to be parsed
- ignore_todo_case (bool): Boolean whether to look for case insensitive todo items like todo, Todo etc.
Returns:
Dict[str, List[TODO]]: Returns a key-value pair where key is relative path of file parsed and value is list of todo objects in that file