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