Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 14 additions & 38 deletions src/clinical_dbs_annotator/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
and main window creation.
"""

import os
import logging
import sys
import tempfile
import traceback

from PySide6.QtWidgets import QApplication

from .logging_config import setup_logging
from .utils import get_theme_manager
from .views import WizardWindow

Expand All @@ -23,46 +22,23 @@ def main() -> int:
Returns:
Exit code (0 for success)
"""
try:
# Check for required dependencies
try:
import pytz # noqa: F401
except ImportError:
print("Error: pytz is required. Install with: pip install pytz")
return 1

# Create application
app = QApplication(sys.argv)
app = QApplication(sys.argv)

# Set application metadata
app.setApplicationName("Clinical DBS Annotator")
app.setOrganizationName("BML")
app.setApplicationName("Clinical DBS Annotator")
app.setOrganizationName("BML")

# Load and apply theme
theme_manager = get_theme_manager()
try:
theme_manager.apply_theme(theme_manager.get_current_theme(), app)
except Exception as e:
print(f"Warning: Could not load theme: {e}")
print("Continuing with default styling...")
setup_logging(app)

# Create and show main window
window = WizardWindow(app)
window.show()
theme_manager = get_theme_manager()
try:
theme_manager.apply_theme(theme_manager.get_current_theme(), app)
except Exception as e:
logging.warning("Could not load theme: %s", e)

# Run application
return app.exec()
window = WizardWindow(app)
window.show()

except Exception:
print("FATAL ERROR:")
traceback.print_exc()
try:
log_path = os.path.join(tempfile.gettempdir(), "ClinicalDBSAnnot_crash.log")
with open(log_path, "w", encoding="utf-8") as f:
f.write(traceback.format_exc())
except Exception:
pass
return 1
return app.exec()


if __name__ == "__main__":
Expand Down
101 changes: 101 additions & 0 deletions src/clinical_dbs_annotator/logging_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import logging
import platform
import sys
import threading
from logging.handlers import RotatingFileHandler
from pathlib import Path

from PySide6.QtCore import (
QMessageLogContext,
QStandardPaths,
QtMsgType,
qInstallMessageHandler,
)
from PySide6.QtWidgets import QApplication

from . import __version__

_configured = False
_log_file_path: Path | None = None


def setup_logging(_app: QApplication) -> Path:
global _configured, _log_file_path
if _configured:
assert _log_file_path is not None
return _log_file_path

base = Path(
QStandardPaths.writableLocation(
QStandardPaths.StandardLocation.AppLocalDataLocation
)
)
log_dir = base / "logs"
log_dir.mkdir(parents=True, exist_ok=True)
log_path = log_dir / "clinical-dbs-annotator.log"

fmt = logging.Formatter("%(asctime)s ¦ %(levelname)s ¦ %(name)s ¦ %(message)s")
root = logging.getLogger()
root.setLevel(logging.DEBUG)
for h in root.handlers[:]:
root.removeHandler(h)

fh = RotatingFileHandler(
log_path, maxBytes=5_000_000, backupCount=3, encoding="utf-8"
)
fh.setLevel(logging.INFO)
fh.setFormatter(fmt)
root.addHandler(fh)

if not getattr(sys, "frozen", False):
sh = logging.StreamHandler(sys.stderr)
sh.setLevel(logging.INFO)
sh.setFormatter(fmt)
root.addHandler(sh)

def exc_hook(exc_type, exc, tb):
logging.getLogger("uncaught").critical(
"Uncaught exception",
exc_info=(exc_type, exc, tb),
)

sys.excepthook = exc_hook

def thread_exc_hook(args: threading.ExceptHookArgs) -> None:
logging.getLogger("uncaught").critical(
"Uncaught thread exception",
exc_info=(args.exc_type, args.exc_value, args.exc_traceback),
)

threading.excepthook = thread_exc_hook

def qt_handler(mode: QtMsgType, context: QMessageLogContext, message: str) -> None:
if mode == QtMsgType.QtDebugMsg:
level = logging.DEBUG
elif mode == QtMsgType.QtInfoMsg:
level = logging.INFO
elif mode == QtMsgType.QtWarningMsg:
level = logging.WARNING
elif mode == QtMsgType.QtCriticalMsg:
level = logging.ERROR
else:
level = logging.CRITICAL
suffix = ""
if context.file:
suffix = f" ({context.file}:{context.line})"
logging.getLogger("qt").log(level, "%s%s", message, suffix)

qInstallMessageHandler(qt_handler)

logging.getLogger("clinical_dbs_annotator").info(
"Started v%s Python %s | %s | log=%s",
__version__,
platform.python_version(),
platform.platform(),
log_path.resolve(),
)

resolved = log_path.resolve()
_configured = True
_log_file_path = resolved
return resolved