karcytics-sdk 2.0.0__tar.gz
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.
- karcytics_sdk-2.0.0/PKG-INFO +156 -0
- karcytics_sdk-2.0.0/README.md +134 -0
- karcytics_sdk-2.0.0/pyproject.toml +112 -0
- karcytics_sdk-2.0.0/setup.cfg +4 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/__init__.py +10 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/cli/__init__.py +0 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/cli/commands/__init__.py +0 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/cli/commands/diagnostics.py +81 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/cli/commands/migrate.py +112 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/cli/commands/scaffold.py +450 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/cli/commands/security.py +109 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/cli/main.py +43 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/contrib/__init__.py +38 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/contrib/image_utils.py +682 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/host/__init__.py +40 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/host/ai.py +421 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/host/core_services.py +160 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/host/docs.py +45 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/host/marketplace_cache.py +157 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/host/sign_plugin.py +478 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/host/trust_manager.py +487 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/host/trust_overrides.py +113 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/host/trust_path.py +71 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/host/trust_storage.py +102 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/interfaces/__init__.py +5 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/interfaces/i_event_bus.py +15 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/interfaces/i_logger.py +26 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/interfaces/i_task_scheduler.py +17 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/__init__.py +137 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/analysis.py +207 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/base.py +347 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/components.py +671 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/context.py +29 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/daemon.py +693 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/dialogs.py +259 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/events.py +85 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/interfaces.py +46 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/io.py +189 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/logging.py +53 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/managed_task.py +48 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/manifest.py +32 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/manifest_parser.py +78 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/preferences.py +37 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/ribbon.py +81 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/security_parser.py +78 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/signals.py +45 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/state.py +57 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/theme_fallback.py +95 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/validation.py +114 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/wizard.py +443 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/plugin/workflow.py +74 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/py.typed +1 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/sdk_cli.py +119 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/testing/__init__.py +3 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk/testing/contract.py +72 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk.egg-info/PKG-INFO +156 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk.egg-info/SOURCES.txt +73 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk.egg-info/dependency_links.txt +1 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk.egg-info/entry_points.txt +2 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk.egg-info/requires.txt +13 -0
- karcytics_sdk-2.0.0/src/karcytics_sdk.egg-info/top_level.txt +1 -0
- karcytics_sdk-2.0.0/tests/test_host_ai.py +195 -0
- karcytics_sdk-2.0.0/tests/test_host_security.py +463 -0
- karcytics_sdk-2.0.0/tests/test_image_utils.py +176 -0
- karcytics_sdk-2.0.0/tests/test_marketplace_cache.py +90 -0
- karcytics_sdk-2.0.0/tests/test_namespaces.py +30 -0
- karcytics_sdk-2.0.0/tests/test_plugin_architecture.py +56 -0
- karcytics_sdk-2.0.0/tests/test_plugin_ribbon.py +42 -0
- karcytics_sdk-2.0.0/tests/test_plugin_state.py +172 -0
- karcytics_sdk-2.0.0/tests/test_plugin_ui.py +562 -0
- karcytics_sdk-2.0.0/tests/test_sdk_cli.py +57 -0
- karcytics_sdk-2.0.0/tests/test_sign_plugin.py +161 -0
- karcytics_sdk-2.0.0/tests/test_testing_contract.py +74 -0
- karcytics_sdk-2.0.0/tests/test_theme_fallback.py +20 -0
- karcytics_sdk-2.0.0/tests/test_workflow_context.py +67 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: karcytics-sdk
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Software Development Kit and CLI for Karcytics.
|
|
5
|
+
Author: Kalaimaran Balasothy
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: Operating System :: OS Independent
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: cryptography>=41.0.0
|
|
11
|
+
Requires-Dist: msgpack>=1.0.0
|
|
12
|
+
Requires-Dist: numpy
|
|
13
|
+
Requires-Dist: pandas
|
|
14
|
+
Requires-Dist: pillow>=12.3.0
|
|
15
|
+
Requires-Dist: PyQt6>=6.5.0
|
|
16
|
+
Requires-Dist: requests>=2.28.0
|
|
17
|
+
Requires-Dist: scikit-image>=0.26.0
|
|
18
|
+
Requires-Dist: scipy
|
|
19
|
+
Provides-Extra: docs
|
|
20
|
+
Requires-Dist: mkdocs-material; extra == "docs"
|
|
21
|
+
Requires-Dist: mkdocstrings[python]; extra == "docs"
|
|
22
|
+
|
|
23
|
+
# 🔌 Karcytics SDK
|
|
24
|
+
|
|
25
|
+
[](https://KalaimaranB.github.io/Karcytics-SDK/)
|
|
26
|
+
[](https://github.com/KalaimaranB/Karcytics-SDK/actions)
|
|
27
|
+
[](https://github.com/KalaimaranB/Karcytics-SDK/blob/main/LICENSE)
|
|
28
|
+
|
|
29
|
+
The Software Development Kit (SDK) and Command-Line Interface (CLI) for building, validating, and signing plugins for the **Karcytics** desktop scientific suite.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 🚀 Key Features
|
|
34
|
+
|
|
35
|
+
- **Decoupled Architecture**: Build and test PyQt6-based scientific plugins independently of the main desktop app.
|
|
36
|
+
- **Fail-Safe Dynamic Theme Fallbacks**: Visual components automatically load custom HSL-tailored colors when running standalone inside CI/CD test gates or external visualizers.
|
|
37
|
+
- **Merkle-Tree Cryptographic Integrity**: Built-in Ed25519 signing and verification tools to secure user environments against remote execution and tampering.
|
|
38
|
+
- **PyPI-Ready Packaging**: Complete declarative `pyproject.toml` config, built to publish natively under the `karcytics-sdk` package.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 🛠️ Installation
|
|
43
|
+
|
|
44
|
+
Install the SDK directly into your plugin's virtual environment:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install karcytics-sdk
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
*(Or during development, install in editable mode):*
|
|
51
|
+
```bash
|
|
52
|
+
git clone https://github.com/KalaimaranB/Karcytics-SDK.git
|
|
53
|
+
cd Karcytics-SDK
|
|
54
|
+
pip install -e .
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 📦 Creating a Custom Karcytics Plugin
|
|
60
|
+
|
|
61
|
+
To build a valid plugin, implement the `KarcyticsPlugin` interface and declare your entrypoints.
|
|
62
|
+
|
|
63
|
+
### 1. `manifest.json`
|
|
64
|
+
Every plugin must include a manifest file in its root directory:
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"id": "my_custom_plugin",
|
|
68
|
+
"name": "My Custom Plugin",
|
|
69
|
+
"version": "1.0.0",
|
|
70
|
+
"author": "Dr. Kalaimaran",
|
|
71
|
+
"description": "High-performance scientific analysis plugin.",
|
|
72
|
+
"category": "analysis",
|
|
73
|
+
"min_core_version": "1.0.0",
|
|
74
|
+
"entrypoint": "plugin:MyPluginClass"
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 2. `plugin.py`
|
|
79
|
+
```python
|
|
80
|
+
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel
|
|
81
|
+
from karcytics_sdk.core.interfaces import KarcyticsPlugin
|
|
82
|
+
from karcytics_sdk.ui import PrimaryButton
|
|
83
|
+
|
|
84
|
+
class MyPluginClass(KarcyticsPlugin):
|
|
85
|
+
"""A professional-grade Karcytics plugin."""
|
|
86
|
+
|
|
87
|
+
def initialize(self) -> None:
|
|
88
|
+
self.logger.info("Initializing custom plugin...")
|
|
89
|
+
|
|
90
|
+
def create_panel(self, parent=None) -> QWidget:
|
|
91
|
+
panel = QWidget(parent)
|
|
92
|
+
layout = QVBoxLayout(panel)
|
|
93
|
+
|
|
94
|
+
title = QLabel("Welcome to Custom Analysis Panel")
|
|
95
|
+
btn = PrimaryButton("Execute Step")
|
|
96
|
+
|
|
97
|
+
layout.addWidget(title)
|
|
98
|
+
layout.addWidget(btn)
|
|
99
|
+
return panel
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 🛡️ Cryptographic Trust Architecture
|
|
105
|
+
|
|
106
|
+
Karcytics implements a professional-grade **Chain of Trust** to protect laboratory environments:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
[ Root Authority ] (Hardcoded Core Key)
|
|
110
|
+
│
|
|
111
|
+
▼ (signs)
|
|
112
|
+
[ Developer Key ] (Dev Certificate)
|
|
113
|
+
│
|
|
114
|
+
▼ (signs)
|
|
115
|
+
[ Plugin Manifest ] (Ed25519 Signature + Merkle-Tree Hashes)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 1. Generate Your Cryptographic Identity
|
|
119
|
+
```bash
|
|
120
|
+
karcytics-sdk setup-identity
|
|
121
|
+
```
|
|
122
|
+
- Local Private Key: `~/.karcytics/dev_private_key.pem`
|
|
123
|
+
- Developer Certificate: `~/.karcytics/dev_cert.bin`
|
|
124
|
+
|
|
125
|
+
### 2. Sign Your Plugin payload
|
|
126
|
+
Calculates Merkle-hashes for all your files recursively, excludes development directories automatically, updates `manifest.json`, and writes `signature.bin`:
|
|
127
|
+
```bash
|
|
128
|
+
karcytics-sdk sign <path/to/plugin>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 3. Modularity Compliance Check
|
|
132
|
+
Verify your plugin matches QA and security standards:
|
|
133
|
+
```bash
|
|
134
|
+
karcytics-sdk evaluate <path/to/plugin>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 📘 Standalone Preview Support
|
|
140
|
+
Since the SDK decouples all theme components from the desktop core using robust try-except fallbacks, you can instantiate and preview components standalone in development:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
import sys
|
|
144
|
+
from PyQt6.QtWidgets import QApplication
|
|
145
|
+
from karcytics_sdk.ui import PrimaryButton, WizardPanel
|
|
146
|
+
|
|
147
|
+
app = QApplication(sys.argv)
|
|
148
|
+
widget = WizardPanel() # Renders beautifully even without the main app!
|
|
149
|
+
widget.show()
|
|
150
|
+
sys.exit(app.exec())
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 📄 License
|
|
156
|
+
This project is licensed under the MIT License.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# 🔌 Karcytics SDK
|
|
2
|
+
|
|
3
|
+
[](https://KalaimaranB.github.io/Karcytics-SDK/)
|
|
4
|
+
[](https://github.com/KalaimaranB/Karcytics-SDK/actions)
|
|
5
|
+
[](https://github.com/KalaimaranB/Karcytics-SDK/blob/main/LICENSE)
|
|
6
|
+
|
|
7
|
+
The Software Development Kit (SDK) and Command-Line Interface (CLI) for building, validating, and signing plugins for the **Karcytics** desktop scientific suite.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 🚀 Key Features
|
|
12
|
+
|
|
13
|
+
- **Decoupled Architecture**: Build and test PyQt6-based scientific plugins independently of the main desktop app.
|
|
14
|
+
- **Fail-Safe Dynamic Theme Fallbacks**: Visual components automatically load custom HSL-tailored colors when running standalone inside CI/CD test gates or external visualizers.
|
|
15
|
+
- **Merkle-Tree Cryptographic Integrity**: Built-in Ed25519 signing and verification tools to secure user environments against remote execution and tampering.
|
|
16
|
+
- **PyPI-Ready Packaging**: Complete declarative `pyproject.toml` config, built to publish natively under the `karcytics-sdk` package.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 🛠️ Installation
|
|
21
|
+
|
|
22
|
+
Install the SDK directly into your plugin's virtual environment:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install karcytics-sdk
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
*(Or during development, install in editable mode):*
|
|
29
|
+
```bash
|
|
30
|
+
git clone https://github.com/KalaimaranB/Karcytics-SDK.git
|
|
31
|
+
cd Karcytics-SDK
|
|
32
|
+
pip install -e .
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 📦 Creating a Custom Karcytics Plugin
|
|
38
|
+
|
|
39
|
+
To build a valid plugin, implement the `KarcyticsPlugin` interface and declare your entrypoints.
|
|
40
|
+
|
|
41
|
+
### 1. `manifest.json`
|
|
42
|
+
Every plugin must include a manifest file in its root directory:
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"id": "my_custom_plugin",
|
|
46
|
+
"name": "My Custom Plugin",
|
|
47
|
+
"version": "1.0.0",
|
|
48
|
+
"author": "Dr. Kalaimaran",
|
|
49
|
+
"description": "High-performance scientific analysis plugin.",
|
|
50
|
+
"category": "analysis",
|
|
51
|
+
"min_core_version": "1.0.0",
|
|
52
|
+
"entrypoint": "plugin:MyPluginClass"
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 2. `plugin.py`
|
|
57
|
+
```python
|
|
58
|
+
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel
|
|
59
|
+
from karcytics_sdk.core.interfaces import KarcyticsPlugin
|
|
60
|
+
from karcytics_sdk.ui import PrimaryButton
|
|
61
|
+
|
|
62
|
+
class MyPluginClass(KarcyticsPlugin):
|
|
63
|
+
"""A professional-grade Karcytics plugin."""
|
|
64
|
+
|
|
65
|
+
def initialize(self) -> None:
|
|
66
|
+
self.logger.info("Initializing custom plugin...")
|
|
67
|
+
|
|
68
|
+
def create_panel(self, parent=None) -> QWidget:
|
|
69
|
+
panel = QWidget(parent)
|
|
70
|
+
layout = QVBoxLayout(panel)
|
|
71
|
+
|
|
72
|
+
title = QLabel("Welcome to Custom Analysis Panel")
|
|
73
|
+
btn = PrimaryButton("Execute Step")
|
|
74
|
+
|
|
75
|
+
layout.addWidget(title)
|
|
76
|
+
layout.addWidget(btn)
|
|
77
|
+
return panel
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 🛡️ Cryptographic Trust Architecture
|
|
83
|
+
|
|
84
|
+
Karcytics implements a professional-grade **Chain of Trust** to protect laboratory environments:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
[ Root Authority ] (Hardcoded Core Key)
|
|
88
|
+
│
|
|
89
|
+
▼ (signs)
|
|
90
|
+
[ Developer Key ] (Dev Certificate)
|
|
91
|
+
│
|
|
92
|
+
▼ (signs)
|
|
93
|
+
[ Plugin Manifest ] (Ed25519 Signature + Merkle-Tree Hashes)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 1. Generate Your Cryptographic Identity
|
|
97
|
+
```bash
|
|
98
|
+
karcytics-sdk setup-identity
|
|
99
|
+
```
|
|
100
|
+
- Local Private Key: `~/.karcytics/dev_private_key.pem`
|
|
101
|
+
- Developer Certificate: `~/.karcytics/dev_cert.bin`
|
|
102
|
+
|
|
103
|
+
### 2. Sign Your Plugin payload
|
|
104
|
+
Calculates Merkle-hashes for all your files recursively, excludes development directories automatically, updates `manifest.json`, and writes `signature.bin`:
|
|
105
|
+
```bash
|
|
106
|
+
karcytics-sdk sign <path/to/plugin>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 3. Modularity Compliance Check
|
|
110
|
+
Verify your plugin matches QA and security standards:
|
|
111
|
+
```bash
|
|
112
|
+
karcytics-sdk evaluate <path/to/plugin>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 📘 Standalone Preview Support
|
|
118
|
+
Since the SDK decouples all theme components from the desktop core using robust try-except fallbacks, you can instantiate and preview components standalone in development:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
import sys
|
|
122
|
+
from PyQt6.QtWidgets import QApplication
|
|
123
|
+
from karcytics_sdk.ui import PrimaryButton, WizardPanel
|
|
124
|
+
|
|
125
|
+
app = QApplication(sys.argv)
|
|
126
|
+
widget = WizardPanel() # Renders beautifully even without the main app!
|
|
127
|
+
widget.show()
|
|
128
|
+
sys.exit(app.exec())
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 📄 License
|
|
134
|
+
This project is licensed under the MIT License.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "karcytics-sdk"
|
|
7
|
+
version = "2.0.0"
|
|
8
|
+
description = "Software Development Kit and CLI for Karcytics."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Kalaimaran Balasothy" }
|
|
13
|
+
]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
]
|
|
18
|
+
dependencies = [
|
|
19
|
+
"cryptography>=41.0.0",
|
|
20
|
+
"msgpack>=1.0.0",
|
|
21
|
+
"numpy",
|
|
22
|
+
"pandas",
|
|
23
|
+
"pillow>=12.3.0",
|
|
24
|
+
"PyQt6>=6.5.0",
|
|
25
|
+
"requests>=2.28.0",
|
|
26
|
+
"scikit-image>=0.26.0",
|
|
27
|
+
"scipy",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
docs = [
|
|
32
|
+
"mkdocs-material",
|
|
33
|
+
"mkdocstrings[python]",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
karcytics-sdk = "karcytics_sdk.cli.main:main"
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.packages.find]
|
|
40
|
+
where = ["src"]
|
|
41
|
+
|
|
42
|
+
[tool.setuptools.package-data]
|
|
43
|
+
karcytics_sdk = ["py.typed"]
|
|
44
|
+
|
|
45
|
+
[tool.pytest.ini_options]
|
|
46
|
+
minversion = "7.0"
|
|
47
|
+
addopts = "-ra -q --tb=short --cov=src/karcytics_sdk --cov-report=term-missing --cov-report=html --cov-fail-under=45"
|
|
48
|
+
testpaths = ["tests"]
|
|
49
|
+
pythonpath = ["src"]
|
|
50
|
+
filterwarnings = [
|
|
51
|
+
"ignore:.*PyQt6.*:DeprecationWarning",
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
[tool.coverage.run]
|
|
55
|
+
source = ["src/karcytics_sdk"]
|
|
56
|
+
omit = [
|
|
57
|
+
"*/__init__.py",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
[tool.coverage.report]
|
|
61
|
+
show_missing = true
|
|
62
|
+
exclude_lines = [
|
|
63
|
+
"pragma: no cover",
|
|
64
|
+
"if __name__ == .__main__.:",
|
|
65
|
+
"raise NotImplementedError",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
[tool.ruff]
|
|
69
|
+
line-length = 120
|
|
70
|
+
target-version = "py311"
|
|
71
|
+
|
|
72
|
+
[tool.ruff.lint]
|
|
73
|
+
select = [
|
|
74
|
+
"E", "F", "W", # Pyflakes & pycodestyle
|
|
75
|
+
"I", # isort (import sorting)
|
|
76
|
+
"UP", # pyupgrade
|
|
77
|
+
"B", # flake8-bugbear
|
|
78
|
+
"D", # pydocstyle
|
|
79
|
+
"C90", # mccabe complexity
|
|
80
|
+
"PLR", # pylint refactoring (complexity)
|
|
81
|
+
]
|
|
82
|
+
ignore = [
|
|
83
|
+
"E501", # Line too long (handled by formatting standards)
|
|
84
|
+
"E722", # Bare excepts (utilised in AI connection retry fallbacks)
|
|
85
|
+
"D100", # Missing docstring in public module
|
|
86
|
+
"D101", # Missing docstring in public class (redundant for UI colors/fallback classes)
|
|
87
|
+
"D102", # Missing docstring in public method (redundant for standard UI properties/callbacks)
|
|
88
|
+
"D103", # Missing docstring in public function
|
|
89
|
+
"D104", # Missing docstring in public package
|
|
90
|
+
"D105", # Missing docstring in magic method (redundant by standard definition)
|
|
91
|
+
"D106", # Missing docstring in public nested class
|
|
92
|
+
"D107", # Missing docstring in __init__ (covered by class docstring)
|
|
93
|
+
"D205", # 1 blank line between summary and description
|
|
94
|
+
"B024", # ABC with no abstract methods (perfectly valid for base data/state models)
|
|
95
|
+
"B027", # Empty hooks in ABCs without abstract decorator (standard custom override hook pattern)
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
[tool.ruff.lint.pydocstyle]
|
|
99
|
+
convention = "google"
|
|
100
|
+
|
|
101
|
+
[tool.ruff.lint.per-file-ignores]
|
|
102
|
+
"tests/*" = ["PLR2004", "PLR0913", "PLR0915", "PLR0917"]
|
|
103
|
+
|
|
104
|
+
[tool.mypy]
|
|
105
|
+
python_version = "3.12"
|
|
106
|
+
warn_return_any = false
|
|
107
|
+
warn_unused_configs = true
|
|
108
|
+
disallow_untyped_defs = false
|
|
109
|
+
check_untyped_defs = false
|
|
110
|
+
ignore_missing_imports = true
|
|
111
|
+
disable_error_code = ["assignment", "union-attr", "call-arg", "no-any-return", "method-assign", "misc", "no-redef"]
|
|
112
|
+
files = "src"
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Karcytics SDK — Software Development Kit for Karcytics desktop plugins.
|
|
2
|
+
|
|
3
|
+
Provides two main namespaces:
|
|
4
|
+
- plugin: Clean API for plugin development with zero unnecessary dependencies.
|
|
5
|
+
- host: Host-facing APIs for the Core application and SDK signing CLI.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from . import host, interfaces, plugin
|
|
9
|
+
|
|
10
|
+
__all__ = ["plugin", "host", "interfaces"]
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
def setup_diagnostics_parser(subparsers):
|
|
2
|
+
# Command: sbom
|
|
3
|
+
sbom_parser = subparsers.add_parser("sbom", help="Generates and prints the SBOM in the specified format.")
|
|
4
|
+
sbom_parser.add_argument(
|
|
5
|
+
"--format", type=str, choices=["--json", "--markdown"], default="--markdown", help="Output format"
|
|
6
|
+
)
|
|
7
|
+
sbom_parser.set_defaults(func=generate_sbom)
|
|
8
|
+
|
|
9
|
+
# Command: evaluate
|
|
10
|
+
eval_parser = subparsers.add_parser("evaluate", help="Perform comprehensive CLI evaluation of a plugin.")
|
|
11
|
+
eval_parser.add_argument("plugin_dir", type=str, help="Path to the plugin directory.")
|
|
12
|
+
eval_parser.set_defaults(func=evaluate_plugin)
|
|
13
|
+
|
|
14
|
+
# Command: doctor
|
|
15
|
+
doctor_parser = subparsers.add_parser("doctor", help="Evaluate a plugin against new SDK architecture.")
|
|
16
|
+
doctor_parser.add_argument("plugin_dir", type=str, help="Path to the plugin directory.")
|
|
17
|
+
doctor_parser.set_defaults(func=doctor_plugin)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def generate_sbom(args) -> bool:
|
|
21
|
+
"""Generates and prints the SBOM in the specified format."""
|
|
22
|
+
try:
|
|
23
|
+
import importlib
|
|
24
|
+
|
|
25
|
+
karcytics_core_sbom = importlib.import_module("karcytics.core.sbom")
|
|
26
|
+
generator = karcytics_core_sbom.SBOMGenerator()
|
|
27
|
+
|
|
28
|
+
if args.format == "--json":
|
|
29
|
+
print(generator.to_json())
|
|
30
|
+
else:
|
|
31
|
+
print(generator.to_markdown())
|
|
32
|
+
return True
|
|
33
|
+
except ImportError:
|
|
34
|
+
print("ERROR: SBOM generation is only supported when running inside the Karcytics main application.")
|
|
35
|
+
return False
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def evaluate_plugin(args) -> bool:
|
|
39
|
+
"""Perform comprehensive CLI evaluation of a plugin."""
|
|
40
|
+
import logging
|
|
41
|
+
import sys
|
|
42
|
+
from pathlib import Path
|
|
43
|
+
|
|
44
|
+
from PyQt6.QtWidgets import QApplication
|
|
45
|
+
|
|
46
|
+
from karcytics_sdk.plugin.manifest_parser import ManifestParser
|
|
47
|
+
|
|
48
|
+
print("Running Plugin Diagnostics Evaluator (evaluate)...")
|
|
49
|
+
_app = QApplication.instance() or QApplication(sys.argv)
|
|
50
|
+
logging.basicConfig(level=logging.INFO)
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
parser = ManifestParser()
|
|
54
|
+
manifest = parser.parse_file(str(Path(args.plugin_dir) / "pyproject.toml"))
|
|
55
|
+
print(f"Manifest parsed successfully: {manifest.get('id')} v{manifest.get('version')}")
|
|
56
|
+
|
|
57
|
+
dependencies = manifest.get("python_dependencies") or manifest.get("dependencies", {})
|
|
58
|
+
if dependencies:
|
|
59
|
+
print("Auditing Plugin Dependencies...")
|
|
60
|
+
all_pinned = True
|
|
61
|
+
for dep, version in dependencies.items():
|
|
62
|
+
if any(c in version for c in (">", "<", "*", "^", "~")):
|
|
63
|
+
print(f"WARNING: Dependency '{dep}' is not pinned. Recommend exact pinning.")
|
|
64
|
+
all_pinned = False
|
|
65
|
+
else:
|
|
66
|
+
print(f"Dependency '{dep}' is pinned to version '{version}'")
|
|
67
|
+
|
|
68
|
+
if all_pinned:
|
|
69
|
+
print("All declared dependencies are securely pinned.")
|
|
70
|
+
|
|
71
|
+
return True
|
|
72
|
+
except Exception as e:
|
|
73
|
+
print(f"Evaluation failed: {e}")
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def doctor_plugin(args) -> bool:
|
|
78
|
+
"""Evaluate a plugin against new SDK architecture (plugin.toml, strict imports)."""
|
|
79
|
+
print(f"Running Plugin Conformance Evaluator (doctor) on {args.plugin_dir}...")
|
|
80
|
+
print("Note: Scaffolded for Phase 1. Full static/runtime checks to be implemented.")
|
|
81
|
+
return True
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def setup_migrate_parser(subparsers):
|
|
6
|
+
# Command: migrate
|
|
7
|
+
migrate_parser = subparsers.add_parser("migrate", help="Migrate a legacy plugin to the new architecture.")
|
|
8
|
+
migrate_parser.add_argument("plugin_dir", type=str, help="Path to the plugin directory.")
|
|
9
|
+
migrate_parser.set_defaults(func=migrate_plugin)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def migrate_plugin(args) -> bool: # noqa: C901
|
|
13
|
+
"""Migrate a legacy plugin to the new architecture (pyproject.toml, src/ layout)."""
|
|
14
|
+
print(f"Migrating legacy plugin at {args.plugin_dir} to new SDK architecture...")
|
|
15
|
+
|
|
16
|
+
p_dir = Path(args.plugin_dir)
|
|
17
|
+
manifest_path = p_dir / "manifest.json"
|
|
18
|
+
|
|
19
|
+
if not manifest_path.exists():
|
|
20
|
+
print("ERROR: manifest.json not found. This doesn't look like a valid legacy plugin.")
|
|
21
|
+
return False
|
|
22
|
+
|
|
23
|
+
with open(manifest_path, encoding="utf-8") as f:
|
|
24
|
+
manifest_data = json.load(f)
|
|
25
|
+
|
|
26
|
+
plugin_id = manifest_data.get("id", p_dir.name.lower().replace("-", "_").replace(" ", "_"))
|
|
27
|
+
|
|
28
|
+
# 1. Generate pyproject.toml
|
|
29
|
+
print("1. Creating pyproject.toml and deprecating manifest.json...")
|
|
30
|
+
|
|
31
|
+
toml_path = p_dir / "pyproject.toml"
|
|
32
|
+
|
|
33
|
+
# Extract dependencies
|
|
34
|
+
dependencies_str = ""
|
|
35
|
+
if "python_dependencies" in manifest_data:
|
|
36
|
+
for dep, ver in manifest_data["python_dependencies"].items():
|
|
37
|
+
dependencies_str += f' "{dep}{ver}",\n'
|
|
38
|
+
|
|
39
|
+
# Build authors block for project
|
|
40
|
+
project_authors = ""
|
|
41
|
+
if "authors" in manifest_data:
|
|
42
|
+
for author in manifest_data["authors"]:
|
|
43
|
+
name = author.get("name", "Unknown")
|
|
44
|
+
project_authors += f' {{ name = "{name}" }},\n'
|
|
45
|
+
|
|
46
|
+
# Build authors block for plugin
|
|
47
|
+
plugin_authors = ""
|
|
48
|
+
if "authors" in manifest_data:
|
|
49
|
+
for author in manifest_data["authors"]:
|
|
50
|
+
name = author.get("name", "Unknown")
|
|
51
|
+
role = author.get("role", "Developer")
|
|
52
|
+
perms_str = json.dumps(author.get("permissions", []))
|
|
53
|
+
plugin_authors += f' {{ name = "{name}", role = "{role}", permissions = {perms_str} }},\n'
|
|
54
|
+
|
|
55
|
+
clean_project_authors = project_authors.rstrip(",\\n")
|
|
56
|
+
clean_deps = dependencies_str.rstrip(",\\n")
|
|
57
|
+
clean_plugin_authors = plugin_authors.rstrip(",\\n")
|
|
58
|
+
reqs_json = json.dumps(manifest_data.get("requires", ["task_scheduler", "logger", "event_bus"]))
|
|
59
|
+
|
|
60
|
+
toml_content = f'''[project]
|
|
61
|
+
name = "{manifest_data.get("name", p_dir.name.title())}"
|
|
62
|
+
version = "{manifest_data.get("version", "1.0.0")}"
|
|
63
|
+
description = "{manifest_data.get("description", "")}"
|
|
64
|
+
readme = "README.md"
|
|
65
|
+
requires-python = ">=3.11"
|
|
66
|
+
authors = [
|
|
67
|
+
{clean_project_authors}
|
|
68
|
+
]
|
|
69
|
+
dependencies = [
|
|
70
|
+
{clean_deps}
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
[tool.biopro.plugin]
|
|
74
|
+
id = "{plugin_id}"
|
|
75
|
+
min_core_version = "{manifest_data.get("min_core_version", "1.4.9")}"
|
|
76
|
+
entry_point = "biopro_plugins.{plugin_id}:initialize"
|
|
77
|
+
requires = {reqs_json}
|
|
78
|
+
authors = [
|
|
79
|
+
{clean_plugin_authors}
|
|
80
|
+
]
|
|
81
|
+
'''
|
|
82
|
+
with open(toml_path, "w", encoding="utf-8") as f:
|
|
83
|
+
f.write(toml_content)
|
|
84
|
+
|
|
85
|
+
print(
|
|
86
|
+
" -> Renaming manifest.json to manifest.json.deprecated (DO NOT DELETE yet, the core still uses it internally!)"
|
|
87
|
+
)
|
|
88
|
+
manifest_path.rename(p_dir / "manifest.json.deprecated")
|
|
89
|
+
|
|
90
|
+
# 2. Setup src structure
|
|
91
|
+
print("2. Restructuring python files into src/...")
|
|
92
|
+
src_dir = p_dir / "src"
|
|
93
|
+
src_dir.mkdir(exist_ok=True)
|
|
94
|
+
|
|
95
|
+
plugin_pkg_dir = src_dir / "biopro_plugins" / plugin_id
|
|
96
|
+
plugin_pkg_dir.mkdir(parents=True, exist_ok=True)
|
|
97
|
+
|
|
98
|
+
# Move all .py files except setup.py to the new package directory
|
|
99
|
+
py_files_moved = 0
|
|
100
|
+
for file in p_dir.glob("*.py"):
|
|
101
|
+
if file.name not in {"setup.py", "conftest.py"}:
|
|
102
|
+
print(f" -> Moving {file.name} to {plugin_pkg_dir.relative_to(p_dir)}")
|
|
103
|
+
file.rename(plugin_pkg_dir / file.name)
|
|
104
|
+
py_files_moved += 1
|
|
105
|
+
|
|
106
|
+
if py_files_moved == 0:
|
|
107
|
+
# Create an empty __init__.py if no files were moved
|
|
108
|
+
(plugin_pkg_dir / "__init__.py").touch()
|
|
109
|
+
|
|
110
|
+
print("\n✅ Migration complete! Please verify your imports in the new src/biopro_plugins/ folder.")
|
|
111
|
+
print("Run 'karcytics-sdk sign .' to sign the new structure.")
|
|
112
|
+
return True
|