API Reference
This section contains the complete API documentation for pyqt-reactive.
Core Modules
Core PyQt6 utilities. |
|
Widget protocol definitions and adapters. |
|
Service package for pyqt-reactive. |
|
Form generation and management package. |
|
Extended widget implementations. |
|
Theming and styling system. |
|
Reusable dialogs for PyQt FormGen. |
Module Documentation
pyqt_reactive.core
Core PyQt6 utilities with zero external dependencies.
Core PyQt6 utilities.
Pure PyQt6 utility components with zero external dependencies. Foundational widgets and helpers with no domain-specific logic.
- class pyqt_reactive.core.DebounceTimer(delay_ms: int, handler: Callable[[], None])[source]
Bases:
objectReusable trailing debounce timer.
Restarts timer on each call. Handler fires only after delay_ms of inactivity.
- Usage:
self._debounce = DebounceTimer(delay_ms=200, handler=self._do_update)
- def on_text_changed(self):
self._debounce.trigger() # Restarts timer
- class pyqt_reactive.core.ReorderableListWidget(parent=None)[source]
Bases:
QListWidgetCustom QListWidget that properly handles drag and drop reordering.
Emits a signal when items are moved so the parent can update the data model. This is a shared implementation used by both PipelineEditor and PlateManager.
- items_reordered
int = …, arguments: Sequence = …) -> PYQT_SIGNAL
types is normally a sequence of individual types. Each type is either a type object or a string that is the name of a C++ type. Alternatively each type could itself be a sequence of types each describing a different overloaded signal. name is the optional C++ name of the signal. If it is not specified then the name of the class attribute that is bound to the signal is used. revision is the optional revision of the signal that is exported to QML. If it is not specified then 0 is used. arguments is the optional sequence of the names of the signal’s arguments.
- Type:
pyqtSignal(*types, name
- Type:
str = …, revision
- class pyqt_reactive.core.BackgroundTask(target: Callable[[...], Any], args: Tuple = (), kwargs: dict = None, debounce_ms: int = 0, parent=None)[source]
Bases:
QThreadUnified background task with cancellation, debounce, and cleanup.
- Usage:
task = BackgroundTask(target=my_func, args=(a, b)) task.result_ready.connect(on_success) task.error_occurred.connect(on_error) # Receives Exception, not str task.start()
# Later: task.cancel() # Safe cancellation
- Error handling:
- def on_error(e: Exception):
logger.exception(“Failed”, exc_info=e) # Full traceback show_message(str(e)) # User-friendly string if isinstance(e, TimeoutError): … # Type checking
- result_ready
int = …, arguments: Sequence = …) -> PYQT_SIGNAL
types is normally a sequence of individual types. Each type is either a type object or a string that is the name of a C++ type. Alternatively each type could itself be a sequence of types each describing a different overloaded signal. name is the optional C++ name of the signal. If it is not specified then the name of the class attribute that is bound to the signal is used. revision is the optional revision of the signal that is exported to QML. If it is not specified then 0 is used. arguments is the optional sequence of the names of the signal’s arguments.
- Type:
pyqtSignal(*types, name
- Type:
str = …, revision
- error_occurred
int = …, arguments: Sequence = …) -> PYQT_SIGNAL
types is normally a sequence of individual types. Each type is either a type object or a string that is the name of a C++ type. Alternatively each type could itself be a sequence of types each describing a different overloaded signal. name is the optional C++ name of the signal. If it is not specified then the name of the class attribute that is bound to the signal is used. revision is the optional revision of the signal that is exported to QML. If it is not specified then 0 is used. arguments is the optional sequence of the names of the signal’s arguments.
- Type:
pyqtSignal(*types, name
- Type:
str = …, revision
- class pyqt_reactive.core.BackgroundTaskManager[source]
Bases:
objectManages background task lifecycle for a widget.
Handles: - Cancelling previous task before starting new one - Cleanup on widget close - Debounce across rapid calls - Button state management (disable during operation, auto-restore)
- Usage in widget:
self._task_manager = BackgroundTaskManager()
- def refresh_data(self):
- self._task_manager.run(
target=self.service.fetch_data, args=(self.query,), button=self.refresh_button, button_loading_text=”Loading…”, on_success=self._on_data_ready, on_error=self._on_error, debounce_ms=200
)
- def closeEvent(self, event):
self._task_manager.cleanup() super().closeEvent(event)
- run(target: Callable[[...], Any], args: Tuple = (), kwargs: dict = None, on_success: Callable[[Any], None] = None, on_error: Callable[[Exception], None] = None, debounce_ms: int = 0, button: QPushButton = None, button_loading_text: str = None) BackgroundTask | None[source]
Run a background task, cancelling any previous one.
- Parameters:
target – Function to execute in background
args – Positional arguments for target
kwargs – Keyword arguments for target
on_success – Callback for successful result
on_error – Callback for error (receives Exception, not str)
debounce_ms – Minimum time between runs (skip if too soon)
button – Button to disable during operation (auto-restored on complete)
button_loading_text – Text while loading (default: original + “…”)
- Returns:
BackgroundTask if started, None if debounced out
- class pyqt_reactive.core.CollapsibleSplitterHelper(splitter: QSplitter, left_panel_index: int = 0)[source]
Bases:
objectHelper for adding double-click toggle to splitter handles.
- class pyqt_reactive.core.RichTextAppender(text_edit: QTextEdit, color_scheme: ColorScheme = None)[source]
Bases:
objectUtility for appending HTML content to QTextEdit with proper cursor/scroll handling.
- Usage:
appender = RichTextAppender(self.chat_history, color_scheme=self.color_scheme) appender.append_html(“<b>User:</b> Hello”) appender.append_code(“def foo(): pass”) appender.append_error(“Something went wrong”)
- __init__(text_edit: QTextEdit, color_scheme: ColorScheme = None)[source]
- append_html(html_content: str, add_spacing: bool = True)[source]
Append HTML content at end, scroll to bottom.
- Parameters:
html_content – HTML string to append
add_spacing – Whether to add blank line after
- append_text(text: str, bold: bool = False, color: str | None = None)[source]
Append plain text (escaped) with optional styling.
- Parameters:
text – Plain text to append
bold – Whether to make text bold
color – Optional text color (hex)
pyqt_reactive.protocols
Widget protocol definitions and adapters for type-safe widget contracts.
Widget protocol definitions and adapters.
ABC-based widget contracts that eliminate duck typing in favor of explicit, fail-loud inheritance-based architecture.
- class pyqt_reactive.protocols.ValueGettable[source]
Bases:
ABCABC for widgets that can return a value.
All input widgets must implement this to participate in form value extraction.
- class pyqt_reactive.protocols.ValueSettable[source]
Bases:
ABCABC for widgets that can accept a value.
All input widgets must implement this to participate in form value updates.
- class pyqt_reactive.protocols.ResolvedValuePreviewSettable[source]
Bases:
ABCABC for widgets that render inherited/resolved values separately from raw edits.
Lazy dataclass container widgets may keep raw
Nonechild fields while previewing the resolved inherited dataclass. This contract lets form chrome refresh that preview without replacing the raw editable value.
- class pyqt_reactive.protocols.RawResolvedValueSettable[source]
Bases:
ABCABC for widgets that can atomically apply a raw value and resolved preview.
Lazy dataclass widgets can avoid rendering a raw intermediate state when a form refresh already has both ObjectState values available.
- class pyqt_reactive.protocols.ChildFieldChromeRefreshable[source]
Bases:
ABCABC for compound widgets that render chrome for their own child fields.
Inline dataclass widgets can own section labels/reset controls internally while still being edited as one form value. This contract lets the form manager refresh those child markers after ObjectState dirty/signature state changes without knowing widget-specific field names.
- class pyqt_reactive.protocols.ChildFieldSemanticChromeRefreshable[source]
Bases:
ABCABC for compound widgets that render semantic chrome for child leaves.
- class pyqt_reactive.protocols.ChildFieldIdentityProvider[source]
Bases:
ABCABC for compound widgets that expose nominal child ObjectState identity.
Bases:
ABCABC for compound widgets that expose concrete widgets for child fields.
Inline dataclass widgets may render their own child sections internally instead of creating nested ParameterFormManager instances. This contract lets generic form navigation scroll to the concrete child section while keeping the widget-specific layout private to the inline editor.
Return the widget that visually represents a child field, if present.
- Parameters:
field_name – Direct child field name inside the compound widget.
Bases:
ABCABC for compound widgets that expose structural descendant targets.
Return a concrete visual target for a child structural path.
An empty
relative_pathrepresents the child structural owner itself.
- class pyqt_reactive.protocols.InlineDataclassGroupBoxChromeProvider[source]
Bases:
ABCABC for inline dataclass value widgets that contribute container title chrome.
Regular nested dataclasses can move child widgets such as enableable checkboxes into the groupbox title row. Inline dataclass widgets do not have a nested ParameterFormManager, so they expose the same chrome through this contract while the container remains generic.
- class pyqt_reactive.protocols.InlineDataclassRootResettable[source]
Bases:
ABCABC for inline dataclass widgets that can reset their child fields.
- class pyqt_reactive.protocols.PlaceholderCapable[source]
Bases:
ABCABC for widgets that can display placeholder text.
Placeholders show inherited/default values without setting actual values.
- class pyqt_reactive.protocols.PlaceholderStateTrackable[source]
Bases:
WidgetCapabilityTaggedABC for widgets that own placeholder chrome/cache state.
- widget_capabilities: ClassVar[frozenset[WidgetCapability]] = frozenset({WidgetCapability.PLACEHOLDER_STATE})
- abstractmethod has_placeholder_state() bool[source]
Return whether placeholder chrome or cached placeholder data is present.
- abstractmethod mark_placeholder_state() None[source]
Mark the widget as currently displaying placeholder chrome.
- abstractmethod clear_placeholder_state() None[source]
Mark the widget as no longer displaying placeholder chrome.
- abstractmethod cached_placeholder_text() str | None[source]
Return cached placeholder text, if any.
- abstractmethod set_cached_placeholder_text(placeholder_text: str) None[source]
Cache placeholder text after a successful render.
- abstractmethod cached_placeholder_resolved_value() Any[source]
Return cached placeholder resolved value, if any.
- class pyqt_reactive.protocols.WidgetCapability(*values)[source]
-
Nominal widget capability tags for generic service-level queries.
- PLACEHOLDER_STATE = 'placeholder_state'
- class pyqt_reactive.protocols.WidgetCapabilityTagged[source]
Bases:
ABCBase for widget contracts that advertise generic capability tags.
- widget_capabilities: ClassVar[frozenset[WidgetCapability]] = frozenset({})
- pyqt_reactive.protocols.widget_capability_tags(widget_or_type: Any) frozenset[WidgetCapability][source]
Return all capability tags declared by a widget class and its bases.
- pyqt_reactive.protocols.widget_supports_capability(widget_or_type: Any, capability: WidgetCapability) bool[source]
Return whether a widget class declares a nominal capability tag.
- class pyqt_reactive.protocols.RangeConfigurable[source]
Bases:
ABCABC for widgets that support numeric range configuration.
Typically implemented by numeric input widgets (spinboxes, sliders).
- class pyqt_reactive.protocols.EnumSelectable[source]
Bases:
ABCABC for widgets that can select from enum values.
Typically implemented by dropdowns and radio button groups.
- class pyqt_reactive.protocols.ChangeSignalEmitter[source]
Bases:
ABCABC for widgets that emit change signals.
Provides explicit contract for signal connection, eliminating duck typing of signal names (textChanged vs valueChanged vs currentIndexChanged).
- abstractmethod connect_change_signal(callback: Callable[[Any], None]) None[source]
Connect callback to widget’s change signal.
The callback will be invoked whenever the widget’s value changes, receiving the new value as its argument.
- Parameters:
callback – Function to call when widget value changes. Signature: callback(new_value: Any) -> None
- class pyqt_reactive.protocols.LineEditAdapter(*args, **kwargs)[source]
Bases:
PlaceholderStateMixin,QLineEdit,ValueGettable,ValueSettable,PlaceholderCapable,ChangeSignalEmitterAdapter for QLineEdit implementing OpenHCS ABCs.
Normalizes Qt API to OpenHCS contracts: - .text() → .get_value() - .setText() → .set_value() - .setPlaceholderText() → .set_placeholder() - .textChanged → .connect_change_signal()
- class pyqt_reactive.protocols.SpinBoxAdapter(parent=None)[source]
Bases:
PlaceholderStateMixin,QSpinBox,ValueGettable,ValueSettable,PlaceholderCapable,RangeConfigurable,ChangeSignalEmitterAdapter for QSpinBox implementing OpenHCS ABCs.
Handles None values using special value text mechanism. When value is None, displays placeholder text at minimum value.
- class pyqt_reactive.protocols.DoubleSpinBoxAdapter(parent=None)[source]
Bases:
PlaceholderStateMixin,QDoubleSpinBox,ValueGettable,ValueSettable,PlaceholderCapable,RangeConfigurable,ChangeSignalEmitterAdapter for QDoubleSpinBox implementing OpenHCS ABCs.
Handles None values and floating-point ranges.
- class pyqt_reactive.protocols.ComboBoxAdapter(*args, **kwargs)[source]
Bases:
PlaceholderStateMixin,QComboBox,ValueGettable,ValueSettable,PlaceholderCapable,ChangeSignalEmitterAdapter for QComboBox implementing OpenHCS ABCs.
Stores actual values in itemData, not just display text. Supports enum population and selection.
- populate_enum(enum_type: type) None[source]
Populate combobox with enum values.
- Parameters:
enum_type – The Enum class to populate from
- class pyqt_reactive.protocols.CheckBoxAdapter(*args, **kwargs)[source]
Bases:
PlaceholderStateMixin,QCheckBox,ValueGettable,ValueSettable,ChangeSignalEmitterAdapter for QCheckBox implementing OpenHCS ABCs.
Returns bool values, treats None as False.
- class pyqt_reactive.protocols.PlaceholderStateMixin(*args, **kwargs)[source]
Bases:
PlaceholderStateTrackableNominal placeholder-state storage for Qt widget adapters.
- widget_capabilities: ClassVar[frozenset[WidgetCapability]] = frozenset({WidgetCapability.PLACEHOLDER_STATE})
- has_placeholder_state() bool[source]
Return whether placeholder chrome or cached placeholder data is present.
- set_cached_placeholder_text(placeholder_text: str) None[source]
Cache placeholder text after a successful render.
- class pyqt_reactive.protocols.PyQtWidgetMeta(name, bases, namespace, /, **kwargs)[source]
Bases:
wrappertype,ABCMetaMetaclass for PyQt widgets that need ABC support.
- class pyqt_reactive.protocols.FunctionRegistryProtocol(*args, **kwargs)[source]
Bases:
ProtocolProtocol for function registries that provide function lookup and metadata.
Applications can implement this protocol to provide their own function registry.
Example
from pyqt_reactive.protocols import register_function_registry from myapp.registry import MyFunctionRegistry
register_function_registry(MyFunctionRegistry())
- get_function_by_name(name: str) Callable | None[source]
Get function by name.
- Parameters:
name – Function name to lookup
- Returns:
Function callable if found, None otherwise
- get_all_functions() Dict[str, Callable][source]
Get all registered functions.
- Returns:
Dictionary mapping function names to callables
- get_function_metadata(name: str) Dict[str, Any] | None[source]
Get metadata for a function.
- Parameters:
name – Function name
- Returns:
Metadata dict if available, None otherwise
- __init__(*args, **kwargs)
- pyqt_reactive.protocols.register_function_registry(registry: FunctionRegistryProtocol) None[source]
Register a function registry implementation.
- Parameters:
registry – Object implementing FunctionRegistryProtocol
- pyqt_reactive.protocols.get_function_registry() FunctionRegistryProtocol | None[source]
Get the registered function registry.
- Returns:
Registered registry or None if not registered
- class pyqt_reactive.protocols.PreviewFormatterRegistry[source]
Bases:
objectRegistry for preview formatters by config type.
Applications can register formatters for specific config types to customize how fields are displayed in list item previews.
Example
from pyqt_reactive.protocols import PreviewFormatterRegistry
- def format_zarr_config(config, field_name):
- if field_name == ‘compression’:
return f”comp={config.compression[:3]}” # Abbreviate
return str(getattr(config, field_name))
PreviewFormatterRegistry.register(ZarrConfig, format_zarr_config)
- classmethod register(config_type: Type, formatter: Callable[[Any, str], str]) None[source]
Register a formatter for a config type.
- Parameters:
config_type – Config class to format
formatter – Formatter function taking (config, field_name) -> str
- pyqt_reactive.protocols.register_preview_formatter(config_type: Type, formatter: Callable[[Any, str], str]) None[source]
Register a preview formatter for a config type.
- Parameters:
config_type – Config class
formatter – Formatter function
- class pyqt_reactive.protocols.FormGenConfig(enable_placeholder_styling: bool = True, enable_help_buttons: bool = True, enable_inheritance_tracking: bool = True, custom_widget_factories: Type, ~typing.Any]=<factory>, jedi_project_paths: List[str] = <factory>, log_dir: str | None = None, log_prefixes: List[str] = <factory>, log_root_logger_name: str | None = None, performance_logger_name: str = 'pyqt_reactive.performance', performance_log_filename: str = 'performance.log', path_cache_file: str | None = None)[source]
Bases:
objectBase configuration for form generation behavior.
Applications can subclass this to provide custom configuration.
- custom_widget_factories
Custom widget factories by type
- Type:
Dict[Type, Any]
- __init__(enable_placeholder_styling: bool = True, enable_help_buttons: bool = True, enable_inheritance_tracking: bool = True, custom_widget_factories: Type, ~typing.Any]=<factory>, jedi_project_paths: List[str] = <factory>, log_dir: str | None = None, log_prefixes: List[str] = <factory>, log_root_logger_name: str | None = None, performance_logger_name: str = 'pyqt_reactive.performance', performance_log_filename: str = 'performance.log', path_cache_file: str | None = None) None
- pyqt_reactive.protocols.set_form_config(config: FormGenConfig) None[source]
Set the global form generation configuration.
- Parameters:
config – FormGenConfig instance
- pyqt_reactive.protocols.get_form_config() FormGenConfig[source]
Get the current form generation configuration.
- Returns:
Current FormGenConfig or default if not set
- class pyqt_reactive.protocols.LLMServiceProtocol(*args, **kwargs)[source]
Bases:
ProtocolProtocol for LLM services used by LLMChatPanel.
- generate_code(request: str, code_type: str | None = None) str[source]
Generate code for a request and optional code type.
- __init__(*args, **kwargs)
- pyqt_reactive.protocols.register_llm_service(service: LLMServiceProtocol) None[source]
Register a global LLM service implementation.
- pyqt_reactive.protocols.get_llm_service() LLMServiceProtocol | None[source]
Get the registered LLM service implementation.
- class pyqt_reactive.protocols.CodegenProvider(*args, **kwargs)[source]
Bases:
ProtocolProtocol for code generators used by the simple code editor.
- generate_complete_orchestrator_code(plate_paths: list[str], pipeline_data: dict, global_config: Any | None = None, per_plate_configs: dict | None = None, pipeline_config: Any | None = None, clean_mode: bool = True) str[source]
- generate_complete_pipeline_steps_code(pipeline_steps: list[Any], clean_mode: bool = True) str[source]
- generate_config_code(config_obj: Any, clean_mode: bool = True, config_class: type | None = None) str[source]
- __init__(*args, **kwargs)
- pyqt_reactive.protocols.register_codegen_provider(provider: CodegenProvider) None[source]
Register a global code generation provider.
- pyqt_reactive.protocols.get_codegen_provider() CodegenProvider | None[source]
Get the registered code generation provider.
- class pyqt_reactive.protocols.LogDiscoveryProvider(*args, **kwargs)[source]
Bases:
ProtocolProtocol for discovering log files and current log path.
- discover_logs(base_log_path: str | None = None, include_main_log: bool = True, log_directory: Path | None = None) List[LogFileInfo][source]
Return discovered logs.
- __init__(*args, **kwargs)
- class pyqt_reactive.protocols.ServerScanProvider(*args, **kwargs)[source]
Bases:
ProtocolProtocol for discovering server logs (e.g., via port scans).
- scan_for_server_logs() List[LogFileInfo][source]
Return logs discovered from live servers.
- __init__(*args, **kwargs)
- pyqt_reactive.protocols.register_log_discovery_provider(provider: LogDiscoveryProvider) None[source]
Register a global log discovery provider.
- pyqt_reactive.protocols.get_log_discovery_provider() LogDiscoveryProvider | None[source]
Get the registered log discovery provider.
- pyqt_reactive.protocols.register_server_scan_provider(provider: ServerScanProvider) None[source]
Register a global server scan provider.
- pyqt_reactive.protocols.get_server_scan_provider() ServerScanProvider | None[source]
Get the registered server scan provider.
- class pyqt_reactive.protocols.WindowFactoryProtocol(*args, **kwargs)[source]
Bases:
ProtocolProtocol for creating windows for a given scope.
Use this for duck-typed checking. For implementation, prefer WindowFactoryABC.
- create_window_for_scope(scope_id: str, object_state: ObjectState | None = None) QWidget | None[source]
Create and show a window for the given scope id.
- __init__(*args, **kwargs)
- class pyqt_reactive.protocols.WindowFactoryABC[source]
Bases:
ABCAbstract base class for window factories.
Subclass this to implement application-specific window creation logic. The factory is responsible for: - Parsing scope_id format to determine window type - Creating the appropriate window class - Showing and activating the window
- abstractmethod create_window_for_scope(scope_id: str, object_state: ObjectState | None = None) QWidget | None[source]
Create and show a window for the given scope_id.
- Parameters:
scope_id – Scope identifier. Format is application-specific, e.g.: - “” (empty string): Global config - “/path/to/item”: Item-level config - “/path/to/item::sub”: Nested scope
object_state – Optional ObjectState for time-travel restore
- Returns:
The created window, or None if creation failed/skipped
- pyqt_reactive.protocols.register_window_factory(factory: WindowFactoryProtocol) None[source]
Register a global window factory.
- Parameters:
factory – Factory instance implementing WindowFactoryProtocol or WindowFactoryABC
- pyqt_reactive.protocols.get_window_factory() WindowFactoryProtocol | None[source]
Get the registered window factory.
- class pyqt_reactive.protocols.ComponentSelectionProvider(*args, **kwargs)[source]
Bases:
ProtocolProtocol for component selection and display metadata.
- get_component_keys(group_by: Any) List[str][source]
Return available component keys for a given group_by.
- has_components_available(group_by: Any) bool[source]
Check if components are available for the given group_by without fetching them all.
Used to determine if UI elements (like component selection buttons) should be enabled. Should return False if the underlying data source (e.g., orchestrator) is not ready.
- get_component_display_name(group_by: Any, component_key: str) str | None[source]
Return a human-readable name for a component key.
- select_components(available_components: Iterable[str], selected_components: Iterable[str], group_by: Any, parent: Any | None = None, **context: Any) List[str] | None[source]
Show selection UI and return chosen components (or None if canceled).
- __init__(*args, **kwargs)
- class pyqt_reactive.protocols.FunctionSelectionProvider(*args, **kwargs)[source]
Bases:
ProtocolProtocol for selecting a function in UI.
- select_function(parent: Any | None = None, **context: Any) Callable | None[source]
Return a selected function or None.
- __init__(*args, **kwargs)
- pyqt_reactive.protocols.register_component_selection_provider(provider: ComponentSelectionProvider) None[source]
Register a global component selection provider.
- pyqt_reactive.protocols.get_component_selection_provider() ComponentSelectionProvider | None[source]
Get the registered component selection provider.
- pyqt_reactive.protocols.register_function_selection_provider(provider: FunctionSelectionProvider) None[source]
Register a global function selection provider.
- pyqt_reactive.protocols.get_function_selection_provider() FunctionSelectionProvider | None[source]
Get the registered function selection provider.
pyqt_reactive.services
Service layer for form management and cross-cutting concerns.
Service package for pyqt-reactive.
Import service APIs from their owning submodules. Keeping this package initializer side-effect free prevents service/form import cycles.
pyqt_reactive.forms
Form generation and management from dataclasses.
Form generation and management package.
Import concrete form APIs from their owning submodules. Keeping this package initializer side-effect free prevents form/service import cycles.
pyqt_reactive.widgets
Extended widget implementations with enhanced behavior.
Extended widget implementations.
Specialized widget subclasses that build on the protocol layer with enhanced behavior.
- class pyqt_reactive.widgets.NoScrollSpinBox(parent=None)[source]
Bases:
IgnoreWheelEventMixin,SpinBoxAdapterSpinBox that ignores wheel events to prevent accidental value changes.
Inherits from SpinBoxAdapter which already implements ValueGettable/ValueSettable ABCs.
- class pyqt_reactive.widgets.NoScrollDoubleSpinBox(parent=None)[source]
Bases:
IgnoreWheelEventMixin,DoubleSpinBoxAdapterDoubleSpinBox that ignores wheel events to prevent accidental value changes.
Inherits from DoubleSpinBoxAdapter which already implements ValueGettable/ValueSettable ABCs.
- class pyqt_reactive.widgets.NoScrollComboBox(parent=None, placeholder='')[source]
Bases:
IgnoreWheelEventMixin,ComboBoxAdapterComboBox that ignores wheel events to prevent accidental value changes.
Inherits from ComboBoxAdapter which already implements ValueGettable/ValueSettable ABCs. Supports placeholder text when currentIndex == -1 (for None values).
- class pyqt_reactive.widgets.NoneAwareCheckBox(parent=None)[source]
Bases:
PlaceholderStateMixin,QCheckBox,ValueGettable,ValueSettable,ResolvedValuePreviewSettable,ChangeSignalEmitterQCheckBox that supports None state for lazy dataclass contexts.
Shows inherited value as grayed placeholder when value is None. Clicking converts placeholder to explicit value.
- PLACEHOLDER_PAINT_OPACITY = 0.45
- connect_change_signal(callback: Callable[[bool | None], None]) None[source]
Implement ChangeSignalEmitter ABC.
- disconnect_change_signal(callback: Callable[[bool | None], None]) None[source]
Implement ChangeSignalEmitter ABC.
- set_placeholder_preview(checked: bool) None[source]
Display an inherited checkbox value without making it concrete.
- set_resolved_value_preview(value) None[source]
Display an inherited resolved bool while preserving raw None.
- class pyqt_reactive.widgets.StatusIndicator(check_fn: Callable[[], Tuple[bool, str]] = None, color_scheme: ColorScheme = None, show_refresh: bool = True, debounce_ms: int = 2000, parent=None)[source]
Bases:
QWidgetReusable status indicator with colored dot, label, and refresh button.
- Usage:
- indicator = StatusIndicator(
check_fn=lambda: my_service.test_connection(), color_scheme=self.color_scheme, parent=self
) layout.addWidget(indicator)
# check_fn returns Tuple[bool, str]: (is_ok, status_message) # True → CONNECTED state, False → DISCONNECTED state
- __init__(check_fn: Callable[[], Tuple[bool, str]] = None, color_scheme: ColorScheme = None, show_refresh: bool = True, debounce_ms: int = 2000, parent=None)[source]
- set_state(state: StatusState, message: str = None)[source]
Update visual state.
- class pyqt_reactive.widgets.StatusState(*values)[source]
Bases:
EnumStatus indicator states — colors resolved from color scheme at runtime.
- UNKNOWN = 'Unknown'
- CHECKING = 'Checking...'
- CONNECTED = 'connected'
- DISCONNECTED = 'disconnected'
- WARNING = 'warning'
- pyqt_reactive.widgets.get_status_color(state: StatusState, color_scheme: ColorScheme) str[source]
Resolve status state to color from scheme.
pyqt_reactive.theming
Color schemes and styling system for dynamic theme switching.
Theming and styling system.
Color schemes, palette management, and stylesheet generation for consistent application-wide theming.
- class pyqt_reactive.theming.ColorScheme(window_bg: Tuple[int, int, int] = (43, 43, 43), panel_bg: Tuple[int, int, int] = (30, 30, 30), frame_bg: Tuple[int, int, int] = (43, 43, 43), border_color: Tuple[int, int, int] = (85, 85, 85), border_light: Tuple[int, int, int] = (102, 102, 102), separator_color: Tuple[int, int, int] = (51, 51, 51), text_primary: Tuple[int, int, int] = (255, 255, 255), text_secondary: Tuple[int, int, int] = (204, 204, 204), text_accent: Tuple[int, int, int] = (0, 170, 255), text_disabled: Tuple[int, int, int] = (102, 102, 102), button_normal_bg: Tuple[int, int, int] = (64, 64, 64), button_hover_bg: Tuple[int, int, int] = (80, 80, 80), button_pressed_bg: Tuple[int, int, int] = (48, 48, 48), button_disabled_bg: Tuple[int, int, int] = (42, 42, 42), button_text: Tuple[int, int, int] = (255, 255, 255), button_disabled_text: Tuple[int, int, int] = (102, 102, 102), input_bg: Tuple[int, int, int] = (64, 64, 64), input_border: Tuple[int, int, int] = (102, 102, 102), input_text: Tuple[int, int, int] = (255, 255, 255), input_focus_border: Tuple[int, int, int] = (0, 170, 255), selection_bg: Tuple[int, int, int] = (0, 120, 212), selection_text: Tuple[int, int, int] = (255, 255, 255), hover_bg: Tuple[int, int, int] = (51, 51, 51), focus_outline: Tuple[int, int, int] = (0, 170, 255), search_highlight_bg: Tuple[int, int, int, int] = (255, 255, 0, 100), search_highlight_text: Tuple[int, int, int] = (0, 0, 0), status_success: Tuple[int, int, int] = (0, 255, 0), status_warning: Tuple[int, int, int] = (255, 170, 0), status_error: Tuple[int, int, int] = (255, 0, 0), status_info: Tuple[int, int, int] = (0, 170, 255), progress_bg: Tuple[int, int, int] = (30, 30, 30), progress_fill: Tuple[int, int, int] = (0, 120, 212), activity_indicator: Tuple[int, int, int] = (0, 170, 255), log_critical_fg: Tuple[int, int, int] = (255, 255, 255), log_critical_bg: Tuple[int, int, int] = (139, 0, 0), log_error_color: Tuple[int, int, int] = (255, 85, 85), log_warning_color: Tuple[int, int, int] = (255, 140, 0), log_info_color: Tuple[int, int, int] = (100, 160, 210), log_debug_color: Tuple[int, int, int] = (160, 160, 160), timestamp_color: Tuple[int, int, int] = (105, 105, 105), logger_name_color: Tuple[int, int, int] = (147, 112, 219), memory_address_color: Tuple[int, int, int] = (255, 182, 193), file_path_color: Tuple[int, int, int] = (34, 139, 34), python_keyword_color: Tuple[int, int, int] = (86, 156, 214), python_string_color: Tuple[int, int, int] = (206, 145, 120), python_number_color: Tuple[int, int, int] = (181, 206, 168), python_operator_color: Tuple[int, int, int] = (212, 212, 212), python_name_color: Tuple[int, int, int] = (156, 220, 254), python_function_color: Tuple[int, int, int] = (220, 220, 170), python_class_color: Tuple[int, int, int] = (78, 201, 176), python_builtin_color: Tuple[int, int, int] = (86, 156, 214), python_comment_color: Tuple[int, int, int] = (106, 153, 85), exception_color: Tuple[int, int, int] = (255, 69, 0), function_call_color: Tuple[int, int, int] = (255, 215, 0), boolean_color: Tuple[int, int, int] = (86, 156, 214), tuple_parentheses_color: Tuple[int, int, int] = (255, 215, 0), set_braces_color: Tuple[int, int, int] = (255, 140, 0), class_representation_color: Tuple[int, int, int] = (78, 201, 176), function_representation_color: Tuple[int, int, int] = (220, 220, 170), module_path_color: Tuple[int, int, int] = (147, 112, 219), hex_number_color: Tuple[int, int, int] = (181, 206, 168), scientific_notation_color: Tuple[int, int, int] = (181, 206, 168), binary_number_color: Tuple[int, int, int] = (181, 206, 168), octal_number_color: Tuple[int, int, int] = (181, 206, 168), python_special_color: Tuple[int, int, int] = (255, 20, 147), single_quoted_string_color: Tuple[int, int, int] = (206, 145, 120), list_comprehension_color: Tuple[int, int, int] = (156, 220, 254), generator_expression_color: Tuple[int, int, int] = (156, 220, 254))[source]
Bases:
objectComprehensive color scheme for OpenHCS PyQt6 GUI with semantic color names.
Extends the LogColorScheme pattern to cover all GUI components including windows, dialogs, widgets, and interactive elements. Supports light/dark theme variants and ensures WCAG accessibility compliance.
All colors meet minimum 4.5:1 contrast ratio for normal text readability.
- to_qcolor(color_tuple: Tuple[int, int, int]) QColor[source]
Convert RGB tuple to QColor object.
- Parameters:
color_tuple – RGB color tuple (r, g, b)
- Returns:
Qt color object
- Return type:
QColor
- to_qcolor_rgba(color_tuple: Tuple[int, int, int, int]) QColor[source]
Convert RGBA tuple to QColor object.
- Parameters:
color_tuple – RGBA color tuple (r, g, b, a)
- Returns:
Qt color object with alpha
- Return type:
QColor
- to_hex(color_tuple: Tuple[int, int, int]) str[source]
Convert RGB tuple to hex color string.
- Parameters:
color_tuple – RGB color tuple (r, g, b)
- Returns:
Hex color string (e.g., “#ff0000”)
- Return type:
- classmethod create_dark_theme() PyQt6ColorScheme[source]
Create a dark theme variant with adjusted colors for dark backgrounds.
This is the default theme, so most colors remain the same with minor adjustments for better contrast on dark backgrounds.
- Returns:
Dark theme color scheme with enhanced contrast
- Return type:
PyQt6ColorScheme
- classmethod create_light_theme() PyQt6ColorScheme[source]
Create a light theme variant with adjusted colors for light backgrounds.
All colors are adjusted to maintain WCAG 4.5:1 contrast ratio on light backgrounds while preserving the semantic meaning and visual hierarchy.
- Returns:
Light theme color scheme with appropriate contrast
- Return type:
PyQt6ColorScheme
- classmethod load_color_scheme_from_config(config_path: str = None) PyQt6ColorScheme[source]
Load color scheme from external configuration file.
- Parameters:
config_path – Path to JSON config file (optional)
- Returns:
Loaded color scheme or default if file not found
- Return type:
PyQt6ColorScheme
- validate_wcag_contrast(foreground: Tuple[int, int, int], background: Tuple[int, int, int], min_ratio: float = 4.5) bool[source]
Validate WCAG contrast ratio between foreground and background colors.
- Parameters:
foreground – Foreground color RGB tuple
background – Background color RGB tuple
min_ratio – Minimum contrast ratio (default: 4.5 for normal text)
- Returns:
True if contrast ratio meets minimum requirement
- Return type:
- get_color_dict() Dict[str, Tuple[int, int, int]][source]
Get all colors as a dictionary for serialization or inspection.
- save_to_json(config_path: str) bool[source]
Save color scheme to JSON configuration file.
- Parameters:
config_path – Path to save JSON config file
- Returns:
True if save successful, False otherwise
- Return type:
- __init__(window_bg: Tuple[int, int, int] = (43, 43, 43), panel_bg: Tuple[int, int, int] = (30, 30, 30), frame_bg: Tuple[int, int, int] = (43, 43, 43), border_color: Tuple[int, int, int] = (85, 85, 85), border_light: Tuple[int, int, int] = (102, 102, 102), separator_color: Tuple[int, int, int] = (51, 51, 51), text_primary: Tuple[int, int, int] = (255, 255, 255), text_secondary: Tuple[int, int, int] = (204, 204, 204), text_accent: Tuple[int, int, int] = (0, 170, 255), text_disabled: Tuple[int, int, int] = (102, 102, 102), button_normal_bg: Tuple[int, int, int] = (64, 64, 64), button_hover_bg: Tuple[int, int, int] = (80, 80, 80), button_pressed_bg: Tuple[int, int, int] = (48, 48, 48), button_disabled_bg: Tuple[int, int, int] = (42, 42, 42), button_text: Tuple[int, int, int] = (255, 255, 255), button_disabled_text: Tuple[int, int, int] = (102, 102, 102), input_bg: Tuple[int, int, int] = (64, 64, 64), input_border: Tuple[int, int, int] = (102, 102, 102), input_text: Tuple[int, int, int] = (255, 255, 255), input_focus_border: Tuple[int, int, int] = (0, 170, 255), selection_bg: Tuple[int, int, int] = (0, 120, 212), selection_text: Tuple[int, int, int] = (255, 255, 255), hover_bg: Tuple[int, int, int] = (51, 51, 51), focus_outline: Tuple[int, int, int] = (0, 170, 255), search_highlight_bg: Tuple[int, int, int, int] = (255, 255, 0, 100), search_highlight_text: Tuple[int, int, int] = (0, 0, 0), status_success: Tuple[int, int, int] = (0, 255, 0), status_warning: Tuple[int, int, int] = (255, 170, 0), status_error: Tuple[int, int, int] = (255, 0, 0), status_info: Tuple[int, int, int] = (0, 170, 255), progress_bg: Tuple[int, int, int] = (30, 30, 30), progress_fill: Tuple[int, int, int] = (0, 120, 212), activity_indicator: Tuple[int, int, int] = (0, 170, 255), log_critical_fg: Tuple[int, int, int] = (255, 255, 255), log_critical_bg: Tuple[int, int, int] = (139, 0, 0), log_error_color: Tuple[int, int, int] = (255, 85, 85), log_warning_color: Tuple[int, int, int] = (255, 140, 0), log_info_color: Tuple[int, int, int] = (100, 160, 210), log_debug_color: Tuple[int, int, int] = (160, 160, 160), timestamp_color: Tuple[int, int, int] = (105, 105, 105), logger_name_color: Tuple[int, int, int] = (147, 112, 219), memory_address_color: Tuple[int, int, int] = (255, 182, 193), file_path_color: Tuple[int, int, int] = (34, 139, 34), python_keyword_color: Tuple[int, int, int] = (86, 156, 214), python_string_color: Tuple[int, int, int] = (206, 145, 120), python_number_color: Tuple[int, int, int] = (181, 206, 168), python_operator_color: Tuple[int, int, int] = (212, 212, 212), python_name_color: Tuple[int, int, int] = (156, 220, 254), python_function_color: Tuple[int, int, int] = (220, 220, 170), python_class_color: Tuple[int, int, int] = (78, 201, 176), python_builtin_color: Tuple[int, int, int] = (86, 156, 214), python_comment_color: Tuple[int, int, int] = (106, 153, 85), exception_color: Tuple[int, int, int] = (255, 69, 0), function_call_color: Tuple[int, int, int] = (255, 215, 0), boolean_color: Tuple[int, int, int] = (86, 156, 214), tuple_parentheses_color: Tuple[int, int, int] = (255, 215, 0), set_braces_color: Tuple[int, int, int] = (255, 140, 0), class_representation_color: Tuple[int, int, int] = (78, 201, 176), function_representation_color: Tuple[int, int, int] = (220, 220, 170), module_path_color: Tuple[int, int, int] = (147, 112, 219), hex_number_color: Tuple[int, int, int] = (181, 206, 168), scientific_notation_color: Tuple[int, int, int] = (181, 206, 168), binary_number_color: Tuple[int, int, int] = (181, 206, 168), octal_number_color: Tuple[int, int, int] = (181, 206, 168), python_special_color: Tuple[int, int, int] = (255, 20, 147), single_quoted_string_color: Tuple[int, int, int] = (206, 145, 120), list_comprehension_color: Tuple[int, int, int] = (156, 220, 254), generator_expression_color: Tuple[int, int, int] = (156, 220, 254)) None
- class pyqt_reactive.theming.ColorSchemeResolution(provided_scheme: ColorScheme | None)[source]
Bases:
objectResolve an optional caller-provided color scheme into a concrete scheme.
- provided_scheme: ColorScheme | None
- resolve() ColorScheme[source]
- __init__(provided_scheme: ColorScheme | None) None
- class pyqt_reactive.theming.WidgetTheme(scheme: ColorScheme, styles: StyleSheetGenerator)[source]
Bases:
objectResolved theme surface for widgets that need colors and stylesheets.
- scheme: ColorScheme
- styles: StyleSheetGenerator
- classmethod from_optional(provided_scheme: ColorScheme | None) WidgetTheme[source]
- __init__(scheme: ColorScheme, styles: StyleSheetGenerator) None
- class pyqt_reactive.theming.PaletteManager(color_scheme: ColorScheme)[source]
Bases:
objectManages QPalette integration with ColorScheme.
Provides methods to apply color schemes to Qt’s palette system, enabling system-wide theming and consistent color application.
- __init__(color_scheme: ColorScheme)[source]
Initialize the palette manager with a color scheme.
- Parameters:
color_scheme – ColorScheme instance to use for palette generation
- update_color_scheme(color_scheme: ColorScheme)[source]
Update the color scheme used for palette generation.
- Parameters:
color_scheme – New ColorScheme instance
- create_palette() QPalette[source]
Create a QPalette from the current color scheme.
- Returns:
Configured palette with color scheme colors
- Return type:
QPalette
- apply_palette_to_application(app: QApplication | None = None)[source]
Apply the color scheme palette to the entire application.
- Parameters:
app – QApplication instance (uses QApplication.instance() if None)
- class pyqt_reactive.theming.ThemeManager(initial_color_scheme: ColorScheme | None = None)[source]
Bases:
objectHigh-level theme management for the entire application.
Coordinates color scheme, style sheet generation, and palette management to provide seamless theme switching capabilities.
- __init__(initial_color_scheme: ColorScheme | None = None)[source]
Initialize the theme manager.
- Parameters:
initial_color_scheme – Initial color scheme (defaults to dark theme)
- apply_color_scheme(color_scheme: ColorScheme)[source]
Apply a new color scheme to the entire application.
- Parameters:
color_scheme – New ColorScheme to apply
- register_theme_change_callback(callback)[source]
Register a callback to be called when theme changes.
- Parameters:
callback – Function to call with new color scheme
- unregister_theme_change_callback(callback)[source]
Unregister a theme change callback.
- Parameters:
callback – Function to remove from callbacks
- get_current_style_sheet() str[source]
Get the current complete application style sheet.
- Returns:
Complete QStyleSheet for current theme
- Return type:
- class pyqt_reactive.theming.StyleSheetGenerator(color_scheme: ColorScheme)[source]
Bases:
objectGenerates QStyleSheet strings from ColorScheme objects.
Provides methods to generate complete stylesheets for different widget types, replacing hardcoded colors with centralized color scheme references.
- __init__(color_scheme: ColorScheme)[source]
Initialize the style generator with a color scheme.
- Parameters:
color_scheme – ColorScheme instance to use for styling
- update_color_scheme(color_scheme: ColorScheme)[source]
Update the color scheme used for style generation.
- Parameters:
color_scheme – New ColorScheme instance
- generate_dialog_style() str[source]
Generate QStyleSheet for dialog windows.
- Returns:
Complete QStyleSheet for dialog styling
- Return type:
- generate_tree_widget_style() str[source]
Generate QStyleSheet for tree widgets and list widgets.
- Returns:
Complete QStyleSheet for tree/list widget styling
- Return type:
- generate_list_widget_style() str[source]
Alias for generate_tree_widget_style (includes QListWidget styling).
- generate_table_widget_style() str[source]
Generate QStyleSheet for table widgets.
- Returns:
Complete QStyleSheet for table widget styling
- Return type:
- generate_button_style() str[source]
Generate QStyleSheet for buttons with all states.
- Returns:
Complete QStyleSheet for button styling
- Return type:
- generate_combobox_style() str[source]
Generate QStyleSheet for combo boxes with dropdown styling.
- Returns:
Complete QStyleSheet for combo box styling
- Return type:
- generate_progress_bar_style() str[source]
Generate QStyleSheet for progress bars.
- Returns:
Complete QStyleSheet for progress bar styling
- Return type:
- generate_frame_style() str[source]
Generate QStyleSheet for frames and panels.
- Returns:
Complete QStyleSheet for frame styling
- Return type:
- generate_tab_widget_style() str[source]
Generate QStyleSheet for tab widgets.
- Returns:
Complete QStyleSheet for tab widget styling
- Return type:
- generate_system_monitor_style() str[source]
Generate QStyleSheet for system monitor widget.
- Returns:
Complete QStyleSheet for system monitor styling
- Return type:
- generate_complete_application_style() str[source]
Generate complete application-wide QStyleSheet.
- Returns:
Complete QStyleSheet for entire application
- Return type:
- generate_config_window_style() str[source]
Generate QStyleSheet for configuration windows with button panel.
- Returns:
Complete QStyleSheet for config window styling
- Return type:
- generate_config_button_styles() dict[str, str][source]
Generate individual button styles for config window buttons.
- Returns:
Dictionary with button styles for generic, reset, cancel, save
- Return type:
- generate_scope_accent_button_style(accent_color: QColor) str[source]
Generate a scoped accent button style using this theme’s button states.
- require_config_button_style(style_name: str) str[source]
Return a named config button style or fail on an undeclared style key.
pyqt_reactive.animation
Flash animations and visual feedback system.
pyqt_reactive.windows
Window management and scoped window registry.
pyqt_reactive.dialogs
Dialog components and utilities.
Reusable dialogs for PyQt FormGen.