synaptipy 0.1.1b4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- Synaptipy/__init__.py +21 -0
- Synaptipy/__main__.py +86 -0
- Synaptipy/application/__init__.py +11 -0
- Synaptipy/application/__main__.py +251 -0
- Synaptipy/application/cli/__init__.py +11 -0
- Synaptipy/application/cli/main.py +10 -0
- Synaptipy/application/controllers/__init__.py +19 -0
- Synaptipy/application/controllers/analysis_formatter.py +539 -0
- Synaptipy/application/controllers/analysis_plot_manager.py +181 -0
- Synaptipy/application/controllers/file_io_controller.py +188 -0
- Synaptipy/application/controllers/live_analysis_controller.py +145 -0
- Synaptipy/application/controllers/shortcut_manager.py +57 -0
- Synaptipy/application/data_loader.py +160 -0
- Synaptipy/application/gui/__init__.py +12 -0
- Synaptipy/application/gui/about_dialog.py +123 -0
- Synaptipy/application/gui/analyser_tab.py +961 -0
- Synaptipy/application/gui/analysis_config_dialog.py +196 -0
- Synaptipy/application/gui/analysis_tabs/__init__.py +10 -0
- Synaptipy/application/gui/analysis_tabs/base.py +2704 -0
- Synaptipy/application/gui/analysis_tabs/metadata_driven.py +1789 -0
- Synaptipy/application/gui/analysis_worker.py +215 -0
- Synaptipy/application/gui/batch_dialog.py +1184 -0
- Synaptipy/application/gui/dialogs/export_manager.py +224 -0
- Synaptipy/application/gui/dialogs/plot_export_dialog.py +68 -0
- Synaptipy/application/gui/dialogs/trial_selection_dialog.py +93 -0
- Synaptipy/application/gui/explorer/__init__.py +6 -0
- Synaptipy/application/gui/explorer/config_panel.py +327 -0
- Synaptipy/application/gui/explorer/explorer_tab.py +2217 -0
- Synaptipy/application/gui/explorer/plot_canvas.py +231 -0
- Synaptipy/application/gui/explorer/sidebar.py +414 -0
- Synaptipy/application/gui/explorer/toolbar.py +131 -0
- Synaptipy/application/gui/explorer/y_controls.py +258 -0
- Synaptipy/application/gui/exporter_tab.py +606 -0
- Synaptipy/application/gui/main_window.py +1096 -0
- Synaptipy/application/gui/nwb_dialog.py +341 -0
- Synaptipy/application/gui/plot_customization_dialog.py +862 -0
- Synaptipy/application/gui/plot_save_dialog.py +336 -0
- Synaptipy/application/gui/preferences_dialog.py +374 -0
- Synaptipy/application/gui/session_summary_dialog.py +97 -0
- Synaptipy/application/gui/ui_generator.py +230 -0
- Synaptipy/application/gui/welcome_screen.py +482 -0
- Synaptipy/application/gui/widgets/plot_canvas.py +620 -0
- Synaptipy/application/gui/widgets/preprocessing.py +329 -0
- Synaptipy/application/plugin_manager.py +276 -0
- Synaptipy/application/services/__init__.py +3 -0
- Synaptipy/application/services/data_loader_service.py +108 -0
- Synaptipy/application/session_manager.py +235 -0
- Synaptipy/application/startup_manager.py +280 -0
- Synaptipy/core/__init__.py +19 -0
- Synaptipy/core/analysis/__init__.py +42 -0
- Synaptipy/core/analysis/batch_engine.py +1127 -0
- Synaptipy/core/analysis/cross_file_utils.py +151 -0
- Synaptipy/core/analysis/epoch_manager.py +291 -0
- Synaptipy/core/analysis/evoked_responses.py +910 -0
- Synaptipy/core/analysis/firing_dynamics.py +679 -0
- Synaptipy/core/analysis/passive_properties.py +2185 -0
- Synaptipy/core/analysis/registry.py +244 -0
- Synaptipy/core/analysis/single_spike.py +925 -0
- Synaptipy/core/analysis/synaptic_events.py +1397 -0
- Synaptipy/core/data_model.py +548 -0
- Synaptipy/core/processing_pipeline.py +345 -0
- Synaptipy/core/results.py +147 -0
- Synaptipy/core/signal_processor.py +839 -0
- Synaptipy/core/source_interfaces.py +28 -0
- Synaptipy/infrastructure/__init__.py +12 -0
- Synaptipy/infrastructure/exporters/__init__.py +15 -0
- Synaptipy/infrastructure/exporters/csv_exporter.py +618 -0
- Synaptipy/infrastructure/exporters/nwb_exporter.py +454 -0
- Synaptipy/infrastructure/file_readers/__init__.py +16 -0
- Synaptipy/infrastructure/file_readers/abf_reader.py +1 -0
- Synaptipy/infrastructure/file_readers/neo_adapter.py +702 -0
- Synaptipy/infrastructure/file_readers/neo_source_handle.py +83 -0
- Synaptipy/infrastructure/neo_patches.py +281 -0
- Synaptipy/resources/icons/logo.afdesign +0 -0
- Synaptipy/resources/icons/logo.icns +0 -0
- Synaptipy/resources/icons/logo.ico +0 -0
- Synaptipy/resources/icons/logo.png +0 -0
- Synaptipy/shared/__init__.py +103 -0
- Synaptipy/shared/constants.py +49 -0
- Synaptipy/shared/data_cache.py +279 -0
- Synaptipy/shared/error_handling.py +70 -0
- Synaptipy/shared/logging_config.py +135 -0
- Synaptipy/shared/plot_customization.py +924 -0
- Synaptipy/shared/plot_exporter.py +245 -0
- Synaptipy/shared/plot_factory.py +297 -0
- Synaptipy/shared/plot_zoom_sync.py +550 -0
- Synaptipy/shared/scroll_settings.py +131 -0
- Synaptipy/shared/styling.py +326 -0
- Synaptipy/shared/theme_manager.py +708 -0
- Synaptipy/shared/utils.py +46 -0
- Synaptipy/shared/viewbox.py +116 -0
- Synaptipy/shared/zoom_theme.py +350 -0
- Synaptipy/templates/analysis_template.py +62 -0
- Synaptipy/templates/plugin_template.py +168 -0
- Synaptipy/templates/tab_template.py +89 -0
- Synaptipy/templates/test_template.py +45 -0
- synaptipy-0.1.1b4.dist-info/METADATA +635 -0
- synaptipy-0.1.1b4.dist-info/RECORD +102 -0
- synaptipy-0.1.1b4.dist-info/WHEEL +5 -0
- synaptipy-0.1.1b4.dist-info/entry_points.txt +2 -0
- synaptipy-0.1.1b4.dist-info/licenses/LICENSE +657 -0
- synaptipy-0.1.1b4.dist-info/top_level.txt +1 -0
Synaptipy/__init__.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Synaptipy: A multi-channel electrophysiology visualization and analysis toolkit.
|
|
4
|
+
|
|
5
|
+
This package provides tools for loading, visualizing, and exporting
|
|
6
|
+
electrophysiology data using the neo library and a Qt-based graphical interface.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# PEP 396 style version marker
|
|
10
|
+
__version__ = "0.1.1b4"
|
|
11
|
+
__author__ = "Anzal K Shahul"
|
|
12
|
+
__email__ = "anzal.ks@gmail.com"
|
|
13
|
+
__license__ = "AGPL-3.0-or-later"
|
|
14
|
+
|
|
15
|
+
# Define the primary public API exposed directly by 'import Synaptipy'
|
|
16
|
+
# Usually just metadata for library packages.
|
|
17
|
+
__all__ = ["__version__", "__author__", "__email__", "__license__"]
|
|
18
|
+
|
|
19
|
+
# Optional: Configure root logger basic settings if not done elsewhere
|
|
20
|
+
# import logging
|
|
21
|
+
# logging.getLogger(__name__).addHandler(logging.NullHandler())
|
Synaptipy/__main__.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Synaptipy - Multi-channel Electrophysiology Visualization and Analysis Toolkit
|
|
4
|
+
|
|
5
|
+
This module serves as the entry point for the package when run as:
|
|
6
|
+
python -m Synaptipy
|
|
7
|
+
|
|
8
|
+
It parses command line arguments and launches the application with the appropriate settings.
|
|
9
|
+
|
|
10
|
+
This file is part of Synaptipy, licensed under the GNU Affero General Public License v3.0.
|
|
11
|
+
See the LICENSE file in the root of the repository for full license details.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import logging
|
|
16
|
+
import os
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
# Set up logging before importing the rest of the package
|
|
21
|
+
from Synaptipy.shared.logging_config import setup_logging
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def parse_args():
|
|
25
|
+
"""Parse command line arguments."""
|
|
26
|
+
parser = argparse.ArgumentParser(
|
|
27
|
+
description="Synaptipy - Electrophysiology Visualization and Analysis Toolkit",
|
|
28
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
29
|
+
)
|
|
30
|
+
parser.add_argument("--dev", action="store_true", help="Run in development mode with increased logging")
|
|
31
|
+
parser.add_argument("--log-dir", type=str, default=None, help="Directory to store log files")
|
|
32
|
+
parser.add_argument("--verbose", "-v", action="store_true", help="Increase output verbosity")
|
|
33
|
+
parser.add_argument("--version", action="store_true", help="Show version information and exit")
|
|
34
|
+
parser.add_argument("--file", type=str, default=None, help="Open a specific file on startup")
|
|
35
|
+
|
|
36
|
+
return parser.parse_args()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def main():
|
|
40
|
+
"""Main entry point for the application."""
|
|
41
|
+
args = parse_args()
|
|
42
|
+
|
|
43
|
+
# Show version and exit if requested
|
|
44
|
+
if args.version:
|
|
45
|
+
from Synaptipy import __version__
|
|
46
|
+
|
|
47
|
+
print(f"Synaptipy version {__version__}")
|
|
48
|
+
return 0
|
|
49
|
+
|
|
50
|
+
# Set up environment variables based on arguments
|
|
51
|
+
if args.dev:
|
|
52
|
+
os.environ["SYNAPTIPY_DEV_MODE"] = "1"
|
|
53
|
+
|
|
54
|
+
# Configure logging
|
|
55
|
+
_log_level = logging.DEBUG if args.verbose or args.dev else logging.INFO # noqa: F841
|
|
56
|
+
setup_logging(dev_mode=args.dev, log_dir=args.log_dir)
|
|
57
|
+
logger = logging.getLogger(__name__)
|
|
58
|
+
|
|
59
|
+
logger.info("Starting Synaptipy...")
|
|
60
|
+
logger.debug(f"Command line arguments: {args}")
|
|
61
|
+
|
|
62
|
+
# Import GUI components here to avoid circular imports
|
|
63
|
+
try:
|
|
64
|
+
from Synaptipy.application.__main__ import run_gui
|
|
65
|
+
|
|
66
|
+
# Launch the GUI
|
|
67
|
+
initial_file = Path(args.file) if args.file else None
|
|
68
|
+
if initial_file and not initial_file.exists():
|
|
69
|
+
logger.error(f"File not found: {initial_file}")
|
|
70
|
+
print(f"Error: File not found: {initial_file}")
|
|
71
|
+
return 1
|
|
72
|
+
|
|
73
|
+
return run_gui()
|
|
74
|
+
except ImportError as e:
|
|
75
|
+
logger.error(f"Failed to import GUI components: {e}")
|
|
76
|
+
print(f"Error: Failed to import GUI components: {e}")
|
|
77
|
+
print("Make sure PySide6 is installed properly.")
|
|
78
|
+
return 1
|
|
79
|
+
except Exception as e:
|
|
80
|
+
logger.exception(f"Unexpected error: {e}")
|
|
81
|
+
print(f"Error: {e}")
|
|
82
|
+
return 1
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
if __name__ == "__main__":
|
|
86
|
+
sys.exit(main())
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Application Layer for Synaptipy.
|
|
4
|
+
|
|
5
|
+
Contains the user interface (GUI, CLI) and logic that orchestrates
|
|
6
|
+
user interactions with the core domain and infrastructure layers.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# Nothing essential needs to be exposed directly from here for typical use.
|
|
10
|
+
# Users will typically interact via the main entry point or specific UI/CLI modules.
|
|
11
|
+
__all__ = []
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# src/Synaptipy/application/__main__.py
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Main entry point for the Synaptipy Viewer GUI application.
|
|
5
|
+
|
|
6
|
+
This module is responsible for:
|
|
7
|
+
1. Processing command line arguments
|
|
8
|
+
2. Setting up the logging system with dev mode support
|
|
9
|
+
3. Initializing the Qt application and UI styling
|
|
10
|
+
4. Creating and displaying the welcome screen with startup manager
|
|
11
|
+
5. Running the event loop
|
|
12
|
+
|
|
13
|
+
The module defines the `run_gui` function called by the entry point script
|
|
14
|
+
defined in pyproject.toml.
|
|
15
|
+
|
|
16
|
+
This file is part of Synaptipy, licensed under the GNU Affero General Public License v3.0.
|
|
17
|
+
See the LICENSE file in the root of the repository for full license details.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import argparse
|
|
21
|
+
import faulthandler
|
|
22
|
+
import logging
|
|
23
|
+
import os
|
|
24
|
+
import sys
|
|
25
|
+
import traceback
|
|
26
|
+
|
|
27
|
+
# Suppress annoying pyqtgraph RuntimeWarnings (overflow in cast)
|
|
28
|
+
import warnings
|
|
29
|
+
|
|
30
|
+
from PySide6 import QtCore, QtGui, QtWidgets
|
|
31
|
+
|
|
32
|
+
# --- Import Core Components ---
|
|
33
|
+
from Synaptipy.application.startup_manager import StartupManager
|
|
34
|
+
from Synaptipy.shared.logging_config import setup_logging
|
|
35
|
+
|
|
36
|
+
warnings.filterwarnings("ignore", category=RuntimeWarning, module="pyqtgraph")
|
|
37
|
+
|
|
38
|
+
# Enable low-level C traceback on SIGBUS/SIGSEGV so fatal crashes include a
|
|
39
|
+
# Python stack trace in the log (zero overhead in normal operation).
|
|
40
|
+
faulthandler.enable()
|
|
41
|
+
|
|
42
|
+
# Log instance to be initialized after setting up logging
|
|
43
|
+
log = logging.getLogger(__name__)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def parse_arguments():
|
|
47
|
+
"""
|
|
48
|
+
Parse command line arguments for the application.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
argparse.Namespace: Parsed command line arguments
|
|
52
|
+
"""
|
|
53
|
+
parser = argparse.ArgumentParser(description="Synaptipy - Electrophysiology Visualization Suite")
|
|
54
|
+
parser.add_argument("--dev", action="store_true", help="Enable development mode with verbose logging")
|
|
55
|
+
parser.add_argument("--log-dir", type=str, help="Custom directory for log files")
|
|
56
|
+
parser.add_argument("--log-file", type=str, help="Custom log filename")
|
|
57
|
+
return parser.parse_args()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# ---------------------------------------------------------------------------
|
|
61
|
+
# Graceful crash reporter
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class CrashReportDialog(QtWidgets.QDialog):
|
|
66
|
+
"""Non-modal dialog shown when an unhandled Python exception escapes to the
|
|
67
|
+
top level. Displays the full traceback in a read-only text area and
|
|
68
|
+
provides a one-click "Copy to Clipboard" button so the user can paste the
|
|
69
|
+
report directly into a GitHub Issue.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
_GITHUB_ISSUES_URL = "https://github.com/anzalks/synaptipy/issues/new"
|
|
73
|
+
|
|
74
|
+
def __init__(self, traceback_text: str, parent=None):
|
|
75
|
+
super().__init__(parent)
|
|
76
|
+
self.setWindowTitle("Synaptipy — Unexpected Error")
|
|
77
|
+
self.setMinimumSize(680, 420)
|
|
78
|
+
self._traceback_text = traceback_text
|
|
79
|
+
self._build_ui()
|
|
80
|
+
|
|
81
|
+
def _build_ui(self) -> None:
|
|
82
|
+
layout = QtWidgets.QVBoxLayout(self)
|
|
83
|
+
|
|
84
|
+
# ---- Header ----
|
|
85
|
+
header = QtWidgets.QLabel(
|
|
86
|
+
"<b>An unexpected error occurred.</b><br>"
|
|
87
|
+
"The error details are shown below. "
|
|
88
|
+
"Please click <i>Copy to Clipboard</i> and paste them into a "
|
|
89
|
+
"<a href='{url}'>GitHub Issue</a> so we can fix this.".format(url=self._GITHUB_ISSUES_URL)
|
|
90
|
+
)
|
|
91
|
+
header.setWordWrap(True)
|
|
92
|
+
header.setOpenExternalLinks(True)
|
|
93
|
+
layout.addWidget(header)
|
|
94
|
+
|
|
95
|
+
# ---- Traceback ----
|
|
96
|
+
self._text_area = QtWidgets.QPlainTextEdit()
|
|
97
|
+
self._text_area.setReadOnly(True)
|
|
98
|
+
self._text_area.setPlainText(self._traceback_text)
|
|
99
|
+
font = QtGui.QFont("Courier New", 9)
|
|
100
|
+
font.setStyleHint(QtGui.QFont.StyleHint.Monospace)
|
|
101
|
+
self._text_area.setFont(font)
|
|
102
|
+
layout.addWidget(self._text_area)
|
|
103
|
+
|
|
104
|
+
# ---- Buttons ----
|
|
105
|
+
btn_box = QtWidgets.QDialogButtonBox()
|
|
106
|
+
copy_btn = btn_box.addButton("Copy to Clipboard", QtWidgets.QDialogButtonBox.ButtonRole.ActionRole)
|
|
107
|
+
close_btn = btn_box.addButton(QtWidgets.QDialogButtonBox.StandardButton.Close)
|
|
108
|
+
copy_btn.clicked.connect(self._copy_to_clipboard)
|
|
109
|
+
close_btn.clicked.connect(self.accept)
|
|
110
|
+
layout.addWidget(btn_box)
|
|
111
|
+
|
|
112
|
+
def _copy_to_clipboard(self) -> None:
|
|
113
|
+
QtWidgets.QApplication.clipboard().setText(self._traceback_text)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _install_excepthook() -> None:
|
|
117
|
+
"""Replace ``sys.excepthook`` with a GUI-aware crash reporter.
|
|
118
|
+
|
|
119
|
+
When an unhandled exception propagates to the top of the event loop,
|
|
120
|
+
the default hook prints to stderr and silently exits. Our replacement
|
|
121
|
+
logs the traceback, then pops up a ``CrashReportDialog`` so the user
|
|
122
|
+
can copy the error into a GitHub Issue.
|
|
123
|
+
|
|
124
|
+
The hook is intentionally *not* installed for ``SystemExit`` and
|
|
125
|
+
``KeyboardInterrupt`` so normal shutdown and Ctrl-C still work.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
def _excepthook(exc_type, exc_value, exc_tb):
|
|
129
|
+
if issubclass(exc_type, (SystemExit, KeyboardInterrupt)):
|
|
130
|
+
sys.__excepthook__(exc_type, exc_value, exc_tb)
|
|
131
|
+
return
|
|
132
|
+
|
|
133
|
+
tb_str = "".join(traceback.format_exception(exc_type, exc_value, exc_tb))
|
|
134
|
+
log.critical("Unhandled exception:\n%s", tb_str)
|
|
135
|
+
|
|
136
|
+
app = QtWidgets.QApplication.instance()
|
|
137
|
+
if app is not None:
|
|
138
|
+
try:
|
|
139
|
+
dlg = CrashReportDialog(tb_str)
|
|
140
|
+
dlg.exec()
|
|
141
|
+
except Exception:
|
|
142
|
+
# If the dialog itself fails, fall back to stderr
|
|
143
|
+
sys.__excepthook__(exc_type, exc_value, exc_tb)
|
|
144
|
+
else:
|
|
145
|
+
sys.__excepthook__(exc_type, exc_value, exc_tb)
|
|
146
|
+
|
|
147
|
+
sys.excepthook = _excepthook
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def run_gui(): # noqa: C901
|
|
151
|
+
"""
|
|
152
|
+
Set up and run the Synaptipy GUI application with welcome screen.
|
|
153
|
+
|
|
154
|
+
This function:
|
|
155
|
+
1. Parses command line arguments
|
|
156
|
+
2. Configures the logging system
|
|
157
|
+
3. Initializes the Qt application
|
|
158
|
+
4. Creates and displays the welcome screen
|
|
159
|
+
5. Manages startup process with progress tracking
|
|
160
|
+
6. Runs the Qt event loop
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
int: The application exit code
|
|
164
|
+
"""
|
|
165
|
+
# Parse command line arguments
|
|
166
|
+
args = parse_arguments()
|
|
167
|
+
|
|
168
|
+
# Check for dev mode environment variable
|
|
169
|
+
env_dev_mode = os.environ.get("SYNAPTIPY_DEV_MODE")
|
|
170
|
+
if env_dev_mode and env_dev_mode.lower() in ("1", "true", "yes"):
|
|
171
|
+
dev_mode = True
|
|
172
|
+
else:
|
|
173
|
+
dev_mode = args.dev
|
|
174
|
+
|
|
175
|
+
# Setup logging with the appropriate mode
|
|
176
|
+
setup_logging(dev_mode=dev_mode, log_dir=args.log_dir, log_filename=args.log_file)
|
|
177
|
+
|
|
178
|
+
log.info("Application starting...")
|
|
179
|
+
if dev_mode:
|
|
180
|
+
log.info("Running in DEVELOPMENT mode with verbose logging")
|
|
181
|
+
|
|
182
|
+
# Create Qt Application with High DPI support
|
|
183
|
+
app = QtWidgets.QApplication.instance()
|
|
184
|
+
if app is None:
|
|
185
|
+
# Enable High DPI scaling before creating QApplication
|
|
186
|
+
# Check if HighDpiScaleFactorRoundingPolicy is available (Qt 6.0+)
|
|
187
|
+
if hasattr(QtCore.Qt, "HighDpiScaleFactorRoundingPolicy"):
|
|
188
|
+
try:
|
|
189
|
+
QtWidgets.QApplication.setHighDpiScaleFactorRoundingPolicy(
|
|
190
|
+
QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough
|
|
191
|
+
)
|
|
192
|
+
log.debug("High DPI PassThrough policy set successfully")
|
|
193
|
+
except Exception as e:
|
|
194
|
+
log.warning(f"Could not set High DPI policy: {e}")
|
|
195
|
+
|
|
196
|
+
app = QtWidgets.QApplication(sys.argv)
|
|
197
|
+
|
|
198
|
+
# Enable High DPI pixmaps (for better icon rendering)
|
|
199
|
+
try:
|
|
200
|
+
app.setAttribute(QtCore.Qt.ApplicationAttribute.AA_UseHighDpiPixmaps, True)
|
|
201
|
+
except Exception as e:
|
|
202
|
+
log.warning(f"Could not enable High DPI pixmaps: {e}")
|
|
203
|
+
|
|
204
|
+
# Force locale to English/US to ensure dot decimal separators
|
|
205
|
+
# This fixes issues where European locales force comma separators in spinboxes
|
|
206
|
+
QtCore.QLocale.setDefault(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates))
|
|
207
|
+
log.debug("Forced application locale to English/US (dot decimal separator)")
|
|
208
|
+
|
|
209
|
+
# Install the GUI-aware crash reporter so unhandled exceptions show a
|
|
210
|
+
# dialog with a "Copy to Clipboard" button instead of silently exiting.
|
|
211
|
+
_install_excepthook()
|
|
212
|
+
log.debug("Crash-report excepthook installed.")
|
|
213
|
+
|
|
214
|
+
# Create startup manager and begin loading process
|
|
215
|
+
try:
|
|
216
|
+
startup_manager = StartupManager(app)
|
|
217
|
+
welcome_screen = startup_manager.start_loading()
|
|
218
|
+
|
|
219
|
+
# Show welcome screen immediately and force display
|
|
220
|
+
welcome_screen.show()
|
|
221
|
+
welcome_screen.raise_() # Bring to front
|
|
222
|
+
welcome_screen.activateWindow() # Activate the window
|
|
223
|
+
|
|
224
|
+
# Force Qt to process events and display the window immediately
|
|
225
|
+
app.processEvents()
|
|
226
|
+
|
|
227
|
+
# Use the optimized display method
|
|
228
|
+
welcome_screen.force_display()
|
|
229
|
+
|
|
230
|
+
log.debug("Welcome screen displayed, beginning startup process")
|
|
231
|
+
|
|
232
|
+
except Exception as e:
|
|
233
|
+
log.critical(f"Failed to create startup manager: {e}", exc_info=True)
|
|
234
|
+
try:
|
|
235
|
+
QtWidgets.QMessageBox.critical(
|
|
236
|
+
None, "Application Startup Error", f"Failed to create startup manager:\n{e}\n\nSee logs."
|
|
237
|
+
)
|
|
238
|
+
except Exception:
|
|
239
|
+
pass
|
|
240
|
+
sys.exit(1)
|
|
241
|
+
|
|
242
|
+
# Start Qt Event Loop
|
|
243
|
+
log.debug("Starting Qt event loop...")
|
|
244
|
+
exit_code = app.exec()
|
|
245
|
+
log.debug(f"Qt event loop finished with exit code {exit_code}.")
|
|
246
|
+
return exit_code
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
# Allow direct execution for development and testing
|
|
250
|
+
if __name__ == "__main__":
|
|
251
|
+
run_gui()
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Command-Line Interface (CLI) subpackage for Synaptipy.
|
|
4
|
+
|
|
5
|
+
This module is reserved for future CLI functionality.
|
|
6
|
+
The primary interface is the GUI, launched via ``synaptipy`` or
|
|
7
|
+
``python -m Synaptipy.application``.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
__all__: list = []
|
|
11
|
+
__all__ = []
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Command-Line Interface (CLI) entry point for Synaptipy.
|
|
4
|
+
|
|
5
|
+
Reserved for future implementation. The primary interface is currently
|
|
6
|
+
the GUI application.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# Future CLI implementation using argparse or click.
|
|
10
|
+
# See docs/developer_guide.md for planned CLI features.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Application controllers for Synaptipy."""
|
|
2
|
+
|
|
3
|
+
from .analysis_formatter import AnalysisResultFormatter, generate_methods_text
|
|
4
|
+
from .analysis_plot_manager import AnalysisPlotManager, PlotContextTrace, PlotDataPackage
|
|
5
|
+
from .file_io_controller import FileIOController
|
|
6
|
+
from .live_analysis_controller import AnalysisRunnable, LiveAnalysisController
|
|
7
|
+
from .shortcut_manager import ShortcutManager
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"AnalysisResultFormatter",
|
|
11
|
+
"generate_methods_text",
|
|
12
|
+
"AnalysisPlotManager",
|
|
13
|
+
"PlotContextTrace",
|
|
14
|
+
"PlotDataPackage",
|
|
15
|
+
"FileIOController",
|
|
16
|
+
"AnalysisRunnable",
|
|
17
|
+
"LiveAnalysisController",
|
|
18
|
+
"ShortcutManager",
|
|
19
|
+
]
|