Skip to content

Commit

Permalink
#139 pyOrthanc integration (#140)
Browse files Browse the repository at this point in the history
* #139 Support for pyOrthanc in orthanc-server-extensions
 * introduce ClientType for (Async)Orthanc pyOrthanc clients

* Bump version: 3.4.0 → 3.5.0

* #139 Support for pyOrthanc in orthanc-server-extensions
 * add pyOrthanc dependency for tox

* #139 Support for pyOrthanc in orthanc-server-extensions
 * simplify the enum approach, use better naming

* #139 Support for pyOrthanc in orthanc-server-extensions
 * extend release notes

* #139 Fix for changed Enum handling in 3.11
  • Loading branch information
walcovanloon committed Oct 13, 2023
1 parent dd20e2f commit 8795cb5
Show file tree
Hide file tree
Showing 12 changed files with 113 additions and 21 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
@@ -1,4 +1,4 @@
FROM osimis/orthanc:22.9.0-full
FROM osimis/orthanc:23.9.2-full

RUN apt-get update && ACCEPT_EULA=Y apt-get dist-upgrade -y && apt-get install -y openssl

Expand All @@ -9,6 +9,6 @@ RUN mkdir -p /ssl && cat /etc/ssl/private/server.key /etc/ssl/certs/server.pem
COPY orthanc_ext /python/orthanc_ext
WORKDIR /python
COPY setup.py README.rst HISTORY.rst ./
RUN pip3 install httpx .[nats-event-publisher] # does not get picked up in setup.py
RUN pip3 install httpx .[nats-event-publisher,pyorthanc] # does not get picked up in setup.py
RUN python3 setup.py install
COPY tests/entry_point.py /python/entry_point.py
10 changes: 9 additions & 1 deletion HISTORY.rst
Expand Up @@ -2,7 +2,15 @@
History
=======

3.3.0 (2022-01-30)
3.5.0 (2023-10-12)
------------------
* Support pyOrthanc as Orthanc API client

3.4.0 (2023-06-21)
------------------
* Improved asyncio performance

3.3.0 (2023-01-30)
------------------
* Publish Orthanc change events to Kafka, RabbitMQ and NATS
* Run asyncio functions (coroutines) for concurrent processing of a change event
Expand Down
2 changes: 1 addition & 1 deletion orthanc_ext/__init__.py
Expand Up @@ -2,4 +2,4 @@

__author__ = """WalkIT"""
__email__ = 'code@walkit.nl'
__version__ = '3.4.0'
__version__ = '3.5.0'
10 changes: 5 additions & 5 deletions orthanc_ext/event_dispatcher.py
Expand Up @@ -4,8 +4,8 @@
from dataclasses import dataclass

from orthanc_ext.executor_utilities import SequentialHybridExecutor
from orthanc_ext.http_utilities import create_internal_client, get_rest_api_base_url, \
get_certificate, ClientType
from orthanc_ext.http_utilities import get_rest_api_base_url, \
get_certificate, OrthancClientTypeFactory, HttpxClientType
from orthanc_ext.logging_configurator import python_logging
from orthanc_ext.python_utilities import ensure_iterable, create_reverse_type_dict

Expand Down Expand Up @@ -67,8 +67,8 @@ def get_sync_handlers(handlers):
return [handler for handler in handlers if not inspect.iscoroutinefunction(handler)]


def create_session(orthanc, client_type=ClientType.SYNC):
def create_session(orthanc, client_type: OrthancClientTypeFactory = HttpxClientType.SYNC):
config = json.loads(orthanc.GetConfiguration())
return create_internal_client(
return client_type.create_internal_client(
get_rest_api_base_url(config), orthanc.GenerateRestApiAuthorizationToken(),
get_certificate(config), client_type)
get_certificate(config))
19 changes: 16 additions & 3 deletions orthanc_ext/http_utilities.py
@@ -1,3 +1,4 @@
from dataclasses import dataclass
from enum import Enum
from typing import Union

Expand All @@ -14,17 +15,29 @@ def get_certificate(config):
return False if not config.get('SslEnabled', False) else config.get('SslCertificate', False)


class ClientType(Enum):
@dataclass
class OrthancClientTypeFactory:
http_client: type

def create_internal_client(self, *args, **kwargs):
return create_internal_client(*args, **kwargs, client_type=self)


class HttpxClientType(OrthancClientTypeFactory, Enum):
SYNC = httpx.Client
ASYNC = httpx.AsyncClient


# deprecated, for backward compatibility
ClientType = HttpxClientType


