Metadata-Version: 2.4
Name: medics-extension-sdk
Version: 2026.5.19
Summary: SDK for creating extensions for the MedICS (Medical Image Computing and Segmentation) platform
Home-page: https://github.com/medics/medics-extension-sdk
Author: MedICS Team
Author-email: MedICS Team <medics@example.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/medics/medics-extension-sdk
Project-URL: Repository, https://github.com/medics/medics-extension-sdk
Project-URL: Bug Reports, https://github.com/medics/medics-extension-sdk/issues
Project-URL: Documentation, https://medics-extension-sdk.readthedocs.io/
Keywords: medical imaging,segmentation,extensions,plugins,MedICS
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Healthcare Industry
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Classifier: Topic :: Scientific/Engineering :: Image Processing
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: qt
Requires-Dist: PySide6>=6.0.0; extra == "qt"
Provides-Extra: qt6
Requires-Dist: PySide6>=6.0.0; extra == "qt6"
Provides-Extra: qt5
Requires-Dist: PyQt5>=5.15.0; extra == "qt5"
Provides-Extra: pyqt6
Requires-Dist: PyQt6>=6.0.0; extra == "pyqt6"
Provides-Extra: dev
Requires-Dist: pytest>=6.0; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: black; extra == "dev"
Requires-Dist: flake8; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Requires-Dist: sphinx; extra == "dev"
Requires-Dist: sphinx-rtd-theme; extra == "dev"
Provides-Extra: examples
Requires-Dist: numpy>=1.20.0; extra == "examples"
Requires-Dist: opencv-python>=4.5.0; extra == "examples"
Requires-Dist: matplotlib>=3.3.0; extra == "examples"
Dynamic: author
Dynamic: home-page
Dynamic: license-file
Dynamic: requires-python

﻿# MedICS Extension SDK

[![PyPI version](https://img.shields.io/pypi/v/medics-extension-sdk)](https://pypi.org/project/medics-extension-sdk/)
[![Python](https://img.shields.io/pypi/pyversions/medics-extension-sdk)](https://pypi.org/project/medics-extension-sdk/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

Python SDK for building extensions for the **MedICS** (Medical Image Computing and Segmentation) platform. Provides base classes, API utilities, and a CLI scaffolding tool.

---

## Installation

```bash
pip install medics-extension-sdk
```

**With Qt support** (required for widget-based extensions):

```bash
pip install medics-extension-sdk[qt]      # PySide6 (recommended)
pip install medics-extension-sdk[pyqt6]   # PyQt6
pip install medics-extension-sdk[qt5]     # PyQt5 (legacy)
```

**Development tools:**

```bash
pip install medics-extension-sdk[dev]
```

---

## Quick Start

### 1. Create an extension class

```python
from medics_extension_sdk import BaseExtension

class MyExtension(BaseExtension):
    def __init__(self, parent=None):
        super().__init__(
            parent=parent,
            extension_name="My Extension",
            author_name="Your Name",
        )

    def get_version(self) -> str:
        return "1.0.0"

    def get_description(self) -> str:
        return "Does something useful with medical images"

    def get_category(self) -> str:
        return "Analysis"

    def create_widget(self, parent=None, **kwargs):
        from PySide6.QtWidgets import QLabel
        return QLabel("Hello from My Extension!")
```

The extension `id` is automatically derived: `"your_name.my_extension"`.

### 2. Access platform services

```python
# Inside any extension method:
self.log_message("Processing started")
value = self.get_config_value("my_ext", "threshold", 0.5)
self.set_config_value("my_ext", "threshold", 0.8)
self.send_event("processing_done", {"status": "ok"})
workspace = self.get_component("workspace_manager")
```

### 3. Expose a programmatic API

Decorate public methods with `@api_method` so they are auto-discovered at runtime:

```python
from medics_extension_sdk import BaseExtension, api_method

class MyExtension(BaseExtension):
    ...

    @api_method(description="Run analysis and return results", category="Processing")
    def run_analysis(self, threshold: float = 0.5) -> dict:
        return {"threshold": threshold, "result": "ok"}
```

Retrieve the API from an instance:

```python
ext = MyExtension()
api = ext.get_instance_api()   # returns apiDict of decorated callables
api.run_analysis(threshold=0.7)
```

---

## Scaffolding

Generate a new extension template with the CLI:

```bash
medics-create-extension "My Segmentation Tool" \
    --author "Jane Doe" \
    --category "Segmentation" \
    --output ./extensions
```

This creates a fully-structured extension directory with a main class, widget, API methods, config file, and README.

---

## API Reference

### `BaseExtension`

| Member | Type | Description |
|--------|------|-------------|
| `id` | `str` (read-only) | Auto-generated from `author_name.extension_name` |
| `extension_name` | `str` (read-only) | Set in `__init__` |
| `author_name` | `str` (read-only) | Set in `__init__` |
| `app_context` | `Any` | Injected by the platform on `initialize()` |
| `get_version()` | abstract | Return version string |
| `get_description()` | abstract | Return short description |
| `get_category()` | `str` | Extension category (default: `"General"`) |
| `create_widget(parent, **kwargs)` | `QWidget` | Override to provide Qt UI |
| `initialize(app_context)` | `bool` | Called by platform at load time |
| `cleanup()` | `None` | Called by platform at unload time |
| `get_instance_api()` | `apiDict` | Returns dict of `@api_method` callables |

**ID format:** `{author_name}.{extension_name}` — lowercased, spaces removed, non-alphanumeric characters replaced with `_`.

### `@api_method(description, category)`

Marks a method for auto-discovery via `get_instance_api()`.

### `apiDict`

`dict` subclass with dot-notation attribute access.

---

## Extension Categories

Standard categories for organizing extensions in the platform UI:

- `"Analysis"` — measurement and analysis tools
- `"Segmentation"` — segmentation algorithms
- `"Visualization"` — rendering and display
- `"Processing"` — image filters and transforms
- `"Import/Export"` — data I/O utilities
- `"Workflow"` — automation and pipeline tools
- `"Utilities"` — general helpers
- `"Research"` — experimental tools

---

## Testing

```python
import pytest
from medics_extension_sdk import BaseExtension

class MyExtension(BaseExtension):
    def __init__(self):
        super().__init__(extension_name="My Ext", author_name="Author")
    def get_version(self): return "1.0.0"
    def get_description(self): return "Test"

def test_id_readonly():
    ext = MyExtension()
    assert ext.id == "author.my_ext"
    with pytest.raises(AttributeError):
        ext.id = "hacked"
```

Run:

```bash
pytest tests/
```

---

## Project Layout

Recommended structure for a published extension package:

```
my_extension/
+-- __init__.py          # exports Extension = MyExtensionClass
+-- my_extension.py      # main extension class
+-- icons/               # optional icon assets
+-- config.ini           # default configuration
+-- README.md
```

---

## License

MIT - see [LICENSE](LICENSE).
