Skip to content

Commit

Permalink
Implemented python ids7client
Browse files Browse the repository at this point in the history
  • Loading branch information
SebLefort authored and sectra-masve committed Jan 9, 2025
1 parent 62e4c35 commit a41af36
Show file tree
Hide file tree
Showing 23 changed files with 1,151 additions and 0 deletions.
3 changes: 3 additions & 0 deletions ids7client/python/.bandit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
skips:
- B311
- B113
52 changes: 52 additions & 0 deletions ids7client/python/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# These are some examples of commonly ignored file patterns.
# You should customize this list as applicable to your project.
# Learn more about .gitignore:
# https://www.atlassian.com/git/tutorials/saving-changes/gitignore

# Node artifact files
node_modules/
dist/

# Compiled Java class files
*.class

# Compiled Python bytecode
*.py[cod]

# Log files
*.log

# Package files
*.jar

# Maven
target/
dist/

# JetBrains IDE
.idea/

# Unit test reports
TEST*.xml

# Generated by MacOS
.DS_Store

# Generated by Windows
Thumbs.db

# Applications
*.app
*.exe
*.war

# Large media files
*.mp4
*.tiff
*.avi
*.flv
*.mov
*.wmv

**/*.egg-info
**/*build
14 changes: 14 additions & 0 deletions ids7client/python/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
SHELL=bash

.PHONY: format
format:
isort .;
black .

.PHONY: lint
lint:
flake8 ids7client/
bandit -c .bandit.yml -r ids7client/
isort --check ids7client/
black ids7client/ --check --diff
mypy ids7client/
174 changes: 174 additions & 0 deletions ids7client/python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# Python Client for Sectra IDS7 PACS

## Introduction

This python package aims to facilite the development of AI applications integrated in Sectra IDS7 PACS.

Please note that for now, not every feature is implemented but the package can easily be enriched:

* some endpoints are missing (e.g., slide downloading)
* QIDO client is pretty basic

### What it implements

* A client for the IDS7 AI API (`IDS7AIClient`)
* A client for the IDS7 QIDO API (`IDS7QidoClient`)
* A set of pydantic models to encapsulate and validate data sent and received from IDS7


### What it does not implement, but might, at some point

* A server to receive analysis requests from IDS7

## Installation

To install ids7client (until it is published in pypi):

```pip install .```

To install ids7client with development dependencies (linting and formating, see below):

```pip install ./[dev]```

## Usage

Before using the client, make sure you have access to a valid authentication token, sent in the analysis requests.

### Example 1: Retrieve image information

```python
from ids7client.ai import IDS7AIClient

# Callback info, sent by IDS7 in the request
callback_url = "https://sectrapacs.com"
callback_token = "abc"

# Slide id, sent by IDS7 in the request
slide_id = "blabla"

client = IDS7AIClient(
url=callback_url,
token=callback_token
)

# Returns the image info with extended and personal health information data
image_info = client.get_image_info(slide_id, extended=True, phi=True)
```

### Example 2: Returning basic results

The following code creates a result payload that can be sent as response to display a frame on the whole slide and a label telling the user that the analysis is pending.

```python
from ids7client.ai import (
ResultContent,
ResultType,
PrimitiveItem,
Style,
Polygon,
Point,
Label,
Result
)

# Slide id, sent by IDS7 in the request
slide_id = "blabla"

data = ResultContent(
type=ResultType.PRIMITIVES,
content=[
PrimitiveItem(
style=Style(
strokeStyle="#000000",
),
polygons=[
Polygon(
points=[
Point(x=0.0, y=0.0),
Point(x=1.0, y=0.0),
Point(x=1.0, y=1.0),
Point(x=0.0, y=1.0),
]
)
],
labels=[
Label(
location=Point(x=0.00, y=0.0),
label="Analysis running",
)
],
)
],
)

result = Result(
slideId=slide_id,
displayResult="Analysis running",
applicationVersion="1.0.0",
data=data
)
```

### Example 3: Retrieving patient, request and exam id

```python
from IDS7Client.ai import IDS7AIClient
from IDS7Client.qido import IDS7QidoClient, DicomCodes

# Callback info, sent by IDS7 in the request
callback_url = "https://sectrapacs.com"
callback_token = "abc"

# Slide id, sent by IDS7 in the request
slide_id = "blabla"

ai_client = IDS7AIClient(
url=callback_url,
token=callback_token
)

# Returns the image info with extended and personal health information data
image_info = client.get_image_info(slide_id, extended=True, phi=True)

# Instanciates QIDO client with provided url, username and password
qido_client = IDS7QidoClient(qido_url, qido_username, qido_password)

# Retrieve study from QIDO API
study = qido_client.find_one_study(studyInstanceUid=data.study_id)

# Retrieve patient, request and exam id from the response
patient_id = study.get_value_as_string(DicomCodes.PATIENT_ID)
request_id = study.get_value_as_string(DicomCodes.REQUEST_ID)
exam_id = study.get_value_as_string(DicomCodes.EXAM_ID)
```

### Error handling and retries

Any request to the IDS7 server is retried 5 times with exponential delays if there is a connection error. Any other error is not handled by the clients.

Clients raise `IDS7RequestError` if the IDS7 server returns an error status code (e.g., 400, 404, 500, etc.). The error includes the returned status code, text and the requested path.

## Code quality

Code quality is ensured with the following tools:

* flake8 for formating
* mypy for static typing analysis
* bandit for security
* black for formating
* isort for imports order

One can format the code using the following command:

```make format```

One can lint the code using the following command:

```make lint```


## What's next?

* HL7 API client
* More detailed data validation (e.g., min and max lengths of arrays)
* Missing IDS7 endpoints
7 changes: 7 additions & 0 deletions ids7client/python/extra_requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
bandit
black
flake8
isort
mypy
types-requests
types-setuptools
1 change: 1 addition & 0 deletions ids7client/python/ids7client/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .errors import IDS7RequestError
41 changes: 41 additions & 0 deletions ids7client/python/ids7client/ai/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from .client import IDS7AIClient
from .schemas import (
Action,
ApplicationInfo,
Attachment,
AttachmentState,
CallbackInfo,
Context,
CreateInput,
DisplayedName,
DisplayProperties,
FocalPlane,
ImageInfo,
ImageNotification,
InputTemplate,
InputType,
Invocation,
Label,
MultiAreaContent,
OpticalPath,
Patch,
PatchContent,
Point,
Polygon,
Polyline,
PrimitiveItem,
Registration,
Result,
ResultContent,
ResultData,
ResultResponse,
ResultType,
Size,
SlideFormat,
Specimen,
Status,
Style,
TaggedPolygonContent,
TaggedPolygonInputContent,
TileFormat,
)
Loading

0 comments on commit a41af36

Please sign in to comment.