22App Tracking logic class. Used for app tracking, filtering, and listing.
33"""
44
5- import threading
65import os
7- import psutil # type: ignore
86import sys
7+ import threading
98
10- if os .name == 'nt' :
9+ import psutil # type: ignore
10+
11+ if os .name == "nt" :
1112 from pywinauto import Desktop
1213 from pywinauto .findwindows import ElementNotFoundError
13- windows = Desktop (backend = "uia" ).windows ()
14- elif sys .platform == 'darwin' :
15- from AppKit import NSWorkspace # type: ignore
1614
17- from core .utils .file_utils import read_file , write_file , apps_file , user_dir_exists , config_file
15+ windows = Desktop (backend = "uia" ).windows ()
16+ elif sys .platform == "darwin" :
17+ from AppKit import NSWorkspace # type: ignore
1818
1919import logging
20+
21+ from core .utils .file_utils import (
22+ apps_file ,
23+ config_file ,
24+ read_file ,
25+ user_dir_exists ,
26+ write_file ,
27+ )
28+
2029logger = logging .getLogger (__name__ )
2130
2231EXCLUDED_APP_PIDS = []
2332INCLUDED_APP_PIDS = []
2433
2534if user_dir_exists () and os .path .exists (apps_file ()):
26- EXCLUDED_APP_PIDS = read_file (apps_file ())['excluded_app_pids' ]
27- INCLUDED_APP_PIDS = read_file (apps_file ())['included_app_pids' ]
35+ EXCLUDED_APP_PIDS = read_file (apps_file ())["excluded_app_pids" ]
36+ INCLUDED_APP_PIDS = read_file (apps_file ())["included_app_pids" ]
37+
2838
2939class AppTracker :
3040 def __init__ (self , parent , logic_controller ):
@@ -34,7 +44,7 @@ def __init__(self, parent, logic_controller):
3444 self .stop_event = threading .Event () # Used to stop the thread gracefully
3545 self .cached_process_count = 0 # Tracks the last known process count
3646 try :
37- self .is_filter_enabled = read_file (config_file ())[' is_filter_enabled' ]
47+ self .is_filter_enabled = read_file (config_file ())[" is_filter_enabled" ]
3848 except (KeyError , FileNotFoundError ):
3949 self .is_filter_enabled = True
4050
@@ -48,17 +58,19 @@ def __init__(self, parent, logic_controller):
4858
4959 def _start_tracking (self ):
5060 if self .update_thread is None :
51- self .update_thread = threading .Thread (target = self ._monitor_processes , name = "app_tracker" )
61+ self .update_thread = threading .Thread (
62+ target = self ._monitor_processes , name = "app_tracker"
63+ )
5264 self .update_thread .start ()
5365
5466 def _fetch_app_names (self ):
5567 apps = []
5668 seen_names = ["AppUsageGUI" , "Python" ]
5769
58- for process in psutil .process_iter ([' pid' , ' name' ]):
70+ for process in psutil .process_iter ([" pid" , " name" ]):
5971 try :
60- pid = process .info [' pid' ]
61- app_name = process .info [' name' ]
72+ pid = process .info [" pid" ]
73+ app_name = process .info [" name" ]
6274 app_name = app_name .split ("." )[0 ] # Use the base name of the process
6375 if (
6476 app_name not in seen_names
@@ -70,11 +82,11 @@ def _fetch_app_names(self):
7082 if app_name == self .selected_app :
7183 logger .debug (f"Seleced App found: { app_name } " )
7284 break
73- #print(app_name) # Debugging line to help optimize
85+ # print(app_name) # Debugging line to help optimize
7486 except (psutil .NoSuchProcess , psutil .AccessDenied , psutil .ZombieProcess ):
7587 # Skip processes that terminate mid-iteration or are inaccessible
7688 pass
77- if os .name == 'nt' :
89+ if os .name == "nt" :
7890 return sorted (apps , key = str .casefold )
7991 return sorted (apps )
8092
@@ -86,14 +98,16 @@ def _monitor_processes(self):
8698 # Process count has changed; update app names
8799 self .cached_process_count = current_process_count
88100 self .app_names = self ._fetch_app_names ()
89- self .stop_event .wait (timeout = 1 ) # Check periodically to avoid excessive CPU usage
101+ self .stop_event .wait (
102+ timeout = 1
103+ ) # Check periodically to avoid excessive CPU usage
90104
91105 def get_app_names (self ):
92106 return self .app_names
93107
94108 def get_selected_app (self ):
95109 return self .selected_app
96-
110+
97111 def set_selected_app (self , app ):
98112 self .selected_app = app
99113
@@ -113,10 +127,13 @@ def start(self):
113127 def reset (self ):
114128 self .selected_app = None
115129 self .update_thread = None
116-
130+
117131 def start_filter_reset (self , refresh = False , update_pids = False ):
118- if os .name == 'nt' :
119- self .temp_reset_thread = threading .Thread (target = self ._reset_excluded_pids (refresh , update_pids ), name = "reset_filter" )
132+ if os .name == "nt" :
133+ self .temp_reset_thread = threading .Thread (
134+ target = self ._reset_excluded_pids (refresh , update_pids ),
135+ name = "reset_filter" ,
136+ )
120137 self .temp_reset_thread .start ()
121138
122139 def _reset_excluded_pids (self , refresh , update_pids ):
@@ -136,34 +153,40 @@ def _update_excluded_apps(self):
136153 return
137154 seen_pids = []
138155 i = 0
139- for process in psutil .process_iter ([' pid' , ' status' ]):
156+ for process in psutil .process_iter ([" pid" , " status" ]):
140157 try :
141- pid = process .info [' pid' ]
158+ pid = process .info [" pid" ]
142159 if pid in seen_pids :
143160 continue
144- #print(f"Checking process: (PID: {pid})") # Debugging line
161+ # print(f"Checking process: (PID: {pid})") # Debugging line
145162 seen_pids .append (pid )
146- if process .info ['status' ] == psutil .STATUS_RUNNING and pid not in INCLUDED_APP_PIDS and pid not in EXCLUDED_APP_PIDS :
163+ if (
164+ process .info ["status" ] == psutil .STATUS_RUNNING
165+ and pid not in INCLUDED_APP_PIDS
166+ and pid not in EXCLUDED_APP_PIDS
167+ ):
147168 if self ._has_gui (pid ):
148169 INCLUDED_APP_PIDS .append (pid )
149170 else :
150171 i += 1
151172 EXCLUDED_APP_PIDS .append (pid )
152- if len (seen_pids ) > (400 if os .name == 'nt' else 10000 ):
173+ if len (seen_pids ) > (400 if os .name == "nt" else 10000 ):
153174 # Limit the number of seen processes to avoid long loading times
154175 break
155176 except (psutil .NoSuchProcess , psutil .AccessDenied , psutil .ZombieProcess ):
156177 # Skip processes that terminate mid-iteration or are inaccessible
157178 pass
158179
159- #print(f"\nExcluded app PIDs: {EXCLUDED_APP_PIDS}") # Debugging line
180+ # print(f"\nExcluded app PIDs: {EXCLUDED_APP_PIDS}") # Debugging line
160181 logger .info (f"New exlusions: { i } " )
161- data = {'excluded_app_pids' : EXCLUDED_APP_PIDS ,
162- 'included_app_pids' : INCLUDED_APP_PIDS }
182+ data = {
183+ "excluded_app_pids" : EXCLUDED_APP_PIDS ,
184+ "included_app_pids" : INCLUDED_APP_PIDS ,
185+ }
163186 write_file (apps_file (), data )
164187
165188 def _has_gui (self , process_id ):
166- if os .name == 'nt' :
189+ if os .name == "nt" :
167190 try :
168191 # Enumerate all top-level windows
169192 for win in windows :
@@ -173,8 +196,8 @@ def _has_gui(self, process_id):
173196 except (ElementNotFoundError , RuntimeError ):
174197 return True # Handle the case where the process is not found
175198 return False
176- elif sys .platform == ' darwin' :
177- #TODO: Implement a better GUI check for macOS
199+ elif sys .platform == " darwin" :
200+ # TODO: Implement a better GUI check for macOS
178201 try :
179202 apps = NSWorkspace .sharedWorkspace ().runningApplications ()
180203 for app in apps :
0 commit comments