Skip to content

Commit 07bba09

Browse files
CopilotMte90
andcommitted
Fix code review issues: add constants, improve change detection, avoid circular imports
Co-authored-by: Mte90 <403283+Mte90@users.noreply.github.com>
1 parent c5a7792 commit 07bba09

File tree

5 files changed

+63
-24
lines changed

5 files changed

+63
-24
lines changed

endpoints/project_endpoints.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ def api_create_project(request: CreateProjectRequest):
4848

4949
# Add project to file watcher if available
5050
try:
51-
from main import _file_watcher
52-
if _file_watcher and _file_watcher.is_running():
53-
_file_watcher.add_project(project["id"], project["path"])
51+
from utils.app_state import get_file_watcher
52+
watcher = get_file_watcher()
53+
if watcher and watcher.is_running():
54+
watcher.add_project(project["id"], project["path"])
5455
except Exception as e:
5556
logger.warning(f"Could not add project to file watcher: {e}")
5657

endpoints/web_endpoints.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def api_health():
4040
- Monitoring systems
4141
- Service availability verification
4242
"""
43-
from main import _file_watcher
43+
from utils.app_state import get_file_watcher
4444

4545
health_data = {
4646
"status": "ok",
@@ -49,8 +49,9 @@ def api_health():
4949
}
5050

5151
# Add file watcher status if available
52-
if _file_watcher:
53-
health_data["file_watcher"] = _file_watcher.get_status()
52+
watcher = get_file_watcher()
53+
if watcher:
54+
health_data["file_watcher"] = watcher.get_status()
5455

5556
return JSONResponse(health_data)
5657

main.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,18 @@
1212
from db.operations import get_or_create_project
1313
from utils.config import CFG
1414
from utils.logger import get_logger
15+
from utils import app_state
1516
from endpoints.project_endpoints import router as project_router
1617
from endpoints.query_endpoints import router as query_router
1718
from endpoints.web_endpoints import router as web_router
1819
from utils.file_watcher import FileWatcher
1920

2021
logger = get_logger(__name__)
2122

22-
# Global FileWatcher instance
23-
_file_watcher = None
24-
2523

2624
@asynccontextmanager
2725
async def lifespan(app: FastAPI):
2826
"""Application lifespan handler."""
29-
global _file_watcher
30-
3127
# Project registry is auto-initialized when needed via create_project
3228

3329
# Auto-create default project from configured local_path if it exists
@@ -41,7 +37,7 @@ async def lifespan(app: FastAPI):
4137
# Start FileWatcher if enabled
4238
if CFG.get("file_watcher_enabled", True):
4339
try:
44-
_file_watcher = FileWatcher(
40+
watcher = FileWatcher(
4541
logger=logger,
4642
enabled=True,
4743
debounce_seconds=CFG.get("file_watcher_debounce", 5),
@@ -53,24 +49,25 @@ async def lifespan(app: FastAPI):
5349
projects = db_operations.list_projects()
5450
for project in projects:
5551
if project.get("path") and os.path.exists(project["path"]):
56-
_file_watcher.add_project(project["id"], project["path"])
52+
watcher.add_project(project["id"], project["path"])
5753
except Exception as e:
5854
logger.warning(f"Could not add projects to file watcher: {e}")
5955

60-
_file_watcher.start()
56+
watcher.start()
57+
app_state.set_file_watcher(watcher)
6158
logger.info("FileWatcher started successfully")
6259
except Exception as e:
6360
logger.error(f"Failed to start FileWatcher: {e}")
64-
_file_watcher = None
6561
else:
6662
logger.info("FileWatcher is disabled in configuration")
6763

6864
yield
6965

7066
# Stop FileWatcher on shutdown
71-
if _file_watcher:
67+
watcher = app_state.get_file_watcher()
68+
if watcher:
7269
try:
73-
_file_watcher.stop()
70+
watcher.stop()
7471
logger.info("FileWatcher stopped successfully")
7572
except Exception as e:
7673
logger.error(f"Error stopping FileWatcher: {e}")

utils/app_state.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""
2+
Shared application state module.
3+
4+
This module provides a central location for shared application state
5+
to avoid circular dependencies between modules.
6+
"""
7+
8+
from typing import Optional
9+
10+
# Global FileWatcher instance
11+
file_watcher: Optional[object] = None
12+
13+
14+
def set_file_watcher(watcher):
15+
"""
16+
Set the global file watcher instance.
17+
18+
Args:
19+
watcher: FileWatcher instance
20+
"""
21+
global file_watcher
22+
file_watcher = watcher
23+
24+
25+
def get_file_watcher():
26+
"""
27+
Get the global file watcher instance.
28+
29+
Returns:
30+
FileWatcher instance or None if not initialized
31+
"""
32+
return file_watcher

utils/file_watcher.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ class FileWatcher:
4141
automatic re-indexing when changes are detected.
4242
"""
4343

44+
# Class constants for configuration limits
45+
MIN_DEBOUNCE_SECONDS = 1
46+
MIN_CHECK_INTERVAL = 5
47+
4448
def __init__(
4549
self,
4650
logger: Optional[logging.Logger] = None,
@@ -58,8 +62,8 @@ def __init__(
5862
check_interval: Seconds between directory scans (default: 10)
5963
"""
6064
self.enabled = enabled
61-
self.debounce_seconds = max(1, debounce_seconds)
62-
self.check_interval = max(5, check_interval)
65+
self.debounce_seconds = max(self.MIN_DEBOUNCE_SECONDS, debounce_seconds)
66+
self.check_interval = max(self.MIN_CHECK_INTERVAL, check_interval)
6367

6468
# Set up logger
6569
if logger:
@@ -285,13 +289,15 @@ def _check_project(self, project_id: str, project_info: Dict) -> None:
285289

286290
def _scan_directory(self, directory: str) -> Dict[str, str]:
287291
"""
288-
Scan a directory and return a dictionary of file paths to modification times.
292+
Scan a directory and return a dictionary of file paths to file signatures.
293+
294+
Uses both modification time and file size for better change detection.
289295
290296
Args:
291297
directory: Directory path to scan
292298
293299
Returns:
294-
Dictionary mapping relative file paths to modification time hashes
300+
Dictionary mapping relative file paths to signature (mtime:size)
295301
"""
296302
file_hashes = {}
297303

@@ -309,10 +315,12 @@ def _scan_directory(self, directory: str) -> Dict[str, str]:
309315
filepath = os.path.join(root, filename)
310316

311317
try:
312-
# Use modification time as a simple hash
313-
mtime = os.path.getmtime(filepath)
318+
# Use both modification time and file size as signature
319+
stat = os.stat(filepath)
320+
mtime = stat.st_mtime
321+
size = stat.st_size
314322
relative_path = os.path.relpath(filepath, directory)
315-
file_hashes[relative_path] = str(mtime)
323+
file_hashes[relative_path] = f"{mtime}:{size}"
316324
except (OSError, ValueError):
317325
# Skip files we can't access
318326
continue

0 commit comments

Comments
 (0)