From c9d43188cde266165d695f122dbed9159bc910ae Mon Sep 17 00:00:00 2001
From: "fern-api[bot]" <115122769+fern-api[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 17:33:09 +0000
Subject: [PATCH 1/5] [fern-generated] Update SDK
Generated by Fern
CLI Version: unknown
Generators:
- fernapi/fern-python-sdk: 5.30.0
---
.fern/metadata.json | 10 +-
poetry.lock | 869 +++++++++---------
pyproject.toml | 7 +-
reference.md | 358 ++++++--
src/phenoml/agent/chat/client.py | 2 +-
src/phenoml/agent/chat/raw_client.py | 4 +
src/phenoml/client.py | 30 +-
src/phenoml/core/client_wrapper.py | 4 +-
src/phenoml/core/http_client.py | 101 +-
src/phenoml/core/http_response.py | 4 +
src/phenoml/core/jsonable_encoder.py | 13 +
src/phenoml/core/oauth_token_provider.py | 8 +-
src/phenoml/core/pydantic_utilities.py | 134 ++-
src/phenoml/fhir2omop/__init__.py | 3 +
src/phenoml/fhir2omop/client.py | 228 +++--
src/phenoml/fhir2omop/raw_client.py | 220 +++--
src/phenoml/fhir2omop/types/__init__.py | 3 +
.../fhir2omop/types/create_omop_response.py | 6 +-
src/phenoml/fhir2omop/types/mapping_entry.py | 3 +-
.../types/mapping_entry_mapping_status.py | 7 +
src/phenoml/fhir2omop/types/omop_tables.py | 3 +-
src/phenoml/fhir2omop/types/summary.py | 17 +-
src/phenoml/implementation_guides/__init__.py | 23 +-
.../implementation_guides/errors/__init__.py | 11 +-
.../errors/conflict_error.py | 10 +
.../implementation_guides/client.py | 226 ++++-
.../implementation_guides/raw_client.py | 354 ++++++-
.../implementation_guides/types/__init__.py | 12 +-
.../types/fhir_implementation_guide.py | 38 +
.../types/implementation_guide_summary.py | 12 +-
.../implementation_guide_version_detail.py | 29 +
src/phenoml/lang2fhir/__init__.py | 3 +
src/phenoml/lang2fhir/client.py | 36 +-
src/phenoml/lang2fhir/raw_client.py | 72 +-
src/phenoml/lang2fhir/types/__init__.py | 3 +
.../lang2fhir/types/resource_review.py | 2 +-
.../types/resource_review_finding.py | 7 +-
.../types/resource_review_flagged.py | 2 +-
.../types/resource_review_remediated.py | 42 +
.../lang2fhir/types/resource_review_result.py | 10 +-
src/phenoml/lang2fhir_batch/client.py | 64 +-
src/phenoml/lang2fhir_batch/raw_client.py | 86 +-
.../lang2fhir_batch/types/batch_error.py | 10 +-
.../types/batch_item_status.py | 5 +-
.../lang2fhir_batch/types/batch_job.py | 4 +-
src/phenoml/profiles/profiles/raw_client.py | 22 +
src/phenoml/profiles/versions/raw_client.py | 22 +
tests/utils/test_http_client.py | 112 ++-
...plementationGuides_implementationGuides.py | 29 +
tests/wire/test_lang2Fhir.py | 4 +-
wiremock/wiremock-mappings.json | 624 ++++++++++++-
51 files changed, 2962 insertions(+), 946 deletions(-)
create mode 100644 src/phenoml/fhir2omop/types/mapping_entry_mapping_status.py
create mode 100644 src/phenoml/implementation_guides/errors/conflict_error.py
create mode 100644 src/phenoml/implementation_guides/types/fhir_implementation_guide.py
create mode 100644 src/phenoml/implementation_guides/types/implementation_guide_version_detail.py
create mode 100644 src/phenoml/lang2fhir/types/resource_review_remediated.py
diff --git a/.fern/metadata.json b/.fern/metadata.json
index 508188d..204732c 100644
--- a/.fern/metadata.json
+++ b/.fern/metadata.json
@@ -1,17 +1,17 @@
{
- "cliVersion": "5.118.0",
+ "cliVersion": "5.130.0",
"generatorName": "fernapi/fern-python-sdk",
- "generatorVersion": "5.18.1",
+ "generatorVersion": "5.30.0",
"generatorConfig": {
"client_class_name": "PhenomlClient",
"wire_tests": {
"enabled": true
}
},
- "originGitCommit": "26224ef37e22adb507f28c21e8991d4a27822bde",
+ "originGitCommit": "ebd41888bd45310e791509e3f06fd54484fc8ef9",
"originGitCommitIsDirty": true,
"invokedBy": "ci",
"requestedVersion": "AUTO",
"ciProvider": "unknown",
- "sdkVersion": "17.0.0"
-}
+ "sdkVersion": "0.0.0.dev0"
+}
\ No newline at end of file
diff --git a/poetry.lock b/poetry.lock
index 3656b36..83909f0 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -688,15 +688,15 @@ zstd = ["zstandard (>=0.18.0)"]
[[package]]
name = "httpx-aiohttp"
-version = "0.1.8"
+version = "0.1.12"
description = "Aiohttp transport for HTTPX"
optional = true
python-versions = ">=3.8"
groups = ["main"]
markers = "extra == \"aiohttp\""
files = [
- {file = "httpx_aiohttp-0.1.8-py3-none-any.whl", hash = "sha256:b7bd958d1331f3759a38a0ba22ad29832cb63ca69498c17735228055bf78fa7e"},
- {file = "httpx_aiohttp-0.1.8.tar.gz", hash = "sha256:756c5e74cdb568c3248ba63fe82bfe8bbe64b928728720f7eaac64b3cf46f308"},
+ {file = "httpx_aiohttp-0.1.12-py3-none-any.whl", hash = "sha256:5b0eac39a7f360fa7867a60bcb46bb1024eada9c01cbfecdb54dc1edb3fb7141"},
+ {file = "httpx_aiohttp-0.1.12.tar.gz", hash = "sha256:81feec51fd82c0ecfa0e9aaf1b1a6c2591260d5e2bcbeb7eb0277a78e610df2c"},
]
[package.dependencies]
@@ -705,14 +705,14 @@ httpx = ">=0.27.0"
[[package]]
name = "idna"
-version = "3.19"
+version = "3.20"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.9"
groups = ["main", "dev"]
files = [
- {file = "idna-3.19-py3-none-any.whl", hash = "sha256:815e7be7a7806d54abb586dc943addc79e8b2ee16915059658cbeff4b1b43bf4"},
- {file = "idna-3.19.tar.gz", hash = "sha256:5e0811a4383b21dc5838069f801c4fb62113b7447663d2530d2bd6e77b49bf15"},
+ {file = "idna-3.20-py3-none-any.whl", hash = "sha256:ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c"},
+ {file = "idna-3.20.tar.gz", hash = "sha256:a7db850025b95ded1eae8a46181a1a6c56c92c96f0e2b005d9ff8dc0210cab44"},
]
[package.extras]
@@ -732,184 +732,184 @@ files = [
[[package]]
name = "multidict"
-version = "6.8.0"
+version = "6.9.0"
description = "multidict implementation"
optional = true
python-versions = ">=3.10"
groups = ["main"]
markers = "extra == \"aiohttp\""
files = [
- {file = "multidict-6.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c0fe437a6d2f36aac2b49517057776575b5bf359df314cca20d230a6e139c089"},
- {file = "multidict-6.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f3a0a31189acf6703307397c6139ddabd734c20c5ef92649fc93e473df6615a3"},
- {file = "multidict-6.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c9c98d2f0126ba84cb45601eed97ff67ff767e19ae6eb3c31b02827b54d700e5"},
- {file = "multidict-6.8.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7bc7003991ebd368a20d05228137a37b3d3066751f3ea1e4f7b8efe8e752f2f5"},
- {file = "multidict-6.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2c5fd0fd39574ccd58e1a52565b341aff522c5c836f1b3eb7605c371e61f52c"},
- {file = "multidict-6.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1cd4d66ce894a45482e1ac2837c31d0bd447df35065e542b60055aa2d00404b"},
- {file = "multidict-6.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7a2573d0fd34f361a4a14e54d8cda3a91ac4e55fbf0d719698024f3b09c5b147"},
- {file = "multidict-6.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edda19aff836ec515caafc09ea53d2ab144a041f09ee9a7cefcbd3ae4e976256"},
- {file = "multidict-6.8.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e418ec99574ca24365ca96546af285c2b021a1a072478a79f0e3cc3b08837154"},
- {file = "multidict-6.8.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:11d71490bf4bbff1141b14b93af419ad68c56b60bea9277fcb3f94dcca4796eb"},
- {file = "multidict-6.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e8e1e895e23818d343e4ae7dd95a0a556fdeaf8b471acf1c0a39b93c6f54d478"},
- {file = "multidict-6.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:15db8e6cab5f4cc9241bc56e69fdf3452cf49c10ee3c7977c742e68a275b3786"},
- {file = "multidict-6.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8dc2d9c3a924ed14166e63650b2cf9f59e7821743bdd50b23802bd97ca09bde5"},
- {file = "multidict-6.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f2fa3d3b1c933d4bcb8fd2018700d5e7235c52f2ab8c88d22286965c5c0f00f8"},
- {file = "multidict-6.8.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d6dc7804c50fabd28644d4d18a4b20aad3681b3e64f3acd3182b330ca73f7a32"},
- {file = "multidict-6.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0eca15d627e942ce186a935061f1568cc46c02e97c419c8da802df2be9f917d8"},
- {file = "multidict-6.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d7e5ba0a0153e35fbce9c51df530c8b4cb0c3012b46a04ff9a048441a269c2ed"},
- {file = "multidict-6.8.0-cp310-cp310-win32.whl", hash = "sha256:b7e62b8fc7bd6cad007b9f2e0ad9c8d4854c06350d5f51e1a439dd18b510ecac"},
- {file = "multidict-6.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:dc911ae6152e455b16a2a1a626aa6cd612fa01efb9d0a4ab3f5cf328b911483d"},
- {file = "multidict-6.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:6300d5176647145ba1e22991c924fb29743e54b4d7b8bc85a0d3ec0e55e189cb"},
- {file = "multidict-6.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1b8986d4313dcee7c932837d16a535f1840b827bac1ea7c5c4c80751d0423794"},
- {file = "multidict-6.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2622fe114c0bd66ca5c461859357587f5a5e35ee5ff49fc5643d1bc78dbb41c6"},
- {file = "multidict-6.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26a7aafc992e78872e2c8c1f7248c0e01139cf9020a7781b0c064fa566832712"},
- {file = "multidict-6.8.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:05c2e90c5289c5f7436ba2c25812a5fbdaa1c1bc11c8d8d3bbf64f5cd7c633dd"},
- {file = "multidict-6.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7941ef106ca1f2c62314a13c7ed913bcf49641f3efdc12864d588e17870920ac"},
- {file = "multidict-6.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a5a7ee1217949ddd43c6b7bcf70d5c22193bb50e8c695386de5905325e93ce9f"},
- {file = "multidict-6.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b62b7e0025aa48dec11e125e655d1157985a5fdcec04b1ad500101ad072b891"},
- {file = "multidict-6.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ea880d441be7c510106bc56064be39266d948aef94ad4955e8784690019a5d9f"},
- {file = "multidict-6.8.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ab83fdd8cf307353edba9c427c17a3a021c2522d690f5633dd9f72d28b48ccca"},
- {file = "multidict-6.8.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3d1f48582686a0a3b81e9b43234766cc96697df72081af3f48107bd3f34d34e5"},
- {file = "multidict-6.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:563661919f603374c40cf45ffcd25535c12b8954203569a2ab1cee5265871cf4"},
- {file = "multidict-6.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2ba9933e8f35fe4a70f540b837254c4055da82dc3a9e500a8f95e61498083a15"},
- {file = "multidict-6.8.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:68d40b2bace413f3231f5729d3fcfb1837fd31c4907e241b5d43211bfd76f3c2"},
- {file = "multidict-6.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a9e246f67ac038568b854ed7c5578e4c6af1f742359901a8fcc3603ff1358df6"},
- {file = "multidict-6.8.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:29b6e7bc4442a56cf8e0dc1cabf3fdc77cd533568d6829fc76a1effd2ce332ec"},
- {file = "multidict-6.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:82780eb8bf59e8fb25dd081fde6e058805045d6374a7f2f877effc826ca4434b"},
- {file = "multidict-6.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2196ba6df392c3574acadd14ef87550f3611349c8618564de324b806a7a31cee"},
- {file = "multidict-6.8.0-cp311-cp311-win32.whl", hash = "sha256:b8b7aa75146266fd3e2a2437cf69ae188688c04ab8665b163d4257b46c1e0c83"},
- {file = "multidict-6.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:b03ca066b47b18b205cc080dca6f76cbd159f8cdd33a02a0700164c13b37e463"},
- {file = "multidict-6.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:54af1266710cb0f305127ae0b970aff8d208057f8a29cd6e1db99b0114947035"},
- {file = "multidict-6.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:22a310ad37672a261e55a8b5e28d0ae08cfb68abb1f46418ccd19835c3b8e836"},
- {file = "multidict-6.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bb8c7da8c861391f7ae48e3593762be2dabe405109e01aec520fbe1a6d15d14b"},
- {file = "multidict-6.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:10456943903744ae1249728161c96bd9d2f7eb5ee17fcc2ffda2dc32e1bb36c7"},
- {file = "multidict-6.8.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:658f5a1895b804423d97b22d06fc0d0b171c7c01dcc3aa9c8faf0c0e26a249a5"},
- {file = "multidict-6.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90c10b22860dbd09982d0b8993b66231a861bea2993d4a817ff35273f6ea285a"},
- {file = "multidict-6.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:088b04a66b3c1fce6fe4d771ec184a0426262d0b86709c908477b4ac7965df40"},
- {file = "multidict-6.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9caef53b20a105c0d66518a34be2f71b2783de8d091767575ef86f6ea422236d"},
- {file = "multidict-6.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a5e1583c14775580da05641240ce0d93f36ce3ddef3d5083a827468b0bcfe874"},
- {file = "multidict-6.8.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:003a3bddb32915c3f67096ea41d24e53edf710edb65a1f5d0c70ab40b0e4d20b"},
- {file = "multidict-6.8.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:35977263d9bf506dbc65349f63b3b8c91606d4abc110990945e3b94bc671319c"},
- {file = "multidict-6.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e9dc7b4ff6ef184504b49ef9a4113d49a646653b2ce89f5f48c1f57cdf6ba081"},
- {file = "multidict-6.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:887f9a975996032c686719eb7b3e1e7942fab5079c2b778bbd9afe9a9d78244f"},
- {file = "multidict-6.8.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f3071e6515cc63714d014da8f738ae9fa3997c476203f3cd46de380c2376ed7b"},
- {file = "multidict-6.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5f3a2af441670d80ce5fdf13b6c1b421fc1fc7fc5182d58ac7486738bb2b742"},
- {file = "multidict-6.8.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:31e8901637e20ccb3cf8f8848b5d0f7a00462bf5b34f7cf3dcbb2753b18e8b39"},
- {file = "multidict-6.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:13967dca8b2f33230a1427b52438326bb1c9101a1df22a3309ed3fcbbb3c96f0"},
- {file = "multidict-6.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad474c11d851b6fc97cb625e4822bc0cbd567fc07dc2602e28faec5a36b42bbb"},
- {file = "multidict-6.8.0-cp312-cp312-win32.whl", hash = "sha256:7bb0dad75068fee80fcb60f88569722c199d8656a16706702dc6e3b786819c90"},
- {file = "multidict-6.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:7d26dc8f070c0ec5579e987fa615ffd6883086106eefdff9e10d160fc5630630"},
- {file = "multidict-6.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:e6ec7d37841609a691b96a10b4fde386c7cd93ebbb939f59c9f23325ee788395"},
- {file = "multidict-6.8.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:ec0a4d066356054d569a66e0a94691a2058b680be5e710298f61db11a3c4609f"},
- {file = "multidict-6.8.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:714597cb5d5e15a8a449d2ae23c45b486a9e8fa33c462c7a33d7f35b65d92943"},
- {file = "multidict-6.8.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:e0db3a4d1e264e225037a6023888972c25206a96e016021a5bea41c9a939f2a9"},
- {file = "multidict-6.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:27747162712e85c84598d364425dbf1714ff335bdb6ba3171c4e5081196e8916"},
- {file = "multidict-6.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:847d6082ae694dc95e548acb201bc100e1cfa96513bc71fdcb86f709dad6c435"},
- {file = "multidict-6.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:88a6df88567680504ae28bfa7a1f2f64243d91e79a40b2c92ef42efc531e23da"},
- {file = "multidict-6.8.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:560b211fc3bd4a1e1c6de44f6d38113bf5b410dfc89a4c0d2a3c0edbf1a0dfb8"},
- {file = "multidict-6.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202436df907c15adbb94360296c425ea53cf8968a5d2cff9b5b9790ae1972b33"},
- {file = "multidict-6.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c46a08bf070d6849fed483e9d9833f9d06aecb8382ed985be0b38508b3ae958e"},
- {file = "multidict-6.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2cd560498ae8e1bcc955643c1d78eb8e338226d07a983c656ea8c4443d3eec0f"},
- {file = "multidict-6.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:758233648ac47b07c575224c4eadd73c8929c3b4c31e2afcfea935fde1cda735"},
- {file = "multidict-6.8.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:122adc7c46ac1e31ecfc7f81b2530533dccafdba70f5d741649f87e336c63384"},
- {file = "multidict-6.8.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8125e60f3c70e323ac07dd8b3635f7b3bbc5c3a9ac04ae5988f668ff7ae28a18"},
- {file = "multidict-6.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:83ff054b04915be5c15680da6c6012474a2cc2bf534129a0e8c6a99f17ba7238"},
- {file = "multidict-6.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:930c6058047410e3edff445f5a6e4457f2e089042dede00e2d18ce06f3ceae2e"},
- {file = "multidict-6.8.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:13e26f59f0eecfc5f67c663ad550ffdaf62c0f657547cde387f6c86af1c9449e"},
- {file = "multidict-6.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fd789a294d8e098528be29b2669b83005ce569339f8cef167fc0274c3115c34c"},
- {file = "multidict-6.8.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:3126f2a96704505aa4e92a72d6e8a5d7f29d40a987ced8bf69e29d71dfc71fbc"},
- {file = "multidict-6.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:23c9ee89967b6a9b4048acb3b93b660ed714ce9c8bf3bbe652959bc120dc02dc"},
- {file = "multidict-6.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a62e302fc8cd6aa8972207e7e951d1fdee7c1dda18568305041d19f0e2c00f5"},
- {file = "multidict-6.8.0-cp313-cp313-win32.whl", hash = "sha256:093167d22a8c95af30f597b8a5686f20a14512989942d4be804d119899caca20"},
- {file = "multidict-6.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:f25b61a708bd276e8cbb6afcbbf1b8e793a3be70ba0a842d0b8692020f83b706"},
- {file = "multidict-6.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:bb36381e1f9f9d06eba2f10bdd438e5d20c07d5b55e1a3eee30b9f44cbf52316"},
- {file = "multidict-6.8.0-cp314-cp314-android_24_x86_64.whl", hash = "sha256:f8b09b25e0f4dc2ea9e2adbb1cc3ba11a94d6fa3dd978ae659c8743052e1afbc"},
- {file = "multidict-6.8.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1f57c414be82490bc0e0305fdb834186229b2d9b6a35fa0afd1eb1a772d125ab"},
- {file = "multidict-6.8.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:00be37bde741bf60871082cd347a093218c44886e99231b7516671c70f2c280d"},
- {file = "multidict-6.8.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:e37b744849fb631bb52e3dadde35ffeee365a6c41cf71257b5b7acc9cd83fd38"},
- {file = "multidict-6.8.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c2b2a96cf1dd99fe7867be4c013314225f4d5786e6685906e29932d42aca6f11"},
- {file = "multidict-6.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:bea7df027015856ba5d0a88e3b4777ff8cb5c66b58fc108050fe79d4dd9d4d2d"},
- {file = "multidict-6.8.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d3da668e903c934ed0b587ecacfed6901f6ae6384a6e975887592b61845e78bc"},
- {file = "multidict-6.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:64eaeda36ee8d88f9e8616a587a8c66a663283cf6e0dcf013c1ddd8c758e4aef"},
- {file = "multidict-6.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ac746cb365bac1c462da9e3e6ab8904a8efe2217a56b0b2e3d9480f41d2b2602"},
- {file = "multidict-6.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:18f0e06360c3e451a3ab800355773c8d125a758238d780c800b0ee5e90ee903c"},
- {file = "multidict-6.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:69708fecaa88bcb2341397b49fc95057a835b02a3670c551b37f95dd79e64e3a"},
- {file = "multidict-6.8.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9606f583e7acaf61e7b3f56074e14037b9af7cb194590edfc0114b3ae5931ff7"},
- {file = "multidict-6.8.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1f66fe6a021173d0d47968491791966b9f3e6d61115f2491744aa0c07a6e67af"},
- {file = "multidict-6.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:be007d1aee2cbd530347dcafedb400891a3b5f1bd7135f95cf5d5b330b5219ee"},
- {file = "multidict-6.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8457aff3c12a89a8e1c4674de5c777857fbc429f40fe117a3d29538547cbc364"},
- {file = "multidict-6.8.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:95c27b4f3f04320fc44e338573f40c5c956b504a7fcf081a157fd0b02579311c"},
- {file = "multidict-6.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:d244cf6b52b5ba1c34c3832f4652a668ebb36d95949b96eed9a1c54d916a90dd"},
- {file = "multidict-6.8.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:5bbbb696c8024475b1877d14ce20d5f1cc05b8f6d786cea0fe3aa7fedc02e891"},
- {file = "multidict-6.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:cbd86f9787c5e2f5fd27d8b21458222f107347c6731c4e93dde68f554b466a2d"},
- {file = "multidict-6.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2f8a4b0b4d639d525928c7f30de527bfdf9ead6e44a5e8cb9c50aced5e4590cb"},
- {file = "multidict-6.8.0-cp314-cp314-win32.whl", hash = "sha256:8890c89d662560e51c55ac1304d6f919b23942abe9ae1127cb1de9aa6132fa52"},
- {file = "multidict-6.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:45cc39ba50fb0754a4359b90f8229ae08598fe2266abe3521b4e5a9ba916534a"},
- {file = "multidict-6.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d0264f8d5cb0a803f650a6a8572dfa0cd1e099a2234c588dc8fb220b415b865f"},
- {file = "multidict-6.8.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:1969971900b0871530f9b62280dcc2d75688e74d2a69262bc01faf2b96c78f04"},
- {file = "multidict-6.8.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:8180b635290a75af8478f1b3e9810135381ae24833293fe77b85c1c21ff842ab"},
- {file = "multidict-6.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4261863fc8b5ab1b815ede94e592e94c6af5b04616014929057e61859e7382a9"},
- {file = "multidict-6.8.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0b143d53590e89f43153d81d505a8448d4d57354354385aef8a51d67ffefa27e"},
- {file = "multidict-6.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:da1c112c5784ccd9d32cd90be6739fee32644e874eff6ae8f0497cba3e352e58"},
- {file = "multidict-6.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f7eefd0233a7c33ca980a5cfef26f1e9b5e2137839e752a99963696729f12d91"},
- {file = "multidict-6.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:348bb85e2038b40c007383616d73f734869063772372519549ebd7da1723d1a4"},
- {file = "multidict-6.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:095f62ea4e7a3be2f6c567ab695ce10e950f2adb905c1bec82281593e0b2d2ad"},
- {file = "multidict-6.8.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be569fff1d85cd29391c431c5641c8772acb75bbdc61e60a8e82fceb9023d385"},
- {file = "multidict-6.8.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3533a03e4e789baf6a286e7b0b1b6da3f3d7c3eab569686ee29ee1d8b52e2cb4"},
- {file = "multidict-6.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1bdb9b8fba5a9aef673ec90db3f55b1ce743f2fbdea4d37dc04d14ccdfc153ff"},
- {file = "multidict-6.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:f8d7b66c9e09c0bb0add2b5895e646b62a0849e71155066f215523de6b95cbe6"},
- {file = "multidict-6.8.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:563d6500ca80dac7bba6f48a78e0ffd87e21a7d4d24642c6503a2ddccd70c110"},
- {file = "multidict-6.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:346ac52e56bcda320c0dcdfdd081947ed7cada33afea4e2284bef7b0733bff9b"},
- {file = "multidict-6.8.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:4ee953a5ebaeed38dc21cc032ed17a9d9782802e00042200497ab4b01b0bf7c0"},
- {file = "multidict-6.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:2f79cc3e8039a8cf5c77e0811b0807953fd52d0863b9b76970b20d696dc64a78"},
- {file = "multidict-6.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:43a4b56555bbcf8af161e7c7682bd93eec10f068c95844511864c018c8e5e13b"},
- {file = "multidict-6.8.0-cp314-cp314t-win32.whl", hash = "sha256:48ea524a25a1cd5972cf293bc95713918cba0bcd6fa9b992d906c857c546abe2"},
- {file = "multidict-6.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d0be2b832435001bc623ca7f1499ca1a853d4f082fb61221a80ce71132f50b26"},
- {file = "multidict-6.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:62b8e291a4f7edbf7cde7a43d831d893ba443a1b627498b53581943b0e348feb"},
- {file = "multidict-6.8.0-cp315-cp315-android_24_x86_64.whl", hash = "sha256:e192018b732f7b168e6604cbdf40fa8e05c996693b9eb445a0d8a73f4b77c5d3"},
- {file = "multidict-6.8.0-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:b25426f9f6ed402835617c8f23609a47045f91ecff365eb6734817e039a8ed25"},
- {file = "multidict-6.8.0-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:fa6c2880709c84457de104385b704fc28860f27e442ad13966fc4af8e714fe9c"},
- {file = "multidict-6.8.0-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:eabb03dc3e4ed6333ecd1cc9826ec80e7a98b5506deeb832d7260c8e44166d23"},
- {file = "multidict-6.8.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:59e539c4eb4d3a53b0e630a6ba2b2f2824732b5e73f90e30a280f12fde157b15"},
- {file = "multidict-6.8.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:835d5a90b11d1f5f8200ff3cc8316bded76eebebc92436398947a27657e645e7"},
- {file = "multidict-6.8.0-cp315-cp315-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d2d236b8a44ae91536a12ebcb996bdb31cf27425f36b4d05c87f2ba2716050ba"},
- {file = "multidict-6.8.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bb9a60b7faa5d37c426fa91cf4d6738182a1f2755b9fab7c9c64cd466c4ce51e"},
- {file = "multidict-6.8.0-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0ef606c15cac6c90279acf34120784b6f36662cbf382defd3955cd8f1115336b"},
- {file = "multidict-6.8.0-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:68186a2d4051c8ffd17be33553bea2ec9bbc8ef860fe2980a221d96126296f31"},
- {file = "multidict-6.8.0-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2cc66abb85e2108c9ff8a1c0d20fa260bf690bbb33caef4ff3ecb2c2cbdfff5d"},
- {file = "multidict-6.8.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:69b3e519a132bb943b0daae15fc8c2168706b17f826481d32a32a5e784b129e3"},
- {file = "multidict-6.8.0-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e41226ecf607f062fe34a2f4cf64ad3a89e3a0180dc800b463b6b14c06dd10dc"},
- {file = "multidict-6.8.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:610c7637bc36b90f39e6c66f710f93d57018f83d53e1e187caaa218c6892b95f"},
- {file = "multidict-6.8.0-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:65c85c79f5a2c04fbbc18f006c014674dc5fdf270cb978d8862c82c6f694e60c"},
- {file = "multidict-6.8.0-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:628ff11e6720f90acd0c305dfa3339f04a783a20de8cda6ac333ba46447261e8"},
- {file = "multidict-6.8.0-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:0935971bffd0b479fc90c4811ca787703e93fcb6afea939a375dfc80285ab368"},
- {file = "multidict-6.8.0-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:9442b14eec262a1f74369bbd07e75bc5155105164649a4b9fbc1ebc7b8fb0b14"},
- {file = "multidict-6.8.0-cp315-cp315-musllinux_1_2_s390x.whl", hash = "sha256:397599503b718f0137f26d3f6532d6955069cd2e5917c47ef581495bc2529ff8"},
- {file = "multidict-6.8.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:9e37024b41d7a7e7e9cce14b248d54707c21c2a2ea30a47b71bdcefcafec00f2"},
- {file = "multidict-6.8.0-cp315-cp315-win32.whl", hash = "sha256:071da134651b04a8507dfb331ac0988f376337c2aea59486bf20989fb5b5a64e"},
- {file = "multidict-6.8.0-cp315-cp315-win_amd64.whl", hash = "sha256:3bafff8598f0528017ddc74194e5451d5c22d046c98935f8f86247b0f286e4f8"},
- {file = "multidict-6.8.0-cp315-cp315-win_arm64.whl", hash = "sha256:e886ef8c9879105fe4fc99417447b3a5f35d1131412ce839470bd2089fe2043f"},
- {file = "multidict-6.8.0-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:883284137e25318ed9735b742ae46341a864888fae28e8b6314c4f84da080f08"},
- {file = "multidict-6.8.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:ca52b9ec80851366197577154c862c4c4c7036ca76ae94cef5cb59c5cfeab944"},
- {file = "multidict-6.8.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:91fa75d0a693832106d98f66c849f034f21c828d14437f1fb97d3784aab89e84"},
- {file = "multidict-6.8.0-cp315-cp315t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:307c1acd812fe897e7fbe10c6758822e8c04be4e7c60a9f54901cdf8b5ab8bc3"},
- {file = "multidict-6.8.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf684986a2490628f059a99dd107b566a2d34cf947f8eb8387e0500a1f90c5"},
- {file = "multidict-6.8.0-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:77745725125d01fd613b6db043362aa7c6bfbfdb23d45dbfc3d92bf58160af62"},
- {file = "multidict-6.8.0-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8daafaa0b2eb43f76898ced78b1e0fb91b38c4fa50da516c18067f2a2d578c20"},
- {file = "multidict-6.8.0-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c68e0c0649d17c2d0339e3674e86a4aeba4a7e6b21c1e394cf947a95433b31d0"},
- {file = "multidict-6.8.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d8a5ac357ac283490a8d1899b0383355fd1f8634b14ba0d59e4c0dd97db85556"},
- {file = "multidict-6.8.0-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:46029e6e27a3ec0dc55b53f58df82d10f04c5e111f78248279b530bedad2c30a"},
- {file = "multidict-6.8.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:8d1046b5427dcafe6e8a0e07527dd74f1ee694006160162f53f3a17f15aad3b4"},
- {file = "multidict-6.8.0-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:f1f4a220db6ed7c8fd16b6d644ffd1f082651693204daf3275e049fadc849e39"},
- {file = "multidict-6.8.0-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:029897732a9c798737457e382bf84e8c64237eff224a90aea2639f4413c45e4e"},
- {file = "multidict-6.8.0-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:29be9fd289e9ab8f480996ea2f686e1654b80242033843cb11691688329423f1"},
- {file = "multidict-6.8.0-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:29631224698de1e42abc8fa7658d830e0aed0029785144b5832b695da5adef2f"},
- {file = "multidict-6.8.0-cp315-cp315t-musllinux_1_2_s390x.whl", hash = "sha256:962f18c59a000f30b084ea2e6b8001521bb315efd4e5f10acf9fb36f366b7882"},
- {file = "multidict-6.8.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:c60e50bc5b07faac92fd3a20fa21cc8cf3e3f7204d2867b206c73293ebc19101"},
- {file = "multidict-6.8.0-cp315-cp315t-win32.whl", hash = "sha256:fc5460940f50dff00731b4132366840ba9685286ea88ea104b661899084f3fea"},
- {file = "multidict-6.8.0-cp315-cp315t-win_amd64.whl", hash = "sha256:b367c342327717d644db4c0ddb37ceb655c84822215ea0773a3a36911b74b71d"},
- {file = "multidict-6.8.0-cp315-cp315t-win_arm64.whl", hash = "sha256:0c1c4debad7337627b86837abdf0237ca3cb3d7e17de7eab0177c263878546d4"},
- {file = "multidict-6.8.0-py3-none-any.whl", hash = "sha256:75daa15ca16d6285eb2e104b2f05ee6f8d9836c68da3ce5c85f615a0450eed0e"},
- {file = "multidict-6.8.0.tar.gz", hash = "sha256:5cd4637ce76312ba1e05eb9c5193fec231f64fee0944e135fa1e951242355b37"},
+ {file = "multidict-6.9.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:63c9da87fa6d4284e57d2a6e549dfe8f2938ab578fddab3f8ed9742812c9d0f3"},
+ {file = "multidict-6.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3663ce6cb19c5e3123c9aad5907804a42d384f8cd4b67e59291efc9480f8da9a"},
+ {file = "multidict-6.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f7f340a4a6ad4dacb0f866143452d794ea32a0d9ddf79d93ecb4c3ac5515d0d4"},
+ {file = "multidict-6.9.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bf44632149302f7fdcf5baecc277d816ab77a47a268f2392dc5d2d01c56770cf"},
+ {file = "multidict-6.9.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:095b091158c89a03ad1237b4880f857d27628f93c23da1616ee5640011439c53"},
+ {file = "multidict-6.9.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3958fa87a161a6b9c6661606784abdd8f1afa21a0d6e99d1b99512e70e6b4f1"},
+ {file = "multidict-6.9.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9f99e0eec05aca200b66735a38f8de5c9be03a6afd62ba7f28860203d936a03f"},
+ {file = "multidict-6.9.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a4d98efa7b004b67cb8cca26b218012efa50c7103cf4ae54898f2bbf89a3c62f"},
+ {file = "multidict-6.9.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a23926c06835ad71e6bc755ebc07ad34655847de63c01a5d06b6501997712c4c"},
+ {file = "multidict-6.9.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:06723cd13ace09a0ce1ed010fc9e57cd762e57ee23691d6cdb13b7fcf1a35468"},
+ {file = "multidict-6.9.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:27dee31d6f3a0d2be018b71721adbe24aed9b08bdc69d133c88eead07beee600"},
+ {file = "multidict-6.9.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:90d341b2c64eacef24fc0a35aaabc5227834ce93bb1da416d61601663df29456"},
+ {file = "multidict-6.9.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:986de92227e44b257fef664a69613a4346a090553c186d0ae3bf15ceab447f5e"},
+ {file = "multidict-6.9.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c8da6d6fc78f971ebb9e29563c891a429374861afda55e4692a7962e3822637d"},
+ {file = "multidict-6.9.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:8903ce696f0aa9dc301c5621fa0f0e24e985d4e6cc247cd63bc9abcd5a081628"},
+ {file = "multidict-6.9.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bf345dacf96fd9c698ad30c620fbdbe6e1edadf83944203ce5b5688f52e3d141"},
+ {file = "multidict-6.9.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e63e05228c1f1c1bef09c08abd2f97b6fe597c9ca14a1c94bec4e76b4664046c"},
+ {file = "multidict-6.9.0-cp310-cp310-win32.whl", hash = "sha256:f25229fddbd6bb3d47f1141c319bead19fa3c9e62790c6d51201564fde05fc2a"},
+ {file = "multidict-6.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:05f197459db34dee24ae7e3560affa5c6f93989805899c9bba13358b5116a12e"},
+ {file = "multidict-6.9.0-cp310-cp310-win_arm64.whl", hash = "sha256:d4464437dbbd7a5a71a5e86f2a9ec92ccbb8d96706f5a173ca985175f23adaf9"},
+ {file = "multidict-6.9.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7e46237ef18c8ee183dde740f0174d6ecf9c26d362b506b5d23fb57bc3634bc0"},
+ {file = "multidict-6.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e33fabca25633cf0e4f9dd4495733d09b7f0628fc9424c5b5e58da644fd4ab94"},
+ {file = "multidict-6.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e82873b56ed37b328501fb063962299ea6f7fc1caf1a5c47966028824bde0807"},
+ {file = "multidict-6.9.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2e2169fdb886288fc6bf9d8e48abca9487f8b3ace1f5ab269b074864d212351e"},
+ {file = "multidict-6.9.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eefec2a6b0381846ce54d88f30de4b3a5c15ff0bddc5264cccba85b710a8785d"},
+ {file = "multidict-6.9.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c63013a210a09d4a8f30814b785450f1d0a2aaef8230c1e068e83f3afceb6030"},
+ {file = "multidict-6.9.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4fd82f81dd0676059f9bc3a418a79f27feab19486100a255bf8488cccb3e60d3"},
+ {file = "multidict-6.9.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:deea26b6979ce46f2fb3b2db9b651e12eb7f94c26a1ee457b79f66ad36a64fd1"},
+ {file = "multidict-6.9.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:58a4aee7188676c8317e3131bd844faf70e427979e1f20b8598c61f6cbd8b073"},
+ {file = "multidict-6.9.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eee11705013394ebeeb383c92beb0fc9a3c449ac3382a6ee3aa23b38c6b06c3a"},
+ {file = "multidict-6.9.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:51e77d089f82ed2e288d3a1cbf6cb7ffa927c8055d8ef61d57b27f4d8da557b6"},
+ {file = "multidict-6.9.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:79640bb8746b703971fb16569e7bfa82d90548137cf4094769aa45cbafda9d9a"},
+ {file = "multidict-6.9.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:092214366f729803010a5c260f4a4f44d223c688641dfc27da851588ac762ffe"},
+ {file = "multidict-6.9.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:da469a672bf3d343eb6757d53ffbac36f1a29b93a9fe76558b5d0fd7a7efa599"},
+ {file = "multidict-6.9.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:4216a8b4214a1ee4511c551c59d51534637394e9433765fbd8face86db43c532"},
+ {file = "multidict-6.9.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f05f5b3171e23801e72fd818de236be9f239b10ba699f23e43bb9596651f8b34"},
+ {file = "multidict-6.9.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0c69b098c85685ba39efef1d8a9711243df8a4c4b051a35d3cce7f323381f8bb"},
+ {file = "multidict-6.9.0-cp311-cp311-win32.whl", hash = "sha256:855be03f39b97e352d54eaa7b14ba2a46846cf14719ddb689cdaaee811462440"},
+ {file = "multidict-6.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:a8040dde3fe35ead6b04adf3cd3fdd3bfc7c941505775d230b4501d18227c77b"},
+ {file = "multidict-6.9.0-cp311-cp311-win_arm64.whl", hash = "sha256:70b3097b838d9fc336f426c7aa7d45b7881ee9b06a10f4bcffd0dcda0cbd44e5"},
+ {file = "multidict-6.9.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fdd484b84d3394e805689c56be3ab1f877ae7ff0eb9ff90a3ee7a755cbebab4f"},
+ {file = "multidict-6.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f93c9058a0eceac0df2ce9d4c8823b84786ee598194753c2ca0c100224405e47"},
+ {file = "multidict-6.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c7ab60b91e11b25e7682c5cd8763fdd17929ea83f234ba441091f1492e631ea3"},
+ {file = "multidict-6.9.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:640113258c5925a9eed2c12523410b25565ac5df2fa6735fbae88fb09bcdd212"},
+ {file = "multidict-6.9.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2ea72901860ccbe94517421681c60b13533ce03ba2f7bd96293c3a4d16ac4ccb"},
+ {file = "multidict-6.9.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:408fac672931f2458be3bc8c89d9facd16dac2aad17c7cee2ca1693eee99f07e"},
+ {file = "multidict-6.9.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:67bed23e9803945b0760650ec3e903af772c49abe869f3bc03c66b2e7649d5ef"},
+ {file = "multidict-6.9.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4bb769ccc72e15d7d441e1a08f169d418376be77cdc387e813129c26b357fe50"},
+ {file = "multidict-6.9.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6a5111a2bd824c821a3dd09da29680391b0caaa18fea7761358f4001e6898d1c"},
+ {file = "multidict-6.9.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8e991677c4bdc5d9f2e71c74717a4e32cfe98930ca05becdf722b5eae1329d6a"},
+ {file = "multidict-6.9.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb69b724c345420ba49187a17a894f146099f5b2e501df42ddb4452ac8be37fa"},
+ {file = "multidict-6.9.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:cff3cff5a725bdb8359962de8d7429aea592d7693dbd197eeabbdfab9b6300e9"},
+ {file = "multidict-6.9.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fca5b74b5909c29041f857c40d51d9273636fb4221cf020e4c452deb1c448a40"},
+ {file = "multidict-6.9.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:11e32ccf23cdbfcf8299a6a825930a858ec9a6aa05d6752d0f90f2bdf19489e1"},
+ {file = "multidict-6.9.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:3ec1e387b1f8a85ae5b94aa8c4e0576912ffa4d31bd0578f24c950d4f05ee476"},
+ {file = "multidict-6.9.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e4826f6b56456fb1e98111d7bc20cbdc7fa0a41b1f9ad80ff2dd3f2f5b226fe1"},
+ {file = "multidict-6.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e71a072c52c78b7f97cd4611df6cef10977e4f2367cd0654a7626192f931adde"},
+ {file = "multidict-6.9.0-cp312-cp312-win32.whl", hash = "sha256:95d339c3b75b4a50c665bdcf8417428cd71c3e5cd48e194cb1d336fcb856beac"},
+ {file = "multidict-6.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:8f06c4da5315a6f709b13408c3e13f3b475f8c559ec7608c3c67062512871235"},
+ {file = "multidict-6.9.0-cp312-cp312-win_arm64.whl", hash = "sha256:0db5bf96ec2ce45a8bc7fbbe8a486089969bb2791a66b6789ee3aed0d5dd562e"},
+ {file = "multidict-6.9.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:662315f8621b3559268813b11134c1f9633edd4ab5f7b713688a243c13f4026d"},
+ {file = "multidict-6.9.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:4bef8cb5edea9c9daeb8396a75eeb97f912c3fb3fa408fe659edfecf91e47424"},
+ {file = "multidict-6.9.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:75f7fc21ffce9a792cb919f0e0b0b52117bd672f2a55d1929d573b6fc437f374"},
+ {file = "multidict-6.9.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8bb6be697065cbf31051465f9939d65624573d2219c3da8316db9e7cf5e0f5a7"},
+ {file = "multidict-6.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:67bcff396d2ad62197c95488a716a88462792b384b5ea6e44bf7c1070eddb8fc"},
+ {file = "multidict-6.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:beda95a6bd0a2e2265b941b90ff72543afbeaebb6a450e3a6a010d10d4a2ffca"},
+ {file = "multidict-6.9.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e78870909e9f9e3d672ba99f1eb75130d7e01c42e642e6a70f434df32ca0ee1"},
+ {file = "multidict-6.9.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:91092d597fcf0940cd6a59e64ba7156ee22d6899993fd7c5b1897fda71482f8f"},
+ {file = "multidict-6.9.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4be612f23990a261060ccd8f15e89dad1f9b7bb0c1021c5c3987f5fc57959391"},
+ {file = "multidict-6.9.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7aaa14f0b9ffa2780c5d3b21da0e9b58778ed47af3369df72e5fd6dc10ff8041"},
+ {file = "multidict-6.9.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:97555ad30ad20a8eb90fa86522088eebbbd68aba03e56d53f4850b3535c65e61"},
+ {file = "multidict-6.9.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c51fd8d59e72e45c64907bf7f81fbd94f4c8dcd1c8b2f23f4c2d7ede788fcfc3"},
+ {file = "multidict-6.9.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:22067e88ff266e6a5dc59114529332692a01cc04b10dbdc2c14ab91217dee819"},
+ {file = "multidict-6.9.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e231de8ce43d4fd10bec4f67f71238ed88a974de30a9f20be7a4ab16c970a988"},
+ {file = "multidict-6.9.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b33e499a7b1f722547d57b4865ed68c03161643b9afe49fe097a0832078d183d"},
+ {file = "multidict-6.9.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1eb7939025bd9289d9dfe3a399102b1642f4fbb105a6af82f284052ee89e97a9"},
+ {file = "multidict-6.9.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:51a08dceed4b42ef25755ee2cbf50df325e90e6b415d00955ffdea2c394ad6c0"},
+ {file = "multidict-6.9.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:cb847cb4002e725f88ffe29883da8290fd0754fa0461ed8988735e20964a9f65"},
+ {file = "multidict-6.9.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:516fa4817cd070088f616a901380db56189f86daee9da79aada3c9b653f49ed7"},
+ {file = "multidict-6.9.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:254e53be2ec70518bb82dfa9b0c7166baaf2bd0e918bd17b65caaf489d5a5522"},
+ {file = "multidict-6.9.0-cp313-cp313-win32.whl", hash = "sha256:9869105ab61db13004f9ed610cd29ce4237b2c609f5f7b8bb8f2339fb9dad17d"},
+ {file = "multidict-6.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:85ed0f3c3b01174aea5a8a8fcd456f64c2e9719c0f42c612c2694ecd35974a65"},
+ {file = "multidict-6.9.0-cp313-cp313-win_arm64.whl", hash = "sha256:1126782e3c3b1a7ccd990be3d3221709348e4b07d6ecf8b50965a93ae2624145"},
+ {file = "multidict-6.9.0-cp314-cp314-android_24_x86_64.whl", hash = "sha256:1b34b10b615db5a3ed424b174a362a3cdf06220bd892d03d151a619bb157c4e9"},
+ {file = "multidict-6.9.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:f7f0b996a20776018a253061a781ba983e7b944e17a0748822026048b8b0bb07"},
+ {file = "multidict-6.9.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:b612842f7f286c42abc5dcbda1db50e9dbed39720dd15feb07dbc9974bfeaa7c"},
+ {file = "multidict-6.9.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:71ee2b3198323cbff7a846538f01599f309dddddba79b5bf5a3dca2e49460ef6"},
+ {file = "multidict-6.9.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d0dc1f9c7dc07d86e5a4ed24f3a55b945106f3e7c70a984ff8dd9267270414ed"},
+ {file = "multidict-6.9.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a26c8672d70d2c12c2f1c4df91fe92422e905efaf1d639bd4d7192868a21e711"},
+ {file = "multidict-6.9.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:186cc28558e3d6921ba797e433cd58ce64eb8b2f553e93f75dccbb9a604b7457"},
+ {file = "multidict-6.9.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ebc02af6ac170631774219c26fd63b4404d1e836a1aa92b738a3127eaa2aebad"},
+ {file = "multidict-6.9.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:62c4ffba9f81a2b17cf081bfe4e6b7eaf17193dc17d5870c01b2763e48efed24"},
+ {file = "multidict-6.9.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3a7e2aaa0e9a6413b54cd90fa0fe5944487872a7130a1c07347627974e677a34"},
+ {file = "multidict-6.9.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:26e34dbbd6c3438ee19e0db1f5b846a7ca957085d193ec312b488924c3941a0d"},
+ {file = "multidict-6.9.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5d811799f821c06883404a171faa880660ef04c2687fc32fdaef22fb645fe80"},
+ {file = "multidict-6.9.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:89fde003cec43783193360c27de2fbb0c8ea2db1cfebc193c3fc657c436f9d38"},
+ {file = "multidict-6.9.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9bfa4ba6d97ae6d9c1f5336c2abad5690bce1802a040f9aa5fa39cb0b3099c02"},
+ {file = "multidict-6.9.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a776fbaf700549943b647f21479d69191c238c84fb55d5a48eec1b4cf6cf6e00"},
+ {file = "multidict-6.9.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ed04614c47379bcdfa01d3e165149518017ea034cd5f48e203c287cc3d2ebd4b"},
+ {file = "multidict-6.9.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9c65d9912983991f368bd01f993191b1593c90ecde6be990d73add46084d235f"},
+ {file = "multidict-6.9.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:4b89b102be78ed286123e75a30efda519e1ef6b9d4a4d01a08213f5e01a18e45"},
+ {file = "multidict-6.9.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:e3ed6563ea143214c63bb4452ae5e8787a39226b22101c179fa4d2eda5972267"},
+ {file = "multidict-6.9.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:448c05bd13f8675b3629fbc3fabb9e7bb19a5636a7a3eb677ea25a08d0544a56"},
+ {file = "multidict-6.9.0-cp314-cp314-win32.whl", hash = "sha256:2b5db4f2ca34fce55d34b9c66a0eb5d0d01962e2420a1218ba836d8e46aa6ea3"},
+ {file = "multidict-6.9.0-cp314-cp314-win_amd64.whl", hash = "sha256:ccf9f7f07e9ab6e24f68ccb2b4da8ded65c1fbc5390ebd897a5fe55cdd4c064f"},
+ {file = "multidict-6.9.0-cp314-cp314-win_arm64.whl", hash = "sha256:64ef289ca3c6eaafaa705978686631cb5acc90a92a09bef39c95a810c5f4b804"},
+ {file = "multidict-6.9.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:f17f485e1837a7d31216be8be991a51265bcfc3cfd2457d5c94ade6086793ad7"},
+ {file = "multidict-6.9.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:3fccacf47e756a0f487b2b7e4afc9f167db0770ecc4e887b38ae2aec99dcb510"},
+ {file = "multidict-6.9.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:527655c10fca73fd336cbcd5ccaaba5d8ded1512a3183ed7ebcc1569db5f1de3"},
+ {file = "multidict-6.9.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2d3520f774e78dad488c97398e5c7253333baa4eea09785aca56d477c4dc05c7"},
+ {file = "multidict-6.9.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:518a76bff2567fb0941603b9ccecdd830dd2d717605e7a28c1edc9e64688759e"},
+ {file = "multidict-6.9.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ff308def558cbbff74ea889ec659d117ac550d4d554467ed6cb3bf6adadac7e6"},
+ {file = "multidict-6.9.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:875a77927cd7bc0bc1d0a0520a7ed2267bb169c5db03cc133eaa746526d4182b"},
+ {file = "multidict-6.9.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2182da6ffc9793dd66d7d3632eea2b131f1a1e26eaedd51956845501830d84fe"},
+ {file = "multidict-6.9.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e680a0b07e44b87a975eca63f84860a772667b0037066a6e93d998eb41ad2814"},
+ {file = "multidict-6.9.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5066b7877e1e2ae2c3712c8037eff40a80d4cf35b393b4c42c81f1c4b73b346d"},
+ {file = "multidict-6.9.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fd0ec96e9877cb4dddf7942dffa777837809663f8e55d4f79a2bad06453446b0"},
+ {file = "multidict-6.9.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:98b0738ac1a1593f609a7b67d25e09c7de57c0f91c2879eb01c46b2dae55c0ba"},
+ {file = "multidict-6.9.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0548fdffa634c495b866d89e02ae58a9588cedaeeb972f6ced433e20dee1db5f"},
+ {file = "multidict-6.9.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:7d0649ae61a341b9a47a2afab57424bd2a0ce98d36ec170ce9a51ce92c7284f6"},
+ {file = "multidict-6.9.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c6d470d693ff45678b9ab237113546f6dc18918be55b3c852a69ed05ae7404a8"},
+ {file = "multidict-6.9.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:ac05ce26d2c902d2eb5afe70f2012d19f3b9510ed5ef054bab27a3d43bc7f39c"},
+ {file = "multidict-6.9.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e82ea3ca4409c20172074f27dc1ba5858174f143d0ee637dd058b8061ff024c6"},
+ {file = "multidict-6.9.0-cp314-cp314t-win32.whl", hash = "sha256:d61680c1969b5b1b900fece510077e7732336eae02f68dda02162e04ff6ff321"},
+ {file = "multidict-6.9.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9a9af5d28024c1de9e0efe06a64b5a8561e6517daa66788169e60d2c588e15c5"},
+ {file = "multidict-6.9.0-cp314-cp314t-win_arm64.whl", hash = "sha256:810ae53369d957fcc3e3855612e3a35a39960adaf4b3b1cb4cb4a2e94185bcfe"},
+ {file = "multidict-6.9.0-cp315-cp315-android_24_x86_64.whl", hash = "sha256:b9bcbd708bb5e1ce8cf9c58908ae9777a90f777406315b046bb10cb3e87f8621"},
+ {file = "multidict-6.9.0-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:27ed5aaee62eeff74786a3259de81ada4f2bf84b75122bc06d7d8eadc1be5643"},
+ {file = "multidict-6.9.0-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30ba80aa7ec7340e80140d29f563e33acb21f3756e42df13612f2a26c80c90ba"},
+ {file = "multidict-6.9.0-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:c26e56c68bde47f8028265b3829915450c944febc75a1e4d0365b8a75557861a"},
+ {file = "multidict-6.9.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:f6705ae71e4b14c693877be3cc09fc62af10197ca08ee08bb57ffce6e0f9c5f4"},
+ {file = "multidict-6.9.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:1fc7b1ce735737b7abf38935928729433ef2c81306dcab7f360ef3c3076bc8e9"},
+ {file = "multidict-6.9.0-cp315-cp315-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b7731a591920d77bd9372a9a8ab3f447129dbf17d29b10928c94005e1606641c"},
+ {file = "multidict-6.9.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69a9295177c33756d7a6f8da0f1db345ac951f2436be6ad4b90f53056526e767"},
+ {file = "multidict-6.9.0-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7b4ae468e341cc84c1ae035ee12f032cc0716f618b1eb417fb14e8454a17c620"},
+ {file = "multidict-6.9.0-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:eb9f52b89e339007a06c88cb95068e9d612ce252baaaa5ece85de96e2d51fca9"},
+ {file = "multidict-6.9.0-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:69190050f74fe139a7b3759c730e4e87484db9cf74b1786910a24496ab7a40f9"},
+ {file = "multidict-6.9.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5f04bbfb064b87455a8012f5829b20201d608cf4b3a1a0e50c7a14173a75109"},
+ {file = "multidict-6.9.0-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0d81d0ec43a73056458e844cf90239d2c3a7aeb4ef05fea8c0f64775d5111847"},
+ {file = "multidict-6.9.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:b8aea3d54f3cc20a557fb951c68294d9aa88d614cf7151aa5629b1d5e4033b74"},
+ {file = "multidict-6.9.0-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:31fd2961bd754ac3177aae9438c01becc22eae029911f13c558e5767a10e5dc2"},
+ {file = "multidict-6.9.0-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:04e6f4eddeff93c778a9e7137568284f28856d960275085fcbd87cf77a53a057"},
+ {file = "multidict-6.9.0-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:319160c73795ce31e86494773e0f12c446d32dae7d1a76f4829007ef69eb80bf"},
+ {file = "multidict-6.9.0-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:0d7fbd38d52119423ed8c69672ca47eac121062c30c976e00ba732d114774874"},
+ {file = "multidict-6.9.0-cp315-cp315-musllinux_1_2_s390x.whl", hash = "sha256:981280a946256fc151584fb3b82b99db091fccac81cfecce530585db559ec62c"},
+ {file = "multidict-6.9.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:fb3d1f3c63d49656a83e1604ef3ac573016cf2e62da84d1937f47107d5689c8b"},
+ {file = "multidict-6.9.0-cp315-cp315-win32.whl", hash = "sha256:0c5388c41bc7c551548c4ce840349f0708f7ced6df877d82900bac82268160fc"},
+ {file = "multidict-6.9.0-cp315-cp315-win_amd64.whl", hash = "sha256:49e47de3823bee4896f1eedc17ce4fc4f42c433bab168ece7911f42e69a4f666"},
+ {file = "multidict-6.9.0-cp315-cp315-win_arm64.whl", hash = "sha256:1ac339b944616d4061a9ee9571c89767543db38c19c8c7917a9c08b1462c4800"},
+ {file = "multidict-6.9.0-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:cb6be563dd43b2d4d528afded1878b559ef1c2f45f89e94d273ef515485727f9"},
+ {file = "multidict-6.9.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:76f0df301516563085342d9cdad03fc3c0301b36c3cfa8454e49ca73878aa59c"},
+ {file = "multidict-6.9.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:34c00a534e948eb5f8b3c50cacea9daa4fc4dfd503f6edd114bb532f53742c9e"},
+ {file = "multidict-6.9.0-cp315-cp315t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cce5e33383904e32b58bef7765c38917899a9dc87058f75c421c82e7c11440ee"},
+ {file = "multidict-6.9.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c375408881861294207c1d038a711120776989c5e8c489b251a818cd74d39886"},
+ {file = "multidict-6.9.0-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3f95940278766f273b668bbd9dd412ab5dd170ff40fc836b714c38de7852f1fc"},
+ {file = "multidict-6.9.0-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6009b58d6994881c53f56d2f2010f0b3cd30139c7b14156c2329d00c0d592e8e"},
+ {file = "multidict-6.9.0-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7d5ab831301decfb7c29d1c243823f6ccbb3766117c5957bdc5b9f283355d0f1"},
+ {file = "multidict-6.9.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17b74ffc94e63843cf34b7eb874ab1653afac0eda3edfa3de1207db7fc8c0ed9"},
+ {file = "multidict-6.9.0-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:62dc471198ac2f1085f6c6ba9aa5ad3343c0cbac0756d2fbe551659d55e14212"},
+ {file = "multidict-6.9.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:da97c0a501c5da00d9c3af6d481ed97dace148f9030f4f5578534981d58682bb"},
+ {file = "multidict-6.9.0-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:986f2a23330e8823b389872ae63b83b862a10e63e8cfbd11b42ab8664d1eaa7e"},
+ {file = "multidict-6.9.0-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:ed96992cac94b32a9c3da5870b05967271397a813029d68197939397860b1470"},
+ {file = "multidict-6.9.0-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:94e767d30be457da0ef134e688cd2b6a438d19b85bf000b1c4a2b9b6f55b4211"},
+ {file = "multidict-6.9.0-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:d1f98df09bc22d298d88dee07eb5365dba1fbf3b41e876a6edb2652a8b3a6ca1"},
+ {file = "multidict-6.9.0-cp315-cp315t-musllinux_1_2_s390x.whl", hash = "sha256:c5290038269f7d96037afc47b05b286e4791adfa7046911e2a0483b6220c84fb"},
+ {file = "multidict-6.9.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:8858d2ddd0bc21b4aaf189016c95840b29ddf0236a049af70a9cb4379bef9abc"},
+ {file = "multidict-6.9.0-cp315-cp315t-win32.whl", hash = "sha256:f90724dade5865b1c9429d9b058f11096e44a7f1f0e0a21eff18d98ef32c22aa"},
+ {file = "multidict-6.9.0-cp315-cp315t-win_amd64.whl", hash = "sha256:150f1e5bcc14234e99aacc931deafa52713157df947efeecc1a3b7601f2714ab"},
+ {file = "multidict-6.9.0-cp315-cp315t-win_arm64.whl", hash = "sha256:734c985bbd60e84d0ea523bafe139394e46b8a3f35754a70111dbcbba243f7f4"},
+ {file = "multidict-6.9.0-py3-none-any.whl", hash = "sha256:57c2445049f7d8e66306f712868219da7ff7168ef42263dc032401211bf1205c"},
+ {file = "multidict-6.9.0.tar.gz", hash = "sha256:d7d32c0543494efbc9394e2b571725071d08e295993486bc9a43f6f89375ee01"},
]
[package.dependencies]
@@ -1011,134 +1011,151 @@ testing = ["coverage", "pytest", "pytest-benchmark"]
[[package]]
name = "propcache"
-version = "0.5.2"
+version = "0.5.4"
description = "Accelerated property cache"
optional = true
python-versions = ">=3.10"
groups = ["main"]
markers = "extra == \"aiohttp\""
files = [
- {file = "propcache-0.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a81be28596d6559f6131ef33e10200de6e17643b3c74ce03f9eb103be6ae8b"},
- {file = "propcache-0.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29cbaac5ea0212663e6845e04b5e188d5a6ae6dd919810ac835bf1d3b42c3f4c"},
- {file = "propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6bf3be92233808fcd338eba0fb4d0b59ec5772af4f4ecfcec450d1bfc0f8b5eb"},
- {file = "propcache-0.5.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2f8ea531c794b9d6274acd4e8d2c2ebcac590a4361d27482edd3010b79f1325e"},
- {file = "propcache-0.5.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:decfca4c79dd53ebab484b00cc4b6717d8c369f86e74aa4ca395a64ac651495e"},
- {file = "propcache-0.5.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4621064bbf28fa77ff64dd5d94367c04684c67d3a5bf1dff25f0cd0d98a38f3b"},
- {file = "propcache-0.5.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b96db7141a592cbc968daf1feea83a118e6ab378af4abbc72b248c895414c22d"},
- {file = "propcache-0.5.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1ca071adabaab6e9219924bbe00af821f1ee7de113a9eca1cdc292de3d120f4d"},
- {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e4294d04a94dcab1b3bccd8b66d962dcad411a1d19414b2a41d1445f1de32ad0"},
- {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a0e399a2eccb91ed18721f86aa85757727400b6865c89e88934781deb9c8498b"},
- {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:823581fd5cb08b12a48bfa11fe962a7916766b6170c17b028fbdf762b85eb9bf"},
- {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:949c91d1a990cf3b2e8188dfcfb25005e0b834a06c63fa4ef9f360878ce21ecf"},
- {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:cc1177027eda740fdb152706bd215a3f124e3eea15afc39f2cb9fe351b50619e"},
- {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b05d643f944a8c3c4bd86d65ffd87bf3264b617f87791940302bc474d2ff5274"},
- {file = "propcache-0.5.2-cp310-cp310-win32.whl", hash = "sha256:8114f28879e0904748e831c3a7774261bd9e75f49be089f389a76f959dcd13fe"},
- {file = "propcache-0.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:5fcb98e7598b1ee0addab320d90f65b530297a867dbfe9de52ea838077e16e3d"},
- {file = "propcache-0.5.2-cp310-cp310-win_arm64.whl", hash = "sha256:04dc2390d9edbbaef7461f33322555976ffddf0b650a038649d026358714e6c5"},
- {file = "propcache-0.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74b70780220e2dd89175ca24b81b68b67c83db499ae611e7f2313cb329801c78"},
- {file = "propcache-0.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4840ab0ae0216d952f4b53dc6d0b992bfc2bedbfe360bdd9b548bc184c08959"},
- {file = "propcache-0.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6844ba6364fb12f403928a82cfd295ab103a2b315c77c747b2dbe4a41894ea7"},
- {file = "propcache-0.5.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2293949b855ce597f2826452d17c2d545fb5622379c4ea6fdf525e9b8e8a2511"},
- {file = "propcache-0.5.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0fd59b5af35f74da48d905dcbad55449ba13be91823cb05a9bd590bbf5b61660"},
- {file = "propcache-0.5.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29f9309a2e42b0d273be006fdb4be2d6c39a47f6f57d8fb1cf9f81481df81b66"},
- {file = "propcache-0.5.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5aaa2b923c1944ac8febd6609cb373540a5563e7cbcb0fd770f75dace2eb817b"},
- {file = "propcache-0.5.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66ea454f095ddf5b6b14f56c064c0941c4788be11e18d2464cf643bf7203ff67"},
- {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:95f1e3f4760d404b13c9976c0229b2b49a3c8e2c62a9ce92efdd2b11ada75e3f"},
- {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:85341b12b9d55bad0bded24cac341bb34289469e03a11f3f583ea1cc1db0326c"},
- {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:26a4dca084132874e639895c3135dfad5eb20bae209f62d1aeb31b03e601c3c0"},
- {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3b199b9b2b3d6a7edf3183ba8a9a137a22b97f7df525feb5ae1eccf026d2a9c6"},
- {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e59bc9e66329185b93dab73f210f1a37f81cb40f321501db8017c9aea15dba27"},
- {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:552ffadf6ad409844bc5919c42a0a83d88314cedddaea0e41e80a8b8fffe881f"},
- {file = "propcache-0.5.2-cp311-cp311-win32.whl", hash = "sha256:cd416c1de191973c52ff1a12a57446bfc7642797b282d7caf2162d7d1b8aa9a0"},
- {file = "propcache-0.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:44e488ef40dbb452700b2b1f8188934121f6648f52c295055662d2191959ff82"},
- {file = "propcache-0.5.2-cp311-cp311-win_arm64.whl", hash = "sha256:54adaa85a22078d1e306304a40984dc5be99d599bf3dc0a24dc98f7daeab89ab"},
- {file = "propcache-0.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:806719138ecd720339a12410fb9614ac9b2b2d3a5fdf8235d56981c36f4039ba"},
- {file = "propcache-0.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:db2b80ea58eab4f86b2beec3cc8b39e8ff9276ac20e96b7cce43c8ae84cd6b5a"},
- {file = "propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e5cbfac9f61484f7e9f3597775500cd3ebe8274e9b050c38f9525c77c97520bf"},
- {file = "propcache-0.5.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbc581d2814337da56222fab8dc5f161cd798a434e49bac27930aaef798e144"},
- {file = "propcache-0.5.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:857187f381f88c8e2fa2fe56ab94879d011b883d5a2ee5a1b60a8cd2a06846d9"},
- {file = "propcache-0.5.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:178b4a2cdaac1818e2bf1c5a99b94383fa73ea5382e032a48dec07dc5668dc42"},
- {file = "propcache-0.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f328175a2cde1f0ff2c4ed8ce968b9dcfb55f3a7153f39e2957ed994da13476"},
- {file = "propcache-0.5.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5671d09a36b06d0fd4a3da0fccbcae360e9b1570924171a15e9e0997f0249fba"},
- {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80168e2ebe4d3ec6599d10ad8f520304ae1cad9b6c5a95372aef1b66b7bfb53a"},
- {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:45f11346f884bc47444f6e6647131055844134c3175b629f84952e2b5cd62b64"},
- {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e778ebd44ef4f66ed60a0416b06b489687db264a9c0b3620362f26489492913"},
- {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:c0cb9ed24c8964e172768d455a38254c2dd8a552905729ce006cad3d3dda59b1"},
- {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1d1ad32d9d4355e2be65574fd0bfd3677e7066b009cd5b9b2dee8aa6a6393b33"},
- {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c80f4ba3e8f00189165999a742ee526ebeccedf6c3f7beb0c7df821e9772435a"},
- {file = "propcache-0.5.2-cp312-cp312-win32.whl", hash = "sha256:8c7972d8f193740d9175f0998ab38717e6cd322d5935c5b0fef8c0d323fd9031"},
- {file = "propcache-0.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:d9ee8826a7d47863a08ac44e1a5f611a462eefc3a194b492da242128bec75b42"},
- {file = "propcache-0.5.2-cp312-cp312-win_arm64.whl", hash = "sha256:2800a4a8ead6b28cccd1ec54b59346f0def7922ee1c7598e8499c733cfbb7c84"},
- {file = "propcache-0.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:099aaf4b4d1a02265b92a977edf00b5c4f63b3b17ac6de39b0d637c9cac0188a"},
- {file = "propcache-0.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68ce1c44c7a813a7f71ea04315a8c7b330b63db99d059a797a4651bb6f69f117"},
- {file = "propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fc299c129490f55f254cd90be0deca4764e36e9a7c08b4aa588479a3bbed3098"},
- {file = "propcache-0.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a6ae2198be502c10f09b2516e7b5d019816924bc3183a43ce792a7bd6625e6f4"},
- {file = "propcache-0.5.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6041d31504dc1779d700e1edcfb08eea334b357620b06681a4eabb57a74e574e"},
- {file = "propcache-0.5.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7eabc04151c78a9f4d5bbb5f1faf571e4defeb4b585e0fe95b60ff2dbe4d3d7"},
- {file = "propcache-0.5.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4db0ba63d693afd40d249bd93f842b5f144f8fcbb83de05660373bcf30517b1d"},
- {file = "propcache-0.5.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1dbcf7675229b35d31abb6547d8ebc8c27a830ac3f9a794edff6254873ec7c0a"},
- {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d310c013aad2c72f1c3f2f8dd3279d460a858c551f97aeb8c63e4693cca7b4d2"},
- {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:06187263ddad280d05b4d8a8b3bb7d164cbebd469236544a42e6d9b28ac6a4fa"},
- {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3115559b8effafd63b142ea5ed53d63a16ea6469cbc63dce4ee194b42db5d853"},
- {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c60462af8e6dc30c35407c7237ea908d777b22862bbee27bc4699c0d8bcdc45a"},
- {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40314bca9ac559716fe374094fc81c11dcc34b64fd6c585360f5775690505704"},
- {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cfa21e036ce1e1db2be04ba3b85d2df1bb1702fa01932d984c5464c665228ff4"},
- {file = "propcache-0.5.2-cp313-cp313-win32.whl", hash = "sha256:f156a3529f38063b6dbaf356e15602a7f95f8055b1295a438433a6386f10463d"},
- {file = "propcache-0.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:dfed59d0a5aeb01e242e66ff0300bc4a265a7c05f612d30016f0b60b1017d757"},
- {file = "propcache-0.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:ba338430e87ceb9c8f0cf754de38a9860560261e56c00376debd628698a7364f"},
- {file = "propcache-0.5.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a592f5f3da71c8691c788c13cb6734b6d17663d2e1cb8caddf0673d01ef8847d"},
- {file = "propcache-0.5.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6a997d0489e9668a384fcfd5061b857aa5361de73191cac204d04b889cfbbafa"},
- {file = "propcache-0.5.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:10734b5484ea113152ee25a91dccedf81631791805d2c9ccb054958e51842c94"},
- {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cafca7e56c12bb02ae16d283742bef25a61122e9dab2b5b3f2ccbe589ce32164"},
- {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f064f8d2b59177878b7615df1735cd8fe3462ed6be8c7b217d17a276489c2b7f"},
- {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f78abfa8dfc32376fd1aacf597b2f2fbbe0ea751419aee718af5d4f82537ef8c"},
- {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7467da8a9822bf1a55336f877340c5bcbd3c482afc43a99771169f74a26dedc"},
- {file = "propcache-0.5.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a6ddc6ac9e25de626c1f129c1b467d7ecd33ce2237d3fd0c4e429feef0a7ee1f"},
- {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2f22cbbac9e26a8e864c0985ff1268d5d939d53d9d9411a9824279097e03a2cb"},
- {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:fc76378c62a0f04d0cd82fbb1a2cd2d7e28fcb40d5873f28a6c44e388aaa2751"},
- {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:acd2c8edba48e31e58a363b8cf4e5c7db3b04b3f9e371f601df30d9b0d244836"},
- {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:452b5065457eb9991ec5eb38ff41d6cd4c991c9ac7c531c4d5849ae473a9a13f"},
- {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3430bb2bfe1331885c427745a751e774ee679fd4344f80b97bf879815fe8fa55"},
- {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cef6cea3922890dd6c9654971001fa797b526c16ab5e1e46c05fd6f877be7568"},
- {file = "propcache-0.5.2-cp313-cp313t-win32.whl", hash = "sha256:72d61e16dd78228b58c5d47be830ff3da7e5f139abdf0aef9d86cde1c5cf2191"},
- {file = "propcache-0.5.2-cp313-cp313t-win_amd64.whl", hash = "sha256:0958834041a0166d343b8d2cedcd8bcbaeb4fdbe0cf08320c5379f143c3be6e7"},
- {file = "propcache-0.5.2-cp313-cp313t-win_arm64.whl", hash = "sha256:6de8bd93ddde9b992cf2b2e0d796d501a19026b5b9fd87356d7d0779531a8d96"},
- {file = "propcache-0.5.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:46088abff4cba581dea21ae0467a480526cb25aa5f3c269e909f800328bc3999"},
- {file = "propcache-0.5.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fc88b26f08d634f7bc819a7852e5214f5802641ab8d9fd5326892292eee1993e"},
- {file = "propcache-0.5.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:97797ebb098e670a2f92dd66f32897e30d7615b14e7f59711de23e30a9072539"},
- {file = "propcache-0.5.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba57fffe4ac99c5d30076161b5866336d97600769bad35cc68f7774b15298a4e"},
- {file = "propcache-0.5.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:583c19759d9eec1e5b69e2fbef36a7d9c326041be9746cb822d335c8cedc2979"},
- {file = "propcache-0.5.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d0326e2e5e1f3163fa306c834e48e8d490e5fae607a097a40c0648109b47ba80"},
- {file = "propcache-0.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e00820e192c8dbebcafb383ebbf99030895f09905e7a0eb2e0340a0bcc2bc825"},
- {file = "propcache-0.5.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c66afea89b1e43725731d2004732a046fe6fe955d51f952c3e95a7314a284a39"},
- {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc37dec6c6cdad0b57881a5658fd14fbf53e333b1a86cf86559f190e1d9ec4"},
- {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5570dbcc97571c15f68068e529c92715a12f8d54030e272d264b377e22bd17a5"},
- {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f814362777a9f841adddb200ecdf8f5cb1e5a3c4b7a86378edbd6ccb26edd702"},
- {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:196913dea116aeb5a2ba95af4ddcb7ea85559ae07d8eee8751688310d09168c3"},
- {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:6e7b8719005dd1175be4ab1cd25e9b98659a5e0347331506ec6760d2773a7fb5"},
- {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:51f96d685ab16e88cab128cd37a52c5da540809c8b879fa047731bfcb4ad35a4"},
- {file = "propcache-0.5.2-cp314-cp314-win32.whl", hash = "sha256:cc6fc3cc62e8501d3ed62894425040d2728ecddb1ed072737a5c70bd537aa9f0"},
- {file = "propcache-0.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:81e3a30b0bb60caa22033dd0f8a3618d1d67356212514f62c57db75cb0ef410c"},
- {file = "propcache-0.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:0d2c9bf8528f135dbb805ce027567e09164f7efa51a2be07458a2c0420f292d0"},
- {file = "propcache-0.5.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:4bc8ff1feffc6a61c7002ffe84634c41b822e104990ae009f44a0834430070bb"},
- {file = "propcache-0.5.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:79aa3ff0a9b566633b642fa9caf7e21ed1c13d6feca718187873f199e1514078"},
- {file = "propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1b31822f4474c4036bae62de9402710051d431a606d6a0f907fec79935a071aa"},
- {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13fef48778b5a2a756523fdb781326b028ca75e32858b04f2cdd19f394564917"},
- {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8b73ab70f1a3351fbc71f663b3e645af6dd0329100c353081cf69c37433fc6fe"},
- {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5538d2c13d93e4698af7e092b57bc7298fd35d1d58e656ae18f23ee0d0378e03"},
- {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd645f03898405cabe694fb8bc35241e3a9c332ec85627584fe3de201452b335"},
- {file = "propcache-0.5.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a473b3440261e0c60706e732b2ed2f517857344fc21bf48fdfe211e2d98eb285"},
- {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7afa37062e6650640e932e4cc9297d81f9f42d9944029cc386b8247dea4da837"},
- {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8a90efd5777e996e42d568db9ac740b944d691e565cbfd31b2f7832f9184b2b8"},
- {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:f19bb891234d72535764d703bfed1153cc34f4214d5bd7150aee1eec9e8f4366"},
- {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:32775082acd2d807ee3db715c7770d38767b817870acfa08c29e057f3c4d5b56"},
- {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9282fb1a3bccd038da9f768b927b24a0c753e466c086b7c4f3c6982851eefb2d"},
- {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc49723e2f60d6b32a0f0b08a3fd6d13203c07f1cd9566cfce0f12a917c967a2"},
- {file = "propcache-0.5.2-cp314-cp314t-win32.whl", hash = "sha256:2d7aa89ebca5acc98cba9d1472d976e394782f587bad6661003602a619fd1821"},
- {file = "propcache-0.5.2-cp314-cp314t-win_amd64.whl", hash = "sha256:d447bb0b3054be5818458fbb171208b1d9ff11eba14e18ca18b90cbb45767370"},
- {file = "propcache-0.5.2-cp314-cp314t-win_arm64.whl", hash = "sha256:fe67a3d11cd9b4efabfa45c3d00ffba2b26811442a73a581a94b67c2b5faccf6"},
- {file = "propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe"},
- {file = "propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427"},
+ {file = "propcache-0.5.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b77c313314524ca9c38fbd70f73515d04597ac58c40c939bc0e71eeb4abff680"},
+ {file = "propcache-0.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8f911c395cef73c510bac566da9507bb6a43e7763d0c79138dc60ee53f11207e"},
+ {file = "propcache-0.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d83b12902eb8bce151259c86c03ba746600b2d994543de46e370cecf96c452f2"},
+ {file = "propcache-0.5.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9281e922c072158c91974d4589f1dbe0fee6d467f284c28e463f9f5a4d933f4"},
+ {file = "propcache-0.5.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9f3551b8a35c1df3e7ea4d2d86edee15f0dde1bddd434a71744048683544d0ef"},
+ {file = "propcache-0.5.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ec6a85f424afa8d23e0d9a094e5dbb6eda01da91c92b9183cd433768247ffc97"},
+ {file = "propcache-0.5.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f574e460d1c8a08384a016fdb09ccf3543433263ed6b2f97104f979e64ea57c2"},
+ {file = "propcache-0.5.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d8e017eeb7482bed34cdb0d61cf2bcfc88d104bbab296a17cd16a6af8aabc70e"},
+ {file = "propcache-0.5.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f273dcf7149a50527c4fd1f55cfe9eac0f60753f5af544b4c9352578e20c0874"},
+ {file = "propcache-0.5.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:fc2461ecc45f17893f8207e73b46ea8ba93e33630e51cf4af3fbc21d47462b1a"},
+ {file = "propcache-0.5.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:279655a16973f1ee2bd2fe79973137681642fd9ae0d89215bba263726eb0dc3a"},
+ {file = "propcache-0.5.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:e9f165403b81fea7e89c932d89046a1e3d9a3a60e8d7ef2f249dccdcb0982bf5"},
+ {file = "propcache-0.5.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1783582065a1f07f9d9ee1e992e13f15d7dc8fb1eb3a7476d43eb3f2e69d26bb"},
+ {file = "propcache-0.5.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d605bb239b796e82a81c6709548b2bd460ab73b4590cb0c83de8a2dd9694d0f"},
+ {file = "propcache-0.5.4-cp310-cp310-win32.whl", hash = "sha256:141fdbd73748db0cf7636035030aaac383d2efde8f34e7bc24594cc776d225b8"},
+ {file = "propcache-0.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:146f48a9e4812611a7581003b1a39de56c34967046310c4171a68ef908c9a745"},
+ {file = "propcache-0.5.4-cp310-cp310-win_arm64.whl", hash = "sha256:6c7599df2b57ebeea8de011b5f2f7b85de95e76037d43d34b95e328430275487"},
+ {file = "propcache-0.5.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:897d1ddf6716e8f47200f7aad9a0efa6cc7586df66c6defa572f9eab379c078e"},
+ {file = "propcache-0.5.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9cbfff4423eef4cc6cafc021469641a2b835f610b2647a6c5281903e21b8670d"},
+ {file = "propcache-0.5.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3fc24f209c1b7f7f688b66b98293954f5504279760999b58920ee12dd8471c1d"},
+ {file = "propcache-0.5.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:62530ca89187827e4a4fe733f971abe81a7542eeea48ff61995f19b64d7199c8"},
+ {file = "propcache-0.5.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56fc3f7599528db40b1efa0889a620116e2704144495273d66066e8164e45838"},
+ {file = "propcache-0.5.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4f2d880ff60f45898f4acfa152aac8d04e3ee627d90ff4003491bf92239d5757"},
+ {file = "propcache-0.5.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e9368e87a3efc285e559131092c5db643eb8e56de4ee42064d5baec22ef2bb5"},
+ {file = "propcache-0.5.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:004e685b315646c410771836e72a44f143bbe624f29653a42687815069a303d5"},
+ {file = "propcache-0.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:594eb4c6ec35e7179b058481f4e9f02521b56de16fa577c4b85c76fb1bf8a9f8"},
+ {file = "propcache-0.5.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2dba2f02d2d5c09ef8a0e6c1a42aeaa451f4be9898cb00b04fe98717da2eb23b"},
+ {file = "propcache-0.5.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c3ef2818d63bc86071e9d2989ae75a1bc32b8f7059cfd9f5abbbee70c32e2ed6"},
+ {file = "propcache-0.5.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:dd2ac8f5b643454c2cc6b6118b13da16e88f4a6434fc3ba61aca384029f04f36"},
+ {file = "propcache-0.5.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:4054acf80d40456a0537f2913b349718649d8d6458a14ab7f48d0ce28c30869d"},
+ {file = "propcache-0.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:40e94adb1e7d39ff28a8bd8d8b8fbd1df6b9f40976dbe379134f1ce058e532dd"},
+ {file = "propcache-0.5.4-cp311-cp311-win32.whl", hash = "sha256:9f86f7259efe2c951f43e57d471c9b41daa5bfc7db9f67189059cf1ae6d77fd9"},
+ {file = "propcache-0.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:e904d4d01f36bd6e197590be1533c44e06058771e0746dd073a8ebb3ef880858"},
+ {file = "propcache-0.5.4-cp311-cp311-win_arm64.whl", hash = "sha256:d42a9a856a4a6e2f6c10f1318c07e7daa498d6593abe745c71dae4521a26ca39"},
+ {file = "propcache-0.5.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b28f41fa3b8c6900457f858ec5b03998f3a6d535fbc1bb2edec5961ea05ec429"},
+ {file = "propcache-0.5.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:dcbf346a318a5e30063f547630b02bb787ce2f45b6368d5da143660b6a3835d8"},
+ {file = "propcache-0.5.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:87a3caecf8095e48dc72f84bfa42e23a848cf410cc9cc13031fba4869b706a21"},
+ {file = "propcache-0.5.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60a64cbccaa11b7760ce705a14ada17ba459e7ca9f23ba587eb013821032d7ef"},
+ {file = "propcache-0.5.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a74bfa37147cc08fb29df10bd9c16f40fa7f860cd3a6d2fff853323a94f6e17f"},
+ {file = "propcache-0.5.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a4d7a54719b67338a305dca2ce6aafe366817df94ddfd4b5514374356f5ca546"},
+ {file = "propcache-0.5.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2814ecd8e818f487bee4b0f921bc4d1c176cc5fc71ac0f072d0fa67eda4ac14b"},
+ {file = "propcache-0.5.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6af4693716bfb03f1752ef1b30faa593db2c01d5272e9b8564a1549452a979ab"},
+ {file = "propcache-0.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4fbc1a15dc8cd1689508758d626b372b1f09d28d9577667feaf9e6bfcd8efcbc"},
+ {file = "propcache-0.5.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:cdee8205a44d0be91bbac4c41b95d86641b72dfc7aef1279400e4fda3f26a937"},
+ {file = "propcache-0.5.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9a2a8a50a93dee0268a860a07fa3b4bd968f8ce4dbd794957da772f395368526"},
+ {file = "propcache-0.5.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7ffafcbfc7b549ab940047e505c831eabac5e67de53e1bc174adbc5285c55944"},
+ {file = "propcache-0.5.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d1f5a500bfcbb2c0ab85e98a0dcd70f5899d34efe365a0187700369a79603031"},
+ {file = "propcache-0.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8a235f73d6e020855dc29dff012d920c02ee0feab8d73a24185a7569f4be1161"},
+ {file = "propcache-0.5.4-cp312-cp312-win32.whl", hash = "sha256:b3083bfe87f95c756e610bd8025f26cbd1cd4aaa03a422f2d65efb7a97cd53d8"},
+ {file = "propcache-0.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:98914de2c4d7f0f9f4a8c6ea4bf05841f4175796941e3ef7d47eb718f22311fb"},
+ {file = "propcache-0.5.4-cp312-cp312-win_arm64.whl", hash = "sha256:8876b39961e33d912afe3c1bee18ee564fdad0206f873cc15d522756b7f50737"},
+ {file = "propcache-0.5.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:36c0d9db44b523ef93d03341b1c42d69ff01d673c053d1b1c6c3a363bcaa39ba"},
+ {file = "propcache-0.5.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1d52a05dc417279f7e5c7618c5dfbbc29923aaf9bc0a5c1802ddcebf54c61a0"},
+ {file = "propcache-0.5.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:44149f46500a0a41b95b4d99c2e586a77319539730607b9892974a092788b111"},
+ {file = "propcache-0.5.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dbab5f5ff6897c81f355d079010cdae85b02e5a0b518b5251523b8ad8ae9ac3c"},
+ {file = "propcache-0.5.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c3e98c55bde2bcf7db3c70d1aed7ae9aa8aebbf19a250c66645cde44cdb8b867"},
+ {file = "propcache-0.5.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:db3ae52ccc150dbc84704e9d642743897f3e1c54742ff34cacb661e52e3818a9"},
+ {file = "propcache-0.5.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f85915e00dcb1cd9f2f890ead064ed40a27df06f0db65be427b29482ae357572"},
+ {file = "propcache-0.5.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c2ba30a89035b57b73e00475de948521602f543d79ce01db10b04b36c4c76fc8"},
+ {file = "propcache-0.5.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ae58f361bd5dae942717c65d3413b478c70aea9c462599e7b9adad3731db3894"},
+ {file = "propcache-0.5.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:96f7c5c15656040ddcbc51e56dc59b58aa25999d743c126abd425b9766ab43e9"},
+ {file = "propcache-0.5.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7cc528e760a8af06f2b13e9b9f362cd90c7c718ea61228a96dbd31ba16ed7f47"},
+ {file = "propcache-0.5.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:425f8cc86ab5018b4b8d4a23bc8e74d964bd3d757c3702e301aa79be76c53f6c"},
+ {file = "propcache-0.5.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:a5793c7698a53f56f4a1889a4737c7eeb1b7ad0842fa6b1abca22913ff79c8c1"},
+ {file = "propcache-0.5.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c02c0e570c5c7e077b0181a9f3cdb7d4c3617d1cda6b5c95bd5d34022923d82c"},
+ {file = "propcache-0.5.4-cp313-cp313-win32.whl", hash = "sha256:3e413d7a4a9b4866b7a761d6060d434b64d23cd35122eda3b026a0bbe8196b25"},
+ {file = "propcache-0.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:0c889f6fa84957bc7e8b4eab71fd16a0455068d5045e3aa40c733071d2b2fd77"},
+ {file = "propcache-0.5.4-cp313-cp313-win_arm64.whl", hash = "sha256:69fc35c0779522da366c563e5faf203ffc1f8ff0021d5b1337fa4efa5be73177"},
+ {file = "propcache-0.5.4-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:e6720ba44ad7e72174314d0e1fb0172494cff5c73a3a8a2159c3d2402ff15565"},
+ {file = "propcache-0.5.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:4cfe0a92ae30151869e67a4b5f5e105e4e03ad30b3f38e5211b5bf77d0881993"},
+ {file = "propcache-0.5.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d759d05634f1b038fb625a66662a8c85e5a8fec912da381b5149ddac107482b"},
+ {file = "propcache-0.5.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:251c63dd46a0659bb875cb254dc4c1e79ee91a847c737cd62373295afc2235dc"},
+ {file = "propcache-0.5.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7a8d5ff04eb1f85698a78d20c62a14676e7b960dcafde09a388d60ad377d355d"},
+ {file = "propcache-0.5.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7b9100a93b372418d8688f3f2a3e5b45c64d70ca4d6176e121aca1e3bfc1e32f"},
+ {file = "propcache-0.5.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cc07876cfb079b6f6f36d21ce75784ad6c2c6b563eeac0ed26c2fa2669b85df9"},
+ {file = "propcache-0.5.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0951315a6b3142ee2167404d707743f0157c110091342b1aa0accac5cf0e4acf"},
+ {file = "propcache-0.5.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bee7d3aed13d56f54e681df38c3a23031bc9e3863f687d9d598825c9146acd7d"},
+ {file = "propcache-0.5.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4e985382be6d15da8d0c2710a6fa7b9070fc9ecdeefb7f580e88373984ec8be3"},
+ {file = "propcache-0.5.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9e9ab13760aa8b6d0881ae7cb04fd891d8d490cd2554ea8e79bb278399169bcc"},
+ {file = "propcache-0.5.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:1b2f3bec4261a94019575481c726c29850f72e27907773c75b1de421e20e9f9d"},
+ {file = "propcache-0.5.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:720cf832eb2d0b0dfee129cb3335a26f6ce3cc45ee1187e8f0731758caa16792"},
+ {file = "propcache-0.5.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fb0a5be8d9aa213150e8d8148a42aca4984b285bcad1e69587dc4298edd929b"},
+ {file = "propcache-0.5.4-cp314-cp314-win32.whl", hash = "sha256:30cc1cebaf9aef49db06357a50398323ae04d70460c0491837d026ab7d6452ea"},
+ {file = "propcache-0.5.4-cp314-cp314-win_amd64.whl", hash = "sha256:0a095db8e15a6020db149ecbed6461939fe74f6acaa3ae8b702a1fe8c38cd983"},
+ {file = "propcache-0.5.4-cp314-cp314-win_arm64.whl", hash = "sha256:45488d1a5f9ab5bd90aaa1ca20f50fe1922b8ffad71a2009d2adf41355897aac"},
+ {file = "propcache-0.5.4-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:53eaa697c4d0422ff4cb714d00231b43352064d97b944033b30c1d57cc506ec0"},
+ {file = "propcache-0.5.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:886b59c4d28ca97dd23b025fdfc50a0356be934efbbbca89ad26230067f86fe5"},
+ {file = "propcache-0.5.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3fa15757fea1dfcd5b7745cad9f4638929605531bd4018ab2adff7955f1a403d"},
+ {file = "propcache-0.5.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f0093ac3e9daada202c2082439d414a625c57184727a46e112a3fb2a81cb788"},
+ {file = "propcache-0.5.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3cd3a7edb6b95b9b33998135ebfa18d709da82290fb8f27c858970b5a12c8b56"},
+ {file = "propcache-0.5.4-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c174bfd1c48a1b51a3078e95586dde718374bac79719ab3541ec9e74aec40574"},
+ {file = "propcache-0.5.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a219f0ac59817a9114dd2aa57c13180f993e819ba658c7ddab4b66ed1ee0d370"},
+ {file = "propcache-0.5.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:17a7400cec0256f0a71ae71f9da398f9894c956ff6668a1c9d317b3367316320"},
+ {file = "propcache-0.5.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:978f28401afbc76cdc3df9e1717b4229a06b626a1dcc75db4e1f2beb3884c3e9"},
+ {file = "propcache-0.5.4-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4a1f4f5ffa55dce6307631f3cb2948e117e665966ea512e0d502b16c24f567e7"},
+ {file = "propcache-0.5.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:213bb68d9ced5cf2bf717b1071bf2b09b4b04c426256f9fe6d054c60318424c4"},
+ {file = "propcache-0.5.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:286867fb156488c251a3721766e380ac4495e4fd6b51aaa1403d89ce7f4359d9"},
+ {file = "propcache-0.5.4-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:445ee3bfb46e85838387fb3c536a73cc0b994dc192b004e40e170adc54aa2a7e"},
+ {file = "propcache-0.5.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:48cb48c5346a97de792254af77715aa2529c2a1ebc5f586aa0aae44a02f1fe57"},
+ {file = "propcache-0.5.4-cp314-cp314t-win32.whl", hash = "sha256:03b229037d25b801e7af53fd52b9fc49d9439b036fca1e087e02780631adfa97"},
+ {file = "propcache-0.5.4-cp314-cp314t-win_amd64.whl", hash = "sha256:8a1fc236528c457cd739c88abe823da851b7ab645d72792f88658114cc340c12"},
+ {file = "propcache-0.5.4-cp314-cp314t-win_arm64.whl", hash = "sha256:135036c5cfc93864affb0f9af9a27e5d7a71cb7bd745e7b6dbfc2d56cc30e827"},
+ {file = "propcache-0.5.4-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:45bf2e730ab8905d0527fe05a86500f406e64305c34cc81ebe64b4617cab9760"},
+ {file = "propcache-0.5.4-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:31eb43ba2edc704ab2ec27815315dd8a19def0fb16215be4cfe8d32fe78ffd51"},
+ {file = "propcache-0.5.4-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:174507f82d3594622acb1dd2dafecf2d899d6d506335494e7107767bf05f3aae"},
+ {file = "propcache-0.5.4-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:50e337653721d20ead710da33bf44487fbe8a0db8782714b60306481e9f95b51"},
+ {file = "propcache-0.5.4-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0d21d0d2c82bbfeb1677a9711f38df968f9837576102bb4add1bd449d28d88f1"},
+ {file = "propcache-0.5.4-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ccf4f7a79e26bb7efb06ecd50c177833b71df05cbc748701372325e6bcc17f6f"},
+ {file = "propcache-0.5.4-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23278f808cd81d5ada7184a76606b925fb3389c60e1077b2cd7da7b1fcf0553c"},
+ {file = "propcache-0.5.4-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e738ab81179510ce79b2eac9a6ecf47feffd9e76d1c72e403005dddb6e36c06c"},
+ {file = "propcache-0.5.4-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:a419ee85e654927baabda3929c03c0cc1112bf472ff0dfd6142f4e3a81ca4162"},
+ {file = "propcache-0.5.4-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:b61805357d966680acf68b3b6d49772631ed9df44ebece10ff1460e117a7da8a"},
+ {file = "propcache-0.5.4-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:58134228927cee6c047d626c08e60a81be604a20578a12ce752cc5c9a84d4826"},
+ {file = "propcache-0.5.4-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:350b272b2279f4135a64fc0c304a5d08e28a137c9573442c606152446638a831"},
+ {file = "propcache-0.5.4-cp315-cp315-musllinux_1_2_s390x.whl", hash = "sha256:45bebbe252550fec975ba3b62bc6f931643cfd3b5464ef47619cf3fef154e01c"},
+ {file = "propcache-0.5.4-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:ada748108a43d29b7c328ba7db3755327cd94f028bcc1a7ee3f0addcfacd9c38"},
+ {file = "propcache-0.5.4-cp315-cp315-win32.whl", hash = "sha256:ee19113bce2f3acd46432050688b70f61acd6857d75abb9ec96341b7e9ced123"},
+ {file = "propcache-0.5.4-cp315-cp315-win_amd64.whl", hash = "sha256:ceb3e879afac028f93d272c957814695dc5569e4904262dbee92f6c41bd5e4a3"},
+ {file = "propcache-0.5.4-cp315-cp315-win_arm64.whl", hash = "sha256:c83acbce9f2b5e3f5f5eda9e53d2001fed22fcdfef81274a9e02d8fd53b70a30"},
+ {file = "propcache-0.5.4-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:a5e8ef588c109725dc713ba69aadcac00a1ef90c2ce9c0a8c7075128f569f47f"},
+ {file = "propcache-0.5.4-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:4d86476a935c88963d9b8e1a9a0d38188790e9622169bfbafa173046846709d3"},
+ {file = "propcache-0.5.4-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:f5470694918830da62fac9e69133b53d23b736d7070e587b27a4a2be37e08e68"},
+ {file = "propcache-0.5.4-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10ef33a68a61ce317e095fd2e202a592ea92392b90944a78c993f0d9a73ab06c"},
+ {file = "propcache-0.5.4-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5cacf3c9efd09df409dc33654dd077e1c245ba8fb747b0f0236ef41b7c49b589"},
+ {file = "propcache-0.5.4-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:770e8209d018175fc0063936fa9583b6d27e88c5ad31543f3383d66080efdd62"},
+ {file = "propcache-0.5.4-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03969626faf0783a592dfa17e28eac06018bd0b44dafae6943d53b92421a7f72"},
+ {file = "propcache-0.5.4-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ef3b928d9c984322b5c44e6964d8dbc653da87d2d8ee1647fa6da43072e650a9"},
+ {file = "propcache-0.5.4-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:7177c43eddf10a0893c4fec52ebb408fdcd7f7d63962caace9180d8f81b14ece"},
+ {file = "propcache-0.5.4-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:420162a77f94eb1cf5ef7893f500016dabd548e73de956785a1dd899cc73006a"},
+ {file = "propcache-0.5.4-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:3eb2e820e8e2101407da93f17c57cbb7d225461955fc60105daaba14cd421ee2"},
+ {file = "propcache-0.5.4-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:13e52b6e0bde97dee98ab66552dbff2931649c96f1ac432eac299fe689ec373b"},
+ {file = "propcache-0.5.4-cp315-cp315t-musllinux_1_2_s390x.whl", hash = "sha256:12682126712ddc19b70ff819debbd279e58adf1f0c8f8f8138c18ade2044b284"},
+ {file = "propcache-0.5.4-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:3af0c8642b2da4815d86e631232ac8286e17644fad907c19508aa8e7cb4ba8ad"},
+ {file = "propcache-0.5.4-cp315-cp315t-win32.whl", hash = "sha256:1df8d8561b21465c5dd56110a01caf897e026d065b4b84e98a488209094272ec"},
+ {file = "propcache-0.5.4-cp315-cp315t-win_amd64.whl", hash = "sha256:02c0a34f16889cf800f10f0247a564d8ce6eeab6ffcd7c87198f769067eb8432"},
+ {file = "propcache-0.5.4-cp315-cp315t-win_arm64.whl", hash = "sha256:dc4242ca653c9b30ab51c5f8193323e7bc0928f897ee9103201e59a43abcb72e"},
+ {file = "propcache-0.5.4-py3-none-any.whl", hash = "sha256:62c60aec739ed00124573cce1178138fd690c7676352d67a37328c1cf51d7468"},
+ {file = "propcache-0.5.4.tar.gz", hash = "sha256:ff6b113f50bc066a698db5d944d2c6dc7507168dd3341e255a8892fd0715a558"},
]
[[package]]
@@ -1568,14 +1585,14 @@ typing-extensions = ">=4.15.0"
[[package]]
name = "urllib3"
-version = "2.7.0"
+version = "2.8.0"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.10"
groups = ["dev"]
files = [
- {file = "urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897"},
- {file = "urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c"},
+ {file = "urllib3-2.8.0-py3-none-any.whl", hash = "sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3"},
+ {file = "urllib3-2.8.0.tar.gz", hash = "sha256:63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63"},
]
[package.extras]
@@ -1586,117 +1603,151 @@ zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""]
[[package]]
name = "yarl"
-version = "1.24.5"
+version = "1.25.1"
description = "Yet another URL library"
optional = true
python-versions = ">=3.10"
groups = ["main"]
markers = "extra == \"aiohttp\""
files = [
- {file = "yarl-1.24.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88f50c94e21a0a7f14042c015b0eba1881af78562e7bf007e0033e624da59750"},
- {file = "yarl-1.24.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6efbccc3d7f75d5b03105172a8dc86d82ba4da86817952529dd93185f4a88be2"},
- {file = "yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0ebfaffe1a16cb72141c8e09f18cc76856dbe58639f393a4f2b26e474b96b871"},
- {file = "yarl-1.24.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8ac73abdc7ab75610f95a8fd994c6457e87752b02a63987e188f937a1fc180f0"},
- {file = "yarl-1.24.5-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4d97a951a81039050e45f04e96689b58b8243fa5e62aa14fe67cb6075300885e"},
- {file = "yarl-1.24.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fe7b7bb170daccbba19ad33012d2b15f1e7942296fd4d45fc1b79013da8cc0f2"},
- {file = "yarl-1.24.5-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:89a1bbb58e0e3f7a283653d854b1e95d65e5cfd4af224dac5f02629ec1a3e621"},
- {file = "yarl-1.24.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7fa5e51397466ea7e98de493fa2ff1b8193cfef8a7b0f9b4842f92d342df0dba"},
- {file = "yarl-1.24.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4103b77b8a8225e413107d2349b65eb3c1c52627b5cc5c3c4c1c6a798b218950"},
- {file = "yarl-1.24.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f9f3e9c8a9ecffa57bef8fb4fa19e5fa4d2d8307cf6bac5b1fca5e5860f4ba00"},
- {file = "yarl-1.24.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0ebc836c47a6477e182169c6a476fc691d12b518894bf7dd2572f0d59f1c7ed"},
- {file = "yarl-1.24.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:96d30286dd02679e32a39aa8f0b7498fc847fcda46cfc09df5513e82ce252440"},
- {file = "yarl-1.24.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:fd8c81f346b58f45818d09ea11db69a8d5fd34a224b79871f6d44f12cd7977b1"},
- {file = "yarl-1.24.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5c55256dee8f4b27bfbf636c8363383c7c8db7890c7cba5217d7bd5f5f21dab6"},
- {file = "yarl-1.24.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9f4d8cf085a4c6a40fb97ea0f46938a8df43c85d31f9d45e2a8867ea9293790d"},
- {file = "yarl-1.24.5-cp310-cp310-win_amd64.whl", hash = "sha256:240cbec09667c1fed4c6cd0060b9ec57332427d7441289a2ed8875dc9fb2b224"},
- {file = "yarl-1.24.5-cp310-cp310-win_arm64.whl", hash = "sha256:8a6987eaad834cb32dd57d9d582225f0054a5d1af706ccfbbdba735af4927e13"},
- {file = "yarl-1.24.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2c1fe720934a16ea8e7146175cba2126f87f54912c8c5435e7f7c7a51ef808d3"},
- {file = "yarl-1.24.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c687ed078e145f5fd53a14854beff320e1d2ab76df03e2009c98f39a0f68f39a"},
- {file = "yarl-1.24.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:709f1efed56c4a145793c046cd4939f9959bcd818979a787b77d8e09c57a0840"},
- {file = "yarl-1.24.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:874019bd513008b009f58657134e5d0c5e030b3559bd0553976837adf52fe966"},
- {file = "yarl-1.24.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a4582acf7ef76482f6f511ebaf1946dae7f2e85ec4728b81a678c01df63bd723"},
- {file = "yarl-1.24.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2cabe6546e41dabe439999a23fcb5246e0c3b595b4315b96ef755252be90caeb"},
- {file = "yarl-1.24.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:17f57620f5475b3c69109376cc87e42a7af5db13c9398e4292772a706ff10780"},
- {file = "yarl-1.24.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:570fec8fbd22b032733625f03f10b7ff023bc399213db15e72a7acaef28c2f4e"},
- {file = "yarl-1.24.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5fede79c6f73ff2c3ef822864cb1ada23196e62756df53bc6231d351a49516a2"},
- {file = "yarl-1.24.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8ccf9aca873b767977c73df497a85dbedee4ee086ae9ae49dc461333b9b79f58"},
- {file = "yarl-1.24.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ad5d8201d310b031e6cd839d9bac2d4e5a01533ce5d3d5b50b7de1ef3af1de61"},
- {file = "yarl-1.24.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:841f0852f48fefea3b12c9dfec00704dfa3aef5215d0e3ce564bb3d7cd8d57c6"},
- {file = "yarl-1.24.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:9baafc71b04f8f4bb0703b21d6fc9f0c30b346c636a532ff16ec8491a5ea4b1f"},
- {file = "yarl-1.24.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d897129df1a22b12aeed2c2c98df0785a2e8e6e0bde87b389491d0025c187077"},
- {file = "yarl-1.24.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dd625535328fd9882374356269227670189adfcc6a2d90284f323c05862eecbd"},
- {file = "yarl-1.24.5-cp311-cp311-win_amd64.whl", hash = "sha256:f4239bbec5a3577ddb49e4b50aeb32d8e5792098262ae2f63723f916a29b1a25"},
- {file = "yarl-1.24.5-cp311-cp311-win_arm64.whl", hash = "sha256:3ac6aff147deb9c09461b2d4bbdf6256831198f5d8a23f5d37138213090b6d8a"},
- {file = "yarl-1.24.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d693396e5aea78db03decd60aec9ece16c9b40ba00a587f089615ff4e718a81d"},
- {file = "yarl-1.24.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3363fcc96e665878946ad7a106b9a13eac0541766a690ef287c0232ac768b6ec"},
- {file = "yarl-1.24.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9d399bdcfb4a0f659b9b3788bbc89babe63d9a6a65aacdf4d4e7065ff2e6316c"},
- {file = "yarl-1.24.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90333fd89b43c0d08ac85f3f1447593fc2c66de18c3d6378d7125ea118dc7a54"},
- {file = "yarl-1.24.5-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:665b0a2c463cc9423dd647e0bfd9f4ccc9b50f768c55304d5e9f80b177c1de12"},
- {file = "yarl-1.24.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e006d3a974c4ee19512e5f058abedb6eef36a5e553c14812bdeba1758d812e6d"},
- {file = "yarl-1.24.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e7d42c531243450ef0d4d9c172e7ed6ef052640f195629065041b5add4e058d1"},
- {file = "yarl-1.24.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f08c7513ecef5aad65687bfdf6bc601ae9fccd04a42904501f8f7141abad9eb9"},
- {file = "yarl-1.24.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6c95b17fe34ed802f17e205112e6e10db92275c34fee290aa9bdc55a9c724027"},
- {file = "yarl-1.24.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:56b149b22de33b23b0c6077ab9518c6dcb538ad462e1830e68d06591ccf6e38b"},
- {file = "yarl-1.24.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a8fe66b8f300da93798025a785a5b90b42f3810dc2b72283ff84a41aaaebc293"},
- {file = "yarl-1.24.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:377fe3732edbaf78ee74efdf2c9f49f6e99f20e7f9d2649fda3eb4badd77d76e"},
- {file = "yarl-1.24.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e8ffa78582120024f476a611d7befc123cee59e47e8309d470cf667d806e613b"},
- {file = "yarl-1.24.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:daba5e594f06114e37db186efd2dd916609071e59daca901a0a2e71f02b142ce"},
- {file = "yarl-1.24.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:65be18ec59496c13908f02a2472751d9ef840b4f3fb5726f129306bf6a2a7bba"},
- {file = "yarl-1.24.5-cp312-cp312-win_amd64.whl", hash = "sha256:a929d878fec099030c292803b31e5d5540a7b6a31e6a3cc76cb4685fc2a2f51b"},
- {file = "yarl-1.24.5-cp312-cp312-win_arm64.whl", hash = "sha256:7ce27823052e2013b597e0c738b13e7e36b8ccb9400df8959417b052ab0fd92c"},
- {file = "yarl-1.24.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:79af890482fc94648e8cde4c68620378f7fef60932710fa17a66abc039244da2"},
- {file = "yarl-1.24.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:46c2f213e23a04b93a392942d782eb9e413e6ef6bf7c8c53884e599a5c174dcb"},
- {file = "yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92ab3e11448f2ff7bf53c5a26eff0edc086898ec8b21fb154b85839ce1d88075"},
- {file = "yarl-1.24.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ebb0ec7f17803063d5aeb982f3b1bd2b2f4e4fae6751226cbd6ba1fcfe9e63ff"},
- {file = "yarl-1.24.5-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:82632daed195dcc8ea664e8556dc9bdbd671960fb3776bd92806ce05792c2448"},
- {file = "yarl-1.24.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:53e549287ef628fecba270045c9701b0c564563a9b0577d24a4ec75b8ab8040f"},
- {file = "yarl-1.24.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fcd3b77e2f17bbe4ca56ec7bcb07992647d19d0b9c05d84886dcd6f9eb810afd"},
- {file = "yarl-1.24.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d46b86567dd4e248c6c159fcbcdcce01e0a5c8a7cd2334a0fff759d0fa075b16"},
- {file = "yarl-1.24.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7f72c74aa99359e27a2ee8d6613fefa28b5f76a983c083074dfc2aaa4ab46213"},
- {file = "yarl-1.24.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3f45789ce415a7ec0820dc4f82925f9b5f7732070be1dec1f5f23ec381435a24"},
- {file = "yarl-1.24.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6e73e7fe93f17a7b191f52ec9da9dd8c06a8fe735a1ecbd13b97d1c723bff385"},
- {file = "yarl-1.24.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4a36f9becdd4c5c52a20c3e9484128b070b1dcfc8944c006f3a528295a359a9c"},
- {file = "yarl-1.24.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:7bcbe0fcf850eae67b6b01749815a4f7161c560a844c769ad7b48fcd99f791c4"},
- {file = "yarl-1.24.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:24e861e9630e0daddcb9191fb187f60f034e17a4426f8101279f0c475cd74144"},
- {file = "yarl-1.24.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9335a099ad87287c37fe5d1a982ff392fa5efe5d14b40a730b1ec1d6a41382b4"},
- {file = "yarl-1.24.5-cp313-cp313-win_amd64.whl", hash = "sha256:2dbe06fc16bc91502bca713704022182e5729861ae00277c3a23354b40929740"},
- {file = "yarl-1.24.5-cp313-cp313-win_arm64.whl", hash = "sha256:6b8536851f9f65e7f00c7a1d49ba7f2be0ffe2c11555367fc9f50d9f842410a1"},
- {file = "yarl-1.24.5-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:2729fcfc4f6a596fb0c50f32090400aa9367774ac296a00387e65098c0befa76"},
- {file = "yarl-1.24.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ff330d3c30db4eb6b01d79e29d2d0b407a7ecad39cfd9ec993ece57396a2ec0d"},
- {file = "yarl-1.24.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e42d75862735da90e7fc5a7b23db0c976f737113a54b3c9777a9b665e9cbff75"},
- {file = "yarl-1.24.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3732e66413163e72508da9eff9ce9d2846fde51fae45d3605393d3e6cd303e9"},
- {file = "yarl-1.24.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5b8ee53be440a0cffc991a27be3057e0530122548dbe7c0892df08822fce5ede"},
- {file = "yarl-1.24.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:af3aefa655adb5869491fa907e652290386800ae99cc50095cba71e2c6aefdca"},
- {file = "yarl-1.24.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2120b96872df4a117cde97d270bac96aea7cc52205d305cf4611df694a487027"},
- {file = "yarl-1.24.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:66410eb6345d467151934b49bfa70fb32f5b35a6140baa40ad97d6436abea2e9"},
- {file = "yarl-1.24.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4af7b7e1be0a69bee8210735fe6dcfc38879adfac6d62e789d53ba432d1ffa41"},
- {file = "yarl-1.24.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa139875ff98ab97da323cfadfaff08900d1ad42f1b5087b0b812a55c5a06373"},
- {file = "yarl-1.24.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:0055afc45e864b92729ac7600e2d102c17bef060647e74bca75fa84d66b9ff36"},
- {file = "yarl-1.24.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f0e466ed7511fe9d459a819edbc6c2585c0b6eabde9fa8a8947552468a7a6ef0"},
- {file = "yarl-1.24.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f141474e85b7e54998ec5180530a7cda99ab29e282fa50e0756d89981a9b43c5"},
- {file = "yarl-1.24.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:e2935f8c39e3b03e83519292d78f075189978f3f4adc15a78144c7c8e2a1cba5"},
- {file = "yarl-1.24.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9d1216a7f6f77836617dba35687c5b78a4170afc3c3f18fc788f785ba26565c4"},
- {file = "yarl-1.24.5-cp314-cp314-win_amd64.whl", hash = "sha256:5ba4f78df2bcc19f764a4b26a8a4f5049c110090ad5825993aacb052bf8003ad"},
- {file = "yarl-1.24.5-cp314-cp314-win_arm64.whl", hash = "sha256:9e4e16c73d717c5cf27626c524d0a2e261ad20e46932b2670f64ad5dde23e26f"},
- {file = "yarl-1.24.5-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:e1ae548a9d901adca07899a4147a7c826bbcc06239d3ce9a59f57886a28a4c88"},
- {file = "yarl-1.24.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:ff405d91509d88e8d44129cd87b18d70acd1f0c1aeabd7bc3c46792b1fe2acba"},
- {file = "yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:47e98aab9d8d82ff682e7b0b5dded33bf138a32b817fcf7fa3b27b2d7c412928"},
- {file = "yarl-1.24.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f0a658a6d3fafee5c6f63c58f3e785c8c43c93fbc02bf9f2b6663f8185e0971f"},
- {file = "yarl-1.24.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4377407001ca3c057773f44d8ddd6358fa5f691407c1ba92210bd3cf8d9e4c95"},
- {file = "yarl-1.24.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7c0494a31a1ac5461a226e7947a9c9b78c44e1dc7185164fa7e9651557a5d9bc"},
- {file = "yarl-1.24.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a7cff474ab7cd149765bb784cf6d78b32e18e20473fb7bda860bce98ab58e9da"},
- {file = "yarl-1.24.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cbb833ccacdb5519eff9b8b71ee618cc2801c878e77e288775d77c3a2ced858a"},
- {file = "yarl-1.24.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:82f75e05912e84b7a0fe57075d9c59de3cb352b928330f2eb69b2e1f54c3e1f0"},
- {file = "yarl-1.24.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:16a2f5010280020e90f5330257e6944bc33e73593b136cc5a241e6c1dc292498"},
- {file = "yarl-1.24.5-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:ffcd54362564dc1a30fb74d8b8a6e5a6b11ebd5e27266adc3b7427a21a6c9104"},
- {file = "yarl-1.24.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0465ec8cedc2349b97a6b595ace64084a50c6e839eca40aa0626f38b8350e331"},
- {file = "yarl-1.24.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:4db9aecb141cb7a5447171b57aa1ed3a8fee06af40b992ffc31206c0b0121550"},
- {file = "yarl-1.24.5-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:f540c013589084679a6c7fac07096b10159737918174f5dfc5e11bf5bca4dfe6"},
- {file = "yarl-1.24.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a61834fb15d81322d872eaafd333838ae7c9cea84067f232656f75965933d047"},
- {file = "yarl-1.24.5-cp314-cp314t-win_amd64.whl", hash = "sha256:5c88e5815a49d289e599f3513aa7fde0bc2092ff188f99c940f007f90f53d104"},
- {file = "yarl-1.24.5-cp314-cp314t-win_arm64.whl", hash = "sha256:cf139c02f5f23ef6532040a30ff662c00a318c952334f211046b8e60b7f17688"},
- {file = "yarl-1.24.5-py3-none-any.whl", hash = "sha256:a33700d13d9b7d84fd10947b09ff69fb9a792e519c8cb9764a3ca70baa6c23a7"},
- {file = "yarl-1.24.5.tar.gz", hash = "sha256:e81b83143bee16329c23db3c1b2d82b29892fcbcb849186d2f6e98a5abe9a57f"},
+ {file = "yarl-1.25.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:142c06c4d6a35ee3ec5da08499805e879cb3ca7c1fbfbecb0140fe72403818d6"},
+ {file = "yarl-1.25.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:24ce942011a61953e7d313438038f4d32ff21387b775f58a957f7a07dd55ef95"},
+ {file = "yarl-1.25.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e23c82b63cd7652fc24d33ed6cc17099d607aa3b4fc4ddc75e95062f3d82df4"},
+ {file = "yarl-1.25.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8ee202350cf57abf0e9502a41601841019c25d3db7ff52d980aaf31446254059"},
+ {file = "yarl-1.25.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5df89f769cc8ff94c3d7e7603386fba309d25ce5240132d26c15baa8d0e96c4c"},
+ {file = "yarl-1.25.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:83e9f4a25085bd4b7214701a0794ff1f50fc633ffb8bdfebf07abdd81c2db126"},
+ {file = "yarl-1.25.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e636b64d24fd9c38053c5e389a1174c66361fa49dcfd220f4dd35b4abde7cb89"},
+ {file = "yarl-1.25.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e5637ca8d0bd7fb72648a6c7934af4baaccb697657f7438c9d264fc2abb8b0b1"},
+ {file = "yarl-1.25.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:683e362b8ba453080f7489c66f4ea794e751c35b72e7eab3575ef784c2fbc7fb"},
+ {file = "yarl-1.25.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:df23df54b5114a17c2d0ef192433e2e5a9f0c5178c32375e90b7cfc965f349d0"},
+ {file = "yarl-1.25.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f53dcd26694f148f738edc052b5a69234833e739f10f4c3287bdfd8ec0f7b326"},
+ {file = "yarl-1.25.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:b8075fe90bc08e40b8b8a1874fab42ee4c7b56af05c5886e9cc841397f916908"},
+ {file = "yarl-1.25.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:a8c2b841478068440d8b733005d13a5ef535b9928cbc05f17182d410f32ba449"},
+ {file = "yarl-1.25.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ca32926d7d77bcc8838425c4c95e040a3ace1cb7dfdae599013458dcda2607ca"},
+ {file = "yarl-1.25.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:192a866877a49993949ef1975864ad8728bea28ee810f6abe1a0729c2b500426"},
+ {file = "yarl-1.25.1-cp310-cp310-win_amd64.whl", hash = "sha256:3f4d48a6112712973e676bd792121fee470e432d749177162d9949d5c9460a1b"},
+ {file = "yarl-1.25.1-cp310-cp310-win_arm64.whl", hash = "sha256:48796ea00a303961507dc6c8437c4b325a6fc3f95f7c36c71b91ea9a8150963c"},
+ {file = "yarl-1.25.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9d693bf4bf534e9ba3ae2780cfd577f5135629f7b5ac653490859d0b77864865"},
+ {file = "yarl-1.25.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ab2054c5531af2a9ba7b69b8ec91e4f884420e83a8c5e579b013084cb57e5e5d"},
+ {file = "yarl-1.25.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:564fdc7085d2245ab84f88882fdb1d6ac0723124bff6ded35bfb1c00f812630d"},
+ {file = "yarl-1.25.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:acae6b45d1ace09b6ba3876da43b88366ef368f73b988c7f57e14231753d4420"},
+ {file = "yarl-1.25.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1fb2a01ba8cd9c5d2c5dc1ec35e0fc951d04b4f037541d4ac090c993ce58b3d7"},
+ {file = "yarl-1.25.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e92b6bcc741b86d67606c40d3cb9c7cc8e6c737f81e31f4a94efc204456c92e3"},
+ {file = "yarl-1.25.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:72c34ac7ad4314c19362d5ce27626dcc8429bd30bbf8c179f4234078851f9492"},
+ {file = "yarl-1.25.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5add7b4ca7afeea91d52e4d4e4db3b1fe9885b71f07054560d8c4296b7441a2"},
+ {file = "yarl-1.25.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:def538065f9e4d4cf1ae164bd59aba00dfa84f03923e0de4c3788f252d6bcd17"},
+ {file = "yarl-1.25.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a191bfdb30a79b98e5d175d75285f9fcb78bf0e46ba5efda042e1c72071a0de"},
+ {file = "yarl-1.25.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:71f42c5b9a948c113bbdebfa544598321431d064ff959d32e99b1feb61d68345"},
+ {file = "yarl-1.25.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:72849d892954be4d09e569b8b831ac39ce58417fedc767d4308a0fe542018a40"},
+ {file = "yarl-1.25.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:efb01a106f971cb3752856bca2318bbdf7f01bd8823779c461586cbe5ffd5258"},
+ {file = "yarl-1.25.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a1daf47cd95a7c3a63456336bc5aaa8c86dd3a47d07ed3d0e76132ae4666a5a1"},
+ {file = "yarl-1.25.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9489e6abf47ba37f332075a91444c7cfedb03e6ce99fbb2f116bfe1ce810da3b"},
+ {file = "yarl-1.25.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7306dee25b8a0e737363f347362b875094b4dc4e367311470656ae420fdbf8e"},
+ {file = "yarl-1.25.1-cp311-cp311-win_arm64.whl", hash = "sha256:abb1384477f5901d436b5d2e5465954de46ea6098f59163d243660b5c4461d35"},
+ {file = "yarl-1.25.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:94d7aa6debf92a1dd14cb5280b083a764169a13cfb23a452111160274ed989f4"},
+ {file = "yarl-1.25.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:83d4a37e4b95da4d8bda930d6d35b75b4cdadbacbb4980cae290ea3100b5d51d"},
+ {file = "yarl-1.25.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e029648f9c951db30e98a7d7ec90835db88ec4b32820efe2a9bdc2287e032eb6"},
+ {file = "yarl-1.25.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d781294bb815ecb5ea57ff6bbf8038e0a31a95fdf3e1788f66e0dc100d64b58"},
+ {file = "yarl-1.25.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e12c538e00e7c1b286a07061046b90e8124e6a9793efae2c70db6a4aad07faad"},
+ {file = "yarl-1.25.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7e4de3ac4adbad3d0bc7c6f4360a7dbff5de2f15e3b723be3198074e17fd9c40"},
+ {file = "yarl-1.25.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:419f392a1da624877975709e3864dfe833af6cc7671b39318086d456e288380c"},
+ {file = "yarl-1.25.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6f117789d22dce188e5754e8bc65b7e6ebf8cb73963b9fa761f672a5883769d"},
+ {file = "yarl-1.25.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:80e47012e730da131c9f059c80936783f9659aae22dc31c03c0595590d11ed54"},
+ {file = "yarl-1.25.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e80f557716fd765439577131e526b8942ffc2c07bdbc5e39fa62f660ba1e963f"},
+ {file = "yarl-1.25.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f61964f235a43738bfac50da46fc4254943a7eea3051aeb0b6fc7c992c29fadc"},
+ {file = "yarl-1.25.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e546fe1d4a93ebc2910f0d768baff19faa09843ab3f2036a67ed6e69fae4419d"},
+ {file = "yarl-1.25.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:cce0727fd5ac04d372fa9bbfde9febc2bcf209aadfcf0468e45dec72719895d1"},
+ {file = "yarl-1.25.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af4ea5b37403ef4e30f3927eaed540db942bde01d8d3ff083527c0704d1c9c68"},
+ {file = "yarl-1.25.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:68782fdb4027b8d1eee25ec35e9a6db05e863b899eb0310b3a33b6c3fef55707"},
+ {file = "yarl-1.25.1-cp312-cp312-win_amd64.whl", hash = "sha256:7d575b54cb3863ef9bc290ea4b009999d55dc237326131e4853cf33e888fee03"},
+ {file = "yarl-1.25.1-cp312-cp312-win_arm64.whl", hash = "sha256:bc3ac7bf569f6b64dad04dd7808c7872dae8a97df657856eac05e9b7e3614a85"},
+ {file = "yarl-1.25.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:25868beca8b6765f8f7d0e11fe6dd7c66dd4b0793b9500286d20cc92352126a5"},
+ {file = "yarl-1.25.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:10b2fd95332f0d716d5eee3c9fb2ce8eada19082de7fee83d32e37992fd75c26"},
+ {file = "yarl-1.25.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f12afda4eea8c8994a76d4df1875c765194f5fbe8a9d197929ea303caee29ec"},
+ {file = "yarl-1.25.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:14b79a30a93a3ce2e8832603fd0ab780ada281b0ba5110b519a634f2d7d7d1fc"},
+ {file = "yarl-1.25.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4bd6340d20ae2c7ca719b87b426e808e90743b676d05d4c26c4fb5ca71f41184"},
+ {file = "yarl-1.25.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:126a2533570c554719ca40a1288fdee1700b6bc82e7131aa69fa85252d92e651"},
+ {file = "yarl-1.25.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a3faadac7d812ddac258feb57b9846b60c1b437c4f4b9ad42595c6f6fe4390df"},
+ {file = "yarl-1.25.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be80550d9bfe83d9b62398a37081a90434e6df2d978ec345c3d2820de6beddab"},
+ {file = "yarl-1.25.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e07595c7d6f4db270ceede356a1bd1c07a34f1c26f958d1ed0cd7b48e0d2bba3"},
+ {file = "yarl-1.25.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eb96ed1ae6c7d072d60840c0434aef07a2df611812810807fbc54263a6053e9a"},
+ {file = "yarl-1.25.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3feb99222553a8cbedfa52c2f59dd84c3f50d5b582c728d522caf8d72769a54b"},
+ {file = "yarl-1.25.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a2ed0ba415ccdf08f14bf544cb78346d0f76086707ffee24921a2c84dbf1305a"},
+ {file = "yarl-1.25.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2b49375d22299b0a834c2bca72f39aaecc270d96fb24c30424899676f487b22a"},
+ {file = "yarl-1.25.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ef74070ac553c59eb4f04258722066d6c6135b7baa03b2e9f2da65c096e96d98"},
+ {file = "yarl-1.25.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0a66db89ea473abeac4b70523cafd94db3772380e565f9d28af7a179b7af71fa"},
+ {file = "yarl-1.25.1-cp313-cp313-win_amd64.whl", hash = "sha256:1f51020b2eb8a003c84925638ec63c21a750a4bddd3a22ec8eac6a742dadf1b9"},
+ {file = "yarl-1.25.1-cp313-cp313-win_arm64.whl", hash = "sha256:b10dd0557ba422715b5206b3743192135a6022acca8baec51aa127d0a75db8fe"},
+ {file = "yarl-1.25.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:a9ca696eb02e5c02a8afd872ada510eba9b7fe6e68b9572c2e9a9b1941e31e2e"},
+ {file = "yarl-1.25.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a5877f2255aab518ebe528289037699201d5dc5f045f2396cb30aa02db22f57f"},
+ {file = "yarl-1.25.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7a5c3115595995779ee21f2567035793911c3802a43c74f3fbb0314929ec67ac"},
+ {file = "yarl-1.25.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77e5099b99b37f3cf79c246998ca9f7313a78054cd1809ec46bc1afad47e1c4c"},
+ {file = "yarl-1.25.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6efaf45df6a849cef613a03a94c845647456662f85438c886bb67a9c027c8c2c"},
+ {file = "yarl-1.25.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d5f90e44653c4e0f78501ed9bb7d3fce835a8d62b7c6ed0cb16557534087e743"},
+ {file = "yarl-1.25.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:632da579b2d879f6bad20f2cfa35ded1efe2f4f77f8abb26a6234a5b236acd2f"},
+ {file = "yarl-1.25.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:30eec96e8a91bd588ce897c9543f6d5d8d34b28fbcba28a4dedf20ebeae9fe57"},
+ {file = "yarl-1.25.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:12b6bc4906e11f5e1a1cdcb12296e7afbd366c783cc8073403cd2fb74334e453"},
+ {file = "yarl-1.25.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9d6ed3d17bccce4c05343e1ca8da13bc5c02c812a4e7282ddd05e8769322d3fc"},
+ {file = "yarl-1.25.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:f38a70074041d3b7e138e452799f5174198bae5bd5ab2000917badf403908c5f"},
+ {file = "yarl-1.25.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca89e4e21854ed27ec753297dde84b16c9f8e53b14a4866fb44457d643c19f8"},
+ {file = "yarl-1.25.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:1ab7618921a93767387a4b83776f751588f5b5ae9bb5bc96620e2e2e00bca868"},
+ {file = "yarl-1.25.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:0ae12ff2b805fa02c4dab838005caef735e39986322698c48588d3beacb65c62"},
+ {file = "yarl-1.25.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:90c30ed53546da833c700115c0064c22120d1b1560f474699fd31f22dd668233"},
+ {file = "yarl-1.25.1-cp314-cp314-win_amd64.whl", hash = "sha256:acfa7e22aa6c6e7a5996a41d275bfa01efa7ea56ab890590280e9063e2cf5c1b"},
+ {file = "yarl-1.25.1-cp314-cp314-win_arm64.whl", hash = "sha256:8e7d98cdbb6d71e726f7d525952867096053d1f290dd4e3c50d7d313a136f414"},
+ {file = "yarl-1.25.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:d21f0fa80a02d05299207eeaafef345d812ace96d5306e4ef265e1d419a615fa"},
+ {file = "yarl-1.25.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:17c9877a89fb6e2bca6f9087eb24cd7fb434653946ef5075e470d23d49b52287"},
+ {file = "yarl-1.25.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:29273edf1530e397bd07cb784db1fbe0d2590b77569f2e24679a9c0a2d763b94"},
+ {file = "yarl-1.25.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7abffdf37af1cec6a2ad69b827aa84320db5894791bc8ed932dc93fb274b7e9"},
+ {file = "yarl-1.25.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2239a02249d9326655419e0168a28ca9008938eaab31dc29fc875c217927a6c0"},
+ {file = "yarl-1.25.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:664ec6a520b74a1df2810666eb67695fcb77fa663e6ea0a25aaf2e529cb24dfa"},
+ {file = "yarl-1.25.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4f1c91f5a5980a937ff8e238e98e6897e1ad74a4b1e2c0d68c73b5ffbb3f5c0b"},
+ {file = "yarl-1.25.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c88edaec8c349ad4c5ad4c486a3defcc4b80ceb2f074436ffa0a87caf5e76a6"},
+ {file = "yarl-1.25.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:35dcbea443fafb3eece757ad4e514560ddeb6c34cfae1582c620d7b293d7feee"},
+ {file = "yarl-1.25.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:882569ff613758cac762a457a5d72d6e211b28d4bcfea89d1d71ea942b02eac0"},
+ {file = "yarl-1.25.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:d0f1489233a254bb3643d2f05de7d59019254d81daeca6b9162fe9edef57e0c7"},
+ {file = "yarl-1.25.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:f41753a76f4f63927d03a0d8ba8f5ce0f2083bec29a8cfaccc55371b1564b96b"},
+ {file = "yarl-1.25.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8fb0eb4955adf0579001581f2f71a126e8781ba61bcd120f127b0401163c6c2d"},
+ {file = "yarl-1.25.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a1e32763e641a1566507d90a8d3b19bfc3cc04a9d4e5ae3e32189874ed4b58a3"},
+ {file = "yarl-1.25.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:65b5b2066651b7432d389e9799d979c703bcc6ef44266bb8153ef54e91e4aab3"},
+ {file = "yarl-1.25.1-cp314-cp314t-win_amd64.whl", hash = "sha256:734f6e5400352ac4254456003d462866c684703570929cff7a7bde015d0cb371"},
+ {file = "yarl-1.25.1-cp314-cp314t-win_arm64.whl", hash = "sha256:287e99ff5aa4dc1c7630bfc683ded6f106d756c99dec432a2d7f197a784f51c6"},
+ {file = "yarl-1.25.1-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:9b1bdaae98bc016825dd3c9d8ee1832f829b3341f9cc6ebd1a1b0a7fef7367cc"},
+ {file = "yarl-1.25.1-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:e7011b8fb8c4054bf0c12e5edc6cd83778b0028e99ce59b18586ed036f92cfdc"},
+ {file = "yarl-1.25.1-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:f074e8d4aa0a5798920ddb6de3d08b228c614ff3724c3e8bd7577f4bafea867b"},
+ {file = "yarl-1.25.1-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d42e7e3ca399555578b4d617e3a6ecf13371b3743a115995fa010c7bf341459"},
+ {file = "yarl-1.25.1-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:aa4ed3dd308548f9e707d9caaf005d2d7f8c1e7868f858dfeb47fe76e16b391d"},
+ {file = "yarl-1.25.1-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42a66563d8cc056ee32e6191e05097a7b2b3bc302e0bc3133daf8710eb18bd26"},
+ {file = "yarl-1.25.1-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:98d370568f393215d605304cdb77b3d5539bd192c75b623c7304c42c8d6d8273"},
+ {file = "yarl-1.25.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23bf5b403c879a54964e0feac7285688e04bb220074878d737d331522da0a5bf"},
+ {file = "yarl-1.25.1-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d45673badd08456d0340e9364eddafe1c53a9d2896424294de4d7dd71ad3ee57"},
+ {file = "yarl-1.25.1-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:0136d640dfa9b0523853e411430a99f8a91eca85774c6420285a33b755bc6de3"},
+ {file = "yarl-1.25.1-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:59ba3a6e1aa8cfe5adf4bd270fd965db21955401b7ca6f1696010c55ed4daec2"},
+ {file = "yarl-1.25.1-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:87796fedc3ba97ec14fab55acb48584276e6c1e4c1e89c422bda62c838e754a9"},
+ {file = "yarl-1.25.1-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:bd0912757081f89b107d6c00b2ff8a194401b0b87eadcf4481de2b865a8fd44f"},
+ {file = "yarl-1.25.1-cp315-cp315-musllinux_1_2_s390x.whl", hash = "sha256:b51c159a9794633f5e0db7ecec7b2b6e3734eca1f5d17dc989ff3552a43ff78b"},
+ {file = "yarl-1.25.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:319e070a01db9920fb63761843f96a104c8e2b9427266731810dc1e22595b17c"},
+ {file = "yarl-1.25.1-cp315-cp315-win_amd64.whl", hash = "sha256:a2059a2d891bd156bc5184e7ab7a56e78a84dfcfdeac8c501b552533ad1c36ee"},
+ {file = "yarl-1.25.1-cp315-cp315-win_arm64.whl", hash = "sha256:a78b50b4f7918a3de71105d5c0b93bbc57bb8339a4d03a9dfd449f9068e76f3d"},
+ {file = "yarl-1.25.1-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:b5402a340723fa7da00b5cff987ddab61276be6d11251ea71ae02bcac54890d8"},
+ {file = "yarl-1.25.1-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:eda19ea5ee88742f47a2340816e6f2d40b53bed3ab5b69794769f36af9f35bb4"},
+ {file = "yarl-1.25.1-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:75baa6cf9b6d1c52f3e111a130e202fd8cf0a5b3a066c3f73d615e885092e4ec"},
+ {file = "yarl-1.25.1-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dbcef5a9119ef653653132cccaf999b30a0af6f33bb0a4ba80bec30056868487"},
+ {file = "yarl-1.25.1-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7efc9f082dfed77c316edffa9deb52888e1bc6789171887cc1f68e06d65465c8"},
+ {file = "yarl-1.25.1-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fe01645169a2112aa1d4ebc3e4c5f029c5c8f97adfc32e5d37c993b39a994d75"},
+ {file = "yarl-1.25.1-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1c557dfd5e3db046053a0bdc72261ade790ebe8e2c7a41b36b0ca1f14cb95f3"},
+ {file = "yarl-1.25.1-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ce4d6ccafb33d39bd78444612d14938ead674c25702ded2ee9c54a47735d225"},
+ {file = "yarl-1.25.1-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:80a063f8297fc796296f00f100be520f209b23dc98f93ce8eba6ee7122598209"},
+ {file = "yarl-1.25.1-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:7cb414a73e21a7ab58254926073f2930cb22f5b4314ea4260a687e2b3fd4dce3"},
+ {file = "yarl-1.25.1-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:85a18376073f8a39aa07be34f9fc77e2869aa72c55c441efdd2cf79a0407504d"},
+ {file = "yarl-1.25.1-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:77716e245c90f058466a05e6a465bb8600f767a8f4b18b4d40f3aff958e5f73c"},
+ {file = "yarl-1.25.1-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:1e80dcf1446e1b080b1932b0d103c464a04112f5bc31f0f983ad418172063cde"},
+ {file = "yarl-1.25.1-cp315-cp315t-musllinux_1_2_s390x.whl", hash = "sha256:bdc8d8b8c22e9e43ac68316b5e6cf083dec537f4ec213cb4aa967b583bc3fa64"},
+ {file = "yarl-1.25.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:dfbf531053a0935f2e871bcd4753f90313688772ff8c017f5ea402e315a78c1f"},
+ {file = "yarl-1.25.1-cp315-cp315t-win_amd64.whl", hash = "sha256:b13b88747769537f3d32e89e3a735da10c0a9e35d7322928c701b5f93d3afffd"},
+ {file = "yarl-1.25.1-cp315-cp315t-win_arm64.whl", hash = "sha256:783dd1467083f4d3f7722ad6a313f24c173e7571372738fcb7a6e6d1ba48df25"},
+ {file = "yarl-1.25.1-py3-none-any.whl", hash = "sha256:681c758b0490f9e96b78e5fa8e8dc6e648e9185bb6eaebe73183c33ea0c445f3"},
+ {file = "yarl-1.25.1.tar.gz", hash = "sha256:03dd38de09bc213e9a8b29761eec33ee1d5318dac0e49d8af36e4d27830e23a7"},
]
[package.dependencies]
@@ -1710,4 +1761,4 @@ aiohttp = ["aiohttp", "httpx-aiohttp"]
[metadata]
lock-version = "2.1"
python-versions = "^3.10"
-content-hash = "65ef513ef69a32344fa2133df094babe6493482ea7586d0e19edbcb2f4bbe7c8"
+content-hash = "d6f20007544f9ff1b04d92f47b351e1eda2f66672b4c62350d35c919bc2ae9f3"
diff --git a/pyproject.toml b/pyproject.toml
index 17a6e91..1dc545d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ dynamic = ["version"]
[tool.poetry]
name = "phenoml"
-version = "17.0.0"
+version = "0.0.0.dev0"
description = ""
readme = "README.md"
authors = []
@@ -31,9 +31,6 @@ classifiers = [
packages = [
{ include = "phenoml", from = "src"}
]
-include = [
- { path = "src/phenoml/openapi/openapi.json", format = ["sdist", "wheel"] }
-]
[tool.poetry.urls]
Repository = 'https://github.com/phenoml/phenoml-python-sdk'
@@ -42,7 +39,7 @@ Repository = 'https://github.com/phenoml/phenoml-python-sdk'
python = "^3.10"
aiohttp = { version = ">=3.14.1,<4", optional = true, python = ">=3.10"}
httpx = ">=0.21.2"
-httpx-aiohttp = { version = "0.1.8", optional = true, python = ">=3.10"}
+httpx-aiohttp = { version = "^0.1.8", optional = true, python = ">=3.10"}
pydantic = ">= 1.9.2"
pydantic-core = ">=2.18.2,<3.0.0"
typing_extensions = ">= 4.0.0"
diff --git a/reference.md b/reference.md
index 99385a6..c6c4962 100644
--- a/reference.md
+++ b/reference.md
@@ -3719,52 +3719,81 @@ Multiple FHIR provider integrations can be provided as comma-separated values.
-
-Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows
-(person, visit_occurrence, condition_occurrence, drug_exposure,
-procedure_occurrence, measurement, observation).
-
-Resource support is intentionally limited to the OMOP tables returned by
-this endpoint:
-- `Patient` -> `person`
+Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows,
+grouped by destination table in `tables`.
+
+Current resource coverage:
+- `Patient` -> `person`; `deceased[x]` can also produce `death`, and the
+ first address can produce `location`
+- `observation_period` -> one derived row per person with dated visit,
+ clinical, or death rows, spanning those dates
+- `Location` -> `location` and `care_site`
+- `Organization` -> `care_site`; its first address can produce `location`
+- `HealthcareService` -> `care_site`
+- `Practitioner` and `PractitionerRole` -> `provider`
- `Encounter` -> `visit_occurrence`
- `Condition` -> `condition_occurrence`
- `Procedure` -> `procedure_occurrence`
- `MedicationRequest`, `MedicationStatement`, and
`MedicationAdministration` -> `drug_exposure`
- `Immunization` -> `drug_exposure`
-- `Observation` with a numeric `valueQuantity`, `valueInteger`, or
- numeric-looking `valueString` (for example `"<2"`) -> `measurement`
-- non-numeric `Observation` -> `observation`
+- `Observation` -> `measurement` or `observation`. For coded
+ Observations, the resolved OMOP concept domain selects the table; value
+ form only breaks ties. For text-only Observations, numeric values route
+ to `measurement` and nonnumeric values to `observation`.
- `AllergyIntolerance` -> `observation`
-`Medication` is supported only as reference data for medication
-resources; it is not emitted as its own row because OMOP CDM has no
-Medication table. Other reference/admin resources such as `Practitioner`,
-`Organization`, `Location`, `Coverage`, and `Claim`, and clinical
-workflow/document resources such as `DiagnosticReport`, `ServiceRequest`,
-`CarePlan`, `DocumentReference`, `Composition`, `Specimen`, and
-`DeviceUseStatement`, are currently accepted in a Bundle but are not
-shaped into OMOP rows. Unsupported resource types are ignored rather than
-listed under `dropped`; `dropped` is reserved for supported resource types
-that were missing the subject/patient, code, or medication reference data
-needed to produce a valid row.
-
-Each resource's primary clinical coding is resolved to a standard OMOP
-`concept_id`. Alongside the OMOP rows grouped by table (`tables`), the
-response carries `mappings` (how each source coding resolved, linked back
-to the row it produced), `dropped` (resources that could not be shaped
-into a row), `vocab_version` (the OMOP vocabulary release codes were
-resolved against), and a small `summary` of the resolution outcomes.
+`Medication` is reference data for medication resources; it does not
+create its own row because OMOP CDM has no Medication table. Administrative
+linkages (provider, care site, and location) are best-effort and limited to
+references supplied in the request. Their supporting concepts, including
+provider specialty, country, and place of service, are not mapped.
+
+`DiagnosticReport`, `ServiceRequest`, `CarePlan`, `DocumentReference`,
+`Composition`, `Specimen`, `DeviceUseStatement`, `Coverage`, `Claim`, and
+other unsupported resource types are accepted in a Bundle but ignored: they
+create no row and no `dropped` entry. `dropped` is reserved for supported
+row-producing resources that could not be shaped because the subject/patient,
+clinical code/text, or medication data was not usable. A single-Patient
+Bundle can attribute a supported clinical resource with a missing or
+unresolvable subject to that sole person; in a multi-Patient Bundle, that
+resource is dropped instead.
+
+Coded Observation routing is selected from the resolved OMOP concept
+domain. Numeric and nonnumeric `value[x]` forms establish the preferred
+target only when the code is valid for both tables. A text-only
+Observation has no resolver target, so numeric values route to
+`measurement` and nonnumeric values to `observation`. Numeric values
+populate `value_as_number` in the selected row; nonnumeric values
+populate `value_as_string` for an `observation` or `value_source_value`
+for a `measurement`. `valueCodeableConcept` remains source text and does
+not populate `value_as_concept_id`; other unsupported `value[x]` forms
+and Observation components do not populate separate converted values. A
+numeric comparator (`<`, `<=`, `>`, `>=`) is represented only by a
+measurement's `operator_concept_id`; units remain source text and have
+`unit_concept_id` of `0`.
+
+A single standard OMOP `concept_id` is selected for each clinical row
+after considering all of the resource's supplied codings. Alongside the
+OMOP rows grouped by table (`tables`), the response carries `mappings`
+(an entry for every source coding, linked back to the row it produced),
+`dropped` (resources that could not be shaped into a row),
+`vocab_version` (the OMOP vocabulary release codes were resolved
+against), and a small `summary` of the resolution outcomes.
A `concept_id` of `0` is reported, not omitted (OMOP "no matching
concept" semantics): it covers both a coding with no standard match
(`UNMAPPED`) and an unverified suggestion for a text-only resource
-(`UNCHECKED`). Only the primary clinical coding is resolved, so
-`gender`/`race`/`ethnicity`/`visit`/`value`/`unit` `concept_id`s are
-always `0`; the one populated non-resolved concept is measurement
+(`UNCHECKED`). Demographic, visit, categorical-value, and unit concept
+fields currently remain `0`; the one populated non-resolved concept is
+measurement
`operator_concept_id`, set from a value comparator (`<`, `<=`, `>`, `>=`)
-rather than the resolver. Each `*_source_value` carries the verbatim FHIR
-coding (`system#code`), and `*_type_concept_id` is set to `32817` (EHR).
+rather than terminology resolution. Clinical `*_source_value` fields
+preserve the selected FHIR coding (`system#code`, or `code` when no
+system is supplied), falling back to source text for text-only resources.
+Other `*_source_value` fields preserve row-specific raw source values,
+such as resource identifiers, names, units, or status codes, and
+`*_type_concept_id` is set to `32817` (EHR).
Medication codes are resolved whether they appear inline
(`medicationCodeableConcept`) or via a `medicationReference` to a contained,
@@ -3772,8 +3801,18 @@ relative (`Type/id`), or bundle-entry (`urn:uuid`) `Medication` resource.
Resources that cannot be shaped into a row — a medication with no usable
code, resolvable reference, or display, or any clinical resource whose
subject/patient reference cannot be tied to a person — are reported under
-`dropped` rather than emitted as blank rows. The
-bundle must contain at least one Patient resource.
+`dropped` rather than emitted as blank rows. The Bundle must contain at
+least one Patient resource.
+
+All row IDs start at `1` for each request and are not stable or global.
+For clinical conversion rows whose resource supplies an `id`, `mappings`
+associates each row with that source FHIR resource ID. A `person` row
+retains the Patient ID or its first identifier value in
+`person_source_value`, when present; other reference and derived rows do
+not uniformly carry a FHIR resource ID. Input resources without those
+source identifiers cannot be correlated across responses from the
+returned rows alone. Consumers combining responses need to establish
+their own stable keys and remap every primary and foreign key together.
@@ -3823,11 +3862,12 @@ client.fhir2omop.create(
FHIR resources (single resource or Bundle). Must contain at least one
Patient resource. Supported row-producing resources are Patient,
-Encounter, Condition, Procedure, MedicationRequest,
+Location, Organization, HealthcareService, Practitioner,
+PractitionerRole, Encounter, Condition, Procedure, MedicationRequest,
MedicationStatement, MedicationAdministration, Immunization,
Observation, and AllergyIntolerance. Standalone Medication resources
are consumed by medication references rather than mapped to their own
-table. Other resource types are accepted but ignored.
+table. Unsupported resource types are accepted in a Bundle but ignored.
@@ -4689,11 +4729,9 @@ client.implementation_guides.implementation_guides.update(
-
-Deletes the stored metadata for an implementation guide — its
-profile_context and timestamps. Member profiles keep their
-implementation_guide assignment, so a guide still referenced by at least
-one profile continues to appear in listings, just without context or
-timestamps.
+Deletes the stored name-level metadata and any exact canonical package
+versions beneath the guide. Legacy member profile assignments are not
+changed.
@@ -4751,6 +4789,184 @@ client.implementation_guides.implementation_guides.delete(
+
+
+
+
+client.implementation_guides.implementation_guides.create_version(...) -> ImplementationGuideVersionDetail
+
+-
+
+#### 📝 Description
+
+
+-
+
+
+-
+
+Publishes an exact package beneath this guide family. PR 2 temporarily
+permits one exact package version per guide family; publishing another
+version returns `409 Conflict` until multi-version package support lands.
+
+
+
+
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from phenoml import PhenomlClient
+from phenoml.environment import PhenomlClientEnvironment
+from phenoml.implementation_guides import FhirImplementationGuide
+
+client = PhenomlClient(
+ client_id="",
+ client_secret="",
+ environment=PhenomlClientEnvironment.DEFAULT,
+)
+
+client.implementation_guides.implementation_guides.create_version(
+ name="name",
+ implementation_guide=FhirImplementationGuide(
+ resource_type="ImplementationGuide",
+ url="url",
+ version="version",
+ ),
+ profile_refs=[
+ "profile_refs"
+ ],
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**name:** `str`
+
+
+
+
+
+-
+
+**implementation_guide:** `FhirImplementationGuide`
+
+
+
+
+
+-
+
+**profile_refs:** `typing.List[str]` — Exact canonical `url|version` references to builtin or custom profiles. A package can contain at most 250 references.
+
+
+
+
+
+-
+
+**profile_context:** `typing.Optional[str]` — Natural-language profile-selection context for this package.
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
+
+
+
+
+client.implementation_guides.implementation_guides.get_version(...) -> ImplementationGuideVersionDetail
+
+-
+
+#### 🔌 Usage
+
+
+-
+
+
+-
+
+```python
+from phenoml import PhenomlClient
+from phenoml.environment import PhenomlClientEnvironment
+
+client = PhenomlClient(
+ client_id="",
+ client_secret="",
+ environment=PhenomlClientEnvironment.DEFAULT,
+)
+
+client.implementation_guides.implementation_guides.get_version(
+ name="name",
+ version="1.0.0",
+)
+
+```
+
+
+
+
+
+#### ⚙️ Parameters
+
+
+-
+
+
+-
+
+**name:** `str`
+
+
+
+
+
+-
+
+**version:** `str` — The authored ImplementationGuide.version. It may contain letters, numbers, and the punctuation characters `.`, `_`, `~`, `+`, and `-`; it cannot be exactly `.` or `..`.
+
+
+
+
+
+-
+
+**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
+
+
+
+
+
@@ -5179,7 +5395,7 @@ client.lang2fhir.upload_profile(
-
-Extracts text from a document (PDF or image) and converts it into a structured FHIR resource.
+Extracts text from a PDF, image, RTF, or XML/C-CDA document and converts it into a structured FHIR resource.
**Patient identifier handling.** When generating a `patient` (or `patient-canvas`) resource, US Core requires `Patient.identifier` (a business identifier such as an MRN). When the source text contains an identifier, it is extracted with an appropriate URI system. When the source text does not contain a detectable identifier, a synthetic one is generated with `system: "urn:phenoml:lang2fhir-generated-id"` and a UUID `value` so the resource remains FHIR-valid and US Core conformant. Callers who need a tenant-specific namespace should rewrite the synthetic system after extraction.
@@ -5208,7 +5424,7 @@ client = PhenomlClient(
client.lang2fhir.document(
version="R4",
resource="questionnaire",
- content="JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)",
+ content="JVBERi0xLjQKJeLjz9MK...(base64-encoded document bytes)",
)
```
@@ -5244,8 +5460,11 @@ client.lang2fhir.document(
**content:** `str`
Base64 encoded file content.
-Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff).
+Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff), RTF (application/rtf), XML/C-CDA (text/xml).
+RTF and XML/C-CDA uploads are available on dedicated instances only.
File type is auto-detected from content magic bytes.
+The decoded file must not exceed 20 MiB. RTF and XML/C-CDA documents whose extracted text exceeds 1 MiB are rejected.
+Generic XML must include an XML declaration; C-CDA documents rooted at `ClinicalDocument` may omit it.
@@ -5285,7 +5504,7 @@ File type is auto-detected from content magic bytes.
-
-Extracts text from a document (PDF or image) and converts it into multiple FHIR resources,
+Extracts text from a PDF, image, RTF, or XML/C-CDA document and converts it into multiple FHIR resources,
returned as a transaction Bundle. Combines document text extraction with multi-resource detection.
Automatically detects Patient, Condition, MedicationRequest, Observation, and other resource types.
Resources are linked with proper references (e.g., Conditions reference the Patient).
@@ -5319,7 +5538,7 @@ client = PhenomlClient(
client.lang2fhir.document_multi(
version="R4",
- content="JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)",
+ content="JVBERi0xLjQKJeLjz9MK...(base64-encoded document bytes)",
provider="medplum",
config=DocumentConfig(
split_classifications=[
@@ -5362,8 +5581,11 @@ client.lang2fhir.document_multi(
**content:** `str`
Base64 encoded file content.
-Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff).
+Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff), RTF (application/rtf), XML/C-CDA (text/xml).
+RTF and XML/C-CDA uploads are available on dedicated instances only.
File type is auto-detected from content magic bytes.
+The decoded file must not exceed 20 MiB. RTF and XML/C-CDA documents whose extracted text exceeds 1 MiB are rejected.
+Generic XML must include an XML declaration; C-CDA documents rooted at `ClinicalDocument` may omit it.
@@ -5540,10 +5762,8 @@ credential. A `request_id` whose job was canceled or failed before it
finalized is released for a fresh replay; once a job is finalized, its
`request_id` keeps resolving to it even after cancellation.
-An instance may hold at most 4 active (pending or processing) jobs at
-once; a create past that limit returns `409`. The limit is instance-wide
-— jobs are shared across the instance's credentials — so another
-credential's jobs count against it.
+There is no limit on how many jobs an instance may hold at once; how many
+items run in parallel is a property of the instance, not of the job count.
@@ -5587,8 +5807,9 @@ client.lang2fhir_batch.create(
**request_id:** `typing.Optional[str]`
-Optional client idempotency token. A retried create with the same
-token returns the original job instead of opening a second one.
+Optional client idempotency token (at most 256 UTF-8 bytes). A
+retried create with the same token returns the original job instead
+of opening a second one.
@@ -5629,7 +5850,7 @@ The upload enforces these rules:
- Set **exactly one** of `document` or `create`. Setting both, or
neither, is a `400`.
- When `document` is set, `file` is **required** — it supplies the
- document's binary content (PDF or image).
+ document's file content (PDF, image, RTF, or XML/C-CDA).
- When `create` is set, `file` is **forbidden** — a create item carries
no file.
- `document` and `create` must each be a JSON **object**.
@@ -5743,7 +5964,13 @@ accompanied by a `file`.
**file:** `typing.Optional[core.File]`
-The document's binary content (PDF, PNG, JPEG, or TIFF).
+The document's file content (PDF, PNG, JPEG, TIFF, RTF, or
+XML/C-CDA). The document pipeline accepts files up to 20 MiB;
+an upload that passes the storage cap but exceeds this limit
+fails during processing. RTF and XML/C-CDA documents whose
+extracted text exceeds 1 MiB also fail during processing.
+Generic XML must include an XML declaration; C-CDA documents
+rooted at `ClinicalDocument` may omit it.
Required with `document`; forbidden with `create`.
@@ -5754,10 +5981,11 @@ Required with `document`; forbidden with `create`.
**request_id:** `typing.Optional[str]`
-Optional idempotency token (max 256 bytes). Re-uploading under
-the same token overwrites the same item instead of adding a
-new one. The token is scoped to this job; the same token in
-another job is independent and creates a separate item.
+Optional idempotency token (at most 256 UTF-8 bytes).
+Re-uploading under the same token overwrites the same item
+instead of adding a new one. The token is scoped to this job;
+the same token in another job is independent and creates a
+separate item.
@@ -5767,9 +5995,9 @@ another job is independent and creates a separate item.
**id:** `typing.Optional[str]`
-Optional caller-supplied correlation label (max 512 bytes),
-echoed back on status and result listings so you can match the
-server's item_id to your own record.
+Optional caller-supplied correlation label (at most 512 UTF-8
+bytes), echoed back on status and result listings so you can
+match the server's item_id to your own record.
@@ -5880,8 +6108,8 @@ client.lang2fhir_batch.finalize(
-
-Drives a job to the terminal `canceled` state on request, freeing its
-active-job slot immediately. Takes no request body.
+Drives a job to the terminal `canceled` state on request. Takes no
+request body.
Cancel does not delete the job: the job record and any results already
produced are preserved for the normal retention window, the same as a
diff --git a/src/phenoml/agent/chat/client.py b/src/phenoml/agent/chat/client.py
index 9939bf6..6cce68f 100644
--- a/src/phenoml/agent/chat/client.py
+++ b/src/phenoml/agent/chat/client.py
@@ -418,7 +418,7 @@ async def stream(
async def main() -> None:
- response = await client.agent.chat.stream(
+ response = client.agent.chat.stream(
phenoml_on_behalf_of="Patient/550e8400-e29b-41d4-a716-446655440000",
phenoml_fhir_provider="550e8400-e29b-41d4-a716-446655440000:eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c...",
message="What is the patient's current condition?",
diff --git a/src/phenoml/agent/chat/raw_client.py b/src/phenoml/agent/chat/raw_client.py
index b163d97..221e657 100644
--- a/src/phenoml/agent/chat/raw_client.py
+++ b/src/phenoml/agent/chat/raw_client.py
@@ -277,6 +277,8 @@ def _iter():
for _sse in _event_source.iter_sse():
if _sse.data == None:
return
+ if len(_sse.data) == 0:
+ continue
try:
yield typing.cast(
AgentChatStreamEvent,
@@ -766,6 +768,8 @@ async def _iter():
async for _sse in _event_source.aiter_sse():
if _sse.data == None:
return
+ if len(_sse.data) == 0:
+ continue
try:
yield typing.cast(
AgentChatStreamEvent,
diff --git a/src/phenoml/client.py b/src/phenoml/client.py
index 87cfa7e..8073193 100644
--- a/src/phenoml/client.py
+++ b/src/phenoml/client.py
@@ -63,8 +63,8 @@ class PhenomlClient:
base_url : typing.Optional[str]
The base url to use for requests from the client.
- token : typing.Callable[[], str]
- Authenticate by providing a callable that returns a pre-generated bearer token. In this mode, OAuth client credentials are not required.
+ token : typing.Union[str, typing.Callable[[], str]]
+ Authenticate by providing a pre-generated bearer token, or a callable that returns one. In this mode, OAuth client credentials are not required.
timeout : typing.Optional[float]
The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.
@@ -130,7 +130,7 @@ def __init__(
follow_redirects: typing.Optional[bool] = True,
httpx_client: typing.Optional[httpx.Client] = None,
logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
- token: typing.Callable[[], str],
+ token: typing.Union[str, typing.Callable[[], str]],
): ...
def __init__(
self,
@@ -141,7 +141,7 @@ def __init__(
headers: typing.Optional[typing.Dict[str, str]] = None,
client_id: typing.Optional[str] = os.getenv("PHENOML_CLIENT_ID"),
client_secret: typing.Optional[str] = os.getenv("PHENOML_CLIENT_SECRET"),
- token: typing.Optional[typing.Callable[[], str]] = None,
+ token: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None,
_token_getter_override: typing.Optional[typing.Callable[[], str]] = None,
timeout: typing.Optional[float] = None,
max_retries: typing.Optional[int] = None,
@@ -155,7 +155,12 @@ def __init__(
_defaulted_max_retries = max_retries if max_retries is not None else 2
if instance_url is not None:
_instance_url = instance_url if instance_url is not None else "experiment.app.pheno.ml"
- base_url = "https://{instanceUrl}".format(instanceUrl=_instance_url)
+ _environment_url_templates = {
+ PhenomlClientEnvironment.DEFAULT: "https://{instanceUrl}",
+ }
+ _url_template = _environment_url_templates.get(environment, "https://{instanceUrl}")
+ if base_url is None:
+ base_url = _url_template.format(instanceUrl=_instance_url)
if token is not None:
self._client_wrapper = SyncClientWrapper(
base_url=_get_base_url(base_url=base_url, environment=environment),
@@ -398,8 +403,8 @@ class AsyncPhenomlClient:
base_url : typing.Optional[str]
The base url to use for requests from the client.
- token : typing.Callable[[], str]
- Authenticate by providing a callable that returns a pre-generated bearer token. In this mode, OAuth client credentials are not required.
+ token : typing.Union[str, typing.Callable[[], str]]
+ Authenticate by providing a pre-generated bearer token, or a callable that returns one. In this mode, OAuth client credentials are not required.
timeout : typing.Optional[float]
The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.
@@ -465,7 +470,7 @@ def __init__(
follow_redirects: typing.Optional[bool] = True,
httpx_client: typing.Optional[httpx.AsyncClient] = None,
logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
- token: typing.Callable[[], str],
+ token: typing.Union[str, typing.Callable[[], str]],
): ...
def __init__(
self,
@@ -476,7 +481,7 @@ def __init__(
headers: typing.Optional[typing.Dict[str, str]] = None,
client_id: typing.Optional[str] = os.getenv("PHENOML_CLIENT_ID"),
client_secret: typing.Optional[str] = os.getenv("PHENOML_CLIENT_SECRET"),
- token: typing.Optional[typing.Callable[[], str]] = None,
+ token: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None,
_token_getter_override: typing.Optional[typing.Callable[[], str]] = None,
timeout: typing.Optional[float] = None,
max_retries: typing.Optional[int] = None,
@@ -490,7 +495,12 @@ def __init__(
_defaulted_max_retries = max_retries if max_retries is not None else 2
if instance_url is not None:
_instance_url = instance_url if instance_url is not None else "experiment.app.pheno.ml"
- base_url = "https://{instanceUrl}".format(instanceUrl=_instance_url)
+ _environment_url_templates = {
+ PhenomlClientEnvironment.DEFAULT: "https://{instanceUrl}",
+ }
+ _url_template = _environment_url_templates.get(environment, "https://{instanceUrl}")
+ if base_url is None:
+ base_url = _url_template.format(instanceUrl=_instance_url)
if token is not None:
self._client_wrapper = AsyncClientWrapper(
base_url=_get_base_url(base_url=base_url, environment=environment),
diff --git a/src/phenoml/core/client_wrapper.py b/src/phenoml/core/client_wrapper.py
index dc25c0d..c03a243 100644
--- a/src/phenoml/core/client_wrapper.py
+++ b/src/phenoml/core/client_wrapper.py
@@ -33,12 +33,12 @@ def get_headers(self) -> typing.Dict[str, str]:
import platform
headers: typing.Dict[str, str] = {
- "User-Agent": "phenoml/17.0.0",
+ "User-Agent": "phenoml/0.0.0-fern-placeholder",
"X-Fern-Language": "Python",
"X-Fern-Runtime": f"python/{platform.python_version()}",
"X-Fern-Platform": f"{platform.system().lower()}/{platform.release()}",
"X-Fern-SDK-Name": "phenoml",
- "X-Fern-SDK-Version": "17.0.0",
+ "X-Fern-SDK-Version": "0.0.0.dev0",
**(self.get_custom_headers() or {}),
}
token = self._get_token()
diff --git a/src/phenoml/core/http_client.py b/src/phenoml/core/http_client.py
index 124dce2..3e5a786 100644
--- a/src/phenoml/core/http_client.py
+++ b/src/phenoml/core/http_client.py
@@ -3,6 +3,7 @@
import asyncio
import email.utils
import re
+import socket
import time
import typing
from contextlib import asynccontextmanager, contextmanager
@@ -23,6 +24,39 @@
JITTER_FACTOR = 0.2 # 20% random jitter
+def get_keepalive_socket_options(
+ idle: int = 60,
+ intvl: int = 30,
+ cnt: int = 5,
+) -> typing.List[typing.Tuple[int, int, int]]:
+ """
+ Build TCP keepalive socket options for the current platform.
+
+ Keepalive probes keep otherwise-idle connections alive so that long,
+ non-streaming requests survive idle-connection reaping by a firewall,
+ load balancer, or NAT. The available socket constants are OS-dependent,
+ so each option is guarded and only emitted when the platform defines it:
+
+ - ``SO_KEEPALIVE`` is portable (Linux/macOS/Windows).
+ - The idle-before-first-probe knob is ``TCP_KEEPIDLE`` on Linux and modern
+ Windows, but ``TCP_KEEPALIVE`` on macOS.
+ - ``TCP_KEEPINTVL`` / ``TCP_KEEPCNT`` exist on Linux/macOS/modern Windows.
+
+ Passing these tuples to ``httpx.HTTPTransport(socket_options=...)`` /
+ ``httpx.AsyncHTTPTransport(socket_options=...)`` applies them to every
+ connection the transport opens.
+ """
+ opts: typing.List[typing.Tuple[int, int, int]] = [(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)]
+ idle_const = getattr(socket, "TCP_KEEPIDLE", None) or getattr(socket, "TCP_KEEPALIVE", None)
+ if idle_const:
+ opts.append((socket.IPPROTO_TCP, idle_const, idle))
+ if hasattr(socket, "TCP_KEEPINTVL"):
+ opts.append((socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, intvl))
+ if hasattr(socket, "TCP_KEEPCNT"):
+ opts.append((socket.IPPROTO_TCP, socket.TCP_KEEPCNT, cnt))
+ return opts
+
+
def _parse_retry_after(response_headers: httpx.Headers) -> typing.Optional[float]:
"""
This function parses the `Retry-After` header in a HTTP response and returns the number of seconds to wait.
@@ -238,7 +272,16 @@ def get_request_body(
data: typing.Optional[typing.Any],
request_options: typing.Optional[RequestOptions],
omit: typing.Optional[typing.Any],
+ optional_body: bool = False,
) -> typing.Tuple[typing.Optional[typing.Any], typing.Optional[typing.Any]]:
+ # A whole body left at the sentinel was never passed by the caller, so it is absent
+ # rather than empty: the request carries no content and no `Content-Type`.
+ if omit is not None:
+ if json is omit:
+ json = None
+ if data is omit:
+ data = None
+
json_body = None
data_body = None
if data is not None:
@@ -254,14 +297,36 @@ def get_request_body(
# Only collapse empty dict to None when the body was not explicitly provided
# and there are no additional body parameters. This preserves explicit empty
# bodies (e.g., when an endpoint has a request body type but all fields are optional).
- if json_body == {} and json is None and not has_additional_body_parameters:
+ # `optional_body` marks an endpoint whose body the API does not require, where a body
+ # that ends up empty means the caller passed none of its properties, so the request is
+ # sent with no content and no `Content-Type`.
+ if json_body == {} and (json is None or optional_body) and not has_additional_body_parameters:
json_body = None
- if data_body == {} and data is None and not has_additional_body_parameters:
+ if data_body == {} and (data is None or optional_body) and not has_additional_body_parameters:
data_body = None
return json_body, data_body
+def drop_content_type_without_body(
+ headers: typing.Dict[str, typing.Any],
+ *,
+ json_body: typing.Optional[typing.Any],
+ data_body: typing.Optional[typing.Any],
+ optional_body: bool,
+) -> typing.Dict[str, typing.Any]:
+ """Strip ``Content-Type`` from a request that carries no body.
+
+ ``get_request_body`` drops the body of an ``optional_body`` endpoint when the caller
+ supplied none of it, but the endpoint still passes the content type it would have used.
+ A request that sends nothing must not advertise a media type, so a server that branches
+ on the header sees a bodyless call for what it is.
+ """
+ if not optional_body or json_body is not None or data_body is not None:
+ return headers
+ return {key: value for key, value in headers.items() if key.lower() != "content-type"}
+
+
class HttpClient:
def __init__(
self,
@@ -309,6 +374,7 @@ def request(
request_options: typing.Optional[RequestOptions] = None,
retries: int = 0,
omit: typing.Optional[typing.Any] = None,
+ optional_body: bool = False,
force_multipart: typing.Optional[bool] = None,
) -> httpx.Response:
base_url = self.get_base_url(base_url)
@@ -321,7 +387,9 @@ def request(
)
timeout = _timeout if _timeout is not None else httpx.USE_CLIENT_DEFAULT
- json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+ json_body, data_body = get_request_body(
+ json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body
+ )
request_files: typing.Optional[RequestFiles] = (
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
@@ -364,6 +432,9 @@ def request(
}
)
)
+ _request_headers = drop_content_type_without_body(
+ _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body
+ )
if self.logger.is_debug():
self.logger.debug(
@@ -472,6 +543,7 @@ def stream(
request_options: typing.Optional[RequestOptions] = None,
retries: int = 0,
omit: typing.Optional[typing.Any] = None,
+ optional_body: bool = False,
force_multipart: typing.Optional[bool] = None,
) -> typing.Iterator[httpx.Response]:
base_url = self.get_base_url(base_url)
@@ -493,7 +565,9 @@ def stream(
if (request_files is None or len(request_files) == 0) and force_multipart:
request_files = FORCE_MULTIPART
- json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+ json_body, data_body = get_request_body(
+ json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body
+ )
data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart)
@@ -527,6 +601,9 @@ def stream(
}
)
)
+ _request_headers = drop_content_type_without_body(
+ _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body
+ )
if self.logger.is_debug():
self.logger.debug(
@@ -604,6 +681,7 @@ async def request(
request_options: typing.Optional[RequestOptions] = None,
retries: int = 0,
omit: typing.Optional[typing.Any] = None,
+ optional_body: bool = False,
force_multipart: typing.Optional[bool] = None,
) -> httpx.Response:
base_url = self.get_base_url(base_url)
@@ -625,7 +703,9 @@ async def request(
if (request_files is None or len(request_files) == 0) and force_multipart:
request_files = FORCE_MULTIPART
- json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+ json_body, data_body = get_request_body(
+ json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body
+ )
data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart)
@@ -662,6 +742,9 @@ async def request(
}
)
)
+ _request_headers = drop_content_type_without_body(
+ _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body
+ )
if self.logger.is_debug():
self.logger.debug(
@@ -770,6 +853,7 @@ async def stream(
request_options: typing.Optional[RequestOptions] = None,
retries: int = 0,
omit: typing.Optional[typing.Any] = None,
+ optional_body: bool = False,
force_multipart: typing.Optional[bool] = None,
) -> typing.AsyncIterator[httpx.Response]:
base_url = self.get_base_url(base_url)
@@ -791,7 +875,9 @@ async def stream(
if (request_files is None or len(request_files) == 0) and force_multipart:
request_files = FORCE_MULTIPART
- json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+ json_body, data_body = get_request_body(
+ json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body
+ )
data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart)
@@ -828,6 +914,9 @@ async def stream(
}
)
)
+ _request_headers = drop_content_type_without_body(
+ _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body
+ )
if self.logger.is_debug():
self.logger.debug(
diff --git a/src/phenoml/core/http_response.py b/src/phenoml/core/http_response.py
index 00bb109..9aa1e18 100644
--- a/src/phenoml/core/http_response.py
+++ b/src/phenoml/core/http_response.py
@@ -24,6 +24,10 @@ def headers(self) -> Dict[str, str]:
def status_code(self) -> int:
return self._response.status_code
+ @property
+ def response(self) -> httpx.Response:
+ return self._response
+
class HttpResponse(Generic[T], BaseHttpResponse):
"""HTTP response wrapper that exposes response headers and data."""
diff --git a/src/phenoml/core/jsonable_encoder.py b/src/phenoml/core/jsonable_encoder.py
index 5b0902e..f638cc9 100644
--- a/src/phenoml/core/jsonable_encoder.py
+++ b/src/phenoml/core/jsonable_encoder.py
@@ -15,6 +15,7 @@
from pathlib import PurePath
from types import GeneratorType
from typing import Any, Callable, Dict, List, Optional, Set, Union
+from urllib.parse import quote
import pydantic
from .datetime_utils import serialize_datetime
@@ -118,3 +119,15 @@ def encode_path_param(obj: Any) -> str:
if isinstance(obj, bool):
return "true" if obj else "false"
return str(jsonable_encoder(obj))
+
+
+def quote_path_param(obj: Any) -> str:
+ """Encode a value for use in a URL path segment, percent-encoding it.
+
+ Same as encode_path_param, except the result is percent-encoded so
+ that a value containing "/" or ".." cannot change which endpoint
+ the request resolves to.
+ """
+ if isinstance(obj, bool):
+ return "true" if obj else "false"
+ return quote(str(jsonable_encoder(obj)), safe="")
diff --git a/src/phenoml/core/oauth_token_provider.py b/src/phenoml/core/oauth_token_provider.py
index 0360d17..370bb86 100644
--- a/src/phenoml/core/oauth_token_provider.py
+++ b/src/phenoml/core/oauth_token_provider.py
@@ -31,7 +31,9 @@ def get_token(self) -> str:
return self._refresh()
def _refresh(self) -> str:
- token_response = self._auth_client.get_token(client_id=self._client_id, client_secret=self._client_secret)
+ token_response = self._auth_client.get_token(
+ client_id=self._client_id, client_secret=self._client_secret, grant_type="client_credentials"
+ )
self._access_token = token_response.access_token
self._expires_at = self._get_expires_at(
expires_in_seconds=token_response.expires_in, buffer_in_minutes=self.BUFFER_IN_MINUTES
@@ -62,7 +64,9 @@ async def get_token(self) -> str:
return await self._refresh()
async def _refresh(self) -> str:
- token_response = await self._auth_client.get_token(client_id=self._client_id, client_secret=self._client_secret)
+ token_response = await self._auth_client.get_token(
+ client_id=self._client_id, client_secret=self._client_secret, grant_type="client_credentials"
+ )
self._access_token = token_response.access_token
self._expires_at = self._get_expires_at(
expires_in_seconds=token_response.expires_in, buffer_in_minutes=self.BUFFER_IN_MINUTES
diff --git a/src/phenoml/core/pydantic_utilities.py b/src/phenoml/core/pydantic_utilities.py
index 6587f5e..70816b9 100644
--- a/src/phenoml/core/pydantic_utilities.py
+++ b/src/phenoml/core/pydantic_utilities.py
@@ -5,6 +5,7 @@
import inspect
import json
import logging
+import weakref
from collections import defaultdict
from dataclasses import asdict
from typing import (
@@ -184,6 +185,58 @@ def _get_type_adapter(type_: Type[Any]) -> Any:
return adapter
+_field_alias_cache: "weakref.WeakKeyDictionary[type, Tuple[Dict[str, str], Tuple[str, ...]]]" = (
+ weakref.WeakKeyDictionary()
+)
+
+
+def _get_field_aliases(model: type) -> Tuple[Dict[str, str], Tuple[str, ...]]:
+ """
+ Map of field name to Pydantic alias for the fields whose alias differs from their name, together with the
+ keys that are ambiguous (an alias of one field and the name of another). Computed once per model class.
+ """
+ cached = _field_alias_cache.get(model)
+ if cached is None:
+ fields: Mapping[str, Any] = (
+ getattr(model, "model_fields", {}) if IS_PYDANTIC_V2 else getattr(model, "__fields__", {})
+ )
+ name_to_alias: Dict[str, str] = {}
+ for name, field in fields.items():
+ alias = getattr(field, "alias", None)
+ if alias is not None and alias != name:
+ name_to_alias[name] = alias
+ cached = (name_to_alias, tuple(alias for alias in name_to_alias.values() if alias in fields))
+ _field_alias_cache[model] = cached
+ return cached
+
+
+def _coerce_keys_to_aliases(model: type, data: Any) -> Any:
+ """
+ Accept Python field names in input by rewriting them to their Pydantic aliases,
+ while avoiding silent collisions when a key could refer to multiple fields.
+ """
+ if not isinstance(data, Mapping):
+ return data
+
+ name_to_alias, ambiguous_keys = _get_field_aliases(model)
+ for key in ambiguous_keys:
+ if key in data and name_to_alias.get(key, key) not in data:
+ raise ValueError(
+ f"Ambiguous input key '{key}': it is both a field name and an alias. "
+ "Provide the explicit alias key to disambiguate."
+ )
+
+ if not name_to_alias or not any(name in data for name in name_to_alias):
+ return data if isinstance(data, dict) else dict(data)
+
+ rewritten: Dict[str, Any] = dict(data)
+ for name, alias in name_to_alias.items():
+ if name in data and alias not in rewritten:
+ rewritten[alias] = rewritten.pop(name)
+
+ return rewritten
+
+
def parse_obj_as(type_: Type[T], object_: Any) -> T:
# convert_and_respect_annotation_metadata is required for TypedDict aliasing.
#
@@ -193,20 +246,7 @@ def parse_obj_as(type_: Type[T], object_: Any) -> T:
# - If the model encodes aliasing only via FieldMetadata annotations, then we MUST pre-dealias because Pydantic
# will not recognize those aliases during validation.
if inspect.isclass(type_) and issubclass(type_, pydantic.BaseModel):
- has_pydantic_aliases = False
- if IS_PYDANTIC_V2:
- for field_name, field_info in getattr(type_, "model_fields", {}).items(): # type: ignore[attr-defined]
- alias = getattr(field_info, "alias", None)
- if alias is not None and alias != field_name:
- has_pydantic_aliases = True
- break
- else:
- for field in getattr(type_, "__fields__", {}).values():
- alias = getattr(field, "alias", None)
- name = getattr(field, "name", None)
- if alias is not None and name is not None and alias != name:
- has_pydantic_aliases = True
- break
+ has_pydantic_aliases = bool(_get_field_aliases(type_)[0])
dealiased_object = (
object_
@@ -239,39 +279,7 @@ class UniversalBaseModel(pydantic.BaseModel):
@pydantic.model_validator(mode="before") # type: ignore[attr-defined]
@classmethod
def _coerce_field_names_to_aliases(cls, data: Any) -> Any:
- """
- Accept Python field names in input by rewriting them to their Pydantic aliases,
- while avoiding silent collisions when a key could refer to multiple fields.
- """
- if not isinstance(data, Mapping):
- return data
-
- fields = getattr(cls, "model_fields", {}) # type: ignore[attr-defined]
- name_to_alias: Dict[str, str] = {}
- alias_to_name: Dict[str, str] = {}
-
- for name, field_info in fields.items():
- alias = getattr(field_info, "alias", None) or name
- name_to_alias[name] = alias
- if alias != name:
- alias_to_name[alias] = name
-
- # Detect ambiguous keys: a key that is an alias for one field and a name for another.
- ambiguous_keys = set(alias_to_name.keys()).intersection(set(name_to_alias.keys()))
- for key in ambiguous_keys:
- if key in data and name_to_alias[key] not in data:
- raise ValueError(
- f"Ambiguous input key '{key}': it is both a field name and an alias. "
- "Provide the explicit alias key to disambiguate."
- )
-
- original_keys = set(data.keys())
- rewritten: Dict[str, Any] = dict(data)
- for name, alias in name_to_alias.items():
- if alias != name and name in original_keys and alias not in rewritten:
- rewritten[alias] = rewritten.pop(name)
-
- return rewritten
+ return _coerce_keys_to_aliases(cls, data)
@pydantic.model_serializer(mode="plain", when_used="json") # type: ignore[attr-defined]
def serialize_model(self) -> Any: # type: ignore[name-defined]
@@ -287,37 +295,7 @@ class Config:
@pydantic.root_validator(pre=True)
def _coerce_field_names_to_aliases(cls, values: Any) -> Any:
- """
- Pydantic v1 equivalent of _coerce_field_names_to_aliases.
- """
- if not isinstance(values, Mapping):
- return values
-
- fields = getattr(cls, "__fields__", {})
- name_to_alias: Dict[str, str] = {}
- alias_to_name: Dict[str, str] = {}
-
- for name, field in fields.items():
- alias = getattr(field, "alias", None) or name
- name_to_alias[name] = alias
- if alias != name:
- alias_to_name[alias] = name
-
- ambiguous_keys = set(alias_to_name.keys()).intersection(set(name_to_alias.keys()))
- for key in ambiguous_keys:
- if key in values and name_to_alias[key] not in values:
- raise ValueError(
- f"Ambiguous input key '{key}': it is both a field name and an alias. "
- "Provide the explicit alias key to disambiguate."
- )
-
- original_keys = set(values.keys())
- rewritten: Dict[str, Any] = dict(values)
- for name, alias in name_to_alias.items():
- if alias != name and name in original_keys and alias not in rewritten:
- rewritten[alias] = rewritten.pop(name)
-
- return rewritten
+ return _coerce_keys_to_aliases(cls, values) # type: ignore[arg-type]
@classmethod
def model_construct(cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any) -> "Model":
diff --git a/src/phenoml/fhir2omop/__init__.py b/src/phenoml/fhir2omop/__init__.py
index 8906ff1..79dcad2 100644
--- a/src/phenoml/fhir2omop/__init__.py
+++ b/src/phenoml/fhir2omop/__init__.py
@@ -15,6 +15,7 @@
DrugExposureRow,
LocationRow,
MappingEntry,
+ MappingEntryMappingStatus,
MeasurementRow,
ObservationPeriodRow,
ObservationRow,
@@ -37,6 +38,7 @@
"InternalServerError": ".errors",
"LocationRow": ".types",
"MappingEntry": ".types",
+ "MappingEntryMappingStatus": ".types",
"MeasurementRow": ".types",
"ObservationPeriodRow": ".types",
"ObservationRow": ".types",
@@ -83,6 +85,7 @@ def __dir__():
"InternalServerError",
"LocationRow",
"MappingEntry",
+ "MappingEntryMappingStatus",
"MeasurementRow",
"ObservationPeriodRow",
"ObservationRow",
diff --git a/src/phenoml/fhir2omop/client.py b/src/phenoml/fhir2omop/client.py
index ac8e881..ec01349 100644
--- a/src/phenoml/fhir2omop/client.py
+++ b/src/phenoml/fhir2omop/client.py
@@ -30,52 +30,81 @@ def create(
self, *, fhir_resources: typing.Dict[str, typing.Any], request_options: typing.Optional[RequestOptions] = None
) -> CreateOmopResponse:
"""
- Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows
- (person, visit_occurrence, condition_occurrence, drug_exposure,
- procedure_occurrence, measurement, observation).
-
- Resource support is intentionally limited to the OMOP tables returned by
- this endpoint:
- - `Patient` -> `person`
+ Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows,
+ grouped by destination table in `tables`.
+
+ Current resource coverage:
+ - `Patient` -> `person`; `deceased[x]` can also produce `death`, and the
+ first address can produce `location`
+ - `observation_period` -> one derived row per person with dated visit,
+ clinical, or death rows, spanning those dates
+ - `Location` -> `location` and `care_site`
+ - `Organization` -> `care_site`; its first address can produce `location`
+ - `HealthcareService` -> `care_site`
+ - `Practitioner` and `PractitionerRole` -> `provider`
- `Encounter` -> `visit_occurrence`
- `Condition` -> `condition_occurrence`
- `Procedure` -> `procedure_occurrence`
- `MedicationRequest`, `MedicationStatement`, and
`MedicationAdministration` -> `drug_exposure`
- `Immunization` -> `drug_exposure`
- - `Observation` with a numeric `valueQuantity`, `valueInteger`, or
- numeric-looking `valueString` (for example `"<2"`) -> `measurement`
- - non-numeric `Observation` -> `observation`
+ - `Observation` -> `measurement` or `observation`. For coded
+ Observations, the resolved OMOP concept domain selects the table; value
+ form only breaks ties. For text-only Observations, numeric values route
+ to `measurement` and nonnumeric values to `observation`.
- `AllergyIntolerance` -> `observation`
- `Medication` is supported only as reference data for medication
- resources; it is not emitted as its own row because OMOP CDM has no
- Medication table. Other reference/admin resources such as `Practitioner`,
- `Organization`, `Location`, `Coverage`, and `Claim`, and clinical
- workflow/document resources such as `DiagnosticReport`, `ServiceRequest`,
- `CarePlan`, `DocumentReference`, `Composition`, `Specimen`, and
- `DeviceUseStatement`, are currently accepted in a Bundle but are not
- shaped into OMOP rows. Unsupported resource types are ignored rather than
- listed under `dropped`; `dropped` is reserved for supported resource types
- that were missing the subject/patient, code, or medication reference data
- needed to produce a valid row.
-
- Each resource's primary clinical coding is resolved to a standard OMOP
- `concept_id`. Alongside the OMOP rows grouped by table (`tables`), the
- response carries `mappings` (how each source coding resolved, linked back
- to the row it produced), `dropped` (resources that could not be shaped
- into a row), `vocab_version` (the OMOP vocabulary release codes were
- resolved against), and a small `summary` of the resolution outcomes.
+ `Medication` is reference data for medication resources; it does not
+ create its own row because OMOP CDM has no Medication table. Administrative
+ linkages (provider, care site, and location) are best-effort and limited to
+ references supplied in the request. Their supporting concepts, including
+ provider specialty, country, and place of service, are not mapped.
+
+ `DiagnosticReport`, `ServiceRequest`, `CarePlan`, `DocumentReference`,
+ `Composition`, `Specimen`, `DeviceUseStatement`, `Coverage`, `Claim`, and
+ other unsupported resource types are accepted in a Bundle but ignored: they
+ create no row and no `dropped` entry. `dropped` is reserved for supported
+ row-producing resources that could not be shaped because the subject/patient,
+ clinical code/text, or medication data was not usable. A single-Patient
+ Bundle can attribute a supported clinical resource with a missing or
+ unresolvable subject to that sole person; in a multi-Patient Bundle, that
+ resource is dropped instead.
+
+ Coded Observation routing is selected from the resolved OMOP concept
+ domain. Numeric and nonnumeric `value[x]` forms establish the preferred
+ target only when the code is valid for both tables. A text-only
+ Observation has no resolver target, so numeric values route to
+ `measurement` and nonnumeric values to `observation`. Numeric values
+ populate `value_as_number` in the selected row; nonnumeric values
+ populate `value_as_string` for an `observation` or `value_source_value`
+ for a `measurement`. `valueCodeableConcept` remains source text and does
+ not populate `value_as_concept_id`; other unsupported `value[x]` forms
+ and Observation components do not populate separate converted values. A
+ numeric comparator (`<`, `<=`, `>`, `>=`) is represented only by a
+ measurement's `operator_concept_id`; units remain source text and have
+ `unit_concept_id` of `0`.
+
+ A single standard OMOP `concept_id` is selected for each clinical row
+ after considering all of the resource's supplied codings. Alongside the
+ OMOP rows grouped by table (`tables`), the response carries `mappings`
+ (an entry for every source coding, linked back to the row it produced),
+ `dropped` (resources that could not be shaped into a row),
+ `vocab_version` (the OMOP vocabulary release codes were resolved
+ against), and a small `summary` of the resolution outcomes.
A `concept_id` of `0` is reported, not omitted (OMOP "no matching
concept" semantics): it covers both a coding with no standard match
(`UNMAPPED`) and an unverified suggestion for a text-only resource
- (`UNCHECKED`). Only the primary clinical coding is resolved, so
- `gender`/`race`/`ethnicity`/`visit`/`value`/`unit` `concept_id`s are
- always `0`; the one populated non-resolved concept is measurement
+ (`UNCHECKED`). Demographic, visit, categorical-value, and unit concept
+ fields currently remain `0`; the one populated non-resolved concept is
+ measurement
`operator_concept_id`, set from a value comparator (`<`, `<=`, `>`, `>=`)
- rather than the resolver. Each `*_source_value` carries the verbatim FHIR
- coding (`system#code`), and `*_type_concept_id` is set to `32817` (EHR).
+ rather than terminology resolution. Clinical `*_source_value` fields
+ preserve the selected FHIR coding (`system#code`, or `code` when no
+ system is supplied), falling back to source text for text-only resources.
+ Other `*_source_value` fields preserve row-specific raw source values,
+ such as resource identifiers, names, units, or status codes, and
+ `*_type_concept_id` is set to `32817` (EHR).
Medication codes are resolved whether they appear inline
(`medicationCodeableConcept`) or via a `medicationReference` to a contained,
@@ -83,19 +112,30 @@ def create(
Resources that cannot be shaped into a row — a medication with no usable
code, resolvable reference, or display, or any clinical resource whose
subject/patient reference cannot be tied to a person — are reported under
- `dropped` rather than emitted as blank rows. The
- bundle must contain at least one Patient resource.
+ `dropped` rather than emitted as blank rows. The Bundle must contain at
+ least one Patient resource.
+
+ All row IDs start at `1` for each request and are not stable or global.
+ For clinical conversion rows whose resource supplies an `id`, `mappings`
+ associates each row with that source FHIR resource ID. A `person` row
+ retains the Patient ID or its first identifier value in
+ `person_source_value`, when present; other reference and derived rows do
+ not uniformly carry a FHIR resource ID. Input resources without those
+ source identifiers cannot be correlated across responses from the
+ returned rows alone. Consumers combining responses need to establish
+ their own stable keys and remap every primary and foreign key together.
Parameters
----------
fhir_resources : typing.Dict[str, typing.Any]
FHIR resources (single resource or Bundle). Must contain at least one
Patient resource. Supported row-producing resources are Patient,
- Encounter, Condition, Procedure, MedicationRequest,
+ Location, Organization, HealthcareService, Practitioner,
+ PractitionerRole, Encounter, Condition, Procedure, MedicationRequest,
MedicationStatement, MedicationAdministration, Immunization,
Observation, and AllergyIntolerance. Standalone Medication resources
are consumed by medication references rather than mapped to their own
- table. Other resource types are accepted but ignored.
+ table. Unsupported resource types are accepted in a Bundle but ignored.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -195,52 +235,81 @@ async def create(
self, *, fhir_resources: typing.Dict[str, typing.Any], request_options: typing.Optional[RequestOptions] = None
) -> CreateOmopResponse:
"""
- Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows
- (person, visit_occurrence, condition_occurrence, drug_exposure,
- procedure_occurrence, measurement, observation).
-
- Resource support is intentionally limited to the OMOP tables returned by
- this endpoint:
- - `Patient` -> `person`
+ Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows,
+ grouped by destination table in `tables`.
+
+ Current resource coverage:
+ - `Patient` -> `person`; `deceased[x]` can also produce `death`, and the
+ first address can produce `location`
+ - `observation_period` -> one derived row per person with dated visit,
+ clinical, or death rows, spanning those dates
+ - `Location` -> `location` and `care_site`
+ - `Organization` -> `care_site`; its first address can produce `location`
+ - `HealthcareService` -> `care_site`
+ - `Practitioner` and `PractitionerRole` -> `provider`
- `Encounter` -> `visit_occurrence`
- `Condition` -> `condition_occurrence`
- `Procedure` -> `procedure_occurrence`
- `MedicationRequest`, `MedicationStatement`, and
`MedicationAdministration` -> `drug_exposure`
- `Immunization` -> `drug_exposure`
- - `Observation` with a numeric `valueQuantity`, `valueInteger`, or
- numeric-looking `valueString` (for example `"<2"`) -> `measurement`
- - non-numeric `Observation` -> `observation`
+ - `Observation` -> `measurement` or `observation`. For coded
+ Observations, the resolved OMOP concept domain selects the table; value
+ form only breaks ties. For text-only Observations, numeric values route
+ to `measurement` and nonnumeric values to `observation`.
- `AllergyIntolerance` -> `observation`
- `Medication` is supported only as reference data for medication
- resources; it is not emitted as its own row because OMOP CDM has no
- Medication table. Other reference/admin resources such as `Practitioner`,
- `Organization`, `Location`, `Coverage`, and `Claim`, and clinical
- workflow/document resources such as `DiagnosticReport`, `ServiceRequest`,
- `CarePlan`, `DocumentReference`, `Composition`, `Specimen`, and
- `DeviceUseStatement`, are currently accepted in a Bundle but are not
- shaped into OMOP rows. Unsupported resource types are ignored rather than
- listed under `dropped`; `dropped` is reserved for supported resource types
- that were missing the subject/patient, code, or medication reference data
- needed to produce a valid row.
-
- Each resource's primary clinical coding is resolved to a standard OMOP
- `concept_id`. Alongside the OMOP rows grouped by table (`tables`), the
- response carries `mappings` (how each source coding resolved, linked back
- to the row it produced), `dropped` (resources that could not be shaped
- into a row), `vocab_version` (the OMOP vocabulary release codes were
- resolved against), and a small `summary` of the resolution outcomes.
+ `Medication` is reference data for medication resources; it does not
+ create its own row because OMOP CDM has no Medication table. Administrative
+ linkages (provider, care site, and location) are best-effort and limited to
+ references supplied in the request. Their supporting concepts, including
+ provider specialty, country, and place of service, are not mapped.
+
+ `DiagnosticReport`, `ServiceRequest`, `CarePlan`, `DocumentReference`,
+ `Composition`, `Specimen`, `DeviceUseStatement`, `Coverage`, `Claim`, and
+ other unsupported resource types are accepted in a Bundle but ignored: they
+ create no row and no `dropped` entry. `dropped` is reserved for supported
+ row-producing resources that could not be shaped because the subject/patient,
+ clinical code/text, or medication data was not usable. A single-Patient
+ Bundle can attribute a supported clinical resource with a missing or
+ unresolvable subject to that sole person; in a multi-Patient Bundle, that
+ resource is dropped instead.
+
+ Coded Observation routing is selected from the resolved OMOP concept
+ domain. Numeric and nonnumeric `value[x]` forms establish the preferred
+ target only when the code is valid for both tables. A text-only
+ Observation has no resolver target, so numeric values route to
+ `measurement` and nonnumeric values to `observation`. Numeric values
+ populate `value_as_number` in the selected row; nonnumeric values
+ populate `value_as_string` for an `observation` or `value_source_value`
+ for a `measurement`. `valueCodeableConcept` remains source text and does
+ not populate `value_as_concept_id`; other unsupported `value[x]` forms
+ and Observation components do not populate separate converted values. A
+ numeric comparator (`<`, `<=`, `>`, `>=`) is represented only by a
+ measurement's `operator_concept_id`; units remain source text and have
+ `unit_concept_id` of `0`.
+
+ A single standard OMOP `concept_id` is selected for each clinical row
+ after considering all of the resource's supplied codings. Alongside the
+ OMOP rows grouped by table (`tables`), the response carries `mappings`
+ (an entry for every source coding, linked back to the row it produced),
+ `dropped` (resources that could not be shaped into a row),
+ `vocab_version` (the OMOP vocabulary release codes were resolved
+ against), and a small `summary` of the resolution outcomes.
A `concept_id` of `0` is reported, not omitted (OMOP "no matching
concept" semantics): it covers both a coding with no standard match
(`UNMAPPED`) and an unverified suggestion for a text-only resource
- (`UNCHECKED`). Only the primary clinical coding is resolved, so
- `gender`/`race`/`ethnicity`/`visit`/`value`/`unit` `concept_id`s are
- always `0`; the one populated non-resolved concept is measurement
+ (`UNCHECKED`). Demographic, visit, categorical-value, and unit concept
+ fields currently remain `0`; the one populated non-resolved concept is
+ measurement
`operator_concept_id`, set from a value comparator (`<`, `<=`, `>`, `>=`)
- rather than the resolver. Each `*_source_value` carries the verbatim FHIR
- coding (`system#code`), and `*_type_concept_id` is set to `32817` (EHR).
+ rather than terminology resolution. Clinical `*_source_value` fields
+ preserve the selected FHIR coding (`system#code`, or `code` when no
+ system is supplied), falling back to source text for text-only resources.
+ Other `*_source_value` fields preserve row-specific raw source values,
+ such as resource identifiers, names, units, or status codes, and
+ `*_type_concept_id` is set to `32817` (EHR).
Medication codes are resolved whether they appear inline
(`medicationCodeableConcept`) or via a `medicationReference` to a contained,
@@ -248,19 +317,30 @@ async def create(
Resources that cannot be shaped into a row — a medication with no usable
code, resolvable reference, or display, or any clinical resource whose
subject/patient reference cannot be tied to a person — are reported under
- `dropped` rather than emitted as blank rows. The
- bundle must contain at least one Patient resource.
+ `dropped` rather than emitted as blank rows. The Bundle must contain at
+ least one Patient resource.
+
+ All row IDs start at `1` for each request and are not stable or global.
+ For clinical conversion rows whose resource supplies an `id`, `mappings`
+ associates each row with that source FHIR resource ID. A `person` row
+ retains the Patient ID or its first identifier value in
+ `person_source_value`, when present; other reference and derived rows do
+ not uniformly carry a FHIR resource ID. Input resources without those
+ source identifiers cannot be correlated across responses from the
+ returned rows alone. Consumers combining responses need to establish
+ their own stable keys and remap every primary and foreign key together.
Parameters
----------
fhir_resources : typing.Dict[str, typing.Any]
FHIR resources (single resource or Bundle). Must contain at least one
Patient resource. Supported row-producing resources are Patient,
- Encounter, Condition, Procedure, MedicationRequest,
+ Location, Organization, HealthcareService, Practitioner,
+ PractitionerRole, Encounter, Condition, Procedure, MedicationRequest,
MedicationStatement, MedicationAdministration, Immunization,
Observation, and AllergyIntolerance. Standalone Medication resources
are consumed by medication references rather than mapped to their own
- table. Other resource types are accepted but ignored.
+ table. Unsupported resource types are accepted in a Bundle but ignored.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
diff --git a/src/phenoml/fhir2omop/raw_client.py b/src/phenoml/fhir2omop/raw_client.py
index 51990ac..adb5a99 100644
--- a/src/phenoml/fhir2omop/raw_client.py
+++ b/src/phenoml/fhir2omop/raw_client.py
@@ -28,52 +28,81 @@ def create(
self, *, fhir_resources: typing.Dict[str, typing.Any], request_options: typing.Optional[RequestOptions] = None
) -> HttpResponse[CreateOmopResponse]:
"""
- Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows
- (person, visit_occurrence, condition_occurrence, drug_exposure,
- procedure_occurrence, measurement, observation).
+ Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows,
+ grouped by destination table in `tables`.
- Resource support is intentionally limited to the OMOP tables returned by
- this endpoint:
- - `Patient` -> `person`
+ Current resource coverage:
+ - `Patient` -> `person`; `deceased[x]` can also produce `death`, and the
+ first address can produce `location`
+ - `observation_period` -> one derived row per person with dated visit,
+ clinical, or death rows, spanning those dates
+ - `Location` -> `location` and `care_site`
+ - `Organization` -> `care_site`; its first address can produce `location`
+ - `HealthcareService` -> `care_site`
+ - `Practitioner` and `PractitionerRole` -> `provider`
- `Encounter` -> `visit_occurrence`
- `Condition` -> `condition_occurrence`
- `Procedure` -> `procedure_occurrence`
- `MedicationRequest`, `MedicationStatement`, and
`MedicationAdministration` -> `drug_exposure`
- `Immunization` -> `drug_exposure`
- - `Observation` with a numeric `valueQuantity`, `valueInteger`, or
- numeric-looking `valueString` (for example `"<2"`) -> `measurement`
- - non-numeric `Observation` -> `observation`
+ - `Observation` -> `measurement` or `observation`. For coded
+ Observations, the resolved OMOP concept domain selects the table; value
+ form only breaks ties. For text-only Observations, numeric values route
+ to `measurement` and nonnumeric values to `observation`.
- `AllergyIntolerance` -> `observation`
- `Medication` is supported only as reference data for medication
- resources; it is not emitted as its own row because OMOP CDM has no
- Medication table. Other reference/admin resources such as `Practitioner`,
- `Organization`, `Location`, `Coverage`, and `Claim`, and clinical
- workflow/document resources such as `DiagnosticReport`, `ServiceRequest`,
- `CarePlan`, `DocumentReference`, `Composition`, `Specimen`, and
- `DeviceUseStatement`, are currently accepted in a Bundle but are not
- shaped into OMOP rows. Unsupported resource types are ignored rather than
- listed under `dropped`; `dropped` is reserved for supported resource types
- that were missing the subject/patient, code, or medication reference data
- needed to produce a valid row.
+ `Medication` is reference data for medication resources; it does not
+ create its own row because OMOP CDM has no Medication table. Administrative
+ linkages (provider, care site, and location) are best-effort and limited to
+ references supplied in the request. Their supporting concepts, including
+ provider specialty, country, and place of service, are not mapped.
- Each resource's primary clinical coding is resolved to a standard OMOP
- `concept_id`. Alongside the OMOP rows grouped by table (`tables`), the
- response carries `mappings` (how each source coding resolved, linked back
- to the row it produced), `dropped` (resources that could not be shaped
- into a row), `vocab_version` (the OMOP vocabulary release codes were
- resolved against), and a small `summary` of the resolution outcomes.
+ `DiagnosticReport`, `ServiceRequest`, `CarePlan`, `DocumentReference`,
+ `Composition`, `Specimen`, `DeviceUseStatement`, `Coverage`, `Claim`, and
+ other unsupported resource types are accepted in a Bundle but ignored: they
+ create no row and no `dropped` entry. `dropped` is reserved for supported
+ row-producing resources that could not be shaped because the subject/patient,
+ clinical code/text, or medication data was not usable. A single-Patient
+ Bundle can attribute a supported clinical resource with a missing or
+ unresolvable subject to that sole person; in a multi-Patient Bundle, that
+ resource is dropped instead.
+
+ Coded Observation routing is selected from the resolved OMOP concept
+ domain. Numeric and nonnumeric `value[x]` forms establish the preferred
+ target only when the code is valid for both tables. A text-only
+ Observation has no resolver target, so numeric values route to
+ `measurement` and nonnumeric values to `observation`. Numeric values
+ populate `value_as_number` in the selected row; nonnumeric values
+ populate `value_as_string` for an `observation` or `value_source_value`
+ for a `measurement`. `valueCodeableConcept` remains source text and does
+ not populate `value_as_concept_id`; other unsupported `value[x]` forms
+ and Observation components do not populate separate converted values. A
+ numeric comparator (`<`, `<=`, `>`, `>=`) is represented only by a
+ measurement's `operator_concept_id`; units remain source text and have
+ `unit_concept_id` of `0`.
+
+ A single standard OMOP `concept_id` is selected for each clinical row
+ after considering all of the resource's supplied codings. Alongside the
+ OMOP rows grouped by table (`tables`), the response carries `mappings`
+ (an entry for every source coding, linked back to the row it produced),
+ `dropped` (resources that could not be shaped into a row),
+ `vocab_version` (the OMOP vocabulary release codes were resolved
+ against), and a small `summary` of the resolution outcomes.
A `concept_id` of `0` is reported, not omitted (OMOP "no matching
concept" semantics): it covers both a coding with no standard match
(`UNMAPPED`) and an unverified suggestion for a text-only resource
- (`UNCHECKED`). Only the primary clinical coding is resolved, so
- `gender`/`race`/`ethnicity`/`visit`/`value`/`unit` `concept_id`s are
- always `0`; the one populated non-resolved concept is measurement
+ (`UNCHECKED`). Demographic, visit, categorical-value, and unit concept
+ fields currently remain `0`; the one populated non-resolved concept is
+ measurement
`operator_concept_id`, set from a value comparator (`<`, `<=`, `>`, `>=`)
- rather than the resolver. Each `*_source_value` carries the verbatim FHIR
- coding (`system#code`), and `*_type_concept_id` is set to `32817` (EHR).
+ rather than terminology resolution. Clinical `*_source_value` fields
+ preserve the selected FHIR coding (`system#code`, or `code` when no
+ system is supplied), falling back to source text for text-only resources.
+ Other `*_source_value` fields preserve row-specific raw source values,
+ such as resource identifiers, names, units, or status codes, and
+ `*_type_concept_id` is set to `32817` (EHR).
Medication codes are resolved whether they appear inline
(`medicationCodeableConcept`) or via a `medicationReference` to a contained,
@@ -81,19 +110,30 @@ def create(
Resources that cannot be shaped into a row — a medication with no usable
code, resolvable reference, or display, or any clinical resource whose
subject/patient reference cannot be tied to a person — are reported under
- `dropped` rather than emitted as blank rows. The
- bundle must contain at least one Patient resource.
+ `dropped` rather than emitted as blank rows. The Bundle must contain at
+ least one Patient resource.
+
+ All row IDs start at `1` for each request and are not stable or global.
+ For clinical conversion rows whose resource supplies an `id`, `mappings`
+ associates each row with that source FHIR resource ID. A `person` row
+ retains the Patient ID or its first identifier value in
+ `person_source_value`, when present; other reference and derived rows do
+ not uniformly carry a FHIR resource ID. Input resources without those
+ source identifiers cannot be correlated across responses from the
+ returned rows alone. Consumers combining responses need to establish
+ their own stable keys and remap every primary and foreign key together.
Parameters
----------
fhir_resources : typing.Dict[str, typing.Any]
FHIR resources (single resource or Bundle). Must contain at least one
Patient resource. Supported row-producing resources are Patient,
- Encounter, Condition, Procedure, MedicationRequest,
+ Location, Organization, HealthcareService, Practitioner,
+ PractitionerRole, Encounter, Condition, Procedure, MedicationRequest,
MedicationStatement, MedicationAdministration, Immunization,
Observation, and AllergyIntolerance. Standalone Medication resources
are consumed by medication references rather than mapped to their own
- table. Other resource types are accepted but ignored.
+ table. Unsupported resource types are accepted in a Bundle but ignored.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -187,52 +227,81 @@ async def create(
self, *, fhir_resources: typing.Dict[str, typing.Any], request_options: typing.Optional[RequestOptions] = None
) -> AsyncHttpResponse[CreateOmopResponse]:
"""
- Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows
- (person, visit_occurrence, condition_occurrence, drug_exposure,
- procedure_occurrence, measurement, observation).
+ Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows,
+ grouped by destination table in `tables`.
- Resource support is intentionally limited to the OMOP tables returned by
- this endpoint:
- - `Patient` -> `person`
+ Current resource coverage:
+ - `Patient` -> `person`; `deceased[x]` can also produce `death`, and the
+ first address can produce `location`
+ - `observation_period` -> one derived row per person with dated visit,
+ clinical, or death rows, spanning those dates
+ - `Location` -> `location` and `care_site`
+ - `Organization` -> `care_site`; its first address can produce `location`
+ - `HealthcareService` -> `care_site`
+ - `Practitioner` and `PractitionerRole` -> `provider`
- `Encounter` -> `visit_occurrence`
- `Condition` -> `condition_occurrence`
- `Procedure` -> `procedure_occurrence`
- `MedicationRequest`, `MedicationStatement`, and
`MedicationAdministration` -> `drug_exposure`
- `Immunization` -> `drug_exposure`
- - `Observation` with a numeric `valueQuantity`, `valueInteger`, or
- numeric-looking `valueString` (for example `"<2"`) -> `measurement`
- - non-numeric `Observation` -> `observation`
+ - `Observation` -> `measurement` or `observation`. For coded
+ Observations, the resolved OMOP concept domain selects the table; value
+ form only breaks ties. For text-only Observations, numeric values route
+ to `measurement` and nonnumeric values to `observation`.
- `AllergyIntolerance` -> `observation`
- `Medication` is supported only as reference data for medication
- resources; it is not emitted as its own row because OMOP CDM has no
- Medication table. Other reference/admin resources such as `Practitioner`,
- `Organization`, `Location`, `Coverage`, and `Claim`, and clinical
- workflow/document resources such as `DiagnosticReport`, `ServiceRequest`,
- `CarePlan`, `DocumentReference`, `Composition`, `Specimen`, and
- `DeviceUseStatement`, are currently accepted in a Bundle but are not
- shaped into OMOP rows. Unsupported resource types are ignored rather than
- listed under `dropped`; `dropped` is reserved for supported resource types
- that were missing the subject/patient, code, or medication reference data
- needed to produce a valid row.
+ `Medication` is reference data for medication resources; it does not
+ create its own row because OMOP CDM has no Medication table. Administrative
+ linkages (provider, care site, and location) are best-effort and limited to
+ references supplied in the request. Their supporting concepts, including
+ provider specialty, country, and place of service, are not mapped.
- Each resource's primary clinical coding is resolved to a standard OMOP
- `concept_id`. Alongside the OMOP rows grouped by table (`tables`), the
- response carries `mappings` (how each source coding resolved, linked back
- to the row it produced), `dropped` (resources that could not be shaped
- into a row), `vocab_version` (the OMOP vocabulary release codes were
- resolved against), and a small `summary` of the resolution outcomes.
+ `DiagnosticReport`, `ServiceRequest`, `CarePlan`, `DocumentReference`,
+ `Composition`, `Specimen`, `DeviceUseStatement`, `Coverage`, `Claim`, and
+ other unsupported resource types are accepted in a Bundle but ignored: they
+ create no row and no `dropped` entry. `dropped` is reserved for supported
+ row-producing resources that could not be shaped because the subject/patient,
+ clinical code/text, or medication data was not usable. A single-Patient
+ Bundle can attribute a supported clinical resource with a missing or
+ unresolvable subject to that sole person; in a multi-Patient Bundle, that
+ resource is dropped instead.
+
+ Coded Observation routing is selected from the resolved OMOP concept
+ domain. Numeric and nonnumeric `value[x]` forms establish the preferred
+ target only when the code is valid for both tables. A text-only
+ Observation has no resolver target, so numeric values route to
+ `measurement` and nonnumeric values to `observation`. Numeric values
+ populate `value_as_number` in the selected row; nonnumeric values
+ populate `value_as_string` for an `observation` or `value_source_value`
+ for a `measurement`. `valueCodeableConcept` remains source text and does
+ not populate `value_as_concept_id`; other unsupported `value[x]` forms
+ and Observation components do not populate separate converted values. A
+ numeric comparator (`<`, `<=`, `>`, `>=`) is represented only by a
+ measurement's `operator_concept_id`; units remain source text and have
+ `unit_concept_id` of `0`.
+
+ A single standard OMOP `concept_id` is selected for each clinical row
+ after considering all of the resource's supplied codings. Alongside the
+ OMOP rows grouped by table (`tables`), the response carries `mappings`
+ (an entry for every source coding, linked back to the row it produced),
+ `dropped` (resources that could not be shaped into a row),
+ `vocab_version` (the OMOP vocabulary release codes were resolved
+ against), and a small `summary` of the resolution outcomes.
A `concept_id` of `0` is reported, not omitted (OMOP "no matching
concept" semantics): it covers both a coding with no standard match
(`UNMAPPED`) and an unverified suggestion for a text-only resource
- (`UNCHECKED`). Only the primary clinical coding is resolved, so
- `gender`/`race`/`ethnicity`/`visit`/`value`/`unit` `concept_id`s are
- always `0`; the one populated non-resolved concept is measurement
+ (`UNCHECKED`). Demographic, visit, categorical-value, and unit concept
+ fields currently remain `0`; the one populated non-resolved concept is
+ measurement
`operator_concept_id`, set from a value comparator (`<`, `<=`, `>`, `>=`)
- rather than the resolver. Each `*_source_value` carries the verbatim FHIR
- coding (`system#code`), and `*_type_concept_id` is set to `32817` (EHR).
+ rather than terminology resolution. Clinical `*_source_value` fields
+ preserve the selected FHIR coding (`system#code`, or `code` when no
+ system is supplied), falling back to source text for text-only resources.
+ Other `*_source_value` fields preserve row-specific raw source values,
+ such as resource identifiers, names, units, or status codes, and
+ `*_type_concept_id` is set to `32817` (EHR).
Medication codes are resolved whether they appear inline
(`medicationCodeableConcept`) or via a `medicationReference` to a contained,
@@ -240,19 +309,30 @@ async def create(
Resources that cannot be shaped into a row — a medication with no usable
code, resolvable reference, or display, or any clinical resource whose
subject/patient reference cannot be tied to a person — are reported under
- `dropped` rather than emitted as blank rows. The
- bundle must contain at least one Patient resource.
+ `dropped` rather than emitted as blank rows. The Bundle must contain at
+ least one Patient resource.
+
+ All row IDs start at `1` for each request and are not stable or global.
+ For clinical conversion rows whose resource supplies an `id`, `mappings`
+ associates each row with that source FHIR resource ID. A `person` row
+ retains the Patient ID or its first identifier value in
+ `person_source_value`, when present; other reference and derived rows do
+ not uniformly carry a FHIR resource ID. Input resources without those
+ source identifiers cannot be correlated across responses from the
+ returned rows alone. Consumers combining responses need to establish
+ their own stable keys and remap every primary and foreign key together.
Parameters
----------
fhir_resources : typing.Dict[str, typing.Any]
FHIR resources (single resource or Bundle). Must contain at least one
Patient resource. Supported row-producing resources are Patient,
- Encounter, Condition, Procedure, MedicationRequest,
+ Location, Organization, HealthcareService, Practitioner,
+ PractitionerRole, Encounter, Condition, Procedure, MedicationRequest,
MedicationStatement, MedicationAdministration, Immunization,
Observation, and AllergyIntolerance. Standalone Medication resources
are consumed by medication references rather than mapped to their own
- table. Other resource types are accepted but ignored.
+ table. Unsupported resource types are accepted in a Bundle but ignored.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
diff --git a/src/phenoml/fhir2omop/types/__init__.py b/src/phenoml/fhir2omop/types/__init__.py
index 669a67a..d033dac 100644
--- a/src/phenoml/fhir2omop/types/__init__.py
+++ b/src/phenoml/fhir2omop/types/__init__.py
@@ -14,6 +14,7 @@
from .drug_exposure_row import DrugExposureRow
from .location_row import LocationRow
from .mapping_entry import MappingEntry
+ from .mapping_entry_mapping_status import MappingEntryMappingStatus
from .measurement_row import MeasurementRow
from .observation_period_row import ObservationPeriodRow
from .observation_row import ObservationRow
@@ -32,6 +33,7 @@
"DrugExposureRow": ".drug_exposure_row",
"LocationRow": ".location_row",
"MappingEntry": ".mapping_entry",
+ "MappingEntryMappingStatus": ".mapping_entry_mapping_status",
"MeasurementRow": ".measurement_row",
"ObservationPeriodRow": ".observation_period_row",
"ObservationRow": ".observation_row",
@@ -74,6 +76,7 @@ def __dir__():
"DrugExposureRow",
"LocationRow",
"MappingEntry",
+ "MappingEntryMappingStatus",
"MeasurementRow",
"ObservationPeriodRow",
"ObservationRow",
diff --git a/src/phenoml/fhir2omop/types/create_omop_response.py b/src/phenoml/fhir2omop/types/create_omop_response.py
index 122c5a9..8143365 100644
--- a/src/phenoml/fhir2omop/types/create_omop_response.py
+++ b/src/phenoml/fhir2omop/types/create_omop_response.py
@@ -29,9 +29,9 @@ class CreateOmopResponse(UniversalBaseModel):
vocab_version: typing.Optional[str] = pydantic.Field(default=None)
"""
- The OMOP vocabulary release the clinical codes were resolved against
- (e.g. "v20240229"), for reproducibility. Present when at least one
- coded concept was resolved.
+ The OMOP vocabulary release returned for coded concept resolution
+ (for example, "v20240229"), for reproducibility. It is generally
+ absent for requests containing only text-only resources.
"""
summary: typing.Optional[Summary] = None
diff --git a/src/phenoml/fhir2omop/types/mapping_entry.py b/src/phenoml/fhir2omop/types/mapping_entry.py
index e19b7e0..194bb75 100644
--- a/src/phenoml/fhir2omop/types/mapping_entry.py
+++ b/src/phenoml/fhir2omop/types/mapping_entry.py
@@ -4,6 +4,7 @@
import pydantic
from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .mapping_entry_mapping_status import MappingEntryMappingStatus
class MappingEntry(UniversalBaseModel):
@@ -34,7 +35,7 @@ class MappingEntry(UniversalBaseModel):
"""
target_name: typing.Optional[str] = None
- mapping_status: typing.Optional[str] = pydantic.Field(default=None)
+ mapping_status: typing.Optional[MappingEntryMappingStatus] = pydantic.Field(default=None)
"""
ALREADY_STANDARD (source coding is already a standard OMOP concept),
MAPPED (source coding was mapped to a standard concept), UNCHECKED (a
diff --git a/src/phenoml/fhir2omop/types/mapping_entry_mapping_status.py b/src/phenoml/fhir2omop/types/mapping_entry_mapping_status.py
new file mode 100644
index 0000000..655e0c4
--- /dev/null
+++ b/src/phenoml/fhir2omop/types/mapping_entry_mapping_status.py
@@ -0,0 +1,7 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+MappingEntryMappingStatus = typing.Union[
+ typing.Literal["ALREADY_STANDARD", "MAPPED", "UNCHECKED", "UNMAPPED"], typing.Any
+]
diff --git a/src/phenoml/fhir2omop/types/omop_tables.py b/src/phenoml/fhir2omop/types/omop_tables.py
index 10f0cba..df5a767 100644
--- a/src/phenoml/fhir2omop/types/omop_tables.py
+++ b/src/phenoml/fhir2omop/types/omop_tables.py
@@ -20,7 +20,8 @@
class OmopTables(UniversalBaseModel):
"""
- OMOP CDM v5.4 rows grouped by destination table.
+ OMOP CDM v5.4 rows grouped by destination table. IDs are sequential and
+ scoped to one response; they are not stable keys across requests.
"""
location: typing.Optional[typing.List[LocationRow]] = None
diff --git a/src/phenoml/fhir2omop/types/summary.py b/src/phenoml/fhir2omop/types/summary.py
index 6885bf8..3c95188 100644
--- a/src/phenoml/fhir2omop/types/summary.py
+++ b/src/phenoml/fhir2omop/types/summary.py
@@ -8,31 +8,30 @@
class Summary(UniversalBaseModel):
"""
- The request's data-quality headline: how the coded concepts split across
- resolution outcomes, and the share that was not already in a target
- standard vocabulary. Each coded resource is counted once (per resolved
- concept), even when it carried several codings — unlike `mappings`, which
- has one entry per coding.
+ The request's data-quality headline: how resolution outcomes split, and
+ the share that was not already in a target standard vocabulary. Each
+ row-producing clinical resource is counted once, even when it carried
+ several codings — unlike `mappings`, which has one entry per coding.
"""
codes_already_standard: typing.Optional[int] = pydantic.Field(default=None)
"""
- Coded concepts already a standard OMOP concept (ALREADY_STANDARD).
+ Resolution outcomes already a standard OMOP concept (ALREADY_STANDARD).
"""
codes_normalized: typing.Optional[int] = pydantic.Field(default=None)
"""
- Coded concepts mapped or suggested to a standard concept (MAPPED or UNCHECKED).
+ Resolution outcomes mapped or suggested to a standard concept (MAPPED or UNCHECKED).
"""
codes_unmapped: typing.Optional[int] = pydantic.Field(default=None)
"""
- Coded concepts with no standard concept found (UNMAPPED).
+ Resolution outcomes with no standard concept found (UNMAPPED).
"""
off_vocab_rate: typing.Optional[float] = pydantic.Field(default=None)
"""
- Share of coded concepts not already standard ((normalized + unmapped) / total).
+ Share of resolution outcomes not already standard ((normalized + unmapped) / total).
"""
if IS_PYDANTIC_V2:
diff --git a/src/phenoml/implementation_guides/__init__.py b/src/phenoml/implementation_guides/__init__.py
index 2d19295..8b08ecc 100644
--- a/src/phenoml/implementation_guides/__init__.py
+++ b/src/phenoml/implementation_guides/__init__.py
@@ -6,15 +6,31 @@
from importlib import import_module
if typing.TYPE_CHECKING:
- from .types import ImplementationGuideDetail, ImplementationGuideListResponse, ImplementationGuideSummary
- from .errors import BadRequestError, ForbiddenError, InternalServerError, NotFoundError, UnauthorizedError
+ from .types import (
+ FhirImplementationGuide,
+ ImplementationGuideDetail,
+ ImplementationGuideListResponse,
+ ImplementationGuideSummary,
+ ImplementationGuideVersionDetail,
+ )
+ from .errors import (
+ BadRequestError,
+ ConflictError,
+ ForbiddenError,
+ InternalServerError,
+ NotFoundError,
+ UnauthorizedError,
+ )
from . import implementation_guides
_dynamic_imports: typing.Dict[str, str] = {
"BadRequestError": ".errors",
+ "ConflictError": ".errors",
+ "FhirImplementationGuide": ".types",
"ForbiddenError": ".errors",
"ImplementationGuideDetail": ".types",
"ImplementationGuideListResponse": ".types",
"ImplementationGuideSummary": ".types",
+ "ImplementationGuideVersionDetail": ".types",
"InternalServerError": ".errors",
"NotFoundError": ".errors",
"UnauthorizedError": ".errors",
@@ -45,10 +61,13 @@ def __dir__():
__all__ = [
"BadRequestError",
+ "ConflictError",
+ "FhirImplementationGuide",
"ForbiddenError",
"ImplementationGuideDetail",
"ImplementationGuideListResponse",
"ImplementationGuideSummary",
+ "ImplementationGuideVersionDetail",
"InternalServerError",
"NotFoundError",
"UnauthorizedError",
diff --git a/src/phenoml/implementation_guides/errors/__init__.py b/src/phenoml/implementation_guides/errors/__init__.py
index 306a114..29aa057 100644
--- a/src/phenoml/implementation_guides/errors/__init__.py
+++ b/src/phenoml/implementation_guides/errors/__init__.py
@@ -7,12 +7,14 @@
if typing.TYPE_CHECKING:
from .bad_request_error import BadRequestError
+ from .conflict_error import ConflictError
from .forbidden_error import ForbiddenError
from .internal_server_error import InternalServerError
from .not_found_error import NotFoundError
from .unauthorized_error import UnauthorizedError
_dynamic_imports: typing.Dict[str, str] = {
"BadRequestError": ".bad_request_error",
+ "ConflictError": ".conflict_error",
"ForbiddenError": ".forbidden_error",
"InternalServerError": ".internal_server_error",
"NotFoundError": ".not_found_error",
@@ -41,4 +43,11 @@ def __dir__():
return sorted(lazy_attrs)
-__all__ = ["BadRequestError", "ForbiddenError", "InternalServerError", "NotFoundError", "UnauthorizedError"]
+__all__ = [
+ "BadRequestError",
+ "ConflictError",
+ "ForbiddenError",
+ "InternalServerError",
+ "NotFoundError",
+ "UnauthorizedError",
+]
diff --git a/src/phenoml/implementation_guides/errors/conflict_error.py b/src/phenoml/implementation_guides/errors/conflict_error.py
new file mode 100644
index 0000000..abe1a9f
--- /dev/null
+++ b/src/phenoml/implementation_guides/errors/conflict_error.py
@@ -0,0 +1,10 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from ...core.api_error import ApiError
+
+
+class ConflictError(ApiError):
+ def __init__(self, body: typing.Any, headers: typing.Optional[typing.Dict[str, str]] = None):
+ super().__init__(status_code=409, headers=headers, body=body)
diff --git a/src/phenoml/implementation_guides/implementation_guides/client.py b/src/phenoml/implementation_guides/implementation_guides/client.py
index 6cc3374..ba604eb 100644
--- a/src/phenoml/implementation_guides/implementation_guides/client.py
+++ b/src/phenoml/implementation_guides/implementation_guides/client.py
@@ -4,9 +4,11 @@
from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ...core.request_options import RequestOptions
+from ..types.fhir_implementation_guide import FhirImplementationGuide
from ..types.implementation_guide_detail import ImplementationGuideDetail
from ..types.implementation_guide_list_response import ImplementationGuideListResponse
from ..types.implementation_guide_summary import ImplementationGuideSummary
+from ..types.implementation_guide_version_detail import ImplementationGuideVersionDetail
from .raw_client import AsyncRawImplementationGuidesClient, RawImplementationGuidesClient
# this is used as the default value for optional parameters
@@ -136,11 +138,9 @@ def update(
def delete(self, name: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
"""
- Deletes the stored metadata for an implementation guide — its
- profile_context and timestamps. Member profiles keep their
- implementation_guide assignment, so a guide still referenced by at least
- one profile continues to appear in listings, just without context or
- timestamps.
+ Deletes the stored name-level metadata and any exact canonical package
+ versions beneath the guide. Legacy member profile assignments are not
+ changed.
Parameters
----------
@@ -169,6 +169,102 @@ def delete(self, name: str, *, request_options: typing.Optional[RequestOptions]
_response = self._raw_client.delete(name, request_options=request_options)
return _response.data
+ def create_version(
+ self,
+ name: str,
+ *,
+ implementation_guide: FhirImplementationGuide,
+ profile_refs: typing.Sequence[str],
+ profile_context: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ImplementationGuideVersionDetail:
+ """
+ Publishes an exact package beneath this guide family. PR 2 temporarily
+ permits one exact package version per guide family; publishing another
+ version returns `409 Conflict` until multi-version package support lands.
+
+ Parameters
+ ----------
+ name : str
+
+ implementation_guide : FhirImplementationGuide
+
+ profile_refs : typing.Sequence[str]
+ Exact canonical `url|version` references to builtin or custom profiles. A package can contain at most 250 references.
+
+ profile_context : typing.Optional[str]
+ Natural-language profile-selection context for this package.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ImplementationGuideVersionDetail
+ Canonical package published
+
+ Examples
+ --------
+ from phenoml import PhenomlClient
+ from phenoml.implementation_guides import FhirImplementationGuide
+
+ client = PhenomlClient(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+ )
+ client.implementation_guides.implementation_guides.create_version(
+ name="name",
+ implementation_guide=FhirImplementationGuide(
+ url="url",
+ version="version",
+ ),
+ profile_refs=["profile_refs"],
+ )
+ """
+ _response = self._raw_client.create_version(
+ name,
+ implementation_guide=implementation_guide,
+ profile_refs=profile_refs,
+ profile_context=profile_context,
+ request_options=request_options,
+ )
+ return _response.data
+
+ def get_version(
+ self, name: str, version: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> ImplementationGuideVersionDetail:
+ """
+ Parameters
+ ----------
+ name : str
+
+ version : str
+ The authored ImplementationGuide.version. It may contain letters, numbers, and the punctuation characters `.`, `_`, `~`, `+`, and `-`; it cannot be exactly `.` or `..`.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ImplementationGuideVersionDetail
+ Exact canonical package
+
+ Examples
+ --------
+ from phenoml import PhenomlClient
+
+ client = PhenomlClient(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+ )
+ client.implementation_guides.implementation_guides.get_version(
+ name="name",
+ version="1.0.0",
+ )
+ """
+ _response = self._raw_client.get_version(name, version, request_options=request_options)
+ return _response.data
+
class AsyncImplementationGuidesClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
@@ -321,11 +417,9 @@ async def main() -> None:
async def delete(self, name: str, *, request_options: typing.Optional[RequestOptions] = None) -> None:
"""
- Deletes the stored metadata for an implementation guide — its
- profile_context and timestamps. Member profiles keep their
- implementation_guide assignment, so a guide still referenced by at least
- one profile continues to appear in listings, just without context or
- timestamps.
+ Deletes the stored name-level metadata and any exact canonical package
+ versions beneath the guide. Legacy member profile assignments are not
+ changed.
Parameters
----------
@@ -361,3 +455,115 @@ async def main() -> None:
"""
_response = await self._raw_client.delete(name, request_options=request_options)
return _response.data
+
+ async def create_version(
+ self,
+ name: str,
+ *,
+ implementation_guide: FhirImplementationGuide,
+ profile_refs: typing.Sequence[str],
+ profile_context: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ImplementationGuideVersionDetail:
+ """
+ Publishes an exact package beneath this guide family. PR 2 temporarily
+ permits one exact package version per guide family; publishing another
+ version returns `409 Conflict` until multi-version package support lands.
+
+ Parameters
+ ----------
+ name : str
+
+ implementation_guide : FhirImplementationGuide
+
+ profile_refs : typing.Sequence[str]
+ Exact canonical `url|version` references to builtin or custom profiles. A package can contain at most 250 references.
+
+ profile_context : typing.Optional[str]
+ Natural-language profile-selection context for this package.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ImplementationGuideVersionDetail
+ Canonical package published
+
+ Examples
+ --------
+ import asyncio
+
+ from phenoml import AsyncPhenomlClient
+ from phenoml.implementation_guides import FhirImplementationGuide
+
+ client = AsyncPhenomlClient(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+ )
+
+
+ async def main() -> None:
+ await client.implementation_guides.implementation_guides.create_version(
+ name="name",
+ implementation_guide=FhirImplementationGuide(
+ url="url",
+ version="version",
+ ),
+ profile_refs=["profile_refs"],
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.create_version(
+ name,
+ implementation_guide=implementation_guide,
+ profile_refs=profile_refs,
+ profile_context=profile_context,
+ request_options=request_options,
+ )
+ return _response.data
+
+ async def get_version(
+ self, name: str, version: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> ImplementationGuideVersionDetail:
+ """
+ Parameters
+ ----------
+ name : str
+
+ version : str
+ The authored ImplementationGuide.version. It may contain letters, numbers, and the punctuation characters `.`, `_`, `~`, `+`, and `-`; it cannot be exactly `.` or `..`.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ImplementationGuideVersionDetail
+ Exact canonical package
+
+ Examples
+ --------
+ import asyncio
+
+ from phenoml import AsyncPhenomlClient
+
+ client = AsyncPhenomlClient(
+ client_id="YOUR_CLIENT_ID",
+ client_secret="YOUR_CLIENT_SECRET",
+ )
+
+
+ async def main() -> None:
+ await client.implementation_guides.implementation_guides.get_version(
+ name="name",
+ version="1.0.0",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.get_version(name, version, request_options=request_options)
+ return _response.data
diff --git a/src/phenoml/implementation_guides/implementation_guides/raw_client.py b/src/phenoml/implementation_guides/implementation_guides/raw_client.py
index 8700e84..1eb8291 100644
--- a/src/phenoml/implementation_guides/implementation_guides/raw_client.py
+++ b/src/phenoml/implementation_guides/implementation_guides/raw_client.py
@@ -10,14 +10,18 @@
from ...core.parse_error import ParsingError
from ...core.pydantic_utilities import parse_obj_as
from ...core.request_options import RequestOptions
+from ...core.serialization import convert_and_respect_annotation_metadata
from ..errors.bad_request_error import BadRequestError
+from ..errors.conflict_error import ConflictError
from ..errors.forbidden_error import ForbiddenError
from ..errors.internal_server_error import InternalServerError
from ..errors.not_found_error import NotFoundError
from ..errors.unauthorized_error import UnauthorizedError
+from ..types.fhir_implementation_guide import FhirImplementationGuide
from ..types.implementation_guide_detail import ImplementationGuideDetail
from ..types.implementation_guide_list_response import ImplementationGuideListResponse
from ..types.implementation_guide_summary import ImplementationGuideSummary
+from ..types.implementation_guide_version_detail import ImplementationGuideVersionDetail
from pydantic import ValidationError
# this is used as the default value for optional parameters
@@ -308,11 +312,9 @@ def update(
def delete(self, name: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[None]:
"""
- Deletes the stored metadata for an implementation guide — its
- profile_context and timestamps. Member profiles keep their
- implementation_guide assignment, so a guide still referenced by at least
- one profile continues to appear in listings, just without context or
- timestamps.
+ Deletes the stored name-level metadata and any exact canonical package
+ versions beneath the guide. Legacy member profile assignments are not
+ changed.
Parameters
----------
@@ -398,6 +400,173 @@ def delete(self, name: str, *, request_options: typing.Optional[RequestOptions]
)
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+ def create_version(
+ self,
+ name: str,
+ *,
+ implementation_guide: FhirImplementationGuide,
+ profile_refs: typing.Sequence[str],
+ profile_context: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ImplementationGuideVersionDetail]:
+ """
+ Publishes an exact package beneath this guide family. PR 2 temporarily
+ permits one exact package version per guide family; publishing another
+ version returns `409 Conflict` until multi-version package support lands.
+
+ Parameters
+ ----------
+ name : str
+
+ implementation_guide : FhirImplementationGuide
+
+ profile_refs : typing.Sequence[str]
+ Exact canonical `url|version` references to builtin or custom profiles. A package can contain at most 250 references.
+
+ profile_context : typing.Optional[str]
+ Natural-language profile-selection context for this package.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ImplementationGuideVersionDetail]
+ Canonical package published
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"fhir/implementation-guides/{encode_path_param(name)}/versions",
+ method="POST",
+ json={
+ "implementation_guide": convert_and_respect_annotation_metadata(
+ object_=implementation_guide, annotation=FhirImplementationGuide, direction="write"
+ ),
+ "profile_refs": profile_refs,
+ "profile_context": profile_context,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ImplementationGuideVersionDetail,
+ parse_obj_as(
+ type_=ImplementationGuideVersionDetail, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get_version(
+ self, name: str, version: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[ImplementationGuideVersionDetail]:
+ """
+ Parameters
+ ----------
+ name : str
+
+ version : str
+ The authored ImplementationGuide.version. It may contain letters, numbers, and the punctuation characters `.`, `_`, `~`, `+`, and `-`; it cannot be exactly `.` or `..`.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ImplementationGuideVersionDetail]
+ Exact canonical package
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ f"fhir/implementation-guides/{encode_path_param(name)}/versions/{encode_path_param(version)}",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ImplementationGuideVersionDetail,
+ parse_obj_as(
+ type_=ImplementationGuideVersionDetail, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
class AsyncRawImplementationGuidesClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
@@ -685,11 +854,9 @@ async def delete(
self, name: str, *, request_options: typing.Optional[RequestOptions] = None
) -> AsyncHttpResponse[None]:
"""
- Deletes the stored metadata for an implementation guide — its
- profile_context and timestamps. Member profiles keep their
- implementation_guide assignment, so a guide still referenced by at least
- one profile continues to appear in listings, just without context or
- timestamps.
+ Deletes the stored name-level metadata and any exact canonical package
+ versions beneath the guide. Legacy member profile assignments are not
+ changed.
Parameters
----------
@@ -774,3 +941,170 @@ async def delete(
status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
)
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def create_version(
+ self,
+ name: str,
+ *,
+ implementation_guide: FhirImplementationGuide,
+ profile_refs: typing.Sequence[str],
+ profile_context: typing.Optional[str] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ImplementationGuideVersionDetail]:
+ """
+ Publishes an exact package beneath this guide family. PR 2 temporarily
+ permits one exact package version per guide family; publishing another
+ version returns `409 Conflict` until multi-version package support lands.
+
+ Parameters
+ ----------
+ name : str
+
+ implementation_guide : FhirImplementationGuide
+
+ profile_refs : typing.Sequence[str]
+ Exact canonical `url|version` references to builtin or custom profiles. A package can contain at most 250 references.
+
+ profile_context : typing.Optional[str]
+ Natural-language profile-selection context for this package.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ImplementationGuideVersionDetail]
+ Canonical package published
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"fhir/implementation-guides/{encode_path_param(name)}/versions",
+ method="POST",
+ json={
+ "implementation_guide": convert_and_respect_annotation_metadata(
+ object_=implementation_guide, annotation=FhirImplementationGuide, direction="write"
+ ),
+ "profile_refs": profile_refs,
+ "profile_context": profile_context,
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ImplementationGuideVersionDetail,
+ parse_obj_as(
+ type_=ImplementationGuideVersionDetail, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get_version(
+ self, name: str, version: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[ImplementationGuideVersionDetail]:
+ """
+ Parameters
+ ----------
+ name : str
+
+ version : str
+ The authored ImplementationGuide.version. It may contain letters, numbers, and the punctuation characters `.`, `_`, `~`, `+`, and `-`; it cannot be exactly `.` or `..`.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ImplementationGuideVersionDetail]
+ Exact canonical package
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"fhir/implementation-guides/{encode_path_param(name)}/versions/{encode_path_param(version)}",
+ method="GET",
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ImplementationGuideVersionDetail,
+ parse_obj_as(
+ type_=ImplementationGuideVersionDetail, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 404:
+ raise NotFoundError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/src/phenoml/implementation_guides/types/__init__.py b/src/phenoml/implementation_guides/types/__init__.py
index 2b67df5..6c2a89f 100644
--- a/src/phenoml/implementation_guides/types/__init__.py
+++ b/src/phenoml/implementation_guides/types/__init__.py
@@ -6,13 +6,17 @@
from importlib import import_module
if typing.TYPE_CHECKING:
+ from .fhir_implementation_guide import FhirImplementationGuide
from .implementation_guide_detail import ImplementationGuideDetail
from .implementation_guide_list_response import ImplementationGuideListResponse
from .implementation_guide_summary import ImplementationGuideSummary
+ from .implementation_guide_version_detail import ImplementationGuideVersionDetail
_dynamic_imports: typing.Dict[str, str] = {
+ "FhirImplementationGuide": ".fhir_implementation_guide",
"ImplementationGuideDetail": ".implementation_guide_detail",
"ImplementationGuideListResponse": ".implementation_guide_list_response",
"ImplementationGuideSummary": ".implementation_guide_summary",
+ "ImplementationGuideVersionDetail": ".implementation_guide_version_detail",
}
@@ -37,4 +41,10 @@ def __dir__():
return sorted(lazy_attrs)
-__all__ = ["ImplementationGuideDetail", "ImplementationGuideListResponse", "ImplementationGuideSummary"]
+__all__ = [
+ "FhirImplementationGuide",
+ "ImplementationGuideDetail",
+ "ImplementationGuideListResponse",
+ "ImplementationGuideSummary",
+ "ImplementationGuideVersionDetail",
+]
diff --git a/src/phenoml/implementation_guides/types/fhir_implementation_guide.py b/src/phenoml/implementation_guides/types/fhir_implementation_guide.py
new file mode 100644
index 0000000..949b9df
--- /dev/null
+++ b/src/phenoml/implementation_guides/types/fhir_implementation_guide.py
@@ -0,0 +1,38 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ...core.serialization import FieldMetadata
+
+
+class FhirImplementationGuide(UniversalBaseModel):
+ """
+ A complete authored FHIR ImplementationGuide JSON resource.
+ """
+
+ resource_type: typing_extensions.Annotated[
+ typing.Literal["ImplementationGuide"], FieldMetadata(alias="resourceType"), pydantic.Field(alias="resourceType")
+ ] = "ImplementationGuide"
+ id: typing.Optional[str] = None
+ url: str
+ version: str
+ name: typing.Optional[str] = None
+ status: typing.Optional[str] = None
+ package_id: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="packageId"), pydantic.Field(alias="packageId")
+ ] = None
+ fhir_version: typing_extensions.Annotated[
+ typing.Optional[typing.List[str]], FieldMetadata(alias="fhirVersion"), pydantic.Field(alias="fhirVersion")
+ ] = None
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/phenoml/implementation_guides/types/implementation_guide_summary.py b/src/phenoml/implementation_guides/types/implementation_guide_summary.py
index bd3364d..a6489ab 100644
--- a/src/phenoml/implementation_guides/types/implementation_guide_summary.py
+++ b/src/phenoml/implementation_guides/types/implementation_guide_summary.py
@@ -9,7 +9,7 @@
class ImplementationGuideSummary(UniversalBaseModel):
"""
- Metadata for an implementation guide. This is an instance-local grouping record, not a complete FHIR ImplementationGuide resource.
+ Metadata for an implementation guide. Canonical fields are present only for published canonical packages; metadata-only legacy records omit them.
"""
name: typing.Optional[str] = pydantic.Field(default=None)
@@ -27,6 +27,16 @@ class ImplementationGuideSummary(UniversalBaseModel):
The number of custom profiles in this implementation guide.
"""
+ canonical_url: typing.Optional[str] = pydantic.Field(default=None)
+ """
+ Canonical FHIR ImplementationGuide URL, when the family has an exact package.
+ """
+
+ version_count: typing.Optional[int] = pydantic.Field(default=None)
+ """
+ Number of retained exact package versions.
+ """
+
created_at: typing.Optional[dt.datetime] = pydantic.Field(default=None)
"""
Present only for guides that have stored metadata (a profile_context has been set). Omitted for guides that exist solely because a profile references them.
diff --git a/src/phenoml/implementation_guides/types/implementation_guide_version_detail.py b/src/phenoml/implementation_guides/types/implementation_guide_version_detail.py
new file mode 100644
index 0000000..a5c2e66
--- /dev/null
+++ b/src/phenoml/implementation_guides/types/implementation_guide_version_detail.py
@@ -0,0 +1,29 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import datetime as dt
+import typing
+
+import pydantic
+from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from .fhir_implementation_guide import FhirImplementationGuide
+
+
+class ImplementationGuideVersionDetail(UniversalBaseModel):
+ name: str
+ url: str
+ version: str
+ profile_context: str
+ profiles: typing.List[str]
+ profile_refs: typing.List[str]
+ implementation_guide: FhirImplementationGuide
+ created_at: dt.datetime
+ updated_at: dt.datetime
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/phenoml/lang2fhir/__init__.py b/src/phenoml/lang2fhir/__init__.py
index 8b0af5d..78441a8 100644
--- a/src/phenoml/lang2fhir/__init__.py
+++ b/src/phenoml/lang2fhir/__init__.py
@@ -33,6 +33,7 @@
ResourceReviewFinding,
ResourceReviewFindingFieldKind,
ResourceReviewFlagged,
+ ResourceReviewRemediated,
ResourceReviewResult,
ResourceReviewTarget,
ResourceReviewTargetFieldsItem,
@@ -85,6 +86,7 @@
"ResourceReviewFinding": ".types",
"ResourceReviewFindingFieldKind": ".types",
"ResourceReviewFlagged": ".types",
+ "ResourceReviewRemediated": ".types",
"ResourceReviewResult": ".types",
"ResourceReviewTarget": ".types",
"ResourceReviewTargetFieldsItem": ".types",
@@ -152,6 +154,7 @@ def __dir__():
"ResourceReviewFinding",
"ResourceReviewFindingFieldKind",
"ResourceReviewFlagged",
+ "ResourceReviewRemediated",
"ResourceReviewResult",
"ResourceReviewTarget",
"ResourceReviewTargetFieldsItem",
diff --git a/src/phenoml/lang2fhir/client.py b/src/phenoml/lang2fhir/client.py
index c4a0ad5..875324c 100644
--- a/src/phenoml/lang2fhir/client.py
+++ b/src/phenoml/lang2fhir/client.py
@@ -291,7 +291,7 @@ def document(
request_options: typing.Optional[RequestOptions] = None,
) -> FhirResource:
"""
- Extracts text from a document (PDF or image) and converts it into a structured FHIR resource.
+ Extracts text from a PDF, image, RTF, or XML/C-CDA document and converts it into a structured FHIR resource.
**Patient identifier handling.** When generating a `patient` (or `patient-canvas`) resource, US Core requires `Patient.identifier` (a business identifier such as an MRN). When the source text contains an identifier, it is extracted with an appropriate URI system. When the source text does not contain a detectable identifier, a synthetic one is generated with `system: "urn:phenoml:lang2fhir-generated-id"` and a UUID `value` so the resource remains FHIR-valid and US Core conformant. Callers who need a tenant-specific namespace should rewrite the synthetic system after extraction.
@@ -305,8 +305,11 @@ def document(
content : str
Base64 encoded file content.
- Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff).
+ Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff), RTF (application/rtf), XML/C-CDA (text/xml).
+ RTF and XML/C-CDA uploads are available on dedicated instances only.
File type is auto-detected from content magic bytes.
+ The decoded file must not exceed 20 MiB. RTF and XML/C-CDA documents whose extracted text exceeds 1 MiB are rejected.
+ Generic XML must include an XML declaration; C-CDA documents rooted at `ClinicalDocument` may omit it.
config : typing.Optional[DocumentConfig]
@@ -329,7 +332,7 @@ def document(
client.lang2fhir.document(
version="R4",
resource="questionnaire",
- content="JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)",
+ content="JVBERi0xLjQKJeLjz9MK...(base64-encoded document bytes)",
)
"""
_response = self._raw_client.document(
@@ -351,7 +354,7 @@ def document_multi(
request_options: typing.Optional[RequestOptions] = None,
) -> DocumentMultiResponse:
"""
- Extracts text from a document (PDF or image) and converts it into multiple FHIR resources,
+ Extracts text from a PDF, image, RTF, or XML/C-CDA document and converts it into multiple FHIR resources,
returned as a transaction Bundle. Combines document text extraction with multi-resource detection.
Automatically detects Patient, Condition, MedicationRequest, Observation, and other resource types.
Resources are linked with proper references (e.g., Conditions reference the Patient).
@@ -367,8 +370,11 @@ def document_multi(
content : str
Base64 encoded file content.
- Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff).
+ Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff), RTF (application/rtf), XML/C-CDA (text/xml).
+ RTF and XML/C-CDA uploads are available on dedicated instances only.
File type is auto-detected from content magic bytes.
+ The decoded file must not exceed 20 MiB. RTF and XML/C-CDA documents whose extracted text exceeds 1 MiB are rejected.
+ Generic XML must include an XML declaration; C-CDA documents rooted at `ClinicalDocument` may omit it.
provider : typing.Optional[str]
Optional FHIR provider name for provider-specific profiles
@@ -405,7 +411,7 @@ def document_multi(
)
client.lang2fhir.document_multi(
version="R4",
- content="JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)",
+ content="JVBERi0xLjQKJeLjz9MK...(base64-encoded document bytes)",
provider="medplum",
config=DocumentConfig(
split_classifications=[
@@ -737,7 +743,7 @@ async def document(
request_options: typing.Optional[RequestOptions] = None,
) -> FhirResource:
"""
- Extracts text from a document (PDF or image) and converts it into a structured FHIR resource.
+ Extracts text from a PDF, image, RTF, or XML/C-CDA document and converts it into a structured FHIR resource.
**Patient identifier handling.** When generating a `patient` (or `patient-canvas`) resource, US Core requires `Patient.identifier` (a business identifier such as an MRN). When the source text contains an identifier, it is extracted with an appropriate URI system. When the source text does not contain a detectable identifier, a synthetic one is generated with `system: "urn:phenoml:lang2fhir-generated-id"` and a UUID `value` so the resource remains FHIR-valid and US Core conformant. Callers who need a tenant-specific namespace should rewrite the synthetic system after extraction.
@@ -751,8 +757,11 @@ async def document(
content : str
Base64 encoded file content.
- Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff).
+ Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff), RTF (application/rtf), XML/C-CDA (text/xml).
+ RTF and XML/C-CDA uploads are available on dedicated instances only.
File type is auto-detected from content magic bytes.
+ The decoded file must not exceed 20 MiB. RTF and XML/C-CDA documents whose extracted text exceeds 1 MiB are rejected.
+ Generic XML must include an XML declaration; C-CDA documents rooted at `ClinicalDocument` may omit it.
config : typing.Optional[DocumentConfig]
@@ -780,7 +789,7 @@ async def main() -> None:
await client.lang2fhir.document(
version="R4",
resource="questionnaire",
- content="JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)",
+ content="JVBERi0xLjQKJeLjz9MK...(base64-encoded document bytes)",
)
@@ -805,7 +814,7 @@ async def document_multi(
request_options: typing.Optional[RequestOptions] = None,
) -> DocumentMultiResponse:
"""
- Extracts text from a document (PDF or image) and converts it into multiple FHIR resources,
+ Extracts text from a PDF, image, RTF, or XML/C-CDA document and converts it into multiple FHIR resources,
returned as a transaction Bundle. Combines document text extraction with multi-resource detection.
Automatically detects Patient, Condition, MedicationRequest, Observation, and other resource types.
Resources are linked with proper references (e.g., Conditions reference the Patient).
@@ -821,8 +830,11 @@ async def document_multi(
content : str
Base64 encoded file content.
- Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff).
+ Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff), RTF (application/rtf), XML/C-CDA (text/xml).
+ RTF and XML/C-CDA uploads are available on dedicated instances only.
File type is auto-detected from content magic bytes.
+ The decoded file must not exceed 20 MiB. RTF and XML/C-CDA documents whose extracted text exceeds 1 MiB are rejected.
+ Generic XML must include an XML declaration; C-CDA documents rooted at `ClinicalDocument` may omit it.
provider : typing.Optional[str]
Optional FHIR provider name for provider-specific profiles
@@ -864,7 +876,7 @@ async def document_multi(
async def main() -> None:
await client.lang2fhir.document_multi(
version="R4",
- content="JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)",
+ content="JVBERi0xLjQKJeLjz9MK...(base64-encoded document bytes)",
provider="medplum",
config=DocumentConfig(
split_classifications=[
diff --git a/src/phenoml/lang2fhir/raw_client.py b/src/phenoml/lang2fhir/raw_client.py
index 7848589..c2cdb41 100644
--- a/src/phenoml/lang2fhir/raw_client.py
+++ b/src/phenoml/lang2fhir/raw_client.py
@@ -537,7 +537,7 @@ def document(
request_options: typing.Optional[RequestOptions] = None,
) -> HttpResponse[FhirResource]:
"""
- Extracts text from a document (PDF or image) and converts it into a structured FHIR resource.
+ Extracts text from a PDF, image, RTF, or XML/C-CDA document and converts it into a structured FHIR resource.
**Patient identifier handling.** When generating a `patient` (or `patient-canvas`) resource, US Core requires `Patient.identifier` (a business identifier such as an MRN). When the source text contains an identifier, it is extracted with an appropriate URI system. When the source text does not contain a detectable identifier, a synthetic one is generated with `system: "urn:phenoml:lang2fhir-generated-id"` and a UUID `value` so the resource remains FHIR-valid and US Core conformant. Callers who need a tenant-specific namespace should rewrite the synthetic system after extraction.
@@ -551,8 +551,11 @@ def document(
content : str
Base64 encoded file content.
- Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff).
+ Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff), RTF (application/rtf), XML/C-CDA (text/xml).
+ RTF and XML/C-CDA uploads are available on dedicated instances only.
File type is auto-detected from content magic bytes.
+ The decoded file must not exceed 20 MiB. RTF and XML/C-CDA documents whose extracted text exceeds 1 MiB are rejected.
+ Generic XML must include an XML declaration; C-CDA documents rooted at `ClinicalDocument` may omit it.
config : typing.Optional[DocumentConfig]
@@ -613,6 +616,17 @@ def document(
),
),
)
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
if _response.status_code == 404:
raise NotFoundError(
headers=dict(_response.headers),
@@ -691,7 +705,7 @@ def document_multi(
request_options: typing.Optional[RequestOptions] = None,
) -> HttpResponse[DocumentMultiResponse]:
"""
- Extracts text from a document (PDF or image) and converts it into multiple FHIR resources,
+ Extracts text from a PDF, image, RTF, or XML/C-CDA document and converts it into multiple FHIR resources,
returned as a transaction Bundle. Combines document text extraction with multi-resource detection.
Automatically detects Patient, Condition, MedicationRequest, Observation, and other resource types.
Resources are linked with proper references (e.g., Conditions reference the Patient).
@@ -707,8 +721,11 @@ def document_multi(
content : str
Base64 encoded file content.
- Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff).
+ Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff), RTF (application/rtf), XML/C-CDA (text/xml).
+ RTF and XML/C-CDA uploads are available on dedicated instances only.
File type is auto-detected from content magic bytes.
+ The decoded file must not exceed 20 MiB. RTF and XML/C-CDA documents whose extracted text exceeds 1 MiB are rejected.
+ Generic XML must include an XML declaration; C-CDA documents rooted at `ClinicalDocument` may omit it.
provider : typing.Optional[str]
Optional FHIR provider name for provider-specific profiles
@@ -789,6 +806,17 @@ def document_multi(
),
),
)
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
if _response.status_code == 404:
raise NotFoundError(
headers=dict(_response.headers),
@@ -1354,7 +1382,7 @@ async def document(
request_options: typing.Optional[RequestOptions] = None,
) -> AsyncHttpResponse[FhirResource]:
"""
- Extracts text from a document (PDF or image) and converts it into a structured FHIR resource.
+ Extracts text from a PDF, image, RTF, or XML/C-CDA document and converts it into a structured FHIR resource.
**Patient identifier handling.** When generating a `patient` (or `patient-canvas`) resource, US Core requires `Patient.identifier` (a business identifier such as an MRN). When the source text contains an identifier, it is extracted with an appropriate URI system. When the source text does not contain a detectable identifier, a synthetic one is generated with `system: "urn:phenoml:lang2fhir-generated-id"` and a UUID `value` so the resource remains FHIR-valid and US Core conformant. Callers who need a tenant-specific namespace should rewrite the synthetic system after extraction.
@@ -1368,8 +1396,11 @@ async def document(
content : str
Base64 encoded file content.
- Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff).
+ Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff), RTF (application/rtf), XML/C-CDA (text/xml).
+ RTF and XML/C-CDA uploads are available on dedicated instances only.
File type is auto-detected from content magic bytes.
+ The decoded file must not exceed 20 MiB. RTF and XML/C-CDA documents whose extracted text exceeds 1 MiB are rejected.
+ Generic XML must include an XML declaration; C-CDA documents rooted at `ClinicalDocument` may omit it.
config : typing.Optional[DocumentConfig]
@@ -1430,6 +1461,17 @@ async def document(
),
),
)
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
if _response.status_code == 404:
raise NotFoundError(
headers=dict(_response.headers),
@@ -1508,7 +1550,7 @@ async def document_multi(
request_options: typing.Optional[RequestOptions] = None,
) -> AsyncHttpResponse[DocumentMultiResponse]:
"""
- Extracts text from a document (PDF or image) and converts it into multiple FHIR resources,
+ Extracts text from a PDF, image, RTF, or XML/C-CDA document and converts it into multiple FHIR resources,
returned as a transaction Bundle. Combines document text extraction with multi-resource detection.
Automatically detects Patient, Condition, MedicationRequest, Observation, and other resource types.
Resources are linked with proper references (e.g., Conditions reference the Patient).
@@ -1524,8 +1566,11 @@ async def document_multi(
content : str
Base64 encoded file content.
- Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff).
+ Supported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff), RTF (application/rtf), XML/C-CDA (text/xml).
+ RTF and XML/C-CDA uploads are available on dedicated instances only.
File type is auto-detected from content magic bytes.
+ The decoded file must not exceed 20 MiB. RTF and XML/C-CDA documents whose extracted text exceeds 1 MiB are rejected.
+ Generic XML must include an XML declaration; C-CDA documents rooted at `ClinicalDocument` may omit it.
provider : typing.Optional[str]
Optional FHIR provider name for provider-specific profiles
@@ -1606,6 +1651,17 @@ async def document_multi(
),
),
)
+ if _response.status_code == 403:
+ raise ForbiddenError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
if _response.status_code == 404:
raise NotFoundError(
headers=dict(_response.headers),
diff --git a/src/phenoml/lang2fhir/types/__init__.py b/src/phenoml/lang2fhir/types/__init__.py
index 1230315..faaded9 100644
--- a/src/phenoml/lang2fhir/types/__init__.py
+++ b/src/phenoml/lang2fhir/types/__init__.py
@@ -36,6 +36,7 @@
from .resource_review_finding import ResourceReviewFinding
from .resource_review_finding_field_kind import ResourceReviewFindingFieldKind
from .resource_review_flagged import ResourceReviewFlagged
+ from .resource_review_remediated import ResourceReviewRemediated
from .resource_review_result import ResourceReviewResult
from .resource_review_target import ResourceReviewTarget
from .resource_review_target_fields_item import ResourceReviewTargetFieldsItem
@@ -71,6 +72,7 @@
"ResourceReviewFinding": ".resource_review_finding",
"ResourceReviewFindingFieldKind": ".resource_review_finding_field_kind",
"ResourceReviewFlagged": ".resource_review_flagged",
+ "ResourceReviewRemediated": ".resource_review_remediated",
"ResourceReviewResult": ".resource_review_result",
"ResourceReviewTarget": ".resource_review_target",
"ResourceReviewTargetFieldsItem": ".resource_review_target_fields_item",
@@ -130,6 +132,7 @@ def __dir__():
"ResourceReviewFinding",
"ResourceReviewFindingFieldKind",
"ResourceReviewFlagged",
+ "ResourceReviewRemediated",
"ResourceReviewResult",
"ResourceReviewTarget",
"ResourceReviewTargetFieldsItem",
diff --git a/src/phenoml/lang2fhir/types/resource_review.py b/src/phenoml/lang2fhir/types/resource_review.py
index 02f825d..6a62b33 100644
--- a/src/phenoml/lang2fhir/types/resource_review.py
+++ b/src/phenoml/lang2fhir/types/resource_review.py
@@ -9,7 +9,7 @@
class ResourceReview(UniversalBaseModel):
"""
- Opt-in, report-only faithfulness audit (honored by /lang2fhir/create/multi and /lang2fhir/document/multi). For each selected resource type an LLM checks whether selected dates and clinical code concepts are actually supported by the full source document. Resources with an unsupported field are pulled out of the returned bundle and reported under resource_review in the response.
+ Opt-in faithfulness audit (honored by /lang2fhir/create/multi and /lang2fhir/document/multi). For each selected resource type an LLM checks whether selected dates and clinical code concepts are actually supported by the full source document. An unsupported individual coding is removed when another coding remains in its concept. Resources with an unsupported structural field, a profile-required coding, or no coding remaining in an affected concept, are pulled out of the returned bundle and reported under resource_review in the response.
"""
targets: typing.List[ResourceReviewTarget] = pydantic.Field()
diff --git a/src/phenoml/lang2fhir/types/resource_review_finding.py b/src/phenoml/lang2fhir/types/resource_review_finding.py
index 5703149..c78e567 100644
--- a/src/phenoml/lang2fhir/types/resource_review_finding.py
+++ b/src/phenoml/lang2fhir/types/resource_review_finding.py
@@ -27,7 +27,12 @@ class ResourceReviewFinding(UniversalBaseModel):
value: typing.Optional[str] = None
supported: typing.Optional[bool] = pydantic.Field(default=None)
"""
- Always false for a flagged finding.
+ False when the reviewer found the field unsupported. Do not treat this field as a verdict when unaudited is true.
+ """
+
+ unaudited: typing.Optional[bool] = pydantic.Field(default=None)
+ """
+ True when the reviewer did not return a verdict for this field; the resource was quarantined without treating the finding as evidence that the value is unsupported.
"""
rationale: typing.Optional[str] = pydantic.Field(default=None)
diff --git a/src/phenoml/lang2fhir/types/resource_review_flagged.py b/src/phenoml/lang2fhir/types/resource_review_flagged.py
index 01b845d..a3f08af 100644
--- a/src/phenoml/lang2fhir/types/resource_review_flagged.py
+++ b/src/phenoml/lang2fhir/types/resource_review_flagged.py
@@ -29,7 +29,7 @@ class ResourceReviewFlagged(UniversalBaseModel):
findings: typing.Optional[typing.List[ResourceReviewFinding]] = pydantic.Field(default=None)
"""
- The unsupported fields that caused the resource to be flagged.
+ The findings that caused the resource to be quarantined.
"""
if IS_PYDANTIC_V2:
diff --git a/src/phenoml/lang2fhir/types/resource_review_remediated.py b/src/phenoml/lang2fhir/types/resource_review_remediated.py
new file mode 100644
index 0000000..0db4999
--- /dev/null
+++ b/src/phenoml/lang2fhir/types/resource_review_remediated.py
@@ -0,0 +1,42 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+import pydantic
+import typing_extensions
+from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
+from ...core.serialization import FieldMetadata
+from .resource_review_finding import ResourceReviewFinding
+
+
+class ResourceReviewRemediated(UniversalBaseModel):
+ temp_id: typing_extensions.Annotated[
+ typing.Optional[str],
+ FieldMetadata(alias="tempId"),
+ pydantic.Field(alias="tempId", description="The urn:uuid of the remediated resource (its bundle fullUrl)."),
+ ] = None
+ """
+ The urn:uuid of the remediated resource (its bundle fullUrl).
+ """
+
+ resource_type: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="resourceType"), pydantic.Field(alias="resourceType")
+ ] = None
+ action: typing.Optional[typing.Literal["removed_codings"]] = pydantic.Field(default=None)
+ """
+ The safe change applied to the resource in the returned bundle.
+ """
+
+ findings: typing.Optional[typing.List[ResourceReviewFinding]] = pydantic.Field(default=None)
+ """
+ Findings for fields in the pre-remediation resource that caused this action.
+ """
+
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
+ else:
+
+ class Config:
+ frozen = True
+ smart_union = True
+ extra = pydantic.Extra.allow
diff --git a/src/phenoml/lang2fhir/types/resource_review_result.py b/src/phenoml/lang2fhir/types/resource_review_result.py
index fa91ed5..16ae116 100644
--- a/src/phenoml/lang2fhir/types/resource_review_result.py
+++ b/src/phenoml/lang2fhir/types/resource_review_result.py
@@ -5,16 +5,22 @@
import pydantic
from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
from .resource_review_flagged import ResourceReviewFlagged
+from .resource_review_remediated import ResourceReviewRemediated
class ResourceReviewResult(UniversalBaseModel):
"""
- Present when resource_review was requested and at least one resource was flagged.
+ Present when resource_review was requested and at least one resource was quarantined or safely remediated. The returned bundle is authoritative and contains the post-review representation of every retained resource.
"""
flagged: typing.Optional[typing.List[ResourceReviewFlagged]] = pydantic.Field(default=None)
"""
- Resources pulled from the bundle because a reviewed field was not supported by the source.
+ Resources pulled from the bundle because an unsupported finding could not be safely repaired.
+ """
+
+ remediated: typing.Optional[typing.List[ResourceReviewRemediated]] = pydantic.Field(default=None)
+ """
+ Resources retained in the bundle after unsupported codings were safely removed.
"""
if IS_PYDANTIC_V2:
diff --git a/src/phenoml/lang2fhir_batch/client.py b/src/phenoml/lang2fhir_batch/client.py
index d641755..08698ab 100644
--- a/src/phenoml/lang2fhir_batch/client.py
+++ b/src/phenoml/lang2fhir_batch/client.py
@@ -90,16 +90,15 @@ def create(
finalized is released for a fresh replay; once a job is finalized, its
`request_id` keeps resolving to it even after cancellation.
- An instance may hold at most 4 active (pending or processing) jobs at
- once; a create past that limit returns `409`. The limit is instance-wide
- — jobs are shared across the instance's credentials — so another
- credential's jobs count against it.
+ There is no limit on how many jobs an instance may hold at once; how many
+ items run in parallel is a property of the instance, not of the job count.
Parameters
----------
request_id : typing.Optional[str]
- Optional client idempotency token. A retried create with the same
- token returns the original job instead of opening a second one.
+ Optional client idempotency token (at most 256 UTF-8 bytes). A
+ retried create with the same token returns the original job instead
+ of opening a second one.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -145,7 +144,7 @@ def upload_item(
- Set **exactly one** of `document` or `create`. Setting both, or
neither, is a `400`.
- When `document` is set, `file` is **required** — it supplies the
- document's binary content (PDF or image).
+ document's file content (PDF, image, RTF, or XML/C-CDA).
- When `create` is set, `file` is **forbidden** — a create item carries
no file.
- `document` and `create` must each be a JSON **object**.
@@ -202,15 +201,16 @@ def upload_item(
See core.File for more documentation
request_id : typing.Optional[str]
- Optional idempotency token (max 256 bytes). Re-uploading under
- the same token overwrites the same item instead of adding a
- new one. The token is scoped to this job; the same token in
- another job is independent and creates a separate item.
+ Optional idempotency token (at most 256 UTF-8 bytes).
+ Re-uploading under the same token overwrites the same item
+ instead of adding a new one. The token is scoped to this job;
+ the same token in another job is independent and creates a
+ separate item.
id : typing.Optional[str]
- Optional caller-supplied correlation label (max 512 bytes),
- echoed back on status and result listings so you can match the
- server's item_id to your own record.
+ Optional caller-supplied correlation label (at most 512 UTF-8
+ bytes), echoed back on status and result listings so you can
+ match the server's item_id to your own record.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -281,8 +281,8 @@ def finalize(self, job_id: str, *, request_options: typing.Optional[RequestOptio
def cancel(self, job_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> BatchJob:
"""
- Drives a job to the terminal `canceled` state on request, freeing its
- active-job slot immediately. Takes no request body.
+ Drives a job to the terminal `canceled` state on request. Takes no
+ request body.
Cancel does not delete the job: the job record and any results already
produced are preserved for the normal retention window, the same as a
@@ -554,16 +554,15 @@ async def create(
finalized is released for a fresh replay; once a job is finalized, its
`request_id` keeps resolving to it even after cancellation.
- An instance may hold at most 4 active (pending or processing) jobs at
- once; a create past that limit returns `409`. The limit is instance-wide
- — jobs are shared across the instance's credentials — so another
- credential's jobs count against it.
+ There is no limit on how many jobs an instance may hold at once; how many
+ items run in parallel is a property of the instance, not of the job count.
Parameters
----------
request_id : typing.Optional[str]
- Optional client idempotency token. A retried create with the same
- token returns the original job instead of opening a second one.
+ Optional client idempotency token (at most 256 UTF-8 bytes). A
+ retried create with the same token returns the original job instead
+ of opening a second one.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -617,7 +616,7 @@ async def upload_item(
- Set **exactly one** of `document` or `create`. Setting both, or
neither, is a `400`.
- When `document` is set, `file` is **required** — it supplies the
- document's binary content (PDF or image).
+ document's file content (PDF, image, RTF, or XML/C-CDA).
- When `create` is set, `file` is **forbidden** — a create item carries
no file.
- `document` and `create` must each be a JSON **object**.
@@ -674,15 +673,16 @@ async def upload_item(
See core.File for more documentation
request_id : typing.Optional[str]
- Optional idempotency token (max 256 bytes). Re-uploading under
- the same token overwrites the same item instead of adding a
- new one. The token is scoped to this job; the same token in
- another job is independent and creates a separate item.
+ Optional idempotency token (at most 256 UTF-8 bytes).
+ Re-uploading under the same token overwrites the same item
+ instead of adding a new one. The token is scoped to this job;
+ the same token in another job is independent and creates a
+ separate item.
id : typing.Optional[str]
- Optional caller-supplied correlation label (max 512 bytes),
- echoed back on status and result listings so you can match the
- server's item_id to your own record.
+ Optional caller-supplied correlation label (at most 512 UTF-8
+ bytes), echoed back on status and result listings so you can
+ match the server's item_id to your own record.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -769,8 +769,8 @@ async def main() -> None:
async def cancel(self, job_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> BatchJob:
"""
- Drives a job to the terminal `canceled` state on request, freeing its
- active-job slot immediately. Takes no request body.
+ Drives a job to the terminal `canceled` state on request. Takes no
+ request body.
Cancel does not delete the job: the job record and any results already
produced are preserved for the normal retention window, the same as a
diff --git a/src/phenoml/lang2fhir_batch/raw_client.py b/src/phenoml/lang2fhir_batch/raw_client.py
index 8873fac..d72d92e 100644
--- a/src/phenoml/lang2fhir_batch/raw_client.py
+++ b/src/phenoml/lang2fhir_batch/raw_client.py
@@ -161,16 +161,15 @@ def create(
finalized is released for a fresh replay; once a job is finalized, its
`request_id` keeps resolving to it even after cancellation.
- An instance may hold at most 4 active (pending or processing) jobs at
- once; a create past that limit returns `409`. The limit is instance-wide
- — jobs are shared across the instance's credentials — so another
- credential's jobs count against it.
+ There is no limit on how many jobs an instance may hold at once; how many
+ items run in parallel is a property of the instance, not of the job count.
Parameters
----------
request_id : typing.Optional[str]
- Optional client idempotency token. A retried create with the same
- token returns the original job instead of opening a second one.
+ Optional client idempotency token (at most 256 UTF-8 bytes). A
+ retried create with the same token returns the original job instead
+ of opening a second one.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -224,17 +223,6 @@ def create(
),
),
)
- if _response.status_code == 409:
- raise ConflictError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Any,
- parse_obj_as(
- type_=typing.Any, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
if _response.status_code == 499:
raise ClientClosedRequestError(
headers=dict(_response.headers),
@@ -298,7 +286,7 @@ def upload_item(
- Set **exactly one** of `document` or `create`. Setting both, or
neither, is a `400`.
- When `document` is set, `file` is **required** — it supplies the
- document's binary content (PDF or image).
+ document's file content (PDF, image, RTF, or XML/C-CDA).
- When `create` is set, `file` is **forbidden** — a create item carries
no file.
- `document` and `create` must each be a JSON **object**.
@@ -355,15 +343,16 @@ def upload_item(
See core.File for more documentation
request_id : typing.Optional[str]
- Optional idempotency token (max 256 bytes). Re-uploading under
- the same token overwrites the same item instead of adding a
- new one. The token is scoped to this job; the same token in
- another job is independent and creates a separate item.
+ Optional idempotency token (at most 256 UTF-8 bytes).
+ Re-uploading under the same token overwrites the same item
+ instead of adding a new one. The token is scoped to this job;
+ the same token in another job is independent and creates a
+ separate item.
id : typing.Optional[str]
- Optional caller-supplied correlation label (max 512 bytes),
- echoed back on status and result listings so you can match the
- server's item_id to your own record.
+ Optional caller-supplied correlation label (at most 512 UTF-8
+ bytes), echoed back on status and result listings so you can
+ match the server's item_id to your own record.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -630,8 +619,8 @@ def finalize(
def cancel(self, job_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> HttpResponse[BatchJob]:
"""
- Drives a job to the terminal `canceled` state on request, freeing its
- active-job slot immediately. Takes no request body.
+ Drives a job to the terminal `canceled` state on request. Takes no
+ request body.
Cancel does not delete the job: the job record and any results already
produced are preserved for the normal retention window, the same as a
@@ -1265,16 +1254,15 @@ async def create(
finalized is released for a fresh replay; once a job is finalized, its
`request_id` keeps resolving to it even after cancellation.
- An instance may hold at most 4 active (pending or processing) jobs at
- once; a create past that limit returns `409`. The limit is instance-wide
- — jobs are shared across the instance's credentials — so another
- credential's jobs count against it.
+ There is no limit on how many jobs an instance may hold at once; how many
+ items run in parallel is a property of the instance, not of the job count.
Parameters
----------
request_id : typing.Optional[str]
- Optional client idempotency token. A retried create with the same
- token returns the original job instead of opening a second one.
+ Optional client idempotency token (at most 256 UTF-8 bytes). A
+ retried create with the same token returns the original job instead
+ of opening a second one.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -1328,17 +1316,6 @@ async def create(
),
),
)
- if _response.status_code == 409:
- raise ConflictError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Any,
- parse_obj_as(
- type_=typing.Any, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
if _response.status_code == 499:
raise ClientClosedRequestError(
headers=dict(_response.headers),
@@ -1402,7 +1379,7 @@ async def upload_item(
- Set **exactly one** of `document` or `create`. Setting both, or
neither, is a `400`.
- When `document` is set, `file` is **required** — it supplies the
- document's binary content (PDF or image).
+ document's file content (PDF, image, RTF, or XML/C-CDA).
- When `create` is set, `file` is **forbidden** — a create item carries
no file.
- `document` and `create` must each be a JSON **object**.
@@ -1459,15 +1436,16 @@ async def upload_item(
See core.File for more documentation
request_id : typing.Optional[str]
- Optional idempotency token (max 256 bytes). Re-uploading under
- the same token overwrites the same item instead of adding a
- new one. The token is scoped to this job; the same token in
- another job is independent and creates a separate item.
+ Optional idempotency token (at most 256 UTF-8 bytes).
+ Re-uploading under the same token overwrites the same item
+ instead of adding a new one. The token is scoped to this job;
+ the same token in another job is independent and creates a
+ separate item.
id : typing.Optional[str]
- Optional caller-supplied correlation label (max 512 bytes),
- echoed back on status and result listings so you can match the
- server's item_id to your own record.
+ Optional caller-supplied correlation label (at most 512 UTF-8
+ bytes), echoed back on status and result listings so you can
+ match the server's item_id to your own record.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
@@ -1736,8 +1714,8 @@ async def cancel(
self, job_id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> AsyncHttpResponse[BatchJob]:
"""
- Drives a job to the terminal `canceled` state on request, freeing its
- active-job slot immediately. Takes no request body.
+ Drives a job to the terminal `canceled` state on request. Takes no
+ request body.
Cancel does not delete the job: the job record and any results already
produced are preserved for the normal retention window, the same as a
diff --git a/src/phenoml/lang2fhir_batch/types/batch_error.py b/src/phenoml/lang2fhir_batch/types/batch_error.py
index 29efa45..396e45a 100644
--- a/src/phenoml/lang2fhir_batch/types/batch_error.py
+++ b/src/phenoml/lang2fhir_batch/types/batch_error.py
@@ -15,12 +15,10 @@ class BatchError(UniversalBaseModel):
"""
Short stable token to branch on. Item-level kinds: `invalid_input`
(the stored body was not a valid create/document request),
- `processing_failed` (the conversion failed), `budget_exceeded` (the
- item ran past its time budget — 600s for a document item, 450s for a
- create item), `result_too_large` (the result exceeded the storage
- cap), `input_unavailable` (the input could not be read), and
- `retries_exhausted` / `attempts_exhausted` (buried after too many
- failed attempts).
+ `processing_failed` (the conversion failed), `result_too_large` (the
+ result exceeded the storage cap), `input_unavailable` (the input
+ could not be read), and `retries_exhausted` / `attempts_exhausted`
+ (the item could not complete after repeated interruptions).
Job-level kinds: `timeout` (the job did not finish within 36 hours
of creation).
"""
diff --git a/src/phenoml/lang2fhir_batch/types/batch_item_status.py b/src/phenoml/lang2fhir_batch/types/batch_item_status.py
index e2da4e9..84e5f98 100644
--- a/src/phenoml/lang2fhir_batch/types/batch_item_status.py
+++ b/src/phenoml/lang2fhir_batch/types/batch_item_status.py
@@ -31,9 +31,8 @@ class BatchItemStatus(UniversalBaseModel):
attempts: int = pydantic.Field()
"""
- Number of processing attempts so far. An item runs up to 3 attempts,
- and only an interruption — a worker preemption or a recovered internal
- error — is retried; a conversion error fails the item with no retry.
+ Number of processing attempts started so far. The service may retry
+ interrupted work; a conversion error fails the item without retry.
"""
detect_retries: typing.Optional[int] = pydantic.Field(default=None)
diff --git a/src/phenoml/lang2fhir_batch/types/batch_job.py b/src/phenoml/lang2fhir_batch/types/batch_job.py
index a574933..91bd46b 100644
--- a/src/phenoml/lang2fhir_batch/types/batch_job.py
+++ b/src/phenoml/lang2fhir_batch/types/batch_job.py
@@ -31,8 +31,8 @@ class BatchJob(UniversalBaseModel):
failure (the job could not run at all), distinct from individual item
failures, which never fail the job. `canceled` is a caller-requested
cancellation via `POST /lang2fhir/batch/{job_id}/cancel`; like the
- other terminal states it frees the job's active-job slot and keeps any
- results already produced readable for the retention window.
+ other terminal states it keeps any results already produced readable
+ for the retention window.
"""
finalized: bool = pydantic.Field()
diff --git a/src/phenoml/profiles/profiles/raw_client.py b/src/phenoml/profiles/profiles/raw_client.py
index 907ac1d..54ef7fc 100644
--- a/src/phenoml/profiles/profiles/raw_client.py
+++ b/src/phenoml/profiles/profiles/raw_client.py
@@ -527,6 +527,17 @@ def delete(self, id: str, *, request_options: typing.Optional[RequestOptions] =
),
),
)
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
if _response.status_code == 500:
raise InternalServerError(
headers=dict(_response.headers),
@@ -1051,6 +1062,17 @@ async def delete(
),
),
)
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
if _response.status_code == 500:
raise InternalServerError(
headers=dict(_response.headers),
diff --git a/src/phenoml/profiles/versions/raw_client.py b/src/phenoml/profiles/versions/raw_client.py
index 0a1e0c1..7f77e6e 100644
--- a/src/phenoml/profiles/versions/raw_client.py
+++ b/src/phenoml/profiles/versions/raw_client.py
@@ -429,6 +429,17 @@ def delete(
),
),
)
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
if _response.status_code == 500:
raise InternalServerError(
headers=dict(_response.headers),
@@ -853,6 +864,17 @@ async def delete(
),
),
)
+ if _response.status_code == 409:
+ raise ConflictError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ typing.Any,
+ parse_obj_as(
+ type_=typing.Any, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
if _response.status_code == 500:
raise InternalServerError(
headers=dict(_response.headers),
diff --git a/tests/utils/test_http_client.py b/tests/utils/test_http_client.py
index 732c2f9..4cf2992 100644
--- a/tests/utils/test_http_client.py
+++ b/tests/utils/test_http_client.py
@@ -11,6 +11,7 @@
HttpClient,
_build_url,
_should_retry,
+ drop_content_type_without_body,
get_request_body,
remove_none_from_dict,
)
@@ -121,6 +122,67 @@ def test_explicit_empty_json_body_is_preserved() -> None:
assert data_body2 == {}
+def test_omitted_body_sends_no_content() -> None:
+ """A body left at the sentinel was never passed, so nothing is sent.
+
+ This is how an endpoint whose body may be omitted stays bodyless, as opposed to
+ sending an empty ``{}``. An explicit ``None`` still reaches the wire as ``null``.
+ """
+ omit = cast(Any, ...)
+ unrelated_request_options: RequestOptions = {"max_retries": 3}
+
+ json_body, data_body = get_request_body(json=omit, data=None, request_options=unrelated_request_options, omit=omit)
+ assert json_body is None
+ assert data_body is None
+
+ json_body2, data_body2 = get_request_body(
+ json=None, data=omit, request_options=unrelated_request_options, omit=omit
+ )
+ assert json_body2 is None
+ assert data_body2 is None
+
+ # an explicitly passed body is untouched
+ json_body3, _ = get_request_body(json={"hello": "world"}, data=None, request_options=None, omit=omit)
+ assert json_body3 == {"hello": "world"}
+
+
+def test_optional_body_sends_no_content_when_every_property_is_omitted() -> None:
+ """An endpoint that inlines an omittable body sends nothing once every property is omitted.
+
+ The body reaches the client as a dict of sentinels rather than as a single argument, so
+ ``optional_body`` is what tells the client that an empty result means "no body at all".
+ """
+ omit = cast(Any, ...)
+
+ json_body, data_body = get_request_body(
+ json={"amount": omit, "source": omit}, data=None, request_options=None, omit=omit, optional_body=True
+ )
+ assert json_body is None
+ assert data_body is None
+
+ # a body the API requires still goes out as `{}`
+ required_json_body, _ = get_request_body(
+ json={"amount": omit, "source": omit}, data=None, request_options=None, omit=omit
+ )
+ assert required_json_body == {}
+
+ # a property the caller did pass keeps the body
+ populated_json_body, _ = get_request_body(
+ json={"amount": 1, "source": omit}, data=None, request_options=None, omit=omit, optional_body=True
+ )
+ assert populated_json_body == {"amount": 1}
+
+ # additional body parameters keep the body, since the caller asked for them
+ with_additional_body_parameters, _ = get_request_body(
+ json={"amount": omit},
+ data=None,
+ request_options={"additional_body_parameters": {"custom": "value"}},
+ omit=omit,
+ optional_body=True,
+ )
+ assert with_additional_body_parameters == {"custom": "value"}
+
+
def test_json_body_preserves_none_values() -> None:
"""Test that JSON bodies preserve None values (they become JSON null)."""
json_body, data_body = get_request_body(
@@ -672,28 +734,20 @@ def _make_response(status_code: int) -> httpx.Response:
return httpx.Response(status_code=status_code, content=b"")
-@pytest.mark.parametrize(
- "status_code",
- [408, 409, 429, 500, 501, 502, 503, 504, 599],
-)
+RETRYABLE_STATUS_CODES = [408, 409, 429, 500, 501, 502, 503, 504, 599]
+NON_RETRYABLE_STATUS_CODES = [200, 201, 301, 400, 401, 403, 404]
+
+
+@pytest.mark.parametrize("status_code", RETRYABLE_STATUS_CODES)
def test_should_retry_retryable_status_codes(status_code: int) -> None:
- """Legacy mode: retries on 408, 409, 429, and all >= 500."""
assert _should_retry(_make_response(status_code)) is True
-@pytest.mark.parametrize(
- "status_code",
- [200, 201, 301, 400, 401, 403, 404],
-)
+@pytest.mark.parametrize("status_code", NON_RETRYABLE_STATUS_CODES)
def test_should_not_retry_non_retryable_status_codes(status_code: int) -> None:
assert _should_retry(_make_response(status_code)) is False
-def test_should_retry_599_upper_boundary() -> None:
- """Legacy mode retries on >= 500, which includes 599."""
- assert _should_retry(_make_response(599)) is True
-
-
# ---------------------------------------------------------------------------
# RequestOptions timeout resolution tests (timeout / deprecated timeout_in_seconds)
# ---------------------------------------------------------------------------
@@ -759,3 +813,33 @@ async def test_async_request_options_timeout_takes_precedence() -> None:
)
await http_client.request(path="/test", method="GET", request_options={"timeout": 30, "timeout_in_seconds": 45})
assert dummy_client.last_request_kwargs["timeout"] == 30
+
+
+def test_drop_content_type_without_body_omits_header_for_bodyless_optional_call() -> None:
+ """An optional-body endpoint the caller left empty must not advertise a media type.
+
+ `get_request_body` drops the body, but the endpoint still hands over the content type it
+ would have used, so a server that branches on the header would see a JSON request carrying
+ nothing at all.
+ """
+ headers = {"content-type": "application/json", "authorization": "Bearer x"}
+
+ assert drop_content_type_without_body(headers, json_body=None, data_body=None, optional_body=True) == {
+ "authorization": "Bearer x"
+ }
+
+
+def test_drop_content_type_without_body_keeps_header_when_a_body_is_sent() -> None:
+ headers = {"content-type": "application/json"}
+
+ assert (
+ drop_content_type_without_body(headers, json_body={"amount": 60}, data_body=None, optional_body=True) == headers
+ )
+ assert drop_content_type_without_body(headers, json_body=None, data_body="raw", optional_body=True) == headers
+
+
+def test_drop_content_type_without_body_leaves_required_body_endpoints_alone() -> None:
+ """Without the opt-in, an endpoint keeps the header it has always sent."""
+ headers = {"Content-Type": "application/json"}
+
+ assert drop_content_type_without_body(headers, json_body=None, data_body=None, optional_body=False) == headers
diff --git a/tests/wire/test_implementationGuides_implementationGuides.py b/tests/wire/test_implementationGuides_implementationGuides.py
index f65a229..f0cef92 100644
--- a/tests/wire/test_implementationGuides_implementationGuides.py
+++ b/tests/wire/test_implementationGuides_implementationGuides.py
@@ -1,5 +1,7 @@
from .conftest import get_client, verify_request_count
+from phenoml.implementation_guides import FhirImplementationGuide
+
def test_implementationGuides_implementationGuides_list_() -> None:
"""Test list endpoint with WireMock"""
@@ -37,3 +39,30 @@ def test_implementationGuides_implementationGuides_delete() -> None:
name="acme-cardiology",
)
verify_request_count(test_id, "DELETE", "/fhir/implementation-guides/acme-cardiology", None, 1)
+
+
+def test_implementationGuides_implementationGuides_create_version() -> None:
+ """Test createVersion endpoint with WireMock"""
+ test_id = "implementation_guides.implementation_guides.create_version.0"
+ client = get_client(test_id)
+ client.implementation_guides.implementation_guides.create_version(
+ name="name",
+ implementation_guide=FhirImplementationGuide(
+ resource_type="ImplementationGuide",
+ url="url",
+ version="version",
+ ),
+ profile_refs=["profile_refs"],
+ )
+ verify_request_count(test_id, "POST", "/fhir/implementation-guides/name/versions", None, 1)
+
+
+def test_implementationGuides_implementationGuides_get_version() -> None:
+ """Test getVersion endpoint with WireMock"""
+ test_id = "implementation_guides.implementation_guides.get_version.0"
+ client = get_client(test_id)
+ client.implementation_guides.implementation_guides.get_version(
+ name="name",
+ version="1.0.0",
+ )
+ verify_request_count(test_id, "GET", "/fhir/implementation-guides/name/versions/1.0.0", None, 1)
diff --git a/tests/wire/test_lang2Fhir.py b/tests/wire/test_lang2Fhir.py
index 8095b87..5e23cb8 100644
--- a/tests/wire/test_lang2Fhir.py
+++ b/tests/wire/test_lang2Fhir.py
@@ -55,7 +55,7 @@ def test_lang2Fhir_document() -> None:
client.lang2fhir.document(
version="R4",
resource="questionnaire",
- content="JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)",
+ content="JVBERi0xLjQKJeLjz9MK...(base64-encoded document bytes)",
)
verify_request_count(test_id, "POST", "/lang2fhir/document", None, 1)
@@ -66,7 +66,7 @@ def test_lang2Fhir_document_multi() -> None:
client = get_client(test_id)
client.lang2fhir.document_multi(
version="R4",
- content="JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)",
+ content="JVBERi0xLjQKJeLjz9MK...(base64-encoded document bytes)",
provider="medplum",
config=DocumentConfig(
split_classifications=[
diff --git a/wiremock/wiremock-mappings.json b/wiremock/wiremock-mappings.json
index 9d3fc77..1f0e821 100644
--- a/wiremock/wiremock-mappings.json
+++ b/wiremock/wiremock-mappings.json
@@ -5,7 +5,12 @@
"name": "Create a new agent - default",
"request": {
"urlPathTemplate": "/agent/create",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 201,
@@ -32,6 +37,11 @@
"request": {
"urlPathTemplate": "/agent/list",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"queryParameters": {
"tags": {
"equalTo": "tags"
@@ -64,6 +74,11 @@
"request": {
"urlPathTemplate": "/agent/{id}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "id"
@@ -95,6 +110,11 @@
"request": {
"urlPathTemplate": "/agent/{id}",
"method": "PUT",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "id"
@@ -126,6 +146,11 @@
"request": {
"urlPathTemplate": "/agent/{id}",
"method": "DELETE",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "id"
@@ -157,6 +182,11 @@
"request": {
"urlPathTemplate": "/agent/{id}",
"method": "PATCH",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "id"
@@ -187,7 +217,12 @@
"name": "Chat with agent - Query Patient Condition",
"request": {
"urlPathTemplate": "/agent/chat",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -213,7 +248,12 @@
"name": "Chat with agent (streaming) - default",
"request": {
"urlPathTemplate": "/agent/stream-chat",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -240,6 +280,11 @@
"request": {
"urlPathTemplate": "/agent/chat/messages",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"queryParameters": {
"chat_session_id": {
"equalTo": "chat_session_id"
@@ -280,7 +325,12 @@
"name": "Create agent prompt - default",
"request": {
"urlPathTemplate": "/agent/prompts",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 201,
@@ -306,7 +356,12 @@
"name": "List agent prompts - default",
"request": {
"urlPathTemplate": "/agent/prompts/list",
- "method": "GET"
+ "method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -334,6 +389,11 @@
"request": {
"urlPathTemplate": "/agent/prompts/{id}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "id"
@@ -365,6 +425,11 @@
"request": {
"urlPathTemplate": "/agent/prompts/{id}",
"method": "PUT",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "id"
@@ -396,6 +461,11 @@
"request": {
"urlPathTemplate": "/agent/prompts/{id}",
"method": "DELETE",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "id"
@@ -427,6 +497,11 @@
"request": {
"urlPathTemplate": "/agent/prompts/{id}",
"method": "PATCH",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "id"
@@ -483,7 +558,12 @@
"name": "Analyze text for patient cohort criteria - default",
"request": {
"urlPathTemplate": "/cohort",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -509,7 +589,12 @@
"name": "Upload custom code system - JSON codes (preferred)",
"request": {
"urlPathTemplate": "/construe/upload",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 202,
@@ -535,7 +620,12 @@
"name": "List available code systems - default",
"request": {
"urlPathTemplate": "/construe/codes/systems",
- "method": "GET"
+ "method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -563,6 +653,11 @@
"request": {
"urlPathTemplate": "/construe/codes/systems/{codesystem}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"codesystem": {
"equalTo": "ICD-10-CM"
@@ -599,6 +694,11 @@
"request": {
"urlPathTemplate": "/construe/codes/systems/{codesystem}",
"method": "DELETE",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"codesystem": {
"equalTo": "CUSTOM_CODES"
@@ -635,6 +735,11 @@
"request": {
"urlPathTemplate": "/construe/codes/systems/{codesystem}/export",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"codesystem": {
"equalTo": "CUSTOM_CODES"
@@ -670,7 +775,12 @@
"name": "Submit feedback on extraction results - default",
"request": {
"urlPathTemplate": "/construe/feedback",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 201,
@@ -696,7 +806,12 @@
"name": "Extract medical codes from text - Basic Extraction",
"request": {
"urlPathTemplate": "/construe/extract",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -722,7 +837,12 @@
"name": "[Alpha] Extract medical codes with phenocr - HPO Phenotype Extraction",
"request": {
"urlPathTemplate": "/construe/phenocr",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -748,7 +868,12 @@
"name": "Crosswalk a code to target code systems - ICD-10-CM to HPO",
"request": {
"urlPathTemplate": "/construe/codes/crosswalk",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -775,6 +900,11 @@
"request": {
"urlPathTemplate": "/construe/codes/{codesystem}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"codesystem": {
"equalTo": "ICD-10-CM"
@@ -817,6 +947,11 @@
"request": {
"urlPathTemplate": "/construe/codes/{codesystem}/{codeID}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"codesystem": {
"equalTo": "ICD-10-CM"
@@ -856,6 +991,11 @@
"request": {
"urlPathTemplate": "/construe/codes/{codesystem}/search/semantic",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"codesystem": {
"equalTo": "ICD-10-CM"
@@ -898,6 +1038,11 @@
"request": {
"urlPathTemplate": "/construe/codes/{codesystem}/search/text",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"codesystem": {
"equalTo": "ICD-10-CM"
@@ -940,6 +1085,11 @@
"request": {
"urlPathTemplate": "/fhir-provider/{fhir_provider_id}/fhir/{fhir_path}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"fhir_provider_id": {
"equalTo": "550e8400-e29b-41d4-a716-446655440000"
@@ -974,6 +1124,11 @@
"request": {
"urlPathTemplate": "/fhir-provider/{fhir_provider_id}/fhir/{fhir_path}",
"method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"fhir_provider_id": {
"equalTo": "550e8400-e29b-41d4-a716-446655440000"
@@ -1008,6 +1163,11 @@
"request": {
"urlPathTemplate": "/fhir-provider/{fhir_provider_id}/fhir/{fhir_path}",
"method": "PUT",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"fhir_provider_id": {
"equalTo": "550e8400-e29b-41d4-a716-446655440000"
@@ -1042,6 +1202,11 @@
"request": {
"urlPathTemplate": "/fhir-provider/{fhir_provider_id}/fhir/{fhir_path}",
"method": "DELETE",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"fhir_provider_id": {
"equalTo": "550e8400-e29b-41d4-a716-446655440000"
@@ -1076,6 +1241,11 @@
"request": {
"urlPathTemplate": "/fhir-provider/{fhir_provider_id}/fhir/{fhir_path}",
"method": "PATCH",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"fhir_provider_id": {
"equalTo": "550e8400-e29b-41d4-a716-446655440000"
@@ -1110,6 +1280,11 @@
"request": {
"urlPathTemplate": "/fhir-provider/{fhir_provider_id}/fhir",
"method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"fhir_provider_id": {
"equalTo": "550e8400-e29b-41d4-a716-446655440000"
@@ -1140,7 +1315,12 @@
"name": "Map FHIR resources to OMOP CDM v5.4 - Mapping result",
"request": {
"urlPathTemplate": "/fhir2omop/create",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -1166,7 +1346,12 @@
"name": "Create FHIR provider - default",
"request": {
"urlPathTemplate": "/fhir-provider",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 201,
@@ -1192,7 +1377,12 @@
"name": "List FHIR providers - default",
"request": {
"urlPathTemplate": "/fhir-provider/list",
- "method": "GET"
+ "method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -1220,6 +1410,11 @@
"request": {
"urlPathTemplate": "/fhir-provider/{fhir_provider_id}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"fhir_provider_id": {
"equalTo": "fhir_provider_id"
@@ -1251,6 +1446,11 @@
"request": {
"urlPathTemplate": "/fhir-provider/{fhir_provider_id}",
"method": "DELETE",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"fhir_provider_id": {
"equalTo": "fhir_provider_id"
@@ -1282,6 +1482,11 @@
"request": {
"urlPathTemplate": "/fhir-provider/{fhir_provider_id}/add-auth-config",
"method": "PATCH",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"fhir_provider_id": {
"equalTo": "1716d214-de93-43a4-aa6b-a878d864e2ad"
@@ -1313,6 +1518,11 @@
"request": {
"urlPathTemplate": "/fhir-provider/{fhir_provider_id}/set-active-auth-config",
"method": "PATCH",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"fhir_provider_id": {
"equalTo": "1716d214-de93-43a4-aa6b-a878d864e2ad"
@@ -1344,6 +1554,11 @@
"request": {
"urlPathTemplate": "/fhir-provider/{fhir_provider_id}/remove-auth-config",
"method": "PATCH",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"fhir_provider_id": {
"equalTo": "1716d214-de93-43a4-aa6b-a878d864e2ad"
@@ -1374,11 +1589,16 @@
"name": "List implementation guides - default",
"request": {
"urlPathTemplate": "/fhir/implementation-guides",
- "method": "GET"
+ "method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
- "body": "{\n \"implementation_guides\": [\n {\n \"name\": \"acme-cardiology\",\n \"profile_context\": \"When the text mentions phenotypic features, prefer the hpo-observation profile over Condition.\",\n \"profile_count\": 3,\n \"created_at\": \"2024-01-15T09:30:00Z\",\n \"updated_at\": \"2024-01-15T09:30:00Z\"\n }\n ]\n}",
+ "body": "{\n \"implementation_guides\": [\n {\n \"name\": \"acme-cardiology\",\n \"profile_context\": \"When the text mentions phenotypic features, prefer the hpo-observation profile over Condition.\",\n \"profile_count\": 3,\n \"canonical_url\": \"canonical_url\",\n \"version_count\": 1,\n \"created_at\": \"2024-01-15T09:30:00Z\",\n \"updated_at\": \"2024-01-15T09:30:00Z\"\n }\n ]\n}",
"headers": {
"Content-Type": "application/json"
}
@@ -1402,6 +1622,11 @@
"request": {
"urlPathTemplate": "/fhir/implementation-guides/{name}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"name": {
"equalTo": "acme-cardiology"
@@ -1410,7 +1635,7 @@
},
"response": {
"status": 200,
- "body": "{\n \"name\": \"acme-cardiology\",\n \"profile_context\": \"When the text mentions phenotypic features, prefer the hpo-observation profile over Condition.\",\n \"profile_count\": 3,\n \"created_at\": \"2024-01-15T09:30:00Z\",\n \"updated_at\": \"2024-01-15T09:30:00Z\",\n \"profiles\": [\n \"custom-patient\",\n \"acme-vital-signs\"\n ]\n}",
+ "body": "{\n \"name\": \"acme-cardiology\",\n \"profile_context\": \"When the text mentions phenotypic features, prefer the hpo-observation profile over Condition.\",\n \"profile_count\": 3,\n \"canonical_url\": \"canonical_url\",\n \"version_count\": 1,\n \"created_at\": \"2024-01-15T09:30:00Z\",\n \"updated_at\": \"2024-01-15T09:30:00Z\",\n \"profiles\": [\n \"custom-patient\",\n \"acme-vital-signs\"\n ]\n}",
"headers": {
"Content-Type": "application/json"
}
@@ -1433,6 +1658,11 @@
"request": {
"urlPathTemplate": "/fhir/implementation-guides/{name}",
"method": "PUT",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"name": {
"equalTo": "acme-cardiology"
@@ -1441,7 +1671,7 @@
},
"response": {
"status": 200,
- "body": "{\n \"name\": \"acme-cardiology\",\n \"profile_context\": \"When the text mentions phenotypic features, prefer the hpo-observation profile over Condition.\",\n \"profile_count\": 3,\n \"created_at\": \"2024-01-15T09:30:00Z\",\n \"updated_at\": \"2024-01-15T09:30:00Z\"\n}",
+ "body": "{\n \"name\": \"acme-cardiology\",\n \"profile_context\": \"When the text mentions phenotypic features, prefer the hpo-observation profile over Condition.\",\n \"profile_count\": 3,\n \"canonical_url\": \"canonical_url\",\n \"version_count\": 1,\n \"created_at\": \"2024-01-15T09:30:00Z\",\n \"updated_at\": \"2024-01-15T09:30:00Z\"\n}",
"headers": {
"Content-Type": "application/json"
}
@@ -1459,11 +1689,16 @@
}
},
{
- "id": "44652922-4793-4275-840e-4dc1b1bde786",
- "name": "Delete an implementation guide's metadata - default",
+ "id": "2678a6e7-10b0-4621-ad5c-67980574a8f8",
+ "name": "Delete an implementation guide family - default",
"request": {
"urlPathTemplate": "/fhir/implementation-guides/{name}",
"method": "DELETE",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"name": {
"equalTo": "acme-cardiology"
@@ -1477,7 +1712,82 @@
"Content-Type": "application/json"
}
},
- "uuid": "44652922-4793-4275-840e-4dc1b1bde786",
+ "uuid": "2678a6e7-10b0-4621-ad5c-67980574a8f8",
+ "persistent": true,
+ "priority": 3,
+ "metadata": {
+ "mocklab": {
+ "created": {
+ "at": "2020-01-01T00:00:00.000Z",
+ "via": "SYSTEM"
+ }
+ }
+ }
+ },
+ {
+ "id": "a7a30315-de87-4485-a1e4-15eeea48b530",
+ "name": "Publish an exact custom-profile package - default",
+ "request": {
+ "urlPathTemplate": "/fhir/implementation-guides/{name}/versions",
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
+ "pathParameters": {
+ "name": {
+ "equalTo": "name"
+ }
+ }
+ },
+ "response": {
+ "status": 201,
+ "body": "{\n \"name\": \"name\",\n \"url\": \"url\",\n \"version\": \"version\",\n \"profile_context\": \"profile_context\",\n \"profiles\": [\n \"profiles\"\n ],\n \"profile_refs\": [\n \"profile_refs\"\n ],\n \"implementation_guide\": {\n \"resourceType\": \"ImplementationGuide\",\n \"id\": \"id\",\n \"url\": \"url\",\n \"version\": \"version\",\n \"name\": \"name\",\n \"status\": \"status\",\n \"packageId\": \"packageId\",\n \"fhirVersion\": [\n \"fhirVersion\"\n ]\n },\n \"created_at\": \"2024-01-15T09:30:00Z\",\n \"updated_at\": \"2024-01-15T09:30:00Z\"\n}",
+ "headers": {
+ "Content-Type": "application/json"
+ }
+ },
+ "uuid": "a7a30315-de87-4485-a1e4-15eeea48b530",
+ "persistent": true,
+ "priority": 3,
+ "metadata": {
+ "mocklab": {
+ "created": {
+ "at": "2020-01-01T00:00:00.000Z",
+ "via": "SYSTEM"
+ }
+ }
+ }
+ },
+ {
+ "id": "bfd69c60-e799-438e-a780-2c4c1fd1a9a8",
+ "name": "Get an exact custom-profile package - default",
+ "request": {
+ "urlPathTemplate": "/fhir/implementation-guides/{name}/versions/{version}",
+ "method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
+ "pathParameters": {
+ "name": {
+ "equalTo": "name"
+ },
+ "version": {
+ "equalTo": "1.0.0"
+ }
+ }
+ },
+ "response": {
+ "status": 200,
+ "body": "{\n \"name\": \"name\",\n \"url\": \"url\",\n \"version\": \"version\",\n \"profile_context\": \"profile_context\",\n \"profiles\": [\n \"profiles\"\n ],\n \"profile_refs\": [\n \"profile_refs\"\n ],\n \"implementation_guide\": {\n \"resourceType\": \"ImplementationGuide\",\n \"id\": \"id\",\n \"url\": \"url\",\n \"version\": \"version\",\n \"name\": \"name\",\n \"status\": \"status\",\n \"packageId\": \"packageId\",\n \"fhirVersion\": [\n \"fhirVersion\"\n ]\n },\n \"created_at\": \"2024-01-15T09:30:00Z\",\n \"updated_at\": \"2024-01-15T09:30:00Z\"\n}",
+ "headers": {
+ "Content-Type": "application/json"
+ }
+ },
+ "uuid": "bfd69c60-e799-438e-a780-2c4c1fd1a9a8",
"persistent": true,
"priority": 3,
"metadata": {
@@ -1494,7 +1804,12 @@
"name": "Create FHIR resource from text - Condition Resource",
"request": {
"urlPathTemplate": "/lang2fhir/create",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -1520,11 +1835,16 @@
"name": "Extract multiple FHIR resources from text - Full Patient Record",
"request": {
"urlPathTemplate": "/lang2fhir/create/multi",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
- "body": "{\n \"success\": true,\n \"message\": \"Successfully extracted 3 resources\",\n \"bundle\": {\n \"resourceType\": \"Bundle\",\n \"type\": \"transaction\",\n \"entry\": [\n {\n \"fullUrl\": \"urn:uuid:patient-001\",\n \"resource\": {\n \"resourceType\": \"Patient\",\n \"name\": [\n {\n \"given\": [\n \"John\"\n ],\n \"family\": \"Smith\"\n }\n ],\n \"gender\": \"male\"\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Patient\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:condition-001\",\n \"resource\": {\n \"resourceType\": \"Condition\",\n \"code\": {\n \"text\": \"Type 2 Diabetes\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Condition\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:medication-001\",\n \"resource\": {\n \"resourceType\": \"MedicationRequest\",\n \"medicationCodeableConcept\": {\n \"text\": \"Metformin 500mg\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"MedicationRequest\"\n }\n }\n ]\n },\n \"resources\": [\n {\n \"tempId\": \"urn:uuid:a842c4bc-f6cb-4555-9741-ac3aec4ef0b8\",\n \"resourceType\": \"Patient\",\n \"description\": \"John Smith (DOB 1980-05-12) was diagnosed with Type 2 Diabetes during office visit on 2025-03-01 with Dr. Chen\",\n \"originalText\": \"diagnosed with Type 2 Diabetes\",\n \"group\": \"clinical\",\n \"sourcePages\": [\n 2\n ]\n }\n ],\n \"validation\": {\n \"passes\": [\n {}\n ],\n \"fixed\": true,\n \"attempts\": 1,\n \"summary\": \"summary\"\n },\n \"resource_review\": {\n \"flagged\": [\n {\n \"tempId\": \"urn:uuid:a842c4bc-f6cb-4555-9741-ac3aec4ef0b8\",\n \"resourceType\": \"Condition\",\n \"findings\": [\n {\n \"fieldPath\": \"onsetDateTime\",\n \"value\": \"2024-01-15\",\n \"supported\": false,\n \"rationale\": \"Date is the visit date, not when the condition began.\"\n }\n ]\n }\n ]\n }\n}",
+ "body": "{\n \"success\": true,\n \"message\": \"Successfully extracted 3 resources\",\n \"bundle\": {\n \"resourceType\": \"Bundle\",\n \"type\": \"transaction\",\n \"entry\": [\n {\n \"fullUrl\": \"urn:uuid:patient-001\",\n \"resource\": {\n \"resourceType\": \"Patient\",\n \"name\": [\n {\n \"given\": [\n \"John\"\n ],\n \"family\": \"Smith\"\n }\n ],\n \"gender\": \"male\"\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Patient\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:condition-001\",\n \"resource\": {\n \"resourceType\": \"Condition\",\n \"code\": {\n \"text\": \"Type 2 Diabetes\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Condition\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:medication-001\",\n \"resource\": {\n \"resourceType\": \"MedicationRequest\",\n \"medicationCodeableConcept\": {\n \"text\": \"Metformin 500mg\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"MedicationRequest\"\n }\n }\n ]\n },\n \"resources\": [\n {\n \"tempId\": \"urn:uuid:a842c4bc-f6cb-4555-9741-ac3aec4ef0b8\",\n \"resourceType\": \"Patient\",\n \"description\": \"John Smith (DOB 1980-05-12) was diagnosed with Type 2 Diabetes during office visit on 2025-03-01 with Dr. Chen\",\n \"originalText\": \"diagnosed with Type 2 Diabetes\",\n \"group\": \"clinical\",\n \"sourcePages\": [\n 2\n ]\n }\n ],\n \"validation\": {\n \"passes\": [\n {}\n ],\n \"fixed\": true,\n \"attempts\": 1,\n \"summary\": \"summary\"\n },\n \"resource_review\": {\n \"flagged\": [\n {\n \"tempId\": \"urn:uuid:a842c4bc-f6cb-4555-9741-ac3aec4ef0b8\",\n \"resourceType\": \"Condition\",\n \"findings\": [\n {\n \"fieldPath\": \"onsetDateTime\",\n \"value\": \"2024-01-15\",\n \"supported\": false,\n \"unaudited\": true,\n \"rationale\": \"Date is the visit date, not when the condition began.\"\n }\n ]\n }\n ],\n \"remediated\": [\n {\n \"tempId\": \"urn:uuid:a842c4bc-f6cb-4555-9741-ac3aec4ef0b8\",\n \"resourceType\": \"Condition\",\n \"findings\": [\n {\n \"fieldPath\": \"onsetDateTime\",\n \"value\": \"2024-01-15\",\n \"supported\": false,\n \"unaudited\": true,\n \"rationale\": \"Date is the visit date, not when the condition began.\"\n }\n ]\n }\n ]\n }\n}",
"headers": {
"Content-Type": "application/json"
}
@@ -1546,7 +1866,12 @@
"name": "Generate FHIR search parameters from text - Search Appointments",
"request": {
"urlPathTemplate": "/lang2fhir/search",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -1572,7 +1897,12 @@
"name": "Upload custom FHIR profile (deprecated) - default",
"request": {
"urlPathTemplate": "/lang2fhir/profile/upload",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 201,
@@ -1598,7 +1928,12 @@
"name": "Convert document to FHIR resource - default",
"request": {
"urlPathTemplate": "/lang2fhir/document",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -1624,11 +1959,16 @@
"name": "Extract multiple FHIR resources from a document - default",
"request": {
"urlPathTemplate": "/lang2fhir/document/multi",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
- "body": "{\n \"success\": true,\n \"message\": \"Successfully extracted 3 resources\",\n \"bundle\": {\n \"resourceType\": \"Bundle\",\n \"type\": \"transaction\",\n \"entry\": [\n {\n \"fullUrl\": \"urn:uuid:patient-001\",\n \"resource\": {\n \"resourceType\": \"Patient\",\n \"meta\": {\n \"tag\": [\n {\n \"system\": \"https://phenoml.com/fhir/split-classification\",\n \"code\": \"clinical\"\n }\n ]\n },\n \"name\": [\n {\n \"given\": [\n \"John\"\n ],\n \"family\": \"Doe\"\n }\n ],\n \"gender\": \"male\",\n \"birthDate\": \"1979-03-15\"\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Patient\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:condition-001\",\n \"resource\": {\n \"resourceType\": \"Condition\",\n \"meta\": {\n \"tag\": [\n {\n \"system\": \"https://phenoml.com/fhir/split-classification\",\n \"code\": \"clinical\"\n }\n ]\n },\n \"code\": {\n \"text\": \"Type 2 Diabetes Mellitus\"\n },\n \"subject\": {\n \"reference\": \"urn:uuid:patient-001\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Condition\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:medication-001\",\n \"resource\": {\n \"resourceType\": \"MedicationRequest\",\n \"meta\": {\n \"tag\": [\n {\n \"system\": \"https://phenoml.com/fhir/split-classification\",\n \"code\": \"clinical\"\n }\n ]\n },\n \"medicationCodeableConcept\": {\n \"text\": \"Metformin 500mg\"\n },\n \"subject\": {\n \"reference\": \"urn:uuid:patient-001\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"MedicationRequest\"\n }\n }\n ]\n },\n \"resources\": [\n {\n \"tempId\": \"urn:uuid:patient-001\",\n \"resourceType\": \"Patient\",\n \"description\": \"John Doe, born 1979-03-15\",\n \"originalText\": \"John Doe, DOB 1979-03-15\",\n \"group\": \"clinical\",\n \"sourcePages\": [\n 1\n ]\n },\n {\n \"tempId\": \"urn:uuid:condition-001\",\n \"resourceType\": \"Condition\",\n \"description\": \"Type 2 Diabetes Mellitus diagnosis\",\n \"originalText\": \"diagnosed with Type 2 Diabetes\",\n \"group\": \"clinical\",\n \"sourcePages\": [\n 1\n ]\n },\n {\n \"tempId\": \"urn:uuid:medication-001\",\n \"resourceType\": \"MedicationRequest\",\n \"description\": \"Metformin 500mg prescription\",\n \"originalText\": \"Prescribed Metformin 500mg\",\n \"group\": \"clinical\",\n \"sourcePages\": [\n 2\n ]\n }\n ],\n \"validation\": {\n \"passes\": [\n {}\n ],\n \"fixed\": true,\n \"attempts\": 1,\n \"summary\": \"summary\"\n },\n \"resource_review\": {\n \"flagged\": [\n {\n \"tempId\": \"urn:uuid:a842c4bc-f6cb-4555-9741-ac3aec4ef0b8\",\n \"resourceType\": \"Condition\",\n \"findings\": [\n {\n \"fieldPath\": \"onsetDateTime\",\n \"value\": \"2024-01-15\",\n \"supported\": false,\n \"rationale\": \"Date is the visit date, not when the condition began.\"\n }\n ]\n }\n ]\n },\n \"page_classifications\": [\n {\n \"page_number\": 1,\n \"include\": true,\n \"classification_id\": \"clinical\",\n \"reason\": \"clinical demographics and diagnosis\"\n },\n {\n \"page_number\": 2,\n \"include\": true,\n \"classification_id\": \"clinical\",\n \"reason\": \"clinical medication details\"\n },\n {\n \"page_number\": 3,\n \"include\": false,\n \"classification_id\": \"admin\",\n \"reason\": \"administrative cover sheet\"\n }\n ]\n}",
+ "body": "{\n \"success\": true,\n \"message\": \"Successfully extracted 3 resources\",\n \"bundle\": {\n \"resourceType\": \"Bundle\",\n \"type\": \"transaction\",\n \"entry\": [\n {\n \"fullUrl\": \"urn:uuid:patient-001\",\n \"resource\": {\n \"resourceType\": \"Patient\",\n \"meta\": {\n \"tag\": [\n {\n \"system\": \"https://phenoml.com/fhir/split-classification\",\n \"code\": \"clinical\"\n }\n ]\n },\n \"name\": [\n {\n \"given\": [\n \"John\"\n ],\n \"family\": \"Doe\"\n }\n ],\n \"gender\": \"male\",\n \"birthDate\": \"1979-03-15\"\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Patient\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:condition-001\",\n \"resource\": {\n \"resourceType\": \"Condition\",\n \"meta\": {\n \"tag\": [\n {\n \"system\": \"https://phenoml.com/fhir/split-classification\",\n \"code\": \"clinical\"\n }\n ]\n },\n \"code\": {\n \"text\": \"Type 2 Diabetes Mellitus\"\n },\n \"subject\": {\n \"reference\": \"urn:uuid:patient-001\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Condition\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:medication-001\",\n \"resource\": {\n \"resourceType\": \"MedicationRequest\",\n \"meta\": {\n \"tag\": [\n {\n \"system\": \"https://phenoml.com/fhir/split-classification\",\n \"code\": \"clinical\"\n }\n ]\n },\n \"medicationCodeableConcept\": {\n \"text\": \"Metformin 500mg\"\n },\n \"subject\": {\n \"reference\": \"urn:uuid:patient-001\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"MedicationRequest\"\n }\n }\n ]\n },\n \"resources\": [\n {\n \"tempId\": \"urn:uuid:patient-001\",\n \"resourceType\": \"Patient\",\n \"description\": \"John Doe, born 1979-03-15\",\n \"originalText\": \"John Doe, DOB 1979-03-15\",\n \"group\": \"clinical\",\n \"sourcePages\": [\n 1\n ]\n },\n {\n \"tempId\": \"urn:uuid:condition-001\",\n \"resourceType\": \"Condition\",\n \"description\": \"Type 2 Diabetes Mellitus diagnosis\",\n \"originalText\": \"diagnosed with Type 2 Diabetes\",\n \"group\": \"clinical\",\n \"sourcePages\": [\n 1\n ]\n },\n {\n \"tempId\": \"urn:uuid:medication-001\",\n \"resourceType\": \"MedicationRequest\",\n \"description\": \"Metformin 500mg prescription\",\n \"originalText\": \"Prescribed Metformin 500mg\",\n \"group\": \"clinical\",\n \"sourcePages\": [\n 2\n ]\n }\n ],\n \"validation\": {\n \"passes\": [\n {}\n ],\n \"fixed\": true,\n \"attempts\": 1,\n \"summary\": \"summary\"\n },\n \"resource_review\": {\n \"flagged\": [\n {\n \"tempId\": \"urn:uuid:a842c4bc-f6cb-4555-9741-ac3aec4ef0b8\",\n \"resourceType\": \"Condition\",\n \"findings\": [\n {\n \"fieldPath\": \"onsetDateTime\",\n \"value\": \"2024-01-15\",\n \"supported\": false,\n \"unaudited\": true,\n \"rationale\": \"Date is the visit date, not when the condition began.\"\n }\n ]\n }\n ],\n \"remediated\": [\n {\n \"tempId\": \"urn:uuid:a842c4bc-f6cb-4555-9741-ac3aec4ef0b8\",\n \"resourceType\": \"Condition\",\n \"findings\": [\n {\n \"fieldPath\": \"onsetDateTime\",\n \"value\": \"2024-01-15\",\n \"supported\": false,\n \"unaudited\": true,\n \"rationale\": \"Date is the visit date, not when the condition began.\"\n }\n ]\n }\n ]\n },\n \"page_classifications\": [\n {\n \"page_number\": 1,\n \"include\": true,\n \"classification_id\": \"clinical\",\n \"reason\": \"clinical demographics and diagnosis\"\n },\n {\n \"page_number\": 2,\n \"include\": true,\n \"classification_id\": \"clinical\",\n \"reason\": \"clinical medication details\"\n },\n {\n \"page_number\": 3,\n \"include\": false,\n \"classification_id\": \"admin\",\n \"reason\": \"administrative cover sheet\"\n }\n ]\n}",
"headers": {
"Content-Type": "application/json"
}
@@ -1651,6 +1991,11 @@
"request": {
"urlPathTemplate": "/lang2fhir/batch",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"queryParameters": {
"cursor": {
"equalTo": "cursor"
@@ -1685,7 +2030,12 @@
"name": "Create a batch job - default",
"request": {
"urlPathTemplate": "/lang2fhir/batch",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 202,
@@ -1712,6 +2062,11 @@
"request": {
"urlPathTemplate": "/lang2fhir/batch/{job_id}/items",
"method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"job_id": {
"equalTo": "job_id"
@@ -1743,6 +2098,11 @@
"request": {
"urlPathTemplate": "/lang2fhir/batch/{job_id}/finalize",
"method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"job_id": {
"equalTo": "job_id"
@@ -1774,6 +2134,11 @@
"request": {
"urlPathTemplate": "/lang2fhir/batch/{job_id}/cancel",
"method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"job_id": {
"equalTo": "job_id"
@@ -1805,6 +2170,11 @@
"request": {
"urlPathTemplate": "/lang2fhir/batch/{job_id}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"job_id": {
"equalTo": "job_id"
@@ -1844,6 +2214,11 @@
"request": {
"urlPathTemplate": "/lang2fhir/batch/{job_id}/results",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"job_id": {
"equalTo": "job_id"
@@ -1883,6 +2258,11 @@
"request": {
"urlPathTemplate": "/lang2fhir/batch/{job_id}/results/{item_id}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"job_id": {
"equalTo": "job_id"
@@ -1917,6 +2297,11 @@
"request": {
"urlPathTemplate": "/fhir/profiles",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"queryParameters": {
"url": {
"equalTo": "http://phenoml.com/fhir/StructureDefinition/custom-patient|1.0.0"
@@ -1948,7 +2333,12 @@
"name": "Upload a custom FHIR profile - default",
"request": {
"urlPathTemplate": "/fhir/profiles",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 201,
@@ -1975,6 +2365,11 @@
"request": {
"urlPathTemplate": "/fhir/profiles/{id}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "custom-patient"
@@ -2006,6 +2401,11 @@
"request": {
"urlPathTemplate": "/fhir/profiles/{id}",
"method": "PUT",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "custom-patient"
@@ -2037,6 +2437,11 @@
"request": {
"urlPathTemplate": "/fhir/profiles/{id}",
"method": "DELETE",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "custom-patient"
@@ -2068,6 +2473,11 @@
"request": {
"urlPathTemplate": "/fhir/profiles/{id}/versions",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "custom-patient"
@@ -2099,6 +2509,11 @@
"request": {
"urlPathTemplate": "/fhir/profiles/{id}/versions",
"method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "custom-patient"
@@ -2130,6 +2545,11 @@
"request": {
"urlPathTemplate": "/fhir/profiles/{id}/versions/{version}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "custom-patient"
@@ -2164,6 +2584,11 @@
"request": {
"urlPathTemplate": "/fhir/profiles/{id}/versions/{version}",
"method": "DELETE",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "custom-patient"
@@ -2197,7 +2622,12 @@
"name": "List all summary templates - default",
"request": {
"urlPathTemplate": "/fhir2summary/templates",
- "method": "GET"
+ "method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -2224,7 +2654,12 @@
"name": "Create a new summary template - Discharge Summary Template",
"request": {
"urlPathTemplate": "/fhir2summary/template",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -2251,6 +2686,11 @@
"request": {
"urlPathTemplate": "/fhir2summary/template/{id}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "id"
@@ -2282,6 +2722,11 @@
"request": {
"urlPathTemplate": "/fhir2summary/template/{id}",
"method": "PUT",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "id"
@@ -2313,6 +2758,11 @@
"request": {
"urlPathTemplate": "/fhir2summary/template/{id}",
"method": "DELETE",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "id"
@@ -2343,7 +2793,12 @@
"name": "Generate a summary from FHIR resources - Narrative Summary",
"request": {
"urlPathTemplate": "/fhir2summary/create",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -2369,7 +2824,12 @@
"name": "Create FHIR resource from text and store it - default",
"request": {
"urlPathTemplate": "/tools/lang2fhir-and-create",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -2395,7 +2855,12 @@
"name": "Extract and store multiple FHIR resources - default",
"request": {
"urlPathTemplate": "/tools/lang2fhir-and-create-multi",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -2421,7 +2886,12 @@
"name": "Search FHIR resources from natural language - default",
"request": {
"urlPathTemplate": "/tools/lang2fhir-and-search",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -2447,7 +2917,12 @@
"name": "Analyze patient cohorts - default",
"request": {
"urlPathTemplate": "/tools/cohort",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -2473,7 +2948,12 @@
"name": "Create MCP server - default",
"request": {
"urlPathTemplate": "/tools/mcp-server/create",
- "method": "POST"
+ "method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -2499,7 +2979,12 @@
"name": "List MCP servers - default",
"request": {
"urlPathTemplate": "/tools/mcp-server/list",
- "method": "GET"
+ "method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ }
},
"response": {
"status": 200,
@@ -2527,6 +3012,11 @@
"request": {
"urlPathTemplate": "/tools/mcp-server/{mcp_server_id}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"mcp_server_id": {
"equalTo": "mcp_server_id"
@@ -2558,6 +3048,11 @@
"request": {
"urlPathTemplate": "/tools/mcp-server/{mcp_server_id}",
"method": "DELETE",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"mcp_server_id": {
"equalTo": "mcp_server_id"
@@ -2589,6 +3084,11 @@
"request": {
"urlPathTemplate": "/tools/mcp-server/{mcp_server_id}/list",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"mcp_server_id": {
"equalTo": "mcp_server_id"
@@ -2620,6 +3120,11 @@
"request": {
"urlPathTemplate": "/tools/mcp-server/tool/{mcp_server_tool_id}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"mcp_server_tool_id": {
"equalTo": "mcp_server_tool_id"
@@ -2651,6 +3156,11 @@
"request": {
"urlPathTemplate": "/tools/mcp-server/tool/{mcp_server_tool_id}",
"method": "DELETE",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"mcp_server_tool_id": {
"equalTo": "mcp_server_tool_id"
@@ -2682,6 +3192,11 @@
"request": {
"urlPathTemplate": "/workflows",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"queryParameters": {
"verbose": {
"equalTo": "true"
@@ -2714,6 +3229,11 @@
"request": {
"urlPathTemplate": "/workflows",
"method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"queryParameters": {
"verbose": {
"equalTo": "true"
@@ -2745,6 +3265,11 @@
"request": {
"urlPathTemplate": "/workflows/{id}",
"method": "GET",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "id"
@@ -2781,6 +3306,11 @@
"request": {
"urlPathTemplate": "/workflows/{id}",
"method": "PUT",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "id"
@@ -2817,6 +3347,11 @@
"request": {
"urlPathTemplate": "/workflows/{id}",
"method": "DELETE",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "id"
@@ -2848,6 +3383,11 @@
"request": {
"urlPathTemplate": "/workflows/{id}/execute",
"method": "POST",
+ "headers": {
+ "Authorization": {
+ "matches": "Bearer .+"
+ }
+ },
"pathParameters": {
"id": {
"equalTo": "7a8b9c0d-1234-5678-abcd-ef9876543210"
@@ -2875,6 +3415,6 @@
}
],
"meta": {
- "total": 94
+ "total": 96
}
}
\ No newline at end of file
From 57fc3941e271ada84922612d69699f72944768b6 Mon Sep 17 00:00:00 2001
From: "fern-api[bot]" <115122769+fern-api[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 17:33:09 +0000
Subject: [PATCH 2/5] [fern-autoversion] SDK regeneration
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
🌿 Generated with Fern
---
.fern/metadata.json | 2 +-
pyproject.toml | 2 +-
src/phenoml/core/client_wrapper.py | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.fern/metadata.json b/.fern/metadata.json
index 204732c..c542fd9 100644
--- a/.fern/metadata.json
+++ b/.fern/metadata.json
@@ -13,5 +13,5 @@
"invokedBy": "ci",
"requestedVersion": "AUTO",
"ciProvider": "unknown",
- "sdkVersion": "0.0.0.dev0"
+ "sdkVersion": "17.0.1"
}
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 1dc545d..61c1467 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ dynamic = ["version"]
[tool.poetry]
name = "phenoml"
-version = "0.0.0.dev0"
+version = "17.0.1"
description = ""
readme = "README.md"
authors = []
diff --git a/src/phenoml/core/client_wrapper.py b/src/phenoml/core/client_wrapper.py
index c03a243..cc09709 100644
--- a/src/phenoml/core/client_wrapper.py
+++ b/src/phenoml/core/client_wrapper.py
@@ -38,7 +38,7 @@ def get_headers(self) -> typing.Dict[str, str]:
"X-Fern-Runtime": f"python/{platform.python_version()}",
"X-Fern-Platform": f"{platform.system().lower()}/{platform.release()}",
"X-Fern-SDK-Name": "phenoml",
- "X-Fern-SDK-Version": "0.0.0.dev0",
+ "X-Fern-SDK-Version": "17.0.1",
**(self.get_custom_headers() or {}),
}
token = self._get_token()
From 78e97d754120b6d038320bb0170ce4006592d813 Mon Sep 17 00:00:00 2001
From: "fern-api[bot]" <115122769+fern-api[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 17:33:09 +0000
Subject: [PATCH 3/5] [fern-replay] Applied customizations
Patches applied (1):
- patch-6516695e: Release 15.0.2: restore bundled openapi.json packaging (#169)
---
.fern/replay.lock | 27 +++++++++++++++++++++------
pyproject.toml | 3 +++
2 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/.fern/replay.lock b/.fern/replay.lock
index 25dc6cb..d1dbd05 100644
--- a/.fern/replay.lock
+++ b/.fern/replay.lock
@@ -120,21 +120,36 @@ generations:
cli_version: unknown
generator_versions:
fernapi/fern-python-sdk: 5.18.1
-current_generation: 3ac2feef8a9595d7dea2a99b024322ae61959133
+ - commit_sha: d3f3f207d7703ae90bf28f7fde8e487fdc1a1d1c
+ tree_hash: 7920ab53b981de5f0f40a4f098d3d17f115f8b21
+ timestamp: 2026-09-21T17:32:02.282Z
+ cli_version: unknown
+ generator_versions:
+ fernapi/fern-python-sdk: 5.30.0
+current_generation: d3f3f207d7703ae90bf28f7fde8e487fdc1a1d1c
patches:
- id: patch-6516695e
- content_hash: sha256:5caeff601ccd2db4bda36068ff6c1ac7dba46f1c049cccc367a7db553613acad
+ content_hash: sha256:1d979cf90aad13d61c31dd2bace465f9b4427b9282da800066490b1b716224bd
original_commit: 6516695ecaba47ae4bcc8119acca86a1113adeeb
original_message: "Release 15.0.2: restore bundled openapi.json packaging (#169)"
original_author: Gavin Sharp
- base_generation: 3ac2feef8a9595d7dea2a99b024322ae61959133
+ base_generation: d3f3f207d7703ae90bf28f7fde8e487fdc1a1d1c
files:
- pyproject.toml
patch_content: |
diff --git a/pyproject.toml b/pyproject.toml
- index cea8b20..f3f1f73 100644
+ index 1dc545d..23c4eae 100644
--- a/pyproject.toml
+++ b/pyproject.toml
+ @@ -4,7 +4,7 @@ dynamic = ["version"]
+
+ [tool.poetry]
+ name = "phenoml"
+ -version = "0.0.0.dev0"
+ +version = "17.0.1"
+ description = ""
+ readme = "README.md"
+ authors = []
@@ -31,6 +31,9 @@ classifiers = [
packages = [
{ include = "phenoml", from = "src"}
@@ -153,7 +168,7 @@ patches:
[tool.poetry]
name = "phenoml"
- version = "17.0.0"
+ version = "17.0.1"
description = ""
readme = "README.md"
authors = []
@@ -191,7 +206,7 @@ patches:
python = "^3.10"
aiohttp = { version = ">=3.14.1,<4", optional = true, python = ">=3.10"}
httpx = ">=0.21.2"
- httpx-aiohttp = { version = "0.1.8", optional = true, python = ">=3.10"}
+ httpx-aiohttp = { version = "^0.1.8", optional = true, python = ">=3.10"}
pydantic = ">= 1.9.2"
pydantic-core = ">=2.18.2,<3.0.0"
typing_extensions = ">= 4.0.0"
diff --git a/pyproject.toml b/pyproject.toml
index 61c1467..23c4eae 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -31,6 +31,9 @@ classifiers = [
packages = [
{ include = "phenoml", from = "src"}
]
+include = [
+ { path = "src/phenoml/openapi/openapi.json", format = ["sdist", "wheel"] }
+]
[tool.poetry.urls]
Repository = 'https://github.com/phenoml/phenoml-python-sdk'
From ca1e00af87a51ee2070e861e18cd7b5f1cd3cb4a Mon Sep 17 00:00:00 2001
From: "fern-api[bot]" <115122769+fern-api[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 17:33:10 +0000
Subject: [PATCH 4/5] SDK regeneration
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
🌿 Generated with Fern
---
changelog.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/changelog.md b/changelog.md
index 2a9ecbb..6162272 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,5 @@
+## [17.0.1] - 2026-09-21
+
## [17.0.0] - 2026-09-09
### Breaking Changes
- **`ProfileSummary`** — `id`, `source`, `resource_type`, `url`, `version`, `fhir_version`, `implementation_guide`, `created_at`, and `updated_at` are now required; remove `None` guards for these fields.
From 5e97239fbfc63486dc9ca397f0a553e69797e8bc Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 17:33:26 +0000
Subject: [PATCH 5/5] chore: sync OpenAPI spec + code-examples for
ebd41888bd45310e791509e3f06fd54484fc8ef9 [skip ci]
---
code-examples.json | 79 ++++++-
src/phenoml/openapi/openapi.json | 375 +++++++++++++++++++++++++++----
2 files changed, 408 insertions(+), 46 deletions(-)
diff --git a/code-examples.json b/code-examples.json
index 79472cc..aac561b 100644
--- a/code-examples.json
+++ b/code-examples.json
@@ -2,8 +2,8 @@
"metadata": {
"language": "python",
"packageName": "phenoml",
- "sdkVersion": "17.0.0",
- "specCommit": "26224ef37e22adb507f28c21e8991d4a27822bde",
+ "sdkVersion": "17.0.1",
+ "specCommit": "ebd41888bd45310e791509e3f06fd54484fc8ef9",
"generatorName": "fernapi/fern-python-sdk"
},
"renderRules": {
@@ -3250,7 +3250,7 @@
"body": {
"version": "R4",
"resource": "questionnaire",
- "content": "JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)"
+ "content": "JVBERi0xLjQKJeLjz9MK...(base64-encoded document bytes)"
}
},
"response": {
@@ -3312,7 +3312,7 @@
"request": {
"body": {
"version": "R4",
- "content": "JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)",
+ "content": "JVBERi0xLjQKJeLjz9MK...(base64-encoded document bytes)",
"provider": "medplum",
"config": {
"split_classifications": [
@@ -3957,6 +3957,77 @@
]
}
},
+ "POST /fhir/implementation-guides/{name}/versions": {
+ "httpMethod": "POST",
+ "httpPath": "/fhir/implementation-guides/{name}/versions",
+ "request": {
+ "body": null
+ },
+ "response": {
+ "body": null
+ },
+ "render": {
+ "callTemplate": "client.implementation_guides.implementation_guides.create_version(name={{name}}, {{__body__}})",
+ "params": [
+ {
+ "name": "name",
+ "kind": "string"
+ }
+ ],
+ "body": {
+ "fieldSeparator": ", ",
+ "fields": [
+ {
+ "jsonKey": "implementation_guide",
+ "fieldTemplate": "implementation_guide={{value}}",
+ "kind": "object",
+ "required": true
+ },
+ {
+ "jsonKey": "profile_refs",
+ "fieldTemplate": "profile_refs={{value}}",
+ "kind": "list",
+ "required": true,
+ "items": {
+ "jsonKey": "",
+ "fieldTemplate": "{{value}}",
+ "kind": "string",
+ "required": true
+ }
+ },
+ {
+ "jsonKey": "profile_context",
+ "fieldTemplate": "profile_context={{value}}",
+ "kind": "string",
+ "required": false
+ }
+ ]
+ }
+ }
+ },
+ "GET /fhir/implementation-guides/{name}/versions/{version}": {
+ "httpMethod": "GET",
+ "httpPath": "/fhir/implementation-guides/{name}/versions/{version}",
+ "request": {
+ "body": null
+ },
+ "response": {
+ "body": null
+ },
+ "render": {
+ "callTemplate": "client.implementation_guides.implementation_guides.get_version(name={{name}}, version={{version}})",
+ "params": [
+ {
+ "name": "name",
+ "kind": "string"
+ },
+ {
+ "name": "version",
+ "kind": "string"
+ }
+ ]
+ }
+ },
"GET /fhir/profiles": {
"httpMethod": "GET",
"httpPath": "/fhir/profiles",
diff --git a/src/phenoml/openapi/openapi.json b/src/phenoml/openapi/openapi.json
index 0a3b0ed..18748f1 100644
--- a/src/phenoml/openapi/openapi.json
+++ b/src/phenoml/openapi/openapi.json
@@ -2,7 +2,7 @@
"openapi": "3.0.3",
"info": {
"title": "Phenoml API",
- "version": "26224ef37e22adb507f28c21e8991d4a27822bde"
+ "version": "ebd41888bd45310e791509e3f06fd54484fc8ef9"
},
"x-services": [
{
@@ -3274,7 +3274,7 @@
"post": {
"operationId": "fhir2omop_create",
"summary": "Map FHIR resources to OMOP CDM v5.4",
- "description": "Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows\n(person, visit_occurrence, condition_occurrence, drug_exposure,\nprocedure_occurrence, measurement, observation).\n\nResource support is intentionally limited to the OMOP tables returned by\nthis endpoint:\n- `Patient` -> `person`\n- `Encounter` -> `visit_occurrence`\n- `Condition` -> `condition_occurrence`\n- `Procedure` -> `procedure_occurrence`\n- `MedicationRequest`, `MedicationStatement`, and\n `MedicationAdministration` -> `drug_exposure`\n- `Immunization` -> `drug_exposure`\n- `Observation` with a numeric `valueQuantity`, `valueInteger`, or\n numeric-looking `valueString` (for example `\"<2\"`) -> `measurement`\n- non-numeric `Observation` -> `observation`\n- `AllergyIntolerance` -> `observation`\n\n`Medication` is supported only as reference data for medication\nresources; it is not emitted as its own row because OMOP CDM has no\nMedication table. Other reference/admin resources such as `Practitioner`,\n`Organization`, `Location`, `Coverage`, and `Claim`, and clinical\nworkflow/document resources such as `DiagnosticReport`, `ServiceRequest`,\n`CarePlan`, `DocumentReference`, `Composition`, `Specimen`, and\n`DeviceUseStatement`, are currently accepted in a Bundle but are not\nshaped into OMOP rows. Unsupported resource types are ignored rather than\nlisted under `dropped`; `dropped` is reserved for supported resource types\nthat were missing the subject/patient, code, or medication reference data\nneeded to produce a valid row.\n\nEach resource's primary clinical coding is resolved to a standard OMOP\n`concept_id`. Alongside the OMOP rows grouped by table (`tables`), the\nresponse carries `mappings` (how each source coding resolved, linked back\nto the row it produced), `dropped` (resources that could not be shaped\ninto a row), `vocab_version` (the OMOP vocabulary release codes were\nresolved against), and a small `summary` of the resolution outcomes.\n\nA `concept_id` of `0` is reported, not omitted (OMOP \"no matching\nconcept\" semantics): it covers both a coding with no standard match\n(`UNMAPPED`) and an unverified suggestion for a text-only resource\n(`UNCHECKED`). Only the primary clinical coding is resolved, so\n`gender`/`race`/`ethnicity`/`visit`/`value`/`unit` `concept_id`s are\nalways `0`; the one populated non-resolved concept is measurement\n`operator_concept_id`, set from a value comparator (`<`, `<=`, `>`, `>=`)\nrather than the resolver. Each `*_source_value` carries the verbatim FHIR\ncoding (`system#code`), and `*_type_concept_id` is set to `32817` (EHR).\n\nMedication codes are resolved whether they appear inline\n(`medicationCodeableConcept`) or via a `medicationReference` to a contained,\nrelative (`Type/id`), or bundle-entry (`urn:uuid`) `Medication` resource.\nResources that cannot be shaped into a row \u2014 a medication with no usable\ncode, resolvable reference, or display, or any clinical resource whose\nsubject/patient reference cannot be tied to a person \u2014 are reported under\n`dropped` rather than emitted as blank rows. The\nbundle must contain at least one Patient resource.\n",
+ "description": "Maps a FHIR R4 resource or Bundle into OMOP Common Data Model v5.4 rows,\ngrouped by destination table in `tables`.\n\nCurrent resource coverage:\n- `Patient` -> `person`; `deceased[x]` can also produce `death`, and the\n first address can produce `location`\n- `observation_period` -> one derived row per person with dated visit,\n clinical, or death rows, spanning those dates\n- `Location` -> `location` and `care_site`\n- `Organization` -> `care_site`; its first address can produce `location`\n- `HealthcareService` -> `care_site`\n- `Practitioner` and `PractitionerRole` -> `provider`\n- `Encounter` -> `visit_occurrence`\n- `Condition` -> `condition_occurrence`\n- `Procedure` -> `procedure_occurrence`\n- `MedicationRequest`, `MedicationStatement`, and\n `MedicationAdministration` -> `drug_exposure`\n- `Immunization` -> `drug_exposure`\n- `Observation` -> `measurement` or `observation`. For coded\n Observations, the resolved OMOP concept domain selects the table; value\n form only breaks ties. For text-only Observations, numeric values route\n to `measurement` and nonnumeric values to `observation`.\n- `AllergyIntolerance` -> `observation`\n\n`Medication` is reference data for medication resources; it does not\ncreate its own row because OMOP CDM has no Medication table. Administrative\nlinkages (provider, care site, and location) are best-effort and limited to\nreferences supplied in the request. Their supporting concepts, including\nprovider specialty, country, and place of service, are not mapped.\n\n`DiagnosticReport`, `ServiceRequest`, `CarePlan`, `DocumentReference`,\n`Composition`, `Specimen`, `DeviceUseStatement`, `Coverage`, `Claim`, and\nother unsupported resource types are accepted in a Bundle but ignored: they\ncreate no row and no `dropped` entry. `dropped` is reserved for supported\nrow-producing resources that could not be shaped because the subject/patient,\nclinical code/text, or medication data was not usable. A single-Patient\nBundle can attribute a supported clinical resource with a missing or\nunresolvable subject to that sole person; in a multi-Patient Bundle, that\nresource is dropped instead.\n\nCoded Observation routing is selected from the resolved OMOP concept\ndomain. Numeric and nonnumeric `value[x]` forms establish the preferred\ntarget only when the code is valid for both tables. A text-only\nObservation has no resolver target, so numeric values route to\n`measurement` and nonnumeric values to `observation`. Numeric values\npopulate `value_as_number` in the selected row; nonnumeric values\npopulate `value_as_string` for an `observation` or `value_source_value`\nfor a `measurement`. `valueCodeableConcept` remains source text and does\nnot populate `value_as_concept_id`; other unsupported `value[x]` forms\nand Observation components do not populate separate converted values. A\nnumeric comparator (`<`, `<=`, `>`, `>=`) is represented only by a\nmeasurement's `operator_concept_id`; units remain source text and have\n`unit_concept_id` of `0`.\n\nA single standard OMOP `concept_id` is selected for each clinical row\nafter considering all of the resource's supplied codings. Alongside the\nOMOP rows grouped by table (`tables`), the response carries `mappings`\n(an entry for every source coding, linked back to the row it produced),\n`dropped` (resources that could not be shaped into a row),\n`vocab_version` (the OMOP vocabulary release codes were resolved\nagainst), and a small `summary` of the resolution outcomes.\n\nA `concept_id` of `0` is reported, not omitted (OMOP \"no matching\nconcept\" semantics): it covers both a coding with no standard match\n(`UNMAPPED`) and an unverified suggestion for a text-only resource\n(`UNCHECKED`). Demographic, visit, categorical-value, and unit concept\nfields currently remain `0`; the one populated non-resolved concept is\nmeasurement\n`operator_concept_id`, set from a value comparator (`<`, `<=`, `>`, `>=`)\nrather than terminology resolution. Clinical `*_source_value` fields\npreserve the selected FHIR coding (`system#code`, or `code` when no\nsystem is supplied), falling back to source text for text-only resources.\nOther `*_source_value` fields preserve row-specific raw source values,\nsuch as resource identifiers, names, units, or status codes, and\n`*_type_concept_id` is set to `32817` (EHR).\n\nMedication codes are resolved whether they appear inline\n(`medicationCodeableConcept`) or via a `medicationReference` to a contained,\nrelative (`Type/id`), or bundle-entry (`urn:uuid`) `Medication` resource.\nResources that cannot be shaped into a row \u2014 a medication with no usable\ncode, resolvable reference, or display, or any clinical resource whose\nsubject/patient reference cannot be tied to a person \u2014 are reported under\n`dropped` rather than emitted as blank rows. The Bundle must contain at\nleast one Patient resource.\n\nAll row IDs start at `1` for each request and are not stable or global.\nFor clinical conversion rows whose resource supplies an `id`, `mappings`\nassociates each row with that source FHIR resource ID. A `person` row\nretains the Patient ID or its first identifier value in\n`person_source_value`, when present; other reference and derived rows do\nnot uniformly carry a FHIR resource ID. Input resources without those\nsource identifiers cannot be correlated across responses from the\nreturned rows alone. Consumers combining responses need to establish\ntheir own stable keys and remap every primary and foreign key together.\n",
"requestBody": {
"required": true,
"content": {
@@ -3366,7 +3366,7 @@
"examples": {
"mapping_result": {
"summary": "Mapping result",
- "description": "The example bundle mapped to OMOP. Both source codes are already\nstandard, so each clinical row carries its own OMOP `concept_id`\nwith `ALREADY_STANDARD` status and a `target_code` equal to the\nsource code. Illustrative `concept_id` values.\n",
+ "description": "The example bundle mapped to OMOP. Both source codes are already\nstandard, so each clinical row carries its own OMOP `concept_id`\nwith `ALREADY_STANDARD` status and a `target_code` equal to the\nsource code. The concept IDs and vocabulary version illustrate\nthe response shape; production values depend on the vocabulary\nrelease used for the request.\n",
"value": {
"success": true,
"message": "FHIR resources mapped to OMOP CDM v5.4",
@@ -4586,7 +4586,7 @@
"post": {
"operationId": "batch_create",
"summary": "Create a batch job",
- "description": "Opens an empty batch job. Items arrive on later upload calls and the set\nis sealed at finalize.\n\nSupplying `request_id` makes the create idempotent on that token: a\nretried submit whose response was lost returns the original job rather\nthan opening a second one. This dedupe is scoped to the calling\ncredential. A `request_id` whose job was canceled or failed before it\nfinalized is released for a fresh replay; once a job is finalized, its\n`request_id` keeps resolving to it even after cancellation.\n\nAn instance may hold at most 4 active (pending or processing) jobs at\nonce; a create past that limit returns `409`. The limit is instance-wide\n\u2014 jobs are shared across the instance's credentials \u2014 so another\ncredential's jobs count against it.\n",
+ "description": "Opens an empty batch job. Items arrive on later upload calls and the set\nis sealed at finalize.\n\nSupplying `request_id` makes the create idempotent on that token: a\nretried submit whose response was lost returns the original job rather\nthan opening a second one. This dedupe is scoped to the calling\ncredential. A `request_id` whose job was canceled or failed before it\nfinalized is released for a fresh replay; once a job is finalized, its\n`request_id` keeps resolving to it even after cancellation.\n\nThere is no limit on how many jobs an instance may hold at once; how many\nitems run in parallel is a property of the instance, not of the job count.\n",
"requestBody": {
"required": true,
"content": {
@@ -4617,9 +4617,6 @@
"401": {
"description": "Unauthorized"
},
- "409": {
- "description": "The instance is at its 4-job active-batch limit; wait for one to finish"
- },
"499": {
"description": "Client closed request before response was ready"
},
@@ -4702,7 +4699,7 @@
"post": {
"operationId": "batch_uploadItem",
"summary": "Upload one batch item",
- "description": "Stores one item of a job from a multipart upload. A batch's items arrive\none per request. The item carries **either** a `document` extraction\n(whose input file rides as raw bytes in the `file` part) **or** a\n`create` extraction (JSON only, no file).\n\nThe upload enforces these rules:\n- Set **exactly one** of `document` or `create`. Setting both, or\n neither, is a `400`.\n- When `document` is set, `file` is **required** \u2014 it supplies the\n document's binary content (PDF or image).\n- When `create` is set, `file` is **forbidden** \u2014 a create item carries\n no file.\n- `document` and `create` must each be a JSON **object**.\n\nOnly the item's structure is checked here: the fields inside `document`\nor `create` are not validated at upload. A body that is well-formed JSON\nbut not a valid request for its endpoint is still accepted with `202`\nand fails later during processing, recorded as an item `error`. A\nwrong-typed field the endpoint cannot decode fails as `invalid_input`; a\nbody that decodes but the pipeline rejects (for example, a missing\nrequired field) fails as `processing_failed`.\n\nSupplying `request_id` makes the upload idempotent on that token. A\nre-upload under the same token overwrites the same item rather than\nadding a second, so a client that lost an upload's response can safely\nre-send it. The response's `deduplicated` is `true` only when the\nre-uploaded payload matches the one already stored; a same-token upload\nwith a changed payload overwrites in place and returns `false`.\n\nSet a `request_id` on **every** upload: re-sending under the same token\nis the only way to repair a lost or incomplete upload, including the one\na finalize `409` reports. Without one, a re-send adds a new item instead\nof replacing the missing one, and the job cannot be finalized.\n\nUploads are rejected once the job has been finalized (`409`), once it\nholds its 500-item limit (`409`), or when the item is too large (`413` \u2014\nsee the raw-file limit in the API description).\n",
+ "description": "Stores one item of a job from a multipart upload. A batch's items arrive\none per request. The item carries **either** a `document` extraction\n(whose input file rides as raw bytes in the `file` part) **or** a\n`create` extraction (JSON only, no file).\n\nThe upload enforces these rules:\n- Set **exactly one** of `document` or `create`. Setting both, or\n neither, is a `400`.\n- When `document` is set, `file` is **required** \u2014 it supplies the\n document's file content (PDF, image, RTF, or XML/C-CDA).\n- When `create` is set, `file` is **forbidden** \u2014 a create item carries\n no file.\n- `document` and `create` must each be a JSON **object**.\n\nOnly the item's structure is checked here: the fields inside `document`\nor `create` are not validated at upload. A body that is well-formed JSON\nbut not a valid request for its endpoint is still accepted with `202`\nand fails later during processing, recorded as an item `error`. A\nwrong-typed field the endpoint cannot decode fails as `invalid_input`; a\nbody that decodes but the pipeline rejects (for example, a missing\nrequired field) fails as `processing_failed`.\n\nSupplying `request_id` makes the upload idempotent on that token. A\nre-upload under the same token overwrites the same item rather than\nadding a second, so a client that lost an upload's response can safely\nre-send it. The response's `deduplicated` is `true` only when the\nre-uploaded payload matches the one already stored; a same-token upload\nwith a changed payload overwrites in place and returns `false`.\n\nSet a `request_id` on **every** upload: re-sending under the same token\nis the only way to repair a lost or incomplete upload, including the one\na finalize `409` reports. Without one, a re-send adds a new item instead\nof replacing the missing one, and the job cannot be finalized.\n\nUploads are rejected once the job has been finalized (`409`), once it\nholds its 500-item limit (`409`), or when the item is too large (`413` \u2014\nsee the raw-file limit in the API description).\n",
"parameters": [
{
"name": "job_id",
@@ -4731,17 +4728,15 @@
"file": {
"type": "string",
"format": "binary",
- "description": "The document's binary content (PDF, PNG, JPEG, or TIFF).\nRequired with `document`; forbidden with `create`.\n"
+ "description": "The document's file content (PDF, PNG, JPEG, TIFF, RTF, or\nXML/C-CDA). The document pipeline accepts files up to 20 MiB;\nan upload that passes the storage cap but exceeds this limit\nfails during processing. RTF and XML/C-CDA documents whose\nextracted text exceeds 1 MiB also fail during processing.\nGeneric XML must include an XML declaration; C-CDA documents\nrooted at `ClinicalDocument` may omit it.\nRequired with `document`; forbidden with `create`.\n"
},
"request_id": {
"type": "string",
- "maxLength": 256,
- "description": "Optional idempotency token (max 256 bytes). Re-uploading under\nthe same token overwrites the same item instead of adding a\nnew one. The token is scoped to this job; the same token in\nanother job is independent and creates a separate item.\n"
+ "description": "Optional idempotency token (at most 256 UTF-8 bytes).\nRe-uploading under the same token overwrites the same item\ninstead of adding a new one. The token is scoped to this job;\nthe same token in another job is independent and creates a\nseparate item.\n"
},
"id": {
"type": "string",
- "maxLength": 512,
- "description": "Optional caller-supplied correlation label (max 512 bytes),\nechoed back on status and result listings so you can match the\nserver's item_id to your own record.\n"
+ "description": "Optional caller-supplied correlation label (at most 512 UTF-8\nbytes), echoed back on status and result listings so you can\nmatch the server's item_id to your own record.\n"
}
}
},
@@ -4860,7 +4855,7 @@
"post": {
"operationId": "batch_cancel",
"summary": "Cancel a batch job",
- "description": "Drives a job to the terminal `canceled` state on request, freeing its\nactive-job slot immediately. Takes no request body.\n\nCancel does not delete the job: the job record and any results already\nproduced are preserved for the normal retention window, the same as a\n`completed` or `failed` job. Items stop being processed and keep the state\nthey held at cancellation, so a canceled job's `counts` may show\nunfinished items that never resolve.\n\nCancel is idempotent: canceling an already-`canceled` job returns `200`\nwith the job. Canceling a job that has already `completed` or `failed` is\na `409`.\n",
+ "description": "Drives a job to the terminal `canceled` state on request. Takes no\nrequest body.\n\nCancel does not delete the job: the job record and any results already\nproduced are preserved for the normal retention window, the same as a\n`completed` or `failed` job. Items stop being processed and keep the state\nthey held at cancellation, so a canceled job's `counts` may show\nunfinished items that never resolve.\n\nCancel is idempotent: canceling an already-`canceled` job returns `200`\nwith the job. Canceling a job that has already `completed` or `failed` is\na `409`.\n",
"parameters": [
{
"name": "job_id",
@@ -5605,7 +5600,7 @@
"post": {
"operationId": "lang2fhir_document",
"summary": "Convert document to FHIR resource",
- "description": "Extracts text from a document (PDF or image) and converts it into a structured FHIR resource.\n\n**Patient identifier handling.** When generating a `patient` (or `patient-canvas`) resource, US Core requires `Patient.identifier` (a business identifier such as an MRN). When the source text contains an identifier, it is extracted with an appropriate URI system. When the source text does not contain a detectable identifier, a synthetic one is generated with `system: \"urn:phenoml:lang2fhir-generated-id\"` and a UUID `value` so the resource remains FHIR-valid and US Core conformant. Callers who need a tenant-specific namespace should rewrite the synthetic system after extraction.\n",
+ "description": "Extracts text from a PDF, image, RTF, or XML/C-CDA document and converts it into a structured FHIR resource.\n\n**Patient identifier handling.** When generating a `patient` (or `patient-canvas`) resource, US Core requires `Patient.identifier` (a business identifier such as an MRN). When the source text contains an identifier, it is extracted with an appropriate URI system. When the source text does not contain a detectable identifier, a synthetic one is generated with `system: \"urn:phenoml:lang2fhir-generated-id\"` and a UUID `value` so the resource remains FHIR-valid and US Core conformant. Callers who need a tenant-specific namespace should rewrite the synthetic system after extraction.\n",
"requestBody": {
"required": true,
"content": {
@@ -5616,7 +5611,7 @@
"example": {
"version": "R4",
"resource": "questionnaire",
- "content": "JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)"
+ "content": "JVBERi0xLjQKJeLjz9MK...(base64-encoded document bytes)"
}
}
}
@@ -5655,6 +5650,9 @@
"401": {
"description": "Unauthorized"
},
+ "403": {
+ "description": "Forbidden - RTF and XML/C-CDA uploads are only available on dedicated instances"
+ },
"404": {
"description": "Profile not found"
},
@@ -5683,7 +5681,7 @@
"post": {
"operationId": "lang2fhir_documentMulti",
"summary": "Extract multiple FHIR resources from a document",
- "description": "Extracts text from a document (PDF or image) and converts it into multiple FHIR resources,\nreturned as a transaction Bundle. Combines document text extraction with multi-resource detection.\nAutomatically detects Patient, Condition, MedicationRequest, Observation, and other resource types.\nResources are linked with proper references (e.g., Conditions reference the Patient).\n\n**Patient identifier handling.** US Core requires `Patient.identifier` (a business identifier such as an MRN). When the source text contains an identifier, it is extracted with an appropriate URI system. When the source text does not contain a detectable identifier, a synthetic one is generated with `system: \"urn:phenoml:lang2fhir-generated-id\"` and a UUID `value` so the bundle remains FHIR-valid and US Core conformant. Callers who need a tenant-specific namespace should rewrite the synthetic system after extraction.\n\n**Split classifications (optional).** `config.split_classifications` is a caller-defined list, not a fixed taxonomy. Choose each classification `id` and write a natural-language `description` for the per-page classifier. For each page, the classifier assigns the best-matching classification or leaves the page ungrouped. Classifications with `operation: \"group\"` keep matching pages and label resources extracted from those pages; classifications with `operation: \"drop\"` remove matching pages before extraction. The `clinical` and `admin` ids in the example are illustrative, not a fixed set.\n",
+ "description": "Extracts text from a PDF, image, RTF, or XML/C-CDA document and converts it into multiple FHIR resources,\nreturned as a transaction Bundle. Combines document text extraction with multi-resource detection.\nAutomatically detects Patient, Condition, MedicationRequest, Observation, and other resource types.\nResources are linked with proper references (e.g., Conditions reference the Patient).\n\n**Patient identifier handling.** US Core requires `Patient.identifier` (a business identifier such as an MRN). When the source text contains an identifier, it is extracted with an appropriate URI system. When the source text does not contain a detectable identifier, a synthetic one is generated with `system: \"urn:phenoml:lang2fhir-generated-id\"` and a UUID `value` so the bundle remains FHIR-valid and US Core conformant. Callers who need a tenant-specific namespace should rewrite the synthetic system after extraction.\n\n**Split classifications (optional).** `config.split_classifications` is a caller-defined list, not a fixed taxonomy. Choose each classification `id` and write a natural-language `description` for the per-page classifier. For each page, the classifier assigns the best-matching classification or leaves the page ungrouped. Classifications with `operation: \"group\"` keep matching pages and label resources extracted from those pages; classifications with `operation: \"drop\"` remove matching pages before extraction. The `clinical` and `admin` ids in the example are illustrative, not a fixed set.\n",
"requestBody": {
"required": true,
"content": {
@@ -5693,7 +5691,7 @@
},
"example": {
"version": "R4",
- "content": "JVBERi0xLjQKJeLjz9MK...(base64-encoded PDF or image bytes)",
+ "content": "JVBERi0xLjQKJeLjz9MK...(base64-encoded document bytes)",
"provider": "medplum",
"config": {
"split_classifications": [
@@ -5868,6 +5866,9 @@
"401": {
"description": "Unauthorized"
},
+ "403": {
+ "description": "Forbidden - RTF and XML/C-CDA uploads are only available on dedicated instances"
+ },
"404": {
"description": "Profile not found"
},
@@ -6574,11 +6575,11 @@
"tags": [
"FHIR Artifacts / Implementation Guides"
],
- "summary": "Delete an implementation guide's metadata",
- "description": "Deletes the stored metadata for an implementation guide \u2014 its\nprofile_context and timestamps. Member profiles keep their\nimplementation_guide assignment, so a guide still referenced by at least\none profile continues to appear in listings, just without context or\ntimestamps.\n",
+ "summary": "Delete an implementation guide family",
+ "description": "Deletes the stored name-level metadata and any exact canonical package\nversions beneath the guide. Legacy member profile assignments are not\nchanged.\n",
"responses": {
"204": {
- "description": "Implementation guide metadata successfully deleted"
+ "description": "Implementation guide family successfully deleted"
},
"400": {
"description": "The name is reserved or malformed"
@@ -6590,7 +6591,7 @@
"description": "Forbidden - custom profiles are only available on dedicated instances"
},
"404": {
- "description": "No implementation guide metadata exists for this name"
+ "description": "No implementation guide family exists for this name"
},
"500": {
"description": "Server error"
@@ -6604,6 +6605,117 @@
"x-service": "fhir_artifacts"
}
},
+ "/fhir/implementation-guides/{name}/versions": {
+ "parameters": [
+ {
+ "name": "name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "post": {
+ "operationId": "implementation-guides_createVersion",
+ "tags": [
+ "FHIR Artifacts / Implementation Guides"
+ ],
+ "summary": "Publish an exact custom-profile package",
+ "description": "Publishes an exact package beneath this guide family. PR 2 temporarily\npermits one exact package version per guide family; publishing another\nversion returns `409 Conflict` until multi-version package support lands.\n",
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/implementation-guides_CreateCanonicalImplementationGuideRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Canonical package published",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/implementation-guides_ImplementationGuideVersionDetail"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid ImplementationGuide, profile reference, version, or context"
+ },
+ "404": {
+ "description": "An exact profile reference was not found"
+ },
+ "409": {
+ "description": "A package family URL or exact version already exists"
+ }
+ },
+ "security": [
+ {
+ "bearerAuth": []
+ }
+ ],
+ "x-service": "fhir_artifacts"
+ }
+ },
+ "/fhir/implementation-guides/{name}/versions/{version}": {
+ "parameters": [
+ {
+ "name": "name",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "version",
+ "in": "path",
+ "required": true,
+ "description": "The authored ImplementationGuide.version. It may contain letters, numbers, and the punctuation characters `.`, `_`, `~`, `+`, and `-`; it cannot be exactly `.` or `..`.\n",
+ "schema": {
+ "type": "string",
+ "pattern": "^[A-Za-z0-9._~+-]+$"
+ },
+ "example": "1.0.0"
+ }
+ ],
+ "get": {
+ "operationId": "implementation-guides_getVersion",
+ "tags": [
+ "FHIR Artifacts / Implementation Guides"
+ ],
+ "summary": "Get an exact custom-profile package",
+ "responses": {
+ "200": {
+ "description": "Exact canonical package",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/implementation-guides_ImplementationGuideVersionDetail"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid guide name or version"
+ },
+ "404": {
+ "description": "Package version not found"
+ }
+ },
+ "security": [
+ {
+ "bearerAuth": []
+ }
+ ],
+ "x-service": "fhir_artifacts"
+ }
+ },
"/fhir/profiles": {
"get": {
"operationId": "profiles_list",
@@ -6832,6 +6944,9 @@
"404": {
"description": "Profile not found"
},
+ "409": {
+ "description": "Profile is pinned by an exact implementation guide package"
+ },
"500": {
"description": "Server error"
}
@@ -7050,6 +7165,9 @@
"404": {
"description": "Profile or version not found"
},
+ "409": {
+ "description": "Profile version is pinned by an exact implementation guide package"
+ },
"500": {
"description": "Server error"
}
@@ -10278,7 +10396,7 @@
"fhir_resources": {
"type": "object",
"additionalProperties": true,
- "description": "FHIR resources (single resource or Bundle). Must contain at least one\nPatient resource. Supported row-producing resources are Patient,\nEncounter, Condition, Procedure, MedicationRequest,\nMedicationStatement, MedicationAdministration, Immunization,\nObservation, and AllergyIntolerance. Standalone Medication resources\nare consumed by medication references rather than mapped to their own\ntable. Other resource types are accepted but ignored.\n"
+ "description": "FHIR resources (single resource or Bundle). Must contain at least one\nPatient resource. Supported row-producing resources are Patient,\nLocation, Organization, HealthcareService, Practitioner,\nPractitionerRole, Encounter, Condition, Procedure, MedicationRequest,\nMedicationStatement, MedicationAdministration, Immunization,\nObservation, and AllergyIntolerance. Standalone Medication resources\nare consumed by medication references rather than mapped to their own\ntable. Unsupported resource types are accepted in a Bundle but ignored.\n"
}
}
},
@@ -10310,7 +10428,7 @@
},
"vocab_version": {
"type": "string",
- "description": "The OMOP vocabulary release the clinical codes were resolved against\n(e.g. \"v20240229\"), for reproducibility. Present when at least one\ncoded concept was resolved.\n"
+ "description": "The OMOP vocabulary release returned for coded concept resolution\n(for example, \"v20240229\"), for reproducibility. It is generally\nabsent for requests containing only text-only resources.\n"
},
"summary": {
"$ref": "#/components/schemas/fhir2omop_Summary"
@@ -10319,7 +10437,7 @@
},
"fhir2omop_OmopTables": {
"type": "object",
- "description": "OMOP CDM v5.4 rows grouped by destination table.",
+ "description": "OMOP CDM v5.4 rows grouped by destination table. IDs are sequential and\nscoped to one response; they are not stable keys across requests.\n",
"properties": {
"location": {
"type": "array",
@@ -10978,6 +11096,12 @@
},
"mapping_status": {
"type": "string",
+ "enum": [
+ "ALREADY_STANDARD",
+ "MAPPED",
+ "UNCHECKED",
+ "UNMAPPED"
+ ],
"description": "ALREADY_STANDARD (source coding is already a standard OMOP concept),\nMAPPED (source coding was mapped to a standard concept), UNCHECKED (a\nstandard code was suggested \u2014 e.g. for a text-only resource \u2014 but not\nverified against the OMOP vocabulary, so `concept_id` stays `0`), or\nUNMAPPED (no standard concept found).\n"
},
"note": {
@@ -10987,24 +11111,24 @@
},
"fhir2omop_Summary": {
"type": "object",
- "description": "The request's data-quality headline: how the coded concepts split across\nresolution outcomes, and the share that was not already in a target\nstandard vocabulary. Each coded resource is counted once (per resolved\nconcept), even when it carried several codings \u2014 unlike `mappings`, which\nhas one entry per coding.\n",
+ "description": "The request's data-quality headline: how resolution outcomes split, and\nthe share that was not already in a target standard vocabulary. Each\nrow-producing clinical resource is counted once, even when it carried\nseveral codings \u2014 unlike `mappings`, which has one entry per coding.\n",
"properties": {
"codes_already_standard": {
"type": "integer",
- "description": "Coded concepts already a standard OMOP concept (ALREADY_STANDARD)."
+ "description": "Resolution outcomes already a standard OMOP concept (ALREADY_STANDARD)."
},
"codes_normalized": {
"type": "integer",
- "description": "Coded concepts mapped or suggested to a standard concept (MAPPED or UNCHECKED)."
+ "description": "Resolution outcomes mapped or suggested to a standard concept (MAPPED or UNCHECKED)."
},
"codes_unmapped": {
"type": "integer",
- "description": "Coded concepts with no standard concept found (UNMAPPED)."
+ "description": "Resolution outcomes with no standard concept found (UNMAPPED)."
},
"off_vocab_rate": {
"type": "number",
"format": "double",
- "description": "Share of coded concepts not already standard ((normalized + unmapped) / total)."
+ "description": "Share of resolution outcomes not already standard ((normalized + unmapped) / total)."
}
}
},
@@ -11788,7 +11912,7 @@
"properties": {
"request_id": {
"type": "string",
- "description": "Optional client idempotency token. A retried create with the same\ntoken returns the original job instead of opening a second one.\n",
+ "description": "Optional client idempotency token (at most 256 UTF-8 bytes). A\nretried create with the same token returns the original job instead\nof opening a second one.\n",
"example": "submit-2025-09-02-batch-001"
}
}
@@ -11803,7 +11927,7 @@
"properties": {
"kind": {
"type": "string",
- "description": "Short stable token to branch on. Item-level kinds: `invalid_input`\n(the stored body was not a valid create/document request),\n`processing_failed` (the conversion failed), `budget_exceeded` (the\nitem ran past its time budget \u2014 600s for a document item, 450s for a\ncreate item), `result_too_large` (the result exceeded the storage\ncap), `input_unavailable` (the input could not be read), and\n`retries_exhausted` / `attempts_exhausted` (buried after too many\nfailed attempts).\nJob-level kinds: `timeout` (the job did not finish within 36 hours\nof creation).\n",
+ "description": "Short stable token to branch on. Item-level kinds: `invalid_input`\n(the stored body was not a valid create/document request),\n`processing_failed` (the conversion failed), `result_too_large` (the\nresult exceeded the storage cap), `input_unavailable` (the input\ncould not be read), and `retries_exhausted` / `attempts_exhausted`\n(the item could not complete after repeated interruptions).\nJob-level kinds: `timeout` (the job did not finish within 36 hours\nof creation).\n",
"example": "processing_failed"
},
"message": {
@@ -11838,7 +11962,7 @@
},
"status": {
"type": "string",
- "description": "Job status. `completed` means every item has finished \u2014 some may have\nfailed, so check `counts` for the split. `failed` is a whole-job\nfailure (the job could not run at all), distinct from individual item\nfailures, which never fail the job. `canceled` is a caller-requested\ncancellation via `POST /lang2fhir/batch/{job_id}/cancel`; like the\nother terminal states it frees the job's active-job slot and keeps any\nresults already produced readable for the retention window.\n",
+ "description": "Job status. `completed` means every item has finished \u2014 some may have\nfailed, so check `counts` for the split. `failed` is a whole-job\nfailure (the job could not run at all), distinct from individual item\nfailures, which never fail the job. `canceled` is a caller-requested\ncancellation via `POST /lang2fhir/batch/{job_id}/cancel`; like the\nother terminal states it keeps any results already produced readable\nfor the retention window.\n",
"enum": [
"pending",
"processing",
@@ -11951,7 +12075,7 @@
},
"attempts": {
"type": "integer",
- "description": "Number of processing attempts so far. An item runs up to 3 attempts,\nand only an interruption \u2014 a worker preemption or a recovered internal\nerror \u2014 is retried; a conversion error fails the item with no retry.\n",
+ "description": "Number of processing attempts started so far. The service may retry\ninterrupted work; a conversion error fails the item without retry.\n",
"example": 1
},
"detect_retries": {
@@ -12568,7 +12692,7 @@
},
"content": {
"type": "string",
- "description": "Base64 encoded file content.\nSupported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff).\nFile type is auto-detected from content magic bytes.\n"
+ "description": "Base64 encoded file content.\nSupported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff), RTF (application/rtf), XML/C-CDA (text/xml).\nRTF and XML/C-CDA uploads are available on dedicated instances only.\nFile type is auto-detected from content magic bytes.\nThe decoded file must not exceed 20 MiB. RTF and XML/C-CDA documents whose extracted text exceeds 1 MiB are rejected.\nGeneric XML must include an XML declaration; C-CDA documents rooted at `ClinicalDocument` may omit it.\n"
},
"provider": {
"type": "string",
@@ -12708,7 +12832,7 @@
},
"lang2fhir_ResourceReview": {
"type": "object",
- "description": "Opt-in, report-only faithfulness audit (honored by /lang2fhir/create/multi and /lang2fhir/document/multi). For each selected resource type an LLM checks whether selected dates and clinical code concepts are actually supported by the full source document. Resources with an unsupported field are pulled out of the returned bundle and reported under resource_review in the response.\n",
+ "description": "Opt-in faithfulness audit (honored by /lang2fhir/create/multi and /lang2fhir/document/multi). For each selected resource type an LLM checks whether selected dates and clinical code concepts are actually supported by the full source document. An unsupported individual coding is removed when another coding remains in its concept. Resources with an unsupported structural field, a profile-required coding, or no coding remaining in an affected concept, are pulled out of the returned bundle and reported under resource_review in the response.\n",
"required": [
"targets"
],
@@ -12754,14 +12878,21 @@
},
"lang2fhir_ResourceReviewResult": {
"type": "object",
- "description": "Present when resource_review was requested and at least one resource was flagged.\n",
+ "description": "Present when resource_review was requested and at least one resource was quarantined or safely remediated. The returned bundle is authoritative and contains the post-review representation of every retained resource.\n",
"properties": {
"flagged": {
"type": "array",
- "description": "Resources pulled from the bundle because a reviewed field was not supported by the source.",
+ "description": "Resources pulled from the bundle because an unsupported finding could not be safely repaired.",
"items": {
"$ref": "#/components/schemas/lang2fhir_ResourceReviewFlagged"
}
+ },
+ "remediated": {
+ "type": "array",
+ "description": "Resources retained in the bundle after unsupported codings were safely removed.",
+ "items": {
+ "$ref": "#/components/schemas/lang2fhir_ResourceReviewRemediated"
+ }
}
}
},
@@ -12783,7 +12914,35 @@
},
"findings": {
"type": "array",
- "description": "The unsupported fields that caused the resource to be flagged.",
+ "description": "The findings that caused the resource to be quarantined.",
+ "items": {
+ "$ref": "#/components/schemas/lang2fhir_ResourceReviewFinding"
+ }
+ }
+ }
+ },
+ "lang2fhir_ResourceReviewRemediated": {
+ "type": "object",
+ "properties": {
+ "tempId": {
+ "type": "string",
+ "description": "The urn:uuid of the remediated resource (its bundle fullUrl).",
+ "example": "urn:uuid:a842c4bc-f6cb-4555-9741-ac3aec4ef0b8"
+ },
+ "resourceType": {
+ "type": "string",
+ "example": "Condition"
+ },
+ "action": {
+ "type": "string",
+ "enum": [
+ "removed_codings"
+ ],
+ "description": "The safe change applied to the resource in the returned bundle."
+ },
+ "findings": {
+ "type": "array",
+ "description": "Findings for fields in the pre-remediation resource that caused this action.",
"items": {
"$ref": "#/components/schemas/lang2fhir_ResourceReviewFinding"
}
@@ -12812,9 +12971,14 @@
},
"supported": {
"type": "boolean",
- "description": "Always false for a flagged finding.",
+ "description": "False when the reviewer found the field unsupported. Do not treat this field as a verdict when unaudited is true.",
"example": false
},
+ "unaudited": {
+ "type": "boolean",
+ "description": "True when the reviewer did not return a verdict for this field; the resource was quarantined without treating the finding as evidence that the value is unsupported.",
+ "example": true
+ },
"rationale": {
"type": "string",
"description": "Short explanation of why the value is not supported by the source.",
@@ -12861,7 +13025,7 @@
},
"content": {
"type": "string",
- "description": "Base64 encoded file content.\nSupported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff).\nFile type is auto-detected from content magic bytes.\n"
+ "description": "Base64 encoded file content.\nSupported file types: PDF (application/pdf), PNG (image/png), JPEG (image/jpeg), TIFF (image/tiff), RTF (application/rtf), XML/C-CDA (text/xml).\nRTF and XML/C-CDA uploads are available on dedicated instances only.\nFile type is auto-detected from content magic bytes.\nThe decoded file must not exceed 20 MiB. RTF and XML/C-CDA documents whose extracted text exceeds 1 MiB are rejected.\nGeneric XML must include an XML declaration; C-CDA documents rooted at `ClinicalDocument` may omit it.\n"
},
"config": {
"$ref": "#/components/schemas/lang2fhir_DocumentConfig"
@@ -13056,7 +13220,7 @@
},
"implementation-guides_ImplementationGuideSummary": {
"type": "object",
- "description": "Metadata for an implementation guide. This is an instance-local grouping record, not a complete FHIR ImplementationGuide resource.\n",
+ "description": "Metadata for an implementation guide. Canonical fields are present only for published canonical packages; metadata-only legacy records omit them.\n",
"properties": {
"name": {
"type": "string",
@@ -13073,6 +13237,14 @@
"description": "The number of custom profiles in this implementation guide.",
"example": 3
},
+ "canonical_url": {
+ "type": "string",
+ "description": "Canonical FHIR ImplementationGuide URL, when the family has an exact package."
+ },
+ "version_count": {
+ "type": "integer",
+ "description": "Number of retained exact package versions."
+ },
"created_at": {
"type": "string",
"format": "date-time",
@@ -13119,6 +13291,125 @@
}
]
},
+ "implementation-guides_CreateCanonicalImplementationGuideRequest": {
+ "type": "object",
+ "required": [
+ "implementation_guide",
+ "profile_refs"
+ ],
+ "properties": {
+ "implementation_guide": {
+ "$ref": "#/components/schemas/implementation-guides_FHIRImplementationGuide"
+ },
+ "profile_refs": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 250,
+ "description": "Exact canonical `url|version` references to builtin or custom profiles. A package can contain at most 250 references.\n",
+ "items": {
+ "type": "string"
+ }
+ },
+ "profile_context": {
+ "type": "string",
+ "maxLength": 2000,
+ "description": "Natural-language profile-selection context for this package."
+ }
+ }
+ },
+ "implementation-guides_ImplementationGuideVersionDetail": {
+ "type": "object",
+ "required": [
+ "name",
+ "url",
+ "version",
+ "profile_context",
+ "profiles",
+ "profile_refs",
+ "implementation_guide",
+ "created_at",
+ "updated_at"
+ ],
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string"
+ },
+ "version": {
+ "type": "string"
+ },
+ "profile_context": {
+ "type": "string"
+ },
+ "profiles": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "profile_refs": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "implementation_guide": {
+ "$ref": "#/components/schemas/implementation-guides_FHIRImplementationGuide"
+ },
+ "created_at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "updated_at": {
+ "type": "string",
+ "format": "date-time"
+ }
+ }
+ },
+ "implementation-guides_FHIRImplementationGuide": {
+ "type": "object",
+ "description": "A complete authored FHIR ImplementationGuide JSON resource.",
+ "required": [
+ "resourceType",
+ "url",
+ "version"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "resourceType": {
+ "type": "string",
+ "enum": [
+ "ImplementationGuide"
+ ]
+ },
+ "id": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string"
+ },
+ "version": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "status": {
+ "type": "string"
+ },
+ "packageId": {
+ "type": "string"
+ },
+ "fhirVersion": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
"implementation-guides_UpdateImplementationGuideRequest": {
"type": "object",
"properties": {