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 20 21def parse_files_for_todo_items(project_parent_dir: str, files: List[str], ignore_todo_case: bool) -> Dict[str, List[TODO]]: 22 """Parses the list of `files` one by one to collect all todo items 23 24 Args: 25 project_parent_dir (str): Parent directory of the project folder (required to get relative path of files and avoid exposing temporary paths) 26 files (List[str]): List of all files that need to be parsed 27 ignore_todo_case (bool): Boolean whether to look for case insensitive todo items like todo, Todo etc. 28 29 Returns: 30 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 31 """ 32 all_todos_objs = {} 33 for file in files: 34 try: 35 rel_file_path = os.path.relpath(file, project_parent_dir) 36 all_todos_objs[rel_file_path] = [] 37 line_no_to_chars_map = compute_file_line_no_to_chars_map(file) 38 with open(file, "r") as f: 39 file_content = f.read() 40 41 flags = re.MULTILINE 42 if ignore_todo_case: 43 flags |= re.IGNORECASE 44 45 todo_items = re.finditer(r"TODO.*", file_content, flags=flags) 46 for todo_item_idx, todo_item in enumerate(todo_items): 47 try: 48 todo_item_group = todo_item.group() 49 todo_date_username = re.findall(r"TODO\s*(\{.*\})?\s*(@[^\s]*)?\s*(.*)?", todo_item_group, flags=flags) 50 51 if todo_date_username: 52 todo_date_username = todo_date_username[0] 53 54 msg = "" 55 if len(todo_date_username) > 2: 56 msg = todo_date_username[2] 57 58 user = USER(UNKNOWN_USER_NAME) # By default we assume an unknown user 59 if len(todo_date_username) > 1: 60 user = USER(todo_date_username[1][1:] or UNKNOWN_USER_NAME) # handle empty string 61 62 completion_date_str = "" 63 if len(todo_date_username) > 0: 64 completion_date_str = todo_date_username[0] 65 if completion_date_str: 66 completion_date_str = completion_date_str[1:-1] 67 68 module = rel_file_path 69 todo_position = todo_item.span() 70 71 line = compute_line_and_pos_given_span(line_no_to_chars_map, todo_position) 72 position = POSITION(line) 73 74 todo = TODO(msg, user, completion_date_str, module, position) 75 76 all_todos_objs[rel_file_path].append(todo) 77 except Exception: 78 logger.exception(f"Error in parsing todo item: {todo_item}, idx: {todo_item_idx}, all_todos: {all_todos_objs}") 79 except Exception: 80 logger.exception(f"Error in parsing todo items in file: {file}") 81 82 return all_todos_objs
logger =
<Logger todonotifier.todo_notifier (INFO)>
def
parse_files_for_todo_items( project_parent_dir: str, files: List[str], ignore_todo_case: bool) -> Dict[str, List[todonotifier.models.TODO]]:
22def parse_files_for_todo_items(project_parent_dir: str, files: List[str], ignore_todo_case: bool) -> Dict[str, List[TODO]]: 23 """Parses the list of `files` one by one to collect all todo items 24 25 Args: 26 project_parent_dir (str): Parent directory of the project folder (required to get relative path of files and avoid exposing temporary paths) 27 files (List[str]): List of all files that need to be parsed 28 ignore_todo_case (bool): Boolean whether to look for case insensitive todo items like todo, Todo etc. 29 30 Returns: 31 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 32 """ 33 all_todos_objs = {} 34 for file in files: 35 try: 36 rel_file_path = os.path.relpath(file, project_parent_dir) 37 all_todos_objs[rel_file_path] = [] 38 line_no_to_chars_map = compute_file_line_no_to_chars_map(file) 39 with open(file, "r") as f: 40 file_content = f.read() 41 42 flags = re.MULTILINE 43 if ignore_todo_case: 44 flags |= re.IGNORECASE 45 46 todo_items = re.finditer(r"TODO.*", file_content, flags=flags) 47 for todo_item_idx, todo_item in enumerate(todo_items): 48 try: 49 todo_item_group = todo_item.group() 50 todo_date_username = re.findall(r"TODO\s*(\{.*\})?\s*(@[^\s]*)?\s*(.*)?", todo_item_group, flags=flags) 51 52 if todo_date_username: 53 todo_date_username = todo_date_username[0] 54 55 msg = "" 56 if len(todo_date_username) > 2: 57 msg = todo_date_username[2] 58 59 user = USER(UNKNOWN_USER_NAME) # By default we assume an unknown user 60 if len(todo_date_username) > 1: 61 user = USER(todo_date_username[1][1:] or UNKNOWN_USER_NAME) # handle empty string 62 63 completion_date_str = "" 64 if len(todo_date_username) > 0: 65 completion_date_str = todo_date_username[0] 66 if completion_date_str: 67 completion_date_str = completion_date_str[1:-1] 68 69 module = rel_file_path 70 todo_position = todo_item.span() 71 72 line = compute_line_and_pos_given_span(line_no_to_chars_map, todo_position) 73 position = POSITION(line) 74 75 todo = TODO(msg, user, completion_date_str, module, position) 76 77 all_todos_objs[rel_file_path].append(todo) 78 except Exception: 79 logger.exception(f"Error in parsing todo item: {todo_item}, idx: {todo_item_idx}, all_todos: {all_todos_objs}") 80 except Exception: 81 logger.exception(f"Error in parsing todo items in file: {file}") 82 83 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