Refactor imports and improve logging in multiple modules; streamline type hints and remove redundant code

This commit is contained in:
William Valentin
2025-07-28 12:37:43 -07:00
parent 8e03f105b0
commit 8a0b4fcdf2
7 changed files with 71 additions and 78 deletions
+1
View File
@@ -1,4 +1,5 @@
import os import os
from dotenv import load_dotenv from dotenv import load_dotenv
load_dotenv(override=True) load_dotenv(override=True)
+5 -11
View File
@@ -1,7 +1,6 @@
import os
import csv import csv
import logging import logging
from typing import List, Union import os
import pandas as pd import pandas as pd
@@ -36,13 +35,8 @@ class DataManager:
def load_data(self) -> pd.DataFrame: def load_data(self) -> pd.DataFrame:
"""Load data from CSV file.""" """Load data from CSV file."""
if ( if not os.path.exists(self.filename) or os.path.getsize(self.filename) == 0:
not os.path.exists(self.filename) self.logger.warning("CSV file is empty or doesn't exist. No data to load.")
or os.path.getsize(self.filename) == 0
):
self.logger.warning(
"CSV file is empty or doesn't exist. No data to load."
)
return pd.DataFrame() return pd.DataFrame()
try: try:
@@ -69,7 +63,7 @@ class DataManager:
self.logger.error(f"Error loading data: {str(e)}") self.logger.error(f"Error loading data: {str(e)}")
return pd.DataFrame() return pd.DataFrame()
def add_entry(self, entry_data: List[Union[str, int]]) -> bool: def add_entry(self, entry_data: list[str | int]) -> bool:
"""Add a new entry to the CSV file.""" """Add a new entry to the CSV file."""
try: try:
with open(self.filename, mode="a", newline="") as file: with open(self.filename, mode="a", newline="") as file:
@@ -80,7 +74,7 @@ class DataManager:
self.logger.error(f"Error adding entry: {str(e)}") self.logger.error(f"Error adding entry: {str(e)}")
return False return False
def update_entry(self, date: str, values: List[Union[str, int]]) -> bool: def update_entry(self, date: str, values: list[str | int]) -> bool:
"""Update an existing entry identified by date.""" """Update an existing entry identified by date."""
try: try:
df: pd.DataFrame = self.load_data() df: pd.DataFrame = self.load_data()
+8 -8
View File
@@ -1,11 +1,11 @@
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.axes import Axes
from tkinter import ttk
import tkinter as tk import tkinter as tk
from typing import Dict from tkinter import ttk
import matplotlib.figure
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib.axes import Axes
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
class GraphManager: class GraphManager:
@@ -19,7 +19,7 @@ class GraphManager:
self.parent_frame.grid_columnconfigure(0, weight=1) self.parent_frame.grid_columnconfigure(0, weight=1)
# Initialize toggle variables for chart elements # Initialize toggle variables for chart elements
self.toggle_vars: Dict[str, tk.BooleanVar] = { self.toggle_vars: dict[str, tk.BooleanVar] = {
"depression": tk.BooleanVar(value=True), "depression": tk.BooleanVar(value=True),
"anxiety": tk.BooleanVar(value=True), "anxiety": tk.BooleanVar(value=True),
"sleep": tk.BooleanVar(value=True), "sleep": tk.BooleanVar(value=True),
+2 -1
View File
@@ -1,6 +1,7 @@
import os import os
from constants import LOG_CLEAR, LOG_LEVEL, LOG_PATH
from logger import init_logger from logger import init_logger
from constants import LOG_PATH, LOG_CLEAR, LOG_LEVEL
if not os.path.exists(LOG_PATH): if not os.path.exists(LOG_PATH):
try: try:
+4 -8
View File
@@ -1,20 +1,16 @@
import logging import logging
import colorlog import colorlog
from constants import LOG_PATH from constants import LOG_PATH
def init_logger(dunder_name, testing_mode) -> logging.Logger: def init_logger(dunder_name, testing_mode) -> logging.Logger:
log_format = ( log_format = "%(asctime)s - %(name)s - %(funcName)s - %(levelname)s - %(message)s"
"%(asctime)s - "
"%(name)s - "
"%(funcName)s - "
"%(levelname)s - "
"%(message)s"
)
""" Initialize logging """ """ Initialize logging """
bold_seq = "\033[1m" bold_seq = "\033[1m"
colorlog_format = f"{bold_seq} " "%(log_color)s " f"{log_format}" colorlog_format = f"{bold_seq} %(log_color)s {log_format}"
colorlog.basicConfig(format=colorlog_format) colorlog.basicConfig(format=colorlog_format)
logger = logging.getLogger(dunder_name) logger = logging.getLogger(dunder_name)
+14 -12
View File
@@ -1,15 +1,16 @@
import os import os
import sys import sys
import tkinter as tk import tkinter as tk
from collections.abc import Callable
from tkinter import messagebox from tkinter import messagebox
from typing import Dict, List, Tuple, Any, Callable, Union from typing import Any
import pandas as pd import pandas as pd
from init import logger
from constants import LOG_LEVEL, LOG_PATH from constants import LOG_LEVEL, LOG_PATH
from data_manager import DataManager from data_manager import DataManager
from graph_manager import GraphManager from graph_manager import GraphManager
from init import logger
from ui_manager import UIManager from ui_manager import UIManager
@@ -31,7 +32,8 @@ class MedTrackerApp:
logger.info(f"Using data file: {first_argument}") logger.info(f"Using data file: {first_argument}")
else: else:
logger.warning( logger.warning(
f"Data file {first_argument} does not exist. Using default file: {self.filename}" f"Data file {first_argument} doesn't exist. \
Using default file: {self.filename}"
) )
if LOG_LEVEL == "DEBUG": if LOG_LEVEL == "DEBUG":
@@ -75,10 +77,10 @@ class MedTrackerApp:
self.graph_manager: GraphManager = GraphManager(graph_frame) self.graph_manager: GraphManager = GraphManager(graph_frame)
# --- Create Input Frame --- # --- Create Input Frame ---
input_ui: Dict[str, Any] = self.ui_manager.create_input_frame(main_frame) input_ui: dict[str, Any] = self.ui_manager.create_input_frame(main_frame)
self.input_frame: ttk.Frame = input_ui["frame"] self.input_frame: ttk.Frame = input_ui["frame"]
self.symptom_vars: Dict[str, tk.IntVar] = input_ui["symptom_vars"] self.symptom_vars: dict[str, tk.IntVar] = input_ui["symptom_vars"]
self.medicine_vars: Dict[str, List[Union[tk.IntVar, ttk.Spinbox]]] = input_ui[ self.medicine_vars: dict[str, list[tk.IntVar | ttk.Spinbox]] = input_ui[
"medicine_vars" "medicine_vars"
] ]
self.note_var: tk.StringVar = input_ui["note_var"] self.note_var: tk.StringVar = input_ui["note_var"]
@@ -99,7 +101,7 @@ class MedTrackerApp:
) )
# --- Create Table Frame --- # --- Create Table Frame ---
table_ui: Dict[str, Any] = self.ui_manager.create_table_frame(main_frame) table_ui: dict[str, Any] = self.ui_manager.create_table_frame(main_frame)
self.tree: ttk.Treeview = table_ui["tree"] self.tree: ttk.Treeview = table_ui["tree"]
self.tree.bind("<Double-1>", self.on_double_click) self.tree.bind("<Double-1>", self.on_double_click)
@@ -115,10 +117,10 @@ class MedTrackerApp:
logger.debug(f"Editing item_id={item_id}, values={item_values}") logger.debug(f"Editing item_id={item_id}, values={item_values}")
self._create_edit_window(item_id, item_values) self._create_edit_window(item_id, item_values)
def _create_edit_window(self, item_id: str, values: Tuple[str, ...]) -> None: def _create_edit_window(self, item_id: str, values: tuple[str, ...]) -> None:
"""Create a new Toplevel window for editing an entry.""" """Create a new Toplevel window for editing an entry."""
# Define callbacks for edit window buttons # Define callbacks for edit window buttons
callbacks: Dict[str, Callable] = { callbacks: dict[str, Callable] = {
"save": self._save_edit, "save": self._save_edit,
"delete": lambda win: self._delete_entry(win, item_id), "delete": lambda win: self._delete_entry(win, item_id),
} }
@@ -141,7 +143,7 @@ class MedTrackerApp:
note: str, note: str,
) -> None: ) -> None:
"""Save the edited data to the CSV file.""" """Save the edited data to the CSV file."""
values: List[Union[str, int]] = [ values: list[str | int] = [
date, date,
dep, dep,
anx, anx,
@@ -173,7 +175,7 @@ class MedTrackerApp:
def add_entry(self) -> None: def add_entry(self) -> None:
"""Add a new entry to the CSV file.""" """Add a new entry to the CSV file."""
entry: List[Union[str, int]] = [ entry: list[str | int] = [
self.date_var.get(), self.date_var.get(),
self.symptom_vars["depression"].get(), self.symptom_vars["depression"].get(),
self.symptom_vars["anxiety"].get(), self.symptom_vars["anxiety"].get(),
@@ -240,7 +242,7 @@ class MedTrackerApp:
# Update the treeview with the data # Update the treeview with the data
if not df.empty: if not df.empty:
for index, row in df.iterrows(): for _index, row in df.iterrows():
self.tree.insert(parent="", index="end", values=list(row)) self.tree.insert(parent="", index="end", values=list(row))
logger.debug(f"Loaded {len(df)} entries into treeview.") logger.debug(f"Loaded {len(df)} entries into treeview.")
+37 -38
View File
@@ -1,10 +1,12 @@
from datetime import datetime
import os
import logging import logging
import os
import sys import sys
import tkinter as tk import tkinter as tk
from collections.abc import Callable
from datetime import datetime
from tkinter import ttk from tkinter import ttk
from typing import Dict, List, Tuple, Any, Callable, Union from typing import Any
from PIL import Image, ImageTk from PIL import Image, ImageTk
@@ -20,22 +22,19 @@ class UIManager:
try: try:
self.logger.info(f"Trying to load icon from: {img_path}") self.logger.info(f"Trying to load icon from: {img_path}")
# Try to find the icon in various locations # Try to find the icon in various locations
if not os.path.exists(img_path): # Check if we're in PyInstaller bundle
# Check if we're in PyInstaller bundle if not os.path.exists(img_path) and hasattr(sys, "_MEIPASS"):
if hasattr(sys, "_MEIPASS"): # PyInstaller creates a temp folder and stores path in _MEIPASS
# PyInstaller creates a temp folder and stores path in _MEIPASS base_path: str = sys._MEIPASS
base_path: str = sys._MEIPASS potential_paths: list[str] = [
potential_paths: List[str] = [ os.path.join(base_path, os.path.basename(img_path)),
os.path.join(base_path, os.path.basename(img_path)), os.path.join(base_path, "chart-671.png"),
os.path.join(base_path, "chart-671.png"), ]
] for path in potential_paths:
for path in potential_paths: if os.path.exists(path):
if os.path.exists(path): self.logger.info(f"Found icon in PyInstaller bundle: {path}")
self.logger.info( img_path = path
f"Found icon in PyInstaller bundle: {path}" break
)
img_path = path
break
icon_image: Image.Image = Image.open(img_path) icon_image: Image.Image = Image.open(img_path)
icon_image = icon_image.resize( icon_image = icon_image.resize(
@@ -52,14 +51,14 @@ class UIManager:
self.logger.error(f"Error setting icon: {str(e)}") self.logger.error(f"Error setting icon: {str(e)}")
return False return False
def create_input_frame(self, parent_frame: ttk.Frame) -> Dict[str, Any]: def create_input_frame(self, parent_frame: ttk.Frame) -> dict[str, Any]:
"""Create and configure the input frame with all widgets.""" """Create and configure the input frame with all widgets."""
input_frame: ttk.LabelFrame = ttk.LabelFrame(parent_frame, text="New Entry") input_frame: ttk.LabelFrame = ttk.LabelFrame(parent_frame, text="New Entry")
input_frame.grid(row=1, column=0, padx=10, pady=10, sticky="nsew") input_frame.grid(row=1, column=0, padx=10, pady=10, sticky="nsew")
input_frame.grid_columnconfigure(1, weight=1) input_frame.grid_columnconfigure(1, weight=1)
# Create variables for symptoms # Create variables for symptoms
symptom_vars: Dict[str, tk.IntVar] = { symptom_vars: dict[str, tk.IntVar] = {
"depression": tk.IntVar(value=0), "depression": tk.IntVar(value=0),
"anxiety": tk.IntVar(value=0), "anxiety": tk.IntVar(value=0),
"sleep": tk.IntVar(value=0), "sleep": tk.IntVar(value=0),
@@ -67,7 +66,7 @@ class UIManager:
} }
# Create scales for symptoms # Create scales for symptoms
symptom_labels: List[Tuple[str, str]] = [ symptom_labels: list[tuple[str, str]] = [
("Depression (0-10):", "depression"), ("Depression (0-10):", "depression"),
("Anxiety (0-10):", "anxiety"), ("Anxiety (0-10):", "anxiety"),
("Sleep Quality (0-10):", "sleep"), ("Sleep Quality (0-10):", "sleep"),
@@ -93,14 +92,14 @@ class UIManager:
medicine_frame = ttk.LabelFrame(input_frame, text="Medicine") medicine_frame = ttk.LabelFrame(input_frame, text="Medicine")
medicine_frame.grid(row=4, column=1, padx=0, pady=10, sticky="nsew") medicine_frame.grid(row=4, column=1, padx=0, pady=10, sticky="nsew")
medicine_vars: Dict[str, Tuple[tk.IntVar, str]] = { medicine_vars: dict[str, tuple[tk.IntVar, str]] = {
"bupropion": (tk.IntVar(value=0), "Bupropion 150/300 mg"), "bupropion": (tk.IntVar(value=0), "Bupropion 150/300 mg"),
"hydroxyzine": (tk.IntVar(value=0), "Hydroxyzine 25mg"), "hydroxyzine": (tk.IntVar(value=0), "Hydroxyzine 25mg"),
"gabapentin": (tk.IntVar(value=0), "Gabapentin 100mg"), "gabapentin": (tk.IntVar(value=0), "Gabapentin 100mg"),
"propranolol": (tk.IntVar(value=0), "Propranolol 10mg"), "propranolol": (tk.IntVar(value=0), "Propranolol 10mg"),
} }
for idx, (name, (var, text)) in enumerate(medicine_vars.items()): for idx, (_name, (var, text)) in enumerate(medicine_vars.items()):
ttk.Checkbutton(medicine_frame, text=text, variable=var).grid( ttk.Checkbutton(medicine_frame, text=text, variable=var).grid(
row=idx, column=0, sticky="w", padx=5, pady=2 row=idx, column=0, sticky="w", padx=5, pady=2
) )
@@ -135,7 +134,7 @@ class UIManager:
"date_var": date_var, "date_var": date_var,
} }
def create_table_frame(self, parent_frame: ttk.Frame) -> Dict[str, Any]: def create_table_frame(self, parent_frame: ttk.Frame) -> dict[str, Any]:
"""Create and configure the table frame with a treeview.""" """Create and configure the table frame with a treeview."""
table_frame: ttk.LabelFrame = ttk.LabelFrame( table_frame: ttk.LabelFrame = ttk.LabelFrame(
parent_frame, text="Log (Double-click to edit)" parent_frame, text="Log (Double-click to edit)"
@@ -146,7 +145,7 @@ class UIManager:
table_frame.grid_rowconfigure(0, weight=1) table_frame.grid_rowconfigure(0, weight=1)
table_frame.grid_columnconfigure(0, weight=1) table_frame.grid_columnconfigure(0, weight=1)
columns: List[str] = [ columns: list[str] = [
"Date", "Date",
"Depression", "Depression",
"Anxiety", "Anxiety",
@@ -161,7 +160,7 @@ class UIManager:
tree: ttk.Treeview = ttk.Treeview(table_frame, columns=columns, show="headings") tree: ttk.Treeview = ttk.Treeview(table_frame, columns=columns, show="headings")
col_labels: List[str] = [ col_labels: list[str] = [
"Date", "Date",
"Depression", "Depression",
"Anxiety", "Anxiety",
@@ -174,10 +173,10 @@ class UIManager:
"Note", "Note",
] ]
for col, label in zip(columns, col_labels): for col, label in zip(columns, col_labels, strict=False):
tree.heading(col, text=label) tree.heading(col, text=label)
col_settings: List[Tuple[str, int, str]] = [ col_settings: list[tuple[str, int, str]] = [
("Date", 80, "center"), ("Date", 80, "center"),
("Depression", 80, "center"), ("Depression", 80, "center"),
("Anxiety", 80, "center"), ("Anxiety", 80, "center"),
@@ -209,7 +208,7 @@ class UIManager:
return graph_frame return graph_frame
def add_buttons( def add_buttons(
self, frame: ttk.Frame, buttons_config: List[Dict[str, Any]] self, frame: ttk.Frame, buttons_config: list[dict[str, Any]]
) -> ttk.Frame: ) -> ttk.Frame:
"""Add buttons to a frame based on configuration.""" """Add buttons to a frame based on configuration."""
button_frame: ttk.Frame = ttk.Frame(frame) button_frame: ttk.Frame = ttk.Frame(frame)
@@ -230,7 +229,7 @@ class UIManager:
return button_frame return button_frame
def create_edit_window( def create_edit_window(
self, values: Tuple[str, ...], callbacks: Dict[str, Callable] self, values: tuple[str, ...], callbacks: dict[str, Callable]
) -> tk.Toplevel: ) -> tk.Toplevel:
"""Create a new window for editing an entry.""" """Create a new window for editing an entry."""
edit_win: tk.Toplevel = tk.Toplevel(master=self.root) edit_win: tk.Toplevel = tk.Toplevel(master=self.root)
@@ -283,9 +282,9 @@ class UIManager:
anx: int, anx: int,
slp: int, slp: int,
app: int, app: int,
) -> Dict[str, Union[tk.StringVar, tk.IntVar]]: ) -> dict[str, tk.StringVar | tk.IntVar]:
"""Create fields for editing entry values.""" """Create fields for editing entry values."""
vars_dict: Dict[str, Union[tk.StringVar, tk.IntVar]] = {} vars_dict: dict[str, tk.StringVar | tk.IntVar] = {}
# Ensure values are converted to appropriate types # Ensure values are converted to appropriate types
try: try:
@@ -377,7 +376,7 @@ class UIManager:
hydro: int, hydro: int,
gaba: int, gaba: int,
prop: int, prop: int,
) -> Dict[str, tk.IntVar]: ) -> dict[str, tk.IntVar]:
"""Create medicine checkboxes in the edit window.""" """Create medicine checkboxes in the edit window."""
ttk.Label(parent, text="Treatment:").grid( ttk.Label(parent, text="Treatment:").grid(
row=row, column=0, sticky="w", padx=5, pady=2 row=row, column=0, sticky="w", padx=5, pady=2
@@ -385,14 +384,14 @@ class UIManager:
medicine_frame: ttk.LabelFrame = ttk.LabelFrame(parent, text="Medicine") medicine_frame: ttk.LabelFrame = ttk.LabelFrame(parent, text="Medicine")
medicine_frame.grid(row=row, column=1, padx=0, pady=10, sticky="nsew") medicine_frame.grid(row=row, column=1, padx=0, pady=10, sticky="nsew")
medicine_vars: Dict[str, Tuple[int, str]] = { medicine_vars: dict[str, tuple[int, str]] = {
"bupropion": (bup, "Bupropion 150/300 mg"), "bupropion": (bup, "Bupropion 150/300 mg"),
"hydroxyzine": (hydro, "Hydroxyzine 25mg"), "hydroxyzine": (hydro, "Hydroxyzine 25mg"),
"gabapentin": (gaba, "Gabapentin 100mg"), "gabapentin": (gaba, "Gabapentin 100mg"),
"propranolol": (prop, "Propranolol 10mg"), "propranolol": (prop, "Propranolol 10mg"),
} }
vars_dict: Dict[str, tk.IntVar] = {} vars_dict: dict[str, tk.IntVar] = {}
for idx, (key, (value, label)) in enumerate(medicine_vars.items()): for idx, (key, (value, label)) in enumerate(medicine_vars.items()):
vars_dict[key] = tk.IntVar(value=int(value)) vars_dict[key] = tk.IntVar(value=int(value))
ttk.Checkbutton(medicine_frame, text=label, variable=vars_dict[key]).grid( ttk.Checkbutton(medicine_frame, text=label, variable=vars_dict[key]).grid(
@@ -405,8 +404,8 @@ class UIManager:
self, self,
parent: tk.Toplevel, parent: tk.Toplevel,
row: int, row: int,
vars_dict: Dict[str, Any], vars_dict: dict[str, Any],
callbacks: Dict[str, Callable], callbacks: dict[str, Callable],
) -> None: ) -> None:
"""Add buttons to the edit window.""" """Add buttons to the edit window."""
button_frame: ttk.Frame = ttk.Frame(parent) button_frame: ttk.Frame = ttk.Frame(parent)