def create_internal_client(
base_url,
token='',
cert: Union[str, bool] = False,
client_type: ClientType = ClientType.SYNC) -> httpx.Client:
return client_type.value(
client_type: ClientType = HttpxClientType.SYNC):
return client_type.http_client(
base_url=base_url,
timeout=httpx.Timeout(300, connect=30),
verify=cert,
Expand Down
30 changes: 30 additions & 0 deletions orthanc_ext/pyorthanc_utilities.py
@@ -0,0 +1,30 @@
from enum import Enum
from typing import Union

import httpx
from pyorthanc import Orthanc, AsyncOrthanc

from orthanc_ext.http_utilities import OrthancClientTypeFactory


class PyOrthancClientType(OrthancClientTypeFactory, Enum):
SYNC = Orthanc
ASYNC = AsyncOrthanc

def create_internal_client(self, *args, **kwargs):
return create_internal_client(*args, **kwargs, client_type=self)


def create_internal_client(
base_url,
token='',
cert: Union[str, bool] = False,
client_type: PyOrthancClientType = PyOrthancClientType.SYNC):

# note: only difference with the httpx.Client constructor is the `base_url` positional argument.
return client_type.http_client(
base_url,
base_url=base_url,
timeout=httpx.Timeout(300, connect=30),
verify=cert,
headers={'Authorization': token})
2 changes: 1 addition & 1 deletion setup.cfg
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 3.4.0
current_version = 3.5.0
commit = True
tag = True

Expand Down
5 changes: 3 additions & 2 deletions setup.py
Expand Up @@ -46,11 +46,12 @@
extras_require={
'nats-event-publisher': ['cloudevents', 'nats-py'],
'kafka-event-publisher': ['cloudevents', 'aiokafka'],
'rabbitmq-event-publisher': ['cloudevents', 'aio-pika']
'rabbitmq-event-publisher': ['cloudevents', 'aio-pika'],
'pyorthanc': ['pyorthanc>1.0']
},
test_suite='tests',
tests_require=test_requirements,
url='https://github.com/walkIT-nl/orthanc-server-extensions',
version='3.4.0',
version='3.5.0',
zip_safe=False,
)
10 changes: 5 additions & 5 deletions tests/entry_point.py
@@ -1,13 +1,12 @@
"""Test entry point script for Orthanc Python Plugin.
"""

import logging
from functools import partial

import orthanc # NOQA provided by the plugin runtime.

from orthanc_ext import event_dispatcher
from orthanc_ext.http_utilities import ClientType
from orthanc_ext.pyorthanc_utilities import PyOrthancClientType
from orthanc_ext.python_utilities import pipeline
from orthanc_ext.scripts.nats_event_publisher import create_stream, publish_to_nats, NatsConfig

Expand All @@ -21,7 +20,7 @@ def start_maintenance_cycle(event, _):


def retrieve_system_info(_, client):
return client.get('/system').json()
return client.get_system()


def show_system_info(info, _client):
Expand All @@ -30,6 +29,7 @@ def show_system_info(info, _client):


nats_config = NatsConfig('nats://nats')

event_dispatcher.register_event_handlers({
orthanc.ChangeType.ORTHANC_STARTED: [
partial(log_event, 'started'),
Expand All @@ -38,6 +38,6 @@ def show_system_info(info, _client):
],
orthanc.ChangeType.STABLE_STUDY: [partial(publish_to_nats, nats_config)],
orthanc.ChangeType.ORTHANC_STOPPED: partial(log_event, 'stopped')
}, orthanc, event_dispatcher.create_session(orthanc),
}, orthanc, event_dispatcher.create_session(orthanc, client_type=PyOrthancClientType.SYNC),
event_dispatcher.create_session(
orthanc, client_type=ClientType.ASYNC))
orthanc, client_type=PyOrthancClientType.ASYNC))
19 changes: 19 additions & 0 deletions tests/test_http_utilities.py
@@ -0,0 +1,19 @@
import httpx

from orthanc_ext.event_dispatcher import create_session
from orthanc_ext.http_utilities import ClientType, HttpxClientType
from orthanc_ext.orthanc import OrthancApiHandler


def test_shall_create_sync_client():
client = HttpxClientType.SYNC.create_internal_client(base_url='http://localhost:8042')
assert client is not None
assert type(client) == httpx.Client


def test_shall_support_create_session_for_backward_compatibility():
assert type(create_session(OrthancApiHandler(), ClientType.SYNC)) == httpx.Client


def test_shall_support_create_async_client_for_backward_compatibility():
assert type(create_session(OrthancApiHandler(), ClientType.ASYNC)) == httpx.AsyncClient
21 changes: 21 additions & 0 deletions tests/test_pyorthanc_utilities.py
@@ -0,0 +1,21 @@
from pyorthanc import Orthanc, AsyncOrthanc

from orthanc_ext.event_dispatcher import create_session
from orthanc_ext.orthanc import OrthancApiHandler
from orthanc_ext.pyorthanc_utilities import PyOrthancClientType


def test_shall_create_sync_client():
client = PyOrthancClientType.SYNC.create_internal_client(base_url='http://localhost:8042')
assert client is not None
assert type(client) == Orthanc


def test_shall_create_async_client():
client = PyOrthancClientType.ASYNC.create_internal_client(base_url='http://localhost:8042')
assert client is not None
assert type(client) == AsyncOrthanc


def test_shall_support_create_session_for_backward_compatibility():
assert create_session(OrthancApiHandler(), PyOrthancClientType.SYNC) is not None
2 changes: 1 addition & 1 deletion tox.ini
Expand Up @@ -15,7 +15,7 @@ python =
setenv =
PYTHONPATH = {toxinidir}
deps =
.[nats-event-publisher, kafka-event-publisher, rabbitmq-event-publisher]
.[nats-event-publisher, kafka-event-publisher, rabbitmq-event-publisher, pyorthanc]
-r{toxinidir}/requirements_dev.txt
pytest-cov
; If you want to make tox run the tests with the same versions, create a
Expand Down

0 comments on commit 8795cb5

Please sign in to comment.