Skip to main content

Aidbox SDK for python

Project description

build status pypi Supported Python version

aidbox-python-sdk

  1. Create a python 3.9+ environment pyenv
  2. Set env variables and activate virtual environment source activate_settings.sh
  3. Install the required packages with pipenv install --dev
  4. Make sure the app's settings are configured correctly (see activate_settings.sh and aidbox_python_sdk/settings.py). You can also use environment variables to define sensitive settings, eg. DB connection variables (see example .env-ptl)
  5. You can then run example with python example.py.

Getting started

Minimal application

main.py

from aidbox_python_sdk.main import create_app as _create_app
from aidbox_python_sdk.settings import Settings
from aidbox_python_sdk.sdk import SDK


settings = Settings(**{})
sdk = SDK(settings, resources={}, seeds={})


def create_app():
    app = await _create_app(SDK)
    return app


async def create_gunicorn_app() -> web.Application:
    return create_app()

Register handler for operation

import logging
from aiohttp import web
from aidbox_python_sdk.types import SDKOperation, SDKOperationRequest

from yourappfolder import sdk 


@sdk.operation(
    methods=["POST", "PATCH"],
    path=["signup", "register", {"name": "date"}, {"name": "test"}],
    timeout=60000  ## Optional parameter to set a custom timeout for operation in milliseconds
)
def signup_register_op(_operation: SDKOperation, request: SDKOperationRequest):
    """
    POST /signup/register/21.02.19/testvalue
    PATCH /signup/register/22.02.19/patchtestvalue
    """
    logging.debug("`signup_register_op` operation handler")
    logging.debug("Operation data: %s", operation)
    logging.debug("Request: %s", request)
    return web.json_response({"success": "Ok", "request": request["route-params"]})

Usage of AppKeys

To access Aidbox Client, SDK, settings, DB Proxy the app (web.Application) is extended by default with the following app keys that are defined in aidbox_python_sdk.app_keys module:

from aidbox_python_sdk import app_keys as ak
from aidbox_python_sdk.types import SDKOperation, SDKOperationRequest

@sdk.operation(["POST"], ["example"])
async def update_organization_op(_operation: SDKOperation, request: SDKOperationRequest):
    app = request.app
    client = app[ak.client] # AsyncAidboxClient
    sdk = app[ak.sdk] # SDK
    settings = app[ak.settings] # Settings
    db = app[ak.db] # DBProxy
    return web.json_response()

Usage of FHIR Client

FHIR Client is not plugged in by default, however, to use it you can extend the app by adding new AppKey

app/app_keys.py

from fhirpy import AsyncFHIRClient

fhir_client: web.AppKey[AsyncFHIRClient] = web.AppKey("fhir_client", AsyncFHIRClient)

main.py

from collections.abc import AsyncGenerator

from aidbox_python_sdk.main import create_app as _create_app
from aidbox_python_sdk.settings import Settings
from aidbox_python_sdk.sdk import SDK
from aiohttp import BasicAuth, web
from fhirpy import AsyncFHIRClient

from app import app_keys as ak

