From 573d2c1b85bf92ee856ac2bc4401910b812885b8 Mon Sep 17 00:00:00 2001
From: Frederick de Ruiter <127706008+fderuiter@users.noreply.github.com>
Date: Tue, 19 Aug 2025 16:38:34 +0000
Subject: [PATCH] feat: Update documentation and add new quick start test
script
---
README.md | 18 ++++++++++---
docs/async_quick_start.rst | 3 +++
docs/cli.rst | 16 +++++++++++
docs/configuration.rst | 54 +++++++++++++++++++++----------------
docs/index.rst | 4 +++
docs/quick_start.rst | 3 +++
imednet/models/records.py | 10 +++++++
imednet/models/sites.py | 2 ++
imednet/models/studies.py | 2 ++
imednet/models/subjects.py | 4 +++
scripts/quick_start_test.py | 11 ++++++++
11 files changed, 100 insertions(+), 27 deletions(-)
create mode 100644 scripts/quick_start_test.py
diff --git a/README.md b/README.md
index 9c5c8045..c8b07e8c 100644
--- a/README.md
+++ b/README.md
@@ -6,8 +6,11 @@
+
**Unofficial Python SDK for the iMednet clinical trials API.**
+Full documentation:
+
@@ -72,8 +75,7 @@ pip install git+https://github.com/fderuiter/imednet-python-sdk.git@main
### Synchronous Example
```python
-from imednet import ImednetSDK
-from imednet.config import load_config
+from imednet import ImednetSDK, load_config
from imednet.utils import configure_json_logging
configure_json_logging()
@@ -90,8 +92,7 @@ print(sdk.studies.list())
```python
import asyncio
-from imednet import AsyncImednetSDK
-from imednet.config import load_config
+from imednet import AsyncImednetSDK, load_config
from imednet.utils import configure_json_logging
@@ -176,10 +177,19 @@ disable this behaviour. See ``docs/cli.rst`` for full examples.
./scripts/setup.sh # once
poetry run ruff check --fix .
poetry run black --check .
+poetry run isort --check --profile black .
poetry run mypy imednet
poetry run pytest -q
```
+After running tests, validate documentation builds cleanly (no warnings):
+
+```bash
+make docs
+```
+
+See [docs/AGENTS.md](docs/AGENTS.md) for full documentation guidelines.
+
### Smoke-test workflow
The optional [smoke.yml](.github/workflows/smoke.yml) action runs the `tests/live` suite.
diff --git a/docs/async_quick_start.rst b/docs/async_quick_start.rst
index d1599c48..5552c331 100644
--- a/docs/async_quick_start.rst
+++ b/docs/async_quick_start.rst
@@ -37,8 +37,11 @@ List studies asynchronously and poll a job:
status = await sdk.async_poll_job("STUDY", "BATCH", interval=2, timeout=60)
print(status)
+
asyncio.run(main())
+For synchronous usage, see :doc:`quick_start`.
+
The example script :doc:`examples/async_quick_start` provides a runnable version that
validates required environment variables and optionally polls a job when
``IMEDNET_JOB_STUDY_KEY`` and ``IMEDNET_BATCH_ID`` are set.
diff --git a/docs/cli.rst b/docs/cli.rst
index 85ad8fa1..647d191d 100644
--- a/docs/cli.rst
+++ b/docs/cli.rst
@@ -7,6 +7,22 @@ for the full list and details on using an ``.env`` file. The CLI calls
:func:`imednet.config.load_config` under the hood to read these values.
Command Hierarchy
+
+Global Options
+--------------
+
+The CLI supports several global flags and behaviors:
+
+- ``--help``: Show help for any command or subcommand.
+- ``--version``: Print the CLI version and exit.
+- ``.env`` loading: If a ``.env`` file is present in the working directory, environment variables are loaded automatically.
+
+Example:
+
+.. code-block:: console
+
+ $ imednet --version
+ imednet, version X.Y.Z
-----------------
.. mermaid::
diff --git a/docs/configuration.rst b/docs/configuration.rst
index 8ad9388e..b1648970 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -8,29 +8,37 @@ shell or stored in a ``.env`` file that the CLI loads automatically via
Environment Variables
---------------------
-``IMEDNET_API_KEY``
- API key used for authentication.
-
-``IMEDNET_SECURITY_KEY``
- Security key used for authentication.
-
-``IMEDNET_BASE_URL``
- Optional base URL for private deployments.
-
-``IMEDNET_STUDY_KEY``
- Study identifier used by examples and some tests.
-
-``IMEDNET_RUN_E2E``
- Set to ``1`` to enable end-to-end tests that hit a live environment.
-
-``IMEDNET_BATCH_ID``
- Batch identifier used by job polling tests. Created automatically if unset.
-
-``IMEDNET_FORM_KEY``
- Form key for record-creation tests. If unset, the first form is used.
-
-``IMEDNET_ALLOW_MUTATION``
- Set to ``1`` to allow workflow tests that submit data.
+.. list-table::
+ :header-rows: 1
+ :widths: 25 50 15
+
+ * - Variable
+ - Description
+ - Default
+ * - IMEDNET_API_KEY
+ - API key used for authentication.
+ - None
+ * - IMEDNET_SECURITY_KEY
+ - Security key used for authentication.
+ - None
+ * - IMEDNET_BASE_URL
+ - Optional base URL for private deployments.
+ - None
+ * - IMEDNET_STUDY_KEY
+ - Study identifier used by examples and some tests.
+ - None
+ * - IMEDNET_RUN_E2E
+ - Set to ``1`` to enable end-to-end tests that hit a live environment.
+ - None
+ * - IMEDNET_BATCH_ID
+ - Batch identifier used by job polling tests. Created automatically if unset.
+ - None
+ * - IMEDNET_FORM_KEY
+ - Form key for record-creation tests. If unset, the first form is used.
+ - None
+ * - IMEDNET_ALLOW_MUTATION
+ - Set to ``1`` to allow workflow tests that submit data.
+ - None
Using a .env File
-----------------
diff --git a/docs/index.rst b/docs/index.rst
index ec06b13d..100bd2ac 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,3 +1,7 @@
+
+.. note::
+ This SDK is unofficial and not affiliated with the vendor. Use at your own risk.
+
Welcome to imednet's documentation!
=======================================
diff --git a/docs/quick_start.rst b/docs/quick_start.rst
index c298fdd3..1bf0be64 100644
--- a/docs/quick_start.rst
+++ b/docs/quick_start.rst
@@ -36,6 +36,9 @@ Enable structured logging and list studies:
The example script :doc:`examples/quick_start` provides a runnable version that
validates required environment variables.
+
+For asynchronous usage, see :doc:`async_quick_start`.
+
Cached endpoints can be refreshed with ``refresh=True``. The caches are not thread safe so long running applications should recreate the SDK when needed.
Custom retry logic can be provided via a ``RetryPolicy``:
diff --git a/imednet/models/records.py b/imednet/models/records.py
index 98f9c772..031582cb 100644
--- a/imednet/models/records.py
+++ b/imednet/models/records.py
@@ -9,6 +9,8 @@
class Keyword(JsonModel):
+ """A keyword or tag associated with a record."""
+
keyword_name: str = Field("", alias="keywordName")
keyword_key: str = Field("", alias="keywordKey")
keyword_id: int = Field(0, alias="keywordId")
@@ -18,6 +20,8 @@ class Keyword(JsonModel):
class Record(JsonModel):
+ """A data record for a subject, form, and visit."""
+
study_key: str = Field("", alias="studyKey")
interval_id: int = Field(0, alias="intervalId")
form_id: int = Field(0, alias="formId")
@@ -42,6 +46,8 @@ class Record(JsonModel):
class RecordJobResponse(JsonModel):
+ """Response for a record-related job (batch operations, etc)."""
+
job_id: str = Field("", alias="jobId")
batch_id: str = Field("", alias="batchId")
state: str = Field("", alias="state")
@@ -50,10 +56,14 @@ class RecordJobResponse(JsonModel):
class RecordData(RootModel[Dict[str, Any]]):
+ """Arbitrary record data as a dictionary."""
+
pass
class BaseRecordRequest(JsonModel):
+ """Base class for record creation/update requests."""
+
form_key: str = Field("", alias="formKey")
data: RecordData = Field(default_factory=lambda: RecordData({}), alias="data")
diff --git a/imednet/models/sites.py b/imednet/models/sites.py
index bdebb8d3..54d77f7c 100644
--- a/imednet/models/sites.py
+++ b/imednet/models/sites.py
@@ -8,6 +8,8 @@
class Site(JsonModel):
+ """A site participating in a study."""
+
study_key: str = Field("", alias="studyKey")
site_id: int = Field(0, alias="siteId")
site_name: str = Field("", alias="siteName")
diff --git a/imednet/models/studies.py b/imednet/models/studies.py
index 5095fac9..f96599e1 100644
--- a/imednet/models/studies.py
+++ b/imednet/models/studies.py
@@ -8,6 +8,8 @@
class Study(JsonModel):
+ """Represents a clinical study and its metadata."""
+
sponsor_key: str = Field("", alias="sponsorKey")
study_key: str = Field("", alias="studyKey")
study_id: int = Field(0, alias="studyId")
diff --git a/imednet/models/subjects.py b/imednet/models/subjects.py
index f1cd6b53..da0a89b8 100644
--- a/imednet/models/subjects.py
+++ b/imednet/models/subjects.py
@@ -9,6 +9,8 @@
class SubjectKeyword(JsonModel):
+ """A keyword or tag associated with a subject."""
+
keyword_name: str = Field("", alias="keywordName")
keyword_key: str = Field("", alias="keywordKey")
keyword_id: int = Field(0, alias="keywordId")
@@ -18,6 +20,8 @@ class SubjectKeyword(JsonModel):
class Subject(JsonModel):
+ """A subject (participant) in a study, with status and site info."""
+
study_key: str = Field("", alias="studyKey")
subject_id: int = Field(0, alias="subjectId")
subject_oid: str = Field("", alias="subjectOid")
diff --git a/scripts/quick_start_test.py b/scripts/quick_start_test.py
new file mode 100644
index 00000000..2d4d6cf6
--- /dev/null
+++ b/scripts/quick_start_test.py
@@ -0,0 +1,11 @@
+from imednet import ImednetSDK, load_config
+from imednet.utils import configure_json_logging
+
+configure_json_logging()
+cfg = load_config()
+sdk = ImednetSDK(
+ api_key=cfg.api_key,
+ security_key=cfg.security_key,
+ base_url=cfg.base_url,
+)
+print("SDK initialized successfully.")