diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9303b3d..95d0727 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,7 +45,7 @@ repos: - id: no-commit-to-branch args: [--branch, dev, --branch, int, --branch, main] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.4 + rev: v0.8.2 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/.pyproject_generation/pyproject_custom.toml b/.pyproject_generation/pyproject_custom.toml index db6adb6..e404f74 100644 --- a/.pyproject_generation/pyproject_custom.toml +++ b/.pyproject_generation/pyproject_custom.toml @@ -1,6 +1,6 @@ [project] name = "ghga_datasteward_kit" -version = "4.4.1" +version = "4.5.0" description = "GHGA Data Steward Kit - A utils package for GHGA data stewards." dependencies = [ "crypt4gh >=1.6, <2", diff --git a/.pyproject_generation/pyproject_template.toml b/.pyproject_generation/pyproject_template.toml index 07a11ff..1ee6e46 100644 --- a/.pyproject_generation/pyproject_template.toml +++ b/.pyproject_generation/pyproject_template.toml @@ -40,6 +40,7 @@ fixable = [ "UP", # e.g. List -> list "I", # sort imports "D", # pydocstyle + "RUF022", # sort items in __all__ ] ignore = [ "E111", # indentation with invalid multiple (for formatter) @@ -59,6 +60,7 @@ ignore = [ "D206", # indent-with-spaces (for formatter) "D300", # triple-single-quotes (for formatter) "UP040", # type statement (not yet supported by mypy) + "PLC0206", # Extracting value from dictionary without calling `.items()` ] select = [ "C90", # McCabe Complexity diff --git a/README.md b/README.md index 3c5c98c..6c72132 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,9 @@ This is achieved using the data steward kit, using the following steps: where the command is prefixed with `legacy-`. Please see [this section](#files-batch-upload) for further details. This will output one summary JSON per uploaded file. The encryption secret is automatically - transferred to GHGA central. + transferred to GHGA central for the normal upload path. + For the legacy version of the commands, the encryption secret is present in the summary + JSON and will be exchanged for a secret during ingest. Once the upload of all files of a submission has completed, please notify the GHGA Central Data Steward and provide the summary JSONs obtained in step 2. @@ -120,11 +122,13 @@ The following paragraphs provide additional help for using the different command This command facilitates encrypting files using Crypt4GH and uploading the encrypted content to a (remote) S3-compatible object storage. This process consists of multiple steps: -1. Generate a unique file id -2. Create unencrypted file checksum -3. Encrypt and upload file in chunks -4. Download encrypted file content, decrypt and verify checksum -5. Write file/upload information to output file +1. Generate a unique file/object id for S3 +2. Create SHA256 checksum for the unencrypted file +3. Encrypt and upload file in chunks, generate checksums for encrypted parts. +Verify successful transfer using content MD5 on the part level +4. Compute content MD5 of the assembled object locally and compare with S3 +5. Decrypt local parts, generate SHA256 checksum and compare with checksum calculated in step 2 +6. Write file/upload information to output file The user needs to provide a config yaml containing information as described [here](./s3_upload_config.md). @@ -146,6 +150,15 @@ It contains the following information: Attention: Keep this output file in a safe, private location. If this file is lost, the uploaded file content becomes inaccessible. +#### About concurrency + +In addition to the already existing batch upload command that allows for parallel processing and transfer on the file level, v4.3.0 added an asynchronous task handler for upload and download parallelization on the file part level. + +Moving from directly downloading the uploaded file to using content MD5 for validation purposes, there is no clear preference in which mode of parallelism should be used, as no benchmarking has been done yet with the current changes. + +By default, part level parallelism is set by the `client_max_parallel_transfers` to a value of 10. +If you want to disable it, the value has to be explicitly set to 1. + ### files ingest-upload-metadata *To be performed by Central Data Stewards only.* @@ -156,8 +169,12 @@ running system and make the corresponding files available for download. This command requires a configuration file as described [here](./ingest_config.md). -#### ingest version compatibility -Currently v4.4.0 of this tool and v4.0.0 of the `File Ingest Service` are compatible. +#### Ingest version compatibility + +| Datasteward Kit Version | File Ingest Service Version | +| :---------------------: | :-------------------------: | +| >=4.5.0 | >=5.0.0 | +| >=4.4.0, <4.5.0 | >=4.0.0, <5 | ### metadata diff --git a/lock/requirements-dev.txt b/lock/requirements-dev.txt index 0dff205..7667bd3 100644 --- a/lock/requirements-dev.txt +++ b/lock/requirements-dev.txt @@ -62,42 +62,40 @@ attrs==24.2.0 \ # via # jsonschema # referencing -bcrypt==4.2.0 \ - --hash=sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb \ - --hash=sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399 \ - --hash=sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291 \ - --hash=sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d \ - --hash=sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7 \ - --hash=sha256:1ff39b78a52cf03fdf902635e4c81e544714861ba3f0efc56558979dd4f09170 \ - --hash=sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d \ - --hash=sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe \ - --hash=sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060 \ - --hash=sha256:373db9abe198e8e2c70d12b479464e0d5092cc122b20ec504097b5f2297ed184 \ - --hash=sha256:39e1d30c7233cfc54f5c3f2c825156fe044efdd3e0b9d309512cc514a263ec2a \ - --hash=sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68 \ - --hash=sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c \ - --hash=sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458 \ - --hash=sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9 \ - --hash=sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328 \ - --hash=sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7 \ - --hash=sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34 \ - --hash=sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e \ - --hash=sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2 \ - --hash=sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5 \ - --hash=sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae \ - --hash=sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00 \ - --hash=sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841 \ - --hash=sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8 \ - --hash=sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221 \ - --hash=sha256:f4f4acf526fcd1c34e7ce851147deedd4e26e6402369304220250598b26448db +bcrypt==4.2.1 \ + --hash=sha256:041fa0155c9004eb98a232d54da05c0b41d4b8e66b6fc3cb71b4b3f6144ba837 \ + --hash=sha256:04e56e3fe8308a88b77e0afd20bec516f74aecf391cdd6e374f15cbed32783d6 \ + --hash=sha256:1340411a0894b7d3ef562fb233e4b6ed58add185228650942bdc885362f32c17 \ + --hash=sha256:533e7f3bcf2f07caee7ad98124fab7499cb3333ba2274f7a36cf1daee7409d99 \ + --hash=sha256:6765386e3ab87f569b276988742039baab087b2cdb01e809d74e74503c2faafe \ + --hash=sha256:687cf30e6681eeda39548a93ce9bfbb300e48b4d445a43db4298d2474d2a1e54 \ + --hash=sha256:76132c176a6d9953cdc83c296aeaed65e1a708485fd55abf163e0d9f8f16ce0e \ + --hash=sha256:76d3e352b32f4eeb34703370e370997065d28a561e4a18afe4fef07249cb4396 \ + --hash=sha256:807261df60a8b1ccd13e6599c779014a362ae4e795f5c59747f60208daddd96d \ + --hash=sha256:89df2aea2c43be1e1fa066df5f86c8ce822ab70a30e4c210968669565c0f4685 \ + --hash=sha256:8ad2f4528cbf0febe80e5a3a57d7a74e6635e41af1ea5675282a33d769fba413 \ + --hash=sha256:8c458cd103e6c5d1d85cf600e546a639f234964d0228909d8f8dbeebff82d526 \ + --hash=sha256:8dbd0747208912b1e4ce730c6725cb56c07ac734b3629b60d4398f082ea718ad \ + --hash=sha256:909faa1027900f2252a9ca5dfebd25fc0ef1417943824783d1c8418dd7d6df4a \ + --hash=sha256:aaa2e285be097050dba798d537b6efd9b698aa88eef52ec98d23dcd6d7cf6fea \ + --hash=sha256:adadd36274510a01f33e6dc08f5824b97c9580583bd4487c564fc4617b328005 \ + --hash=sha256:b1ee315739bc8387aa36ff127afc99120ee452924e0df517a8f3e4c0187a0f5f \ + --hash=sha256:b588af02b89d9fad33e5f98f7838bf590d6d692df7153647724a7f20c186f6bf \ + --hash=sha256:b7703ede632dc945ed1172d6f24e9f30f27b1b1a067f32f68bf169c5f08d0425 \ + --hash=sha256:c6f5fa3775966cca251848d4d5393ab016b3afed251163c1436fefdec3b02c84 \ + --hash=sha256:cde78d385d5e93ece5479a0a87f73cd6fa26b171c786a884f955e165032b262c \ + --hash=sha256:cfdf3d7530c790432046c40cda41dfee8c83e29482e6a604f8930b9930e94139 \ + --hash=sha256:e158009a54c4c8bc91d5e0da80920d048f918c61a581f0a63e4e93bb556d362f \ + --hash=sha256:e84e0e6f8e40a242b11bce56c313edc2be121cec3e0ec2d76fce01f6af33c07c \ + --hash=sha256:f85b1ffa09240c89aa2e1ae9f3b1c687104f7b2b9d2098da4e923f1b7082d331 # via crypt4gh -boto3==1.35.63 \ - --hash=sha256:d0f938d4f6f392b6ffc5e75fff14a42e5bbb5228675a0367c8af55398abadbec \ - --hash=sha256:deb593d9a0fb240deb4c43e4da8e6626d7c36be7b2fd2fe28f49d44d395b7de0 +boto3==1.35.76 \ + --hash=sha256:31ddcdb6f15dace2b68f6a0f11bdb58dd3ae79b8a3ccb174ff811ef0bbf938e0 \ + --hash=sha256:69458399f41f57a50770c8974796d96978bcca44915c260319696bb43e47dffd # via hexkit -botocore==1.35.63 \ - --hash=sha256:0ca1200694a4c0a3fa846795d8e8a08404c214e21195eb9e010c4b8a4ca78a4a \ - --hash=sha256:2b8196bab0a997d206c3d490b52e779ef47dffb68c57c685443f77293aca1589 +botocore==1.35.76 \ + --hash=sha256:a75a42ae53395796b8300c5fefb2d65a8696dc40dc85e49cf3a769e0c0202b13 \ + --hash=sha256:b4729d12d00267b3185628f83543917b6caae292385230ab464067621aa086af # via # boto3 # hexkit @@ -312,102 +310,104 @@ click==8.1.7 \ # prefixcommons # typer # uvicorn -coverage==7.6.7 \ - --hash=sha256:0266b62cbea568bd5e93a4da364d05de422110cbed5056d69339bd5af5685433 \ - --hash=sha256:0573f5cbf39114270842d01872952d301027d2d6e2d84013f30966313cadb529 \ - --hash=sha256:0ddcb70b3a3a57581b450571b31cb774f23eb9519c2aaa6176d3a84c9fc57671 \ - --hash=sha256:108bb458827765d538abcbf8288599fee07d2743357bdd9b9dad456c287e121e \ - --hash=sha256:14045b8bfd5909196a90da145a37f9d335a5d988a83db34e80f41e965fb7cb42 \ - --hash=sha256:1a5407a75ca4abc20d6252efeb238377a71ce7bda849c26c7a9bece8680a5d99 \ - --hash=sha256:2bc3e45c16564cc72de09e37413262b9f99167803e5e48c6156bccdfb22c8327 \ - --hash=sha256:2d608a7808793e3615e54e9267519351c3ae204a6d85764d8337bd95993581a8 \ - --hash=sha256:34d23e28ccb26236718a3a78ba72744212aa383141961dd6825f6595005c8b06 \ - --hash=sha256:37a15573f988b67f7348916077c6d8ad43adb75e478d0910957394df397d2874 \ - --hash=sha256:3c0317288f032221d35fa4cbc35d9f4923ff0dfd176c79c9b356e8ef8ef2dff4 \ - --hash=sha256:3c42ec2c522e3ddd683dec5cdce8e62817afb648caedad9da725001fa530d354 \ - --hash=sha256:3c6b24007c4bcd0b19fac25763a7cac5035c735ae017e9a349b927cfc88f31c1 \ - --hash=sha256:40cca284c7c310d622a1677f105e8507441d1bb7c226f41978ba7c86979609ab \ - --hash=sha256:46f21663e358beae6b368429ffadf14ed0a329996248a847a4322fb2e35d64d3 \ - --hash=sha256:49ed5ee4109258973630c1f9d099c7e72c5c36605029f3a91fe9982c6076c82b \ - --hash=sha256:5c95e0fa3d1547cb6f021ab72f5c23402da2358beec0a8e6d19a368bd7b0fb37 \ - --hash=sha256:5dd4e4a49d9c72a38d18d641135d2fb0bdf7b726ca60a103836b3d00a1182acd \ - --hash=sha256:5e444b8e88339a2a67ce07d41faabb1d60d1004820cee5a2c2b54e2d8e429a0f \ - --hash=sha256:60dcf7605c50ea72a14490d0756daffef77a5be15ed1b9fea468b1c7bda1bc3b \ - --hash=sha256:623e6965dcf4e28a3debaa6fcf4b99ee06d27218f46d43befe4db1c70841551c \ - --hash=sha256:673184b3156cba06154825f25af33baa2671ddae6343f23175764e65a8c4c30b \ - --hash=sha256:6cf96ceaa275f071f1bea3067f8fd43bec184a25a962c754024c973af871e1b7 \ - --hash=sha256:70a56a2ec1869e6e9fa69ef6b76b1a8a7ef709972b9cc473f9ce9d26b5997ce3 \ - --hash=sha256:77256ad2345c29fe59ae861aa11cfc74579c88d4e8dbf121cbe46b8e32aec808 \ - --hash=sha256:796c9b107d11d2d69e1849b2dfe41730134b526a49d3acb98ca02f4985eeff7a \ - --hash=sha256:7c07de0d2a110f02af30883cd7dddbe704887617d5c27cf373362667445a4c76 \ - --hash=sha256:7e61b0e77ff4dddebb35a0e8bb5a68bf0f8b872407d8d9f0c726b65dfabe2469 \ - --hash=sha256:82c809a62e953867cf57e0548c2b8464207f5f3a6ff0e1e961683e79b89f2c55 \ - --hash=sha256:850cfd2d6fc26f8346f422920ac204e1d28814e32e3a58c19c91980fa74d8289 \ - --hash=sha256:87ea64b9fa52bf395272e54020537990a28078478167ade6c61da7ac04dc14bc \ - --hash=sha256:90746521206c88bdb305a4bf3342b1b7316ab80f804d40c536fc7d329301ee13 \ - --hash=sha256:951aade8297358f3618a6e0660dc74f6b52233c42089d28525749fc8267dccd2 \ - --hash=sha256:963e4a08cbb0af6623e61492c0ec4c0ec5c5cf74db5f6564f98248d27ee57d30 \ - --hash=sha256:987a8e3da7da4eed10a20491cf790589a8e5e07656b6dc22d3814c4d88faf163 \ - --hash=sha256:9c2eb378bebb2c8f65befcb5147877fc1c9fbc640fc0aad3add759b5df79d55d \ - --hash=sha256:a1ab9763d291a17b527ac6fd11d1a9a9c358280adb320e9c2672a97af346ac2c \ - --hash=sha256:a3b925300484a3294d1c70f6b2b810d6526f2929de954e5b6be2bf8caa1f12c1 \ - --hash=sha256:acbb8af78f8f91b3b51f58f288c0994ba63c646bc1a8a22ad072e4e7e0a49f1c \ - --hash=sha256:ad32a981bcdedb8d2ace03b05e4fd8dace8901eec64a532b00b15217d3677dd2 \ - --hash=sha256:aee9cf6b0134d6f932d219ce253ef0e624f4fa588ee64830fcba193269e4daa3 \ - --hash=sha256:af05bbba896c4472a29408455fe31b3797b4d8648ed0a2ccac03e074a77e2314 \ - --hash=sha256:b6cce5c76985f81da3769c52203ee94722cd5d5889731cd70d31fee939b74bf0 \ - --hash=sha256:bb684694e99d0b791a43e9fc0fa58efc15ec357ac48d25b619f207c41f2fd384 \ - --hash=sha256:c132b5a22821f9b143f87446805e13580b67c670a548b96da945a8f6b4f2efbb \ - --hash=sha256:c296263093f099da4f51b3dff1eff5d4959b527d4f2f419e16508c5da9e15e8c \ - --hash=sha256:c973b2fe4dc445cb865ab369df7521df9c27bf40715c837a113edaa2aa9faf45 \ - --hash=sha256:cdd94501d65adc5c24f8a1a0eda110452ba62b3f4aeaba01e021c1ed9cb8f34a \ - --hash=sha256:d79d4826e41441c9a118ff045e4bccb9fdbdcb1d02413e7ea6eb5c87b5439d24 \ - --hash=sha256:dbba8210f5067398b2c4d96b4e64d8fb943644d5eb70be0d989067c8ca40c0f8 \ - --hash=sha256:df002e59f2d29e889c37abd0b9ee0d0e6e38c24f5f55d71ff0e09e3412a340ec \ - --hash=sha256:dfd14bcae0c94004baba5184d1c935ae0d1231b8409eb6c103a5fd75e8ecdc56 \ - --hash=sha256:e25bacb53a8c7325e34d45dddd2f2fbae0dbc230d0e2642e264a64e17322a777 \ - --hash=sha256:e2c8e3384c12dfa19fa9a52f23eb091a8fad93b5b81a41b14c17c78e23dd1d8b \ - --hash=sha256:e5f2a0f161d126ccc7038f1f3029184dbdf8f018230af17ef6fd6a707a5b881f \ - --hash=sha256:e69ad502f1a2243f739f5bd60565d14a278be58be4c137d90799f2c263e7049a \ - --hash=sha256:ead9b9605c54d15be228687552916c89c9683c215370c4a44f1f217d2adcc34d \ - --hash=sha256:f07ff574986bc3edb80e2c36391678a271d555f91fd1d332a1e0f4b5ea4b6ea9 \ - --hash=sha256:f2c7a045eef561e9544359a0bf5784b44e55cefc7261a20e730baa9220c83413 \ - --hash=sha256:f3e8796434a8106b3ac025fd15417315d7a58ee3e600ad4dbcfddc3f4b14342c \ - --hash=sha256:f63e21ed474edd23f7501f89b53280014436e383a14b9bd77a648366c81dce7b \ - --hash=sha256:fd49c01e5057a451c30c9b892948976f5d38f2cbd04dc556a82743ba8e27ed8c +coverage==7.6.8 \ + --hash=sha256:093896e530c38c8e9c996901858ac63f3d4171268db2c9c8b373a228f459bbc5 \ + --hash=sha256:09b9f848b28081e7b975a3626e9081574a7b9196cde26604540582da60235fdf \ + --hash=sha256:0b0c69f4f724c64dfbfe79f5dfb503b42fe6127b8d479b2677f2b227478db2eb \ + --hash=sha256:13618bed0c38acc418896005732e565b317aa9e98d855a0e9f211a7ffc2d6638 \ + --hash=sha256:13690e923a3932e4fad4c0ebfb9cb5988e03d9dcb4c5150b5fcbf58fd8bddfc4 \ + --hash=sha256:177f01eeaa3aee4a5ffb0d1439c5952b53d5010f86e9d2667963e632e30082cc \ + --hash=sha256:193e3bffca48ad74b8c764fb4492dd875038a2f9925530cb094db92bb5e47bed \ + --hash=sha256:1defe91d41ce1bd44b40fabf071e6a01a5aa14de4a31b986aa9dfd1b3e3e414a \ + --hash=sha256:1f188a2402f8359cf0c4b1fe89eea40dc13b52e7b4fd4812450da9fcd210181d \ + --hash=sha256:202a2d645c5a46b84992f55b0a3affe4f0ba6b4c611abec32ee88358db4bb649 \ + --hash=sha256:24eda3a24a38157eee639ca9afe45eefa8d2420d49468819ac5f88b10de84f4c \ + --hash=sha256:2e4e0f60cb4bd7396108823548e82fdab72d4d8a65e58e2c19bbbc2f1e2bfa4b \ + --hash=sha256:379c111d3558272a2cae3d8e57e6b6e6f4fe652905692d54bad5ea0ca37c5ad4 \ + --hash=sha256:37cda8712145917105e07aab96388ae76e787270ec04bcb9d5cc786d7cbb8443 \ + --hash=sha256:38c51297b35b3ed91670e1e4efb702b790002e3245a28c76e627478aa3c10d83 \ + --hash=sha256:3985b9be361d8fb6b2d1adc9924d01dec575a1d7453a14cccd73225cb79243ee \ + --hash=sha256:3988665ee376abce49613701336544041f2117de7b7fbfe91b93d8ff8b151c8e \ + --hash=sha256:3ac47fa29d8d41059ea3df65bd3ade92f97ee4910ed638e87075b8e8ce69599e \ + --hash=sha256:3b4b4299dd0d2c67caaaf286d58aef5e75b125b95615dda4542561a5a566a1e3 \ + --hash=sha256:3ea8bb1ab9558374c0ab591783808511d135a833c3ca64a18ec927f20c4030f0 \ + --hash=sha256:3fe47da3e4fda5f1abb5709c156eca207eacf8007304ce3019eb001e7a7204cb \ + --hash=sha256:428ac484592f780e8cd7b6b14eb568f7c85460c92e2a37cb0c0e5186e1a0d076 \ + --hash=sha256:44e6c85bbdc809383b509d732b06419fb4544dca29ebe18480379633623baafb \ + --hash=sha256:4674f0daa1823c295845b6a740d98a840d7a1c11df00d1fd62614545c1583787 \ + --hash=sha256:4be32da0c3827ac9132bb488d331cb32e8d9638dd41a0557c5569d57cf22c9c1 \ + --hash=sha256:4db3ed6a907b555e57cc2e6f14dc3a4c2458cdad8919e40b5357ab9b6db6c43e \ + --hash=sha256:5c52a036535d12590c32c49209e79cabaad9f9ad8aa4cbd875b68c4d67a9cbce \ + --hash=sha256:629a1ba2115dce8bf75a5cce9f2486ae483cb89c0145795603d6554bdc83e801 \ + --hash=sha256:62a66ff235e4c2e37ed3b6104d8b478d767ff73838d1222132a7a026aa548764 \ + --hash=sha256:63068a11171e4276f6ece913bde059e77c713b48c3a848814a6537f35afb8365 \ + --hash=sha256:63c19702db10ad79151a059d2d6336fe0c470f2e18d0d4d1a57f7f9713875dcf \ + --hash=sha256:644ec81edec0f4ad17d51c838a7d01e42811054543b76d4ba2c5d6af741ce2a6 \ + --hash=sha256:6535d996f6537ecb298b4e287a855f37deaf64ff007162ec0afb9ab8ba3b8b71 \ + --hash=sha256:6f4548c5ead23ad13fb7a2c8ea541357474ec13c2b736feb02e19a3085fac002 \ + --hash=sha256:716a78a342679cd1177bc8c2fe957e0ab91405bd43a17094324845200b2fddf4 \ + --hash=sha256:74610105ebd6f33d7c10f8907afed696e79c59e3043c5f20eaa3a46fddf33b4c \ + --hash=sha256:768939f7c4353c0fac2f7c37897e10b1414b571fd85dd9fc49e6a87e37a2e0d8 \ + --hash=sha256:86cffe9c6dfcfe22e28027069725c7f57f4b868a3f86e81d1c62462764dc46d4 \ + --hash=sha256:8aae5aea53cbfe024919715eca696b1a3201886ce83790537d1c3668459c7146 \ + --hash=sha256:8b2b8503edb06822c86d82fa64a4a5cb0760bb8f31f26e138ec743f422f37cfc \ + --hash=sha256:912e95017ff51dc3d7b6e2be158dedc889d9a5cc3382445589ce554f1a34c0ea \ + --hash=sha256:9a7b8ac36fd688c8361cbc7bf1cb5866977ece6e0b17c34aa0df58bda4fa18a4 \ + --hash=sha256:9e89d5c8509fbd6c03d0dd1972925b22f50db0792ce06324ba069f10787429ad \ + --hash=sha256:ae270e79f7e169ccfe23284ff5ea2d52a6f401dc01b337efb54b3783e2ce3f28 \ + --hash=sha256:b07c25d52b1c16ce5de088046cd2432b30f9ad5e224ff17c8f496d9cb7d1d451 \ + --hash=sha256:b39e6011cd06822eb964d038d5dff5da5d98652b81f5ecd439277b32361a3a50 \ + --hash=sha256:bd55f8fc8fa494958772a2a7302b0354ab16e0b9272b3c3d83cdb5bec5bd1779 \ + --hash=sha256:c15b32a7aca8038ed7644f854bf17b663bc38e1671b5d6f43f9a2b2bd0c46f63 \ + --hash=sha256:c1b4474beee02ede1eef86c25ad4600a424fe36cff01a6103cb4533c6bf0169e \ + --hash=sha256:c79c0685f142ca53256722a384540832420dff4ab15fec1863d7e5bc8691bdcc \ + --hash=sha256:c9ebfb2507751f7196995142f057d1324afdab56db1d9743aab7f50289abd022 \ + --hash=sha256:d7ad66e8e50225ebf4236368cc43c37f59d5e6728f15f6e258c8639fa0dd8e6d \ + --hash=sha256:d82ab6816c3277dc962cfcdc85b1efa0e5f50fb2c449432deaf2398a2928ab94 \ + --hash=sha256:d9fd2547e6decdbf985d579cf3fc78e4c1d662b9b0ff7cc7862baaab71c9cc5b \ + --hash=sha256:de38add67a0af869b0d79c525d3e4588ac1ffa92f39116dbe0ed9753f26eba7d \ + --hash=sha256:e19122296822deafce89a0c5e8685704c067ae65d45e79718c92df7b3ec3d331 \ + --hash=sha256:e44961e36cb13c495806d4cac67640ac2866cb99044e210895b506c26ee63d3a \ + --hash=sha256:e4c81ed2820b9023a9a90717020315e63b17b18c274a332e3b6437d7ff70abe0 \ + --hash=sha256:e683e6ecc587643f8cde8f5da6768e9d165cd31edf39ee90ed7034f9ca0eefee \ + --hash=sha256:f39e2f3530ed1626c66e7493be7a8423b023ca852aacdc91fb30162c350d2a92 \ + --hash=sha256:f56f49b2553d7dd85fd86e029515a221e5c1f8cb3d9c38b470bc38bde7b8445a \ + --hash=sha256:fb9fc32399dca861584d96eccd6c980b69bbcd7c228d06fb74fe53e007aa8ef9 # via pytest-cov crypt4gh==1.7 \ --hash=sha256:1569bc4ff9b689c8852e3892ac3f6fea4b31948ca0b1e5bc28d0d2f80def2a28 \ --hash=sha256:9aeb37065769a560b5bbe8cf67c47eb4d8b53ed36725a8d3fb0385084c682c3c # via ghga-datasteward-kit (pyproject.toml) -cryptography==43.0.3 \ - --hash=sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362 \ - --hash=sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4 \ - --hash=sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa \ - --hash=sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83 \ - --hash=sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff \ - --hash=sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805 \ - --hash=sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6 \ - --hash=sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664 \ - --hash=sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08 \ - --hash=sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e \ - --hash=sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18 \ - --hash=sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f \ - --hash=sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73 \ - --hash=sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5 \ - --hash=sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984 \ - --hash=sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd \ - --hash=sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3 \ - --hash=sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e \ - --hash=sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405 \ - --hash=sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2 \ - --hash=sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c \ - --hash=sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995 \ - --hash=sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73 \ - --hash=sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16 \ - --hash=sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7 \ - --hash=sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd \ - --hash=sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7 +cryptography==44.0.0 \ + --hash=sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7 \ + --hash=sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731 \ + --hash=sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b \ + --hash=sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc \ + --hash=sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543 \ + --hash=sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385 \ + --hash=sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c \ + --hash=sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591 \ + --hash=sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede \ + --hash=sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb \ + --hash=sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f \ + --hash=sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123 \ + --hash=sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c \ + --hash=sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba \ + --hash=sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c \ + --hash=sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285 \ + --hash=sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd \ + --hash=sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092 \ + --hash=sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa \ + --hash=sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289 \ + --hash=sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02 \ + --hash=sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64 \ + --hash=sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053 \ + --hash=sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417 \ + --hash=sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e \ + --hash=sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e \ + --hash=sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7 \ + --hash=sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756 \ + --hash=sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4 # via # crypt4gh # jwcrypto @@ -451,9 +451,9 @@ et-xmlfile==2.0.0 \ --hash=sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa \ --hash=sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54 # via openpyxl -fastapi==0.115.5 \ - --hash=sha256:0e7a4d0dc0d01c68df21887cce0945e72d3c48b9f4f79dfe7a7d53aa08fbb289 \ - --hash=sha256:596b95adbe1474da47049e802f9a65ab2ffa9c2b07e7efee70eb8a66c9f2f796 +fastapi==0.115.6 \ + --hash=sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654 \ + --hash=sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305 # via ghga-service-commons filelock==3.16.1 \ --hash=sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0 \ @@ -567,9 +567,9 @@ hbreader==0.9.1 \ # jsonasobj2 # linkml # linkml-runtime -hexkit==3.7.0 \ - --hash=sha256:1e0273be7232f9ccb68d24ff88671ab7592fbe25522aa53d10177e245e3834dd \ - --hash=sha256:dffbb79549df70963b3e08a5f00452b778619220044e851340fa30ba25212c1d +hexkit==3.8.1 \ + --hash=sha256:51c9f00003f5ed8dfe0585617031c530f2d08f704955f5c5e3340e6f947d597a \ + --hash=sha256:d33b390e861e41deb54217ce85d0a5f3c8fe6ddc3656514d45cc173fe2775553 # via # ghga-datasteward-kit (pyproject.toml) # ghga-service-commons @@ -623,15 +623,15 @@ httptools==0.6.4 \ --hash=sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f \ --hash=sha256:fc411e1c0a7dcd2f902c7c48cf079947a7e65b5485dea9decb82b9105ca71a43 # via uvicorn -httpx==0.27.2 \ - --hash=sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0 \ - --hash=sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2 +httpx==0.28.0 \ + --hash=sha256:0858d3bab51ba7e386637f22a61d8ccddaeec5f3fe4209da3a6168dbb91573e0 \ + --hash=sha256:dc0b419a0cfeb6e8b34e85167c0da2671206f5095f1baa9663d23bcfd6b535fc # via # -r lock/requirements-dev-template.in # pytest-httpx -identify==2.6.2 \ - --hash=sha256:c097384259f49e372f4ea00a19719d95ae27dd5ff0fd77ad630aa891306b82f3 \ - --hash=sha256:fab5c716c24d7a789775228823797296a2994b075fb6080ac83a102772a98cbd +identify==2.6.3 \ + --hash=sha256:62f5dae9b5fef52c84cc188514e9ea4f3f636b1d8799ab5ebc475471f9e47a02 \ + --hash=sha256:9edba65473324c2ea9684b1f944fe3191db3345e50b6d04571d10ed164f8d7bd # via pre-commit idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ @@ -687,6 +687,8 @@ jsonpatch==1.33 \ --hash=sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c # via linkml-dataops jsonpath-ng==1.7.0 \ + --hash=sha256:898c93fc173f0c336784a3fa63d7434297544b7198124a68f9a3ef9597b0ae6e \ + --hash=sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6 \ --hash=sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c # via linkml-dataops jsonpointer==3.0.0 \ @@ -912,9 +914,9 @@ pycparser==2.22 \ --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc # via cffi -pydantic==2.9.2 \ - --hash=sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f \ - --hash=sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12 +pydantic==2.10.3 \ + --hash=sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d \ + --hash=sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9 # via # curies # fastapi @@ -926,96 +928,107 @@ pydantic==2.9.2 \ # linkml-runtime # linkml-validator # pydantic-settings -pydantic-core==2.23.4 \ - --hash=sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36 \ - --hash=sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05 \ - --hash=sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071 \ - --hash=sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327 \ - --hash=sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c \ - --hash=sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36 \ - --hash=sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29 \ - --hash=sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744 \ - --hash=sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d \ - --hash=sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec \ - --hash=sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e \ - --hash=sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e \ - --hash=sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577 \ - --hash=sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232 \ - --hash=sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863 \ - --hash=sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6 \ - --hash=sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368 \ - --hash=sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480 \ - --hash=sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2 \ - --hash=sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2 \ - --hash=sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6 \ - --hash=sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769 \ - --hash=sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d \ - --hash=sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2 \ - --hash=sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84 \ - --hash=sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166 \ - --hash=sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271 \ - --hash=sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5 \ - --hash=sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb \ - --hash=sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13 \ - --hash=sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323 \ - --hash=sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556 \ - --hash=sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665 \ - --hash=sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef \ - --hash=sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb \ - --hash=sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119 \ - --hash=sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126 \ - --hash=sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510 \ - --hash=sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b \ - --hash=sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87 \ - --hash=sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f \ - --hash=sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc \ - --hash=sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8 \ - --hash=sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21 \ - --hash=sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f \ - --hash=sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6 \ - --hash=sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658 \ - --hash=sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b \ - --hash=sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3 \ - --hash=sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb \ - --hash=sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59 \ - --hash=sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24 \ - --hash=sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9 \ - --hash=sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3 \ - --hash=sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd \ - --hash=sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753 \ - --hash=sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55 \ - --hash=sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad \ - --hash=sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a \ - --hash=sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605 \ - --hash=sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e \ - --hash=sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b \ - --hash=sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433 \ - --hash=sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8 \ - --hash=sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07 \ - --hash=sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728 \ - --hash=sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0 \ - --hash=sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327 \ - --hash=sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555 \ - --hash=sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64 \ - --hash=sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6 \ - --hash=sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea \ - --hash=sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b \ - --hash=sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df \ - --hash=sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e \ - --hash=sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd \ - --hash=sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068 \ - --hash=sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3 \ - --hash=sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040 \ - --hash=sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12 \ - --hash=sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916 \ - --hash=sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f \ - --hash=sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f \ - --hash=sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801 \ - --hash=sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231 \ - --hash=sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5 \ - --hash=sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8 \ - --hash=sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee \ - --hash=sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607 +pydantic-core==2.27.1 \ + --hash=sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9 \ + --hash=sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b \ + --hash=sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c \ + --hash=sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529 \ + --hash=sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc \ + --hash=sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854 \ + --hash=sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d \ + --hash=sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278 \ + --hash=sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a \ + --hash=sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c \ + --hash=sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f \ + --hash=sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27 \ + --hash=sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f \ + --hash=sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac \ + --hash=sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2 \ + --hash=sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97 \ + --hash=sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a \ + --hash=sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919 \ + --hash=sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9 \ + --hash=sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4 \ + --hash=sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c \ + --hash=sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131 \ + --hash=sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5 \ + --hash=sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd \ + --hash=sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089 \ + --hash=sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107 \ + --hash=sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6 \ + --hash=sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60 \ + --hash=sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf \ + --hash=sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5 \ + --hash=sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08 \ + --hash=sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05 \ + --hash=sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2 \ + --hash=sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e \ + --hash=sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c \ + --hash=sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17 \ + --hash=sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62 \ + --hash=sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23 \ + --hash=sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be \ + --hash=sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067 \ + --hash=sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02 \ + --hash=sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f \ + --hash=sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235 \ + --hash=sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840 \ + --hash=sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5 \ + --hash=sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807 \ + --hash=sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16 \ + --hash=sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c \ + --hash=sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864 \ + --hash=sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e \ + --hash=sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a \ + --hash=sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35 \ + --hash=sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737 \ + --hash=sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a \ + --hash=sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3 \ + --hash=sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52 \ + --hash=sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05 \ + --hash=sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31 \ + --hash=sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89 \ + --hash=sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de \ + --hash=sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6 \ + --hash=sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36 \ + --hash=sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c \ + --hash=sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154 \ + --hash=sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb \ + --hash=sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e \ + --hash=sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd \ + --hash=sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3 \ + --hash=sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f \ + --hash=sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78 \ + --hash=sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960 \ + --hash=sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618 \ + --hash=sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08 \ + --hash=sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4 \ + --hash=sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c \ + --hash=sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c \ + --hash=sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330 \ + --hash=sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8 \ + --hash=sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792 \ + --hash=sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025 \ + --hash=sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9 \ + --hash=sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f \ + --hash=sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01 \ + --hash=sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337 \ + --hash=sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4 \ + --hash=sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f \ + --hash=sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd \ + --hash=sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51 \ + --hash=sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab \ + --hash=sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc \ + --hash=sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676 \ + --hash=sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381 \ + --hash=sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed \ + --hash=sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb \ + --hash=sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967 \ + --hash=sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073 \ + --hash=sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae \ + --hash=sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c \ + --hash=sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206 \ + --hash=sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b # via pydantic pydantic-settings==2.6.1 \ --hash=sha256:7fb0637c786a558d3103436278a7c4f1cfd29ba8973238a50c5bb9a55387da87 \ @@ -1119,9 +1132,9 @@ pyshexc==0.9.1 \ # via # linkml # pyshex -pytest==8.3.3 \ - --hash=sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181 \ - --hash=sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2 +pytest==8.3.4 \ + --hash=sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6 \ + --hash=sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761 # via # -r lock/requirements-dev-template.in # pytest-asyncio @@ -1136,9 +1149,9 @@ pytest-cov==6.0.0 \ --hash=sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35 \ --hash=sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0 # via -r lock/requirements-dev-template.in -pytest-httpx==0.33.0 \ - --hash=sha256:4af9ab0dae5e9c14cb1e27d18af3db1f627b2cf3b11c02b34ddf26aff6b0a24c \ - --hash=sha256:bdd1b00a846cfe857194e4d3ba72dc08ba0d163154a4404269c9b971f357c05d +pytest-httpx==0.35.0 \ + --hash=sha256:d619ad5d2e67734abfbb224c3d9025d64795d4b8711116b1a13f72a251ae511f \ + --hash=sha256:ee11a00ffcea94a5cbff47af2114d34c5b231c326902458deed73f9c459fd744 # via -r lock/requirements-dev-template.in pytest-logging==2015.11.4 \ --hash=sha256:cec5c85ecf18aab7b2ead5498a31b9f758680ef5a902b9054ab3f2bdbb77c896 @@ -1276,97 +1289,110 @@ rich==13.9.4 \ --hash=sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098 \ --hash=sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90 # via typer -rpds-py==0.21.0 \ - --hash=sha256:031819f906bb146561af051c7cef4ba2003d28cff07efacef59da973ff7969ba \ - --hash=sha256:0626238a43152918f9e72ede9a3b6ccc9e299adc8ade0d67c5e142d564c9a83d \ - --hash=sha256:085ed25baac88953d4283e5b5bd094b155075bb40d07c29c4f073e10623f9f2e \ - --hash=sha256:0a9e0759e7be10109645a9fddaaad0619d58c9bf30a3f248a2ea57a7c417173a \ - --hash=sha256:0c025820b78817db6a76413fff6866790786c38f95ea3f3d3c93dbb73b632202 \ - --hash=sha256:1ff2eba7f6c0cb523d7e9cff0903f2fe1feff8f0b2ceb6bd71c0e20a4dcee271 \ - --hash=sha256:20cc1ed0bcc86d8e1a7e968cce15be45178fd16e2ff656a243145e0b439bd250 \ - --hash=sha256:241e6c125568493f553c3d0fdbb38c74babf54b45cef86439d4cd97ff8feb34d \ - --hash=sha256:2c51d99c30091f72a3c5d126fad26236c3f75716b8b5e5cf8effb18889ced928 \ - --hash=sha256:2d6129137f43f7fa02d41542ffff4871d4aefa724a5fe38e2c31a4e0fd343fb0 \ - --hash=sha256:30b912c965b2aa76ba5168fd610087bad7fcde47f0a8367ee8f1876086ee6d1d \ - --hash=sha256:30bdc973f10d28e0337f71d202ff29345320f8bc49a31c90e6c257e1ccef4333 \ - --hash=sha256:320c808df533695326610a1b6a0a6e98f033e49de55d7dc36a13c8a30cfa756e \ - --hash=sha256:32eb88c30b6a4f0605508023b7141d043a79b14acb3b969aa0b4f99b25bc7d4a \ - --hash=sha256:3b766a9f57663396e4f34f5140b3595b233a7b146e94777b97a8413a1da1be18 \ - --hash=sha256:3b929c2bb6e29ab31f12a1117c39f7e6d6450419ab7464a4ea9b0b417174f044 \ - --hash=sha256:3e30a69a706e8ea20444b98a49f386c17b26f860aa9245329bab0851ed100677 \ - --hash=sha256:3e53861b29a13d5b70116ea4230b5f0f3547b2c222c5daa090eb7c9c82d7f664 \ - --hash=sha256:40c91c6e34cf016fa8e6b59d75e3dbe354830777fcfd74c58b279dceb7975b75 \ - --hash=sha256:4991ca61656e3160cdaca4851151fd3f4a92e9eba5c7a530ab030d6aee96ec89 \ - --hash=sha256:4ab2c2a26d2f69cdf833174f4d9d86118edc781ad9a8fa13970b527bf8236027 \ - --hash=sha256:4e8921a259f54bfbc755c5bbd60c82bb2339ae0324163f32868f63f0ebb873d9 \ - --hash=sha256:4eb2de8a147ffe0626bfdc275fc6563aa7bf4b6db59cf0d44f0ccd6ca625a24e \ - --hash=sha256:5145282a7cd2ac16ea0dc46b82167754d5e103a05614b724457cffe614f25bd8 \ - --hash=sha256:520ed8b99b0bf86a176271f6fe23024323862ac674b1ce5b02a72bfeff3fff44 \ - --hash=sha256:52c041802a6efa625ea18027a0723676a778869481d16803481ef6cc02ea8cb3 \ - --hash=sha256:5555db3e618a77034954b9dc547eae94166391a98eb867905ec8fcbce1308d95 \ - --hash=sha256:58a0e345be4b18e6b8501d3b0aa540dad90caeed814c515e5206bb2ec26736fd \ - --hash=sha256:590ef88db231c9c1eece44dcfefd7515d8bf0d986d64d0caf06a81998a9e8cab \ - --hash=sha256:5afb5efde74c54724e1a01118c6e5c15e54e642c42a1ba588ab1f03544ac8c7a \ - --hash=sha256:688c93b77e468d72579351a84b95f976bd7b3e84aa6686be6497045ba84be560 \ - --hash=sha256:6b4ef7725386dc0762857097f6b7266a6cdd62bfd209664da6712cb26acef035 \ - --hash=sha256:6bc0e697d4d79ab1aacbf20ee5f0df80359ecf55db33ff41481cf3e24f206919 \ - --hash=sha256:6dcc4949be728ede49e6244eabd04064336012b37f5c2200e8ec8eb2988b209c \ - --hash=sha256:6f54e7106f0001244a5f4cf810ba8d3f9c542e2730821b16e969d6887b664266 \ - --hash=sha256:808f1ac7cf3b44f81c9475475ceb221f982ef548e44e024ad5f9e7060649540e \ - --hash=sha256:8404b3717da03cbf773a1d275d01fec84ea007754ed380f63dfc24fb76ce4592 \ - --hash=sha256:878f6fea96621fda5303a2867887686d7a198d9e0f8a40be100a63f5d60c88c9 \ - --hash=sha256:8a7ff941004d74d55a47f916afc38494bd1cfd4b53c482b77c03147c91ac0ac3 \ - --hash=sha256:95a5bad1ac8a5c77b4e658671642e4af3707f095d2b78a1fdd08af0dfb647624 \ - --hash=sha256:97ef67d9bbc3e15584c2f3c74bcf064af36336c10d2e21a2131e123ce0f924c9 \ - --hash=sha256:98486337f7b4f3c324ab402e83453e25bb844f44418c066623db88e4c56b7c7b \ - --hash=sha256:98e4fe5db40db87ce1c65031463a760ec7906ab230ad2249b4572c2fc3ef1f9f \ - --hash=sha256:998a8080c4495e4f72132f3d66ff91f5997d799e86cec6ee05342f8f3cda7dca \ - --hash=sha256:9afe42102b40007f588666bc7de82451e10c6788f6f70984629db193849dced1 \ - --hash=sha256:9e20da3957bdf7824afdd4b6eeb29510e83e026473e04952dca565170cd1ecc8 \ - --hash=sha256:a017f813f24b9df929674d0332a374d40d7f0162b326562daae8066b502d0590 \ - --hash=sha256:a429b99337062877d7875e4ff1a51fe788424d522bd64a8c0a20ef3021fdb6ed \ - --hash=sha256:a58ce66847711c4aa2ecfcfaff04cb0327f907fead8945ffc47d9407f41ff952 \ - --hash=sha256:a78d8b634c9df7f8d175451cfeac3810a702ccb85f98ec95797fa98b942cea11 \ - --hash=sha256:a89a8ce9e4e75aeb7fa5d8ad0f3fecdee813802592f4f46a15754dcb2fd6b061 \ - --hash=sha256:a8eeec67590e94189f434c6d11c426892e396ae59e4801d17a93ac96b8c02a6c \ - --hash=sha256:aaeb25ccfb9b9014a10eaf70904ebf3f79faaa8e60e99e19eef9f478651b9b74 \ - --hash=sha256:ad116dda078d0bc4886cb7840e19811562acdc7a8e296ea6ec37e70326c1b41c \ - --hash=sha256:af04ac89c738e0f0f1b913918024c3eab6e3ace989518ea838807177d38a2e94 \ - --hash=sha256:af4a644bf890f56e41e74be7d34e9511e4954894d544ec6b8efe1e21a1a8da6c \ - --hash=sha256:b21747f79f360e790525e6f6438c7569ddbfb1b3197b9e65043f25c3c9b489d8 \ - --hash=sha256:b229ce052ddf1a01c67d68166c19cb004fb3612424921b81c46e7ea7ccf7c3bf \ - --hash=sha256:b4de1da871b5c0fd5537b26a6fc6814c3cc05cabe0c941db6e9044ffbb12f04a \ - --hash=sha256:b80b4690bbff51a034bfde9c9f6bf9357f0a8c61f548942b80f7b66356508bf5 \ - --hash=sha256:b876f2bc27ab5954e2fd88890c071bd0ed18b9c50f6ec3de3c50a5ece612f7a6 \ - --hash=sha256:b8f107395f2f1d151181880b69a2869c69e87ec079c49c0016ab96860b6acbe5 \ - --hash=sha256:b9b76e2afd585803c53c5b29e992ecd183f68285b62fe2668383a18e74abe7a3 \ - --hash=sha256:c2b2f71c6ad6c2e4fc9ed9401080badd1469fa9889657ec3abea42a3d6b2e1ed \ - --hash=sha256:c3761f62fcfccf0864cc4665b6e7c3f0c626f0380b41b8bd1ce322103fa3ef87 \ - --hash=sha256:c38dbf31c57032667dd5a2f0568ccde66e868e8f78d5a0d27dcc56d70f3fcd3b \ - --hash=sha256:ca9989d5d9b1b300bc18e1801c67b9f6d2c66b8fd9621b36072ed1df2c977f72 \ - --hash=sha256:cbd7504a10b0955ea287114f003b7ad62330c9e65ba012c6223dba646f6ffd05 \ - --hash=sha256:d167e4dbbdac48bd58893c7e446684ad5d425b407f9336e04ab52e8b9194e2ed \ - --hash=sha256:d2132377f9deef0c4db89e65e8bb28644ff75a18df5293e132a8d67748397b9f \ - --hash=sha256:da52d62a96e61c1c444f3998c434e8b263c384f6d68aca8274d2e08d1906325c \ - --hash=sha256:daa8efac2a1273eed2354397a51216ae1e198ecbce9036fba4e7610b308b6153 \ - --hash=sha256:dc5695c321e518d9f03b7ea6abb5ea3af4567766f9852ad1560f501b17588c7b \ - --hash=sha256:de552f4a1916e520f2703ec474d2b4d3f86d41f353e7680b597512ffe7eac5d0 \ - --hash=sha256:de609a6f1b682f70bb7163da745ee815d8f230d97276db049ab447767466a09d \ - --hash=sha256:e12bb09678f38b7597b8346983d2323a6482dcd59e423d9448108c1be37cac9d \ - --hash=sha256:e168afe6bf6ab7ab46c8c375606298784ecbe3ba31c0980b7dcbb9631dcba97e \ - --hash=sha256:e78868e98f34f34a88e23ee9ccaeeec460e4eaf6db16d51d7a9b883e5e785a5e \ - --hash=sha256:e860f065cc4ea6f256d6f411aba4b1251255366e48e972f8a347cf88077b24fd \ - --hash=sha256:ea3a6ac4d74820c98fcc9da4a57847ad2cc36475a8bd9683f32ab6d47a2bd682 \ - --hash=sha256:ebf64e281a06c904a7636781d2e973d1f0926a5b8b480ac658dc0f556e7779f4 \ - --hash=sha256:ed6378c9d66d0de903763e7706383d60c33829581f0adff47b6535f1802fa6db \ - --hash=sha256:ee1e4fc267b437bb89990b2f2abf6c25765b89b72dd4a11e21934df449e0c976 \ - --hash=sha256:ee4eafd77cc98d355a0d02f263efc0d3ae3ce4a7c24740010a8b4012bbb24937 \ - --hash=sha256:efec946f331349dfc4ae9d0e034c263ddde19414fe5128580f512619abed05f1 \ - --hash=sha256:f414da5c51bf350e4b7960644617c130140423882305f7574b6cf65a3081cecb \ - --hash=sha256:f71009b0d5e94c0e86533c0b27ed7cacc1239cb51c178fd239c3cfefefb0400a \ - --hash=sha256:f983e4c2f603c95dde63df633eec42955508eefd8d0f0e6d236d31a044c882d7 \ - --hash=sha256:faa5e8496c530f9c71f2b4e1c49758b06e5f4055e17144906245c99fa6d45356 \ - --hash=sha256:fed5dfefdf384d6fe975cc026886aece4f292feaf69d0eeb716cfd3c5a4dd8be +rpds-py==0.22.3 \ + --hash=sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518 \ + --hash=sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059 \ + --hash=sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61 \ + --hash=sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5 \ + --hash=sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9 \ + --hash=sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543 \ + --hash=sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2 \ + --hash=sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a \ + --hash=sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d \ + --hash=sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56 \ + --hash=sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d \ + --hash=sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd \ + --hash=sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b \ + --hash=sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4 \ + --hash=sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99 \ + --hash=sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d \ + --hash=sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd \ + --hash=sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe \ + --hash=sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1 \ + --hash=sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e \ + --hash=sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f \ + --hash=sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3 \ + --hash=sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca \ + --hash=sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d \ + --hash=sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e \ + --hash=sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc \ + --hash=sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea \ + --hash=sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38 \ + --hash=sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b \ + --hash=sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c \ + --hash=sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff \ + --hash=sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723 \ + --hash=sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e \ + --hash=sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493 \ + --hash=sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6 \ + --hash=sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83 \ + --hash=sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091 \ + --hash=sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1 \ + --hash=sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627 \ + --hash=sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1 \ + --hash=sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728 \ + --hash=sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16 \ + --hash=sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c \ + --hash=sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45 \ + --hash=sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7 \ + --hash=sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a \ + --hash=sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730 \ + --hash=sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967 \ + --hash=sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25 \ + --hash=sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24 \ + --hash=sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055 \ + --hash=sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d \ + --hash=sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0 \ + --hash=sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e \ + --hash=sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7 \ + --hash=sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c \ + --hash=sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f \ + --hash=sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd \ + --hash=sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652 \ + --hash=sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8 \ + --hash=sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11 \ + --hash=sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333 \ + --hash=sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96 \ + --hash=sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64 \ + --hash=sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b \ + --hash=sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e \ + --hash=sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c \ + --hash=sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9 \ + --hash=sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec \ + --hash=sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb \ + --hash=sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37 \ + --hash=sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad \ + --hash=sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9 \ + --hash=sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c \ + --hash=sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf \ + --hash=sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4 \ + --hash=sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f \ + --hash=sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d \ + --hash=sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09 \ + --hash=sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d \ + --hash=sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566 \ + --hash=sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74 \ + --hash=sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338 \ + --hash=sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15 \ + --hash=sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c \ + --hash=sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648 \ + --hash=sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84 \ + --hash=sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3 \ + --hash=sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123 \ + --hash=sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520 \ + --hash=sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831 \ + --hash=sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e \ + --hash=sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf \ + --hash=sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b \ + --hash=sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2 \ + --hash=sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3 \ + --hash=sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130 \ + --hash=sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b \ + --hash=sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de \ + --hash=sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5 \ + --hash=sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d \ + --hash=sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00 \ + --hash=sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e # via # jsonschema # referencing @@ -1417,37 +1443,37 @@ ruamel-yaml-clib==0.2.12 \ --hash=sha256:fc4b630cd3fa2cf7fce38afa91d7cfe844a9f75d7f0f36393fa98815e911d987 \ --hash=sha256:fd5415dded15c3822597455bc02bcd66e81ef8b7a48cb71a33628fc9fdde39df # via ruamel-yaml -ruff==0.7.4 \ - --hash=sha256:00b4cf3a6b5fad6d1a66e7574d78956bbd09abfd6c8a997798f01f5da3d46a05 \ - --hash=sha256:0d06218747d361d06fd2fdac734e7fa92df36df93035db3dc2ad7aa9852cb109 \ - --hash=sha256:0e92dfb5f00eaedb1501b2f906ccabfd67b2355bdf117fea9719fc99ac2145bc \ - --hash=sha256:11bff065102c3ae9d3ea4dc9ecdfe5a5171349cdd0787c1fc64761212fc9cf1f \ - --hash=sha256:2e32829c429dd081ee5ba39aef436603e5b22335c3d3fff013cd585806a6486a \ - --hash=sha256:3bd726099f277d735dc38900b6a8d6cf070f80828877941983a57bca1cd92172 \ - --hash=sha256:63a569b36bc66fbadec5beaa539dd81e0527cb258b94e29e0531ce41bacc1f20 \ - --hash=sha256:662a63b4971807623f6f90c1fb664613f67cc182dc4d991471c23c541fee62dd \ - --hash=sha256:745775c7b39f914238ed1f1b0bebed0b9155a17cd8bc0b08d3c87e4703b990d6 \ - --hash=sha256:75c53f54904be42dd52a548728a5b572344b50d9b2873d13a3f8c5e3b91f5cac \ - --hash=sha256:7dbdc7d8274e1422722933d1edddfdc65b4336abf0b16dfcb9dedd6e6a517d06 \ - --hash=sha256:80094ecd4793c68b2571b128f91754d60f692d64bc0d7272ec9197fdd09bf9ea \ - --hash=sha256:876f5e09eaae3eb76814c1d3b68879891d6fde4824c015d48e7a7da4cf066a3a \ - --hash=sha256:997512325c6620d1c4c2b15db49ef59543ef9cd0f4aa8065ec2ae5103cedc7e7 \ - --hash=sha256:a4919925e7684a3f18e18243cd6bea7cfb8e968a6eaa8437971f681b7ec51478 \ - --hash=sha256:cd12e35031f5af6b9b93715d8c4f40360070b2041f81273d0527683d5708fce2 \ - --hash=sha256:cfb365c135b830778dda8c04fb7d4280ed0b984e1aec27f574445231e20d6c63 \ - --hash=sha256:e0cea28d0944f74ebc33e9f934238f15c758841f9f5edd180b5315c203293452 +ruff==0.8.2 \ + --hash=sha256:1ca4e3a87496dc07d2427b7dd7ffa88a1e597c28dad65ae6433ecb9f2e4f022f \ + --hash=sha256:2aae99ec70abf43372612a838d97bfe77d45146254568d94926e8ed5bbb409ea \ + --hash=sha256:32096b41aaf7a5cc095fa45b4167b890e4c8d3fd217603f3634c92a541de7248 \ + --hash=sha256:5fe716592ae8a376c2673fdfc1f5c0c193a6d0411f90a496863c99cd9e2ae25d \ + --hash=sha256:60f578c11feb1d3d257b2fb043ddb47501ab4816e7e221fbb0077f0d5d4e7b6f \ + --hash=sha256:705832cd7d85605cb7858d8a13d75993c8f3ef1397b0831289109e953d833d29 \ + --hash=sha256:729850feed82ef2440aa27946ab39c18cb4a8889c1128a6d589ffa028ddcfc22 \ + --hash=sha256:81c148825277e737493242b44c5388a300584d73d5774defa9245aaef55448b0 \ + --hash=sha256:ac42caaa0411d6a7d9594363294416e0e48fc1279e1b0e948391695db2b3d5b1 \ + --hash=sha256:b402ddee3d777683de60ff76da801fa7e5e8a71038f57ee53e903afbcefdaa58 \ + --hash=sha256:b84f4f414dda8ac7f75075c1fa0b905ac0ff25361f42e6d5da681a465e0f78e5 \ + --hash=sha256:c49ab4da37e7c457105aadfd2725e24305ff9bc908487a9bf8d548c6dad8bb3d \ + --hash=sha256:cbd5cf9b0ae8f30eebc7b360171bd50f59ab29d39f06a670b3e4501a36ba5897 \ + --hash=sha256:d261d7850c8367704874847d95febc698a950bf061c9475d4a8b7689adc4f7fa \ + --hash=sha256:e769083da9439508833cfc7c23e351e1809e67f47c50248250ce1ac52c21fb93 \ + --hash=sha256:ec016beb69ac16be416c435828be702ee694c0d722505f9c1f35e1b9c0cc1bf5 \ + --hash=sha256:f05cdf8d050b30e2ba55c9b09330b51f9f97d36d4673213679b965d25a785f3c \ + --hash=sha256:fb88e2a506b70cfbc2de6fae6681c4f944f7dd5f2fe87233a7233d888bad73e8 # via -r lock/requirements-dev-template.in -s3transfer==0.10.3 \ - --hash=sha256:263ed587a5803c6c708d3ce44dc4dfedaab4c1a32e8329bab818933d79ddcf5d \ - --hash=sha256:4f50ed74ab84d474ce614475e0b8d5047ff080810aac5d01ea25231cfc944b0c +s3transfer==0.10.4 \ + --hash=sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e \ + --hash=sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7 # via boto3 semver==3.0.2 \ --hash=sha256:6253adb39c70f6e51afed2fa7152bcd414c411286088fb4b9effb133885ab4cc \ --hash=sha256:b1ea4686fe70b981f85359eda33199d60c53964284e0cfb4977d243e37cf4bf4 # via ghga-transpiler -setuptools==75.5.0 \ - --hash=sha256:5c4ccb41111392671f02bb5f8436dfc5a9a7185e80500531b133f5775c4163ef \ - --hash=sha256:87cb777c3b96d638ca02031192d40390e0ad97737e27b6b4fa831bea86f2f829 +setuptools==75.6.0 \ + --hash=sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6 \ + --hash=sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d # via -r lock/requirements-dev-template.in shellingham==1.5.4 \ --hash=sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686 \ @@ -1459,9 +1485,9 @@ shexjsg==0.8.2 \ # via # pyshex # pyshexc -six==1.16.0 \ - --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ - --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 +six==1.17.0 \ + --hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \ + --hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81 # via # python-dateutil # rfc3339-validator @@ -1472,9 +1498,7 @@ snakeviz==2.2.2 \ sniffio==1.3.1 \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc - # via - # anyio - # httpx + # via anyio sortedcontainers==2.4.0 \ --hash=sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88 \ --hash=sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0 @@ -1548,9 +1572,9 @@ sqlalchemy==2.0.36 \ --hash=sha256:fddbe92b4760c6f5d48162aef14824add991aeda8ddadb3c31d56eb15ca69f8e \ --hash=sha256:fdf3386a801ea5aba17c6410dd1dc8d39cf454ca2565541b5ac42a84e1e28f53 # via linkml -starlette==0.41.2 \ - --hash=sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62 \ - --hash=sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d +starlette==0.41.3 \ + --hash=sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835 \ + --hash=sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7 # via fastapi stringcase==1.2.0 \ --hash=sha256:48a06980661908efe8d9d34eab2b6c13aefa2163b3ced26972902e3bdfd87008 @@ -1569,22 +1593,22 @@ tomli-w==1.1.0 \ --hash=sha256:1403179c78193e3184bfaade390ddbd071cba48a32a2e62ba11aae47490c63f7 \ --hash=sha256:49e847a3a304d516a169a601184932ef0f6b61623fe680f836a2aa7128ed0d33 # via -r lock/requirements-dev-template.in -tornado==6.4.1 \ - --hash=sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8 \ - --hash=sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f \ - --hash=sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4 \ - --hash=sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3 \ - --hash=sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14 \ - --hash=sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842 \ - --hash=sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9 \ - --hash=sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698 \ - --hash=sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7 \ - --hash=sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d \ - --hash=sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4 +tornado==6.4.2 \ + --hash=sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803 \ + --hash=sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec \ + --hash=sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482 \ + --hash=sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634 \ + --hash=sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38 \ + --hash=sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b \ + --hash=sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c \ + --hash=sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf \ + --hash=sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946 \ + --hash=sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73 \ + --hash=sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1 # via snakeviz -typer==0.13.0 \ - --hash=sha256:d85fe0b777b2517cc99c8055ed735452f2659cd45e451507c76f48ce5c1d00e2 \ - --hash=sha256:f1c7198347939361eec90139ffa0fd8b3df3a2259d5852a0f7400e476d95985c +typer==0.15.1 \ + --hash=sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847 \ + --hash=sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a # via # -r lock/requirements-dev-template.in # ghga-transpiler @@ -1620,25 +1644,25 @@ urllib3==2.2.3 \ # pyshex # requests # testcontainers -uv==0.5.2 \ - --hash=sha256:15c7ffa08ae21abd221dbdf9ba25c8969235f587cec6df8035552434e5ca1cc5 \ - --hash=sha256:2597e91be45b3f4458d0d16a5a1cda7e93af7d6dbfddf251aae5377f9187fa88 \ - --hash=sha256:27d666da8fbb0f87d9df67abf9feea0da4ee1336730f2c4be29a11f3feaa0a29 \ - --hash=sha256:374e9498e155fcaa8728a6770b84f03781106d705332f4ec059e1cc93c8f4d8a \ - --hash=sha256:5052758d374dd769efd0c70b4789ffb08439567eb114ad8fe728536bb5cc5299 \ - --hash=sha256:675ca34829ceca3e9de395cf05e8f881334a24488f97dd923c463830270d52a7 \ - --hash=sha256:67776d34cba359c63919c5ad50331171261d2ec7a83fd07f032eb8cc22e22b8e \ - --hash=sha256:71467545d51883d1af7094c8f6da69b55e7d49b742c2dc707d644676dcb66515 \ - --hash=sha256:772b32d157ec8f27c0099ecac94cf5cd298bce72f1a1f512205591de4e9f0c5c \ - --hash=sha256:7bde66f13571e437fd45f32f5742ab53d5e011b4edb1c74cb74cb8b1cbb828b5 \ - --hash=sha256:89e60ad9601f35f187326de84f35e7517c6eb1438359da42ec85cfd9c1895957 \ - --hash=sha256:a4d4fdad03e6dc3e8216192b8a12bcf2c71c8b12046e755575c7f262cbb61924 \ - --hash=sha256:a8a9897dd7657258c53f41aecdbe787da99f4fc0775f19826ab65cc0a7136cbf \ - --hash=sha256:c9795b990fb0b2a18d3a8cef8822e13c6a6f438bc16d34ccf01d931c76cfd5da \ - --hash=sha256:cfba5b0070652da4174083b78852f3ab3d262ba1c8b63a4d5ae497263b02b834 \ - --hash=sha256:d0834c6b37750c045bbea80600d3ae3e95becc4db148f5c0d0bc3ec6a7924e8f \ - --hash=sha256:d1fe4e025dbb9ec5c9250bfc1231847b8487706538f94d10c769f0a54db3e0af \ - --hash=sha256:dfcd8275ff8cb59d5f26f826a44270b2fe8f38aa7188d7355c48d3e9b759d0c0 +uv==0.5.6 \ + --hash=sha256:152466b8854bc30661620671cd1e5e854123e734fb4f380bc83eab5e3c4450a9 \ + --hash=sha256:2b1dc05b9b242989d4a6dc99916a0fd6dc98ea5146f757505da69ac20825067d \ + --hash=sha256:485decff72ba2ba6c8b82de0f8ecc877bd4080dc4e27604f3ebd9da98e00c53f \ + --hash=sha256:4ca83b575d316030503d81d3cc85a53be45d8bab56892f845f7e545006e5df59 \ + --hash=sha256:5b49db3c842dcdaccdaf8ea26770c2b18632528f68e7f3211415ae25796de71a \ + --hash=sha256:6c7afc715f48a6ddc61257ed62c74595b5762eb67a6f23696fae6e609698a990 \ + --hash=sha256:6e13c1bb1f00b596a50711afffc407570edf9825fea4cfbc1d80cfb59816e501 \ + --hash=sha256:6e14da824a775abe4f28f03c4a672df99697fdd42c5e99df40d99a7d5c90e5c8 \ + --hash=sha256:848b12fe47ee8dd871ae5cfb1fefc2bac7cdb90bd34ff1f08bf78dd751f6950a \ + --hash=sha256:87b0b77ebf036363b8b0ed55c0f4a4a687b20500e3f9aa45574dfe05f9761057 \ + --hash=sha256:8bc30ef6996c3352a45d75ebc9aeb2e7ae5ebb7b2118b6f036ddd02d4f689daa \ + --hash=sha256:920dd926d235f826454e7b68cb1890ded6e67510e6195c346eef41caabc9d9b7 \ + --hash=sha256:9297f084ca2004044a9353525777c9cb1151a0d768de87cc3920574597674f88 \ + --hash=sha256:9c1ebf58ef3906e05e0060cda4a801a45e93334169821a89effa6ba9607dfa07 \ + --hash=sha256:a15ac68584b346e592ca4c5167ffd4c4ba9906706b423b696e7b37d03dea753b \ + --hash=sha256:c1a3b180e90734812034cc1594256f519bff6c2715f3f1ceb9ac7bc578005f5d \ + --hash=sha256:eae7301bd35891545a4e139b0f1bd5aa7981afba43654233297be463d6d6ba8b \ + --hash=sha256:f2e6a13da16b8a3a43d50a1be5910c4e55b04889bcacfb8c9a22dcff817fa326 # via -r lock/requirements-dev-template.in uvicorn==0.29.0 \ --hash=sha256:2c2aac7ff4f4365c206fd773a39bf4ebd1047c238f8b8268ad996829323473de \ @@ -1683,9 +1707,9 @@ uvloop==0.21.0 \ --hash=sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816 \ --hash=sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2 # via uvicorn -virtualenv==20.27.1 \ - --hash=sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba \ - --hash=sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4 +virtualenv==20.28.0 \ + --hash=sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0 \ + --hash=sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa # via pre-commit watchdog==6.0.0 \ --hash=sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a \ @@ -1719,90 +1743,78 @@ watchdog==6.0.0 \ --hash=sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c \ --hash=sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2 # via linkml -watchfiles==0.24.0 \ - --hash=sha256:01550ccf1d0aed6ea375ef259706af76ad009ef5b0203a3a4cce0f6024f9b68a \ - --hash=sha256:01def80eb62bd5db99a798d5e1f5f940ca0a05986dcfae21d833af7a46f7ee22 \ - --hash=sha256:07cdef0c84c03375f4e24642ef8d8178e533596b229d32d2bbd69e5128ede02a \ - --hash=sha256:083dc77dbdeef09fa44bb0f4d1df571d2e12d8a8f985dccde71ac3ac9ac067a0 \ - --hash=sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827 \ - --hash=sha256:21ab23fdc1208086d99ad3f69c231ba265628014d4aed31d4e8746bd59e88cd1 \ - --hash=sha256:2dadf8a8014fde6addfd3c379e6ed1a981c8f0a48292d662e27cabfe4239c83c \ - --hash=sha256:2e28d91ef48eab0afb939fa446d8ebe77e2f7593f5f463fd2bb2b14132f95b6e \ - --hash=sha256:2efec17819b0046dde35d13fb8ac7a3ad877af41ae4640f4109d9154ed30a188 \ - --hash=sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b \ - --hash=sha256:316449aefacf40147a9efaf3bd7c9bdd35aaba9ac5d708bd1eb5763c9a02bef5 \ - --hash=sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90 \ - --hash=sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef \ - --hash=sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b \ - --hash=sha256:3770e260b18e7f4e576edca4c0a639f704088602e0bc921c5c2e721e3acb8d15 \ - --hash=sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48 \ - --hash=sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e \ - --hash=sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df \ - --hash=sha256:449f43f49c8ddca87c6b3980c9284cab6bd1f5c9d9a2b00012adaaccd5e7decd \ - --hash=sha256:4933a508d2f78099162da473841c652ad0de892719043d3f07cc83b33dfd9d91 \ - --hash=sha256:49d617df841a63b4445790a254013aea2120357ccacbed00253f9c2b5dc24e2d \ - --hash=sha256:49fb58bcaa343fedc6a9e91f90195b20ccb3135447dc9e4e2570c3a39565853e \ - --hash=sha256:4a7fa2bc0efef3e209a8199fd111b8969fe9db9c711acc46636686331eda7dd4 \ - --hash=sha256:4abf4ad269856618f82dee296ac66b0cd1d71450fc3c98532d93798e73399b7a \ - --hash=sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370 \ - --hash=sha256:4d28cea3c976499475f5b7a2fec6b3a36208656963c1a856d328aeae056fc5c1 \ - --hash=sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea \ - --hash=sha256:54ca90a9ae6597ae6dc00e7ed0a040ef723f84ec517d3e7ce13e63e4bc82fa04 \ - --hash=sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896 \ - --hash=sha256:5c51749f3e4e269231510da426ce4a44beb98db2dce9097225c338f815b05d4f \ - --hash=sha256:632676574429bee8c26be8af52af20e0c718cc7f5f67f3fb658c71928ccd4f7f \ - --hash=sha256:6509ed3f467b79d95fc62a98229f79b1a60d1b93f101e1c61d10c95a46a84f43 \ - --hash=sha256:6bdcfa3cd6fdbdd1a068a52820f46a815401cbc2cb187dd006cb076675e7b735 \ - --hash=sha256:7138eff8baa883aeaa074359daabb8b6c1e73ffe69d5accdc907d62e50b1c0da \ - --hash=sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a \ - --hash=sha256:73bde715f940bea845a95247ea3e5eb17769ba1010efdc938ffcb967c634fa61 \ - --hash=sha256:78470906a6be5199524641f538bd2c56bb809cd4bf29a566a75051610bc982c3 \ - --hash=sha256:7ae3e208b31be8ce7f4c2c0034f33406dd24fbce3467f77223d10cd86778471c \ - --hash=sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f \ - --hash=sha256:82ae557a8c037c42a6ef26c494d0631cacca040934b101d001100ed93d43f361 \ - --hash=sha256:82b2509f08761f29a0fdad35f7e1638b8ab1adfa2666d41b794090361fb8b855 \ - --hash=sha256:8360f7314a070c30e4c976b183d1d8d1585a4a50c5cb603f431cebcbb4f66327 \ - --hash=sha256:85d5f0c7771dcc7a26c7a27145059b6bb0ce06e4e751ed76cdf123d7039b60b5 \ - --hash=sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab \ - --hash=sha256:9301c689051a4857d5b10777da23fafb8e8e921bcf3abe6448a058d27fb67633 \ - --hash=sha256:951088d12d339690a92cef2ec5d3cfd957692834c72ffd570ea76a6790222777 \ - --hash=sha256:95cf3b95ea665ab03f5a54765fa41abf0529dbaf372c3b83d91ad2cfa695779b \ - --hash=sha256:96619302d4374de5e2345b2b622dc481257a99431277662c30f606f3e22f42be \ - --hash=sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f \ - --hash=sha256:9a60e2bf9dc6afe7f743e7c9b149d1fdd6dbf35153c78fe3a14ae1a9aee3d98b \ - --hash=sha256:9f895d785eb6164678ff4bb5cc60c5996b3ee6df3edb28dcdeba86a13ea0465e \ - --hash=sha256:a2a9891723a735d3e2540651184be6fd5b96880c08ffe1a98bae5017e65b544b \ - --hash=sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366 \ - --hash=sha256:aa0fd7248cf533c259e59dc593a60973a73e881162b1a2f73360547132742823 \ - --hash=sha256:acbfa31e315a8f14fe33e3542cbcafc55703b8f5dcbb7c1eecd30f141df50db3 \ - --hash=sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1 \ - --hash=sha256:b3ef2c69c655db63deb96b3c3e587084612f9b1fa983df5e0c3379d41307467f \ - --hash=sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418 \ - --hash=sha256:b665caeeda58625c3946ad7308fbd88a086ee51ccb706307e5b1fa91556ac886 \ - --hash=sha256:b74fdffce9dfcf2dc296dec8743e5b0332d15df19ae464f0e249aa871fc1c571 \ - --hash=sha256:b995bfa6bf01a9e09b884077a6d37070464b529d8682d7691c2d3b540d357a0c \ - --hash=sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94 \ - --hash=sha256:bdcd5538e27f188dd3c804b4a8d5f52a7fc7f87e7fd6b374b8e36a4ca03db428 \ - --hash=sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234 \ - --hash=sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6 \ - --hash=sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968 \ - --hash=sha256:d337193bbf3e45171c8025e291530fb7548a93c45253897cd764a6a71c937ed9 \ - --hash=sha256:d3dcb774e3568477275cc76554b5a565024b8ba3a0322f77c246bc7111c5bb9c \ - --hash=sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e \ - --hash=sha256:d7a2e3b7f5703ffbd500dabdefcbc9eafeff4b9444bbdd5d83d79eedf8428fab \ - --hash=sha256:d831ee0a50946d24a53821819b2327d5751b0c938b12c0653ea5be7dea9c82ec \ - --hash=sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444 \ - --hash=sha256:e5171ef898299c657685306d8e1478a45e9303ddcd8ac5fed5bd52ad4ae0b69b \ - --hash=sha256:e94e98c7cb94cfa6e071d401ea3342767f28eb5a06a58fafdc0d2a4974f4f35c \ - --hash=sha256:ec39698c45b11d9694a1b635a70946a5bad066b593af863460a8e600f0dff1ca \ - --hash=sha256:ed9aba6e01ff6f2e8285e5aa4154e2970068fe0fc0998c4380d0e6278222269b \ - --hash=sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18 \ - --hash=sha256:ee82c98bed9d97cd2f53bdb035e619309a098ea53ce525833e26b93f673bc318 \ - --hash=sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07 \ - --hash=sha256:f7d9b87c4c55e3ea8881dfcbf6d61ea6775fffed1fedffaa60bd047d3c08c430 \ - --hash=sha256:f83df90191d67af5a831da3a33dd7628b02a95450e168785586ed51e6d28943c \ - --hash=sha256:fca9433a45f18b7c779d2bae7beeec4f740d28b788b117a48368d95a3233ed83 \ - --hash=sha256:fd92bbaa2ecdb7864b7600dcdb6f2f1db6e0346ed425fbd01085be04c63f0b05 +watchfiles==1.0.0 \ + --hash=sha256:06d828fe2adc4ac8a64b875ca908b892a3603d596d43e18f7948f3fef5fc671c \ + --hash=sha256:074c7618cd6c807dc4eaa0982b4a9d3f8051cd0b72793511848fd64630174b17 \ + --hash=sha256:09551237645d6bff3972592f2aa5424df9290e7a2e15d63c5f47c48cde585935 \ + --hash=sha256:0fc3bf0effa2d8075b70badfdd7fb839d7aa9cea650d17886982840d71fdeabf \ + --hash=sha256:12ab123135b2f42517f04e720526d41448667ae8249e651385afb5cda31fedc0 \ + --hash=sha256:13a4f9ee0cd25682679eea5c14fc629e2eaa79aab74d963bc4e21f43b8ea1877 \ + --hash=sha256:1d19df28f99d6a81730658fbeb3ade8565ff687f95acb59665f11502b441be5f \ + --hash=sha256:1e176b6b4119b3f369b2b4e003d53a226295ee862c0962e3afd5a1c15680b4e3 \ + --hash=sha256:1ee5edc939f53466b329bbf2e58333a5461e6c7b50c980fa6117439e2c18b42d \ + --hash=sha256:1f73c2147a453315d672c1ad907abe6d40324e34a185b51e15624bc793f93cc6 \ + --hash=sha256:1ff236d7a3f4b0a42f699a22fc374ba526bc55048a70cbb299661158e1bb5e1f \ + --hash=sha256:245fab124b9faf58430da547512d91734858df13f2ddd48ecfa5e493455ffccb \ + --hash=sha256:28babb38cf2da8e170b706c4b84aa7e4528a6fa4f3ee55d7a0866456a1662041 \ + --hash=sha256:28fb64b5843d94e2c2483f7b024a1280662a44409bedee8f2f51439767e2d107 \ + --hash=sha256:29cf884ad4285d23453c702ed03d689f9c0e865e3c85d20846d800d4787de00f \ + --hash=sha256:2a825ba4b32c214e3855b536eb1a1f7b006511d8e64b8215aac06eb680642d84 \ + --hash=sha256:2ac778a460ea22d63c7e6fb0bc0f5b16780ff0b128f7f06e57aaec63bd339285 \ + --hash=sha256:2c2696611182c85eb0e755b62b456f48debff484b7306b56f05478b843ca8ece \ + --hash=sha256:2d9c0518fabf4a3f373b0a94bb9e4ea7a1df18dec45e26a4d182aa8918dee855 \ + --hash=sha256:2de52b499e1ab037f1a87cb8ebcb04a819bf087b1015a4cf6dcf8af3c2a2613e \ + --hash=sha256:37566c844c9ce3b5deb964fe1a23378e575e74b114618d211fbda8f59d7b5dab \ + --hash=sha256:3d94fd83ed54266d789f287472269c0def9120a2022674990bd24ad989ebd7a0 \ + --hash=sha256:48051d1c504448b2fcda71c5e6e3610ae45de6a0b8f5a43b961f250be4bdf5a8 \ + --hash=sha256:487d15927f1b0bd24e7df921913399bb1ab94424c386bea8b267754d698f8f0e \ + --hash=sha256:4a3b33c3aefe9067ebd87846806cd5fc0b017ab70d628aaff077ab9abf4d06b3 \ + --hash=sha256:4ff9c7e84e8b644a8f985c42bcc81457240316f900fc72769aaedec9d088055a \ + --hash=sha256:533a7cbfe700e09780bb31c06189e39c65f06c7f447326fee707fd02f9a6e945 \ + --hash=sha256:53ae447f06f8f29f5ab40140f19abdab822387a7c426a369eb42184b021e97eb \ + --hash=sha256:550109001920a993a4383b57229c717fa73627d2a4e8fcb7ed33c7f1cddb0c85 \ + --hash=sha256:5bbd0311588c2de7f9ea5cf3922ccacfd0ec0c1922870a2be503cc7df1ca8be7 \ + --hash=sha256:5dccfc70480087567720e4e36ec381bba1ed68d7e5f368fe40c93b3b1eba0105 \ + --hash=sha256:5f75cd42e7e2254117cf37ff0e68c5b3f36c14543756b2da621408349bd9ca7c \ + --hash=sha256:648e2b6db53eca6ef31245805cd528a16f56fa4cc15aeec97795eaf713c11435 \ + --hash=sha256:774ef36b16b7198669ce655d4f75b4c3d370e7f1cbdfb997fb10ee98717e2058 \ + --hash=sha256:8a2127cd68950787ee36753e6d401c8ea368f73beaeb8e54df5516a06d1ecd82 \ + --hash=sha256:90004553be36427c3d06ec75b804233f8f816374165d5225b93abd94ba6e7234 \ + --hash=sha256:905f69aad276639eff3893759a07d44ea99560e67a1cf46ff389cd62f88872a2 \ + --hash=sha256:9122b8fdadc5b341315d255ab51d04893f417df4e6c1743b0aac8bf34e96e025 \ + --hash=sha256:9272fdbc0e9870dac3b505bce1466d386b4d8d6d2bacf405e603108d50446940 \ + --hash=sha256:936f362e7ff28311b16f0b97ec51e8f2cc451763a3264640c6ed40fb252d1ee4 \ + --hash=sha256:947ccba18a38b85c366dafeac8df2f6176342d5992ca240a9d62588b214d731f \ + --hash=sha256:95dc785bc284552d044e561b8f4fe26d01ab5ca40d35852a6572d542adfeb4bc \ + --hash=sha256:95de85c254f7fe8cbdf104731f7f87f7f73ae229493bebca3722583160e6b152 \ + --hash=sha256:9b4fb98100267e6a5ebaff6aaa5d20aea20240584647470be39fe4823012ac96 \ + --hash=sha256:9c01446626574561756067f00b37e6b09c8622b0fc1e9fdbc7cbcea328d4e514 \ + --hash=sha256:9c9a8d8fd97defe935ef8dd53d562e68942ad65067cd1c54d6ed8a088b1d931d \ + --hash=sha256:9e1d9284cc84de7855fcf83472e51d32daf6f6cecd094160192628bc3fee1b78 \ + --hash=sha256:a0abf173975eb9dd17bb14c191ee79999e650997cc644562f91df06060610e62 \ + --hash=sha256:a2218e78e2c6c07b1634a550095ac2a429026b2d5cbcd49a594f893f2bb8c936 \ + --hash=sha256:a5a7a06cfc65e34fd0a765a7623c5ba14707a0870703888e51d3d67107589817 \ + --hash=sha256:b2bca898c1dc073912d3db7fa6926cc08be9575add9e84872de2c99c688bac4e \ + --hash=sha256:b46e15c34d4e401e976d6949ad3a74d244600d5c4b88c827a3fdf18691a46359 \ + --hash=sha256:b551c465a59596f3d08170bd7e1c532c7260dd90ed8135778038e13c5d48aa81 \ + --hash=sha256:b555a93c15bd2c71081922be746291d776d47521a00703163e5fbe6d2a402399 \ + --hash=sha256:bc338ce9f8846543d428260fa0f9a716626963148edc937d71055d01d81e1525 \ + --hash=sha256:bedf84835069f51c7b026b3ca04e2e747ea8ed0a77c72006172c72d28c9f69fc \ + --hash=sha256:c3d258d78341d5d54c0c804a5b7faa66cd30ba50b2756a7161db07ce15363b8d \ + --hash=sha256:c83a6d33a9eda0af6a7470240d1af487807adc269704fe76a4972dd982d16236 \ + --hash=sha256:c9a13ac46b545a7d0d50f7641eefe47d1597e7d1783a5d89e09d080e6dff44b0 \ + --hash=sha256:cf517701a4a872417f4e02a136e929537743461f9ec6cdb8184d9a04f4843545 \ + --hash=sha256:d2b39aa8edd9e5f56f99a2a2740a251dc58515398e9ed5a4b3e5ff2827060755 \ + --hash=sha256:d3572d4c34c4e9c33d25b3da47d9570d5122f8433b9ac6519dca49c2740d23cd \ + --hash=sha256:d562a6114ddafb09c33246c6ace7effa71ca4b6a2324a47f4b09b6445ea78941 \ + --hash=sha256:e1ed613ee107269f66c2df631ec0fc8efddacface85314d392a4131abe299f00 \ + --hash=sha256:e3750434c83b61abb3163b49c64b04180b85b4dabb29a294513faec57f2ffdb7 \ + --hash=sha256:eba98901a2eab909dbd79681190b9049acc650f6111fde1845484a4450761e98 \ + --hash=sha256:f159ac795785cde4899e0afa539f4c723fb5dd336ce5605bc909d34edd00b79b \ + --hash=sha256:f8c4f3a1210ed099a99e6a710df4ff2f8069411059ffe30fa5f9467ebed1256b \ + --hash=sha256:fa13d604fcb9417ae5f2e3de676e66aa97427d888e83662ad205bed35a313176 \ + --hash=sha256:fbd0ab7a9943bbddb87cbc2bf2f09317e74c77dc55b1f5657f81d04666c25269 \ + --hash=sha256:ffd98a299b0a74d1b704ef0ed959efb753e656a4e0425c14e46ae4c3cbdd2919 # via uvicorn webcolors==24.11.1 \ --hash=sha256:515291393b4cdf0eb19c155749a096f779f7d909f7cceea072791cb9095b92e9 \ @@ -1879,77 +1891,72 @@ websockets==14.1 \ --hash=sha256:f6cf0ad281c979306a6a34242b371e90e891bce504509fb6bb5246bbbf31e7b6 \ --hash=sha256:f95ba34d71e2fa0c5d225bde3b3bdb152e957150100e75c86bc7f3964c450d89 # via uvicorn -wrapt==1.16.0 \ - --hash=sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc \ - --hash=sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81 \ - --hash=sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09 \ - --hash=sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e \ - --hash=sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca \ - --hash=sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0 \ - --hash=sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb \ - --hash=sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487 \ - --hash=sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40 \ - --hash=sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c \ - --hash=sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060 \ - --hash=sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202 \ - --hash=sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41 \ - --hash=sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9 \ - --hash=sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b \ - --hash=sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664 \ - --hash=sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d \ - --hash=sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362 \ - --hash=sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00 \ - --hash=sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc \ - --hash=sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1 \ - --hash=sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267 \ - --hash=sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956 \ - --hash=sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966 \ - --hash=sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1 \ - --hash=sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228 \ - --hash=sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72 \ - --hash=sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d \ - --hash=sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292 \ - --hash=sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0 \ - --hash=sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0 \ - --hash=sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36 \ - --hash=sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c \ - --hash=sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5 \ - --hash=sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f \ - --hash=sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73 \ - --hash=sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b \ - --hash=sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2 \ - --hash=sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593 \ - --hash=sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39 \ - --hash=sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389 \ - --hash=sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf \ - --hash=sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf \ - --hash=sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89 \ - --hash=sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c \ - --hash=sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c \ - --hash=sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f \ - --hash=sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440 \ - --hash=sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465 \ - --hash=sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136 \ - --hash=sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b \ - --hash=sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8 \ - --hash=sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3 \ - --hash=sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8 \ - --hash=sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6 \ - --hash=sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e \ - --hash=sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f \ - --hash=sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c \ - --hash=sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e \ - --hash=sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8 \ - --hash=sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2 \ - --hash=sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020 \ - --hash=sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35 \ - --hash=sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d \ - --hash=sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3 \ - --hash=sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537 \ - --hash=sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809 \ - --hash=sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d \ - --hash=sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a \ - --hash=sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4 +wrapt==1.17.0 \ + --hash=sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d \ + --hash=sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301 \ + --hash=sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635 \ + --hash=sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a \ + --hash=sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed \ + --hash=sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721 \ + --hash=sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801 \ + --hash=sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b \ + --hash=sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1 \ + --hash=sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88 \ + --hash=sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8 \ + --hash=sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0 \ + --hash=sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f \ + --hash=sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578 \ + --hash=sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7 \ + --hash=sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045 \ + --hash=sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada \ + --hash=sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d \ + --hash=sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b \ + --hash=sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a \ + --hash=sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977 \ + --hash=sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea \ + --hash=sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346 \ + --hash=sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13 \ + --hash=sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22 \ + --hash=sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339 \ + --hash=sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9 \ + --hash=sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181 \ + --hash=sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c \ + --hash=sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90 \ + --hash=sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a \ + --hash=sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489 \ + --hash=sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f \ + --hash=sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504 \ + --hash=sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea \ + --hash=sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569 \ + --hash=sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4 \ + --hash=sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce \ + --hash=sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab \ + --hash=sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a \ + --hash=sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f \ + --hash=sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c \ + --hash=sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9 \ + --hash=sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf \ + --hash=sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d \ + --hash=sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627 \ + --hash=sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d \ + --hash=sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4 \ + --hash=sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c \ + --hash=sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d \ + --hash=sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad \ + --hash=sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b \ + --hash=sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33 \ + --hash=sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371 \ + --hash=sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1 \ + --hash=sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393 \ + --hash=sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106 \ + --hash=sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df \ + --hash=sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379 \ + --hash=sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451 \ + --hash=sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b \ + --hash=sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575 \ + --hash=sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed \ + --hash=sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb \ + --hash=sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838 # via # deprecated # testcontainers diff --git a/lock/requirements.txt b/lock/requirements.txt index 8e6b15a..fcfc950 100644 --- a/lock/requirements.txt +++ b/lock/requirements.txt @@ -72,46 +72,44 @@ attrs==24.2.0 \ # -c lock/requirements-dev.txt # jsonschema # referencing -bcrypt==4.2.0 \ - --hash=sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb \ - --hash=sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399 \ - --hash=sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291 \ - --hash=sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d \ - --hash=sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7 \ - --hash=sha256:1ff39b78a52cf03fdf902635e4c81e544714861ba3f0efc56558979dd4f09170 \ - --hash=sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d \ - --hash=sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe \ - --hash=sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060 \ - --hash=sha256:373db9abe198e8e2c70d12b479464e0d5092cc122b20ec504097b5f2297ed184 \ - --hash=sha256:39e1d30c7233cfc54f5c3f2c825156fe044efdd3e0b9d309512cc514a263ec2a \ - --hash=sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68 \ - --hash=sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c \ - --hash=sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458 \ - --hash=sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9 \ - --hash=sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328 \ - --hash=sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7 \ - --hash=sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34 \ - --hash=sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e \ - --hash=sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2 \ - --hash=sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5 \ - --hash=sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae \ - --hash=sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00 \ - --hash=sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841 \ - --hash=sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8 \ - --hash=sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221 \ - --hash=sha256:f4f4acf526fcd1c34e7ce851147deedd4e26e6402369304220250598b26448db +bcrypt==4.2.1 \ + --hash=sha256:041fa0155c9004eb98a232d54da05c0b41d4b8e66b6fc3cb71b4b3f6144ba837 \ + --hash=sha256:04e56e3fe8308a88b77e0afd20bec516f74aecf391cdd6e374f15cbed32783d6 \ + --hash=sha256:1340411a0894b7d3ef562fb233e4b6ed58add185228650942bdc885362f32c17 \ + --hash=sha256:533e7f3bcf2f07caee7ad98124fab7499cb3333ba2274f7a36cf1daee7409d99 \ + --hash=sha256:6765386e3ab87f569b276988742039baab087b2cdb01e809d74e74503c2faafe \ + --hash=sha256:687cf30e6681eeda39548a93ce9bfbb300e48b4d445a43db4298d2474d2a1e54 \ + --hash=sha256:76132c176a6d9953cdc83c296aeaed65e1a708485fd55abf163e0d9f8f16ce0e \ + --hash=sha256:76d3e352b32f4eeb34703370e370997065d28a561e4a18afe4fef07249cb4396 \ + --hash=sha256:807261df60a8b1ccd13e6599c779014a362ae4e795f5c59747f60208daddd96d \ + --hash=sha256:89df2aea2c43be1e1fa066df5f86c8ce822ab70a30e4c210968669565c0f4685 \ + --hash=sha256:8ad2f4528cbf0febe80e5a3a57d7a74e6635e41af1ea5675282a33d769fba413 \ + --hash=sha256:8c458cd103e6c5d1d85cf600e546a639f234964d0228909d8f8dbeebff82d526 \ + --hash=sha256:8dbd0747208912b1e4ce730c6725cb56c07ac734b3629b60d4398f082ea718ad \ + --hash=sha256:909faa1027900f2252a9ca5dfebd25fc0ef1417943824783d1c8418dd7d6df4a \ + --hash=sha256:aaa2e285be097050dba798d537b6efd9b698aa88eef52ec98d23dcd6d7cf6fea \ + --hash=sha256:adadd36274510a01f33e6dc08f5824b97c9580583bd4487c564fc4617b328005 \ + --hash=sha256:b1ee315739bc8387aa36ff127afc99120ee452924e0df517a8f3e4c0187a0f5f \ + --hash=sha256:b588af02b89d9fad33e5f98f7838bf590d6d692df7153647724a7f20c186f6bf \ + --hash=sha256:b7703ede632dc945ed1172d6f24e9f30f27b1b1a067f32f68bf169c5f08d0425 \ + --hash=sha256:c6f5fa3775966cca251848d4d5393ab016b3afed251163c1436fefdec3b02c84 \ + --hash=sha256:cde78d385d5e93ece5479a0a87f73cd6fa26b171c786a884f955e165032b262c \ + --hash=sha256:cfdf3d7530c790432046c40cda41dfee8c83e29482e6a604f8930b9930e94139 \ + --hash=sha256:e158009a54c4c8bc91d5e0da80920d048f918c61a581f0a63e4e93bb556d362f \ + --hash=sha256:e84e0e6f8e40a242b11bce56c313edc2be121cec3e0ec2d76fce01f6af33c07c \ + --hash=sha256:f85b1ffa09240c89aa2e1ae9f3b1c687104f7b2b9d2098da4e923f1b7082d331 # via # -c lock/requirements-dev.txt # crypt4gh -boto3==1.35.63 \ - --hash=sha256:d0f938d4f6f392b6ffc5e75fff14a42e5bbb5228675a0367c8af55398abadbec \ - --hash=sha256:deb593d9a0fb240deb4c43e4da8e6626d7c36be7b2fd2fe28f49d44d395b7de0 +boto3==1.35.76 \ + --hash=sha256:31ddcdb6f15dace2b68f6a0f11bdb58dd3ae79b8a3ccb174ff811ef0bbf938e0 \ + --hash=sha256:69458399f41f57a50770c8974796d96978bcca44915c260319696bb43e47dffd # via # -c lock/requirements-dev.txt # hexkit -botocore==1.35.63 \ - --hash=sha256:0ca1200694a4c0a3fa846795d8e8a08404c214e21195eb9e010c4b8a4ca78a4a \ - --hash=sha256:2b8196bab0a997d206c3d490b52e779ef47dffb68c57c685443f77293aca1589 +botocore==1.35.76 \ + --hash=sha256:a75a42ae53395796b8300c5fefb2d65a8696dc40dc85e49cf3a769e0c0202b13 \ + --hash=sha256:b4729d12d00267b3185628f83543917b6caae292385230ab464067621aa086af # via # -c lock/requirements-dev.txt # boto3 @@ -334,34 +332,36 @@ crypt4gh==1.7 \ # via # -c lock/requirements-dev.txt # ghga-datasteward-kit (pyproject.toml) -cryptography==43.0.3 \ - --hash=sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362 \ - --hash=sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4 \ - --hash=sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa \ - --hash=sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83 \ - --hash=sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff \ - --hash=sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805 \ - --hash=sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6 \ - --hash=sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664 \ - --hash=sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08 \ - --hash=sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e \ - --hash=sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18 \ - --hash=sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f \ - --hash=sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73 \ - --hash=sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5 \ - --hash=sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984 \ - --hash=sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd \ - --hash=sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3 \ - --hash=sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e \ - --hash=sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405 \ - --hash=sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2 \ - --hash=sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c \ - --hash=sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995 \ - --hash=sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73 \ - --hash=sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16 \ - --hash=sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7 \ - --hash=sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd \ - --hash=sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7 +cryptography==44.0.0 \ + --hash=sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7 \ + --hash=sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731 \ + --hash=sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b \ + --hash=sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc \ + --hash=sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543 \ + --hash=sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385 \ + --hash=sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c \ + --hash=sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591 \ + --hash=sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede \ + --hash=sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb \ + --hash=sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f \ + --hash=sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123 \ + --hash=sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c \ + --hash=sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba \ + --hash=sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c \ + --hash=sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285 \ + --hash=sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd \ + --hash=sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092 \ + --hash=sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa \ + --hash=sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289 \ + --hash=sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02 \ + --hash=sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64 \ + --hash=sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053 \ + --hash=sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417 \ + --hash=sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e \ + --hash=sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e \ + --hash=sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7 \ + --hash=sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756 \ + --hash=sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4 # via # -c lock/requirements-dev.txt # crypt4gh @@ -410,9 +410,9 @@ et-xmlfile==2.0.0 \ # via # -c lock/requirements-dev.txt # openpyxl -fastapi==0.115.5 \ - --hash=sha256:0e7a4d0dc0d01c68df21887cce0945e72d3c48b9f4f79dfe7a7d53aa08fbb289 \ - --hash=sha256:596b95adbe1474da47049e802f9a65ab2ffa9c2b07e7efee70eb8a66c9f2f796 +fastapi==0.115.6 \ + --hash=sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654 \ + --hash=sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305 # via # -c lock/requirements-dev.txt # ghga-service-commons @@ -537,9 +537,9 @@ hbreader==0.9.1 \ # jsonasobj2 # linkml # linkml-runtime -hexkit==3.7.0 \ - --hash=sha256:1e0273be7232f9ccb68d24ff88671ab7592fbe25522aa53d10177e245e3834dd \ - --hash=sha256:dffbb79549df70963b3e08a5f00452b778619220044e851340fa30ba25212c1d +hexkit==3.8.1 \ + --hash=sha256:51c9f00003f5ed8dfe0585617031c530f2d08f704955f5c5e3340e6f947d597a \ + --hash=sha256:d33b390e861e41deb54217ce85d0a5f3c8fe6ddc3656514d45cc173fe2775553 # via # -c lock/requirements-dev.txt # ghga-datasteward-kit (pyproject.toml) @@ -660,6 +660,8 @@ jsonpatch==1.33 \ # -c lock/requirements-dev.txt # linkml-dataops jsonpath-ng==1.7.0 \ + --hash=sha256:898c93fc173f0c336784a3fa63d7434297544b7198124a68f9a3ef9597b0ae6e \ + --hash=sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6 \ --hash=sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c # via # -c lock/requirements-dev.txt @@ -861,9 +863,9 @@ pycparser==2.22 \ # via # -c lock/requirements-dev.txt # cffi -pydantic==2.9.2 \ - --hash=sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f \ - --hash=sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12 +pydantic==2.10.3 \ + --hash=sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d \ + --hash=sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9 # via # -c lock/requirements-dev.txt # curies @@ -876,96 +878,107 @@ pydantic==2.9.2 \ # linkml-runtime # linkml-validator # pydantic-settings -pydantic-core==2.23.4 \ - --hash=sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36 \ - --hash=sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05 \ - --hash=sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071 \ - --hash=sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327 \ - --hash=sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c \ - --hash=sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36 \ - --hash=sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29 \ - --hash=sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744 \ - --hash=sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d \ - --hash=sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec \ - --hash=sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e \ - --hash=sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e \ - --hash=sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577 \ - --hash=sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232 \ - --hash=sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863 \ - --hash=sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6 \ - --hash=sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368 \ - --hash=sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480 \ - --hash=sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2 \ - --hash=sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2 \ - --hash=sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6 \ - --hash=sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769 \ - --hash=sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d \ - --hash=sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2 \ - --hash=sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84 \ - --hash=sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166 \ - --hash=sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271 \ - --hash=sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5 \ - --hash=sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb \ - --hash=sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13 \ - --hash=sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323 \ - --hash=sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556 \ - --hash=sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665 \ - --hash=sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef \ - --hash=sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb \ - --hash=sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119 \ - --hash=sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126 \ - --hash=sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510 \ - --hash=sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b \ - --hash=sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87 \ - --hash=sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f \ - --hash=sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc \ - --hash=sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8 \ - --hash=sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21 \ - --hash=sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f \ - --hash=sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6 \ - --hash=sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658 \ - --hash=sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b \ - --hash=sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3 \ - --hash=sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb \ - --hash=sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59 \ - --hash=sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24 \ - --hash=sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9 \ - --hash=sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3 \ - --hash=sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd \ - --hash=sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753 \ - --hash=sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55 \ - --hash=sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad \ - --hash=sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a \ - --hash=sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605 \ - --hash=sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e \ - --hash=sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b \ - --hash=sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433 \ - --hash=sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8 \ - --hash=sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07 \ - --hash=sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728 \ - --hash=sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0 \ - --hash=sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327 \ - --hash=sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555 \ - --hash=sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64 \ - --hash=sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6 \ - --hash=sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea \ - --hash=sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b \ - --hash=sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df \ - --hash=sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e \ - --hash=sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd \ - --hash=sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068 \ - --hash=sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3 \ - --hash=sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040 \ - --hash=sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12 \ - --hash=sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916 \ - --hash=sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f \ - --hash=sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f \ - --hash=sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801 \ - --hash=sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231 \ - --hash=sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5 \ - --hash=sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8 \ - --hash=sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee \ - --hash=sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607 +pydantic-core==2.27.1 \ + --hash=sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9 \ + --hash=sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b \ + --hash=sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c \ + --hash=sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529 \ + --hash=sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc \ + --hash=sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854 \ + --hash=sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d \ + --hash=sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278 \ + --hash=sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a \ + --hash=sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c \ + --hash=sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f \ + --hash=sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27 \ + --hash=sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f \ + --hash=sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac \ + --hash=sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2 \ + --hash=sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97 \ + --hash=sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a \ + --hash=sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919 \ + --hash=sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9 \ + --hash=sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4 \ + --hash=sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c \ + --hash=sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131 \ + --hash=sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5 \ + --hash=sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd \ + --hash=sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089 \ + --hash=sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107 \ + --hash=sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6 \ + --hash=sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60 \ + --hash=sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf \ + --hash=sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5 \ + --hash=sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08 \ + --hash=sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05 \ + --hash=sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2 \ + --hash=sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e \ + --hash=sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c \ + --hash=sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17 \ + --hash=sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62 \ + --hash=sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23 \ + --hash=sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be \ + --hash=sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067 \ + --hash=sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02 \ + --hash=sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f \ + --hash=sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235 \ + --hash=sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840 \ + --hash=sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5 \ + --hash=sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807 \ + --hash=sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16 \ + --hash=sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c \ + --hash=sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864 \ + --hash=sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e \ + --hash=sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a \ + --hash=sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35 \ + --hash=sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737 \ + --hash=sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a \ + --hash=sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3 \ + --hash=sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52 \ + --hash=sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05 \ + --hash=sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31 \ + --hash=sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89 \ + --hash=sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de \ + --hash=sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6 \ + --hash=sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36 \ + --hash=sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c \ + --hash=sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154 \ + --hash=sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb \ + --hash=sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e \ + --hash=sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd \ + --hash=sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3 \ + --hash=sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f \ + --hash=sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78 \ + --hash=sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960 \ + --hash=sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618 \ + --hash=sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08 \ + --hash=sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4 \ + --hash=sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c \ + --hash=sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c \ + --hash=sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330 \ + --hash=sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8 \ + --hash=sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792 \ + --hash=sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025 \ + --hash=sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9 \ + --hash=sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f \ + --hash=sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01 \ + --hash=sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337 \ + --hash=sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4 \ + --hash=sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f \ + --hash=sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd \ + --hash=sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51 \ + --hash=sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab \ + --hash=sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc \ + --hash=sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676 \ + --hash=sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381 \ + --hash=sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed \ + --hash=sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb \ + --hash=sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967 \ + --hash=sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073 \ + --hash=sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae \ + --hash=sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c \ + --hash=sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206 \ + --hash=sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b # via # -c lock/requirements-dev.txt # pydantic @@ -1085,9 +1098,9 @@ pyshexc==0.9.1 \ # -c lock/requirements-dev.txt # linkml # pyshex -pytest==8.3.3 \ - --hash=sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181 \ - --hash=sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2 +pytest==8.3.4 \ + --hash=sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6 \ + --hash=sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761 # via # -c lock/requirements-dev.txt # pytest-logging @@ -1242,97 +1255,110 @@ rich==13.9.4 \ # via # -c lock/requirements-dev.txt # typer -rpds-py==0.21.0 \ - --hash=sha256:031819f906bb146561af051c7cef4ba2003d28cff07efacef59da973ff7969ba \ - --hash=sha256:0626238a43152918f9e72ede9a3b6ccc9e299adc8ade0d67c5e142d564c9a83d \ - --hash=sha256:085ed25baac88953d4283e5b5bd094b155075bb40d07c29c4f073e10623f9f2e \ - --hash=sha256:0a9e0759e7be10109645a9fddaaad0619d58c9bf30a3f248a2ea57a7c417173a \ - --hash=sha256:0c025820b78817db6a76413fff6866790786c38f95ea3f3d3c93dbb73b632202 \ - --hash=sha256:1ff2eba7f6c0cb523d7e9cff0903f2fe1feff8f0b2ceb6bd71c0e20a4dcee271 \ - --hash=sha256:20cc1ed0bcc86d8e1a7e968cce15be45178fd16e2ff656a243145e0b439bd250 \ - --hash=sha256:241e6c125568493f553c3d0fdbb38c74babf54b45cef86439d4cd97ff8feb34d \ - --hash=sha256:2c51d99c30091f72a3c5d126fad26236c3f75716b8b5e5cf8effb18889ced928 \ - --hash=sha256:2d6129137f43f7fa02d41542ffff4871d4aefa724a5fe38e2c31a4e0fd343fb0 \ - --hash=sha256:30b912c965b2aa76ba5168fd610087bad7fcde47f0a8367ee8f1876086ee6d1d \ - --hash=sha256:30bdc973f10d28e0337f71d202ff29345320f8bc49a31c90e6c257e1ccef4333 \ - --hash=sha256:320c808df533695326610a1b6a0a6e98f033e49de55d7dc36a13c8a30cfa756e \ - --hash=sha256:32eb88c30b6a4f0605508023b7141d043a79b14acb3b969aa0b4f99b25bc7d4a \ - --hash=sha256:3b766a9f57663396e4f34f5140b3595b233a7b146e94777b97a8413a1da1be18 \ - --hash=sha256:3b929c2bb6e29ab31f12a1117c39f7e6d6450419ab7464a4ea9b0b417174f044 \ - --hash=sha256:3e30a69a706e8ea20444b98a49f386c17b26f860aa9245329bab0851ed100677 \ - --hash=sha256:3e53861b29a13d5b70116ea4230b5f0f3547b2c222c5daa090eb7c9c82d7f664 \ - --hash=sha256:40c91c6e34cf016fa8e6b59d75e3dbe354830777fcfd74c58b279dceb7975b75 \ - --hash=sha256:4991ca61656e3160cdaca4851151fd3f4a92e9eba5c7a530ab030d6aee96ec89 \ - --hash=sha256:4ab2c2a26d2f69cdf833174f4d9d86118edc781ad9a8fa13970b527bf8236027 \ - --hash=sha256:4e8921a259f54bfbc755c5bbd60c82bb2339ae0324163f32868f63f0ebb873d9 \ - --hash=sha256:4eb2de8a147ffe0626bfdc275fc6563aa7bf4b6db59cf0d44f0ccd6ca625a24e \ - --hash=sha256:5145282a7cd2ac16ea0dc46b82167754d5e103a05614b724457cffe614f25bd8 \ - --hash=sha256:520ed8b99b0bf86a176271f6fe23024323862ac674b1ce5b02a72bfeff3fff44 \ - --hash=sha256:52c041802a6efa625ea18027a0723676a778869481d16803481ef6cc02ea8cb3 \ - --hash=sha256:5555db3e618a77034954b9dc547eae94166391a98eb867905ec8fcbce1308d95 \ - --hash=sha256:58a0e345be4b18e6b8501d3b0aa540dad90caeed814c515e5206bb2ec26736fd \ - --hash=sha256:590ef88db231c9c1eece44dcfefd7515d8bf0d986d64d0caf06a81998a9e8cab \ - --hash=sha256:5afb5efde74c54724e1a01118c6e5c15e54e642c42a1ba588ab1f03544ac8c7a \ - --hash=sha256:688c93b77e468d72579351a84b95f976bd7b3e84aa6686be6497045ba84be560 \ - --hash=sha256:6b4ef7725386dc0762857097f6b7266a6cdd62bfd209664da6712cb26acef035 \ - --hash=sha256:6bc0e697d4d79ab1aacbf20ee5f0df80359ecf55db33ff41481cf3e24f206919 \ - --hash=sha256:6dcc4949be728ede49e6244eabd04064336012b37f5c2200e8ec8eb2988b209c \ - --hash=sha256:6f54e7106f0001244a5f4cf810ba8d3f9c542e2730821b16e969d6887b664266 \ - --hash=sha256:808f1ac7cf3b44f81c9475475ceb221f982ef548e44e024ad5f9e7060649540e \ - --hash=sha256:8404b3717da03cbf773a1d275d01fec84ea007754ed380f63dfc24fb76ce4592 \ - --hash=sha256:878f6fea96621fda5303a2867887686d7a198d9e0f8a40be100a63f5d60c88c9 \ - --hash=sha256:8a7ff941004d74d55a47f916afc38494bd1cfd4b53c482b77c03147c91ac0ac3 \ - --hash=sha256:95a5bad1ac8a5c77b4e658671642e4af3707f095d2b78a1fdd08af0dfb647624 \ - --hash=sha256:97ef67d9bbc3e15584c2f3c74bcf064af36336c10d2e21a2131e123ce0f924c9 \ - --hash=sha256:98486337f7b4f3c324ab402e83453e25bb844f44418c066623db88e4c56b7c7b \ - --hash=sha256:98e4fe5db40db87ce1c65031463a760ec7906ab230ad2249b4572c2fc3ef1f9f \ - --hash=sha256:998a8080c4495e4f72132f3d66ff91f5997d799e86cec6ee05342f8f3cda7dca \ - --hash=sha256:9afe42102b40007f588666bc7de82451e10c6788f6f70984629db193849dced1 \ - --hash=sha256:9e20da3957bdf7824afdd4b6eeb29510e83e026473e04952dca565170cd1ecc8 \ - --hash=sha256:a017f813f24b9df929674d0332a374d40d7f0162b326562daae8066b502d0590 \ - --hash=sha256:a429b99337062877d7875e4ff1a51fe788424d522bd64a8c0a20ef3021fdb6ed \ - --hash=sha256:a58ce66847711c4aa2ecfcfaff04cb0327f907fead8945ffc47d9407f41ff952 \ - --hash=sha256:a78d8b634c9df7f8d175451cfeac3810a702ccb85f98ec95797fa98b942cea11 \ - --hash=sha256:a89a8ce9e4e75aeb7fa5d8ad0f3fecdee813802592f4f46a15754dcb2fd6b061 \ - --hash=sha256:a8eeec67590e94189f434c6d11c426892e396ae59e4801d17a93ac96b8c02a6c \ - --hash=sha256:aaeb25ccfb9b9014a10eaf70904ebf3f79faaa8e60e99e19eef9f478651b9b74 \ - --hash=sha256:ad116dda078d0bc4886cb7840e19811562acdc7a8e296ea6ec37e70326c1b41c \ - --hash=sha256:af04ac89c738e0f0f1b913918024c3eab6e3ace989518ea838807177d38a2e94 \ - --hash=sha256:af4a644bf890f56e41e74be7d34e9511e4954894d544ec6b8efe1e21a1a8da6c \ - --hash=sha256:b21747f79f360e790525e6f6438c7569ddbfb1b3197b9e65043f25c3c9b489d8 \ - --hash=sha256:b229ce052ddf1a01c67d68166c19cb004fb3612424921b81c46e7ea7ccf7c3bf \ - --hash=sha256:b4de1da871b5c0fd5537b26a6fc6814c3cc05cabe0c941db6e9044ffbb12f04a \ - --hash=sha256:b80b4690bbff51a034bfde9c9f6bf9357f0a8c61f548942b80f7b66356508bf5 \ - --hash=sha256:b876f2bc27ab5954e2fd88890c071bd0ed18b9c50f6ec3de3c50a5ece612f7a6 \ - --hash=sha256:b8f107395f2f1d151181880b69a2869c69e87ec079c49c0016ab96860b6acbe5 \ - --hash=sha256:b9b76e2afd585803c53c5b29e992ecd183f68285b62fe2668383a18e74abe7a3 \ - --hash=sha256:c2b2f71c6ad6c2e4fc9ed9401080badd1469fa9889657ec3abea42a3d6b2e1ed \ - --hash=sha256:c3761f62fcfccf0864cc4665b6e7c3f0c626f0380b41b8bd1ce322103fa3ef87 \ - --hash=sha256:c38dbf31c57032667dd5a2f0568ccde66e868e8f78d5a0d27dcc56d70f3fcd3b \ - --hash=sha256:ca9989d5d9b1b300bc18e1801c67b9f6d2c66b8fd9621b36072ed1df2c977f72 \ - --hash=sha256:cbd7504a10b0955ea287114f003b7ad62330c9e65ba012c6223dba646f6ffd05 \ - --hash=sha256:d167e4dbbdac48bd58893c7e446684ad5d425b407f9336e04ab52e8b9194e2ed \ - --hash=sha256:d2132377f9deef0c4db89e65e8bb28644ff75a18df5293e132a8d67748397b9f \ - --hash=sha256:da52d62a96e61c1c444f3998c434e8b263c384f6d68aca8274d2e08d1906325c \ - --hash=sha256:daa8efac2a1273eed2354397a51216ae1e198ecbce9036fba4e7610b308b6153 \ - --hash=sha256:dc5695c321e518d9f03b7ea6abb5ea3af4567766f9852ad1560f501b17588c7b \ - --hash=sha256:de552f4a1916e520f2703ec474d2b4d3f86d41f353e7680b597512ffe7eac5d0 \ - --hash=sha256:de609a6f1b682f70bb7163da745ee815d8f230d97276db049ab447767466a09d \ - --hash=sha256:e12bb09678f38b7597b8346983d2323a6482dcd59e423d9448108c1be37cac9d \ - --hash=sha256:e168afe6bf6ab7ab46c8c375606298784ecbe3ba31c0980b7dcbb9631dcba97e \ - --hash=sha256:e78868e98f34f34a88e23ee9ccaeeec460e4eaf6db16d51d7a9b883e5e785a5e \ - --hash=sha256:e860f065cc4ea6f256d6f411aba4b1251255366e48e972f8a347cf88077b24fd \ - --hash=sha256:ea3a6ac4d74820c98fcc9da4a57847ad2cc36475a8bd9683f32ab6d47a2bd682 \ - --hash=sha256:ebf64e281a06c904a7636781d2e973d1f0926a5b8b480ac658dc0f556e7779f4 \ - --hash=sha256:ed6378c9d66d0de903763e7706383d60c33829581f0adff47b6535f1802fa6db \ - --hash=sha256:ee1e4fc267b437bb89990b2f2abf6c25765b89b72dd4a11e21934df449e0c976 \ - --hash=sha256:ee4eafd77cc98d355a0d02f263efc0d3ae3ce4a7c24740010a8b4012bbb24937 \ - --hash=sha256:efec946f331349dfc4ae9d0e034c263ddde19414fe5128580f512619abed05f1 \ - --hash=sha256:f414da5c51bf350e4b7960644617c130140423882305f7574b6cf65a3081cecb \ - --hash=sha256:f71009b0d5e94c0e86533c0b27ed7cacc1239cb51c178fd239c3cfefefb0400a \ - --hash=sha256:f983e4c2f603c95dde63df633eec42955508eefd8d0f0e6d236d31a044c882d7 \ - --hash=sha256:faa5e8496c530f9c71f2b4e1c49758b06e5f4055e17144906245c99fa6d45356 \ - --hash=sha256:fed5dfefdf384d6fe975cc026886aece4f292feaf69d0eeb716cfd3c5a4dd8be +rpds-py==0.22.3 \ + --hash=sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518 \ + --hash=sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059 \ + --hash=sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61 \ + --hash=sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5 \ + --hash=sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9 \ + --hash=sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543 \ + --hash=sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2 \ + --hash=sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a \ + --hash=sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d \ + --hash=sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56 \ + --hash=sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d \ + --hash=sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd \ + --hash=sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b \ + --hash=sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4 \ + --hash=sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99 \ + --hash=sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d \ + --hash=sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd \ + --hash=sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe \ + --hash=sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1 \ + --hash=sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e \ + --hash=sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f \ + --hash=sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3 \ + --hash=sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca \ + --hash=sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d \ + --hash=sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e \ + --hash=sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc \ + --hash=sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea \ + --hash=sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38 \ + --hash=sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b \ + --hash=sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c \ + --hash=sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff \ + --hash=sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723 \ + --hash=sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e \ + --hash=sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493 \ + --hash=sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6 \ + --hash=sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83 \ + --hash=sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091 \ + --hash=sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1 \ + --hash=sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627 \ + --hash=sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1 \ + --hash=sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728 \ + --hash=sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16 \ + --hash=sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c \ + --hash=sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45 \ + --hash=sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7 \ + --hash=sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a \ + --hash=sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730 \ + --hash=sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967 \ + --hash=sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25 \ + --hash=sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24 \ + --hash=sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055 \ + --hash=sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d \ + --hash=sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0 \ + --hash=sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e \ + --hash=sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7 \ + --hash=sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c \ + --hash=sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f \ + --hash=sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd \ + --hash=sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652 \ + --hash=sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8 \ + --hash=sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11 \ + --hash=sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333 \ + --hash=sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96 \ + --hash=sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64 \ + --hash=sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b \ + --hash=sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e \ + --hash=sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c \ + --hash=sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9 \ + --hash=sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec \ + --hash=sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb \ + --hash=sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37 \ + --hash=sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad \ + --hash=sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9 \ + --hash=sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c \ + --hash=sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf \ + --hash=sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4 \ + --hash=sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f \ + --hash=sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d \ + --hash=sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09 \ + --hash=sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d \ + --hash=sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566 \ + --hash=sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74 \ + --hash=sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338 \ + --hash=sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15 \ + --hash=sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c \ + --hash=sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648 \ + --hash=sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84 \ + --hash=sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3 \ + --hash=sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123 \ + --hash=sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520 \ + --hash=sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831 \ + --hash=sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e \ + --hash=sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf \ + --hash=sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b \ + --hash=sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2 \ + --hash=sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3 \ + --hash=sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130 \ + --hash=sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b \ + --hash=sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de \ + --hash=sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5 \ + --hash=sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d \ + --hash=sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00 \ + --hash=sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e # via # -c lock/requirements-dev.txt # jsonschema @@ -1388,9 +1414,9 @@ ruamel-yaml-clib==0.2.12 \ # via # -c lock/requirements-dev.txt # ruamel-yaml -s3transfer==0.10.3 \ - --hash=sha256:263ed587a5803c6c708d3ce44dc4dfedaab4c1a32e8329bab818933d79ddcf5d \ - --hash=sha256:4f50ed74ab84d474ce614475e0b8d5047ff080810aac5d01ea25231cfc944b0c +s3transfer==0.10.4 \ + --hash=sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e \ + --hash=sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7 # via # -c lock/requirements-dev.txt # boto3 @@ -1413,9 +1439,9 @@ shexjsg==0.8.2 \ # -c lock/requirements-dev.txt # pyshex # pyshexc -six==1.16.0 \ - --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ - --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 +six==1.17.0 \ + --hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \ + --hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81 # via # -c lock/requirements-dev.txt # python-dateutil @@ -1506,9 +1532,9 @@ sqlalchemy==2.0.36 \ # via # -c lock/requirements-dev.txt # linkml -starlette==0.41.2 \ - --hash=sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62 \ - --hash=sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d +starlette==0.41.3 \ + --hash=sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835 \ + --hash=sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7 # via # -c lock/requirements-dev.txt # fastapi @@ -1523,9 +1549,9 @@ tenacity==9.0.0 \ # via # -c lock/requirements-dev.txt # ghga-datasteward-kit (pyproject.toml) -typer==0.13.0 \ - --hash=sha256:d85fe0b777b2517cc99c8055ed735452f2659cd45e451507c76f48ce5c1d00e2 \ - --hash=sha256:f1c7198347939361eec90139ffa0fd8b3df3a2259d5852a0f7400e476d95985c +typer==0.15.1 \ + --hash=sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847 \ + --hash=sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a # via # -c lock/requirements-dev.txt # ghga-transpiler @@ -1643,90 +1669,78 @@ watchdog==6.0.0 \ # via # -c lock/requirements-dev.txt # linkml -watchfiles==0.24.0 \ - --hash=sha256:01550ccf1d0aed6ea375ef259706af76ad009ef5b0203a3a4cce0f6024f9b68a \ - --hash=sha256:01def80eb62bd5db99a798d5e1f5f940ca0a05986dcfae21d833af7a46f7ee22 \ - --hash=sha256:07cdef0c84c03375f4e24642ef8d8178e533596b229d32d2bbd69e5128ede02a \ - --hash=sha256:083dc77dbdeef09fa44bb0f4d1df571d2e12d8a8f985dccde71ac3ac9ac067a0 \ - --hash=sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827 \ - --hash=sha256:21ab23fdc1208086d99ad3f69c231ba265628014d4aed31d4e8746bd59e88cd1 \ - --hash=sha256:2dadf8a8014fde6addfd3c379e6ed1a981c8f0a48292d662e27cabfe4239c83c \ - --hash=sha256:2e28d91ef48eab0afb939fa446d8ebe77e2f7593f5f463fd2bb2b14132f95b6e \ - --hash=sha256:2efec17819b0046dde35d13fb8ac7a3ad877af41ae4640f4109d9154ed30a188 \ - --hash=sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b \ - --hash=sha256:316449aefacf40147a9efaf3bd7c9bdd35aaba9ac5d708bd1eb5763c9a02bef5 \ - --hash=sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90 \ - --hash=sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef \ - --hash=sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b \ - --hash=sha256:3770e260b18e7f4e576edca4c0a639f704088602e0bc921c5c2e721e3acb8d15 \ - --hash=sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48 \ - --hash=sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e \ - --hash=sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df \ - --hash=sha256:449f43f49c8ddca87c6b3980c9284cab6bd1f5c9d9a2b00012adaaccd5e7decd \ - --hash=sha256:4933a508d2f78099162da473841c652ad0de892719043d3f07cc83b33dfd9d91 \ - --hash=sha256:49d617df841a63b4445790a254013aea2120357ccacbed00253f9c2b5dc24e2d \ - --hash=sha256:49fb58bcaa343fedc6a9e91f90195b20ccb3135447dc9e4e2570c3a39565853e \ - --hash=sha256:4a7fa2bc0efef3e209a8199fd111b8969fe9db9c711acc46636686331eda7dd4 \ - --hash=sha256:4abf4ad269856618f82dee296ac66b0cd1d71450fc3c98532d93798e73399b7a \ - --hash=sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370 \ - --hash=sha256:4d28cea3c976499475f5b7a2fec6b3a36208656963c1a856d328aeae056fc5c1 \ - --hash=sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea \ - --hash=sha256:54ca90a9ae6597ae6dc00e7ed0a040ef723f84ec517d3e7ce13e63e4bc82fa04 \ - --hash=sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896 \ - --hash=sha256:5c51749f3e4e269231510da426ce4a44beb98db2dce9097225c338f815b05d4f \ - --hash=sha256:632676574429bee8c26be8af52af20e0c718cc7f5f67f3fb658c71928ccd4f7f \ - --hash=sha256:6509ed3f467b79d95fc62a98229f79b1a60d1b93f101e1c61d10c95a46a84f43 \ - --hash=sha256:6bdcfa3cd6fdbdd1a068a52820f46a815401cbc2cb187dd006cb076675e7b735 \ - --hash=sha256:7138eff8baa883aeaa074359daabb8b6c1e73ffe69d5accdc907d62e50b1c0da \ - --hash=sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a \ - --hash=sha256:73bde715f940bea845a95247ea3e5eb17769ba1010efdc938ffcb967c634fa61 \ - --hash=sha256:78470906a6be5199524641f538bd2c56bb809cd4bf29a566a75051610bc982c3 \ - --hash=sha256:7ae3e208b31be8ce7f4c2c0034f33406dd24fbce3467f77223d10cd86778471c \ - --hash=sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f \ - --hash=sha256:82ae557a8c037c42a6ef26c494d0631cacca040934b101d001100ed93d43f361 \ - --hash=sha256:82b2509f08761f29a0fdad35f7e1638b8ab1adfa2666d41b794090361fb8b855 \ - --hash=sha256:8360f7314a070c30e4c976b183d1d8d1585a4a50c5cb603f431cebcbb4f66327 \ - --hash=sha256:85d5f0c7771dcc7a26c7a27145059b6bb0ce06e4e751ed76cdf123d7039b60b5 \ - --hash=sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab \ - --hash=sha256:9301c689051a4857d5b10777da23fafb8e8e921bcf3abe6448a058d27fb67633 \ - --hash=sha256:951088d12d339690a92cef2ec5d3cfd957692834c72ffd570ea76a6790222777 \ - --hash=sha256:95cf3b95ea665ab03f5a54765fa41abf0529dbaf372c3b83d91ad2cfa695779b \ - --hash=sha256:96619302d4374de5e2345b2b622dc481257a99431277662c30f606f3e22f42be \ - --hash=sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f \ - --hash=sha256:9a60e2bf9dc6afe7f743e7c9b149d1fdd6dbf35153c78fe3a14ae1a9aee3d98b \ - --hash=sha256:9f895d785eb6164678ff4bb5cc60c5996b3ee6df3edb28dcdeba86a13ea0465e \ - --hash=sha256:a2a9891723a735d3e2540651184be6fd5b96880c08ffe1a98bae5017e65b544b \ - --hash=sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366 \ - --hash=sha256:aa0fd7248cf533c259e59dc593a60973a73e881162b1a2f73360547132742823 \ - --hash=sha256:acbfa31e315a8f14fe33e3542cbcafc55703b8f5dcbb7c1eecd30f141df50db3 \ - --hash=sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1 \ - --hash=sha256:b3ef2c69c655db63deb96b3c3e587084612f9b1fa983df5e0c3379d41307467f \ - --hash=sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418 \ - --hash=sha256:b665caeeda58625c3946ad7308fbd88a086ee51ccb706307e5b1fa91556ac886 \ - --hash=sha256:b74fdffce9dfcf2dc296dec8743e5b0332d15df19ae464f0e249aa871fc1c571 \ - --hash=sha256:b995bfa6bf01a9e09b884077a6d37070464b529d8682d7691c2d3b540d357a0c \ - --hash=sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94 \ - --hash=sha256:bdcd5538e27f188dd3c804b4a8d5f52a7fc7f87e7fd6b374b8e36a4ca03db428 \ - --hash=sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234 \ - --hash=sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6 \ - --hash=sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968 \ - --hash=sha256:d337193bbf3e45171c8025e291530fb7548a93c45253897cd764a6a71c937ed9 \ - --hash=sha256:d3dcb774e3568477275cc76554b5a565024b8ba3a0322f77c246bc7111c5bb9c \ - --hash=sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e \ - --hash=sha256:d7a2e3b7f5703ffbd500dabdefcbc9eafeff4b9444bbdd5d83d79eedf8428fab \ - --hash=sha256:d831ee0a50946d24a53821819b2327d5751b0c938b12c0653ea5be7dea9c82ec \ - --hash=sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444 \ - --hash=sha256:e5171ef898299c657685306d8e1478a45e9303ddcd8ac5fed5bd52ad4ae0b69b \ - --hash=sha256:e94e98c7cb94cfa6e071d401ea3342767f28eb5a06a58fafdc0d2a4974f4f35c \ - --hash=sha256:ec39698c45b11d9694a1b635a70946a5bad066b593af863460a8e600f0dff1ca \ - --hash=sha256:ed9aba6e01ff6f2e8285e5aa4154e2970068fe0fc0998c4380d0e6278222269b \ - --hash=sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18 \ - --hash=sha256:ee82c98bed9d97cd2f53bdb035e619309a098ea53ce525833e26b93f673bc318 \ - --hash=sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07 \ - --hash=sha256:f7d9b87c4c55e3ea8881dfcbf6d61ea6775fffed1fedffaa60bd047d3c08c430 \ - --hash=sha256:f83df90191d67af5a831da3a33dd7628b02a95450e168785586ed51e6d28943c \ - --hash=sha256:fca9433a45f18b7c779d2bae7beeec4f740d28b788b117a48368d95a3233ed83 \ - --hash=sha256:fd92bbaa2ecdb7864b7600dcdb6f2f1db6e0346ed425fbd01085be04c63f0b05 +watchfiles==1.0.0 \ + --hash=sha256:06d828fe2adc4ac8a64b875ca908b892a3603d596d43e18f7948f3fef5fc671c \ + --hash=sha256:074c7618cd6c807dc4eaa0982b4a9d3f8051cd0b72793511848fd64630174b17 \ + --hash=sha256:09551237645d6bff3972592f2aa5424df9290e7a2e15d63c5f47c48cde585935 \ + --hash=sha256:0fc3bf0effa2d8075b70badfdd7fb839d7aa9cea650d17886982840d71fdeabf \ + --hash=sha256:12ab123135b2f42517f04e720526d41448667ae8249e651385afb5cda31fedc0 \ + --hash=sha256:13a4f9ee0cd25682679eea5c14fc629e2eaa79aab74d963bc4e21f43b8ea1877 \ + --hash=sha256:1d19df28f99d6a81730658fbeb3ade8565ff687f95acb59665f11502b441be5f \ + --hash=sha256:1e176b6b4119b3f369b2b4e003d53a226295ee862c0962e3afd5a1c15680b4e3 \ + --hash=sha256:1ee5edc939f53466b329bbf2e58333a5461e6c7b50c980fa6117439e2c18b42d \ + --hash=sha256:1f73c2147a453315d672c1ad907abe6d40324e34a185b51e15624bc793f93cc6 \ + --hash=sha256:1ff236d7a3f4b0a42f699a22fc374ba526bc55048a70cbb299661158e1bb5e1f \ + --hash=sha256:245fab124b9faf58430da547512d91734858df13f2ddd48ecfa5e493455ffccb \ + --hash=sha256:28babb38cf2da8e170b706c4b84aa7e4528a6fa4f3ee55d7a0866456a1662041 \ + --hash=sha256:28fb64b5843d94e2c2483f7b024a1280662a44409bedee8f2f51439767e2d107 \ + --hash=sha256:29cf884ad4285d23453c702ed03d689f9c0e865e3c85d20846d800d4787de00f \ + --hash=sha256:2a825ba4b32c214e3855b536eb1a1f7b006511d8e64b8215aac06eb680642d84 \ + --hash=sha256:2ac778a460ea22d63c7e6fb0bc0f5b16780ff0b128f7f06e57aaec63bd339285 \ + --hash=sha256:2c2696611182c85eb0e755b62b456f48debff484b7306b56f05478b843ca8ece \ + --hash=sha256:2d9c0518fabf4a3f373b0a94bb9e4ea7a1df18dec45e26a4d182aa8918dee855 \ + --hash=sha256:2de52b499e1ab037f1a87cb8ebcb04a819bf087b1015a4cf6dcf8af3c2a2613e \ + --hash=sha256:37566c844c9ce3b5deb964fe1a23378e575e74b114618d211fbda8f59d7b5dab \ + --hash=sha256:3d94fd83ed54266d789f287472269c0def9120a2022674990bd24ad989ebd7a0 \ + --hash=sha256:48051d1c504448b2fcda71c5e6e3610ae45de6a0b8f5a43b961f250be4bdf5a8 \ + --hash=sha256:487d15927f1b0bd24e7df921913399bb1ab94424c386bea8b267754d698f8f0e \ + --hash=sha256:4a3b33c3aefe9067ebd87846806cd5fc0b017ab70d628aaff077ab9abf4d06b3 \ + --hash=sha256:4ff9c7e84e8b644a8f985c42bcc81457240316f900fc72769aaedec9d088055a \ + --hash=sha256:533a7cbfe700e09780bb31c06189e39c65f06c7f447326fee707fd02f9a6e945 \ + --hash=sha256:53ae447f06f8f29f5ab40140f19abdab822387a7c426a369eb42184b021e97eb \ + --hash=sha256:550109001920a993a4383b57229c717fa73627d2a4e8fcb7ed33c7f1cddb0c85 \ + --hash=sha256:5bbd0311588c2de7f9ea5cf3922ccacfd0ec0c1922870a2be503cc7df1ca8be7 \ + --hash=sha256:5dccfc70480087567720e4e36ec381bba1ed68d7e5f368fe40c93b3b1eba0105 \ + --hash=sha256:5f75cd42e7e2254117cf37ff0e68c5b3f36c14543756b2da621408349bd9ca7c \ + --hash=sha256:648e2b6db53eca6ef31245805cd528a16f56fa4cc15aeec97795eaf713c11435 \ + --hash=sha256:774ef36b16b7198669ce655d4f75b4c3d370e7f1cbdfb997fb10ee98717e2058 \ + --hash=sha256:8a2127cd68950787ee36753e6d401c8ea368f73beaeb8e54df5516a06d1ecd82 \ + --hash=sha256:90004553be36427c3d06ec75b804233f8f816374165d5225b93abd94ba6e7234 \ + --hash=sha256:905f69aad276639eff3893759a07d44ea99560e67a1cf46ff389cd62f88872a2 \ + --hash=sha256:9122b8fdadc5b341315d255ab51d04893f417df4e6c1743b0aac8bf34e96e025 \ + --hash=sha256:9272fdbc0e9870dac3b505bce1466d386b4d8d6d2bacf405e603108d50446940 \ + --hash=sha256:936f362e7ff28311b16f0b97ec51e8f2cc451763a3264640c6ed40fb252d1ee4 \ + --hash=sha256:947ccba18a38b85c366dafeac8df2f6176342d5992ca240a9d62588b214d731f \ + --hash=sha256:95dc785bc284552d044e561b8f4fe26d01ab5ca40d35852a6572d542adfeb4bc \ + --hash=sha256:95de85c254f7fe8cbdf104731f7f87f7f73ae229493bebca3722583160e6b152 \ + --hash=sha256:9b4fb98100267e6a5ebaff6aaa5d20aea20240584647470be39fe4823012ac96 \ + --hash=sha256:9c01446626574561756067f00b37e6b09c8622b0fc1e9fdbc7cbcea328d4e514 \ + --hash=sha256:9c9a8d8fd97defe935ef8dd53d562e68942ad65067cd1c54d6ed8a088b1d931d \ + --hash=sha256:9e1d9284cc84de7855fcf83472e51d32daf6f6cecd094160192628bc3fee1b78 \ + --hash=sha256:a0abf173975eb9dd17bb14c191ee79999e650997cc644562f91df06060610e62 \ + --hash=sha256:a2218e78e2c6c07b1634a550095ac2a429026b2d5cbcd49a594f893f2bb8c936 \ + --hash=sha256:a5a7a06cfc65e34fd0a765a7623c5ba14707a0870703888e51d3d67107589817 \ + --hash=sha256:b2bca898c1dc073912d3db7fa6926cc08be9575add9e84872de2c99c688bac4e \ + --hash=sha256:b46e15c34d4e401e976d6949ad3a74d244600d5c4b88c827a3fdf18691a46359 \ + --hash=sha256:b551c465a59596f3d08170bd7e1c532c7260dd90ed8135778038e13c5d48aa81 \ + --hash=sha256:b555a93c15bd2c71081922be746291d776d47521a00703163e5fbe6d2a402399 \ + --hash=sha256:bc338ce9f8846543d428260fa0f9a716626963148edc937d71055d01d81e1525 \ + --hash=sha256:bedf84835069f51c7b026b3ca04e2e747ea8ed0a77c72006172c72d28c9f69fc \ + --hash=sha256:c3d258d78341d5d54c0c804a5b7faa66cd30ba50b2756a7161db07ce15363b8d \ + --hash=sha256:c83a6d33a9eda0af6a7470240d1af487807adc269704fe76a4972dd982d16236 \ + --hash=sha256:c9a13ac46b545a7d0d50f7641eefe47d1597e7d1783a5d89e09d080e6dff44b0 \ + --hash=sha256:cf517701a4a872417f4e02a136e929537743461f9ec6cdb8184d9a04f4843545 \ + --hash=sha256:d2b39aa8edd9e5f56f99a2a2740a251dc58515398e9ed5a4b3e5ff2827060755 \ + --hash=sha256:d3572d4c34c4e9c33d25b3da47d9570d5122f8433b9ac6519dca49c2740d23cd \ + --hash=sha256:d562a6114ddafb09c33246c6ace7effa71ca4b6a2324a47f4b09b6445ea78941 \ + --hash=sha256:e1ed613ee107269f66c2df631ec0fc8efddacface85314d392a4131abe299f00 \ + --hash=sha256:e3750434c83b61abb3163b49c64b04180b85b4dabb29a294513faec57f2ffdb7 \ + --hash=sha256:eba98901a2eab909dbd79681190b9049acc650f6111fde1845484a4450761e98 \ + --hash=sha256:f159ac795785cde4899e0afa539f4c723fb5dd336ce5605bc909d34edd00b79b \ + --hash=sha256:f8c4f3a1210ed099a99e6a710df4ff2f8069411059ffe30fa5f9467ebed1256b \ + --hash=sha256:fa13d604fcb9417ae5f2e3de676e66aa97427d888e83662ad205bed35a313176 \ + --hash=sha256:fbd0ab7a9943bbddb87cbc2bf2f09317e74c77dc55b1f5657f81d04666c25269 \ + --hash=sha256:ffd98a299b0a74d1b704ef0ed959efb753e656a4e0425c14e46ae4c3cbdd2919 # via # -c lock/requirements-dev.txt # uvicorn @@ -1809,77 +1823,72 @@ websockets==14.1 \ # via # -c lock/requirements-dev.txt # uvicorn -wrapt==1.16.0 \ - --hash=sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc \ - --hash=sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81 \ - --hash=sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09 \ - --hash=sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e \ - --hash=sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca \ - --hash=sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0 \ - --hash=sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb \ - --hash=sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487 \ - --hash=sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40 \ - --hash=sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c \ - --hash=sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060 \ - --hash=sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202 \ - --hash=sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41 \ - --hash=sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9 \ - --hash=sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b \ - --hash=sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664 \ - --hash=sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d \ - --hash=sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362 \ - --hash=sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00 \ - --hash=sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc \ - --hash=sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1 \ - --hash=sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267 \ - --hash=sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956 \ - --hash=sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966 \ - --hash=sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1 \ - --hash=sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228 \ - --hash=sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72 \ - --hash=sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d \ - --hash=sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292 \ - --hash=sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0 \ - --hash=sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0 \ - --hash=sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36 \ - --hash=sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c \ - --hash=sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5 \ - --hash=sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f \ - --hash=sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73 \ - --hash=sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b \ - --hash=sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2 \ - --hash=sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593 \ - --hash=sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39 \ - --hash=sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389 \ - --hash=sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf \ - --hash=sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf \ - --hash=sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89 \ - --hash=sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c \ - --hash=sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c \ - --hash=sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f \ - --hash=sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440 \ - --hash=sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465 \ - --hash=sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136 \ - --hash=sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b \ - --hash=sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8 \ - --hash=sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3 \ - --hash=sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8 \ - --hash=sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6 \ - --hash=sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e \ - --hash=sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f \ - --hash=sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c \ - --hash=sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e \ - --hash=sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8 \ - --hash=sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2 \ - --hash=sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020 \ - --hash=sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35 \ - --hash=sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d \ - --hash=sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3 \ - --hash=sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537 \ - --hash=sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809 \ - --hash=sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d \ - --hash=sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a \ - --hash=sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4 +wrapt==1.17.0 \ + --hash=sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d \ + --hash=sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301 \ + --hash=sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635 \ + --hash=sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a \ + --hash=sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed \ + --hash=sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721 \ + --hash=sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801 \ + --hash=sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b \ + --hash=sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1 \ + --hash=sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88 \ + --hash=sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8 \ + --hash=sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0 \ + --hash=sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f \ + --hash=sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578 \ + --hash=sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7 \ + --hash=sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045 \ + --hash=sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada \ + --hash=sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d \ + --hash=sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b \ + --hash=sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a \ + --hash=sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977 \ + --hash=sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea \ + --hash=sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346 \ + --hash=sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13 \ + --hash=sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22 \ + --hash=sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339 \ + --hash=sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9 \ + --hash=sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181 \ + --hash=sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c \ + --hash=sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90 \ + --hash=sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a \ + --hash=sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489 \ + --hash=sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f \ + --hash=sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504 \ + --hash=sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea \ + --hash=sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569 \ + --hash=sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4 \ + --hash=sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce \ + --hash=sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab \ + --hash=sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a \ + --hash=sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f \ + --hash=sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c \ + --hash=sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9 \ + --hash=sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf \ + --hash=sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d \ + --hash=sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627 \ + --hash=sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d \ + --hash=sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4 \ + --hash=sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c \ + --hash=sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d \ + --hash=sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad \ + --hash=sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b \ + --hash=sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33 \ + --hash=sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371 \ + --hash=sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1 \ + --hash=sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393 \ + --hash=sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106 \ + --hash=sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df \ + --hash=sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379 \ + --hash=sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451 \ + --hash=sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b \ + --hash=sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575 \ + --hash=sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed \ + --hash=sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb \ + --hash=sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838 # via # -c lock/requirements-dev.txt # deprecated diff --git a/pyproject.toml b/pyproject.toml index 577ed72..6ca4270 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ classifiers = [ "Intended Audience :: Developers", ] name = "ghga_datasteward_kit" -version = "4.4.1" +version = "4.5.0" description = "GHGA Data Steward Kit - A utils package for GHGA data stewards." dependencies = [ "crypt4gh >=1.6, <2", @@ -67,6 +67,7 @@ fixable = [ "UP", "I", "D", + "RUF022", ] ignore = [ "E111", @@ -86,6 +87,7 @@ ignore = [ "D206", "D300", "UP040", + "PLC0206", ] select = [ "C90", diff --git a/s3_upload_config.md b/s3_upload_config.md index 1aa4d61..d4378d2 100644 --- a/s3_upload_config.md +++ b/s3_upload_config.md @@ -19,6 +19,8 @@ - **`selected_storage_alias`** *(string)*: Alias of the selected storage node/location. Has to match the backend configuration and must also be present in the local storage configuration. During the later ingest phase, the alias will be validated by the File Ingest Service. +- **`client_max_parallel_transfers`** *(integer)*: Maximum number of parallel transfer tasks for file parts. Exclusive minimum: 0. Default: 10. + ## Definitions - **`S3Config`** *(object)*: S3 server specific config params. diff --git a/src/ghga_datasteward_kit/cli/file.py b/src/ghga_datasteward_kit/cli/file.py index 56b4ce6..6f279a6 100644 --- a/src/ghga_datasteward_kit/cli/file.py +++ b/src/ghga_datasteward_kit/cli/file.py @@ -24,10 +24,10 @@ log = logging.getLogger(__name__) -cli = typer.Typer() +cli = typer.Typer(no_args_is_help=True) -@cli.command() +@cli.command(no_args_is_help=True) def legacy_upload( input_path: Path = typer.Option(..., help="Local path of the input file"), alias: str = typer.Option(..., help="A human readable file alias"), @@ -37,7 +37,7 @@ def legacy_upload( s3_upload.legacy_main(input_path=input_path, alias=alias, config_path=config_path) -@cli.command() +@cli.command(no_args_is_help=True) def upload( input_path: Path = typer.Option(..., help="Local path of the input file"), alias: str = typer.Option(..., help="A human readable file alias"), @@ -47,7 +47,7 @@ def upload( s3_upload.main(input_path=input_path, alias=alias, config_path=config_path) -@cli.command() +@cli.command(no_args_is_help=True) def legacy_batch_upload( tsv: Path = typer.Option( ..., @@ -73,7 +73,7 @@ def legacy_batch_upload( ) -@cli.command() +@cli.command(no_args_is_help=True) def batch_upload( tsv: Path = typer.Option( ..., @@ -99,7 +99,7 @@ def batch_upload( ) -@cli.command() +@cli.command(no_args_is_help=True) def ingest_upload_metadata( config_path: Path = typer.Option(..., help="Path to a config YAML."), ): @@ -117,7 +117,7 @@ def ingest_upload_metadata( print("Successfully sent all file upload metadata for ingest.") -@cli.command() +@cli.command(no_args_is_help=True) def delete_file( file_id: str = typer.Option( ..., diff --git a/src/ghga_datasteward_kit/cli/main.py b/src/ghga_datasteward_kit/cli/main.py index 2200a54..f0f92e3 100644 --- a/src/ghga_datasteward_kit/cli/main.py +++ b/src/ghga_datasteward_kit/cli/main.py @@ -29,12 +29,12 @@ TokenNotExistError, ) -cli = typer.Typer() +cli = typer.Typer(no_args_is_help=True) cli.add_typer(file_cli, name="files", help="File related operations.") cli.add_typer(metadata_cli, name="metadata", help="Metadata related operations.") -@cli.command() +@cli.command(no_args_is_help=True) def generate_catalog_accessions( *, store_path: Path = typer.Option( @@ -65,7 +65,7 @@ def generate_catalog_accessions( typer.echo(accession) -@cli.command() +@cli.command(no_args_is_help=True) def load( *, config_path: Path = typer.Option( diff --git a/src/ghga_datasteward_kit/cli/metadata.py b/src/ghga_datasteward_kit/cli/metadata.py index 4cbf5a1..1eae983 100644 --- a/src/ghga_datasteward_kit/cli/metadata.py +++ b/src/ghga_datasteward_kit/cli/metadata.py @@ -23,12 +23,12 @@ from ghga_datasteward_kit import metadata -cli = typer.Typer() +cli = typer.Typer(no_args_is_help=True) -cli.command()(transpile) +cli.command(no_args_is_help=True)(transpile) -@cli.command() +@cli.command(no_args_is_help=True) def submit( submission_title: str = typer.Option(..., help="The title of the submission."), submission_description: str = typer.Option( @@ -61,7 +61,7 @@ def submit( ) -@cli.command() +@cli.command(no_args_is_help=True) def generate_artifact_models( config_path: Path = typer.Option( ..., @@ -77,7 +77,7 @@ def generate_artifact_models( metadata.generate_artifact_models_from_path(config_path=config_path) -@cli.command() +@cli.command(no_args_is_help=True) def transform( config_path: Path = typer.Option( ..., diff --git a/src/ghga_datasteward_kit/s3_upload/config.py b/src/ghga_datasteward_kit/s3_upload/config.py index e559c3e..c369c57 100644 --- a/src/ghga_datasteward_kit/s3_upload/config.py +++ b/src/ghga_datasteward_kit/s3_upload/config.py @@ -119,9 +119,6 @@ class LegacyConfig(S3ObjectStoragesConfig): default=5, description="Number of times a request should be retried on non critical errors.", ) - debug: bool = Field( - default=False, description="Enable debug functionality for upload." - ) @field_validator("output_dir") def expand_env_vars_output_dir(cls, output_dir: Path): # noqa: N805 diff --git a/src/ghga_datasteward_kit/s3_upload/downloader.py b/src/ghga_datasteward_kit/s3_upload/downloader.py deleted file mode 100644 index c062046..0000000 --- a/src/ghga_datasteward_kit/s3_upload/downloader.py +++ /dev/null @@ -1,185 +0,0 @@ -# Copyright 2021 - 2024 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln -# for the German Human Genome-Phenome Archive (GHGA) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -"""Functionality related to downloading uploaded files for validation purposes.""" - -import math -from asyncio import PriorityQueue, Semaphore, Task, create_task -from collections.abc import Coroutine -from typing import Any - -import httpx -from httpx import Response - -from ghga_datasteward_kit import models -from ghga_datasteward_kit.s3_upload.config import LegacyConfig -from ghga_datasteward_kit.s3_upload.file_decryption import Decryptor -from ghga_datasteward_kit.s3_upload.utils import ( - LOG, - StorageCleaner, - configure_retries, - get_bucket_id, - get_object_storage, - get_ranges, - httpx_client, -) - - -class DownloadTaskHandler: - """Wraps task scheduling details.""" - - def __init__(self): - self._tasks: set[Task] = set() - - async def schedule(self, fn: Coroutine[Any, Any, None]): - """Create a task and register its callback.""" - task = create_task(fn) - self._tasks.add(task) - task.add_done_callback(self._tasks.discard) - - -class ChunkedDownloader: - """Handler class dealing with download functionality""" - - def __init__( # noqa: PLR0913 - self, - config: LegacyConfig, - file_id: str, - encrypted_file_size: int, - file_secret: bytes, - part_size: int, - target_checksums: models.Checksums, - storage_cleaner: StorageCleaner, - ) -> None: - self.config = config - self.storage = get_object_storage(self.config) - self.file_id = file_id - self.file_size = encrypted_file_size - self.file_secret = file_secret - self.part_size = part_size - self.target_checksums = target_checksums - self.storage_cleaner = storage_cleaner - self.retry_handler = configure_retries(config) - self._queue: PriorityQueue[tuple[int, bytes] | tuple[int, BaseException]] = ( - PriorityQueue(config.client_max_parallel_transfers) - ) - self._semaphore = Semaphore(config.client_max_parallel_transfers) - - async def _download_part( - self, - *, - client: httpx.AsyncClient, - headers: httpx.Headers, - part_number: int, - ): - """Download single file part to queue. This should be scheduled as a asyncio.Task.""" - async with self._semaphore: - try: - url = await self.storage.get_object_download_url( - bucket_id=get_bucket_id(self.config), - object_id=self.file_id, - ) - response: Response = await self.retry_handler( - fn=client.get, - url=url, - headers=headers, - ) - await self._queue.put((part_number, response.content)) - except BaseException as exception: - await self._queue.put((part_number, exception)) - - async def _drain_queue(self): - """Fetch downloaded parts from queue and keep local queue to yield parts in order.""" - next_part_to_yield = 1 - parts_downloaded = 0 - num_parts = math.ceil(self.file_size / self.part_size) - # Priority queue ensures we get the the part with the lowest part number on calling get - # Due to out of order downloading, in the worst case the next part is fetched last in the - # current batch of scheduled tasks and we keep around an additional max_parallel_tasks - 1 - # parts in the intermediary queue, assuming equal transfer speed for any single part. - results: PriorityQueue[tuple[int, bytes]] = PriorityQueue() - - while next_part_to_yield <= num_parts: - # if there are unprocessed results in the local queue, check if the correct one is among them - if not results.empty(): - part_number, part = await results.get() - if part_number == next_part_to_yield: - next_part_to_yield += 1 - yield part - else: - # if not, put it back - await results.put((part_number, part)) - - if parts_downloaded < num_parts: - # fetch next part from download queue - part_number, part = await self._queue.get() # type: ignore - parts_downloaded += 1 - - # raise exception immediately to abort download process - if isinstance(part, BaseException): - raise self.storage_cleaner.PartDownloadError( - bucket_id=get_bucket_id(self.config), - object_id=self.file_id, - part_number=part_number, - ) from part - - # yield if it's the expected part, else put it into the local queue - if part_number == next_part_to_yield: - next_part_to_yield += 1 - yield part - else: - await results.put((part_number, part)) - - async def download(self): - """Download file in parts and validate checksums""" - LOG.info("(4/7) Downloading file %s for validation.", self.file_id) - num_parts = math.ceil(self.file_size / self.part_size) - decryptor = Decryptor( - file_secret=self.file_secret, - num_parts=num_parts, - part_size=self.part_size, - target_checksums=self.target_checksums, - ) - # schedule and start download tasks - - task_handler = DownloadTaskHandler() - async with httpx_client() as client: - for part_number, (start, stop) in enumerate( - get_ranges(file_size=self.file_size, part_size=self.config.part_size), - start=1, - ): - headers = httpx.Headers({"Range": f"bytes={start}-{stop}"}) - await task_handler.schedule( - self._download_part( - client=client, - headers=headers, - part_number=part_number, - ) - ) - - try: - await decryptor.process_parts(self._drain_queue()) - - except ( - decryptor.FileChecksumValidationError, - decryptor.PartChecksumValidationError, - ) as error: - raise self.storage_cleaner.ChecksumValidationError( - bucket_id=get_bucket_id(self.config), - object_id=self.file_id, - message=str(error), - ) from error - - LOG.info("(6/7) Successfully validated checksums for %s.", self.file_id) diff --git a/src/ghga_datasteward_kit/s3_upload/entrypoint.py b/src/ghga_datasteward_kit/s3_upload/entrypoint.py index a884444..7bc2b57 100755 --- a/src/ghga_datasteward_kit/s3_upload/entrypoint.py +++ b/src/ghga_datasteward_kit/s3_upload/entrypoint.py @@ -19,6 +19,7 @@ import asyncio import base64 import logging +import math from pathlib import Path import typer @@ -26,108 +27,54 @@ from ghga_datasteward_kit import models from ghga_datasteward_kit.s3_upload.config import Config, LegacyConfig -from ghga_datasteward_kit.s3_upload.downloader import ChunkedDownloader +from ghga_datasteward_kit.s3_upload.exceptions import ( + MultipartUploadCompletionError, + SecretExchangeError, + WritingOutputError, +) +from ghga_datasteward_kit.s3_upload.file_decryption import Decryptor +from ghga_datasteward_kit.s3_upload.file_encryption import Encryptor +from ghga_datasteward_kit.s3_upload.http_client import RequestConfigurator, httpx_client +from ghga_datasteward_kit.s3_upload.multipart_upload import MultipartUpload from ghga_datasteward_kit.s3_upload.uploader import ChunkedUploader from ghga_datasteward_kit.s3_upload.utils import ( LOG, - RequestConfigurator, - StorageCleaner, check_adjust_part_size, check_output_path, get_bucket_id, handle_superficial_error, - httpx_client, ) from ghga_datasteward_kit.utils import STEWARD_TOKEN, load_config_yaml, path_join -async def validate_and_transfer_content( - input_path: Path, alias: str, config: LegacyConfig, storage_cleaner: StorageCleaner +def main( + input_path: Path = typer.Option(..., help="Local path of the input file"), + alias: str = typer.Option(..., help="A human readable file alias"), + config_path: Path = typer.Option(..., help="Path to a config YAML."), ): """ - Check and upload encrypted file content. This also includes a verification of the - upload by downloading the content again and performing a checksum validation. - - Returns: - A tuple of the used uploader instance and the file size + Custom script to encrypt data using Crypt4GH and directly uploading it to S3 + object storage. """ - if not input_path.exists(): - msg = f"No such file: {input_path.resolve()}" - handle_superficial_error(msg=msg) - - if input_path.is_dir(): - msg = f"File location points to a directory: {input_path.resolve()}" - handle_superficial_error(msg=msg) - - check_output_path(config.output_dir / f"{alias}.json") - - file_size = input_path.stat().st_size - check_adjust_part_size(config=config, file_size=file_size) + config = load_config_yaml(config_path, Config) - uploader = ChunkedUploader( - input_path=input_path, - alias=alias, - config=config, - unencrypted_file_size=file_size, - storage_cleaner=storage_cleaner, + token = STEWARD_TOKEN.read_token() + asyncio.run( + async_main(input_path=input_path, alias=alias, config=config, token=token) ) - await uploader.encrypt_and_upload() - - try: - downloader = ChunkedDownloader( - config=config, - file_id=uploader.file_id, - encrypted_file_size=uploader.encryptor.encrypted_file_size, - file_secret=uploader.encryptor.file_secret, - part_size=config.part_size, - target_checksums=uploader.encryptor.checksums, - storage_cleaner=storage_cleaner, - ) - await downloader.download() - except KeyboardInterrupt as error: - raise storage_cleaner.DownloadError( - bucket_id=get_bucket_id(config), object_id=downloader.file_id - ) from error - return uploader, file_size - -async def exchange_secret_for_id( - *, - file_id: str, - secret: bytes, - token: str, - config: Config, - storage_cleaner: StorageCleaner, -) -> str: +def legacy_main( + input_path: Path = typer.Option(..., help="Local path of the input file"), + alias: str = typer.Option(..., help="A human readable file alias"), + config_path: Path = typer.Option(..., help="Path to a config YAML."), +): """ - Call file ingest service to store the file secret and obtain a secret ID by which - it can be retrieved. - - If storing the secret fails, the uploaded file is deleted from object storage and - a ValueError is raised containing the file alias and response status code. + Custom script to encrypt data using Crypt4GH and directly uploading it to S3 + object storage. """ - endpoint = "/federated/ingest_secret" - endpoint_url = path_join(config.secret_ingest_baseurl, endpoint) - file_secret = base64.b64encode(secret).decode("utf-8") - payload = encrypt(data=file_secret, key=config.secret_ingest_pubkey) - encrypted_secret = models.EncryptedPayload(payload=payload) - - async with httpx_client() as client: - headers = {"Authorization": f"Bearer {token}"} - response = await client.post( - url=endpoint_url, json=encrypted_secret.model_dump(), headers=headers - ) - - if response.status_code != 200: - message = ( - f"Failed to deposit secret for {file_id} with response code" - + f" {response.status_code}." - ) - raise storage_cleaner.SecretExchangeError( - bucket_id=get_bucket_id(config), object_id=file_id, message=message - ) - return response.json()["secret_id"] + config = load_config_yaml(config_path, LegacyConfig) + asyncio.run(legacy_async_main(input_path=input_path, alias=alias, config=config)) async def async_main(input_path: Path, alias: str, config: Config, token: str): @@ -136,34 +83,33 @@ async def async_main(input_path: Path, alias: str, config: Config, token: str): Prints metadata to .json in the specified output directory """ RequestConfigurator.configure(config=config) + file_size = await check_adjust_input_file( + input_path=input_path, alias=alias, config=config + ) - async with StorageCleaner(config=config) as storage_cleaner: - uploader, file_size = await validate_and_transfer_content( - input_path=input_path, - alias=alias, - config=config, - storage_cleaner=storage_cleaner, + async with MultipartUpload(file_size=file_size, config=config) as upload: + checksums, raw_file_secret = await validate_and_transfer_content( + input_path=input_path, config=config, upload=upload ) ( unencrypted_checksum, encrypted_md5_checksums, encrypted_sha256_checksums, - ) = uploader.encryptor.checksums.get() + ) = checksums.get() secret_id = await exchange_secret_for_id( - file_id=uploader.file_id, - secret=uploader.encryptor.file_secret, + file_id=upload.file_id, + secret=raw_file_secret, token=token, config=config, - storage_cleaner=storage_cleaner, ) metadata = models.OutputMetadata( - alias=uploader.alias, - file_id=uploader.file_id, + alias=alias, + file_id=upload.file_id, bucket_id=get_bucket_id(config=config), - object_id=uploader.file_id, + object_id=upload.file_id, original_path=input_path, part_size=config.part_size, secret_id=secret_id, @@ -171,20 +117,16 @@ async def async_main(input_path: Path, alias: str, config: Config, token: str): encrypted_md5_checksums=encrypted_md5_checksums, encrypted_sha256_checksums=encrypted_sha256_checksums, unencrypted_size=file_size, - encrypted_size=uploader.encryptor.encrypted_file_size, + encrypted_size=upload.encrypted_file_size, storage_alias=config.selected_storage_alias, ) - output_path = config.output_dir / f"{uploader.alias}.json" - LOG.info("(7/7) Writing metadata to %s.", output_path) - try: - metadata.serialize(output_path) - except ( - Exception, - KeyboardInterrupt, - ) as exc: - raise storage_cleaner.WritingOutputError( - bucket_id=get_bucket_id(config), object_id=uploader.file_id - ) from exc + write_output( + alias=alias, + bucket_id=get_bucket_id(config), + object_id=upload.file_id, + metadata=metadata, + output_dir=config.output_dir, + ) async def legacy_async_main(input_path: Path, alias: str, config: LegacyConfig): @@ -193,28 +135,28 @@ async def legacy_async_main(input_path: Path, alias: str, config: LegacyConfig): Prints metadata to .json in the specified output directory """ RequestConfigurator.configure(config=config) + file_size = await check_adjust_input_file( + input_path=input_path, alias=alias, config=config + ) - async with StorageCleaner(config=config) as storage_cleaner: - uploader, file_size = await validate_and_transfer_content( - input_path=input_path, - alias=alias, - config=config, - storage_cleaner=storage_cleaner, + async with MultipartUpload(file_size=file_size, config=config) as upload: + checksums, raw_file_secret = await validate_and_transfer_content( + input_path=input_path, config=config, upload=upload ) ( unencrypted_checksum, encrypted_md5_checksums, encrypted_sha256_checksums, - ) = uploader.encryptor.checksums.get() + ) = checksums.get() - file_secret = base64.b64encode(uploader.encryptor.file_secret).decode("utf-8") + file_secret = base64.b64encode(raw_file_secret).decode("utf-8") metadata = models.LegacyOutputMetadata( - alias=uploader.alias, - file_id=uploader.file_id, + alias=alias, + file_id=upload.file_id, bucket_id=get_bucket_id(config=config), - object_id=uploader.file_id, + object_id=upload.file_id, original_path=input_path, part_size=config.part_size, file_secret=file_secret, @@ -222,50 +164,156 @@ async def legacy_async_main(input_path: Path, alias: str, config: LegacyConfig): encrypted_md5_checksums=encrypted_md5_checksums, encrypted_sha256_checksums=encrypted_sha256_checksums, unencrypted_size=file_size, - encrypted_size=uploader.encryptor.encrypted_file_size, + encrypted_size=upload.encrypted_file_size, storage_alias=config.selected_storage_alias, ) - output_path = config.output_dir / f"{uploader.alias}.json" - LOG.info("(7/7) Writing metadata to %s.", output_path) - try: - metadata.serialize(output_path) - except ( - Exception, - KeyboardInterrupt, - ) as exc: - raise storage_cleaner.WritingOutputError( - bucket_id=get_bucket_id(config), object_id=uploader.file_id - ) from exc + write_output( + alias=alias, + bucket_id=get_bucket_id(config), + object_id=upload.file_id, + metadata=metadata, + output_dir=config.output_dir, + ) -def main( - input_path: Path = typer.Option(..., help="Local path of the input file"), - alias: str = typer.Option(..., help="A human readable file alias"), - config_path: Path = typer.Option(..., help="Path to a config YAML."), -): +async def check_adjust_input_file( + input_path: Path, alias: str, config: LegacyConfig +) -> int: + """Check if input file exists, get file size and adjust part size if necessary.""" + if not input_path.exists(): + msg = f"No such file: {input_path.resolve()}" + handle_superficial_error(msg=msg) + + if input_path.is_dir(): + msg = f"File location points to a directory: {input_path.resolve()}" + handle_superficial_error(msg=msg) + + check_output_path(config.output_dir / f"{alias}.json") + + file_size = input_path.stat().st_size + check_adjust_part_size(config=config, file_size=file_size) + + return file_size + + +async def validate_and_transfer_content( + input_path: Path, upload: MultipartUpload, config: LegacyConfig +) -> tuple[models.Checksums, bytes]: """ - Custom script to encrypt data using Crypt4GH and directly uploading it to S3 - object storage. + Check and upload encrypted file content. + + This also includes a verification of the upload by calculating and supplying part MD5 + sums and checking the ETag of the uploaded object. + Additionally the encrypted parts are decrypted locally and the checksum of the initial + unencrypted and the decrypted file are compared. + + + Returns: + A tuple of the used uploader instance and the file size """ - config = load_config_yaml(config_path, Config) + encryptor = Encryptor(config.part_size) + decryptor = Decryptor(file_secret=encryptor.file_secret) - token = STEWARD_TOKEN.read_token() - asyncio.run( - async_main(input_path=input_path, alias=alias, config=config, token=token) + uploader = ChunkedUploader( + input_path=input_path, + config=config, + encryptor=encryptor, + decryptor=decryptor, + upload=upload, ) + await uploader.encrypt_and_upload() + try: + await upload.storage.complete_multipart_upload( + upload_id=upload.upload_id, + bucket_id=upload.bucket_id, + object_id=upload.file_id, + anticipated_part_quantity=math.ceil( + upload.encrypted_file_size / upload.part_size + ), + anticipated_part_size=upload.part_size, + ) + except BaseException as exc: + raise MultipartUploadCompletionError( + cause=str(exc), + bucket_id=upload.bucket_id, + object_id=upload.file_id, + upload_id=upload.upload_id, + ) from exc + + # Sanity checks + if uploader.upload.encrypted_file_size != uploader.encryptor.encrypted_file_size: + raise ValueError( + "Mismatch between actual and theoretical encrypted part size:\n" + + f"Is: {uploader.encryptor.encrypted_file_size}\n" + + f"Should be: {uploader.upload.encrypted_file_size}" + ) + # check local checksums of the unencrypted content + uploader.decryptor.complete_processing( + bucket_id=upload.bucket_id, + object_id=upload.file_id, + encryption_file_sha256=uploader.encryptor.checksums.unencrypted_sha256.hexdigest(), + ) + # check remote md5 matches locally calculated one + await upload.check_md5_matches() + return uploader.encryptor.checksums, uploader.encryptor.file_secret -def legacy_main( - input_path: Path = typer.Option(..., help="Local path of the input file"), - alias: str = typer.Option(..., help="A human readable file alias"), - config_path: Path = typer.Option(..., help="Path to a config YAML."), -): + +async def exchange_secret_for_id( + *, + file_id: str, + secret: bytes, + token: str, + config: Config, +) -> str: """ - Custom script to encrypt data using Crypt4GH and directly uploading it to S3 - object storage. + Call file ingest service to store the file secret and obtain a secret ID by which + it can be retrieved. + + If storing the secret fails, the uploaded file is deleted from object storage and + a SecretExchangeError is raised with the file ID, bucket ID, and response status code. """ - config = load_config_yaml(config_path, LegacyConfig) - asyncio.run(legacy_async_main(input_path=input_path, alias=alias, config=config)) + endpoint = "/federated/ingest_secret" + endpoint_url = path_join(config.secret_ingest_baseurl, endpoint) + file_secret = base64.b64encode(secret).decode("utf-8") + payload = encrypt(data=file_secret, key=config.secret_ingest_pubkey) + encrypted_secret = models.EncryptedPayload(payload=payload) + + async with httpx_client() as client: + headers = {"Authorization": f"Bearer {token}"} + response = await client.post( + url=endpoint_url, json=encrypted_secret.model_dump(), headers=headers + ) + + if response.status_code != 200: + message = ( + f"Failed to deposit secret for {file_id} with response code" + + f" {response.status_code}." + ) + raise SecretExchangeError( + bucket_id=get_bucket_id(config), object_id=file_id, message=message + ) + return response.json()["secret_id"] + + +def write_output( + *, + alias: str, + bucket_id: str, + object_id: str, + metadata: models.LegacyOutputMetadata | models.OutputMetadata, + output_dir: Path, +): + """Write local output metadata file.""" + output_path = output_dir / f"{alias}.json" + LOG.info("(4/4) Writing metadata to %s.", output_path) + try: + metadata.serialize(output_path) + except ( + Exception, + KeyboardInterrupt, + ) as exc: + raise WritingOutputError(bucket_id=bucket_id, object_id=object_id) from exc if __name__ == "__main__": diff --git a/src/ghga_datasteward_kit/s3_upload/exceptions.py b/src/ghga_datasteward_kit/s3_upload/exceptions.py new file mode 100644 index 0000000..60b5039 --- /dev/null +++ b/src/ghga_datasteward_kit/s3_upload/exceptions.py @@ -0,0 +1,113 @@ +# Copyright 2021 - 2024 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln +# for the German Human Genome-Phenome Archive (GHGA) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Common exception classes""" + + +class ShouldAbortUploadError(RuntimeError): + """Base exception class for errors that are raised before a multipart upload is finished. + + All errors derived from this one result in the ongoing upload being cancelled. + """ + + def __init__(self, *, bucket_id: str, object_id: str, upload_id: str, message: str): + self.bucket_id = bucket_id + self.object_id = object_id + self.upload_id = upload_id + super().__init__(message) + + +class ShouldDeleteObjectError(RuntimeError): + """Base exception class for errors that are raised after a multipart upload is finished. + + All errors derived from this one result in the uploaded object being deleted. + """ + + def __init__(self, *, bucket_id: str, object_id: str, message: str): + self.bucket_id = bucket_id + self.object_id = object_id + super().__init__(message) + + +class ChecksumValidationError(ShouldDeleteObjectError): + """Raised when checksum validation failed and the uploaded file needs removal.""" + + def __init__(self, *, bucket_id: str, object_id: str, message: str): + self.bucket_id = bucket_id + self.object_id = object_id + super().__init__(bucket_id=bucket_id, object_id=object_id, message=message) + + +class MultipartUploadCompletionError(ShouldAbortUploadError): + """Raised when upload completion failed and the ongoing upload needs to be aborted.""" + + def __init__( + self, *, cause: str, bucket_id: str, object_id: str, upload_id: str + ) -> None: + self.bucket_id = bucket_id + self.object_id = object_id + self.upload_id = upload_id + message = ( + f"Failed completing file upload for ''{object_id}'' due to:\n {cause}." + ) + super().__init__( + bucket_id=bucket_id, + object_id=object_id, + upload_id=upload_id, + message=message, + ) + + +class PartUploadError(ShouldAbortUploadError): + """Raised when uploading a file part failed and the ongoing upload needs to be aborted.""" + + def __init__( + self, + *, + cause: str, + bucket_id: str, + object_id: str, + part_number: int, + upload_id: str, + ) -> None: + self.bucket_id = bucket_id + self.object_id = object_id + self.part_number = part_number + self.upload_id = upload_id + message = f"Failed uploading file part {part_number} for ''{object_id}'' due to:\n {cause}." + super().__init__( + bucket_id=bucket_id, + object_id=object_id, + upload_id=upload_id, + message=message, + ) + + +class SecretExchangeError(ShouldDeleteObjectError): + """Raised when secret exchange failed and the uploaded file needs removal.""" + + def __init__(self, *, bucket_id: str, object_id: str, message: str): + self.bucket_id = bucket_id + self.object_id = object_id + super().__init__(bucket_id=bucket_id, object_id=object_id, message=message) + + +class WritingOutputError(ShouldDeleteObjectError): + """Raised when output metadata could not be written and the uploaded file needs removal.""" + + def __init__(self, *, bucket_id: str, object_id: str): + self.bucket_id = bucket_id + self.object_id = object_id + message = f"Failed writing output file for ''{object_id}''." + super().__init__(bucket_id=bucket_id, object_id=object_id, message=message) diff --git a/src/ghga_datasteward_kit/s3_upload/file_decryption.py b/src/ghga_datasteward_kit/s3_upload/file_decryption.py index efa01af..fb84ba5 100644 --- a/src/ghga_datasteward_kit/s3_upload/file_decryption.py +++ b/src/ghga_datasteward_kit/s3_upload/file_decryption.py @@ -15,80 +15,30 @@ # """Functionality to decrypt Crypt4GH encrypted files on-the-fly for validation purposes.""" -import gc import hashlib -from collections.abc import AsyncGenerator -from time import time -from typing import Any import crypt4gh.lib # type: ignore -from ghga_datasteward_kit import models -from ghga_datasteward_kit.s3_upload.utils import LOG, get_segments - -COLLECTION_LIMIT_MIB = 256 * 1024**2 +from ghga_datasteward_kit.s3_upload.exceptions import ChecksumValidationError +from ghga_datasteward_kit.s3_upload.utils import get_segments class Decryptor: """Handles on the fly decryption and checksum calculation""" - class FileChecksumValidationError(RuntimeError): - """Raised when checksum validation failed and the uploaded file needs removal.""" - - def __init__(self, *, current_checksum: str, upload_checksum: str): - message = ( - "Checksum mismatch for file:\n" - + f"Upload:\n{current_checksum}\nDownload:\n{upload_checksum}\n" - + "Uploaded file was deleted due to validation failure." - ) - self.current_checksum = current_checksum - self.upload_checksum = upload_checksum - super().__init__(message) - - class PartChecksumValidationError(RuntimeError): - """Raised when checksum validation failed and the uploaded file needs removal.""" - - def __init__( - self, - *, - part_number: int, - current_part_checksum: str, - upload_part_checksum: str, - ): - message = ( - f"Checksum mismatch for part no. {part_number}:\n" - + f"Upload:\n{current_part_checksum}\nDownload:\n{upload_part_checksum}\n" - + "Uploaded file was deleted due to validation failure." - ) - self.part_number = part_number - self.current_part_checksum = current_part_checksum - self.upload_part_checksum = upload_part_checksum - super().__init__(message) - - def __init__( - self, - *, - file_secret: bytes, - num_parts: int, - part_size: int, - target_checksums: models.Checksums, - ) -> None: + def __init__(self, file_secret: bytes) -> None: self.file_secret = file_secret - self.num_parts = num_parts - self.part_size = part_size - self.target_checksums = target_checksums + self.unencrypted_sha256 = hashlib.sha256() + self.unprocessed_bytes = b"" - def _decrypt(self, part: bytes): + def decrypt_part(self, part: bytes): """Decrypt file part""" - segments, incomplete_segment = get_segments( - part=part, segment_size=crypt4gh.lib.CIPHER_SEGMENT_SIZE + part_to_decrypt = self.unprocessed_bytes + part + segments, self.unprocessed_bytes = get_segments( + part=part_to_decrypt, segment_size=crypt4gh.lib.CIPHER_SEGMENT_SIZE ) - - decrypted_segments = [] - for segment in segments: - decrypted_segments.append(self._decrypt_segment(segment)) - - return b"".join(decrypted_segments), incomplete_segment + decrypted_segments = [self._decrypt_segment(segment) for segment in segments] + self.unencrypted_sha256.update(b"".join(decrypted_segments)) def _decrypt_segment(self, segment: bytes): """Decrypt single ciphersegment""" @@ -96,77 +46,23 @@ def _decrypt_segment(self, segment: bytes): ciphersegment=segment, session_keys=[self.file_secret] ) - def _validate_current_checksum(self, *, file_part: bytes, part_number: int): - """Verify checksums match for the given file part.""" - current_part_md5 = hashlib.md5(file_part, usedforsecurity=False).hexdigest() - current_part_sha256 = hashlib.sha256(file_part).hexdigest() - - upload_part_md5 = self.target_checksums.encrypted_md5[part_number - 1] - upload_part_sha256 = self.target_checksums.encrypted_sha256[part_number - 1] - - if current_part_md5 != upload_part_md5: - raise self.PartChecksumValidationError( - part_number=part_number, - current_part_checksum=current_part_md5, - upload_part_checksum=upload_part_md5, - ) - elif current_part_sha256 != upload_part_sha256: - raise self.PartChecksumValidationError( - part_number=part_number, - current_part_checksum=current_part_sha256, - upload_part_checksum=upload_part_sha256, - ) - - async def process_parts(self, download_files: AsyncGenerator[bytes, Any]): - """Download and decrypt file parts.""" - unprocessed_bytes = b"" - download_buffer = b"" - unencrypted_sha256 = hashlib.sha256() - - start = time() - - part_number = 1 - collection_tracker_mib = 0 - - async for file_part in download_files: - # process encrypted - self._validate_current_checksum( - file_part=file_part, part_number=part_number - ) - unprocessed_bytes += file_part - collection_tracker_mib += len(file_part) - - # decrypt in chunks - decrypted_bytes, unprocessed_bytes = self._decrypt(unprocessed_bytes) - download_buffer += decrypted_bytes - - unencrypted_sha256.update(download_buffer) - download_buffer = b"" - - delta = time() - start - avg_speed = (part_number * (self.part_size / 1024**2)) / delta - - LOG.info( - "(5/7) Downloading part %i/%i (%.2f MiB/s)", - part_number, - self.num_parts, - avg_speed, - ) - part_number += 1 - if collection_tracker_mib >= COLLECTION_LIMIT_MIB: - collection_tracker_mib = 0 - gc.collect() - + def complete_processing( + self, *, bucket_id: str, object_id: str, encryption_file_sha256: str + ): + """Consume remaining bytes and compare checksums""" # process dangling bytes - if unprocessed_bytes: - download_buffer += self._decrypt_segment(unprocessed_bytes) - - unencrypted_sha256.update(download_buffer) - download_buffer = b"" - - current_checksum = unencrypted_sha256.hexdigest() - upload_checksum = self.target_checksums.unencrypted_sha256.hexdigest() - if current_checksum != upload_checksum: - raise self.FileChecksumValidationError( - current_checksum=current_checksum, upload_checksum=upload_checksum + if self.unprocessed_bytes: + last_segment = self._decrypt_segment(self.unprocessed_bytes) + self.unencrypted_sha256.update(last_segment) + + decryption_file_sha256 = self.unencrypted_sha256.hexdigest() + if decryption_file_sha256 != encryption_file_sha256: + raise ChecksumValidationError( + bucket_id=bucket_id, + object_id=object_id, + message=( + f"Checksum mismatch for file:\nDecryption:\n{decryption_file_sha256}\n" + + f"Encryption:\n{encryption_file_sha256}\n" + + "Uploaded file was deleted due to validation failure." + ), ) diff --git a/src/ghga_datasteward_kit/s3_upload/http_client.py b/src/ghga_datasteward_kit/s3_upload/http_client.py new file mode 100644 index 0000000..5640a07 --- /dev/null +++ b/src/ghga_datasteward_kit/s3_upload/http_client.py @@ -0,0 +1,78 @@ +# Copyright 2021 - 2024 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln +# for the German Human Genome-Phenome Archive (GHGA) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""httpx client and retry functionality related code.""" + +import logging +from contextlib import asynccontextmanager + +import httpx +from tenacity import ( + AsyncRetrying, + retry_if_exception_type, + retry_if_result, + stop_after_attempt, + wait_exponential_jitter, +) + +from ghga_datasteward_kit.s3_upload.config import LegacyConfig + + +class RequestConfigurator: + """Helper for user configurable httpx request parameters.""" + + timeout: int | None + max_connections: int + + @classmethod + def configure(cls, config: LegacyConfig): + """Set timeout in seconds""" + cls.timeout = config.client_timeout + cls.max_connections = config.client_max_parallel_transfers + # silence httpx messages on each request due to setting global level info before + logging.getLogger("httpx").setLevel(logging.WARNING) + + +@asynccontextmanager +async def httpx_client(): + """Yields a context manager httpx client and closes it afterward""" + async with httpx.AsyncClient( + timeout=RequestConfigurator.timeout, + limits=httpx.Limits( + max_connections=RequestConfigurator.max_connections, + max_keepalive_connections=RequestConfigurator.max_connections, + ), + ) as client: + yield client + + +def configure_retries(config: LegacyConfig): + """Initialize retry handler from config""" + return AsyncRetrying( + retry=( + retry_if_exception_type( + ( + httpx.ConnectError, + httpx.ConnectTimeout, + httpx.TimeoutException, + ) + ) + | retry_if_result( + lambda response: response.status_code + in config.client_retry_status_codes + ) + ), + stop=stop_after_attempt(config.client_num_retries), + wait=wait_exponential_jitter(max=config.client_exponential_backoff_max), + ) diff --git a/src/ghga_datasteward_kit/s3_upload/multipart_upload.py b/src/ghga_datasteward_kit/s3_upload/multipart_upload.py new file mode 100644 index 0000000..608f7a8 --- /dev/null +++ b/src/ghga_datasteward_kit/s3_upload/multipart_upload.py @@ -0,0 +1,105 @@ +# Copyright 2021 - 2024 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln +# for the German Human Genome-Phenome Archive (GHGA) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Multipart upload context manager dealing with initialization and cleanup.""" + +import hashlib +from uuid import uuid4 + +from ghga_datasteward_kit.s3_upload.config import LegacyConfig +from ghga_datasteward_kit.s3_upload.exceptions import ( + ChecksumValidationError, + ShouldAbortUploadError, + ShouldDeleteObjectError, +) +from ghga_datasteward_kit.s3_upload.utils import ( + get_bucket_id, + get_encrypted_file_size_and_num_parts, + get_object_storage, +) + + +class MultipartUpload: + """Context manager to handle init + complete/abort for S3 multipart upload""" + + def __init__(self, *, file_size: int, config: LegacyConfig) -> None: + self.config = config + self.storage = get_object_storage(config=self.config) + self.file_id = str(uuid4()) + self.bucket_id = get_bucket_id(self.config) + self.part_size = config.part_size + self.unencrypted_file_size = file_size + self.encrypted_file_size, self.num_parts = ( + get_encrypted_file_size_and_num_parts( + unencrypted_file_size=file_size, part_size=config.part_size + ) + ) + self.upload_id = "" + self.md5sums: list[str] = [] + + async def __aenter__(self): + """Start multipart upload""" + self.upload_id = await self.storage.init_multipart_upload( + bucket_id=self.bucket_id, object_id=self.file_id + ) + return self + + async def __aexit__(self, exc_t, exc_v, exc_tb): + """Deal with errors""" + if exc_v == None: + return + # error handling while upload is still ongoing + if isinstance(exc_v, ShouldAbortUploadError): + await self.storage.abort_multipart_upload( + upload_id=exc_v.upload_id, + bucket_id=exc_v.bucket_id, + object_id=exc_v.object_id, + ) + # error handling after upload has been completed + elif isinstance( + exc_v, + ShouldDeleteObjectError, + ): + await self.storage.delete_object( + bucket_id=exc_v.bucket_id, + object_id=exc_v.object_id, + ) + raise exc_v + + async def check_md5_matches(self): + """Calculate final object MD5 and check if the remote matches. + + The final object MD5 is equal to the MD5 of all the concatenated + MD5s from the individual file parts, followed by a dash ("-") and + the number of file parts. + """ + # concatenation needs the raw bytes, convert from hexdigest + concatenated_md5s = b"".join(bytes.fromhex(md5) for md5 in self.md5sums) + object_md5 = hashlib.md5(concatenated_md5s, usedforsecurity=False).hexdigest() + + num_parts = len(self.md5sums) + object_md5 += f"-{num_parts}" + + remote_md5 = await self.storage.get_object_etag( + bucket_id=self.bucket_id, object_id=self.file_id + ) + remote_md5 = remote_md5.strip('"') + + if object_md5 != remote_md5: + raise ChecksumValidationError( + bucket_id=self.bucket_id, + object_id=self.file_id, + message=f"Object MD5 {remote_md5} of the uploaded object does not match" + f" the locally computed one: {object_md5}.", + ) diff --git a/src/ghga_datasteward_kit/s3_upload/uploader.py b/src/ghga_datasteward_kit/s3_upload/uploader.py index 29d758d..2365e2e 100644 --- a/src/ghga_datasteward_kit/s3_upload/uploader.py +++ b/src/ghga_datasteward_kit/s3_upload/uploader.py @@ -16,27 +16,24 @@ """Functionality to upload encrypted file chunks using multipart upload.""" import asyncio -import math +import base64 +import hashlib from collections.abc import Coroutine, Generator from pathlib import Path from time import time from typing import Any -from uuid import uuid4 -import crypt4gh.lib # type: ignore import httpx +from hexkit.providers.s3 import S3ObjectStorage from httpx import Response from ghga_datasteward_kit.s3_upload.config import LegacyConfig +from ghga_datasteward_kit.s3_upload.exceptions import PartUploadError +from ghga_datasteward_kit.s3_upload.file_decryption import Decryptor from ghga_datasteward_kit.s3_upload.file_encryption import Encryptor -from ghga_datasteward_kit.s3_upload.utils import ( - LOG, - StorageCleaner, - configure_retries, - get_bucket_id, - get_object_storage, - httpx_client, -) +from ghga_datasteward_kit.s3_upload.http_client import configure_retries, httpx_client +from ghga_datasteward_kit.s3_upload.multipart_upload import MultipartUpload +from ghga_datasteward_kit.s3_upload.utils import LOG, get_bucket_id class UploadTaskHandler: @@ -45,14 +42,17 @@ class UploadTaskHandler: def __init__(self): self._tasks: set[asyncio.Task] = set() - async def schedule(self, fn: Coroutine[Any, Any, None]): + def schedule(self, fn: Coroutine[Any, Any, None]): """Create a task and register its callback.""" task = asyncio.create_task(fn) self._tasks.add(task) - task.add_done_callback(self._tasks.discard) async def gather(self): """Await all running tasks""" + # Changed back to how it was before, as gather should take care of cancelling + # all remaining tasks and correctly propagate the first error encounterd upwards. + # The infinite loop when all tasks fail happened due to mistakenly converting + # CancelledError into a PartUploadError inside the task. await asyncio.gather(*self._tasks) @@ -61,133 +61,69 @@ class ChunkedUploader: def __init__( self, + *, input_path: Path, - alias: str, config: LegacyConfig, - unencrypted_file_size: int, - storage_cleaner: StorageCleaner, + encryptor: Encryptor, + decryptor: Decryptor, + upload: MultipartUpload, ) -> None: - self.alias = alias self.config = config self.input_path = input_path - self.encryptor = Encryptor(self.config.part_size) - self.file_id = str(uuid4()) - self.unencrypted_file_size = unencrypted_file_size - self.encrypted_file_size = 0 - self._storage_cleaner = storage_cleaner + self.encryptor = encryptor + self.decryptor = decryptor + self.bucket_id = get_bucket_id(config) + self.retry_handler = configure_retries(config) + self.upload = upload + self._in_sequence_part_number = 1 + self._semaphore = asyncio.Semaphore(config.client_max_parallel_transfers) async def encrypt_and_upload(self): """Delegate encryption and perform multipart upload""" - # compute encrypted_file_size - num_segments = math.ceil(self.unencrypted_file_size / crypt4gh.lib.SEGMENT_SIZE) - encrypted_file_size = self.unencrypted_file_size + num_segments * 28 - num_parts = math.ceil(encrypted_file_size / self.config.part_size) - with open(self.input_path, "rb") as file: - async with ( - MultipartUpload( - config=self.config, - file_id=self.file_id, - encrypted_file_size=encrypted_file_size, - part_size=self.config.part_size, - storage_cleaner=self._storage_cleaner, - ) as upload, - httpx_client() as client, - ): - LOG.info("(1/7) Initialized file upload for %s.", upload.file_id) - task_handler = UploadTaskHandler() + async with httpx_client() as client: + LOG.info("(1/4) Initialized file upload for %s.", self.upload.file_id) start = time() file_processor = self.encryptor.process_file(file=file) - for _ in range(num_parts): - await task_handler.schedule( - upload.send_part( + task_handler = UploadTaskHandler() + for _ in range(self.upload.num_parts): + task_handler.schedule( + self.send_part( client=client, file_processor=file_processor, - num_parts=num_parts, start=start, + upload=self.upload, ) ) # Wait for all upload tasks to finish await task_handler.gather() - if encrypted_file_size != self.encryptor.encrypted_file_size: - raise ValueError( - "Mismatch between actual and theoretical encrypted part size:\n" - + f"Is: {self.encryptor.encrypted_file_size}\n" - + f"Should be: {encrypted_file_size}" - ) - LOG.info("(3/7) Finished upload for %s.", upload.file_id) - -class MultipartUpload: - """Context manager to handle init + complete/abort for S3 multipart upload""" - - def __init__( - self, - config: LegacyConfig, - file_id: str, - encrypted_file_size: int, - part_size: int, - storage_cleaner: StorageCleaner, - ) -> None: - self.config = config - self.storage = get_object_storage(config=self.config) - self.file_id = file_id - self.file_size = encrypted_file_size - self.part_size = part_size - self.upload_id = "" - self.storage_cleaner = storage_cleaner - self.retry_handler = configure_retries(config) - self._semaphore = asyncio.Semaphore(config.client_max_parallel_transfers) - self._in_sequence_part_number = 1 - - async def __aenter__(self): - """Start multipart upload""" - self.upload_id = await self.storage.init_multipart_upload( - bucket_id=get_bucket_id(self.config), object_id=self.file_id - ) - return self - - async def __aexit__(self, exc_t, exc_v, exc_tb): - """Complete or clean up multipart upload""" - try: - await self.storage.complete_multipart_upload( - upload_id=self.upload_id, - bucket_id=get_bucket_id(self.config), - object_id=self.file_id, - anticipated_part_quantity=math.ceil(self.file_size / self.part_size), - anticipated_part_size=self.part_size, - ) - except BaseException as exc: - raise self.storage_cleaner.MultipartUploadCompletionError( - cause=str(exc), - bucket_id=get_bucket_id(self.config), - object_id=self.file_id, - upload_id=self.upload_id, - ) from exc + # assign md5 sums for content MD5 comparison of the assembled object + self.upload.md5sums = self.encryptor.checksums.encrypted_md5 + LOG.info("(3/4) Finished upload for %s.", self.upload.file_id) async def send_part( self, *, client: httpx.AsyncClient, file_processor: Generator[tuple[int, bytes], Any, None], - num_parts: int, start: float, + upload: MultipartUpload, ): """Handle upload of one file part""" async with self._semaphore: - part_number, part = next(file_processor) + part_number = 0 # defined here so it can be used in the exception try: - upload_url = await self.storage.get_part_upload_url( - upload_id=self.upload_id, - bucket_id=get_bucket_id(self.config), - object_id=self.file_id, + part_number, part = next(file_processor) + self.decryptor.decrypt_part(part) + response = await self._prepare_and_send_request( + client=client, + storage=upload.storage, + upload_id=upload.upload_id, + part=part, part_number=part_number, ) - response: Response = await self.retry_handler( - fn=client.put, url=upload_url, content=part - ) - # mask the actual current file part number and display an in sequence number instead delta = time() - start avg_speed = ( @@ -196,23 +132,64 @@ async def send_part( / delta ) LOG.info( - "(2/7) Processing upload for file part %i/%i (%.2f MiB/s)", + "(2/4) Processing upload for file part %i/%i (%.2f MiB/s)", self._in_sequence_part_number, - num_parts, + self.upload.num_parts, avg_speed, ) self._in_sequence_part_number += 1 - status_code = response.status_code if status_code != 200: - raise ValueError(f"Received unexpected status code { - status_code} when trying to upload file part {part_number}.") + if status_code == 400: + raise ValueError( + f"Could not validate uploaded part {part_number}: Mismatched MD5 checksum." + ) + raise ValueError( + f"Received unexpected status code {status_code} when trying to upload file part {part_number}." + ) except BaseException as exc: - raise self.storage_cleaner.PartUploadError( + # correctly reraise CancelledError, else this might get stuck waiting + # on semaphore lock release + if isinstance(exc, asyncio.CancelledError): + raise + raise PartUploadError( cause=str(exc), - bucket_id=get_bucket_id(self.config), - object_id=self.file_id, + bucket_id=self.bucket_id, + object_id=self.upload.file_id, part_number=part_number, - upload_id=self.upload_id, + upload_id=upload.upload_id, ) from exc + + async def _prepare_and_send_request( + self, + *, + client: httpx.AsyncClient, + storage: S3ObjectStorage, + upload_id: str, + part: bytes, + part_number: int, + ) -> Response: + """Calculate part MD5, get upload URL and send upload request. + + Exceptions arising during MD5 calculation, encoding or API calls need to be + handled by the caller. + """ + # calculate the hash again here. + # Naively fetching from the encryptor is prone to errors + part_md5 = hashlib.md5(part, usedforsecurity=False).digest() + encoded_part_md5 = base64.b64encode(part_md5).decode("utf-8") + upload_url = await storage.get_part_upload_url( + upload_id=upload_id, + bucket_id=self.bucket_id, + object_id=self.upload.file_id, + part_number=part_number, + part_md5=encoded_part_md5, + ) + response: Response = await self.retry_handler( + fn=client.put, + url=upload_url, + content=part, + headers=httpx.Headers({"Content-MD5": encoded_part_md5}), + ) + return response diff --git a/src/ghga_datasteward_kit/s3_upload/utils.py b/src/ghga_datasteward_kit/s3_upload/utils.py index ccc1d07..a1656db 100644 --- a/src/ghga_datasteward_kit/s3_upload/utils.py +++ b/src/ghga_datasteward_kit/s3_upload/utils.py @@ -16,21 +16,15 @@ """Helper functions used across different modules in the s3_upload package.""" import logging +import math import sys from collections.abc import Iterator -from contextlib import asynccontextmanager from io import BufferedReader from pathlib import Path +import crypt4gh.lib import httpx from hexkit.providers.s3 import S3Config, S3ObjectStorage -from tenacity import ( - AsyncRetrying, - retry_if_exception_type, - retry_if_result, - stop_after_attempt, - wait_exponential_jitter, -) from ghga_datasteward_kit.s3_upload.config import LegacyConfig from ghga_datasteward_kit.utils import path_join @@ -38,55 +32,6 @@ LOG = logging.getLogger("s3_upload") -class RequestConfigurator: - """Helper for user configurable httpx request parameters.""" - - timeout: int | None - max_connections: int - - @classmethod - def configure(cls, config: LegacyConfig): - """Set timeout in seconds""" - cls.timeout = config.client_timeout - cls.max_connections = config.client_max_parallel_transfers - # silence httpx messages on each request due to setting global level info before - logging.getLogger("httpx").setLevel(logging.WARNING) - - -@asynccontextmanager -async def httpx_client(): - """Yields a context manager httpx client and closes it afterward""" - async with httpx.AsyncClient( - timeout=RequestConfigurator.timeout, - limits=httpx.Limits( - max_connections=RequestConfigurator.max_connections, - max_keepalive_connections=RequestConfigurator.max_connections, - ), - ) as client: - yield client - - -def configure_retries(config: LegacyConfig): - """Initialize retry handler from config""" - return AsyncRetrying( - retry=( - retry_if_exception_type( - ( - httpx.ConnectError, - httpx.ConnectTimeout, - httpx.TimeoutException, - ) - ) - | retry_if_result( - lambda response: response.status_code - in config.client_retry_status_codes - ) - ), - stop=stop_after_attempt(config.client_num_retries), - wait=wait_exponential_jitter(max=config.client_exponential_backoff_max), - ) - - def read_file_parts( file: BufferedReader, *, part_size: int, from_part: int = 1 ) -> Iterator[bytes]: @@ -156,20 +101,17 @@ def retrieve_endpoint_urls(config: LegacyConfig, value_name: str = "storage_alia try: response = httpx.get(url) except httpx.RequestError: - LOG.error(f"Could not retrieve data from { - url} due to connection issues.") + LOG.error(f"Could not retrieve data from {url} due to connection issues.") raise status_code = response.status_code if status_code != 200: - raise ValueError(f"Received unexpected response code { - status_code} from {url}.") + raise ValueError(f"Received unexpected response code {status_code} from {url}.") try: return response.json()[value_name] except KeyError as err: raise ValueError( - f"Response from { - url} did not include expected field '{value_name}'" + f"Response from {url} did not include expected field '{value_name}'" ) from err @@ -253,121 +195,11 @@ def check_output_path(output_path: Path): handle_superficial_error(msg=msg) -class StorageCleaner: - """Async context manager to wrap full upload path and clean storage up if any - exceptions were encountered along the way - """ - - class ChecksumValidationError(RuntimeError): - """Raised when checksum validation failed and the uploaded file needs removal.""" - - def __init__(self, *, bucket_id: str, object_id: str, message: str): - self.bucket_id = bucket_id - self.object_id = object_id - super().__init__(message) - - class DownloadError(RuntimeError): - """Raised when downloading a file failed due to keyboard interrupts and the uploaded file needs removal.""" - - def __init__(self, *, bucket_id: str, object_id: str): - self.bucket_id = bucket_id - self.object_id = object_id - message = f"Failed downloading file for ''{object_id}''." - super().__init__(message) - - class MultipartUploadCompletionError(RuntimeError): - """Raised when upload completion failed and the ongoing upload needs to be aborted.""" - - def __init__( - self, *, cause: str, bucket_id: str, object_id: str, upload_id: str - ) -> None: - self.bucket_id = bucket_id - self.object_id = object_id - self.upload_id = upload_id - message = f"Failed completing file upload for ''{ - object_id}'' due to:\n {cause}." - super().__init__(message) - - class PartDownloadError(RuntimeError): - """Raised when downloading a file part failed and the uploaded file needs removal.""" - - def __init__(self, *, bucket_id: str, object_id: str, part_number: int): - self.bucket_id = bucket_id - self.object_id = object_id - message = f"Failed downloading file part { - part_number} for ''{object_id}''." - super().__init__(message) - - class PartUploadError(RuntimeError): - """Raised when uploading a file part failed and the ongoing upload needs to be aborted.""" - - def __init__( - self, - *, - cause: str, - bucket_id: str, - object_id: str, - part_number: int, - upload_id: str, - ) -> None: - self.bucket_id = bucket_id - self.object_id = object_id - self.part_number = part_number - self.upload_id = upload_id - message = f"Failed uploading file part { - part_number} for ''{object_id}'' due to:\n {cause}." - super().__init__(message) - - class SecretExchangeError(RuntimeError): - """Raised when secret exchange failed and the uploaded file needs removal.""" - - def __init__(self, *, bucket_id: str, object_id: str, message: str): - self.bucket_id = bucket_id - self.object_id = object_id - super().__init__(message) - - class WritingOutputError(RuntimeError): - """Raised when output metadata could not be written and the uploaded file needs removal.""" - - def __init__(self, *, bucket_id: str, object_id: str): - self.bucket_id = bucket_id - self.object_id = object_id - message = f"Failed writing output file for ''{object_id}''." - super().__init__(message) - - def __init__(self, *, config: LegacyConfig) -> None: - self.storage = get_object_storage(config=config) - - async def __aenter__(self): - """The context manager enter function.""" - return self - - async def __aexit__(self, exc_t, exc_v, exc_tb): - """The context manager exit function.""" - # error handling while upload is still ongoing - if isinstance( - exc_v, self.MultipartUploadCompletionError | self.PartUploadError - ): - await self.storage.abort_multipart_upload( - upload_id=exc_v.upload_id, - bucket_id=exc_v.bucket_id, - object_id=exc_v.object_id, - ) - raise exc_v - # error handling after upload has been completed - if isinstance( - exc_v, - self.ChecksumValidationError - | self.DownloadError - | self.PartDownloadError - | self.SecretExchangeError - | self.WritingOutputError, - ): - await self.storage.delete_object( - bucket_id=exc_v.bucket_id, - object_id=exc_v.object_id, - ) - raise exc_v - # simply reraise unhandled exceptions with unknown upload status - if exc_v is not None: - raise exc_v +def get_encrypted_file_size_and_num_parts( + *, unencrypted_file_size: int, part_size: int +) -> tuple[int, int]: + """Calculate encrypted file size and number of parts.""" + num_segments = math.ceil(unencrypted_file_size / crypt4gh.lib.SEGMENT_SIZE) + encrypted_file_size = unencrypted_file_size + num_segments * 28 + num_parts = math.ceil(encrypted_file_size / part_size) + return encrypted_file_size, num_parts diff --git a/tests/fixtures/config.py b/tests/fixtures/config.py index f1c2e94..27005cc 100644 --- a/tests/fixtures/config.py +++ b/tests/fixtures/config.py @@ -28,7 +28,7 @@ NoEndpointURLS3Config, S3ObjectStorageNodeConfig, ) -from ghga_datasteward_kit.s3_upload.utils import RequestConfigurator +from ghga_datasteward_kit.s3_upload.http_client import RequestConfigurator def storage_config( diff --git a/tests/test_encryption_decryption.py b/tests/test_encryption_decryption.py new file mode 100644 index 0000000..96c745a --- /dev/null +++ b/tests/test_encryption_decryption.py @@ -0,0 +1,51 @@ +# Copyright 2021 - 2024 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln +# for the German Human Genome-Phenome Archive (GHGA) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Test encryption/decryption functionality for file upload.""" + +import hashlib + +import pytest +from ghga_service_commons.utils.temp_files import big_temp_file + +from ghga_datasteward_kit.s3_upload.exceptions import ChecksumValidationError +from ghga_datasteward_kit.s3_upload.file_decryption import Decryptor +from ghga_datasteward_kit.s3_upload.file_encryption import Encryptor + + +def test_encryption_decryption(): + """Test file encryption and decryption work as expected.""" + encryptor = Encryptor(part_size=8 * 1024**2) + file_secret = encryptor.file_secret + decryptor = Decryptor(file_secret) + + with big_temp_file(50 * 1024**2) as input_file: + for _, part in encryptor.process_file(input_file): # type: ignore + decryptor.decrypt_part(part) + + bucket_id = "test" + object_id = "test" + # check positive case + decryptor.complete_processing( + bucket_id=bucket_id, + object_id=object_id, + encryption_file_sha256=encryptor.checksums.unencrypted_sha256.hexdigest(), + ) + # check error is raised + with pytest.raises(ChecksumValidationError): + decryptor.complete_processing( + bucket_id=bucket_id, + object_id=object_id, + encryption_file_sha256=hashlib.sha256(b"random").hexdigest(), + ) diff --git a/tests/test_retries.py b/tests/test_retries.py index 6df19c2..06b6be7 100644 --- a/tests/test_retries.py +++ b/tests/test_retries.py @@ -19,7 +19,7 @@ from tenacity import RetryError from ghga_datasteward_kit.s3_upload import LegacyConfig -from ghga_datasteward_kit.s3_upload.utils import configure_retries, httpx_client +from ghga_datasteward_kit.s3_upload.http_client import configure_retries, httpx_client from tests.fixtures.config import legacy_config_fixture # noqa: F401 EXCEPTIONS = [httpx.ConnectError, httpx.ConnectTimeout, httpx.TimeoutException] diff --git a/tests/test_s3_upload.py b/tests/test_s3_upload.py index 0df6cd3..d309c2c 100644 --- a/tests/test_s3_upload.py +++ b/tests/test_s3_upload.py @@ -16,17 +16,25 @@ """Testing the whole encryption, upload, validation flow""" import sys +from collections.abc import Generator from pathlib import Path +from typing import Any +import httpx import pytest from ghga_service_commons.utils.temp_files import big_temp_file from hexkit.providers.s3.testutils import S3ContainerFixture from pytest_httpx import HTTPXMock -from ghga_datasteward_kit.s3_upload import Config, LegacyConfig -from ghga_datasteward_kit.s3_upload.entrypoint import async_main, legacy_async_main +from ghga_datasteward_kit.s3_upload import Config, LegacyConfig, exceptions +from ghga_datasteward_kit.s3_upload.entrypoint import ( + async_main, + check_adjust_input_file, + legacy_async_main, + validate_and_transfer_content, +) +from ghga_datasteward_kit.s3_upload.multipart_upload import MultipartUpload from ghga_datasteward_kit.s3_upload.utils import ( - StorageCleaner, get_bucket_id, get_object_storage, ) @@ -39,18 +47,23 @@ ALIAS = "test_file" BUCKET_ID = "test-bucket" +FILE_SIZE = 50 * 1024**2 + +pytestmark = [ + pytest.mark.asyncio, + pytest.mark.httpx_mock( + assert_all_responses_were_requested=False, + can_send_already_matched_responses=True, + should_mock=lambda request: request.url.host + not in ("127.0.0.1", "localhost", "host.docker.internal"), + ), +] -@pytest.mark.httpx_mock( - assert_all_responses_were_requested=False, - can_send_already_matched_responses=True, - should_mock=lambda request: request.url.host - not in ("127.0.0.1", "localhost", "host.docker.internal"), -) -@pytest.mark.asyncio async def test_legacy_process( legacy_config_fixture: LegacyConfig, # noqa: F811 httpx_mock: HTTPXMock, + monkeypatch, ): """Test whole upload/download process for s3_upload script""" with S3ContainerFixture() as container: @@ -72,8 +85,29 @@ async def test_legacy_process( ) storage = get_object_storage(config=config) await storage.create_bucket(bucket_id=get_bucket_id(config)) - sys.set_int_max_str_digits(50 * 1024**2) - with big_temp_file(50 * 1024**2) as file: + sys.set_int_max_str_digits(FILE_SIZE) + + with ( + monkeypatch.context() as patch, + pytest.raises(exceptions.WritingOutputError), + ): + + def raise_checksum_processing_exception(output_path: Path): + """Mock to be used as patch for raising a custom exception""" + raise KeyboardInterrupt() + + patch.setattr( + "ghga_datasteward_kit.models.LegacyOutputMetadata.serialize", + raise_checksum_processing_exception, + ) + with big_temp_file(FILE_SIZE) as file: + await legacy_async_main( + input_path=Path(file.name), alias=ALIAS, config=config + ) + # ensure output file does not exist + assert not (config.output_dir / ALIAS).with_suffix(".json").exists() + + with big_temp_file(FILE_SIZE) as file: await legacy_async_main( input_path=Path(file.name), alias=ALIAS, config=config ) @@ -81,13 +115,6 @@ async def test_legacy_process( assert (config.output_dir / ALIAS).with_suffix(".json").exists() -@pytest.mark.httpx_mock( - assert_all_responses_were_requested=False, - can_send_already_matched_responses=True, - should_mock=lambda request: request.url.host - not in ("127.0.0.1", "localhost", "host.docker.internal"), -) -@pytest.mark.asyncio async def test_process(config_fixture: Config, monkeypatch, httpx_mock: HTTPXMock): # noqa: F811 """Test whole upload/download process for s3_upload script""" @@ -97,7 +124,6 @@ async def secret_exchange_dummy( secret: bytes, token: str, config: Config, - storage_cleaner: StorageCleaner, ): return "test-secret-id" @@ -120,9 +146,33 @@ async def secret_exchange_dummy( ) storage = get_object_storage(config=config) await storage.create_bucket(bucket_id=get_bucket_id(config)) - sys.set_int_max_str_digits(50 * 1024**2) + sys.set_int_max_str_digits(FILE_SIZE) + + with big_temp_file(FILE_SIZE) as file: + with ( + monkeypatch.context() as patch, + pytest.raises(exceptions.WritingOutputError), + ): + + def raise_checksum_processing_exception(output_path: Path): + """Mock to be used as patch for raising a custom exception""" + raise KeyboardInterrupt() + + patch.setattr( + "ghga_datasteward_kit.models.OutputMetadata.serialize", + raise_checksum_processing_exception, + ) + patch.setattr( + "ghga_datasteward_kit.s3_upload.entrypoint.exchange_secret_for_id", + secret_exchange_dummy, + ) + await async_main( + input_path=Path(file.name), + alias=ALIAS, + config=config, + token="dummy-token", + ) - with big_temp_file(50 * 1024**2) as file: with monkeypatch.context() as patch: patch.setattr( "ghga_datasteward_kit.s3_upload.entrypoint.exchange_secret_for_id", @@ -134,5 +184,291 @@ async def secret_exchange_dummy( config=config, token="dummy-token", ) - # output file exists? - assert (config.output_dir / ALIAS).with_suffix(".json").exists() + # output file exists? + assert (config.output_dir / ALIAS).with_suffix(".json").exists() + + +async def test_error_handling_local_checksum_validation( + config_fixture: Config, # noqa: F811 + monkeypatch, + httpx_mock: HTTPXMock, +): + """Test upload context manager error handling and cleanup when raising local checksum validation errors.""" + sys.set_int_max_str_digits(FILE_SIZE) + with S3ContainerFixture() as container, big_temp_file(FILE_SIZE) as file: + s3_config = container.s3_config + config = config_fixture.model_copy( + update={ + "object_storages": storage_config( + s3_access_key_id=s3_config.s3_access_key_id, + s3_secret_access_key=s3_config.s3_secret_access_key.get_secret_value(), + bucket_id=BUCKET_ID, + ), + } + ) + httpx_mock.add_response( + url=path_join(config.wkvs_api_url, "values/storage_aliases"), + json={"storage_aliases": {"test": s3_config.s3_endpoint_url}}, + status_code=200, + ) + storage = get_object_storage(config=config) + await storage.create_bucket(bucket_id=get_bucket_id(config)) + + alias = "test_error_handling" + input_path = Path(file.name) + file_size = await check_adjust_input_file( + input_path=input_path, alias=alias, config=config + ) + + object_ids = await storage.list_all_object_ids(bucket_id=BUCKET_ID) + assert len(object_ids) == 0 + + object_id = "" + # check encryption/decryption errors raise correctly + with pytest.raises(exceptions.ShouldDeleteObjectError): + async with MultipartUpload(file_size=file_size, config=config) as upload: + object_id = upload.file_id + with monkeypatch.context() as patch: + + def raise_checksum_processing_exception( + self, + *, + bucket_id: str, + object_id: str, + encryption_file_sha256: str, + ): + """Mock to be used as patch for raising a custom exception""" + raise exceptions.ChecksumValidationError( + bucket_id=BUCKET_ID, + object_id=object_id, + message="Expected test failure.", + ) + + patch.setattr( + "ghga_datasteward_kit.s3_upload.uploader.Decryptor.complete_processing", + raise_checksum_processing_exception, + ) + await validate_and_transfer_content( + input_path=input_path, upload=upload, config=config + ) + + assert not await storage.does_object_exist( + bucket_id=BUCKET_ID, object_id=object_id + ) + assert not await storage._list_multipart_upload_for_object( + bucket_id=BUCKET_ID, object_id=object_id + ) + + +async def test_error_handling_remote_checksum_validation( + config_fixture: Config, # noqa: F811 + monkeypatch, + httpx_mock: HTTPXMock, +): + """Test upload context manager error handling and cleanup when raising remote checksum validation errors.""" + sys.set_int_max_str_digits(FILE_SIZE) + with S3ContainerFixture() as container, big_temp_file(FILE_SIZE) as file: + s3_config = container.s3_config + config = config_fixture.model_copy( + update={ + "object_storages": storage_config( + s3_access_key_id=s3_config.s3_access_key_id, + s3_secret_access_key=s3_config.s3_secret_access_key.get_secret_value(), + bucket_id=BUCKET_ID, + ), + } + ) + httpx_mock.add_response( + url=path_join(config.wkvs_api_url, "values/storage_aliases"), + json={"storage_aliases": {"test": s3_config.s3_endpoint_url}}, + status_code=200, + ) + storage = get_object_storage(config=config) + await storage.create_bucket(bucket_id=get_bucket_id(config)) + + alias = "test_error_handling" + input_path = Path(file.name) + file_size = await check_adjust_input_file( + input_path=input_path, alias=alias, config=config + ) + + object_ids = await storage.list_all_object_ids(bucket_id=BUCKET_ID) + assert len(object_ids) == 0 + + object_id = "" + # check content MD5 comparison errors raise correctly + with pytest.raises(exceptions.ShouldDeleteObjectError): + async with MultipartUpload(file_size=file_size, config=config) as upload: + object_id = upload.file_id + with monkeypatch.context() as patch: + + def raise_content_checksum_exception(self): + """Mock to be used as patch for raising a custom exception""" + raise exceptions.ChecksumValidationError( + bucket_id=BUCKET_ID, + object_id=object_id, + message="Expected test failure.", + ) + + patch.setattr( + "ghga_datasteward_kit.s3_upload.multipart_upload.MultipartUpload.check_md5_matches", + raise_content_checksum_exception, + ) + await validate_and_transfer_content( + input_path=input_path, upload=upload, config=config + ) + + assert not await storage.does_object_exist( + bucket_id=BUCKET_ID, object_id=object_id + ) + assert not await storage._list_multipart_upload_for_object( + bucket_id=BUCKET_ID, object_id=object_id + ) + + +async def test_error_handling_upload_completion( + config_fixture: Config, # noqa: F811 + monkeypatch, + httpx_mock: HTTPXMock, +): + """Test upload context manager error handling and cleanup when raising upload completion errors.""" + sys.set_int_max_str_digits(FILE_SIZE) + with S3ContainerFixture() as container, big_temp_file(FILE_SIZE) as file: + s3_config = container.s3_config + config = config_fixture.model_copy( + update={ + "object_storages": storage_config( + s3_access_key_id=s3_config.s3_access_key_id, + s3_secret_access_key=s3_config.s3_secret_access_key.get_secret_value(), + bucket_id=BUCKET_ID, + ), + } + ) + httpx_mock.add_response( + url=path_join(config.wkvs_api_url, "values/storage_aliases"), + json={"storage_aliases": {"test": s3_config.s3_endpoint_url}}, + status_code=200, + ) + storage = get_object_storage(config=config) + await storage.create_bucket(bucket_id=get_bucket_id(config)) + + alias = "test_error_handling" + input_path = Path(file.name) + file_size = await check_adjust_input_file( + input_path=input_path, alias=alias, config=config + ) + + object_ids = await storage.list_all_object_ids(bucket_id=BUCKET_ID) + assert len(object_ids) == 0 + + object_id = "" + # check upload completion errors are raised correctly + with pytest.raises(exceptions.ShouldAbortUploadError): + async with MultipartUpload(file_size=file_size, config=config) as upload: + object_id = upload.file_id + + async def raise_upload_completion_exception( + *, + upload_id: str, + bucket_id: str, + object_id: str, + anticipated_part_quantity: int | None = None, + anticipated_part_size: int | None = None, + ): + """Mock to be used as patch for raising a custom exception""" + raise exceptions.MultipartUploadCompletionError( + cause="This should fail for testing purposes.", + bucket_id=BUCKET_ID, + object_id=ALIAS, + upload_id=upload.upload_id, + ) + + upload.storage.complete_multipart_upload = ( + raise_upload_completion_exception + ) + + await validate_and_transfer_content( + input_path=input_path, upload=upload, config=config + ) + + assert not await storage.does_object_exist( + bucket_id=BUCKET_ID, object_id=object_id + ) + assert not await storage._list_multipart_upload_for_object( + bucket_id=BUCKET_ID, object_id=object_id + ) + + +async def test_error_handling_part_upload( + config_fixture: Config, # noqa: F811 + monkeypatch, + httpx_mock: HTTPXMock, +): + """Test upload context manager error handling and cleanup when raising part upload errors.""" + sys.set_int_max_str_digits(FILE_SIZE) + with S3ContainerFixture() as container, big_temp_file(FILE_SIZE) as file: + s3_config = container.s3_config + config = config_fixture.model_copy( + update={ + "object_storages": storage_config( + s3_access_key_id=s3_config.s3_access_key_id, + s3_secret_access_key=s3_config.s3_secret_access_key.get_secret_value(), + bucket_id=BUCKET_ID, + ), + } + ) + httpx_mock.add_response( + url=path_join(config.wkvs_api_url, "values/storage_aliases"), + json={"storage_aliases": {"test": s3_config.s3_endpoint_url}}, + status_code=200, + ) + storage = get_object_storage(config=config) + await storage.create_bucket(bucket_id=get_bucket_id(config)) + + alias = "test_error_handling" + input_path = Path(file.name) + file_size = await check_adjust_input_file( + input_path=input_path, alias=alias, config=config + ) + + object_ids = await storage.list_all_object_ids(bucket_id=BUCKET_ID) + assert len(object_ids) == 0 + + object_id = "" + # check part upload errors raise correctly + with pytest.raises(exceptions.ShouldAbortUploadError): + async with MultipartUpload(file_size=file_size, config=config) as upload: + object_id = upload.file_id + with monkeypatch.context() as patch: + + async def raise_part_upload_exception( + self, + *, + client: httpx.AsyncClient, + file_processor: Generator[tuple[int, bytes], Any, None], + start: float, + upload: MultipartUpload, + ): + """Mock to be used as patch for raising a custom exception""" + raise exceptions.PartUploadError( + cause="Expected test failure", + bucket_id=BUCKET_ID, + object_id=object_id, + upload_id=upload.upload_id, + part_number=0, + ) + + patch.setattr( + "ghga_datasteward_kit.s3_upload.uploader.ChunkedUploader.send_part", + raise_part_upload_exception, + ) + await validate_and_transfer_content( + input_path=input_path, upload=upload, config=config + ) + + assert not await storage.does_object_exist( + bucket_id=BUCKET_ID, object_id=object_id + ) + assert not await storage._list_multipart_upload_for_object( + bucket_id=BUCKET_ID, object_id=object_id + )