diff --git a/docs/notebooks/external_sequences.ipynb b/docs/notebooks/external_sequences.ipynb index 1b5152d9..c59aa186 100644 --- a/docs/notebooks/external_sequences.ipynb +++ b/docs/notebooks/external_sequences.ipynb @@ -178,7 +178,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "input=[] assembly_accession='GCF_000146045.2' sequence_accession='NC_001136.10' locus_tag='YDR294C' gene_id=851888 start=1049459 end=1053228 strand=-1\n", + "input=[] repository_id='NC_001136.10' coordinates=SimpleLocation(ExactPosition(1049458), ExactPosition(1053228), strand=-1) assembly_accession='GCF_000146045.2' locus_tag='YDR294C' gene_id=851888\n", "None\n", "╙── YDR294C (Dseqrecord(-3770))\n", " └─╼ GenomeCoordinatesSource\n" @@ -264,7 +264,7 @@ { "data": { "text/plain": [ - "RepositoryIdSource(input=[], repository_id='NC_001136.10', repository_name='genbank')" + "NCBISequenceSource(input=[], repository_id='NC_001136.10', coordinates=SimpleLocation(ExactPosition(1049458), ExactPosition(1053228), strand=-1))" ] }, "execution_count": null, diff --git a/poetry.lock b/poetry.lock index 95da324e..079f7414 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. [[package]] name = "annotated-doc" @@ -26,23 +26,22 @@ files = [ [[package]] name = "anyio" -version = "4.11.0" +version = "4.12.0" description = "High-level concurrency and networking framework on top of asyncio or Trio" optional = false python-versions = ">=3.9" groups = ["main", "dev", "test"] files = [ - {file = "anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc"}, - {file = "anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4"}, + {file = "anyio-4.12.0-py3-none-any.whl", hash = "sha256:dad2376a628f98eeca4881fc56cd06affd18f659b17a747d3ff0307ced94b1bb"}, + {file = "anyio-4.12.0.tar.gz", hash = "sha256:73c693b567b0c55130c104d0b43a9baf3aa6a31fc6110116509f27bf75e21ec0"}, ] [package.dependencies] idna = ">=2.8" -sniffio = ">=1.1" typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -trio = ["trio (>=0.31.0)"] +trio = ["trio (>=0.31.0) ; python_version < \"3.10\"", "trio (>=0.32.0) ; python_version >= \"3.10\""] [[package]] name = "appdirs" @@ -114,18 +113,18 @@ pycodestyle = ">=2.12.0" [[package]] name = "beautifulsoup4" -version = "4.14.2" +version = "4.14.3" description = "Screen-scraping library" optional = false python-versions = ">=3.7.0" groups = ["main"] files = [ - {file = "beautifulsoup4-4.14.2-py3-none-any.whl", hash = "sha256:5ef6fa3a8cbece8488d66985560f97ed091e22bbc4e9c2338508a9d5de6d4515"}, - {file = "beautifulsoup4-4.14.2.tar.gz", hash = "sha256:2a98ab9f944a11acee9cc848508ec28d9228abfd522ef0fad6a02a72e0ded69e"}, + {file = "beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb"}, + {file = "beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86"}, ] [package.dependencies] -soupsieve = ">1.2" +soupsieve = ">=1.6.1" typing-extensions = ">=4.0.0" [package.extras] @@ -337,14 +336,14 @@ pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} [[package]] name = "cfgv" -version = "3.4.0" +version = "3.5.0" description = "Validate configuration and produce human readable error messages." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" groups = ["dev", "test"] files = [ - {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, - {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, + {file = "cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0"}, + {file = "cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132"}, ] [[package]] @@ -392,104 +391,104 @@ test = ["pytest"] [[package]] name = "coverage" -version = "7.11.3" +version = "7.12.0" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.10" groups = ["test"] files = [ - {file = "coverage-7.11.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0c986537abca9b064510f3fd104ba33e98d3036608c7f2f5537f869bc10e1ee5"}, - {file = "coverage-7.11.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:28c5251b3ab1d23e66f1130ca0c419747edfbcb4690de19467cd616861507af7"}, - {file = "coverage-7.11.3-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4f2bb4ee8dd40f9b2a80bb4adb2aecece9480ba1fa60d9382e8c8e0bd558e2eb"}, - {file = "coverage-7.11.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e5f4bfac975a2138215a38bda599ef00162e4143541cf7dd186da10a7f8e69f1"}, - {file = "coverage-7.11.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f4cbfff5cf01fa07464439a8510affc9df281535f41a1f5312fbd2b59b4ab5c"}, - {file = "coverage-7.11.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:31663572f20bf3406d7ac00d6981c7bbbcec302539d26b5ac596ca499664de31"}, - {file = "coverage-7.11.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9799bd6a910961cb666196b8583ed0ee125fa225c6fdee2cbf00232b861f29d2"}, - {file = "coverage-7.11.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:097acc18bedf2c6e3144eaf09b5f6034926c3c9bb9e10574ffd0942717232507"}, - {file = "coverage-7.11.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:6f033dec603eea88204589175782290a038b436105a8f3637a81c4359df27832"}, - {file = "coverage-7.11.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:dd9ca2d44ed8018c90efb72f237a2a140325a4c3339971364d758e78b175f58e"}, - {file = "coverage-7.11.3-cp310-cp310-win32.whl", hash = "sha256:900580bc99c145e2561ea91a2d207e639171870d8a18756eb57db944a017d4bb"}, - {file = "coverage-7.11.3-cp310-cp310-win_amd64.whl", hash = "sha256:c8be5bfcdc7832011b2652db29ed7672ce9d353dd19bce5272ca33dbcf60aaa8"}, - {file = "coverage-7.11.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:200bb89fd2a8a07780eafcdff6463104dec459f3c838d980455cfa84f5e5e6e1"}, - {file = "coverage-7.11.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8d264402fc179776d43e557e1ca4a7d953020d3ee95f7ec19cc2c9d769277f06"}, - {file = "coverage-7.11.3-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:385977d94fc155f8731c895accdfcc3dd0d9dd9ef90d102969df95d3c637ab80"}, - {file = "coverage-7.11.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0542ddf6107adbd2592f29da9f59f5d9cff7947b5bb4f734805085c327dcffaa"}, - {file = "coverage-7.11.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d60bf4d7f886989ddf80e121a7f4d140d9eac91f1d2385ce8eb6bda93d563297"}, - {file = "coverage-7.11.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0a3b6e32457535df0d41d2d895da46434706dd85dbaf53fbc0d3bd7d914b362"}, - {file = "coverage-7.11.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:876a3ee7fd2613eb79602e4cdb39deb6b28c186e76124c3f29e580099ec21a87"}, - {file = "coverage-7.11.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a730cd0824e8083989f304e97b3f884189efb48e2151e07f57e9e138ab104200"}, - {file = "coverage-7.11.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:b5cd111d3ab7390be0c07ad839235d5ad54d2ca497b5f5db86896098a77180a4"}, - {file = "coverage-7.11.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:074e6a5cd38e06671580b4d872c1a67955d4e69639e4b04e87fc03b494c1f060"}, - {file = "coverage-7.11.3-cp311-cp311-win32.whl", hash = "sha256:86d27d2dd7c7c5a44710565933c7dc9cd70e65ef97142e260d16d555667deef7"}, - {file = "coverage-7.11.3-cp311-cp311-win_amd64.whl", hash = "sha256:ca90ef33a152205fb6f2f0c1f3e55c50df4ef049bb0940ebba666edd4cdebc55"}, - {file = "coverage-7.11.3-cp311-cp311-win_arm64.whl", hash = "sha256:56f909a40d68947ef726ce6a34eb38f0ed241ffbe55c5007c64e616663bcbafc"}, - {file = "coverage-7.11.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5b771b59ac0dfb7f139f70c85b42717ef400a6790abb6475ebac1ecee8de782f"}, - {file = "coverage-7.11.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:603c4414125fc9ae9000f17912dcfd3d3eb677d4e360b85206539240c96ea76e"}, - {file = "coverage-7.11.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:77ffb3b7704eb7b9b3298a01fe4509cef70117a52d50bcba29cffc5f53dd326a"}, - {file = "coverage-7.11.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4d4ca49f5ba432b0755ebb0fc3a56be944a19a16bb33802264bbc7311622c0d1"}, - {file = "coverage-7.11.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:05fd3fb6edff0c98874d752013588836f458261e5eba587afe4c547bba544afd"}, - {file = "coverage-7.11.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0e920567f8c3a3ce68ae5a42cf7c2dc4bb6cc389f18bff2235dd8c03fa405de5"}, - {file = "coverage-7.11.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4bec8c7160688bd5a34e65c82984b25409563134d63285d8943d0599efbc448e"}, - {file = "coverage-7.11.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:adb9b7b42c802bd8cb3927de8c1c26368ce50c8fdaa83a9d8551384d77537044"}, - {file = "coverage-7.11.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:c8f563b245b4ddb591e99f28e3cd140b85f114b38b7f95b2e42542f0603eb7d7"}, - {file = "coverage-7.11.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e2a96fdc7643c9517a317553aca13b5cae9bad9a5f32f4654ce247ae4d321405"}, - {file = "coverage-7.11.3-cp312-cp312-win32.whl", hash = "sha256:e8feeb5e8705835f0622af0fe7ff8d5cb388948454647086494d6c41ec142c2e"}, - {file = "coverage-7.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:abb903ffe46bd319d99979cdba350ae7016759bb69f47882242f7b93f3356055"}, - {file = "coverage-7.11.3-cp312-cp312-win_arm64.whl", hash = "sha256:1451464fd855d9bd000c19b71bb7dafea9ab815741fb0bd9e813d9b671462d6f"}, - {file = "coverage-7.11.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84b892e968164b7a0498ddc5746cdf4e985700b902128421bb5cec1080a6ee36"}, - {file = "coverage-7.11.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f761dbcf45e9416ec4698e1a7649248005f0064ce3523a47402d1bff4af2779e"}, - {file = "coverage-7.11.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1410bac9e98afd9623f53876fae7d8a5db9f5a0ac1c9e7c5188463cb4b3212e2"}, - {file = "coverage-7.11.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:004cdcea3457c0ea3233622cd3464c1e32ebba9b41578421097402bee6461b63"}, - {file = "coverage-7.11.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f067ada2c333609b52835ca4d4868645d3b63ac04fb2b9a658c55bba7f667d3"}, - {file = "coverage-7.11.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:07bc7745c945a6d95676953e86ba7cebb9f11de7773951c387f4c07dc76d03f5"}, - {file = "coverage-7.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8bba7e4743e37484ae17d5c3b8eb1ce78b564cb91b7ace2e2182b25f0f764cb5"}, - {file = "coverage-7.11.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbffc22d80d86fbe456af9abb17f7a7766e7b2101f7edaacc3535501691563f7"}, - {file = "coverage-7.11.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:0dba4da36730e384669e05b765a2c49f39514dd3012fcc0398dd66fba8d746d5"}, - {file = "coverage-7.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ae12fe90b00b71a71b69f513773310782ce01d5f58d2ceb2b7c595ab9d222094"}, - {file = "coverage-7.11.3-cp313-cp313-win32.whl", hash = "sha256:12d821de7408292530b0d241468b698bce18dd12ecaf45316149f53877885f8c"}, - {file = "coverage-7.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:6bb599052a974bb6cedfa114f9778fedfad66854107cf81397ec87cb9b8fbcf2"}, - {file = "coverage-7.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:bb9d7efdb063903b3fdf77caec7b77c3066885068bdc0d44bc1b0c171033f944"}, - {file = "coverage-7.11.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:fb58da65e3339b3dbe266b607bb936efb983d86b00b03eb04c4ad5b442c58428"}, - {file = "coverage-7.11.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8d16bbe566e16a71d123cd66382c1315fcd520c7573652a8074a8fe281b38c6a"}, - {file = "coverage-7.11.3-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a8258f10059b5ac837232c589a350a2df4a96406d6d5f2a09ec587cbdd539655"}, - {file = "coverage-7.11.3-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4c5627429f7fbff4f4131cfdd6abd530734ef7761116811a707b88b7e205afd7"}, - {file = "coverage-7.11.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:465695268414e149bab754c54b0c45c8ceda73dd4a5c3ba255500da13984b16d"}, - {file = "coverage-7.11.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4ebcddfcdfb4c614233cff6e9a3967a09484114a8b2e4f2c7a62dc83676ba13f"}, - {file = "coverage-7.11.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:13b2066303a1c1833c654d2af0455bb009b6e1727b3883c9964bc5c2f643c1d0"}, - {file = "coverage-7.11.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d8750dd20362a1b80e3cf84f58013d4672f89663aee457ea59336df50fab6739"}, - {file = "coverage-7.11.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ab6212e62ea0e1006531a2234e209607f360d98d18d532c2fa8e403c1afbdd71"}, - {file = "coverage-7.11.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a6b17c2b5e0b9bb7702449200f93e2d04cb04b1414c41424c08aa1e5d352da76"}, - {file = "coverage-7.11.3-cp313-cp313t-win32.whl", hash = "sha256:426559f105f644b69290ea414e154a0d320c3ad8a2bb75e62884731f69cf8e2c"}, - {file = "coverage-7.11.3-cp313-cp313t-win_amd64.whl", hash = "sha256:90a96fcd824564eae6137ec2563bd061d49a32944858d4bdbae5c00fb10e76ac"}, - {file = "coverage-7.11.3-cp313-cp313t-win_arm64.whl", hash = "sha256:1e33d0bebf895c7a0905fcfaff2b07ab900885fc78bba2a12291a2cfbab014cc"}, - {file = "coverage-7.11.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fdc5255eb4815babcdf236fa1a806ccb546724c8a9b129fd1ea4a5448a0bf07c"}, - {file = "coverage-7.11.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fe3425dc6021f906c6325d3c415e048e7cdb955505a94f1eb774dafc779ba203"}, - {file = "coverage-7.11.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4ca5f876bf41b24378ee67c41d688155f0e54cdc720de8ef9ad6544005899240"}, - {file = "coverage-7.11.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9061a3e3c92b27fd8036dafa26f25d95695b6aa2e4514ab16a254f297e664f83"}, - {file = "coverage-7.11.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:abcea3b5f0dc44e1d01c27090bc32ce6ffb7aa665f884f1890710454113ea902"}, - {file = "coverage-7.11.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:68c4eb92997dbaaf839ea13527be463178ac0ddd37a7ac636b8bc11a51af2428"}, - {file = "coverage-7.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:149eccc85d48c8f06547534068c41d69a1a35322deaa4d69ba1561e2e9127e75"}, - {file = "coverage-7.11.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:08c0bcf932e47795c49f0406054824b9d45671362dfc4269e0bc6e4bff010704"}, - {file = "coverage-7.11.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:39764c6167c82d68a2d8c97c33dba45ec0ad9172570860e12191416f4f8e6e1b"}, - {file = "coverage-7.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3224c7baf34e923ffc78cb45e793925539d640d42c96646db62dbd61bbcfa131"}, - {file = "coverage-7.11.3-cp314-cp314-win32.whl", hash = "sha256:c713c1c528284d636cd37723b0b4c35c11190da6f932794e145fc40f8210a14a"}, - {file = "coverage-7.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:c381a252317f63ca0179d2c7918e83b99a4ff3101e1b24849b999a00f9cd4f86"}, - {file = "coverage-7.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:3e33a968672be1394eded257ec10d4acbb9af2ae263ba05a99ff901bb863557e"}, - {file = "coverage-7.11.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:f9c96a29c6d65bd36a91f5634fef800212dff69dacdb44345c4c9783943ab0df"}, - {file = "coverage-7.11.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2ec27a7a991d229213c8070d31e3ecf44d005d96a9edc30c78eaeafaa421c001"}, - {file = "coverage-7.11.3-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:72c8b494bd20ae1c58528b97c4a67d5cfeafcb3845c73542875ecd43924296de"}, - {file = "coverage-7.11.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:60ca149a446da255d56c2a7a813b51a80d9497a62250532598d249b3cdb1a926"}, - {file = "coverage-7.11.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb5069074db19a534de3859c43eec78e962d6d119f637c41c8e028c5ab3f59dd"}, - {file = "coverage-7.11.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac5d5329c9c942bbe6295f4251b135d860ed9f86acd912d418dce186de7c19ac"}, - {file = "coverage-7.11.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e22539b676fafba17f0a90ac725f029a309eb6e483f364c86dcadee060429d46"}, - {file = "coverage-7.11.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:2376e8a9c889016f25472c452389e98bc6e54a19570b107e27cde9d47f387b64"}, - {file = "coverage-7.11.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:4234914b8c67238a3c4af2bba648dc716aa029ca44d01f3d51536d44ac16854f"}, - {file = "coverage-7.11.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f0b4101e2b3c6c352ff1f70b3a6fcc7c17c1ab1a91ccb7a33013cb0782af9820"}, - {file = "coverage-7.11.3-cp314-cp314t-win32.whl", hash = "sha256:305716afb19133762e8cf62745c46c4853ad6f9eeba54a593e373289e24ea237"}, - {file = "coverage-7.11.3-cp314-cp314t-win_amd64.whl", hash = "sha256:9245bd392572b9f799261c4c9e7216bafc9405537d0f4ce3ad93afe081a12dc9"}, - {file = "coverage-7.11.3-cp314-cp314t-win_arm64.whl", hash = "sha256:9a1d577c20b4334e5e814c3d5fe07fa4a8c3ae42a601945e8d7940bab811d0bd"}, - {file = "coverage-7.11.3-py3-none-any.whl", hash = "sha256:351511ae28e2509c8d8cae5311577ea7dd511ab8e746ffc8814a0896c3d33fbe"}, - {file = "coverage-7.11.3.tar.gz", hash = "sha256:0f59387f5e6edbbffec2281affb71cdc85e0776c1745150a3ab9b6c1d016106b"}, + {file = "coverage-7.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:32b75c2ba3f324ee37af3ccee5b30458038c50b349ad9b88cee85096132a575b"}, + {file = "coverage-7.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cb2a1b6ab9fe833714a483a915de350abc624a37149649297624c8d57add089c"}, + {file = "coverage-7.12.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5734b5d913c3755e72f70bf6cc37a0518d4f4745cde760c5d8e12005e62f9832"}, + {file = "coverage-7.12.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b527a08cdf15753279b7afb2339a12073620b761d79b81cbe2cdebdb43d90daa"}, + {file = "coverage-7.12.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bb44c889fb68004e94cab71f6a021ec83eac9aeabdbb5a5a88821ec46e1da73"}, + {file = "coverage-7.12.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4b59b501455535e2e5dde5881739897967b272ba25988c89145c12d772810ccb"}, + {file = "coverage-7.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d8842f17095b9868a05837b7b1b73495293091bed870e099521ada176aa3e00e"}, + {file = "coverage-7.12.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c5a6f20bf48b8866095c6820641e7ffbe23f2ac84a2efc218d91235e404c7777"}, + {file = "coverage-7.12.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:5f3738279524e988d9da2893f307c2093815c623f8d05a8f79e3eff3a7a9e553"}, + {file = "coverage-7.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0d68c1f7eabbc8abe582d11fa393ea483caf4f44b0af86881174769f185c94d"}, + {file = "coverage-7.12.0-cp310-cp310-win32.whl", hash = "sha256:7670d860e18b1e3ee5930b17a7d55ae6287ec6e55d9799982aa103a2cc1fa2ef"}, + {file = "coverage-7.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:f999813dddeb2a56aab5841e687b68169da0d3f6fc78ccf50952fa2463746022"}, + {file = "coverage-7.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa124a3683d2af98bd9d9c2bfa7a5076ca7e5ab09fdb96b81fa7d89376ae928f"}, + {file = "coverage-7.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d93fbf446c31c0140208dcd07c5d882029832e8ed7891a39d6d44bd65f2316c3"}, + {file = "coverage-7.12.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:52ca620260bd8cd6027317bdd8b8ba929be1d741764ee765b42c4d79a408601e"}, + {file = "coverage-7.12.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f3433ffd541380f3a0e423cff0f4926d55b0cc8c1d160fdc3be24a4c03aa65f7"}, + {file = "coverage-7.12.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7bbb321d4adc9f65e402c677cd1c8e4c2d0105d3ce285b51b4d87f1d5db5245"}, + {file = "coverage-7.12.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:22a7aade354a72dff3b59c577bfd18d6945c61f97393bc5fb7bd293a4237024b"}, + {file = "coverage-7.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3ff651dcd36d2fea66877cd4a82de478004c59b849945446acb5baf9379a1b64"}, + {file = "coverage-7.12.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:31b8b2e38391a56e3cea39d22a23faaa7c3fc911751756ef6d2621d2a9daf742"}, + {file = "coverage-7.12.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:297bc2da28440f5ae51c845a47c8175a4db0553a53827886e4fb25c66633000c"}, + {file = "coverage-7.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6ff7651cc01a246908eac162a6a86fc0dbab6de1ad165dfb9a1e2ec660b44984"}, + {file = "coverage-7.12.0-cp311-cp311-win32.whl", hash = "sha256:313672140638b6ddb2c6455ddeda41c6a0b208298034544cfca138978c6baed6"}, + {file = "coverage-7.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a1783ed5bd0d5938d4435014626568dc7f93e3cb99bc59188cc18857c47aa3c4"}, + {file = "coverage-7.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:4648158fd8dd9381b5847622df1c90ff314efbfc1df4550092ab6013c238a5fc"}, + {file = "coverage-7.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:29644c928772c78512b48e14156b81255000dcfd4817574ff69def189bcb3647"}, + {file = "coverage-7.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8638cbb002eaa5d7c8d04da667813ce1067080b9a91099801a0053086e52b736"}, + {file = "coverage-7.12.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:083631eeff5eb9992c923e14b810a179798bb598e6a0dd60586819fc23be6e60"}, + {file = "coverage-7.12.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:99d5415c73ca12d558e07776bd957c4222c687b9f1d26fa0e1b57e3598bdcde8"}, + {file = "coverage-7.12.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e949ebf60c717c3df63adb4a1a366c096c8d7fd8472608cd09359e1bd48ef59f"}, + {file = "coverage-7.12.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d907ddccbca819afa2cd014bc69983b146cca2735a0b1e6259b2a6c10be1e70"}, + {file = "coverage-7.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b1518ecbad4e6173f4c6e6c4a46e49555ea5679bf3feda5edb1b935c7c44e8a0"}, + {file = "coverage-7.12.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:51777647a749abdf6f6fd8c7cffab12de68ab93aab15efc72fbbb83036c2a068"}, + {file = "coverage-7.12.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:42435d46d6461a3b305cdfcad7cdd3248787771f53fe18305548cba474e6523b"}, + {file = "coverage-7.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5bcead88c8423e1855e64b8057d0544e33e4080b95b240c2a355334bb7ced937"}, + {file = "coverage-7.12.0-cp312-cp312-win32.whl", hash = "sha256:dcbb630ab034e86d2a0f79aefd2be07e583202f41e037602d438c80044957baa"}, + {file = "coverage-7.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:2fd8354ed5d69775ac42986a691fbf68b4084278710cee9d7c3eaa0c28fa982a"}, + {file = "coverage-7.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:737c3814903be30695b2de20d22bcc5428fdae305c61ba44cdc8b3252984c49c"}, + {file = "coverage-7.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:47324fffca8d8eae7e185b5bb20c14645f23350f870c1649003618ea91a78941"}, + {file = "coverage-7.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ccf3b2ede91decd2fb53ec73c1f949c3e034129d1e0b07798ff1d02ea0c8fa4a"}, + {file = "coverage-7.12.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b365adc70a6936c6b0582dc38746b33b2454148c02349345412c6e743efb646d"}, + {file = "coverage-7.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc13baf85cd8a4cfcf4a35c7bc9d795837ad809775f782f697bf630b7e200211"}, + {file = "coverage-7.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:099d11698385d572ceafb3288a5b80fe1fc58bf665b3f9d362389de488361d3d"}, + {file = "coverage-7.12.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:473dc45d69694069adb7680c405fb1e81f60b2aff42c81e2f2c3feaf544d878c"}, + {file = "coverage-7.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:583f9adbefd278e9de33c33d6846aa8f5d164fa49b47144180a0e037f0688bb9"}, + {file = "coverage-7.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2089cc445f2dc0af6f801f0d1355c025b76c24481935303cf1af28f636688f0"}, + {file = "coverage-7.12.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:950411f1eb5d579999c5f66c62a40961f126fc71e5e14419f004471957b51508"}, + {file = "coverage-7.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b1aab7302a87bafebfe76b12af681b56ff446dc6f32ed178ff9c092ca776e6bc"}, + {file = "coverage-7.12.0-cp313-cp313-win32.whl", hash = "sha256:d7e0d0303c13b54db495eb636bc2465b2fb8475d4c8bcec8fe4b5ca454dfbae8"}, + {file = "coverage-7.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:ce61969812d6a98a981d147d9ac583a36ac7db7766f2e64a9d4d059c2fe29d07"}, + {file = "coverage-7.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bcec6f47e4cb8a4c2dc91ce507f6eefc6a1b10f58df32cdc61dff65455031dfc"}, + {file = "coverage-7.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:459443346509476170d553035e4a3eed7b860f4fe5242f02de1010501956ce87"}, + {file = "coverage-7.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:04a79245ab2b7a61688958f7a855275997134bc84f4a03bc240cf64ff132abf6"}, + {file = "coverage-7.12.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:09a86acaaa8455f13d6a99221d9654df249b33937b4e212b4e5a822065f12aa7"}, + {file = "coverage-7.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:907e0df1b71ba77463687a74149c6122c3f6aac56c2510a5d906b2f368208560"}, + {file = "coverage-7.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b57e2d0ddd5f0582bae5437c04ee71c46cd908e7bc5d4d0391f9a41e812dd12"}, + {file = "coverage-7.12.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:58c1c6aa677f3a1411fe6fb28ec3a942e4f665df036a3608816e0847fad23296"}, + {file = "coverage-7.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4c589361263ab2953e3c4cd2a94db94c4ad4a8e572776ecfbad2389c626e4507"}, + {file = "coverage-7.12.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:91b810a163ccad2e43b1faa11d70d3cf4b6f3d83f9fd5f2df82a32d47b648e0d"}, + {file = "coverage-7.12.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:40c867af715f22592e0d0fb533a33a71ec9e0f73a6945f722a0c85c8c1cbe3a2"}, + {file = "coverage-7.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:68b0d0a2d84f333de875666259dadf28cc67858bc8fd8b3f1eae84d3c2bec455"}, + {file = "coverage-7.12.0-cp313-cp313t-win32.whl", hash = "sha256:73f9e7fbd51a221818fd11b7090eaa835a353ddd59c236c57b2199486b116c6d"}, + {file = "coverage-7.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:24cff9d1f5743f67db7ba46ff284018a6e9aeb649b67aa1e70c396aa1b7cb23c"}, + {file = "coverage-7.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c87395744f5c77c866d0f5a43d97cc39e17c7f1cb0115e54a2fe67ca75c5d14d"}, + {file = "coverage-7.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a1c59b7dc169809a88b21a936eccf71c3895a78f5592051b1af8f4d59c2b4f92"}, + {file = "coverage-7.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8787b0f982e020adb732b9f051f3e49dd5054cebbc3f3432061278512a2b1360"}, + {file = "coverage-7.12.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5ea5a9f7dc8877455b13dd1effd3202e0bca72f6f3ab09f9036b1bcf728f69ac"}, + {file = "coverage-7.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fdba9f15849534594f60b47c9a30bc70409b54947319a7c4fd0e8e3d8d2f355d"}, + {file = "coverage-7.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a00594770eb715854fb1c57e0dea08cce6720cfbc531accdb9850d7c7770396c"}, + {file = "coverage-7.12.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5560c7e0d82b42eb1951e4f68f071f8017c824ebfd5a6ebe42c60ac16c6c2434"}, + {file = "coverage-7.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2e26b481c9159c2773a37947a9718cfdc58893029cdfb177531793e375cfc"}, + {file = "coverage-7.12.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:6e1a8c066dabcde56d5d9fed6a66bc19a2883a3fe051f0c397a41fc42aedd4cc"}, + {file = "coverage-7.12.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f7ba9da4726e446d8dd8aae5a6cd872511184a5d861de80a86ef970b5dacce3e"}, + {file = "coverage-7.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e0f483ab4f749039894abaf80c2f9e7ed77bbf3c737517fb88c8e8e305896a17"}, + {file = "coverage-7.12.0-cp314-cp314-win32.whl", hash = "sha256:76336c19a9ef4a94b2f8dc79f8ac2da3f193f625bb5d6f51a328cd19bfc19933"}, + {file = "coverage-7.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c1059b600aec6ef090721f8f633f60ed70afaffe8ecab85b59df748f24b31fe"}, + {file = "coverage-7.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:172cf3a34bfef42611963e2b661302a8931f44df31629e5b1050567d6b90287d"}, + {file = "coverage-7.12.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:aa7d48520a32cb21c7a9b31f81799e8eaec7239db36c3b670be0fa2403828d1d"}, + {file = "coverage-7.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:90d58ac63bc85e0fb919f14d09d6caa63f35a5512a2205284b7816cafd21bb03"}, + {file = "coverage-7.12.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ca8ecfa283764fdda3eae1bdb6afe58bf78c2c3ec2b2edcb05a671f0bba7b3f9"}, + {file = "coverage-7.12.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:874fe69a0785d96bd066059cd4368022cebbec1a8958f224f0016979183916e6"}, + {file = "coverage-7.12.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b3c889c0b8b283a24d721a9eabc8ccafcfc3aebf167e4cd0d0e23bf8ec4e339"}, + {file = "coverage-7.12.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bb5b894b3ec09dcd6d3743229dc7f2c42ef7787dc40596ae04c0edda487371e"}, + {file = "coverage-7.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:79a44421cd5fba96aa57b5e3b5a4d3274c449d4c622e8f76882d76635501fd13"}, + {file = "coverage-7.12.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:33baadc0efd5c7294f436a632566ccc1f72c867f82833eb59820ee37dc811c6f"}, + {file = "coverage-7.12.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c406a71f544800ef7e9e0000af706b88465f3573ae8b8de37e5f96c59f689ad1"}, + {file = "coverage-7.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e71bba6a40883b00c6d571599b4627f50c360b3d0d02bfc658168936be74027b"}, + {file = "coverage-7.12.0-cp314-cp314t-win32.whl", hash = "sha256:9157a5e233c40ce6613dead4c131a006adfda70e557b6856b97aceed01b0e27a"}, + {file = "coverage-7.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e84da3a0fd233aeec797b981c51af1cabac74f9bd67be42458365b30d11b5291"}, + {file = "coverage-7.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:01d24af36fedda51c2b1aca56e4330a3710f83b02a5ff3743a6b015ffa7c9384"}, + {file = "coverage-7.12.0-py3-none-any.whl", hash = "sha256:159d50c0b12e060b15ed3d39f87ed43d4f7f7ad40b8a534f4dd331adbb51104a"}, + {file = "coverage-7.12.0.tar.gz", hash = "sha256:fc11e0a4e372cb5f282f16ef90d4a585034050ccda536451901abfb19a57f40c"}, ] [package.extras] @@ -588,20 +587,20 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "fastapi" -version = "0.121.2" +version = "0.123.9" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "fastapi-0.121.2-py3-none-any.whl", hash = "sha256:f2d80b49a86a846b70cc3a03eb5ea6ad2939298bf6a7fe377aa9cd3dd079d358"}, - {file = "fastapi-0.121.2.tar.gz", hash = "sha256:ca8e932b2b823ec1721c641e3669472c855ad9564a2854c9899d904c2848b8b9"}, + {file = "fastapi-0.123.9-py3-none-any.whl", hash = "sha256:f54c69f23db14bd3dbcdfaf3fdce0483ca5f499512380c8e379a70cda30aa920"}, + {file = "fastapi-0.123.9.tar.gz", hash = "sha256:ab33d672d8e1cc6e0b49777eb73c32ccf20761011f5ca16755889ab406fd1de0"}, ] [package.dependencies] annotated-doc = ">=0.0.2" pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" -starlette = ">=0.40.0,<0.50.0" +starlette = ">=0.40.0,<0.51.0" typing-extensions = ">=4.8.0" [package.extras] @@ -1038,22 +1037,24 @@ files = [ [[package]] name = "networkx" -version = "3.5" +version = "3.6" description = "Python package for creating and manipulating graphs and networks" optional = false python-versions = ">=3.11" groups = ["main"] files = [ - {file = "networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec"}, - {file = "networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037"}, + {file = "networkx-3.6-py3-none-any.whl", hash = "sha256:cdb395b105806062473d3be36458d8f1459a4e4b98e236a66c3a48996e07684f"}, + {file = "networkx-3.6.tar.gz", hash = "sha256:285276002ad1f7f7da0f7b42f004bcba70d381e936559166363707fdad3d72ad"}, ] [package.extras] +benchmarking = ["asv", "virtualenv"] default = ["matplotlib (>=3.8)", "numpy (>=1.25)", "pandas (>=2.0)", "scipy (>=1.11.2)"] developer = ["mypy (>=1.15)", "pre-commit (>=4.1)"] doc = ["intersphinx-registry", "myst-nb (>=1.1)", "numpydoc (>=1.8.0)", "pillow (>=10)", "pydata-sphinx-theme (>=0.16)", "sphinx (>=8.0)", "sphinx-gallery (>=0.18)", "texext (>=0.6.7)"] -example = ["cairocffi (>=1.7)", "contextily (>=1.6)", "igraph (>=0.11)", "momepy (>=0.7.2)", "osmnx (>=2.0.0)", "scikit-learn (>=1.5)", "seaborn (>=0.13)"] +example = ["cairocffi (>=1.7)", "contextily (>=1.6)", "igraph (>=0.11)", "iplotx (>=0.9.0)", "momepy (>=0.7.2)", "osmnx (>=2.0.0)", "scikit-learn (>=1.5)", "seaborn (>=0.13)"] extra = ["lxml (>=4.6)", "pydot (>=3.0.1)", "pygraphviz (>=1.14)", "sympy (>=1.10)"] +release = ["build (>=0.10)", "changelist (==0.5)", "twine (>=4.0)", "wheel (>=0.40)"] test = ["pytest (>=7.2)", "pytest-cov (>=4.0)", "pytest-xdist (>=3.0)"] test-extras = ["pytest-mpl", "pytest-randomly"] @@ -1155,14 +1156,14 @@ files = [ [[package]] name = "opencloning-linkml" -version = "0.4.8" +version = "0.4.9" description = "A LinkML data model for OpenCloning" optional = false python-versions = "<4.0,>=3.10" groups = ["main"] files = [ - {file = "opencloning_linkml-0.4.8-py3-none-any.whl", hash = "sha256:31e186ede9879a5d647f6b2ade0b46e443fe30450b9af1cd46152360b7fe3ba3"}, - {file = "opencloning_linkml-0.4.8.tar.gz", hash = "sha256:63969677a2a8c850a2261196a3a47793c9bdcc7d37931cf6eb4aed22845484dc"}, + {file = "opencloning_linkml-0.4.9-py3-none-any.whl", hash = "sha256:1adcaffacf167c90475b23c4e134093db369af73be27d2b9ac9ab3cfeb39a7f1"}, + {file = "opencloning_linkml-0.4.9.tar.gz", hash = "sha256:a243d1875df0bf7b3c9487770cd64c0db25c84254a292e2dcea94d9598e9717c"}, ] [package.dependencies] @@ -1355,14 +1356,14 @@ ptyprocess = ">=0.5" [[package]] name = "platformdirs" -version = "4.5.0" +version = "4.5.1" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.10" groups = ["dev", "ipython", "test"] files = [ - {file = "platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3"}, - {file = "platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312"}, + {file = "platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31"}, + {file = "platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda"}, ] [package.extras] @@ -1560,14 +1561,14 @@ files = [ [[package]] name = "pydantic" -version = "2.12.4" +version = "2.12.5" description = "Data validation using Python type hints" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pydantic-2.12.4-py3-none-any.whl", hash = "sha256:92d3d202a745d46f9be6df459ac5a064fdaa3c1c4cd8adcfa332ccf3c05f871e"}, - {file = "pydantic-2.12.4.tar.gz", hash = "sha256:0f8cb9555000a4b5b617f66bfd2566264c4984b27589d3b845685983e8ea85ac"}, + {file = "pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d"}, + {file = "pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49"}, ] [package.dependencies] @@ -1761,7 +1762,7 @@ wheel = "*" [[package]] name = "pydna" -version = "5.5.4-post.16+e95e8603" +version = "5.5.4-post.22+6f25090e" description = "Representing double stranded DNA and functions for simulating cloning and homologous recombination between DNA molecules." optional = false python-versions = ">=3.10,<4.0" @@ -1777,7 +1778,7 @@ numpy = [ {version = ">1.26", markers = "python_version < \"3.12\""}, {version = ">=2.3.0", markers = "python_version >= \"3.12\""}, ] -opencloning-linkml = "^0.4.5" +opencloning-linkml = "^0.4.9" prettytable = ">=3.5.0" pydivsufsort = ">=0.0.14" pyfiglet = "0.8.post1" @@ -1788,13 +1789,13 @@ seguid = ">=0.0.5" clipboard = ["pyperclip (>=1.8.2)"] download = ["pyparsing (>=2.4.7)", "requests (>=2.26.0)"] express = ["cai2 (>=1.0.5)"] -gel = ["matplotlib (>=3.4.3)", "pillow (>=8.4.0)", "scipy (>=1.11.3)", "scipy (>=1.9.3)"] +gel = ["matplotlib (>=3.4.3)", "pillow (>=8.4.0)", "scipy (>=1.11.3) ; python_version >= \"3.12\"", "scipy (>=1.9.3) ; python_version < \"3.12\""] [package.source] type = "git" url = "https://github.com/pydna-group/pydna" -reference = "e95e8603b082e50b7873eab0ae1f8abf7b4d25bc" -resolved_reference = "e95e8603b082e50b7873eab0ae1f8abf7b4d25bc" +reference = "6f25090ec653e38219021aa46fa4440f888e958c" +resolved_reference = "6f25090ec653e38219021aa46fa4440f888e958c" [[package]] name = "pyfiglet" @@ -2256,127 +2257,127 @@ httpx = ">=0.25.0" [[package]] name = "rpds-py" -version = "0.29.0" +version = "0.30.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "rpds_py-0.29.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4ae4b88c6617e1b9e5038ab3fccd7bac0842fdda2b703117b2aa99bc85379113"}, - {file = "rpds_py-0.29.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7d9128ec9d8cecda6f044001fde4fb71ea7c24325336612ef8179091eb9596b9"}, - {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37812c3da8e06f2bb35b3cf10e4a7b68e776a706c13058997238762b4e07f4f"}, - {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:66786c3fb1d8de416a7fa8e1cb1ec6ba0a745b2b0eee42f9b7daa26f1a495545"}, - {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58f5c77f1af888b5fd1876c9a0d9858f6f88a39c9dd7c073a88e57e577da66d"}, - {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:799156ef1f3529ed82c36eb012b5d7a4cf4b6ef556dd7cc192148991d07206ae"}, - {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:453783477aa4f2d9104c4b59b08c871431647cb7af51b549bbf2d9eb9c827756"}, - {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:24a7231493e3c4a4b30138b50cca089a598e52c34cf60b2f35cebf62f274fdea"}, - {file = "rpds_py-0.29.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7033c1010b1f57bb44d8067e8c25aa6fa2e944dbf46ccc8c92b25043839c3fd2"}, - {file = "rpds_py-0.29.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0248b19405422573621172ab8e3a1f29141362d13d9f72bafa2e28ea0cdca5a2"}, - {file = "rpds_py-0.29.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f9f436aee28d13b9ad2c764fc273e0457e37c2e61529a07b928346b219fcde3b"}, - {file = "rpds_py-0.29.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24a16cb7163933906c62c272de20ea3c228e4542c8c45c1d7dc2b9913e17369a"}, - {file = "rpds_py-0.29.0-cp310-cp310-win32.whl", hash = "sha256:1a409b0310a566bfd1be82119891fefbdce615ccc8aa558aff7835c27988cbef"}, - {file = "rpds_py-0.29.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5523b0009e7c3c1263471b69d8da1c7d41b3ecb4cb62ef72be206b92040a950"}, - {file = "rpds_py-0.29.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9b9c764a11fd637e0322a488560533112837f5334ffeb48b1be20f6d98a7b437"}, - {file = "rpds_py-0.29.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3fd2164d73812026ce970d44c3ebd51e019d2a26a4425a5dcbdfa93a34abc383"}, - {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a097b7f7f7274164566ae90a221fd725363c0e9d243e2e9ed43d195ccc5495c"}, - {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7cdc0490374e31cedefefaa1520d5fe38e82fde8748cbc926e7284574c714d6b"}, - {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89ca2e673ddd5bde9b386da9a0aac0cab0e76f40c8f0aaf0d6311b6bbf2aa311"}, - {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5d9da3ff5af1ca1249b1adb8ef0573b94c76e6ae880ba1852f033bf429d4588"}, - {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8238d1d310283e87376c12f658b61e1ee23a14c0e54c7c0ce953efdbdc72deed"}, - {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:2d6fb2ad1c36f91c4646989811e84b1ea5e0c3cf9690b826b6e32b7965853a63"}, - {file = "rpds_py-0.29.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:534dc9df211387547267ccdb42253aa30527482acb38dd9b21c5c115d66a96d2"}, - {file = "rpds_py-0.29.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d456e64724a075441e4ed648d7f154dc62e9aabff29bcdf723d0c00e9e1d352f"}, - {file = "rpds_py-0.29.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a738f2da2f565989401bd6fd0b15990a4d1523c6d7fe83f300b7e7d17212feca"}, - {file = "rpds_py-0.29.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a110e14508fd26fd2e472bb541f37c209409876ba601cf57e739e87d8a53cf95"}, - {file = "rpds_py-0.29.0-cp311-cp311-win32.whl", hash = "sha256:923248a56dd8d158389a28934f6f69ebf89f218ef96a6b216a9be6861804d3f4"}, - {file = "rpds_py-0.29.0-cp311-cp311-win_amd64.whl", hash = "sha256:539eb77eb043afcc45314d1be09ea6d6cafb3addc73e0547c171c6d636957f60"}, - {file = "rpds_py-0.29.0-cp311-cp311-win_arm64.whl", hash = "sha256:bdb67151ea81fcf02d8f494703fb728d4d34d24556cbff5f417d74f6f5792e7c"}, - {file = "rpds_py-0.29.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a0891cfd8db43e085c0ab93ab7e9b0c8fee84780d436d3b266b113e51e79f954"}, - {file = "rpds_py-0.29.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3897924d3f9a0361472d884051f9a2460358f9a45b1d85a39a158d2f8f1ad71c"}, - {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a21deb8e0d1571508c6491ce5ea5e25669b1dd4adf1c9d64b6314842f708b5d"}, - {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9efe71687d6427737a0a2de9ca1c0a216510e6cd08925c44162be23ed7bed2d5"}, - {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:40f65470919dc189c833e86b2c4bd21bd355f98436a2cef9e0a9a92aebc8e57e"}, - {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:def48ff59f181130f1a2cb7c517d16328efac3ec03951cca40c1dc2049747e83"}, - {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad7bd570be92695d89285a4b373006930715b78d96449f686af422debb4d3949"}, - {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:5a572911cd053137bbff8e3a52d31c5d2dba51d3a67ad902629c70185f3f2181"}, - {file = "rpds_py-0.29.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d583d4403bcbf10cffc3ab5cee23d7643fcc960dff85973fd3c2d6c86e8dbb0c"}, - {file = "rpds_py-0.29.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:070befbb868f257d24c3bb350dbd6e2f645e83731f31264b19d7231dd5c396c7"}, - {file = "rpds_py-0.29.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fc935f6b20b0c9f919a8ff024739174522abd331978f750a74bb68abd117bd19"}, - {file = "rpds_py-0.29.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8c5a8ecaa44ce2d8d9d20a68a2483a74c07f05d72e94a4dff88906c8807e77b0"}, - {file = "rpds_py-0.29.0-cp312-cp312-win32.whl", hash = "sha256:ba5e1aeaf8dd6d8f6caba1f5539cddda87d511331714b7b5fc908b6cfc3636b7"}, - {file = "rpds_py-0.29.0-cp312-cp312-win_amd64.whl", hash = "sha256:b5f6134faf54b3cb83375db0f113506f8b7770785be1f95a631e7e2892101977"}, - {file = "rpds_py-0.29.0-cp312-cp312-win_arm64.whl", hash = "sha256:b016eddf00dca7944721bf0cd85b6af7f6c4efaf83ee0b37c4133bd39757a8c7"}, - {file = "rpds_py-0.29.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1585648d0760b88292eecab5181f5651111a69d90eff35d6b78aa32998886a61"}, - {file = "rpds_py-0.29.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:521807963971a23996ddaf764c682b3e46459b3c58ccd79fefbe16718db43154"}, - {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a8896986efaa243ab713c69e6491a4138410f0fe36f2f4c71e18bd5501e8014"}, - {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1d24564a700ef41480a984c5ebed62b74e6ce5860429b98b1fede76049e953e6"}, - {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6596b93c010d386ae46c9fba9bfc9fc5965fa8228edeac51576299182c2e31c"}, - {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5cc58aac218826d054c7da7f95821eba94125d88be673ff44267bb89d12a5866"}, - {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de73e40ebc04dd5d9556f50180395322193a78ec247e637e741c1b954810f295"}, - {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:295ce5ac7f0cf69a651ea75c8f76d02a31f98e5698e82a50a5f4d4982fbbae3b"}, - {file = "rpds_py-0.29.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1ea59b23ea931d494459c8338056fe7d93458c0bf3ecc061cd03916505369d55"}, - {file = "rpds_py-0.29.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f49d41559cebd608042fdcf54ba597a4a7555b49ad5c1c0c03e0af82692661cd"}, - {file = "rpds_py-0.29.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:05a2bd42768ea988294ca328206efbcc66e220d2d9b7836ee5712c07ad6340ea"}, - {file = "rpds_py-0.29.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33ca7bdfedd83339ca55da3a5e1527ee5870d4b8369456b5777b197756f3ca22"}, - {file = "rpds_py-0.29.0-cp313-cp313-win32.whl", hash = "sha256:20c51ae86a0bb9accc9ad4e6cdeec58d5ebb7f1b09dd4466331fc65e1766aae7"}, - {file = "rpds_py-0.29.0-cp313-cp313-win_amd64.whl", hash = "sha256:6410e66f02803600edb0b1889541f4b5cc298a5ccda0ad789cc50ef23b54813e"}, - {file = "rpds_py-0.29.0-cp313-cp313-win_arm64.whl", hash = "sha256:56838e1cd9174dc23c5691ee29f1d1be9eab357f27efef6bded1328b23e1ced2"}, - {file = "rpds_py-0.29.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:37d94eadf764d16b9a04307f2ab1d7af6dc28774bbe0535c9323101e14877b4c"}, - {file = "rpds_py-0.29.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d472cf73efe5726a067dce63eebe8215b14beabea7c12606fd9994267b3cfe2b"}, - {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72fdfd5ff8992e4636621826371e3ac5f3e3b8323e9d0e48378e9c13c3dac9d0"}, - {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2549d833abdf8275c901313b9e8ff8fba57e50f6a495035a2a4e30621a2f7cc4"}, - {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4448dad428f28a6a767c3e3b80cde3446a22a0efbddaa2360f4bb4dc836d0688"}, - {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:115f48170fd4296a33938d8c11f697f5f26e0472e43d28f35624764173a60e4d"}, - {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e5bb73ffc029820f4348e9b66b3027493ae00bca6629129cd433fd7a76308ee"}, - {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:b1581fcde18fcdf42ea2403a16a6b646f8eb1e58d7f90a0ce693da441f76942e"}, - {file = "rpds_py-0.29.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16e9da2bda9eb17ea318b4c335ec9ac1818e88922cbe03a5743ea0da9ecf74fb"}, - {file = "rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:28fd300326dd21198f311534bdb6d7e989dd09b3418b3a91d54a0f384c700967"}, - {file = "rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2aba991e041d031c7939e1358f583ae405a7bf04804ca806b97a5c0e0af1ea5e"}, - {file = "rpds_py-0.29.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f437026dbbc3f08c99cc41a5b2570c6e1a1ddbe48ab19a9b814254128d4ea7a"}, - {file = "rpds_py-0.29.0-cp313-cp313t-win32.whl", hash = "sha256:6e97846e9800a5d0fe7be4d008f0c93d0feeb2700da7b1f7528dabafb31dfadb"}, - {file = "rpds_py-0.29.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f49196aec7c4b406495f60e6f947ad71f317a765f956d74bbd83996b9edc0352"}, - {file = "rpds_py-0.29.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:394d27e4453d3b4d82bb85665dc1fcf4b0badc30fc84282defed71643b50e1a1"}, - {file = "rpds_py-0.29.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:55d827b2ae95425d3be9bc9a5838b6c29d664924f98146557f7715e331d06df8"}, - {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc31a07ed352e5462d3ee1b22e89285f4ce97d5266f6d1169da1142e78045626"}, - {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c4695dd224212f6105db7ea62197144230b808d6b2bba52238906a2762f1d1e7"}, - {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcae1770b401167f8b9e1e3f566562e6966ffa9ce63639916248a9e25fa8a244"}, - {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:90f30d15f45048448b8da21c41703b31c61119c06c216a1bf8c245812a0f0c17"}, - {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44a91e0ab77bdc0004b43261a4b8cd6d6b451e8d443754cfda830002b5745b32"}, - {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:4aa195e5804d32c682e453b34474f411ca108e4291c6a0f824ebdc30a91c973c"}, - {file = "rpds_py-0.29.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7971bdb7bf4ee0f7e6f67fa4c7fbc6019d9850cc977d126904392d363f6f8318"}, - {file = "rpds_py-0.29.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8ae33ad9ce580c7a47452c3b3f7d8a9095ef6208e0a0c7e4e2384f9fc5bf8212"}, - {file = "rpds_py-0.29.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c661132ab2fb4eeede2ef69670fd60da5235209874d001a98f1542f31f2a8a94"}, - {file = "rpds_py-0.29.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bb78b3a0d31ac1bde132c67015a809948db751cb4e92cdb3f0b242e430b6ed0d"}, - {file = "rpds_py-0.29.0-cp314-cp314-win32.whl", hash = "sha256:f475f103488312e9bd4000bc890a95955a07b2d0b6e8884aef4be56132adbbf1"}, - {file = "rpds_py-0.29.0-cp314-cp314-win_amd64.whl", hash = "sha256:b9cf2359a4fca87cfb6801fae83a76aedf66ee1254a7a151f1341632acf67f1b"}, - {file = "rpds_py-0.29.0-cp314-cp314-win_arm64.whl", hash = "sha256:9ba8028597e824854f0f1733d8b964e914ae3003b22a10c2c664cb6927e0feb9"}, - {file = "rpds_py-0.29.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:e71136fd0612556b35c575dc2726ae04a1669e6a6c378f2240312cf5d1a2ab10"}, - {file = "rpds_py-0.29.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:76fe96632d53f3bf0ea31ede2f53bbe3540cc2736d4aec3b3801b0458499ef3a"}, - {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9459a33f077130dbb2c7c3cea72ee9932271fb3126404ba2a2661e4fe9eb7b79"}, - {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5c9546cfdd5d45e562cc0444b6dddc191e625c62e866bf567a2c69487c7ad28a"}, - {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12597d11d97b8f7e376c88929a6e17acb980e234547c92992f9f7c058f1a7310"}, - {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28de03cf48b8a9e6ec10318f2197b83946ed91e2891f651a109611be4106ac4b"}, - {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd7951c964069039acc9d67a8ff1f0a7f34845ae180ca542b17dc1456b1f1808"}, - {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:c07d107b7316088f1ac0177a7661ca0c6670d443f6fe72e836069025e6266761"}, - {file = "rpds_py-0.29.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1de2345af363d25696969befc0c1688a6cb5e8b1d32b515ef84fc245c6cddba3"}, - {file = "rpds_py-0.29.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:00e56b12d2199ca96068057e1ae7f9998ab6e99cda82431afafd32f3ec98cca9"}, - {file = "rpds_py-0.29.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3919a3bbecee589300ed25000b6944174e07cd20db70552159207b3f4bbb45b8"}, - {file = "rpds_py-0.29.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7fa2ccc312bbd91e43aa5e0869e46bc03278a3dddb8d58833150a18b0f0283a"}, - {file = "rpds_py-0.29.0-cp314-cp314t-win32.whl", hash = "sha256:97c817863ffc397f1e6a6e9d2d89fe5408c0a9922dac0329672fb0f35c867ea5"}, - {file = "rpds_py-0.29.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2023473f444752f0f82a58dfcbee040d0a1b3d1b3c2ec40e884bd25db6d117d2"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:acd82a9e39082dc5f4492d15a6b6c8599aa21db5c35aaf7d6889aea16502c07d"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:715b67eac317bf1c7657508170a3e011a1ea6ccb1c9d5f296e20ba14196be6b3"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3b1b87a237cb2dba4db18bcfaaa44ba4cd5936b91121b62292ff21df577fc43"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1c3c3e8101bb06e337c88eb0c0ede3187131f19d97d43ea0e1c5407ea74c0cbf"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8e54d6e61f3ecd3abe032065ce83ea63417a24f437e4a3d73d2f85ce7b7cfe"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3fbd4e9aebf110473a420dea85a238b254cf8a15acb04b22a5a6b5ce8925b760"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80fdf53d36e6c72819993e35d1ebeeb8e8fc688d0c6c2b391b55e335b3afba5a"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:ea7173df5d86f625f8dde6d5929629ad811ed8decda3b60ae603903839ac9ac0"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:76054d540061eda273274f3d13a21a4abdde90e13eaefdc205db37c05230efce"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:9f84c549746a5be3bc7415830747a3a0312573afc9f95785eb35228bb17742ec"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:0ea962671af5cb9a260489e311fa22b2e97103e3f9f0caaea6f81390af96a9ed"}, - {file = "rpds_py-0.29.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:f7728653900035fb7b8d06e1e5900545d8088efc9d5d4545782da7df03ec803f"}, - {file = "rpds_py-0.29.0.tar.gz", hash = "sha256:fe55fe686908f50154d1dc599232016e50c243b438c3b7432f24e2895b0e5359"}, + {file = "rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288"}, + {file = "rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7"}, + {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff"}, + {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7"}, + {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139"}, + {file = "rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464"}, + {file = "rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169"}, + {file = "rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425"}, + {file = "rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038"}, + {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7"}, + {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed"}, + {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85"}, + {file = "rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c"}, + {file = "rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825"}, + {file = "rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229"}, + {file = "rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad"}, + {file = "rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51"}, + {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5"}, + {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e"}, + {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394"}, + {file = "rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf"}, + {file = "rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b"}, + {file = "rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e"}, + {file = "rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2"}, + {file = "rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d"}, + {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7"}, + {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31"}, + {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95"}, + {file = "rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d"}, + {file = "rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15"}, + {file = "rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1"}, + {file = "rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a"}, + {file = "rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0"}, + {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94"}, + {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08"}, + {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27"}, + {file = "rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6"}, + {file = "rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d"}, + {file = "rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0"}, + {file = "rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f"}, + {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65"}, + {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f"}, + {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53"}, + {file = "rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed"}, + {file = "rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950"}, + {file = "rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6"}, + {file = "rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb"}, + {file = "rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5"}, + {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404"}, + {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856"}, + {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40"}, + {file = "rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0"}, + {file = "rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e"}, + {file = "rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84"}, ] [[package]] @@ -2406,18 +2407,6 @@ files = [ {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] -[[package]] -name = "sniffio" -version = "1.3.1" -description = "Sniff out which async library your code is running under" -optional = false -python-versions = ">=3.7" -groups = ["main", "dev", "test"] -files = [ - {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, - {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, -] - [[package]] name = "soupsieve" version = "2.8" @@ -2452,14 +2441,14 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] [[package]] name = "starlette" -version = "0.49.3" +version = "0.50.0" description = "The little ASGI library that shines." optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "starlette-0.49.3-py3-none-any.whl", hash = "sha256:b579b99715fdc2980cf88c8ec96d3bf1ce16f5a8051a7c2b84ef9b1cdecaea2f"}, - {file = "starlette-0.49.3.tar.gz", hash = "sha256:1c14546f299b5901a1ea0e34410575bc33bbd741377a10484a54445588d00284"}, + {file = "starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca"}, + {file = "starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca"}, ] [package.dependencies] @@ -2705,4 +2694,4 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [metadata] lock-version = "2.1" python-versions = "^3.11" -content-hash = "89226063947f0a896117295107fb190439a215ea4cc28756d8de77c6496249d3" +content-hash = "66cafb4bdee008393fc8504786d074cd2ba9d54a88978de413825a42ba8b69d5" diff --git a/pyproject.toml b/pyproject.toml index c8796d82..d411499b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,12 +25,11 @@ pydantic = "^2.7.1" pandas = "^2.2.3" openpyxl = "^3.1.5" pyyaml = "^6.0.2" -opencloning-linkml = "0.4.8" primer3-py = "2.2.0" biopython = "^1.85" packaging = "^25.0" pairwise-alignments-to-msa = "^0.1.1" -pydna = {git = "https://github.com/pydna-group/pydna", rev = "e95e8603b082e50b7873eab0ae1f8abf7b4d25bc"} +pydna = {git = "https://github.com/pydna-group/pydna", rev = "6f25090ec653e38219021aa46fa4440f888e958c"} [tool.poetry.group.dev.dependencies] autopep8 = "^2.0.4" diff --git a/src/opencloning/app_settings.py b/src/opencloning/app_settings.py index 9a25e7e4..3dba6848 100644 --- a/src/opencloning/app_settings.py +++ b/src/opencloning/app_settings.py @@ -22,6 +22,11 @@ def parse_bool(value: str) -> bool: # External services settings ================================= NCBI_API_KEY = os.environ.get('NCBI_API_KEY') +NCBI_MAX_SEQUENCE_LENGTH = ( + int(os.environ.get('NCBI_MAX_SEQUENCE_LENGTH')) + if os.environ.get('NCBI_MAX_SEQUENCE_LENGTH') is not None + else 500000 +) PLANNOTATE_URL = os.environ['PLANNOTATE_URL'] if 'PLANNOTATE_URL' in os.environ else None PLANNOTATE_TIMEOUT = int(os.environ['PLANNOTATE_TIMEOUT']) if 'PLANNOTATE_TIMEOUT' in os.environ else 20 # Handle trailing slash: @@ -58,6 +63,7 @@ class Settings(BaseModel): BATCH_CLONING: bool RECORD_STUBS: bool NCBI_API_KEY: str | None + NCBI_MAX_SEQUENCE_LENGTH: int ALLOWED_ORIGINS: list[str] PLANNOTATE_URL: str | None PLANNOTATE_TIMEOUT: int @@ -73,6 +79,7 @@ class Settings(BaseModel): BATCH_CLONING=BATCH_CLONING, RECORD_STUBS=RECORD_STUBS, NCBI_API_KEY=NCBI_API_KEY, + NCBI_MAX_SEQUENCE_LENGTH=NCBI_MAX_SEQUENCE_LENGTH, ALLOWED_ORIGINS=ALLOWED_ORIGINS, PLANNOTATE_URL=PLANNOTATE_URL, PLANNOTATE_TIMEOUT=PLANNOTATE_TIMEOUT, diff --git a/src/opencloning/batch_cloning/pombe/pombe_clone.py b/src/opencloning/batch_cloning/pombe/pombe_clone.py index e6986bcf..940290c0 100644 --- a/src/opencloning/batch_cloning/pombe/pombe_clone.py +++ b/src/opencloning/batch_cloning/pombe/pombe_clone.py @@ -1,36 +1,34 @@ import os -from opencloning.endpoints.external_import import genome_coordinates, get_from_repository_id_addgene, read_from_file -from opencloning.endpoints.assembly import pcr, homologous_recombination -from opencloning.pydantic_models import BaseCloningStrategy - -from opencloning_linkml.datamodel import ( - GenomeCoordinatesSource, - AddgeneIdSource, - PCRSource, - Primer as PrimerModel, - HomologousRecombinationSource, - UploadedFileSource, - TextFileSequence, -) - -from opencloning.ncbi_requests import get_annotations_from_query +from pydna.assembly2 import homologous_recombination_integration, pcr_assembly +from opencloning.dna_functions import request_from_addgene +from opencloning.ncbi_requests import get_annotations_from_query, get_genome_region_from_annotation import asyncio -import json from Bio import SeqIO +from pydna.primer import Primer +from pydna.opencloning_models import CloningStrategy +from fastapi.datastructures import UploadFile from pydna.parsers import parse as pydna_parse async def main( - gene: str, assembly_accession: str, output_dir: str, plasmid: str | dict = '19343', padding: int = 1000 + gene: str, + assembly_accession: str, + output_dir: str, + plasmid_input: UploadFile | str = '19343', + padding: int = 1000, ): print(f"\033[92mCloning {gene}\033[0m") # Parse primers ================================================================================= - primer_records = list(SeqIO.parse(os.path.join(output_dir, gene, 'primers.fa'), 'fasta')) - checking_primers = list(SeqIO.parse(os.path.join(output_dir, 'checking_primers.fa'), 'fasta')) - primer_records = primer_records[:3] + checking_primers[1:] + primer_records[3:] + checking_primers[:1] - primers = [] - for primer in primer_records: - primers.append(PrimerModel(sequence=str(primer.seq), id=0, name=primer.id)) + primers = [Primer(p) for p in SeqIO.parse(os.path.join(output_dir, gene, 'primers.fa'), 'fasta')] + common_primers = [Primer(p) for p in SeqIO.parse(os.path.join(output_dir, 'checking_primers.fa'), 'fasta')] + + # Get plasmid sequence ================================================================================= + if isinstance(plasmid_input, UploadFile): + file_content = (await plasmid_input.read()).decode() + + plasmid = pydna_parse(file_content)[0] + else: + plasmid = await request_from_addgene(plasmid_input) # Get genome region ===================================================================== annotations = await get_annotations_from_query(gene, assembly_accession) @@ -41,104 +39,24 @@ async def main( if len(annotations) != 1: raise ValueError(f'No right annotation found for {gene}') - annotation = annotations[0] - - gene_range = annotation['genomic_regions'][0]['gene_range']['range'][0] - sequence_accession = annotation['genomic_regions'][0]['gene_range']['accession_version'] - locus_tag = annotation.get('locus_tag', None) - gene_id = annotation.get('gene_id', None) - start = int(gene_range['begin']) - end = int(gene_range['end']) - orientation = 1 if gene_range['orientation'] == 'plus' else -1 - - source = GenomeCoordinatesSource( - id=0, - start=start - padding, - end=end + padding, - strand=orientation, - assembly_accession=assembly_accession, - sequence_accession=sequence_accession, - locus_tag=locus_tag, - gene_id=gene_id, - output_name=gene, - ) - locus = await genome_coordinates(source) - - cloning_strategy = BaseCloningStrategy( - sequences=[], - sources=[], - primers=[], - description=f'Cloning strategy for deleting the gene {gene} using PCR and homologous recombination', - ) - for primer in primers: - cloning_strategy.add_primer(primer) - locus_seq: TextFileSequence = TextFileSequence.model_validate(locus['sequences'][0]) - locus_source: GenomeCoordinatesSource = GenomeCoordinatesSource.model_validate(locus['sources'][0]) - cloning_strategy.add_source_and_sequence(locus_source, locus_seq) - - # Get plasmid sequence =================s================================================================ - if not isinstance(plasmid, str): - if plasmid.filename.endswith('.fa') or plasmid.filename.endswith('.fasta'): - resp = await read_from_file(plasmid, None, None, True, None, None, None) - else: - resp = await read_from_file(plasmid, None, None, None, None, None, None) - # Verify that plasmid is circular - if not pydna_parse(resp['sequences'][0].file_content)[0].circular: - raise ValueError('Plasmid is not circular') - plasmid_source: UploadedFileSource = UploadedFileSource.model_validate(resp['sources'][0]) - else: - addgene_source = AddgeneIdSource( - id=0, - repository_id=plasmid, - repository_name='addgene', - ) - resp = await get_from_repository_id_addgene(addgene_source) - plasmid_source: AddgeneIdSource = AddgeneIdSource.model_validate(resp['sources'][0]) - - plasmid_seq: TextFileSequence = TextFileSequence.model_validate(resp['sequences'][0]) - cloning_strategy.add_source_and_sequence(plasmid_source, plasmid_seq) + locus = await get_genome_region_from_annotation(annotations[0], 1000, 1000) # PCR ================================================================================================ - pcr_source = PCRSource(id=0, output_name='amplified_marker') - resp = await pcr(pcr_source, [plasmid_seq], [primers[0], primers[1]], 15, 0) + pcr_products = pcr_assembly(plasmid, primers[0], primers[1], limit=14, mismatches=0) + pcr_products[0].name = 'amplified_marker' + alleles = homologous_recombination_integration(locus, [pcr_products[0]], 40) + pcr_check1 = pcr_assembly(alleles[0], primers[2], common_primers[1], limit=14, mismatches=0)[0] + pcr_check1.name = 'check_pcr_left' + pcr_check2 = pcr_assembly(alleles[0], primers[3], common_primers[0], limit=14, mismatches=0)[0] + pcr_check2.name = 'check_pcr_right' - pcr_product: TextFileSequence = TextFileSequence.model_validate(resp['sequences'][0]) - pcr_source: PCRSource = PCRSource.model_validate(resp['sources'][0]) - cloning_strategy.add_source_and_sequence(pcr_source, pcr_product) - - # Homologous recombination ======================================================================== - hrec_source = HomologousRecombinationSource(id=0, output_name='deletion_allele') - resp = await homologous_recombination(hrec_source, [locus_seq, pcr_product], 50) - - hrec_product: TextFileSequence = TextFileSequence.model_validate(resp['sequences'][0]) - hrec_source: HomologousRecombinationSource = HomologousRecombinationSource.model_validate(resp['sources'][0]) - cloning_strategy.add_source_and_sequence(hrec_source, hrec_product) - - # Checking pcr 1 ====================================================================================== - check_pcr_source_left = PCRSource(id=0, output_name='check_pcr_left') - resp = await pcr(check_pcr_source_left, [hrec_product], [primers[2], primers[3]], 15, 0) - - check_pcr_product_left: TextFileSequence = TextFileSequence.model_validate(resp['sequences'][0]) - check_pcr_source_left: PCRSource = PCRSource.model_validate(resp['sources'][0]) - cloning_strategy.add_source_and_sequence(check_pcr_source_left, check_pcr_product_left) - - # Checking pcr 2 ====================================================================================== - check_pcr_source_right = PCRSource(id=0, output_name='check_pcr_right') - resp = await pcr(check_pcr_source_right, [hrec_product], [primers[4], primers[5]], 15, 0) - - check_pcr_product_right: TextFileSequence = TextFileSequence.model_validate(resp['sequences'][0]) - check_pcr_source_right: PCRSource = PCRSource.model_validate(resp['sources'][0]) - cloning_strategy.add_source_and_sequence(check_pcr_source_right, check_pcr_product_right) - - cloning_strategy.description = ( - f'Cloning strategy for deleting the gene {gene} using PCR and homologous recombination' - ) + cs = CloningStrategy.from_dseqrecords([pcr_check1, pcr_check2]) if not os.path.exists(os.path.join(output_dir, gene)): os.makedirs(os.path.join(output_dir, gene)) with open(os.path.join(output_dir, gene, 'cloning_strategy.json'), 'w') as f: - json.dump(cloning_strategy.model_dump(), f, indent=2) + f.write(cs.model_dump_json(indent=2)) if __name__ == '__main__': diff --git a/src/opencloning/batch_cloning/pombe/pombe_summary.py b/src/opencloning/batch_cloning/pombe/pombe_summary.py index 65fa4c6a..0532608e 100644 --- a/src/opencloning/batch_cloning/pombe/pombe_summary.py +++ b/src/opencloning/batch_cloning/pombe/pombe_summary.py @@ -40,16 +40,17 @@ def process_folder(working_dir: str): # We do this to have action to .end and .start pcr_sources = [PCRSource.model_validate(s.model_dump()) for s in pcr_sources] locus_source = next(s for s in strategy.sources if s.type == 'GenomeCoordinatesSource') + locus_location = Location.fromstring(locus_source.coordinates) hrec_source = next(s for s in strategy.sources if s.type == 'HomologousRecombinationSource') # We do this to have action to .end and .start hrec_source: HomologousRecombinationSource = HomologousRecombinationSource.model_validate(hrec_source.model_dump()) - chromosome = chromosomes[locus_source.sequence_accession] + chromosome = chromosomes[locus_source.repository_id] insertion_start = ( - locus_source.start + location_boundaries(Location.fromstring(hrec_source.input[0].right_location))[1] + locus_location.start + location_boundaries(Location.fromstring(hrec_source.input[0].right_location))[1] ) insertion_end = ( - locus_source.start + location_boundaries(Location.fromstring(hrec_source.input[-1].left_location))[0] + locus_location.start + location_boundaries(Location.fromstring(hrec_source.input[-1].left_location))[0] ) # Write out the sequences in genbank format and extract some relevant info diff --git a/src/opencloning/batch_cloning/ziqiang_et_al2024/ziqiang_et_al2024.json b/src/opencloning/batch_cloning/ziqiang_et_al2024/ziqiang_et_al2024.json index b35d146b..7dfe99b3 100644 --- a/src/opencloning/batch_cloning/ziqiang_et_al2024/ziqiang_et_al2024.json +++ b/src/opencloning/batch_cloning/ziqiang_et_al2024/ziqiang_et_al2024.json @@ -81,7 +81,6 @@ "database_id": null, "input": [], "repository_id": "71287", - "repository_name": "addgene", "sequence_file_url": "https://media.addgene.org/snapgene-media/v2.0.0/sequences/352460/6c8b0369-e549-4517-95da-8d07146ca49d/addgene-plasmid-71287-sequence-352460.gbk", "addgene_sequence_type": "addgene-full" }, @@ -92,7 +91,6 @@ "database_id": null, "input": [], "repository_id": "71287", - "repository_name": "addgene", "sequence_file_url": "https://media.addgene.org/snapgene-media/v2.0.0/sequences/352460/6c8b0369-e549-4517-95da-8d07146ca49d/addgene-plasmid-71287-sequence-352460.gbk", "addgene_sequence_type": "addgene-full" }, @@ -103,7 +101,6 @@ "database_id": null, "input": [], "repository_id": "213912", - "repository_name": "addgene", "sequence_file_url": "https://media.addgene.org/snapgene-media/v2.0.0/sequences/437264/8bd82b44-a1c3-4f81-8936-ebcc16d171e9/addgene-plasmid-213912-sequence-437264.gbk", "addgene_sequence_type": "addgene-full" }, @@ -114,7 +111,6 @@ "database_id": null, "input": [], "repository_id": "213913", - "repository_name": "addgene", "sequence_file_url": "https://media.addgene.org/snapgene-media/v2.0.0/sequences/437263/af62d64e-1f22-4dce-aafa-7935d1665700/addgene-plasmid-213913-sequence-437263.gbk", "addgene_sequence_type": "addgene-full" }, @@ -125,7 +121,6 @@ "database_id": null, "input": [], "repository_id": "133748", - "repository_name": "addgene", "sequence_file_url": "https://media.addgene.org/snapgene-media/v2.0.0/sequences/271264/c0ae5f43-46e6-4175-a0c1-9a00cbb92034/addgene-plasmid-133748-sequence-271264.gbk", "addgene_sequence_type": "addgene-full" }, @@ -135,8 +130,7 @@ "output_name": "pDONR_P2r-P3", "database_id": null, "input": [], - "repository_id": "gateway_cloning_vectors/pDONR_P2r-P3", - "repository_name": "snapgene" + "repository_id": "gateway_cloning_vectors/pDONR_P2r-P3" }, { "id": 7, @@ -207,7 +201,6 @@ "database_id": null, "input": [], "repository_id": "63143", - "repository_name": "addgene", "sequence_file_url": "https://media.addgene.org/snapgene-media/v2.0.0/sequences/223326/8c81fe9a-fb57-40bc-93d6-e17d83502061/addgene-plasmid-63143-sequence-223326.gbk", "addgene_sequence_type": "addgene-full" } @@ -258,7 +251,7 @@ ], "description": "", "files": null, - "schema_version": "0.4.3", + "schema_version": "0.4.9", "backend_version": null, "frontend_version": null } diff --git a/src/opencloning/endpoints/external_import.py b/src/opencloning/endpoints/external_import.py index 1b03ec7c..10e0d712 100644 --- a/src/opencloning/endpoints/external_import.py +++ b/src/opencloning/endpoints/external_import.py @@ -1,4 +1,5 @@ from fastapi import Body, Query, HTTPException, Response, UploadFile, File +from opencloning.app_settings import settings from pydantic import create_model import io import warnings @@ -25,6 +26,7 @@ SequenceFileFormat, SEVASource, OpenDNACollectionsSource, + NCBISequenceSource, ) from pydna.opencloning_models import SequenceLocationStr from ..dna_functions import ( @@ -245,31 +247,41 @@ def handle_repository_errors(exception: Exception, repository_name: str) -> None ) async def get_from_repository_id( source: ( - RepositoryIdSource - | AddgeneIdSource + AddgeneIdSource | BenchlingUrlSource | SnapGenePlasmidSource | EuroscarfSource | WekWikGeneIdSource | SEVASource | OpenDNACollectionsSource + | NCBISequenceSource ), ): - return RedirectResponse(f'/repository_id/{source.repository_name}', status_code=307) + mapping_dict = { + 'AddgeneIdSource': 'addgene', + 'BenchlingUrlSource': 'benchling', + 'SnapGenePlasmidSource': 'snapgene', + 'EuroscarfSource': 'euroscarf', + 'WekWikGeneIdSource': 'wekwikgene', + 'SEVASource': 'seva', + 'OpenDNACollectionsSource': 'open_dna_collections', + 'NCBISequenceSource': 'genbank', + } + return RedirectResponse(f'/repository_id/{mapping_dict[source.type]}', status_code=307) @router.post( '/repository_id/genbank', response_model=create_model( - 'RepositoryIdResponse', sources=(list[RepositoryIdSource], ...), sequences=(list[TextFileSequence], ...) + 'RepositoryIdResponse', sources=(list[NCBISequenceSource], ...), sequences=(list[TextFileSequence], ...) ), ) -async def get_from_repository_id_genbank(source: RepositoryIdSource): +async def get_from_repository_id_genbank(source: NCBISequenceSource): try: # This request already fails if the sequence does not exist seq_length = await ncbi_requests.get_sequence_length_from_sequence_accession(source.repository_id) - if seq_length > 100000: - raise HTTPException(400, 'sequence is too long (max 100000 bp)') + if seq_length > settings.NCBI_MAX_SEQUENCE_LENGTH: + raise HTTPException(400, f'sequence is too long (max {settings.NCBI_MAX_SEQUENCE_LENGTH} bp)') seq = await ncbi_requests.get_genbank_sequence(source.repository_id) except Exception as exception: handle_repository_errors(exception, 'NCBI') @@ -287,7 +299,7 @@ async def get_from_repository_id_addgene(source: AddgeneIdSource): try: dseq = await request_from_addgene(source.repository_id) except Exception as exception: - handle_repository_errors(exception, source.repository_name) + handle_repository_errors(exception, 'Addgene') return format_products( source.id, @@ -314,7 +326,7 @@ async def get_from_repository_id_wekwikgene(source: WekWikGeneIdSource): try: dseq = await request_from_wekwikgene(source.repository_id) except Exception as exception: - handle_repository_errors(exception, source.repository_name) + handle_repository_errors(exception, 'WeKwikGene') return format_products( source.id, [dseq], @@ -342,7 +354,7 @@ async def get_from_benchling_url( dseq = await get_sequence_from_benchling_url(source.repository_id) return format_products(source.id, [dseq], None, source.output_name) except Exception as exception: - handle_repository_errors(exception, source.repository_name) + handle_repository_errors(exception, 'Benchling') @router.post( @@ -359,7 +371,7 @@ async def get_from_repository_id_snapgene( seq = await request_from_snapgene(plasmid_set, plasmid_name) return format_products(source.id, [seq], None, source.output_name) except Exception as exception: - handle_repository_errors(exception, source.repository_name) + handle_repository_errors(exception, 'Snapgene') @router.post( @@ -377,7 +389,7 @@ async def get_from_repository_id_euroscarf(source: EuroscarfSource): dseq = await get_sequence_from_euroscarf_url(source.repository_id) return format_products(source.id, [dseq], None, source.output_name) except Exception as exception: - handle_repository_errors(exception, source.repository_name) + handle_repository_errors(exception, 'Euroscarf') @router.post( @@ -402,7 +414,7 @@ async def get_from_repository_id_igem(source: IGEMSource): ''', ) except Exception as exception: - handle_repository_errors(exception, source.repository_name) + handle_repository_errors(exception, 'iGEM') @router.post( @@ -431,7 +443,7 @@ async def get_from_repository_id_open_dna_collections(source: OpenDNACollections ''', ) except Exception as exception: - handle_repository_errors(exception, source.repository_name) + handle_repository_errors(exception, 'OpenDNA Collections') @router.post( @@ -445,7 +457,16 @@ async def genome_coordinates( ): # Validate that coordinates make sense - ncbi_requests.validate_coordinates_pre_request(source.start, source.end, source.strand) + try: + location_str = SequenceLocationStr(source.coordinates) + location = location_str.to_biopython_location() + start, end, strand = location_str.get_ncbi_format_coordinates() + except Exception as e: + raise HTTPException(422, f'Invalid coordinates: {e}') from e + + if len(location) > settings.NCBI_MAX_SEQUENCE_LENGTH: + raise HTTPException(400, f'sequence is too long (max {settings.NCBI_MAX_SEQUENCE_LENGTH} bp)') + if source.locus_tag is not None and source.assembly_accession is None: raise HTTPException(422, 'assembly_accession is required if locus_tag is set') @@ -453,7 +474,12 @@ async def genome_coordinates( async def validate_locus_task(): if source.locus_tag is not None: return await ncbi_requests.validate_locus_tag( - source.locus_tag, source.assembly_accession, source.gene_id, source.start, source.end, source.strand + source.locus_tag, + source.assembly_accession, + source.gene_id, + start, + end, + strand, ) async def validate_assembly_task(): @@ -462,16 +488,14 @@ async def validate_assembly_task(): sequence_accessions = await ncbi_requests.get_sequence_accessions_from_assembly_accession( source.assembly_accession ) - if source.sequence_accession not in sequence_accessions: + if source.repository_id not in sequence_accessions: raise HTTPException( 400, - f'Sequence accession {source.sequence_accession} not contained in assembly accession {source.assembly_accession}, which contains accessions: {", ".join(sequence_accessions)}', + f'Sequence accession {source.repository_id} not contained in assembly accession {source.assembly_accession}, which contains accessions: {", ".join(sequence_accessions)}', ) async def get_sequence_task(): - return await ncbi_requests.get_genbank_sequence( - source.sequence_accession, source.start, source.end, source.strand - ) + return await ncbi_requests.get_genbank_sequence(source.repository_id, start, end, strand) tasks = [validate_locus_task(), validate_assembly_task(), get_sequence_task()] @@ -483,7 +507,7 @@ async def get_sequence_task(): source.gene_id = gene_id # NCBI does not complain for coordinates that fall out of the sequence, so we have to check here - if len(seq) != source.end - source.start + 1: + if len(seq) != len(location): raise HTTPException(400, 'coordinates fall outside the sequence') return {'sequences': [format_sequence_genbank(seq, source.output_name)], 'sources': [source.model_copy()]} @@ -502,7 +526,7 @@ async def get_from_repository_id_seva(source: SEVASource): try: dseq = await get_seva_plasmid(source.repository_id) except Exception as exception: - handle_repository_errors(exception, source.repository_name) + handle_repository_errors(exception, 'SEVA') return format_products( source.id, diff --git a/src/opencloning/endpoints/no_input.py b/src/opencloning/endpoints/no_input.py index 89a6efc4..84357e5a 100644 --- a/src/opencloning/endpoints/no_input.py +++ b/src/opencloning/endpoints/no_input.py @@ -16,6 +16,7 @@ TextFileSequence, ManuallyTypedSource, OligoHybridizationSource, + ManuallyTypedSequence, ) from .. import request_examples @@ -30,17 +31,14 @@ 'ManuallyTypedResponse', sources=(list[ManuallyTypedSource], ...), sequences=(list[TextFileSequence], ...) ), ) -async def manually_typed(source: ManuallyTypedSource): +async def manually_typed(source: ManuallyTypedSource, sequence: ManuallyTypedSequence): """Return the sequence from a manually typed sequence""" - if source.circular: - # TODO: This should be done in the model validator - if source.overhang_crick_3prime != 0 or source.overhang_watson_3prime != 0: - raise HTTPException(422, 'Circular sequences cannot have overhangs.') - seq = Dseqrecord(source.user_input, circular=source.circular) + if sequence.circular: + seq = Dseqrecord(sequence.sequence, circular=sequence.circular) else: seq = Dseqrecord( Dseq.from_full_sequence_and_overhangs( - source.user_input, source.overhang_crick_3prime, source.overhang_watson_3prime + sequence.sequence, sequence.overhang_crick_3prime, sequence.overhang_watson_3prime ) ) return {'sequences': [format_sequence_genbank(seq, source.output_name)], 'sources': [source]} diff --git a/src/opencloning/ncbi_requests.py b/src/opencloning/ncbi_requests.py index bb17b9ea..d947ca08 100644 --- a/src/opencloning/ncbi_requests.py +++ b/src/opencloning/ncbi_requests.py @@ -1,7 +1,8 @@ from fastapi import HTTPException import math from pydna.dseqrecord import Dseqrecord -from pydna.opencloning_models import RepositoryIdSource, GenomeCoordinatesSource +from pydna.opencloning_models import GenomeCoordinatesSource, NCBISequenceSource +from Bio.SeqFeature import Location from .app_settings import settings from .http_client import get_http_client, Response @@ -90,6 +91,10 @@ async def get_sequence_length_from_sequence_accession(sequence_accession: str) - async def get_genbank_sequence(sequence_accession, start=None, end=None, strand=None) -> Dseqrecord: from opencloning.dna_functions import get_sequences_from_file_url + # Ensure that start, end, and strand are either all None or none are None + if (start is None or end is None or strand is None) and not (start is None and end is None and strand is None): + raise ValueError('start, end, and strand must either all be None or none be None') + gb_strand = 1 if strand == 1 or strand is None else 2 url = 'https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi' params = { @@ -116,20 +121,16 @@ async def get_genbank_sequence(sequence_accession, start=None, end=None, strand= except Exception as e: raise e - seq.source = RepositoryIdSource(repository_name='genbank', repository_id=sequence_accession) - return seq - + if start is not None: + if strand == -1: + location = Location.fromstring(f'complement({start}..{end})') + else: + location = Location.fromstring(f'{start}..{end}') + else: + location = None -def validate_coordinates_pre_request(start, end, strand): - # TODO: move this to the class - if strand not in [1, -1]: - raise HTTPException(422, 'strand must be 1 or -1') - if start >= end: - raise HTTPException(422, 'start must be less than end') - if start < 1: - raise HTTPException(422, 'start must be greater than 0') - if end - start > 100000: - raise HTTPException(400, 'sequence is too long (max 100000 bp)') + seq.source = NCBISequenceSource(repository_id=sequence_accession, coordinates=location) + return seq def get_info_from_annotation(annotation: dict) -> dict: @@ -171,7 +172,10 @@ async def validate_locus_tag( # The gene should fall within the range (range might be bigger if bases were requested upstream or downstream) if gene_start < start or gene_end > end or gene_strand != strand: - raise HTTPException(400, f'wrong coordinates, expected to fall within {start}, {end} on strand: {strand}') + raise HTTPException( + 400, + f'wrong coordinates, the gene should fall within the requested coordinates, {start}, {end} on strand: {strand}', + ) return gene_id @@ -185,14 +189,14 @@ async def get_genome_region_from_annotation( start = start - padding_left end = end + padding_right seq = await get_genbank_sequence(sequence_accession, start, end, strand) + location_str = f'{start}..{end}' if strand != -1 else f'complement({start}..{end})' + coordinates = Location.fromstring(location_str) source = GenomeCoordinatesSource( assembly_accession=assembly_accession, - sequence_accession=sequence_accession, + repository_id=sequence_accession, + coordinates=coordinates, locus_tag=locus_tag, gene_id=gene_id, - start=start, - end=end, - strand=strand, ) seq.name = locus_tag seq.source = source diff --git a/src/opencloning/request_examples.py b/src/opencloning/request_examples.py index 7fe500c3..d4781b1a 100644 --- a/src/opencloning/request_examples.py +++ b/src/opencloning/request_examples.py @@ -3,58 +3,48 @@ 'summary': 'All parameters provided', 'value': { 'id': 1, - 'sequence_accession': 'NC_003424.3', + 'repository_id': 'NC_003424.3', 'assembly_accession': 'GCF_000002945.2', 'locus_tag': 'SPOM_SPAPB1A10.09', 'gene_id': 2543372, - 'start': 1877009, - 'end': 1881726, - 'strand': 1, + 'coordinates': '1877009..1881726', }, }, 'full_with_genbank_accession': { 'summary': 'All parameters provided, but sequence accession is GenBank', 'value': { 'id': 1, - 'sequence_accession': 'CU329670.1', + 'repository_id': 'CU329670.1', 'assembly_accession': 'GCF_000002945.2', 'locus_tag': 'SPOM_SPAPB1A10.09', 'gene_id': 2543372, - 'start': 1877009, - 'end': 1881726, - 'strand': 1, + 'coordinates': '1877009..1881726', }, }, 'id_omitted': { 'summary': 'Gene ID omitted (filled in response)', 'value': { 'id': 1, - 'sequence_accession': 'NC_003424.3', + 'repository_id': 'NC_003424.3', 'assembly_accession': 'GCF_000002945.2', 'locus_tag': 'SPOM_SPAPB1A10.09', - 'start': 1877009, - 'end': 1881726, - 'strand': 1, + 'coordinates': '1877009..1881726', }, }, 'assembly_accession_omitted': { 'summary': 'Sequence accession only', 'value': { 'id': 1, - 'sequence_accession': 'NC_003424.3', - 'start': 1877009, - 'end': 1881726, - 'strand': 1, + 'repository_id': 'NC_003424.3', + 'coordinates': '1877009..1881726', }, }, 'viral_sequence': { 'summary': 'Viral sequence not associated with assembly', 'value': { 'id': 1, - 'sequence_accession': 'DQ208311.2', - 'start': 20, - 'end': 2050, - 'strand': -1, + 'repository_id': 'DQ208311.2', + 'coordinates': 'complement(20..2050)', }, }, } @@ -84,7 +74,6 @@ 'summary': 'Typical example', 'value': { 'id': 0, - 'repository_name': 'benchling', 'repository_id': 'https://benchling.com/siverson/f/lib_B94YxDHhQh-cidar-moclo-library/seq_kryGidaz-c0062_cd.gb', }, }, @@ -95,7 +84,6 @@ 'summary': 'Typical example', 'value': { 'id': 0, - 'repository_name': 'snapgene', 'repository_id': 'basic_cloning_vectors/pEASY-T1_(linearized)', }, }, diff --git a/tests/test_endpoints_external_import.py b/tests/test_endpoints_external_import.py index 9e552406..a4d50666 100644 --- a/tests/test_endpoints_external_import.py +++ b/tests/test_endpoints_external_import.py @@ -13,7 +13,7 @@ from opencloning.dna_functions import read_dsrecord_from_json import opencloning.main as _main from opencloning_linkml.datamodel import ( - RepositoryIdSource, + NCBISequenceSource, TextFileSequence, UploadedFileSource, GenomeCoordinatesSource, @@ -301,9 +301,8 @@ class GenBankTest(unittest.TestCase): # TODO these tests will not work off-line, so the case where connection cannot be established should be handled in some way def test_request_gene(self): """Test whether the gene is requested from GenBank""" - source = RepositoryIdSource( + source = NCBISequenceSource( id=1, - repository_name='genbank', repository_id='NM_001018957.2', ) response = client.post('/repository_id/genbank', json=source.model_dump()) @@ -314,9 +313,8 @@ def test_request_gene(self): def test_request_wrong_id(self): """Test a wrong Genbank id""" - source = RepositoryIdSource( + source = NCBISequenceSource( id=1, - repository_name='genbank', repository_id='wrong_id', ) response = client.post('/repository_id/genbank', json=source.model_dump()) @@ -331,9 +329,8 @@ def test_request_wrong_id2(self): ) # 400 is the error code for a wrong sequence accession :_) respx.get('https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi').respond(400, text='') - source = RepositoryIdSource( + source = NCBISequenceSource( id=1, - repository_name='genbank', repository_id='wrong_id', ) response = client.post('/repository_id/genbank', json=source.model_dump()) @@ -347,9 +344,8 @@ def test_eutils_down(self): respx.get('https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi').mock( side_effect=httpx.ConnectError('Connection error') ) - source = RepositoryIdSource( + source = NCBISequenceSource( id=1, - repository_name='genbank', repository_id='NM_001018957.2', ) response = client.post('/repository_id/genbank', json=source.model_dump()) @@ -367,9 +363,8 @@ def test_eutils_down(self): def test_redirect(self): """The repository_id endpoint should redirect based on repository_name value""" - source = RepositoryIdSource( + source = NCBISequenceSource( id=1, - repository_name='genbank', repository_id='NM_001018957.2', ) response = client.post('/repository_id', json=source.model_dump()) @@ -380,9 +375,8 @@ def test_redirect(self): def test_rename(self): """If passing output_name, it renames the output""" - source = RepositoryIdSource( + source = NCBISequenceSource( id=1, - repository_name='genbank', repository_id='NM_001018957.2', output_name='hello', ) @@ -394,9 +388,8 @@ def test_rename(self): def test_long_sequence(self): """Test that a long sequence raises an error""" - source = RepositoryIdSource( + source = NCBISequenceSource( id=1, - repository_name='genbank', repository_id='CU329670.1', ) response = client.post('/repository_id/genbank', json=source.model_dump()) @@ -424,7 +417,6 @@ def test_request_plasmid(self): for example in examples: source = AddgeneIdSource( id=1, - repository_name='addgene', repository_id=example['id'], ) @@ -451,7 +443,6 @@ def test_old_url(self): """Works for an Addgene url that has now been replaced by a newer one""" source = AddgeneIdSource( id=1, - repository_name='addgene', repository_id='65109', addgene_sequence_type='addgene-full', sequence_file_url='https://media.addgene.org/snapgene-media/v1.7.9-0-g88a3305/sequences/110162/c1c98803-c8ba-44a6-95b8-d6a94097e36f/addgene-plasmid-65109-sequence-110162.gbk', @@ -477,7 +468,6 @@ def test_missing_sequences(self): # Non-existing id source = AddgeneIdSource( id=1, - repository_name='addgene', repository_id='DUMMYTEST', ) @@ -488,7 +478,6 @@ def test_missing_sequences(self): # Id that has no full-sequences source = AddgeneIdSource( id=1, - repository_name='addgene', repository_id='39291', ) response = client.post('/repository_id/addgene', json=source.model_dump()) @@ -498,7 +487,6 @@ def test_missing_sequences(self): # url does not exist source = AddgeneIdSource( id=1, - repository_name='addgene', repository_id='39282', sequence_file_url='https://media.addgene.org/snapgene-media/wrongggggggg.gbk', ) @@ -509,7 +497,6 @@ def test_redirect(self): """Test repository_id endpoint should redirect based on repository_name value""" source = AddgeneIdSource( id=1, - repository_name='addgene', repository_id='39282', ) response = client.post('/repository_id', json=source.model_dump()) @@ -523,12 +510,11 @@ def test_addgene_down(self): respx.get('https://www.addgene.org/39282/sequences/').mock(side_effect=httpx.ConnectError('Connection error')) source = AddgeneIdSource( id=1, - repository_name='addgene', repository_id='39282', ) response = client.post('/repository_id/addgene', json=source.model_dump()) self.assertEqual(response.status_code, 504) - self.assertIn('Unable to connect to addgene', response.json()['detail']) + self.assertIn('Unable to connect to Addgene', response.json()['detail']) class WekWikGeneSourceTest(unittest.TestCase): @@ -536,7 +522,6 @@ class WekWikGeneSourceTest(unittest.TestCase): def test_valid_id(self): source = WekWikGeneIdSource( id=1, - repository_name='wekwikgene', repository_id='0000304', ) response = client.post('/repository_id/wekwikgene', json=source.model_dump()) @@ -551,7 +536,6 @@ def test_valid_id(self): def test_invalid_id(self): source = WekWikGeneIdSource( id=1, - repository_name='wekwikgene', repository_id='999999999999999999999999999999', # Non-existent ID ) response = client.post('/repository_id/wekwikgene', json=source.model_dump()) @@ -562,7 +546,6 @@ def test_invalid_id(self): def test_wekwikgene_down(self): source = WekWikGeneIdSource( id=1, - repository_name='wekwikgene', repository_id='0000304', ) @@ -571,12 +554,11 @@ def test_wekwikgene_down(self): ) response = client.post('/repository_id/wekwikgene', json=source.model_dump()) self.assertEqual(response.status_code, 504) - self.assertIn('Unable to connect to wekwikgene', response.json()['detail']) + self.assertIn('Unable to connect to WeKwikGene', response.json()['detail']) def test_redirect(self): source = WekWikGeneIdSource( id=1, - repository_name='wekwikgene', repository_id='0000304', ) response = client.post('/repository_id', json=source.model_dump()) @@ -590,7 +572,7 @@ class BenchlingUrlSourceTest(unittest.TestCase): def test_valid_url(self): url = 'https://benchling.com/siverson/f/lib_B94YxDHhQh-cidar-moclo-library/seq_dh1FrJTc-b0015_dh.gb' - source = BenchlingUrlSource(id=0, repository_id=url, repository_name='benchling') + source = BenchlingUrlSource(id=0, repository_id=url) response = client.post('/repository_id/benchling', json=source.model_dump()) self.assertEqual(response.status_code, 200) payload = response.json() @@ -601,7 +583,7 @@ def test_valid_url(self): def test_invalid_url(self): # We have to initialize the object with a valid url url = 'https://benchling.com/siverson/f/lib_B94YxDHhQh-cidar-moclo-library/seq_dh1FrJTc-b0015_dh.gb' - source_object = BenchlingUrlSource(id=0, repository_id=url, repository_name='benchling') + source_object = BenchlingUrlSource(id=0, repository_id=url) # In the dict, we can then edit source_dict = source_object.model_dump() @@ -622,7 +604,7 @@ def test_invalid_url(self): # One that matches the pattern but does not exist url = 'https://benchling.com/bluh/blah.gb' - source = BenchlingUrlSource(id=0, repository_id=url, repository_name='benchling') + source = BenchlingUrlSource(id=0, repository_id=url) response = client.post('/repository_id/benchling', json=source.model_dump()) self.assertEqual(response.status_code, 404) self.assertIn('file requested from url not found', response.json()['detail']) @@ -632,9 +614,7 @@ class SnapGenePlasmidSourceTest(unittest.TestCase): def test_valid_url(self): - source = SnapGenePlasmidSource( - id=0, repository_id='basic_cloning_vectors/pEASY-T1_(linearized)', repository_name='snapgene' - ) + source = SnapGenePlasmidSource(id=0, repository_id='basic_cloning_vectors/pEASY-T1_(linearized)') response = client.post('/repository_id/snapgene', json=source.model_dump()) self.assertEqual(response.status_code, 200) payload = response.json() @@ -649,7 +629,6 @@ def test_valid_url(self): source2 = SnapGenePlasmidSource( id=0, repository_id='basic_cloning_vectors/pEASY-T1_(linearized)', - repository_name='snapgene', output_name='my_name', ) response = client.post('/repository_id/snapgene', json=source2.model_dump()) @@ -661,12 +640,12 @@ def test_valid_url(self): def test_invalid_url(self): # Invalid plasmid set - source = SnapGenePlasmidSource(id=0, repository_id='hello/world', repository_name='snapgene') + source = SnapGenePlasmidSource(id=0, repository_id='hello/world') response = client.post('/repository_id/snapgene', json=source.model_dump()) self.assertEqual(response.status_code, 404) # Invalid plasmid name - source = SnapGenePlasmidSource(id=0, repository_id='basic_cloning_vectors/hello', repository_name='snapgene') + source = SnapGenePlasmidSource(id=0, repository_id='basic_cloning_vectors/hello') response = client.post('/repository_id/snapgene', json=source.model_dump()) self.assertEqual(response.status_code, 404) self.assertIn('hello is not part of basic_cloning_vectors', response.json()['detail']) @@ -681,7 +660,7 @@ def test_invalid_url(self): class EuroscarfSourceTest(unittest.TestCase): def test_valid_url(self): - source = EuroscarfSource(id=0, repository_id='P30174', repository_name='euroscarf') + source = EuroscarfSource(id=0, repository_id='P30174') response = client.post('/repository_id/euroscarf', json=source.model_dump()) self.assertEqual(response.status_code, 200) payload = response.json() @@ -695,7 +674,7 @@ def test_valid_url(self): self.assertTrue(any('yEGFP' in f.qualifiers['gene'] for f in sequence.features)) # Ensure that linear files are circularised - source = EuroscarfSource(id=0, repository_id='P30555', repository_name='euroscarf') + source = EuroscarfSource(id=0, repository_id='P30555') response = client.post('/repository_id/euroscarf', json=source.model_dump()) self.assertEqual(response.status_code, 200) payload = response.json() @@ -705,7 +684,7 @@ def test_valid_url(self): def test_invalid_url(self): # Compatible with regex, but does not exist - source = EuroscarfSource(id=0, repository_id='P99999999999999', repository_name='euroscarf') + source = EuroscarfSource(id=0, repository_id='P99999999999999') response = client.post('/repository_id/euroscarf', json=source.model_dump()) self.assertEqual(response.status_code, 404) @@ -718,7 +697,7 @@ def test_invalid_url(self): @respx.mock def test_circularize_plasmid(self): # We mock a request in which we would get a linear plasmid - source = EuroscarfSource(id=0, repository_id='P9999999999999', repository_name='euroscarf') + source = EuroscarfSource(id=0, repository_id='P9999999999999') respx.get('http://www.euroscarf.de/plasmid_details.php').respond( 200, text='Download' ) @@ -740,21 +719,16 @@ class IGEMSourceTest(unittest.TestCase): @pytest.mark.flaky(reruns=2, reruns_delay=2) def test_igem(self): - source = IGEMSource( - id=0, repository_name='igem', repository_id='BBa_C0062-pSB1C5C', sequence_file_url=self.good_url - ) + source = IGEMSource(id=0, repository_id='BBa_C0062-pSB1C5C', sequence_file_url=self.good_url) response = client.post('/repository_id/igem', json=source.model_dump()) payload = response.json() self.assertEqual(response.status_code, 200) self.assertEqual(payload['sources'][0]['repository_id'], 'BBa_C0062-pSB1C5C') - self.assertEqual(payload['sources'][0]['repository_name'], 'igem') def test_errors(self): # The repository_id does not start with the part_name, even if url is valid - source = IGEMSource( - id=0, repository_name='igem', repository_id='BBa_C0062-dummy', sequence_file_url=self.good_url - ) + source = IGEMSource(id=0, repository_id='BBa_C0062-dummy', sequence_file_url=self.good_url) # The url is not a GenBank file source_json = source.model_dump() @@ -763,7 +737,7 @@ def test_errors(self): self.assertEqual(response.status_code, 422) # The url does not exist - source = IGEMSource(id=0, repository_name='igem', repository_id='dummy-test', sequence_file_url=self.wrong_url) + source = IGEMSource(id=0, repository_id='dummy-test', sequence_file_url=self.wrong_url) response = client.post('/repository_id/igem', json=source.model_dump()) self.assertEqual(response.status_code, 404) @@ -845,9 +819,9 @@ def test_exceptions(self): # Wrong coordinates s = correct_source.model_copy(deep=True) - s.start = 1 - s.end = 10 + s.coordinates = '1..10' response = client.post('/genome_coordinates', json=s.model_dump()) + self.assertIn('gene should fall within', response.json()['detail']) self.assertStatusCode(response.status_code, 400) time.sleep(wait_time) @@ -893,7 +867,7 @@ def test_exceptions(self): s.locus_tag = None s.gene_id = None s.assembly_accession = None - s.sequence_accession = 'blah' + s.repository_id = 'blah' response = client.post('/genome_coordinates', json=s.model_dump()) self.assertStatusCode(response.status_code, 404) time.sleep(wait_time) @@ -902,39 +876,27 @@ def test_exceptions(self): viral_source = GenomeCoordinatesSource.model_validate( request_examples.genome_region_examples['viral_sequence']['value'] ) - viral_source.start = 10 - viral_source.end = 1 - response = client.post('/genome_coordinates', json=viral_source.model_dump()) - self.assertStatusCode(response.status_code, 422) - time.sleep(wait_time) - - viral_source.start = 0 - viral_source.end = 20 + viral_source.coordinates = '10..1' response = client.post('/genome_coordinates', json=viral_source.model_dump()) self.assertStatusCode(response.status_code, 422) time.sleep(wait_time) - viral_source.start = 1 - viral_source.end = 20 - viral_source.strand = 0 + viral_source.coordinates = '0..20' response = client.post('/genome_coordinates', json=viral_source.model_dump()) self.assertStatusCode(response.status_code, 422) time.sleep(wait_time) # Coordinates outside of the sequence - viral_source.start = 1 - # the length is 2151 - viral_source.end = 2152 - viral_source.strand = 1 + viral_source.coordinates = '1..2152' response = client.post('/genome_coordinates', json=viral_source.model_dump()) self.assertStatusCode(response.status_code, 400) time.sleep(wait_time) # Coordinates too long - viral_source.start = 1 - viral_source.end = 100004 + viral_source.coordinates = '1..100004' response = client.post('/genome_coordinates', json=viral_source.model_dump()) self.assertStatusCode(response.status_code, 400) + self.assertIn('coordinates fall outside the sequence', response.json()['detail']) def test_ncbi_down(self): correct_source = GenomeCoordinatesSource.model_validate( @@ -948,13 +910,23 @@ def test_ncbi_down(self): self.assertEqual(response.status_code, 503) self.assertIn('NCBI is down', response.json()['detail']) + def test_max_sequence_length(self): + correct_source = GenomeCoordinatesSource.model_validate( + request_examples.genome_region_examples['full']['value'] + ) + correct_source.coordinates = f'1..{app_settings.NCBI_MAX_SEQUENCE_LENGTH + 1}' + response = client.post('/genome_coordinates', json=correct_source.model_dump()) + self.assertEqual(response.status_code, 400) + self.assertIn( + f'sequence is too long (max {app_settings.NCBI_MAX_SEQUENCE_LENGTH} bp)', response.json()['detail'] + ) + class SEVASourceTest(unittest.TestCase): def test_seva_url(self): source = SEVASource( id=0, repository_id='pSEVA261', - repository_name='seva', sequence_file_url='https://seva-plasmids.com/maps-canonical/maps-plasmids-SEVAs-canonical-versions-web-1-3-gbk/pSEVA261.gbk', ) response = client.post('/repository_id/seva', json=source.model_dump()) @@ -971,7 +943,6 @@ def test_seva_url(self): source = SEVASource( id=0, repository_id='pSEVA2a2d1', - repository_name='seva', ) response = client.post('/repository_id/seva', json=source.model_dump()) self.assertEqual(response.status_code, 200) @@ -980,7 +951,6 @@ def test_ncbi_url(self): source = SEVASource( id=0, repository_id='pSEVA2214', - repository_name='seva', sequence_file_url='https://www.ncbi.nlm.nih.gov/nuccore/MH650998', ) response = client.post('/repository_id/seva', json=source.model_dump()) @@ -997,7 +967,6 @@ def test_errors(self): source = SEVASource( id=0, repository_id='pSEVA261', - repository_name='seva', sequence_file_url='https://seva-plasmids.com/maps-canonical/maps-plasmids-SEVAs-canonical-versions-web-1-3-gbk/pSEVA261.gbk', ) @@ -1036,14 +1005,14 @@ def test_errors(self): # Mock connection error - source = SEVASource(id=0, repository_id='pSEVA261', repository_name='seva') + source = SEVASource(id=0, repository_id='pSEVA261') with respx.mock: respx.get(source.sequence_file_url).mock(side_effect=httpx.ConnectError('Mock Error')) response = client.post('/repository_id/seva', json=source.model_dump()) self.assertEqual(response.status_code, 504) payload = response.json() - self.assertIn('Unable to connect to seva', payload['detail']) + self.assertIn('Unable to connect to SEVA', payload['detail']) # Mock incorrect file with respx.mock: @@ -1066,7 +1035,6 @@ def test_redirect(self): source = SEVASource( id=0, repository_id='pSEVA261', - repository_name='seva', sequence_file_url='https://seva-plasmids.com/maps-canonical/maps-plasmids-SEVAs-canonical-versions-web-1-3-gbk/pSEVA261.gbk', ) with open(f'{test_files}/ase1.gb', 'r') as f: @@ -1081,7 +1049,6 @@ def test_circularize(self): source = SEVASource( id=0, repository_id='pSEVA261', - repository_name='seva', sequence_file_url='https://seva-plasmids.com/maps-canonical/maps-plasmids-SEVAs-canonical-versions-web-1-3-gbk/pSEVA261.gbk', ) with open(f'{test_files}/ase1.gb', 'r') as f: @@ -1101,7 +1068,6 @@ def test_valid_url(self): source = OpenDNACollectionsSource( id=0, repository_id='Ecoli Nanobody Toolkit/BC_RJ_SD8', - repository_name='open_dna_collections', ) response = client.post('/repository_id/open_dna_collections', json=source.model_dump()) self.assertEqual(response.status_code, 200) @@ -1121,7 +1087,6 @@ def test_errors(self): source = OpenDNACollectionsSource( id=0, repository_id='Ecoli Nanobody Toolkit/BC_RJ_SD8', - repository_name='open_dna_collections', sequence_file_url='https://assets.opencloning.org/open-dna-collections/Ecoli%20Nanobody%20Toolkit/genbank_seq/hello.txt', ) response = client.post('/repository_id/open_dna_collections', json=source.model_dump()) @@ -1130,7 +1095,6 @@ def test_errors(self): source = OpenDNACollectionsSource( id=0, repository_id='hello/BC_RJ_SD8', - repository_name='open_dna_collections', ) response = client.post('/repository_id/open_dna_collections', json=source.model_dump()) self.assertEqual(response.status_code, 404) @@ -1139,7 +1103,6 @@ def test_errors(self): source = OpenDNACollectionsSource( id=0, repository_id='Ecoli Nanobody Toolkit/hello', - repository_name='open_dna_collections', ) response = client.post('/repository_id/open_dna_collections', json=source.model_dump()) self.assertEqual(response.status_code, 404) @@ -1159,7 +1122,6 @@ def test_not_allowed_external_url(self): source = SEVASource( id=0, repository_id='pSEVA261', - repository_name='seva', sequence_file_url='https://seva-plasmids.com/dummy.gbk', ) response = client.post('/repository_id/seva', json=source.model_dump()) diff --git a/tests/test_endpoints_no_input.py b/tests/test_endpoints_no_input.py index 13bcd1fa..8557859c 100644 --- a/tests/test_endpoints_no_input.py +++ b/tests/test_endpoints_no_input.py @@ -11,6 +11,7 @@ TextFileSequence, ManuallyTypedSource, OligoHybridizationSource, + ManuallyTypedSequence, ) @@ -96,10 +97,11 @@ def test_manually_typed(self): # Test linear (default) source = ManuallyTypedSource( id=0, - user_input='ATGC', ) + sequence = ManuallyTypedSequence(id=0, sequence='ATGC') + data = {'source': source.model_dump(), 'sequence': sequence.model_dump()} - response = client.post('/manually_typed', json=source.model_dump()) + response = client.post('/manually_typed', json=data) self.assertEqual(response.status_code, 200) payload = response.json() resulting_sequences = [ @@ -113,8 +115,8 @@ def test_manually_typed(self): self.assertEqual(sources[0], source) # Test circular - source.circular = True - response = client.post('/manually_typed', json=source.model_dump()) + data['sequence']['circular'] = True + response = client.post('/manually_typed', json=data) self.assertEqual(response.status_code, 200) payload = response.json() resulting_sequences = [ @@ -131,12 +133,11 @@ def test_manually_typed(self): # Test overhangs source = ManuallyTypedSource( id=0, - user_input='ATGC', - overhang_crick_3prime=1, - overhang_watson_3prime=2, ) + sequence = ManuallyTypedSequence(id=0, sequence='ATGC', overhang_crick_3prime=1, overhang_watson_3prime=2) + data = {'source': source.model_dump(), 'sequence': sequence.model_dump()} - response = client.post('/manually_typed', json=source.model_dump()) + response = client.post('/manually_typed', json=data) self.assertEqual(response.status_code, 200) payload = response.json() resulting_sequences = [ @@ -147,17 +148,19 @@ def test_manually_typed(self): self.assertEqual(resulting_sequences[0].seq, Dseq.from_full_sequence_and_overhangs('ATGC', 1, 2)) # Test that if overhangs are set, it cannot be circular - wrong_source = source.model_dump() - wrong_source['circular'] = True + wrong_data = data.copy() + wrong_data['sequence']['circular'] = True - response = client.post('/manually_typed', json=wrong_source) + response = client.post('/manually_typed', json=wrong_data) self.assertEqual(response.status_code, 422) # Test that it fails if not acgt or empty def test_manually_typed_fail(self): - response = client.post('/manually_typed', json={'user_input': 'ATGZ'}) + response = client.post( + '/manually_typed', json={'source': {'id': 0}, 'sequence': {'id': 0, 'sequence': 'ATGZ'}} + ) self.assertEqual(response.status_code, 422) - response = client.post('/manually_typed', json={'user_input': ''}) + response = client.post('/manually_typed', json={'source': {'id': 0}, 'sequence': {'id': 0, 'sequence': ''}}) self.assertEqual(response.status_code, 422) diff --git a/tests/test_files/bug_fixing/digestion_spanning_origin.json b/tests/test_files/bug_fixing/digestion_spanning_origin.json index b10689f4..6863fd51 100644 --- a/tests/test_files/bug_fixing/digestion_spanning_origin.json +++ b/tests/test_files/bug_fixing/digestion_spanning_origin.json @@ -31,22 +31,14 @@ "type": "ManuallyTypedSource", "output_name": null, "database_id": null, - "input": [], - "overhang_crick_3prime": 0, - "overhang_watson_3prime": 0, - "user_input": "TTCaaaaGAA", - "circular": true + "input": [] }, { "id": 2, "type": "ManuallyTypedSource", "output_name": null, "database_id": null, - "input": [], - "overhang_crick_3prime": 0, - "overhang_watson_3prime": 0, - "user_input": "ttcccccccgaa", - "circular": true + "input": [] }, { "id": 3, @@ -78,7 +70,7 @@ "primers": [], "description": "", "files": null, - "schema_version": "0.4.3", + "schema_version": "0.4.9", "backend_version": null, "frontend_version": null } diff --git a/tests/test_files/bug_fixing/example_error_assembly_origin_spanning_feature.json b/tests/test_files/bug_fixing/example_error_assembly_origin_spanning_feature.json index 3664a9d1..5874becf 100644 --- a/tests/test_files/bug_fixing/example_error_assembly_origin_spanning_feature.json +++ b/tests/test_files/bug_fixing/example_error_assembly_origin_spanning_feature.json @@ -133,7 +133,7 @@ "primers": [], "description": "", "files": null, - "schema_version": "0.4.3", + "schema_version": "0.4.9", "backend_version": null, "frontend_version": null } diff --git a/tests/test_files/bug_fixing/gateway_13bp_followed_by_digestion.json b/tests/test_files/bug_fixing/gateway_13bp_followed_by_digestion.json index 412ff6e0..722d8971 100644 --- a/tests/test_files/bug_fixing/gateway_13bp_followed_by_digestion.json +++ b/tests/test_files/bug_fixing/gateway_13bp_followed_by_digestion.json @@ -56,13 +56,11 @@ "output_name": null, "database_id": null, "input": [], + "repository_id": "NC_000913.3", + "coordinates": "complement(362231..367305)", "assembly_accession": "GCF_000005845.2", - "sequence_accession": "NC_000913.3", "locus_tag": "b0344", - "gene_id": 945006, - "start": 362231, - "end": 367305, - "strand": -1 + "gene_id": 945006 }, { "id": 2, @@ -70,8 +68,7 @@ "output_name": "pDONR221", "database_id": null, "input": [], - "repository_id": "gateway_cloning_vectors/pDONR221", - "repository_name": "snapgene" + "repository_id": "gateway_cloning_vectors/pDONR221" }, { "id": 3, @@ -79,8 +76,7 @@ "output_name": "pcDNA6.2_C-YFP-DEST", "database_id": null, "input": [], - "repository_id": "gateway_cloning_vectors/pcDNA6.2_C-YFP-DEST", - "repository_name": "snapgene" + "repository_id": "gateway_cloning_vectors/pcDNA6.2_C-YFP-DEST" }, { "id": 4, @@ -197,7 +193,7 @@ ], "description": "Cloning the lacZ gene from E. coli into an entry clone, then expression clone", "files": null, - "schema_version": "0.4.3", + "schema_version": "0.4.9", "backend_version": null, "frontend_version": null } diff --git a/tests/test_files/bug_fixing/gateway_13bp_overlap.json b/tests/test_files/bug_fixing/gateway_13bp_overlap.json index cc3f78c4..b7f2ed91 100644 --- a/tests/test_files/bug_fixing/gateway_13bp_overlap.json +++ b/tests/test_files/bug_fixing/gateway_13bp_overlap.json @@ -56,13 +56,11 @@ "output_name": null, "database_id": null, "input": [], + "repository_id": "NC_000913.3", + "coordinates": "complement(362231..367305)", "assembly_accession": "GCF_000005845.2", - "sequence_accession": "NC_000913.3", "locus_tag": "b0344", - "gene_id": 945006, - "start": 362231, - "end": 367305, - "strand": -1 + "gene_id": 945006 }, { "id": 2, @@ -70,8 +68,7 @@ "output_name": "pDONR221", "database_id": null, "input": [], - "repository_id": "gateway_cloning_vectors/pDONR221", - "repository_name": "snapgene" + "repository_id": "gateway_cloning_vectors/pDONR221" }, { "id": 3, @@ -79,8 +76,7 @@ "output_name": "pcDNA6.2_C-YFP-DEST", "database_id": null, "input": [], - "repository_id": "gateway_cloning_vectors/pcDNA6.2_C-YFP-DEST", - "repository_name": "snapgene" + "repository_id": "gateway_cloning_vectors/pcDNA6.2_C-YFP-DEST" }, { "id": 4, @@ -196,7 +192,7 @@ ], "description": "Cloning the lacZ gene from E. coli into an entry clone, then expression clone", "files": null, - "schema_version": "0.4.3", + "schema_version": "0.4.9", "backend_version": null, "frontend_version": null } diff --git a/tests/test_files/bug_fixing/gateway_correct.json b/tests/test_files/bug_fixing/gateway_correct.json index 40015cf2..57647ca4 100644 --- a/tests/test_files/bug_fixing/gateway_correct.json +++ b/tests/test_files/bug_fixing/gateway_correct.json @@ -40,13 +40,11 @@ "output_name": null, "database_id": null, "input": [], + "repository_id": "NC_000913.3", + "coordinates": "complement(362231..367305)", "assembly_accession": "GCF_000005845.2", - "sequence_accession": "NC_000913.3", "locus_tag": "b0344", - "gene_id": 945006, - "start": 362231, - "end": 367305, - "strand": -1 + "gene_id": 945006 }, { "id": 2, @@ -54,8 +52,7 @@ "output_name": "pDONR221", "database_id": null, "input": [], - "repository_id": "gateway_cloning_vectors/pDONR221", - "repository_name": "snapgene" + "repository_id": "gateway_cloning_vectors/pDONR221" }, { "id": 3, @@ -146,7 +143,7 @@ ], "description": "Cloning the lacZ gene from E. coli into an entry clone, then expression clone", "files": null, - "schema_version": "0.4.3", + "schema_version": "0.4.9", "backend_version": "0.2.8.3.post7.dev0+e39da02", "frontend_version": "v0.2.12.8-4-g30b2f82" } diff --git a/tests/test_files/bug_fixing/homologous_recombination.json b/tests/test_files/bug_fixing/homologous_recombination.json index a31388b7..d405efc9 100644 --- a/tests/test_files/bug_fixing/homologous_recombination.json +++ b/tests/test_files/bug_fixing/homologous_recombination.json @@ -41,7 +41,6 @@ "database_id": null, "input": [], "repository_id": "19342", - "repository_name": "addgene", "sequence_file_url": "https://media.addgene.org/snapgene-media/v2.0.0/sequences/8997/a6b027f8-013a-4b68-bf7e-359f34a653d0/addgene-plasmid-19342-sequence-8997.gbk", "addgene_sequence_type": "depositor-full" }, @@ -82,13 +81,11 @@ "output_name": null, "database_id": null, "input": [], + "repository_id": "CU329670.1", + "coordinates": "1877189..1881726", "assembly_accession": "GCA_000002945.3", - "sequence_accession": "CU329670.1", "locus_tag": "SPOM_SPAPB1A10.09", - "gene_id": null, - "start": 1877189, - "end": 1881726, - "strand": 1 + "gene_id": null }, { "id": 4, @@ -139,7 +136,7 @@ ], "description": "Deletion of the ORF of ase1 by homologous recombination in S.pombe", "files": null, - "schema_version": "0.4.3", + "schema_version": "0.4.9", "backend_version": null, "frontend_version": null } diff --git a/tests/test_files/bug_fixing/pcr_spanning_origin.json b/tests/test_files/bug_fixing/pcr_spanning_origin.json index fbfa442b..75272e04 100644 --- a/tests/test_files/bug_fixing/pcr_spanning_origin.json +++ b/tests/test_files/bug_fixing/pcr_spanning_origin.json @@ -23,11 +23,7 @@ "type": "ManuallyTypedSource", "output_name": null, "database_id": null, - "input": [], - "overhang_crick_3prime": 0, - "overhang_watson_3prime": 0, - "user_input": "ATGCAAACAGTAATGATGGATGACATTCAAAGCACTGATTCTATTGCTGAAAAAGATAATCACTCTAATAATGAATCTAACTTTACTTG", - "circular": true + "input": [] }, { "id": 2, @@ -79,7 +75,7 @@ ], "description": "", "files": null, - "schema_version": "0.4.3", + "schema_version": "0.4.9", "backend_version": null, "frontend_version": null } diff --git a/tests/test_files/homologous_recombination.json b/tests/test_files/homologous_recombination.json index 1f4c8a5e..d405efc9 100644 --- a/tests/test_files/homologous_recombination.json +++ b/tests/test_files/homologous_recombination.json @@ -41,7 +41,6 @@ "database_id": null, "input": [], "repository_id": "19342", - "repository_name": "addgene", "sequence_file_url": "https://media.addgene.org/snapgene-media/v2.0.0/sequences/8997/a6b027f8-013a-4b68-bf7e-359f34a653d0/addgene-plasmid-19342-sequence-8997.gbk", "addgene_sequence_type": "depositor-full" }, @@ -82,13 +81,11 @@ "output_name": null, "database_id": null, "input": [], + "repository_id": "CU329670.1", + "coordinates": "1877189..1881726", "assembly_accession": "GCA_000002945.3", - "sequence_accession": "CU329670.1", "locus_tag": "SPOM_SPAPB1A10.09", - "gene_id": null, - "start": 1877189, - "end": 1881726, - "strand": 1 + "gene_id": null }, { "id": 4, @@ -139,7 +136,7 @@ ], "description": "Deletion of the ORF of ase1 by homologous recombination in S.pombe", "files": null, - "schema_version": "0.4.7", + "schema_version": "0.4.9", "backend_version": null, "frontend_version": null } diff --git a/tests/test_ncbi_requests.py b/tests/test_ncbi_requests.py index 69387517..8f62905e 100644 --- a/tests/test_ncbi_requests.py +++ b/tests/test_ncbi_requests.py @@ -8,6 +8,8 @@ from fastapi import HTTPException import unittest +from Bio.SeqFeature import SimpleLocation + class NcbiAsyncRequestsTest(unittest.IsolatedAsyncioTestCase): @@ -95,11 +97,9 @@ async def test_get_genome_region_from_annotation(self): seq = await ncbi_requests.get_genome_region_from_annotation(annotation, 1000, 1000) self.assertEqual(seq.source.locus_tag, 'YDR294C') self.assertEqual(seq.source.gene_id, 851888) - self.assertEqual(seq.source.sequence_accession, 'NC_001136.10') + self.assertEqual(seq.source.repository_id, 'NC_001136.10') self.assertEqual(seq.source.assembly_accession, 'GCF_000146045.2') - self.assertEqual(seq.source.start, 1049459) - self.assertEqual(seq.source.end, 1053228) - self.assertEqual(seq.source.strand, -1) + self.assertEqual(seq.source.coordinates, SimpleLocation(1049458, 1053228, -1)) self.assertEqual(len(seq), 3770) async def test_get_info_from_annotation(self): @@ -170,3 +170,8 @@ async def test_get_info_from_annotation(self): ) self.assertEqual(gene_id, None) self.assertEqual(locus_tag, None) + + async def test_get_genbank_sequence_errors(self): + with pytest.raises(ValueError) as e: + await ncbi_requests.get_genbank_sequence('NC_003424.3', None, 10, 1) + assert e.value.args[0] == 'start, end, and strand must either all be None or none be None' diff --git a/tests/test_stub_route.py b/tests/test_stub_route.py index c12e3353..7d24c404 100644 --- a/tests/test_stub_route.py +++ b/tests/test_stub_route.py @@ -2,7 +2,7 @@ import unittest import shutil import os -from opencloning_linkml.datamodel import ManuallyTypedSource, RestrictionEnzymeDigestionSource +from opencloning_linkml.datamodel import ManuallyTypedSource, RestrictionEnzymeDigestionSource, ManuallyTypedSequence from pytest import MonkeyPatch from importlib import reload from pydna.dseqrecord import Dseqrecord @@ -43,12 +43,11 @@ def tearDown(self): reload(main) def test_stub_route(self): - source = ManuallyTypedSource( - id=0, - user_input='ATGC', - ) + source = ManuallyTypedSource(id=0) + sequence = ManuallyTypedSequence(id=0, sequence='ATGC') + data = {'source': source.model_dump(), 'sequence': sequence.model_dump()} - response = self.client.post('/manually_typed', json=source.model_dump()) + response = self.client.post('/manually_typed', json=data) self.assertEqual(response.status_code, 200) self.assertTrue(os.path.exists('stubs/manually_typed/'))