settings = Settings(**{})
sdk = SDK(settings, resources={}, seeds={)

def create_app():
    app = await _create_app(SDK)
    app.cleanup_ctx.append(fhir_clients_ctx)
    return app


async def create_gunicorn_app() -> web.Application:
    return create_app()


async def fhir_clients_ctx(app: web.Application) -> AsyncGenerator[None, None]:
    app[ak.fhir_client] = await init_fhir_client(app[ak.settings], "/fhir")

    yield


async def init_fhir_client(settings: Settings, prefix: str = "") -> AsyncFHIRClient:
    basic_auth = BasicAuth(
        login=settings.APP_INIT_CLIENT_ID,
        password=settings.APP_INIT_CLIENT_SECRET,
    )

    return AsyncFHIRClient(
        f"{settings.APP_INIT_URL}{prefix}",
        authorization=basic_auth.encode(),
        dump_resource=lambda x: x.model_dump(),
    )

After that, you can use app[ak.fhir_client] that has the type AsyncFHIRClient everywhere where the app is available.

Usage of request_schema

from aidbox_python_sdk.types import SDKOperation, SDKOperationRequest

schema = {
    "required": ["params", "resource"],
    "properties": {
        "params": {
            "type": "object",
            "required": ["abc", "location"],
            "properties": {"abc": {"type": "string"}, "location": {"type": "string"}},
            "additionalProperties": False,
        },
        "resource": {
            "type": "object",
            "required": ["organizationType", "employeesCount"],
            "properties": {
                "organizationType": {"type": "string", "enum": ["profit", "non-profit"]},
                "employeesCount": {"type": "number"},
            },
            "additionalProperties": False,
        },
    },
}


@sdk.operation(["POST"], ["Organization", {"name": "id"}, "$update"], request_schema=schema)
async def update_organization_op(_operation: SDKOperation, request: SDKOperationRequest):
    location = request["params"]["location"]
    return web.json_response({"location": location})

Valid request example

POST /Organization/org-1/$update?abc=xyz&location=us

organizationType: non-profit
employeesCount: 10

Testing with the pytest plugin

The SDK provides a pytest plugin that starts your app, exposes fixtures for the SDK and Aidbox client, and helps isolate tests that create resources.

Activating the plugin

In your project’s conftest.py (e.g. tests/conftest.py), register the plugin:

pytest_plugins = ["aidbox_python_sdk.pytest_plugin"]

Configuring the app factory

The plugin needs your app factory (the callable that returns the web.Application). You can set it in pytest ini:

pyproject.toml

[tool.pytest.ini_options]
aidbox_create_app = "main:create_app"

Use the dotted path to your callable: either module:name (e.g. main:create_app) or module.submodule.name (e.g. mypackage.main.create_app). The default is main:create_app.

To use a different factory without changing ini, override the fixture in your conftest.py:

@pytest.fixture(scope="session")
def create_app():
    from myapp.entry import create_app
    return create_app

Fixtures provided

Fixture Description
app The running web.Application (server in a background thread on port 8081).
client HTTP client for the app + client.server.app for the application instance.
sdk The SDK instance: app[ak.sdk].
aidbox_client AsyncAidboxClient for calling Aidbox (operations, /$psql, etc.).
aidbox_db DB proxy: app[ak.db].
safe_db Isolated DB for the test; see below.

Using safe_db for tests that create resources

Use the safe_db fixture in tests that create or change data. It records the current transaction id, runs your test, then rolls back everything created in that test so the DB stays clean.

NOTE: Without safe_db, all subscriptions are implicitly ignored for that test.

Example:

@pytest.mark.asyncio
async def test_create_patient(aidbox_client, safe_db):
    patient = await aidbox_client.resource("Patient", name=[{"family": "Test"}]).save()
    patients = await aidbox_client.resources("Patient").fetch_all()
    assert len(patients) >= 1
    # after the test, safe_db rolls back and the patient is not persisted

Subscription trigger helper (was_subscription_triggered)

Use sdk.was_subscription_triggered(entity) (or was_subscription_triggered_n_times(entity, n)) only together with the safe_db fixture. Without safe_db, subscription handling is skipped for the test and the returned future is never completed, so the test will hang until the timeout.

Example:

@pytest.mark.asyncio
async def test_patient_subscription(aidbox_client, safe_db, sdk):
    was_patient_sub_triggered = sdk.was_subscription_triggered("Patient")
    patient = await aidbox_client.resource("Patient", name=[{"family": "Test"}]).save()
    await was_patient_sub_triggered
    # assertions...

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aidbox_python_sdk-0.2.3.tar.gz (22.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

aidbox_python_sdk-0.2.3-py3-none-any.whl (20.4 kB view details)

Uploaded Python 3

File details

Details for the file aidbox_python_sdk-0.2.3.tar.gz.

File metadata

  • Download URL: aidbox_python_sdk-0.2.3.tar.gz
  • Upload date:
  • Size: 22.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for aidbox_python_sdk-0.2.3.tar.gz
Algorithm Hash digest
SHA256 2bfbf4a1b23c6136c07e694c649b934b94f304f5665776b4191d8981fd4aa40b
MD5 09554bf550722203c22e344a6cad2e2a
BLAKE2b-256 1b6d92d503e4bef31cb679b037d601449aed9f127f30c8b5387e84c42d76b205

See more details on using hashes here.

Provenance

The following attestation bundles were made for aidbox_python_sdk-0.2.3.tar.gz:

Publisher: publish.yaml on Aidbox/aidbox-python-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file aidbox_python_sdk-0.2.3-py3-none-any.whl.

File metadata

File hashes

Hashes for aidbox_python_sdk-0.2.3-py3-none-any.whl
Algorithm Hash digest
SHA256 203f88c2d58bef24594c03fed10cb1c230b3d489822573459c49b2987e78f915
MD5 c96d5c9a64ee878b69a0f38403d6cb68
BLAKE2b-256 c0713d78dfe178b6072e6f76de365f867813865fdd8d5055614ea77f88803423

See more details on using hashes here.

Provenance

The following attestation bundles were made for aidbox_python_sdk-0.2.3-py3-none-any.whl:

Publisher: publish.yaml on Aidbox/aidbox-python-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page