SKILL: PyQt MVP with Service + Pure Model + Qt Bridge
Purpose
Generate a PyQt application using a strict MVP architecture with:
- Pure Python Model (no Qt)
- Service layer (data producers, threads, ROS, IO)
- Python event system (no Qt in model)
- Presenter as the ONLY Qt bridge
- Thread-safe UI updates via Qt signals
- Dedicated package folders for models, services, views, presenters, and tests
Architecture Overview
Rules
0. Project Layout (REQUIRED)
Always create a dedicated folder for each architectural type:
Rules:
- Do NOT place
model.py,service.py,view.py, orpresenter.pydirectly in the app package root. - Use plural folder names:
models,services,views,presenters. - Keep
app.pyas the composition root that wires all objects together. - Tests must be outside the runtime package in a top-level
tests/folder.
1. Model (STRICT)
- Must NOT import Qt
- Must NOT use pyqtSignal / QObject
- Must use pure Python (dataclass preferred)
- Must expose events using a custom Event class
- Model files must live under
models/ - Models import
Eventfrom their own package:from . import Event
Example:
2. Event System (REQUIRED)
Implement the shared Python callback system in models/__init__.py.
Example:
Minimal form:
3. Service (STRICT)
- Must NOT import Qt
-
Responsible for:
-
Threads / IO / ROS / external data
- Must update model only
- Must NOT touch View
- Must NOT emit Qt signals
- Service files must live under
services/ - Services may provide deterministic helper methods such as
generate_once()to support tests
Example:
4. View (STRICT)
- Only Qt widgets
- No logic
- No model access
- Expose user actions via Qt signals
- View files must live under
views/
Example:
5. Presenter (CRITICAL COMPONENT)
Responsibilities:
- Connect View ↔ Service
- Subscribe to Model events (Python callbacks)
- Convert Python callbacks → Qt signals
- Update View ONLY inside Qt slot
- Presenter files must live under
presenters/
Pattern:
6. Thread Safety (MANDATORY RULE)
NEVER update UI from:
- service
- model
- python callback
ALWAYS use:
7. Composition Root
All objects must be created in one place:
Rules:
- Keep references to presenters
- Do not create objects inside other classes implicitly
- Import models, services, views, and presenters from their dedicated packages
8. Data Flow Rules
- Service updates Model
- Model emits Python event
- Presenter listens
- Presenter emits Qt signal
- Presenter updates View
NO shortcuts allowed.
9. Forbidden Patterns
❌ Model inherits QObject ❌ Service uses Qt ❌ View accesses Model directly ❌ Presenter polls Model ❌ UI updated from background thread
10. Extensions
When generating advanced code, support:
- multiple services
- multiple presenters
- shared model
- background threads
- ROS / sockets / file IO
11. Tests + Mock Data (REQUIRED)
Every generated app must include a top-level tests/ folder.
Required test files:
Rules:
tests/mock_data.pycontains generated or mocked data for models.- Model tests must verify that mocked data is stored correctly.
- Model tests must verify that model events emit mocked data.
- Test code must not import Qt unless it is specifically testing a view or presenter.
- Prefer pure model tests first because they are fast and do not require a display server.
- Use standard-library
unittestunless the project already has a configured test runner.
Example:
Output Requirements
When generating code:
-
Always include:
-
Event class
- Model
- Service
- View
- Presenter
- Main / composition root
- Tests folder
- Mock model data
- Keep files modular using the required folder layout
- Use clear naming:
XModel,XService,XView,XPresenter
Goal
Produce scalable, thread-safe UI architecture suitable for:
- robotics dashboards
- streaming data visualization
- real-time monitoring systems