Restructure into src/ layout under pygui package
Move all application source under src/pygui/ and rewire imports, build config, and QML module path to match. - Relocate backend/, serialcomm/, and the ISC QML module into src/pygui/; convert main.py into pygui/__main__.py with a main() entry point (run via `python -m pygui` or the new `isc` script) - Rewrite absolute imports: backend.* -> pygui.backend.*, serialcomm.* -> pygui.serialcomm.* (source + tests) - Move app icons (isc.ico/icns) into packaging/ - Update README and ISC.qmlproject to the new paths
This commit is contained in:
+7
-1
@@ -5,6 +5,9 @@ __pycache__/
|
||||
*.pyd
|
||||
*.so
|
||||
*.a
|
||||
*.egg-info/
|
||||
.pytest_cache/
|
||||
.ruff_cache/
|
||||
|
||||
# Virtual environment
|
||||
.venv/
|
||||
@@ -14,10 +17,11 @@ env/
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
.qtcreator/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
docs
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
@@ -35,3 +39,5 @@ dist/
|
||||
*.spec
|
||||
*.icns
|
||||
*.ico
|
||||
# Superpowers brainstorming visual companion
|
||||
.superpowers/
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import type QmlProjectModel 1.0
|
||||
|
||||
QmlProject {
|
||||
name: "ISC"
|
||||
version: "1.0"
|
||||
mainFile: "src/pygui/ISC/Main.qml"
|
||||
|
||||
dependencies {
|
||||
module: "QtQuick"
|
||||
minimumVersion: "6.0.0"
|
||||
}
|
||||
|
||||
importPaths: [
|
||||
"src/pygui"
|
||||
]
|
||||
}
|
||||
@@ -16,34 +16,42 @@ python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
pip install -e . # install the `pygui` package (src/ layout) in editable mode
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
source .venv/bin/activate
|
||||
python main.py
|
||||
python -m pygui # or run the `isc` console script
|
||||
```
|
||||
|
||||
This launches the Qt window and loads the `ISC` QML module from `ISC/Main.qml`.
|
||||
This launches the Qt window and loads the `ISC` QML module from `src/pygui/ISC/Main.qml`.
|
||||
|
||||
## Project Structure
|
||||
|
||||
- `main.py`: PySide6 bootstrap; creates the Qt app and loads QML module `ISC/Main`.
|
||||
- `ISC/Main.qml`: top-level window definition.
|
||||
- `ISC/HomePage.qml`: main UI layout (left action rail, workspace panel, footer tabs).
|
||||
- `ISC/Theme.qml`: shared theme constants and dark/light mode tokens.
|
||||
- `ISC/qmldir`: QML module registration.
|
||||
The application lives under a `src/` layout as the `pygui` package:
|
||||
|
||||
- `src/pygui/__main__.py`: PySide6 bootstrap; creates the Qt app and loads QML module `ISC/Main`. Entry point for `python -m pygui`.
|
||||
- `src/pygui/backend/`: Qt-facing models and controllers (device, settings, file browser, wafer parsing).
|
||||
- `src/pygui/serialcomm/`: serial port, device service, and data-parser layer.
|
||||
- `src/pygui/ISC/`: the `ISC` QML module (UI).
|
||||
- `Main.qml`: top-level window definition.
|
||||
- `HomePage.qml`: main UI layout (left action rail, workspace panel, footer tabs).
|
||||
- `Theme.qml`: shared theme constants and dark/light mode tokens.
|
||||
- `qmldir`: QML module registration.
|
||||
- `tests/`: pytest suite.
|
||||
- `packaging/`: PyInstaller spec (`isc.spec`) and app icons.
|
||||
|
||||
## Window Configuration
|
||||
|
||||
Window dimensions and constraints are defined in `ISC/Main.qml`:
|
||||
Window dimensions and constraints are defined in `src/pygui/ISC/Main.qml`:
|
||||
|
||||
- **Default size**: 1400 × 820 pixels
|
||||
- **Minimum size**: 1100 × 700 pixels
|
||||
- **Title bar**: "ISenseCloud"
|
||||
|
||||
To adjust the window, edit the `Window` block in `ISC/Main.qml`:
|
||||
To adjust the window, edit the `Window` block in `src/pygui/ISC/Main.qml`:
|
||||
|
||||
```qml
|
||||
Window {
|
||||
@@ -58,8 +66,8 @@ Window {
|
||||
|
||||
## Customization
|
||||
|
||||
- Toggle dark/light mode in `ISC/Theme.qml` via `isDarkMode`.
|
||||
- Update sidebar and footer labels in `ISC/HomePage.qml` through `sideActions` and `bottomTabs`.
|
||||
- Toggle dark/light mode in `src/pygui/ISC/Theme.qml` via `isDarkMode`.
|
||||
- Update sidebar and footer labels in `src/pygui/ISC/HomePage.qml` through `sideActions` and `bottomTabs`.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
||||
+47
-1
@@ -1,3 +1,8 @@
|
||||
# ===== Build System =====
|
||||
[build-system]
|
||||
requires = ["setuptools>=61"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
# ===== Project Metadata =====
|
||||
[project]
|
||||
name = "pygui"
|
||||
@@ -6,9 +11,50 @@ version = "0.1.0"
|
||||
[project.optional-dependencies]
|
||||
dev = ["pytest"]
|
||||
|
||||
# ===== Console Entry Point =====
|
||||
[project.scripts]
|
||||
isc = "pygui.__main__:main"
|
||||
|
||||
# ===== Package Discovery (src layout) =====
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["src"]
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
# Ship the QML module alongside the Python package.
|
||||
pygui = ["ISC/**/*.qml", "ISC/**/qmldir"]
|
||||
|
||||
# ===== PySide Build Inputs =====
|
||||
[tool.pyside6-project]
|
||||
files = ["ISC/HomePage.qml", "ISC/Main.qml", "ISC/Tabs/DataTab.qml", "ISC/Tabs/GraphTab.qml", "ISC/Tabs/SelectFileDialog.qml", "ISC/Tabs/SettingsTab.qml", "ISC/Tabs/StatusTab.qml", "ISC/Tabs/qmldir", "ISC/Theme.qml", "ISC/qmldir", "backend/data_model.py", "backend/device_controller.py", "backend/graph_view.py", "backend/file_browser.py", "backend/local_settings.py", "backend/local_settings_model.py", "main.py", "serialcomm/__init__.py", "serialcomm/data_parser.py", "serialcomm/serial_port.py", "serialcomm/device_service.py"]
|
||||
files = [
|
||||
"src/pygui/ISC/HomePage.qml",
|
||||
"src/pygui/ISC/Main.qml",
|
||||
"src/pygui/ISC/Theme.qml",
|
||||
"src/pygui/ISC/qmldir",
|
||||
"src/pygui/ISC/Tabs/DataTab.qml",
|
||||
"src/pygui/ISC/Tabs/SelectFileDialog.qml",
|
||||
"src/pygui/ISC/Tabs/SettingsTab.qml",
|
||||
"src/pygui/ISC/Tabs/StatusTab.qml",
|
||||
"src/pygui/ISC/Tabs/qmldir",
|
||||
"src/pygui/__main__.py",
|
||||
"src/pygui/backend/contour_models.py",
|
||||
"src/pygui/backend/crypto_helper.py",
|
||||
"src/pygui/backend/csv_file_metadata.py",
|
||||
"src/pygui/backend/data_model.py",
|
||||
"src/pygui/backend/data_segment.py",
|
||||
"src/pygui/backend/device_controller.py",
|
||||
"src/pygui/backend/file_browser.py",
|
||||
"src/pygui/backend/frame.py",
|
||||
"src/pygui/backend/graph_view.py",
|
||||
"src/pygui/backend/local_settings.py",
|
||||
"src/pygui/backend/local_settings_model.py",
|
||||
"src/pygui/backend/marching_squares.py",
|
||||
"src/pygui/backend/zwafer_models.py",
|
||||
"src/pygui/backend/zwafer_parser.py",
|
||||
"src/pygui/serialcomm/__init__.py",
|
||||
"src/pygui/serialcomm/data_parser.py",
|
||||
"src/pygui/serialcomm/device_service.py",
|
||||
"src/pygui/serialcomm/serial_port.py",
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
|
||||
@@ -5,13 +5,14 @@ from PySide6.QtQml import QQmlApplicationEngine
|
||||
from PySide6.QtQuickControls2 import QQuickStyle
|
||||
from PySide6.QtWidgets import QApplication
|
||||
|
||||
from backend.device_controller import DeviceController
|
||||
from backend.local_settings import LocalSettings
|
||||
from backend.local_settings_model import LocalSettingsModel
|
||||
from backend.file_browser import FileBrowser
|
||||
from pygui.backend.device_controller import DeviceController
|
||||
from pygui.backend.local_settings import LocalSettings
|
||||
from pygui.backend.local_settings_model import LocalSettingsModel
|
||||
from pygui.backend.file_browser import FileBrowser
|
||||
|
||||
|
||||
# ===== Application Entry Point =====
|
||||
if __name__ == "__main__":
|
||||
def main() -> int:
|
||||
# ===== UI Style Setup =====
|
||||
# Use a non-native controls style so our custom QML button backgrounds are supported.
|
||||
QQuickStyle.setStyle("Basic")
|
||||
@@ -35,11 +36,17 @@ if __name__ == "__main__":
|
||||
engine.rootContext().setContextProperty("deviceController", device_controller)
|
||||
|
||||
# ===== QML Startup =====
|
||||
# The "ISC" QML module lives alongside this file (src/pygui/ISC), so the
|
||||
# package directory is the import path the engine searches for qmldir.
|
||||
engine.addImportPath(Path(__file__).parent)
|
||||
engine.loadFromModule("ISC", "Main")
|
||||
|
||||
# ===== Exit Handling =====
|
||||
if not engine.rootObjects():
|
||||
sys.exit(-1)
|
||||
return -1
|
||||
|
||||
sys.exit(app.exec())
|
||||
return app.exec()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -15,17 +15,17 @@ from typing import Any, Optional
|
||||
|
||||
from PySide6.QtCore import QObject, Property, Qt, Signal, Slot
|
||||
|
||||
from backend.data_model import TemperatureTableModel
|
||||
from backend.graph_view import GraphView
|
||||
from backend.local_settings import LocalSettings
|
||||
from serialcomm.data_parser import (
|
||||
from pygui.backend.data_model import TemperatureTableModel
|
||||
from pygui.backend.graph_view import GraphView
|
||||
from pygui.backend.local_settings import LocalSettings
|
||||
from pygui.serialcomm.data_parser import (
|
||||
convert_to_temperatures,
|
||||
parse_binary_data,
|
||||
remove_trailing_zeros,
|
||||
save_to_csv,
|
||||
)
|
||||
from serialcomm.device_service import DeviceService
|
||||
from serialcomm.serial_port import WaferInfo
|
||||
from pygui.serialcomm.device_service import DeviceService
|
||||
from pygui.serialcomm.serial_port import WaferInfo
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -8,8 +8,8 @@ from pathlib import Path
|
||||
from PySide6.QtCore import QObject, Property, QStandardPaths, Signal, Slot
|
||||
from PySide6.QtWidgets import QFileDialog, QMessageBox
|
||||
|
||||
from backend.csv_file_metadata import CSVFileMetadata
|
||||
from backend.zwafer_parser import ZWaferParser
|
||||
from pygui.backend.csv_file_metadata import CSVFileMetadata
|
||||
from pygui.backend.zwafer_parser import ZWaferParser
|
||||
|
||||
|
||||
# ===== File Browser Model =====
|
||||
@@ -0,0 +1,11 @@
|
||||
from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Frame:
|
||||
"""One sample across all sensors ata a point in time"""
|
||||
|
||||
seq: int
|
||||
t: float
|
||||
values: list[float]
|
||||
@@ -6,7 +6,7 @@ from typing import Any
|
||||
|
||||
from PySide6.QtCore import QObject, Property, QDateTime, QStandardPaths, Signal, Slot
|
||||
|
||||
from backend.local_settings import LocalSettings
|
||||
from pygui.backend.local_settings import LocalSettings
|
||||
|
||||
|
||||
MASTER_FAMILIES = ("A", "B", "C", "D", "E", "F", "P", "X", "Z")
|
||||
@@ -2,7 +2,7 @@ from typing import List, Tuple, Optional
|
||||
|
||||
import numpy as np
|
||||
|
||||
from backend.contour_models import ContourLine, ContourSegment
|
||||
from pygui.backend.contour_models import ContourLine, ContourSegment
|
||||
|
||||
|
||||
# ===== Contour Generation =====
|
||||
@@ -2,7 +2,7 @@ from pathlib import Path
|
||||
from typing import Tuple, Optional
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from backend.zwafer_models import ZWaferData, Sensor
|
||||
from pygui.backend.zwafer_models import ZWaferData, Sensor
|
||||
|
||||
|
||||
# ===== Z-Wafer CSV Parser =====
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Serial port communication layer for the temperature-sensing wafer."""
|
||||
|
||||
from serialcomm.device_service import DeviceService
|
||||
from serialcomm.serial_port import SerialPort, WaferInfo
|
||||
from pygui.serialcomm.device_service import DeviceService
|
||||
from pygui.serialcomm.serial_port import SerialPort, WaferInfo
|
||||
|
||||
__all__ = ["DeviceService", "SerialPort", "WaferInfo"]
|
||||
@@ -11,8 +11,8 @@ from typing import Optional
|
||||
|
||||
import serial.tools.list_ports
|
||||
|
||||
from backend.local_settings import LocalSettings
|
||||
from serialcomm.serial_port import SerialPort, WaferInfo
|
||||
from pygui.backend.local_settings import LocalSettings
|
||||
from pygui.serialcomm.serial_port import SerialPort, WaferInfo
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
Reference in New Issue
Block a user