Events & Logging
karcytics_sdk.plugin.events
Central EventBus for Karcytics SDK.
Provides a singleton event bus using Qt signals to allow asynchronous and decoupled communication between different plugins and the core application.
karcytics_sdk.plugin.logging
Karcytics SDK Logging Utilities.
Provides Karcytics-aware loggers that automatically attach plugin metadata and route to the central diagnostic engine.
PluginLoggerAdapter
Bases: LoggerAdapter
Logger adapter that injects plugin_id into every log record.
Source code in src/karcytics_sdk/plugin/logging.py
__init__(logger, plugin_id)
Initialize the logger adapter with a specific plugin identifier.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
logger
|
Logger
|
The parent Python logger instance to adapt. |
required |
plugin_id
|
str
|
The unique identifier of the target plugin. |
required |
Source code in src/karcytics_sdk/plugin/logging.py
process(msg, kwargs)
Process log messages to inject the plugin metadata context.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
msg
|
The actual log message content. |
required | |
kwargs
|
Thread or level attributes associated with the log record. |
required |
Returns:
| Type | Description |
|---|---|
|
A tuple of (processed_message, kwargs) containing the updated extra dict. |
Source code in src/karcytics_sdk/plugin/logging.py
configure_plugin_logging(plugin_id, log_dir=None)
Give an isolated plugin worker its own durable, local log file.
Without this, an isolated worker's root logger has no handlers at all:
Python's own last-resort handler only ever prints WARNING+ to stderr, so
every .debug()/.info() call a plugin makes is silently dropped, not
just unrelayed. PluginDaemon._stderr_reader_loop on the Hub side only
tails whatever does reach stderr, and only the last 200 lines, so
nothing survives a crash on disk regardless. This adds a rotating file
handler under ~/.karcytics/logs/plugin_workers/<plugin_id>.log (kept
distinct from the Hub-relayed logs/plugins/<plugin_id>.log path so the
two processes never contend as concurrent writers on one file) and a
stderr handler so DEBUG+ actually reaches the existing relay too.
Idempotent — safe to call more than once for the same process.
Source code in src/karcytics_sdk/plugin/logging.py
get_logger(name, plugin_id=None)
Get a logger instance, optionally adapted for a specific plugin.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The name of the logger (usually name) |
required |
plugin_id
|
str | None
|
The ID of the plugin this logger belongs to |
None
|
Returns:
| Type | Description |
|---|---|
Logger | PluginLoggerAdapter
|
A logging.Logger or PluginLoggerAdapter instance. |
Source code in src/karcytics_sdk/plugin/logging.py
karcytics_sdk.plugin.signals
Standard plugin signals for Karcytics SDK.
This module defines all standard PySide6 signals that plugins should emit to communicate state changes and results to the Karcytics core application.
PluginSignals
Bases: QObject
Standard signals that all plugins emit.
Plugins should use these signals to ensure consistent communication with Karcytics core and other plugins.
Attributes:
| Name | Type | Description |
|---|---|---|
status_message |
Emitted with a short status string for the UI status bar |
|
log_message |
Emitted with detailed log messages |
|
state_changed |
Emitted when plugin state changes |
|
undo_available |
Emitted with bool indicating if undo is available |
|
redo_available |
Emitted with bool indicating if redo is available |
|
undo_state_changed |
Emitted after any change to the undo history — availability, the undo/redo labels, or the clean (saved) state |
|
analysis_started |
Emitted when analysis begins |
|
analysis_progress |
Emitted with int (0-100) for progress |
|
analysis_complete |
Emitted when analysis finishes |
|
analysis_error |
Emitted with error message if analysis fails |
|
data_changed |
Emitted when underlying data changes |
Source code in src/karcytics_sdk/plugin/signals.py
move_to_gui_thread(obj)
Give a newly built, parentless obj to the application's GUI thread.
Call it right after constructing a long-lived QObject that may be built
off the GUI thread (a lazy singleton first touched by a background
thread, or anything created from a plain threading.Thread). Under
PySide6, a slot that is not a bound QObject method (a lambda,
functools.partial) is delivered through the sender's thread; if that
thread has no running event loop, every such delivery is silently
dropped. Does nothing when no application exists yet or obj is already
on the GUI thread.
Source code in src/karcytics_sdk/plugin/signals.py
safe_disconnect(signal, slot=None)
Disconnect slot from signal, quietly doing nothing if it was not connected.
For the "disconnect, then connect" idiom that keeps a slot connected
exactly once. PySide6 reports a disconnect that finds nothing with a
RuntimeWarning (and, for a deleted sender, a RuntimeError); neither
is useful to a caller that only wants the slot gone.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
signal
|
Any
|
The bound signal, e.g. |
required |
slot
|
Callable[..., Any] | None
|
The slot to remove. |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
True if a connection was removed. |