diff --git a/connegp-0.1.6-py3-none-any.whl b/connegp-0.1.6-py3-none-any.whl
deleted file mode 100755
index 1cc73c1f..00000000
Binary files a/connegp-0.1.6-py3-none-any.whl and /dev/null differ
diff --git a/poetry.lock b/poetry.lock
index 82c21253..ca483b23 100755
--- a/poetry.lock
+++ b/poetry.lock
@@ -93,13 +93,13 @@ uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "cachetools"
-version = "5.3.2"
+version = "5.3.3"
description = "Extensible memoizing collections and decorators"
optional = false
python-versions = ">=3.7"
files = [
- {file = "cachetools-5.3.2-py3-none-any.whl", hash = "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1"},
- {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"},
+ {file = "cachetools-5.3.3-py3-none-any.whl", hash = "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945"},
+ {file = "cachetools-5.3.3.tar.gz", hash = "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105"},
]
[[package]]
@@ -259,82 +259,65 @@ files = [
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
-[[package]]
-name = "connegp"
-version = "0.1.6"
-description = "Content negotiation by profile"
-optional = false
-python-versions = ">=3.8,<4.0"
-files = [
- {file = "connegp-0.1.6-py3-none-any.whl", hash = "sha256:8d4f7f605d568032243e7cfa84c22bedae66e28651acb58af82b4b43d3de899f"},
-]
-
-[package.dependencies]
-pydantic = ">=1.8.2,<3.0.0"
-
-[package.source]
-type = "file"
-url = "connegp-0.1.6-py3-none-any.whl"
-
[[package]]
name = "coverage"
-version = "7.4.1"
+version = "7.4.3"
description = "Code coverage measurement for Python"
optional = false
python-versions = ">=3.8"
files = [
- {file = "coverage-7.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:077d366e724f24fc02dbfe9d946534357fda71af9764ff99d73c3c596001bbd7"},
- {file = "coverage-7.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0193657651f5399d433c92f8ae264aff31fc1d066deee4b831549526433f3f61"},
- {file = "coverage-7.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d17bbc946f52ca67adf72a5ee783cd7cd3477f8f8796f59b4974a9b59cacc9ee"},
- {file = "coverage-7.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3277f5fa7483c927fe3a7b017b39351610265308f5267ac6d4c2b64cc1d8d25"},
- {file = "coverage-7.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dceb61d40cbfcf45f51e59933c784a50846dc03211054bd76b421a713dcdf19"},
- {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6008adeca04a445ea6ef31b2cbaf1d01d02986047606f7da266629afee982630"},
- {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c61f66d93d712f6e03369b6a7769233bfda880b12f417eefdd4f16d1deb2fc4c"},
- {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9bb62fac84d5f2ff523304e59e5c439955fb3b7f44e3d7b2085184db74d733b"},
- {file = "coverage-7.4.1-cp310-cp310-win32.whl", hash = "sha256:f86f368e1c7ce897bf2457b9eb61169a44e2ef797099fb5728482b8d69f3f016"},
- {file = "coverage-7.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:869b5046d41abfea3e381dd143407b0d29b8282a904a19cb908fa24d090cc018"},
- {file = "coverage-7.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b8ffb498a83d7e0305968289441914154fb0ef5d8b3157df02a90c6695978295"},
- {file = "coverage-7.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3cacfaefe6089d477264001f90f55b7881ba615953414999c46cc9713ff93c8c"},
- {file = "coverage-7.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d6850e6e36e332d5511a48a251790ddc545e16e8beaf046c03985c69ccb2676"},
- {file = "coverage-7.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18e961aa13b6d47f758cc5879383d27b5b3f3dcd9ce8cdbfdc2571fe86feb4dd"},
- {file = "coverage-7.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfd1e1b9f0898817babf840b77ce9fe655ecbe8b1b327983df485b30df8cc011"},
- {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6b00e21f86598b6330f0019b40fb397e705135040dbedc2ca9a93c7441178e74"},
- {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:536d609c6963c50055bab766d9951b6c394759190d03311f3e9fcf194ca909e1"},
- {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7ac8f8eb153724f84885a1374999b7e45734bf93a87d8df1e7ce2146860edef6"},
- {file = "coverage-7.4.1-cp311-cp311-win32.whl", hash = "sha256:f3771b23bb3675a06f5d885c3630b1d01ea6cac9e84a01aaf5508706dba546c5"},
- {file = "coverage-7.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:9d2f9d4cc2a53b38cabc2d6d80f7f9b7e3da26b2f53d48f05876fef7956b6968"},
- {file = "coverage-7.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f68ef3660677e6624c8cace943e4765545f8191313a07288a53d3da188bd8581"},
- {file = "coverage-7.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23b27b8a698e749b61809fb637eb98ebf0e505710ec46a8aa6f1be7dc0dc43a6"},
- {file = "coverage-7.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e3424c554391dc9ef4a92ad28665756566a28fecf47308f91841f6c49288e66"},
- {file = "coverage-7.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0860a348bf7004c812c8368d1fc7f77fe8e4c095d661a579196a9533778e156"},
- {file = "coverage-7.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe558371c1bdf3b8fa03e097c523fb9645b8730399c14fe7721ee9c9e2a545d3"},
- {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3468cc8720402af37b6c6e7e2a9cdb9f6c16c728638a2ebc768ba1ef6f26c3a1"},
- {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:02f2edb575d62172aa28fe00efe821ae31f25dc3d589055b3fb64d51e52e4ab1"},
- {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ca6e61dc52f601d1d224526360cdeab0d0712ec104a2ce6cc5ccef6ed9a233bc"},
- {file = "coverage-7.4.1-cp312-cp312-win32.whl", hash = "sha256:ca7b26a5e456a843b9b6683eada193fc1f65c761b3a473941efe5a291f604c74"},
- {file = "coverage-7.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:85ccc5fa54c2ed64bd91ed3b4a627b9cce04646a659512a051fa82a92c04a448"},
- {file = "coverage-7.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8bdb0285a0202888d19ec6b6d23d5990410decb932b709f2b0dfe216d031d218"},
- {file = "coverage-7.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:918440dea04521f499721c039863ef95433314b1db00ff826a02580c1f503e45"},
- {file = "coverage-7.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:379d4c7abad5afbe9d88cc31ea8ca262296480a86af945b08214eb1a556a3e4d"},
- {file = "coverage-7.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b094116f0b6155e36a304ff912f89bbb5067157aff5f94060ff20bbabdc8da06"},
- {file = "coverage-7.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2f5968608b1fe2a1d00d01ad1017ee27efd99b3437e08b83ded9b7af3f6f766"},
- {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:10e88e7f41e6197ea0429ae18f21ff521d4f4490aa33048f6c6f94c6045a6a75"},
- {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a4a3907011d39dbc3e37bdc5df0a8c93853c369039b59efa33a7b6669de04c60"},
- {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d224f0c4c9c98290a6990259073f496fcec1b5cc613eecbd22786d398ded3ad"},
- {file = "coverage-7.4.1-cp38-cp38-win32.whl", hash = "sha256:23f5881362dcb0e1a92b84b3c2809bdc90db892332daab81ad8f642d8ed55042"},
- {file = "coverage-7.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:a07f61fc452c43cd5328b392e52555f7d1952400a1ad09086c4a8addccbd138d"},
- {file = "coverage-7.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8e738a492b6221f8dcf281b67129510835461132b03024830ac0e554311a5c54"},
- {file = "coverage-7.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46342fed0fff72efcda77040b14728049200cbba1279e0bf1188f1f2078c1d70"},
- {file = "coverage-7.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9641e21670c68c7e57d2053ddf6c443e4f0a6e18e547e86af3fad0795414a628"},
- {file = "coverage-7.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aeb2c2688ed93b027eb0d26aa188ada34acb22dceea256d76390eea135083950"},
- {file = "coverage-7.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d12c923757de24e4e2110cf8832d83a886a4cf215c6e61ed506006872b43a6d1"},
- {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0491275c3b9971cdbd28a4595c2cb5838f08036bca31765bad5e17edf900b2c7"},
- {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8dfc5e195bbef80aabd81596ef52a1277ee7143fe419efc3c4d8ba2754671756"},
- {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1a78b656a4d12b0490ca72651fe4d9f5e07e3c6461063a9b6265ee45eb2bdd35"},
- {file = "coverage-7.4.1-cp39-cp39-win32.whl", hash = "sha256:f90515974b39f4dea2f27c0959688621b46d96d5a626cf9c53dbc653a895c05c"},
- {file = "coverage-7.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:64e723ca82a84053dd7bfcc986bdb34af8d9da83c521c19d6b472bc6880e191a"},
- {file = "coverage-7.4.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:32a8d985462e37cfdab611a6f95b09d7c091d07668fdc26e47a725ee575fe166"},
- {file = "coverage-7.4.1.tar.gz", hash = "sha256:1ed4b95480952b1a26d863e546fa5094564aa0065e1e5f0d4d0041f293251d04"},
+ {file = "coverage-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8580b827d4746d47294c0e0b92854c85a92c2227927433998f0d3320ae8a71b6"},
+ {file = "coverage-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:718187eeb9849fc6cc23e0d9b092bc2348821c5e1a901c9f8975df0bc785bfd4"},
+ {file = "coverage-7.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:767b35c3a246bcb55b8044fd3a43b8cd553dd1f9f2c1eeb87a302b1f8daa0524"},
+ {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae7f19afe0cce50039e2c782bff379c7e347cba335429678450b8fe81c4ef96d"},
+ {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba3a8aaed13770e970b3df46980cb068d1c24af1a1968b7818b69af8c4347efb"},
+ {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ee866acc0861caebb4f2ab79f0b94dbfbdbfadc19f82e6e9c93930f74e11d7a0"},
+ {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:506edb1dd49e13a2d4cac6a5173317b82a23c9d6e8df63efb4f0380de0fbccbc"},
+ {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd6545d97c98a192c5ac995d21c894b581f1fd14cf389be90724d21808b657e2"},
+ {file = "coverage-7.4.3-cp310-cp310-win32.whl", hash = "sha256:f6a09b360d67e589236a44f0c39218a8efba2593b6abdccc300a8862cffc2f94"},
+ {file = "coverage-7.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:18d90523ce7553dd0b7e23cbb28865db23cddfd683a38fb224115f7826de78d0"},
+ {file = "coverage-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbbe5e739d45a52f3200a771c6d2c7acf89eb2524890a4a3aa1a7fa0695d2a47"},
+ {file = "coverage-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:489763b2d037b164846ebac0cbd368b8a4ca56385c4090807ff9fad817de4113"},
+ {file = "coverage-7.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:451f433ad901b3bb00184d83fd83d135fb682d780b38af7944c9faeecb1e0bfe"},
+ {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcc66e222cf4c719fe7722a403888b1f5e1682d1679bd780e2b26c18bb648cdc"},
+ {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ec74cfef2d985e145baae90d9b1b32f85e1741b04cd967aaf9cfa84c1334f3"},
+ {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:abbbd8093c5229c72d4c2926afaee0e6e3140de69d5dcd918b2921f2f0c8baba"},
+ {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:35eb581efdacf7b7422af677b92170da4ef34500467381e805944a3201df2079"},
+ {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8249b1c7334be8f8c3abcaaa996e1e4927b0e5a23b65f5bf6cfe3180d8ca7840"},
+ {file = "coverage-7.4.3-cp311-cp311-win32.whl", hash = "sha256:cf30900aa1ba595312ae41978b95e256e419d8a823af79ce670835409fc02ad3"},
+ {file = "coverage-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:18c7320695c949de11a351742ee001849912fd57e62a706d83dfc1581897fa2e"},
+ {file = "coverage-7.4.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b51bfc348925e92a9bd9b2e48dad13431b57011fd1038f08316e6bf1df107d10"},
+ {file = "coverage-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d6cdecaedea1ea9e033d8adf6a0ab11107b49571bbb9737175444cea6eb72328"},
+ {file = "coverage-7.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b2eccb883368f9e972e216c7b4c7c06cabda925b5f06dde0650281cb7666a30"},
+ {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c00cdc8fa4e50e1cc1f941a7f2e3e0f26cb2a1233c9696f26963ff58445bac7"},
+ {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4a8dd3dcf4cbd3165737358e4d7dfbd9d59902ad11e3b15eebb6393b0446e"},
+ {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:062b0a75d9261e2f9c6d071753f7eef0fc9caf3a2c82d36d76667ba7b6470003"},
+ {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ebe7c9e67a2d15fa97b77ea6571ce5e1e1f6b0db71d1d5e96f8d2bf134303c1d"},
+ {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c0a120238dd71c68484f02562f6d446d736adcc6ca0993712289b102705a9a3a"},
+ {file = "coverage-7.4.3-cp312-cp312-win32.whl", hash = "sha256:37389611ba54fd6d278fde86eb2c013c8e50232e38f5c68235d09d0a3f8aa352"},
+ {file = "coverage-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:d25b937a5d9ffa857d41be042b4238dd61db888533b53bc76dc082cb5a15e914"},
+ {file = "coverage-7.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28ca2098939eabab044ad68850aac8f8db6bf0b29bc7f2887d05889b17346454"},
+ {file = "coverage-7.4.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:280459f0a03cecbe8800786cdc23067a8fc64c0bd51dc614008d9c36e1659d7e"},
+ {file = "coverage-7.4.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c0cdedd3500e0511eac1517bf560149764b7d8e65cb800d8bf1c63ebf39edd2"},
+ {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a9babb9466fe1da12417a4aed923e90124a534736de6201794a3aea9d98484e"},
+ {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dec9de46a33cf2dd87a5254af095a409ea3bf952d85ad339751e7de6d962cde6"},
+ {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:16bae383a9cc5abab9bb05c10a3e5a52e0a788325dc9ba8499e821885928968c"},
+ {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2c854ce44e1ee31bda4e318af1dbcfc929026d12c5ed030095ad98197eeeaed0"},
+ {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ce8c50520f57ec57aa21a63ea4f325c7b657386b3f02ccaedeccf9ebe27686e1"},
+ {file = "coverage-7.4.3-cp38-cp38-win32.whl", hash = "sha256:708a3369dcf055c00ddeeaa2b20f0dd1ce664eeabde6623e516c5228b753654f"},
+ {file = "coverage-7.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:1bf25fbca0c8d121a3e92a2a0555c7e5bc981aee5c3fdaf4bb7809f410f696b9"},
+ {file = "coverage-7.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b253094dbe1b431d3a4ac2f053b6d7ede2664ac559705a704f621742e034f1f"},
+ {file = "coverage-7.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77fbfc5720cceac9c200054b9fab50cb2a7d79660609200ab83f5db96162d20c"},
+ {file = "coverage-7.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6679060424faa9c11808598504c3ab472de4531c571ab2befa32f4971835788e"},
+ {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4af154d617c875b52651dd8dd17a31270c495082f3d55f6128e7629658d63765"},
+ {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8640f1fde5e1b8e3439fe482cdc2b0bb6c329f4bb161927c28d2e8879c6029ee"},
+ {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:69b9f6f66c0af29642e73a520b6fed25ff9fd69a25975ebe6acb297234eda501"},
+ {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0842571634f39016a6c03e9d4aba502be652a6e4455fadb73cd3a3a49173e38f"},
+ {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a78ed23b08e8ab524551f52953a8a05d61c3a760781762aac49f8de6eede8c45"},
+ {file = "coverage-7.4.3-cp39-cp39-win32.whl", hash = "sha256:c0524de3ff096e15fcbfe8f056fdb4ea0bf497d584454f344d59fce069d3e6e9"},
+ {file = "coverage-7.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:0209a6369ccce576b43bb227dc8322d8ef9e323d089c6f3f26a597b09cb4d2aa"},
+ {file = "coverage-7.4.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:7cbde573904625509a3f37b6fecea974e363460b556a627c60dc2f47e2fffa51"},
+ {file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52"},
]
[package.extras]
@@ -455,13 +438,13 @@ files = [
[[package]]
name = "httpcore"
-version = "1.0.3"
+version = "1.0.4"
description = "A minimal low-level HTTP client."
optional = false
python-versions = ">=3.8"
files = [
- {file = "httpcore-1.0.3-py3-none-any.whl", hash = "sha256:9a6a501c3099307d9fd76ac244e08503427679b1e81ceb1d922485e2f2462ad2"},
- {file = "httpcore-1.0.3.tar.gz", hash = "sha256:5c0f9546ad17dac4d0772b0808856eb616eb8b48ce94f49ed819fd6982a8a544"},
+ {file = "httpcore-1.0.4-py3-none-any.whl", hash = "sha256:ac418c1db41bade2ad53ae2f3834a3a0f5ae76b56cf5aa497d2d033384fc7d73"},
+ {file = "httpcore-1.0.4.tar.gz", hash = "sha256:cb2839ccfcba0d2d3c1131d3c3e26dfc327326fbe7a5dc0dbfe9f6c9151bb022"},
]
[package.dependencies]
@@ -472,7 +455,7 @@ h11 = ">=0.13,<0.15"
asyncio = ["anyio (>=4.0,<5.0)"]
http2 = ["h2 (>=3,<5)"]
socks = ["socksio (==1.*)"]
-trio = ["trio (>=0.22.0,<0.24.0)"]
+trio = ["trio (>=0.22.0,<0.25.0)"]
[[package]]
name = "httpx"
@@ -919,18 +902,18 @@ virtualenv = ">=20.10.0"
[[package]]
name = "pydantic"
-version = "2.6.1"
+version = "2.6.3"
description = "Data validation using Python type hints"
optional = false
python-versions = ">=3.8"
files = [
- {file = "pydantic-2.6.1-py3-none-any.whl", hash = "sha256:0b6a909df3192245cb736509a92ff69e4fef76116feffec68e93a567347bae6f"},
- {file = "pydantic-2.6.1.tar.gz", hash = "sha256:4fd5c182a2488dc63e6d32737ff19937888001e2a6d86e94b3f233104a5d1fa9"},
+ {file = "pydantic-2.6.3-py3-none-any.whl", hash = "sha256:72c6034df47f46ccdf81869fddb81aade68056003900a8724a4f160700016a2a"},
+ {file = "pydantic-2.6.3.tar.gz", hash = "sha256:e07805c4c7f5c6826e33a1d4c9d47950d7eaf34868e2690f8594d2e30241f11f"},
]
[package.dependencies]
annotated-types = ">=0.4.0"
-pydantic-core = "2.16.2"
+pydantic-core = "2.16.3"
typing-extensions = ">=4.6.1"
[package.extras]
@@ -938,90 +921,90 @@ email = ["email-validator (>=2.0.0)"]
[[package]]
name = "pydantic-core"
-version = "2.16.2"
+version = "2.16.3"
description = ""
optional = false
python-versions = ">=3.8"
files = [
- {file = "pydantic_core-2.16.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3fab4e75b8c525a4776e7630b9ee48aea50107fea6ca9f593c98da3f4d11bf7c"},
- {file = "pydantic_core-2.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8bde5b48c65b8e807409e6f20baee5d2cd880e0fad00b1a811ebc43e39a00ab2"},
- {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2924b89b16420712e9bb8192396026a8fbd6d8726224f918353ac19c4c043d2a"},
- {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16aa02e7a0f539098e215fc193c8926c897175d64c7926d00a36188917717a05"},
- {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:936a787f83db1f2115ee829dd615c4f684ee48ac4de5779ab4300994d8af325b"},
- {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:459d6be6134ce3b38e0ef76f8a672924460c455d45f1ad8fdade36796df1ddc8"},
- {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9ee4febb249c591d07b2d4dd36ebcad0ccd128962aaa1801508320896575ef"},
- {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40a0bd0bed96dae5712dab2aba7d334a6c67cbcac2ddfca7dbcc4a8176445990"},
- {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:870dbfa94de9b8866b37b867a2cb37a60c401d9deb4a9ea392abf11a1f98037b"},
- {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:308974fdf98046db28440eb3377abba274808bf66262e042c412eb2adf852731"},
- {file = "pydantic_core-2.16.2-cp310-none-win32.whl", hash = "sha256:a477932664d9611d7a0816cc3c0eb1f8856f8a42435488280dfbf4395e141485"},
- {file = "pydantic_core-2.16.2-cp310-none-win_amd64.whl", hash = "sha256:8f9142a6ed83d90c94a3efd7af8873bf7cefed2d3d44387bf848888482e2d25f"},
- {file = "pydantic_core-2.16.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:406fac1d09edc613020ce9cf3f2ccf1a1b2f57ab00552b4c18e3d5276c67eb11"},
- {file = "pydantic_core-2.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce232a6170dd6532096cadbf6185271e4e8c70fc9217ebe105923ac105da9978"},
- {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90fec23b4b05a09ad988e7a4f4e081711a90eb2a55b9c984d8b74597599180f"},
- {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8aafeedb6597a163a9c9727d8a8bd363a93277701b7bfd2749fbefee2396469e"},
- {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9957433c3a1b67bdd4c63717eaf174ebb749510d5ea612cd4e83f2d9142f3fc8"},
- {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0d7a9165167269758145756db43a133608a531b1e5bb6a626b9ee24bc38a8f7"},
- {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dffaf740fe2e147fedcb6b561353a16243e654f7fe8e701b1b9db148242e1272"},
- {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ed79883b4328b7f0bd142733d99c8e6b22703e908ec63d930b06be3a0e7113"},
- {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cf903310a34e14651c9de056fcc12ce090560864d5a2bb0174b971685684e1d8"},
- {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46b0d5520dbcafea9a8645a8164658777686c5c524d381d983317d29687cce97"},
- {file = "pydantic_core-2.16.2-cp311-none-win32.whl", hash = "sha256:70651ff6e663428cea902dac297066d5c6e5423fda345a4ca62430575364d62b"},
- {file = "pydantic_core-2.16.2-cp311-none-win_amd64.whl", hash = "sha256:98dc6f4f2095fc7ad277782a7c2c88296badcad92316b5a6e530930b1d475ebc"},
- {file = "pydantic_core-2.16.2-cp311-none-win_arm64.whl", hash = "sha256:ef6113cd31411eaf9b39fc5a8848e71c72656fd418882488598758b2c8c6dfa0"},
- {file = "pydantic_core-2.16.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:88646cae28eb1dd5cd1e09605680c2b043b64d7481cdad7f5003ebef401a3039"},
- {file = "pydantic_core-2.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7b883af50eaa6bb3299780651e5be921e88050ccf00e3e583b1e92020333304b"},
- {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bf26c2e2ea59d32807081ad51968133af3025c4ba5753e6a794683d2c91bf6e"},
- {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99af961d72ac731aae2a1b55ccbdae0733d816f8bfb97b41909e143de735f522"},
- {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02906e7306cb8c5901a1feb61f9ab5e5c690dbbeaa04d84c1b9ae2a01ebe9379"},
- {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5362d099c244a2d2f9659fb3c9db7c735f0004765bbe06b99be69fbd87c3f15"},
- {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ac426704840877a285d03a445e162eb258924f014e2f074e209d9b4ff7bf380"},
- {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b94cbda27267423411c928208e89adddf2ea5dd5f74b9528513f0358bba019cb"},
- {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6db58c22ac6c81aeac33912fb1af0e930bc9774166cdd56eade913d5f2fff35e"},
- {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396fdf88b1b503c9c59c84a08b6833ec0c3b5ad1a83230252a9e17b7dfb4cffc"},
- {file = "pydantic_core-2.16.2-cp312-none-win32.whl", hash = "sha256:7c31669e0c8cc68400ef0c730c3a1e11317ba76b892deeefaf52dcb41d56ed5d"},
- {file = "pydantic_core-2.16.2-cp312-none-win_amd64.whl", hash = "sha256:a3b7352b48fbc8b446b75f3069124e87f599d25afb8baa96a550256c031bb890"},
- {file = "pydantic_core-2.16.2-cp312-none-win_arm64.whl", hash = "sha256:a9e523474998fb33f7c1a4d55f5504c908d57add624599e095c20fa575b8d943"},
- {file = "pydantic_core-2.16.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ae34418b6b389d601b31153b84dce480351a352e0bb763684a1b993d6be30f17"},
- {file = "pydantic_core-2.16.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:732bd062c9e5d9582a30e8751461c1917dd1ccbdd6cafb032f02c86b20d2e7ec"},
- {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b52776a2e3230f4854907a1e0946eec04d41b1fc64069ee774876bbe0eab55"},
- {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef551c053692b1e39e3f7950ce2296536728871110e7d75c4e7753fb30ca87f4"},
- {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ebb892ed8599b23fa8f1799e13a12c87a97a6c9d0f497525ce9858564c4575a4"},
- {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa6c8c582036275997a733427b88031a32ffa5dfc3124dc25a730658c47a572f"},
- {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ba0884a91f1aecce75202473ab138724aa4fb26d7707f2e1fa6c3e68c84fbf"},
- {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7924e54f7ce5d253d6160090ddc6df25ed2feea25bfb3339b424a9dd591688bc"},
- {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69a7b96b59322a81c2203be537957313b07dd333105b73db0b69212c7d867b4b"},
- {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7e6231aa5bdacda78e96ad7b07d0c312f34ba35d717115f4b4bff6cb87224f0f"},
- {file = "pydantic_core-2.16.2-cp38-none-win32.whl", hash = "sha256:41dac3b9fce187a25c6253ec79a3f9e2a7e761eb08690e90415069ea4a68ff7a"},
- {file = "pydantic_core-2.16.2-cp38-none-win_amd64.whl", hash = "sha256:f685dbc1fdadb1dcd5b5e51e0a378d4685a891b2ddaf8e2bba89bd3a7144e44a"},
- {file = "pydantic_core-2.16.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:55749f745ebf154c0d63d46c8c58594d8894b161928aa41adbb0709c1fe78b77"},
- {file = "pydantic_core-2.16.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b30b0dd58a4509c3bd7eefddf6338565c4905406aee0c6e4a5293841411a1286"},
- {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18de31781cdc7e7b28678df7c2d7882f9692ad060bc6ee3c94eb15a5d733f8f7"},
- {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5864b0242f74b9dd0b78fd39db1768bc3f00d1ffc14e596fd3e3f2ce43436a33"},
- {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8f9186ca45aee030dc8234118b9c0784ad91a0bb27fc4e7d9d6608a5e3d386c"},
- {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc6f6c9be0ab6da37bc77c2dda5f14b1d532d5dbef00311ee6e13357a418e646"},
- {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa057095f621dad24a1e906747179a69780ef45cc8f69e97463692adbcdae878"},
- {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ad84731a26bcfb299f9eab56c7932d46f9cad51c52768cace09e92a19e4cf55"},
- {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3b052c753c4babf2d1edc034c97851f867c87d6f3ea63a12e2700f159f5c41c3"},
- {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0f686549e32ccdb02ae6f25eee40cc33900910085de6aa3790effd391ae10c2"},
- {file = "pydantic_core-2.16.2-cp39-none-win32.whl", hash = "sha256:7afb844041e707ac9ad9acad2188a90bffce2c770e6dc2318be0c9916aef1469"},
- {file = "pydantic_core-2.16.2-cp39-none-win_amd64.whl", hash = "sha256:9da90d393a8227d717c19f5397688a38635afec89f2e2d7af0df037f3249c39a"},
- {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f60f920691a620b03082692c378661947d09415743e437a7478c309eb0e4f82"},
- {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:47924039e785a04d4a4fa49455e51b4eb3422d6eaacfde9fc9abf8fdef164e8a"},
- {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6294e76b0380bb7a61eb8a39273c40b20beb35e8c87ee101062834ced19c545"},
- {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe56851c3f1d6f5384b3051c536cc81b3a93a73faf931f404fef95217cf1e10d"},
- {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9d776d30cde7e541b8180103c3f294ef7c1862fd45d81738d156d00551005784"},
- {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:72f7919af5de5ecfaf1eba47bf9a5d8aa089a3340277276e5636d16ee97614d7"},
- {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:4bfcbde6e06c56b30668a0c872d75a7ef3025dc3c1823a13cf29a0e9b33f67e8"},
- {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ff7c97eb7a29aba230389a2661edf2e9e06ce616c7e35aa764879b6894a44b25"},
- {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9b5f13857da99325dcabe1cc4e9e6a3d7b2e2c726248ba5dd4be3e8e4a0b6d0e"},
- {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a7e41e3ada4cca5f22b478c08e973c930e5e6c7ba3588fb8e35f2398cdcc1545"},
- {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60eb8ceaa40a41540b9acae6ae7c1f0a67d233c40dc4359c256ad2ad85bdf5e5"},
- {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7beec26729d496a12fd23cf8da9944ee338c8b8a17035a560b585c36fe81af20"},
- {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:22c5f022799f3cd6741e24f0443ead92ef42be93ffda0d29b2597208c94c3753"},
- {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:eca58e319f4fd6df004762419612122b2c7e7d95ffafc37e890252f869f3fb2a"},
- {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed957db4c33bc99895f3a1672eca7e80e8cda8bd1e29a80536b4ec2153fa9804"},
- {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:459c0d338cc55d099798618f714b21b7ece17eb1a87879f2da20a3ff4c7628e2"},
- {file = "pydantic_core-2.16.2.tar.gz", hash = "sha256:0ba503850d8b8dcc18391f10de896ae51d37fe5fe43dbfb6a35c5c5cad271a06"},
+ {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"},
+ {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"},
+ {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"},
+ {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"},
+ {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"},
+ {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"},
+ {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"},
+ {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"},
+ {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"},
+ {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"},
+ {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"},
+ {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"},
+ {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"},
+ {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"},
+ {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"},
+ {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"},
+ {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"},
+ {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"},
+ {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"},
+ {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"},
+ {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"},
+ {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"},
+ {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"},
+ {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"},
+ {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"},
+ {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"},
+ {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"},
+ {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"},
+ {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"},
+ {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"},
+ {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"},
+ {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"},
+ {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"},
+ {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"},
+ {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"},
+ {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"},
+ {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"},
+ {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"},
+ {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"},
+ {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"},
+ {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"},
+ {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"},
+ {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"},
+ {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"},
+ {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"},
+ {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"},
+ {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"},
+ {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"},
+ {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"},
+ {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"},
+ {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"},
+ {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"},
+ {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"},
+ {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"},
+ {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"},
+ {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"},
+ {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"},
+ {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"},
+ {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"},
+ {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"},
+ {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"},
+ {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"},
+ {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"},
+ {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"},
+ {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"},
+ {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"},
+ {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"},
+ {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"},
+ {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"},
+ {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"},
+ {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"},
+ {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"},
+ {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"},
+ {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"},
+ {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"},
+ {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"},
+ {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"},
+ {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"},
+ {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"},
]
[package.dependencies]
@@ -1029,13 +1012,13 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
[[package]]
name = "pydantic-settings"
-version = "2.2.0"
+version = "2.2.1"
description = "Settings management using Pydantic"
optional = false
python-versions = ">=3.8"
files = [
- {file = "pydantic_settings-2.2.0-py3-none-any.whl", hash = "sha256:5f7bcaf9ad4419559dc5ac155c0324a9aeb2547c60471ee7c7d026f467a6b515"},
- {file = "pydantic_settings-2.2.0.tar.gz", hash = "sha256:648d0a76673e69c51278979cba2e83cf16a23d57519bfd7e553d1c3f37db5560"},
+ {file = "pydantic_settings-2.2.1-py3-none-any.whl", hash = "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091"},
+ {file = "pydantic_settings-2.2.1.tar.gz", hash = "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed"},
]
[package.dependencies]
@@ -1043,7 +1026,7 @@ pydantic = ">=2.3.0"
python-dotenv = ">=0.21.0"
[package.extras]
-toml = ["tomlkit (>=0.12)"]
+toml = ["tomli (>=2.0.1)"]
yaml = ["pyyaml (>=6.0.1)"]
[[package]]
@@ -1374,19 +1357,19 @@ wheel = ">=0.36.1"
[[package]]
name = "setuptools"
-version = "69.1.0"
+version = "69.1.1"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.8"
files = [
- {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"},
- {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"},
+ {file = "setuptools-69.1.1-py3-none-any.whl", hash = "sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56"},
+ {file = "setuptools-69.1.1.tar.gz", hash = "sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8"},
]
[package.extras]
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
-testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
-testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
+testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
+testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
[[package]]
name = "shapely"
@@ -1458,13 +1441,13 @@ files = [
[[package]]
name = "sniffio"
-version = "1.3.0"
+version = "1.3.1"
description = "Sniff out which async library your code is running under"
optional = false
python-versions = ">=3.7"
files = [
- {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"},
- {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"},
+ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
+ {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
]
[[package]]
@@ -1497,13 +1480,13 @@ files = [
[[package]]
name = "typing-extensions"
-version = "4.9.0"
+version = "4.10.0"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
files = [
- {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"},
- {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"},
+ {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"},
+ {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"},
]
[[package]]
@@ -1543,13 +1526,13 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)",
[[package]]
name = "virtualenv"
-version = "20.25.0"
+version = "20.25.1"
description = "Virtual Python Environment builder"
optional = false
python-versions = ">=3.7"
files = [
- {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"},
- {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"},
+ {file = "virtualenv-20.25.1-py3-none-any.whl", hash = "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a"},
+ {file = "virtualenv-20.25.1.tar.gz", hash = "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197"},
]
[package.dependencies]
@@ -1578,4 +1561,4 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"]
[metadata]
lock-version = "2.0"
python-versions = "^3.11"
-content-hash = "9e52b0cd2075bbbc6693b39f79b388a505e3744feeeb85c235b7f735afedc848"
+content-hash = "86ae28eb5f2c4f08bc245ca34113f8d401778b377ca1050aa5d25565ff7ebe1e"
diff --git a/prez/models/profiles_and_mediatypes.py b/prez/models/profiles_and_mediatypes.py
deleted file mode 100755
index fdaa646f..00000000
--- a/prez/models/profiles_and_mediatypes.py
+++ /dev/null
@@ -1,58 +0,0 @@
-from typing import FrozenSet, Optional
-
-from pydantic import BaseModel, model_validator
-from rdflib import Namespace, URIRef
-from starlette.requests import Request
-
-from prez.services.generate_profiles import get_profiles_and_mediatypes
-from prez.services.connegp_service import get_requested_profile_and_mediatype
-from prez.repositories import Repo
-
-PREZ = Namespace("https://prez.dev/")
-
-
-class ProfilesMediatypesInfo(BaseModel):
- class Config:
- arbitrary_types_allowed = True
-
- request: Request # TODO slim down once connegp is refactored so the whole request doesn't need to be passed through
- classes: FrozenSet[URIRef]
- system_repo: Repo
- req_profiles: Optional[str] = None
- req_profiles_token: Optional[str] = None
- req_mediatypes: Optional[FrozenSet] = None
- profile: Optional[URIRef] = None
- mediatype: Optional[str] = None
- selected_class: Optional[URIRef] = None
- profile_headers: Optional[str] = None
- avail_profile_uris: Optional[str] = None
- listing: Optional[bool] = False
-
- @model_validator(mode="after")
- def populate_requested_types(self):
- request = self.request
- (
- self.req_profiles,
- self.req_profiles_token,
- self.req_mediatypes,
- ) = get_requested_profile_and_mediatype(request)
- return self
-
-
-async def populate_profile_and_mediatype(
- prof_model: ProfilesMediatypesInfo, system_repo: Repo
-):
- req_profiles = prof_model.req_profiles
- req_profiles_token = prof_model.req_profiles_token
- req_mediatypes = prof_model.req_mediatypes
- classes = prof_model.classes
- listing = prof_model.listing
- (
- prof_model.profile,
- prof_model.mediatype,
- prof_model.selected_class,
- prof_model.profile_headers,
- prof_model.avail_profile_uris,
- ) = await get_profiles_and_mediatypes(
- classes, system_repo, req_profiles, req_profiles_token, req_mediatypes, listing
- )
diff --git a/prez/services/connegp_service.py b/prez/services/connegp_service.py
index 08b4aaa8..1053dfc8 100755
--- a/prez/services/connegp_service.py
+++ b/prez/services/connegp_service.py
@@ -3,14 +3,11 @@
from textwrap import dedent
from pydantic import BaseModel
-from pyoxigraph import Store
from rdflib import Graph, Namespace, URIRef
-from prez.cache import prefix_graph, system_store
-from prez.dependencies import get_system_repo
from prez.models.model_exceptions import NoProfilesException
from prez.repositories.base import Repo
-from prez.services.curie_functions import get_curie_id_for_uri
+from prez.services.curie_functions import get_curie_id_for_uri, get_uri_for_curie_id
logger = logging.getLogger("prez")
@@ -37,64 +34,58 @@ class NegotiatedPMTs(BaseModel):
headers: dict
params: dict
classes: list[URIRef]
+ system_repo: Repo
listing: bool = False
default_weighting: float = 1.0
requested_profiles: list[tuple[str, float]] | None = None
requested_mediatypes: list[tuple[str, float]] | None = None
available: list[dict] | None = None
selected: dict | None = None
- _system_store: Store | None = None
- _prefix_graph: Graph | None = None
- _system_repo: Repo | None = None
class Config:
arbitrary_types_allowed = True
async def setup(self) -> bool:
- if self._system_store is None:
- self._system_store = system_store
- if self._prefix_graph is None:
- self._prefix_graph = prefix_graph
- if self._system_repo is None:
- self._system_repo = await get_system_repo(self._system_store)
self.requested_profiles = await self._get_requested_profiles()
self.requested_mediatypes = await self._get_requested_mediatypes()
self.available = await self._get_available()
self.selected = await self._get_selected()
return True if self.selected else False
- def _resolve_token(self, token: str) -> str:
+ async def _resolve_token(self, token: str) -> str:
query_str: str = dedent("""
PREFIX dcterms:
PREFIX xsd:
PREFIX prof:
- SELECT ?s
+ SELECT ?profile
WHERE {
- ?s a prof:Profile .
- ?s dcterms:identifier ?o .
+ ?profile a prof:Profile .
+ ?profile dcterms:identifier ?o .
FILTER(?o=""^^xsd:token)
}
""".replace("", token))
try:
- result = {result[0].value for result in self._system_store.query(query_str)}.pop()
- except KeyError:
+ _, results = await self.system_repo.send_queries([], [(None, query_str)])
+ result: str = results[0][1][0]["profile"]["value"]
+ except (KeyError, IndexError, ValueError):
raise TokenError(f"Token: '{token}' could not be resolved to URI")
uri = "<" + result + ">"
return uri
- def _tupilize(self, string: str, is_profile: bool = False) -> tuple[str, float]:
+ async def _tupilize(self, string: str, is_profile: bool = False) -> tuple[str, float]:
parts: list[str | float] = string.split("q=") # split out the weighting
parts[0] = parts[0].strip(" ;") # remove the seperator character, and any whitespace characters
if is_profile and not re.search(r"^<.*>$", parts[0]): # If it doesn't look like a URI ...
try:
- parts[0] = self._resolve_token(parts[0]) # then try to resolve the token to a URI
+ parts[0] = await self._resolve_token(parts[0]) # then try to resolve the token to a URI
except TokenError as e:
logger.error(e.args[0])
try: # if token resolution fails, try to resolve as a curie
- result = str(self._prefix_graph.namespace_manager.expand_curie(parts[0]))
+ result = str(get_uri_for_curie_id(parts[0]))
parts[0] = "<" + result + ">"
except ValueError as e:
+ parts[0] = "" # if curie resolution failed, then the profile is invalid
logger.error(e.args[0])
if len(parts) == 1:
parts.append(self.default_weighting) # If no weight given, set the default
@@ -102,8 +93,7 @@ def _tupilize(self, string: str, is_profile: bool = False) -> tuple[str, float]:
try:
parts[1] = float(parts[1]) # Type-check the seperated weighting
except ValueError as e:
- log = logging.getLogger("prez")
- log.debug(
+ logger.debug(
f"Could not cast q={parts[1]} as float. Defaulting to {self.default_weighting}. {e.args[0]}")
return parts[0], parts[1]
@@ -114,18 +104,18 @@ def _prioritize(types: list[tuple[str, float]]) -> list[tuple[str, float]]:
async def _get_requested_profiles(self) -> list[tuple[str, float]] | None:
raw_profiles: str = self.params.get("_profile", "") # Prefer profiles declared in the QSA, as per the spec.
if not raw_profiles:
- raw_profiles: str = self.headers.get("Accept-Profile", "")
+ raw_profiles: str = self.headers.get("accept-profile", "")
if raw_profiles:
- profiles: list = [self._tupilize(profile, is_profile=True) for profile in raw_profiles.split(",")]
+ profiles: list = [await self._tupilize(profile, is_profile=True) for profile in raw_profiles.split(",")]
return self._prioritize(profiles)
return None
async def _get_requested_mediatypes(self) -> list[tuple[str, float]] | None:
raw_mediatypes: str = self.params.get("_media", "") # Prefer mediatypes declared in the QSA, as per the spec.
if not raw_mediatypes:
- raw_mediatypes: str = self.headers.get("Accept", "")
+ raw_mediatypes: str = self.headers.get("accept", "")
if raw_mediatypes:
- mediatypes: list = [self._tupilize(mediatype) for mediatype in raw_mediatypes.split(",")]
+ mediatypes: list = [await self._tupilize(mediatype) for mediatype in raw_mediatypes.split(",")]
return self._prioritize(mediatypes)
return None
@@ -162,7 +152,6 @@ def generate_response_headers(self) -> dict:
]
)
headers = {
- "Access-Control-Allow-Origin": "*", # HACK: why is this specified here?
"Content-Type": self.selected["mediatype"],
"link": profile_header_links + mediatype_header_links
}
@@ -172,10 +161,10 @@ def _compose_select_query(self) -> str:
prez = Namespace("https://prez.dev/")
profile_class = prez.ListingProfile if self.listing else prez.ObjectProfile
try:
- requested_profile = self.requested_profiles[0] # TODO: handle multiple requested profiles
+ requested_profile = self.requested_profiles[0][0] # TODO: handle multiple requested profiles
except TypeError as e:
requested_profile = None
- logger.debug(e)
+ logger.debug(f"{e}. normally this just means no profiles were requested")
query = dedent(
f"""
@@ -203,7 +192,7 @@ def _compose_select_query(self) -> str:
altr-ext:hasResourceFormat ?format ;
dcterms:title ?title .\
{f'?profile a {profile_class.n3()} .'}
- {f'BIND(?profile=<{requested_profile}> as ?req_profile)' if requested_profile else ''}
+ {f'BIND(?profile={requested_profile} as ?req_profile)' if requested_profile else ''}
BIND(EXISTS {{ ?shape sh:targetClass ?class ;
altr-ext:hasDefaultProfile ?profile }} AS ?def_profile)
{self._generate_mediatype_if_statements()}
@@ -241,7 +230,7 @@ def _generate_mediatype_if_statements(self) -> str:
return ifs
async def _do_query(self, query: str) -> tuple[Graph, list]:
- response = await self._system_repo.send_queries([], [(None, query)])
+ response = await self.system_repo.send_queries([], [(None, query)])
if not response[1][0][1]:
raise NoProfilesException(self.classes)
return response
diff --git a/prez/services/generate_profiles.py b/prez/services/generate_profiles.py
index 532a1785..734122bf 100755
--- a/prez/services/generate_profiles.py
+++ b/prez/services/generate_profiles.py
@@ -1,15 +1,9 @@
import logging
from pathlib import Path
-from typing import FrozenSet
-from rdflib import Graph, URIRef, RDF, PROF, Literal
+from rdflib import Graph
-from prez.cache import profiles_graph_cache, prefix_graph
-from prez.models.model_exceptions import NoProfilesException
-from prez.reference_data.prez_ns import PREZ
-from prez.services.curie_functions import get_curie_id_for_uri
-from prez.repositories import Repo
-from prez.services.query_generation.connegp import select_profile_mediatype
+from prez.cache import profiles_graph_cache
log = logging.getLogger(__name__)
@@ -61,121 +55,3 @@ async def create_profiles_graph(repo) -> Graph:
log.info(f"Remote profile(s) found and added")
else:
log.info("No remote profiles found")
-
-
-async def get_profiles_and_mediatypes(
- classes: FrozenSet[URIRef],
- system_repo: Repo,
- requested_profile: URIRef = None,
- requested_profile_token: str = None,
- requested_mediatype: URIRef = None,
- listing: bool = False,
-):
- query = select_profile_mediatype(
- classes,
- requested_profile,
- requested_profile_token,
- requested_mediatype,
- listing,
- )
- log.debug(f"ConnegP query: {query}")
- response = await system_repo.send_queries([], [(None, query)])
- # log.debug(f"ConnegP response:{results_pretty_printer(response)}")
- if response[1][0][1] == []:
- raise NoProfilesException(classes)
- top_result = response[1][0][1][0]
- profile, mediatype, selected_class = (
- URIRef(top_result["profile"]["value"]),
- Literal(top_result["format"]["value"]),
- URIRef(top_result["class"]["value"]),
- )
- profile_headers, avail_profile_uris = generate_profiles_headers(
- selected_class, response, profile, mediatype
- )
- return profile, mediatype, selected_class, profile_headers, avail_profile_uris
-
-
-def results_pretty_printer(response):
- # Calculate max width for each column, including the new "#" column
- max_widths = [
- len(str(len(response.bindings)))
- ] # length of the highest row number as a string
- for header in response.vars:
- max_width = max(
- len(header.n3(prefix_graph.namespace_manager)),
- max(
- len(
- row[header].n3(prefix_graph.namespace_manager)
- if row[header]
- else ""
- )
- for row in response.bindings
- ),
- )
- max_widths.append(max_width)
-
- # Header row
- header_row = "\n" + " | ".join(
- ["#".ljust(max_widths[0])]
- + [
- str(header).ljust(max_widths[i + 1])
- for i, header in enumerate(response.vars)
- ]
- )
- pp_string = header_row + "\n"
- pp_string += ("-" * len(header_row)) + "\n" # Divider
-
- # Data rows
- row_number = 1
- for row in response.bindings:
- row_data = [str(row_number).ljust(max_widths[0])]
- row_data += [
- (
- row[header].n3(prefix_graph.namespace_manager) if row[header] else ""
- ).ljust(max_widths[i + 1])
- for i, header in enumerate(response.vars)
- ]
- formatted_row = " | ".join(row_data)
- pp_string += formatted_row + "\n"
- row_number += 1
-
- return pp_string
-
-
-def generate_profiles_headers(selected_class, response, profile, mediatype):
- headers = {
- "Access-Control-Allow-Origin": "*",
- "Content-Type": mediatype,
- }
- avail_profiles = set(
- (
- get_curie_id_for_uri(i["profile"]["value"]),
- i["profile"]["value"],
- i["title"]["value"],
- )
- for i in response[1][0][1]
- )
- avail_profiles_headers = ", ".join(
- [
- f'; rel="type"; title="{i[2]}"; token="{i[0]}"; anchor=<{i[1]}>'
- for i in avail_profiles
- ]
- )
- avail_mediatypes_headers = ", ".join(
- [
- f"""<{selected_class}?_profile={get_curie_id_for_uri(i["profile"]["value"])}&_mediatype={i["format"]["value"]}>; \
-rel="{"self" if i["profile"]["value"] == profile and i["format"]["value"] == mediatype else "alternate"}"; \
-type="{i["format"]["value"]}"; profile="{i["profile"]["value"]}"\
-"""
- for i in response[1][0][1]
- ]
- )
- headers["Link"] = ", ".join(
- [
- f'<{profile}>; rel="profile"',
- avail_profiles_headers,
- avail_mediatypes_headers,
- ]
- )
- avail_profile_uris = [i[1] for i in avail_profiles]
- return headers, avail_profile_uris
diff --git a/prez/services/listings.py b/prez/services/listings.py
index a8b6cc81..e2d6f4a1 100755
--- a/prez/services/listings.py
+++ b/prez/services/listings.py
@@ -9,13 +9,10 @@
from prez.cache import profiles_graph_cache, endpoints_graph_cache
from prez.config import settings
-from prez.models.profiles_and_mediatypes import (
- ProfilesMediatypesInfo,
- populate_profile_and_mediatype,
-)
from prez.reference_data.prez_ns import PREZ
from prez.renderers.renderer import return_from_graph
from prez.repositories import Repo
+from prez.services.connegp_service import NegotiatedPMTs
from prez.services.link_generation import add_prez_links
from prez.services.query_generation.classes import get_classes
from prez.services.query_generation.count import CountQuery
@@ -32,17 +29,17 @@
async def listing_function(
- request: Request,
- repo: Repo,
- system_repo: Repo,
- endpoint_uri: URIRef,
- hierarchy_level: int,
- path_nodes: Dict[str, Var | IRI] = None,
- page: int = 1,
- per_page: int = 20,
- cql_parser: CQLParser = None,
- search_term: Optional[str] = None,
- endpoint_structure: Tuple[str] = settings.endpoint_structure,
+ request: Request,
+ repo: Repo,
+ system_repo: Repo,
+ endpoint_uri: URIRef,
+ hierarchy_level: int,
+ path_nodes: Dict[str, Var | IRI] = None,
+ page: int = 1,
+ per_page: int = 20,
+ cql_parser: CQLParser = None,
+ search_term: Optional[str] = None,
+ endpoint_structure: Tuple[str] = settings.endpoint_structure,
):
"""
# determine the relevant node selection part of the query - from SHACL, CQL, Search
@@ -65,29 +62,25 @@ async def listing_function(
target_classes = frozenset([PREZ.CQLObjectList])
elif search_term:
target_classes = frozenset([PREZ.SearchResult])
+
# determine the relevant profile
- prof_and_mt_info = ProfilesMediatypesInfo(
- request=request, classes=target_classes, system_repo=system_repo, listing=True
- )
- await populate_profile_and_mediatype(prof_and_mt_info, system_repo)
- selected_class, selected_profile = (
- prof_and_mt_info.selected_class,
- prof_and_mt_info.profile,
- )
+ pmts = NegotiatedPMTs(headers=request.headers, params=request.query_params, classes=target_classes, listing=True,
+ system_repo=system_repo)
+ success = await pmts.setup()
+ if not success:
+ log.error("ConnegP Error. NegotiatedPMTs.setup() was not successful")
runtime_values = {}
- if prof_and_mt_info.profile == URIRef(
- "http://www.w3.org/ns/dx/conneg/altr-ext#alt-profile"
- ):
+ if pmts.selected["profile"] == URIRef("http://www.w3.org/ns/dx/conneg/altr-ext#alt-profile"):
ns = NodeShape(
uri=URIRef("http://example.org/ns#AltProfilesForListing"),
graph=endpoints_graph_cache,
- path_nodes={"path_node_1": IRI(value=prof_and_mt_info.selected_class)}
+ path_nodes={"path_node_1": IRI(value=pmts.selected["class"])}
)
ns_triples = ns.triples_list
ns_gpnt = ns.gpnt_list
endpoint_uri = URIRef("https://prez.dev/endpoint/system/alt-profiles-listing")
- runtime_values["selectedClass"] = prof_and_mt_info.selected_class
+ runtime_values["selectedClass"] = pmts.selected["class"]
runtime_values["limit"] = per_page
runtime_values["offset"] = (page - 1) * per_page
@@ -114,7 +107,7 @@ async def listing_function(
profile_graph=profiles_graph_cache,
listing_or_object="listing",
endpoint_uri=endpoint_uri,
- profile_uri=selected_profile,
+ profile_uri=pmts.selected["profile"],
endpoint_shacl_triples=ns_triples,
endpoint_shacl_gpnt=ns_gpnt,
cql_triples=cql_triples_list,
@@ -136,26 +129,31 @@ async def listing_function(
queries.append(search_query)
else:
queries.append(main_query)
- req_mt = prof_and_mt_info.req_mediatypes
- if req_mt:
- if list(req_mt)[0] == "application/sparql-query":
- return PlainTextResponse(queries[0], media_type="application/sparql-query")
+ if pmts.requested_mediatypes is not None and pmts.requested_mediatypes[0][0] == "application/sparql-query":
+ return PlainTextResponse(queries[0], media_type="application/sparql-query")
# add a count query if it's an annotated mediatype
- if "anot+" in prof_and_mt_info.mediatype and not search_term:
+ if "anot+" in pmts.selected["mediatype"] and not search_term:
subselect = copy.deepcopy(query_constructor.inner_select)
count_query = CountQuery(subselect=subselect).render()
queries.append(count_query)
- if prof_and_mt_info.profile == URIRef(
- "http://www.w3.org/ns/dx/conneg/altr-ext#alt-profile"
- ):
+ # if prof_and_mt_info.profile == URIRef(
+ # "http://www.w3.org/ns/dx/conneg/altr-ext#alt-profile"
+ # ):
+ # count_class = PROF.Profile
+ # else:
+ # count_class = target_classes
+ # if count_class: # target_class may be unknown (None) for queries involving CQL
+ # queries.append(temp_listing_count(subselect, count_class))
+
+ if pmts.selected["profile"] == URIRef("http://www.w3.org/ns/dx/conneg/altr-ext#alt-profile"):
item_graph, _ = await system_repo.send_queries(queries, [])
- if "anot+" in prof_and_mt_info.mediatype:
+ if "anot+" in pmts.selected["mediatype"]:
await add_prez_links(item_graph, system_repo, endpoint_structure=("profiles",))
else:
item_graph, _ = await repo.send_queries(queries, [])
- if "anot+" in prof_and_mt_info.mediatype:
+ if "anot+" in pmts.selected["mediatype"]:
await add_prez_links(item_graph, repo, endpoint_structure)
# count search results - hard to do in SPARQL as the SELECT part of the query is NOT aggregated
if search_term:
@@ -163,16 +161,16 @@ async def listing_function(
item_graph.add((PREZ.SearchResult, PREZ["count"], Literal(count)))
return await return_from_graph(
item_graph,
- prof_and_mt_info.mediatype,
- selected_profile,
- prof_and_mt_info.profile_headers,
- prof_and_mt_info.selected_class,
+ pmts.selected["mediatype"],
+ pmts.selected["profile"],
+ pmts.generate_response_headers(),
+ pmts.selected["class"],
repo,
)
async def get_shacl_node_selection(
- endpoint_uri, hierarchy_level, path_nodes, repo, system_repo
+ endpoint_uri, hierarchy_level, path_nodes, repo, system_repo
):
"""
Determines the relevant nodeshape based on the endpoint, hierarchy level, and parent URI
diff --git a/prez/services/objects.py b/prez/services/objects.py
index d0562fda..48681e9b 100755
--- a/prez/services/objects.py
+++ b/prez/services/objects.py
@@ -20,20 +20,26 @@
async def object_function(
- request: Request,
- endpoint_uri: URIRef,
- uri: URIRef,
- repo: Repo,
- system_repo: Repo,
- endpoint_structure: Tuple[str] = settings.endpoint_structure,
+ request: Request,
+ endpoint_uri: URIRef,
+ uri: URIRef,
+ request_url: str,
+ repo: Repo,
+ system_repo: Repo,
+ endpoint_structure: Tuple[str] = settings.endpoint_structure,
):
classes = await get_classes(uri=uri, repo=repo)
- pmts = NegotiatedPMTs(**{"headers": request.headers, "params": request.query_params, "classes": classes})
+ pmts = NegotiatedPMTs(headers=request.headers, params=request.query_params, classes=classes,
+ system_repo=system_repo)
+ success = await pmts.setup()
+ if not success:
+ log.error("ConnegP Error. NegotiatedPMTs.setup() was not successful")
+
# handle alternate profiles
runtime_values = {}
if pmts.selected["profile"] == URIRef("http://www.w3.org/ns/dx/conneg/altr-ext#alt-profile"):
endpoint_uri = URIRef("https://prez.dev/endpoint/system/alt-profiles-listing")
- # runtime_values["selectedClass"] = prof_and_mt_info.selected_class
+ # runtime_values["selectedClass"] = prof_and_mt_info.selected_class
# runtime_values["object"] = uri
query_constructor = PrezQueryConstructor(
diff --git a/prez/services/query_generation/connegp.py b/prez/services/query_generation/connegp.py
deleted file mode 100644
index 20ab5f97..00000000
--- a/prez/services/query_generation/connegp.py
+++ /dev/null
@@ -1,123 +0,0 @@
-import logging
-from textwrap import dedent
-from typing import List, Tuple
-
-from rdflib import URIRef, Namespace
-
-from prez.services.curie_functions import get_uri_for_curie_id
-
-log = logging.getLogger(__name__)
-
-ALTREXT = Namespace("http://www.w3.org/ns/dx/conneg/altr-ext#")
-PREZ = Namespace("https://prez.dev/")
-
-
-def select_profile_mediatype(
- classes: List[URIRef],
- requested_profile_uri: URIRef = None,
- requested_profile_token: str = None,
- requested_mediatypes: List[Tuple] = None,
- listing: bool = False,
-):
- """
- Returns a SPARQL SELECT query which will determine the profile and mediatype to return based on user requests,
- defaults, and the availability of these in profiles.
-
- NB: Most specific class refers to the rdfs:Class of an object which has the most specific rdfs:subClassOf links to
- the base class delivered by that API endpoint. The base classes delivered by each API endpoint are:
-
- SpacePrez:
- /s/catalogs -> prez:DatasetList
- /s/catalogs/{ds_id} -> dcat:Dataset
- /s/catalogs/{ds_id}/collections/{fc_id} -> geo:FeatureCollection
- /s/catalogs/{ds_id}/collections -> prez:FeatureCollectionList
- /s/catalogs/{ds_id}/collections/{fc_id}/features -> geo:Feature
-
- VocPrez:
- /v/schemes -> skos:ConceptScheme
- /v/collections -> skos:Collection
- /v/schemes/{cs_id}/concepts -> skos:Concept
-
- CatPrez:
- /c/catalogs -> dcat:Catalog
- /c/catalogs/{cat_id}/datasets -> dcat:Dataset
-
- The following logic is used to determine the profile and mediatype to be returned:
-
- 1. If a profile and mediatype are requested, they are returned if a matching profile which has the requested
- mediatype is found, otherwise the default profile for the most specific class is returned, with its default
- mediatype.
- 2. If a profile only is requested, if it can be found it is returned, otherwise the default profile for the most
- specific class is returned. In both cases the default mediatype is returned.
- 3. If a mediatype only is requested, the default profile for the most specific class is returned, and if the
- requested mediatype is available for that profile, it is returned, otherwise the default mediatype for that profile
- is returned.
- 4. If neither a profile nor mediatype is requested, the default profile for the most specific class is returned,
- with the default mediatype for that profile.
- """
- if listing:
- profile_class = PREZ.ListingProfile
- else:
- profile_class = PREZ.ObjectProfile
- if requested_profile_token:
- requested_profile_uri = get_uri_for_curie_id(requested_profile_token)
- query = dedent(
- f""" PREFIX altr-ext:
- PREFIX dcat:
- PREFIX dcterms:
- PREFIX geo:
- PREFIX prez:
- PREFIX prof:
- PREFIX rdfs:
- PREFIX skos:
- PREFIX sh:
-
- SELECT ?profile ?title ?class (count(?mid) as ?distance) ?req_profile ?def_profile ?format ?req_format ?def_format
-
- WHERE {{
- VALUES ?class {{{" ".join('<' + str(klass) + '>' for klass in classes)}}}
- ?class rdfs:subClassOf* ?mid .
- ?mid rdfs:subClassOf* ?base_class .
- VALUES ?base_class {{ dcat:Dataset geo:FeatureCollection geo:Feature
- skos:ConceptScheme skos:Concept skos:Collection
- dcat:Catalog dcat:Resource prof:Profile prez:SPARQLQuery
- prez:SearchResult prez:CQLObjectList prez:QueryablesList prez:Object }}
- ?profile altr-ext:constrainsClass ?class ;
- altr-ext:hasResourceFormat ?format ;
- dcterms:title ?title .\
- {f'?profile a {profile_class.n3()} .'}
- {f'BIND(?profile=<{requested_profile_uri}> as ?req_profile)' if requested_profile_uri else ''}
- BIND(EXISTS {{ ?shape sh:targetClass ?class ;
- altr-ext:hasDefaultProfile ?profile }} AS ?def_profile)
- {generate_mediatype_if_statements(requested_mediatypes) if requested_mediatypes else ''}
- BIND(EXISTS {{ ?profile altr-ext:hasDefaultResourceFormat ?format }} AS ?def_format)
- }}
- GROUP BY ?class ?profile ?req_profile ?def_profile ?format ?req_format ?def_format ?title
- ORDER BY DESC(?req_profile) DESC(?distance) DESC(?def_profile) DESC(?req_format) DESC(?def_format)"""
- )
- return query
-
-
-def generate_mediatype_if_statements(requested_mediatypes: list):
- """
- Generates a list of if statements which will be used to determine the mediatype to return based on user requests,
- and the availability of these in profiles.
- These are of the form:
- BIND(
- IF(?format="application/ld+json", "0.9",
- IF(?format="text/html", "0.8",
- IF(?format="image/apng", "0.7", ""))) AS ?req_format)
- """
- # TODO ConnegP appears to return a tuple of q values and profiles for headers, and only profiles (no q values) if they
- # are not specified in QSAs.
- if not isinstance(next(iter(requested_mediatypes)), tuple):
- requested_mediatypes = [(1, mt) for mt in requested_mediatypes]
-
- line_join = "," + "\n"
- ifs = (
- f"BIND(\n"
- f"""{line_join.join({chr(9) + 'IF(?format="' + tup[1] + '", "' + str(tup[0]) + '"' for tup in requested_mediatypes})}"""
- f""", ""{')' * len(requested_mediatypes)}\n"""
- f"\tAS ?req_format)"
- )
- return ifs
diff --git a/pyproject.toml b/pyproject.toml
index 428aacc0..f0547c3e 100755
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -9,7 +9,6 @@ python = "^3.11"
uvicorn = "^0.27.1"
httpx = "^0.26.0"
rdflib = "^7.0.0"
-connegp = { file = "connegp-0.1.6-py3-none-any.whl" }
async-lru = "^2.0.4"
geojson-rewind = "^1.0.3"
toml = "^0.10.2"
diff --git a/tests/data/profiles/ogc_records_profile.ttl b/tests/data/profiles/ogc_records_profile.ttl
new file mode 100755
index 00000000..333ef557
--- /dev/null
+++ b/tests/data/profiles/ogc_records_profile.ttl
@@ -0,0 +1,106 @@
+PREFIX altr-ext:
+PREFIX dcat:
+PREFIX dcterms:
+PREFIX geo:
+PREFIX owl:
+PREFIX prez:
+PREFIX prof:
+PREFIX prov:
+PREFIX reg:
+PREFIX rdf:
+PREFIX rdfs:
+PREFIX sh:
+PREFIX skos:
+PREFIX xsd:
+PREFIX endpoint:
+PREFIX shext:
+
+
+prez:OGCRecordsProfile
+ a prof:Profile ;
+ dcterms:identifier "ogc"^^xsd:token ;
+ dcterms:description "A system profile for OGC Records conformant API" ;
+ dcterms:title "OGC Profile" ;
+ altr-ext:constrainsClass prez:CatPrez ;
+ altr-ext:hasDefaultResourceFormat "text/anot+turtle" ;
+ altr-ext:hasNodeShape [
+ a sh:NodeShape ;
+ sh:targetClass dcat:Catalog , skos:Concept , geo:Feature , geo:FeatureCollection , skos:Collection , prez:SearchResult , prez:CQLObjectList ;
+ altr-ext:hasDefaultProfile prez:OGCListingProfile
+ ] , [
+ a sh:NodeShape ;
+ sh:targetClass skos:ConceptScheme ;
+ altr-ext:hasDefaultProfile prez:OGCSchemesListProfile
+ ] , [
+ a sh:NodeShape ;
+ sh:targetClass dcat:Catalog , skos:ConceptScheme , skos:Concept , geo:Feature , geo:FeatureCollection , skos:Collection ;
+ altr-ext:hasDefaultProfile prez:OGCItemProfile
+ ]
+ .
+
+prez:OGCListingProfile
+ a prof:Profile , prez:ListingProfile , sh:NodeShape ;
+ dcterms:title "OGC Listing Profile" ;
+ altr-ext:hasResourceFormat
+ "application/ld+json" ,
+ "application/anot+ld+json" ,
+ "application/rdf+xml" ,
+ "text/anot+turtle" ,
+ "text/turtle" ;
+ altr-ext:hasDefaultResourceFormat "text/anot+turtle" ;
+ altr-ext:constrainsClass dcat:Catalog , skos:Collection , geo:Feature , geo:FeatureCollection , skos:Concept ,
+ dcat:Resource , prof:Profile , prez:SearchResult , prez:CQLObjectList ;
+ sh:property [ sh:path rdf:type ]
+ .
+
+prez:OGCSchemesListProfile
+ a prof:Profile , prez:ListingProfile , sh:NodeShape ;
+ dcterms:title "OGC Concept Scheme Listing Profile" ;
+ altr-ext:hasResourceFormat
+ "application/ld+json" ,
+ "application/anot+ld+json" ,
+ "application/rdf+xml" ,
+ "text/anot+turtle" ,
+ "text/turtle" ;
+ altr-ext:hasDefaultResourceFormat "text/anot+turtle" ;
+ altr-ext:constrainsClass skos:ConceptScheme ;
+ sh:property [
+ sh:minCount 0 ;
+ sh:path (
+ sh:union (
+ dcterms:publisher
+ reg:status
+ ( prov:qualifiedDerivation prov:hadRole )
+ ( prov:qualifiedDerivation prov:entity )
+ )
+ )
+ ]
+ .
+
+prez:OGCItemProfile
+ a prof:Profile , prez:ObjectProfile , sh:NodeShape ;
+ dcterms:title "OGC Object Profile" ;
+ altr-ext:hasResourceFormat
+ "application/ld+json" ,
+ "application/anot+ld+json" ,
+ "application/rdf+xml" ,
+ "text/anot+turtle" ,
+ "text/turtle" ;
+ altr-ext:hasDefaultResourceFormat "text/anot+turtle" ;
+ sh:property [
+ sh:path shext:allPredicateValues ;
+ ] ,
+ [
+ sh:minCount 0 ;
+ sh:path [ sh:inversePath dcterms:hasPart ] ;
+ ] ;
+ shext:bnode-depth 2 ;
+ altr-ext:constrainsClass dcat:Catalog ,
+ dcat:Resource ,
+ skos:ConceptScheme,
+ skos:Collection ,
+ skos:Concept ,
+ geo:FeatureCollection ,
+ geo:Feature ,
+ prof:Profile ;
+ .
diff --git a/tests/data/profiles/spaceprez_default_profiles.ttl b/tests/data/profiles/spaceprez_default_profiles.ttl
new file mode 100755
index 00000000..9e6a3c8a
--- /dev/null
+++ b/tests/data/profiles/spaceprez_default_profiles.ttl
@@ -0,0 +1,138 @@
+PREFIX altr-ext:
+PREFIX dcat:
+PREFIX dcterms:
+PREFIX geo:
+PREFIX owl:
+PREFIX prez:
+PREFIX prof:
+PREFIX rdf:
+PREFIX rdfs:
+PREFIX sh:
+PREFIX skos:
+PREFIX xsd:
+PREFIX shext:
+
+
+prez:SpacePrezProfile
+ a prof:Profile ;
+ dcterms:identifier "spaceprez"^^xsd:token ;
+ dcterms:description "A system profile for SpacePrez" ;
+ skos:prefLabel "SpacePrez profile" ;
+ altr-ext:hasDefaultResourceFormat "text/anot+turtle" ;
+ altr-ext:constrainsClass prez:SpacePrez ;
+ altr-ext:hasNodeShape [
+ a sh:NodeShape ;
+ sh:targetClass dcat:Dataset ;
+ altr-ext:hasDefaultProfile
+ ] , [
+ a sh:NodeShape ;
+ sh:targetClass geo:FeatureCollection ;
+ altr-ext:hasDefaultProfile prez:FeatureCollectionProfile
+ ] , [
+ a sh:NodeShape ;
+ sh:targetClass geo:Feature ;
+ altr-ext:hasDefaultProfile prez:FeatureProfile
+ ] , [
+ a sh:NodeShape ;
+ sh:targetClass prez:DatasetList ;
+ altr-ext:hasDefaultProfile
+ ] , [
+ a sh:NodeShape ;
+ sh:targetClass prez:FeatureCollectionList ;
+ altr-ext:hasDefaultProfile prez:GeoListingProfile
+ ] , [
+ a sh:NodeShape ;
+ sh:targetClass prez:FeatureList ;
+ altr-ext:hasDefaultProfile prez:GeoListingProfile
+ ]
+.
+
+prez:FeatureCollectionProfile a prof:Profile ;
+ dcterms:description "A profile for GeoSPARQL FeatureCollections" ;
+ dcterms:identifier "geofc"^^xsd:token ;
+ dcterms:title "Feature Collection Profile" ;
+ altr-ext:constrainsClass geo:FeatureCollection ;
+ altr-ext:hasDefaultResourceFormat "text/anot+turtle" ;
+ altr-ext:hasResourceFormat
+ "application/ld+json" ,
+ "application/anot+ld+json" ,
+ "application/rdf+xml" ,
+ "text/anot+turtle" ,
+ "text/turtle" ;
+ sh:targetClass geo:FeatureCollection ;
+ sh:property
+ [
+ sh:maxCount 0 ;
+ sh:path rdfs:member ;
+ ] ,
+ [
+ sh:path [ sh:inversePath rdfs:member ] ;
+ ] ;
+ shext:bnode-depth 2 ;
+.
+
+prez:FeatureProfile a prof:Profile ;
+ dcterms:description "A profile for GeoSPARQL Features" ;
+ dcterms:identifier "geofeat"^^xsd:token ;
+ dcterms:title "Feature Profile" ;
+ altr-ext:constrainsClass geo:Feature ;
+ altr-ext:hasDefaultResourceFormat "text/anot+turtle" ;
+ altr-ext:hasResourceFormat
+ "application/ld+json" ,
+ "application/anot+ld+json" ,
+ "application/rdf+xml" ,
+ "text/anot+turtle" ,
+ "text/turtle" ;
+ sh:targetClass geo:Feature ;
+ sh:property
+ [
+ sh:path [ sh:inversePath rdfs:member ] ;
+ ] ,
+ [
+ sh:path shext:allPredicateValues ;
+ ] ;
+ shext:bnode-depth 2 ;
+.
+
+
+prez:GeoListingProfile a prof:Profile ;
+ dcterms:description "A profile for listing GeoSPARQL Features and FeatureCollections" ;
+ dcterms:identifier "geolisting"^^xsd:token ;
+ dcterms:title "Geo Listing Profile" ;
+ altr-ext:constrainsClass prez:FeatureCollectionList , prez:FeatureList ;
+ altr-ext:hasDefaultResourceFormat "text/anot+turtle" ;
+ altr-ext:hasResourceFormat
+ "application/ld+json" ,
+ "application/anot+ld+json" ,
+ "application/rdf+xml" ,
+ "text/anot+turtle" ,
+ "text/turtle" ;
+ sh:property
+ [
+ sh:path [ sh:inversePath rdfs:member ] ;
+ ]
+.
+
+
+ a prof:Profile , prez:SpacePrezProfile ;
+ dcterms:description "Dataset Catalog Vocabulary (DCAT) is a W3C-authored RDF vocabulary designed to facilitate interoperability between data catalogs" ;
+ dcterms:identifier "dcat"^^xsd:token ;
+ dcterms:title "DCAT" ;
+ altr-ext:constrainsClass
+ dcat:Catalog ,
+ dcat:Dataset ;
+ altr-ext:hasDefaultResourceFormat "text/anot+turtle" ;
+ altr-ext:hasResourceFormat
+ "application/ld+json" ,
+ "application/anot+ld+json" ,
+ "application/rdf+xml" ,
+ "text/anot+turtle" ,
+ "text/turtle" ;
+ altr-ext:hasDefaultResourceFormat "text/anot+turtle" ;
+ sh:property [
+ sh:path shext:allPredicateValues ;
+ ] ;
+ shext:bnode-depth 2 ;
+ altr-ext:constrainsClass dcat:Catalog , dcat:Dataset ;
+.
+
diff --git a/tests/test_connegp.py b/tests/test_connegp.py
index 5926f6fa..d09316e6 100644
--- a/tests/test_connegp.py
+++ b/tests/test_connegp.py
@@ -2,50 +2,150 @@
import pytest
from pyoxigraph import Store
-from rdflib import Graph, URIRef
+from pyoxigraph.pyoxigraph import Store
+from rdflib import URIRef
+from prez.app import app
+from prez.dependencies import get_repo
+from prez.repositories import PyoxigraphRepo, Repo
from prez.services.connegp_service import NegotiatedPMTs
-@pytest.fixture(scope="module")
+@pytest.fixture(scope="session")
def test_store() -> Store:
store = Store()
- profiles = Path(__file__).parent / "data" / "profiles" / "remote_profile.ttl"
- store.load(profiles, mime_type="text/turtle")
+ file = Path(__file__).parent / "data/profiles/ogc_records_profile.ttl"
+ store.load(file.read_bytes(), "text/turtle")
+ file = Path(__file__).parent / "data/profiles/spaceprez_default_profiles.ttl"
+ store.load(file.read_bytes(), "text/turtle")
return store
-@pytest.fixture(scope="module")
-def test_prefix_graph():
- graph = Graph(bind_namespaces="rdflib")
- graph.bind("ex", "https://example.com/")
- return graph
+@pytest.fixture(scope="session")
+def test_repo(test_store: Store) -> Repo:
+ return PyoxigraphRepo(test_store)
@pytest.mark.parametrize(
- "headers, params, classes, expected_selected",
+ "headers, params, classes, listing, expected_selected",
[
[
- {"Accept-Profile": ", ;q=0.9"},
- {"_media": "text/anot+turtle, text/turtle;q=0.9"},
- [URIRef("")],
+ {}, # Test that profiles/mediatypes resolve to their defaults if not requested (object endpoint)
+ {},
+ [URIRef("http://www.w3.org/ns/dcat#Catalog")],
+ False,
{
- "profile": "",
- "title": "",
- "mediatype": "",
- "class": ""
+ "profile": URIRef("https://prez.dev/OGCItemProfile"),
+ "title": "OGC Object Profile",
+ "mediatype": "text/anot+turtle",
+ "class": "http://www.w3.org/ns/dcat#Catalog"
+ }
+ ],
+ [
+ {}, # Test that profiles/mediatypes resolve to their defaults if not requested (listing endpoint)
+ {},
+ [URIRef("http://www.w3.org/ns/dcat#Catalog")],
+ True,
+ {
+ "profile": URIRef("https://prez.dev/OGCListingProfile"),
+ "title": "OGC Listing Profile",
+ "mediatype": "text/anot+turtle",
+ "class": "http://www.w3.org/ns/dcat#Catalog"
+ }
+ ],
+ [
+ {"accept": "application/ld+json"}, # Test that a valid mediatype is resolved
+ {},
+ [URIRef("http://www.w3.org/ns/dcat#Catalog")],
+ False,
+ {
+ "profile": URIRef("https://prez.dev/OGCItemProfile"),
+ "title": "OGC Object Profile",
+ "mediatype": "application/ld+json",
+ "class": "http://www.w3.org/ns/dcat#Catalog"
+ }
+ ],
+ [
+ {"accept": "application/ld+json;q=0.7,text/turtle"}, # Test resolution of multiple mediatypes
+ {},
+ [URIRef("http://www.w3.org/ns/dcat#Catalog")],
+ False,
+ {
+ "profile": URIRef("https://prez.dev/OGCItemProfile"),
+ "title": "OGC Object Profile",
+ "mediatype": "text/turtle",
+ "class": "http://www.w3.org/ns/dcat#Catalog"
+ }
+ ],
+ [
+ {},
+ {"_media": "application/ld+json"}, # Test mediatype resolution as QSA
+ [URIRef("http://www.w3.org/ns/dcat#Catalog")],
+ False,
+ {
+ "profile": URIRef("https://prez.dev/OGCItemProfile"),
+ "title": "OGC Object Profile",
+ "mediatype": "application/ld+json",
+ "class": "http://www.w3.org/ns/dcat#Catalog"
+ }
+ ],
+ [
+ {"accept": "text/turtle"},
+ {"_media": "application/ld+json"}, # Test QSA mediatype is preferred
+ [URIRef("http://www.w3.org/ns/dcat#Catalog")],
+ False,
+ {
+ "profile": URIRef("https://prez.dev/OGCItemProfile"),
+ "title": "OGC Object Profile",
+ "mediatype": "application/ld+json",
+ "class": "http://www.w3.org/ns/dcat#Catalog"
+ }
+ ],
+ [
+ {"accept-profile": "oogabooga"}, # Test that invalid profile is ignored
+ {},
+ [URIRef("http://www.w3.org/ns/dcat#Catalog")],
+ False,
+ {
+ "profile": URIRef("https://prez.dev/OGCItemProfile"),
+ "title": "OGC Object Profile",
+ "mediatype": "text/anot+turtle",
+ "class": "http://www.w3.org/ns/dcat#Catalog"
+ }
+ ],
+ [
+ {"accept": "oogabooga"}, # Test that invalid mediatype is ignored
+ {},
+ [URIRef("http://www.w3.org/ns/dcat#Catalog")],
+ False,
+ {
+ "profile": URIRef("https://prez.dev/OGCItemProfile"),
+ "title": "OGC Object Profile",
+ "mediatype": "text/anot+turtle",
+ "class": "http://www.w3.org/ns/dcat#Catalog"
+ }
+ ],
+ [
+ {"accept-profile": ""}, # Test that a valid profile is resolved
+ {},
+ [URIRef("http://www.w3.org/ns/dcat#Catalog")],
+ True,
+ {
+ "profile": URIRef("https://www.w3.org/TR/vocab-dcat/"),
+ "title": "DCAT",
+ "mediatype": "text/anot+turtle",
+ "class": "http://www.w3.org/ns/dcat#Catalog"
}
],
]
)
-def test_connegp(headers, params, classes, expected_selected, test_store, test_prefix_graph):
- pmts = NegotiatedPMTs(**{
- "headers": headers,
- "params": params,
- "classes": classes,
- "_system_store": test_store,
- "_prefix_graph": test_prefix_graph
- })
- pmts.setup()
+@pytest.mark.asyncio
+async def test_connegp(headers, params, classes, listing, expected_selected, test_repo):
+ def override_get_repo():
+ return test_repo
+ app.dependency_overrides[get_repo] = override_get_repo
+ pmts = NegotiatedPMTs(headers=headers, params=params, classes=classes, listing=listing, system_repo=test_repo)
+ success = await pmts.setup()
+ assert success
assert pmts.selected == expected_selected