diff --git a/poetry.lock b/poetry.lock index cd03643..cc47f36 100644 --- a/poetry.lock +++ b/poetry.lock @@ -689,13 +689,13 @@ files = [ [[package]] name = "jinja2" -version = "3.1.2" +version = "3.1.3" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, ] [package.dependencies] @@ -1052,23 +1052,23 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "psycopg" -version = "3.1.16" +version = "3.1.17" description = "PostgreSQL database adapter for Python" optional = false python-versions = ">=3.7" files = [ - {file = "psycopg-3.1.16-py3-none-any.whl", hash = "sha256:0bfe9741f4fb1c8115cadd8fe832fa91ac277e81e0652ff7fa1400f0ef0f59ba"}, - {file = "psycopg-3.1.16.tar.gz", hash = "sha256:a34d922fd7df3134595e71c3428ba6f1bd5f4968db74857fe95de12db2d6b763"}, + {file = "psycopg-3.1.17-py3-none-any.whl", hash = "sha256:96b7b13af6d5a514118b759a66b2799a8a4aa78675fa6bb0d3f7d52d67eff002"}, + {file = "psycopg-3.1.17.tar.gz", hash = "sha256:437e7d7925459f21de570383e2e10542aceb3b9cb972ce957fdd3826ca47edc6"}, ] [package.dependencies] -psycopg-binary = {version = "3.1.16", optional = true, markers = "implementation_name != \"pypy\" and extra == \"binary\""} +psycopg-binary = {version = "3.1.17", optional = true, markers = "implementation_name != \"pypy\" and extra == \"binary\""} typing-extensions = ">=4.1" tzdata = {version = "*", markers = "sys_platform == \"win32\""} [package.extras] -binary = ["psycopg-binary (==3.1.16)"] -c = ["psycopg-c (==3.1.16)"] +binary = ["psycopg-binary (==3.1.17)"] +c = ["psycopg-c (==3.1.17)"] dev = ["black (>=23.1.0)", "codespell (>=2.2)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=1.4.1)", "types-setuptools (>=57.4)", "wheel (>=0.37)"] docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"] pool = ["psycopg-pool"] @@ -1076,91 +1076,91 @@ test = ["anyio (>=3.6.2,<4.0)", "mypy (>=1.4.1)", "pproxy (>=2.7)", "pytest (>=6 [[package]] name = "psycopg-binary" -version = "3.1.16" +version = "3.1.17" description = "PostgreSQL database adapter for Python -- C optimisation distribution" optional = false python-versions = ">=3.7" files = [ - {file = "psycopg_binary-3.1.16-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e08e333366f8583c7bee33ca6a27f84b76e05ee4e9f9f327a48e3ff81386261d"}, - {file = "psycopg_binary-3.1.16-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a18dfcf7eb3db698eb7a38b4a0e82bf5b76a7bc0079068c5837df70b965570f8"}, - {file = "psycopg_binary-3.1.16-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db99192d9f448829322c4f59a584994ce747b8d586ec65788b4c65f7166cfe43"}, - {file = "psycopg_binary-3.1.16-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f6053fe95596e2f67ff2c9464ea23032c748695a3b79060ca01ef878b0ea0f2"}, - {file = "psycopg_binary-3.1.16-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e6092ec21c08ed4ae4ff343c93a3bbb1d39c87dee181860ce40fa3b5c46f4ae"}, - {file = "psycopg_binary-3.1.16-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f81e880d1bd935433efab1c2883a02031df84e739eadcb2c6a715e9c2f41c19"}, - {file = "psycopg_binary-3.1.16-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:430f8843e381199cdc39ce9506a2cdbc27a569c99a0d80193844c787ce7de94d"}, - {file = "psycopg_binary-3.1.16-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:92bda36f0570a5f9a3d6aeb897bad219f1f23fc4e1d0e7780935798771efb536"}, - {file = "psycopg_binary-3.1.16-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b256d500ec0121ad7875bc3539c43c82dc004535d55256a13c49df2d43f07ad8"}, - {file = "psycopg_binary-3.1.16-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:699737cecf675e1eb70b892b1995456db4016eff7189a3ad9325dca5b6715cc3"}, - {file = "psycopg_binary-3.1.16-cp310-cp310-win_amd64.whl", hash = "sha256:5e0885bcd7d9a0c0043be83d6a214069356c640d42496de798d901d0a16a34e7"}, - {file = "psycopg_binary-3.1.16-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4ee8be32eb8b813ef37c5f5968fe03fdddc9a6f0129190f97f6491c798a1ef57"}, - {file = "psycopg_binary-3.1.16-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8f8fb9677fb7873daf9797207e72e9275f61e769a308c4ea8f55dfd3153ebae7"}, - {file = "psycopg_binary-3.1.16-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a611d7256493ee5bb73a070c9c60206af415be6aee01243c186fc03f1eb1a48"}, - {file = "psycopg_binary-3.1.16-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d267cc92f0f0a9ea6c8ef058e95c85e58133d06c06f4ed48d63fc256aef166ab"}, - {file = "psycopg_binary-3.1.16-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e996b38ffeffbaa06d236bbeab5168d33eea95941cf74de1daa0b008333861b1"}, - {file = "psycopg_binary-3.1.16-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8429017cd7a3ef4699bee4ff8125a5e30b26882b817a178608d73e69fb727ab9"}, - {file = "psycopg_binary-3.1.16-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a7d3b2ea267e7676b3693799fadf941c672f5727fae4947efa1f0cc6e25b672c"}, - {file = "psycopg_binary-3.1.16-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d8290cfd475fadf935da0900dc91b845fe92f792e6d53039c0df82f9049a84ad"}, - {file = "psycopg_binary-3.1.16-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:72539a0c6b9a2a9be2acca993df17f4baaa0ed00f1d76b65733725286e3e3304"}, - {file = "psycopg_binary-3.1.16-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1078370a93eaef1dc5aed540055d50cbe37e9154342f3a3d73fd768a6199344d"}, - {file = "psycopg_binary-3.1.16-cp311-cp311-win_amd64.whl", hash = "sha256:adca24d273fe81ecab2312309db547b345155ec50d15676e2df82b8c5409eb06"}, - {file = "psycopg_binary-3.1.16-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e1c416a7c2a699c3e5ba031357682ebca92bd58f399e553173ab5d67cc71cbc5"}, - {file = "psycopg_binary-3.1.16-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e951a8cc7cf919fdc817a28d57160e7286011a4a45dcad3be21f3e4feba8be1a"}, - {file = "psycopg_binary-3.1.16-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eaa02fe8aa9ef8c8743919fdbc92c04b0ee8c43f3d65e53f24d355776c52fb3"}, - {file = "psycopg_binary-3.1.16-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e23375c14c22ce8fd26d057ac4ab827de79aafced173c68a4c0b03520ea02c70"}, - {file = "psycopg_binary-3.1.16-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84472e5c83e805d4c491f331061cbae3ea4e62f80a480fc4b32200be72262ffd"}, - {file = "psycopg_binary-3.1.16-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b0f824565d1dc325c74c076efd5ba842b86219f8bc1b8048c8816621a8b268c"}, - {file = "psycopg_binary-3.1.16-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6b856d44531475488e773ac78d2a7a91c0909a1e8bdbd20d3ebdbdce1868c9a0"}, - {file = "psycopg_binary-3.1.16-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:198c4f16f806f7d2ad0c4a5b774652e17861b55249efb4e344049b1fcf9a24af"}, - {file = "psycopg_binary-3.1.16-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:b23d4b86acba2d745763ee0801821af1c42b127d8df75b903b7e7ca7c5f6400c"}, - {file = "psycopg_binary-3.1.16-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2cfd857f1085c59da592090f2fa0751da30b67dcafea2ac52c4b404678406aae"}, - {file = "psycopg_binary-3.1.16-cp312-cp312-win_amd64.whl", hash = "sha256:46c9cca48d459d8df71fda4eef7d94a189b8333f4bc3cf1d170c1796fcbbc8cd"}, - {file = "psycopg_binary-3.1.16-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f3136d8f92708c04694ca0cae6a2d6c8170e7174b9ee594218cb229b407e8f48"}, - {file = "psycopg_binary-3.1.16-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1063fe43bb06790a4cfed9f1cacebb165939ca672b6fddcb03627d673ae00bd9"}, - {file = "psycopg_binary-3.1.16-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58289209495a92022e58757add4badb495815a4477f5e9840d481eac2ea422b2"}, - {file = "psycopg_binary-3.1.16-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18c58f99beec18d38094edcb1ae7e6a1e58fb1a53ed08b0f18df714aa4b07cc"}, - {file = "psycopg_binary-3.1.16-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e122c904d4c4e044a3797a62624316cf7359271564f9ebe8ca342ed4a8cef3bd"}, - {file = "psycopg_binary-3.1.16-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:82ffad0edfa3dd77d6aa40c267f61275a6a4061f735cefe97cfd83cfa78e112a"}, - {file = "psycopg_binary-3.1.16-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:82099b6b4b0b12b63c4169d69b48bdbce97e674b86fa51b015e9949fc0ce5c82"}, - {file = "psycopg_binary-3.1.16-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3815c72c590ffe3ad1dc3b7021d082b42215bbd91d2c7211d4a101eec1d0b83e"}, - {file = "psycopg_binary-3.1.16-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2f308bfd39d6dcf3f46165f98d816bce5ac78aaf782eceb3cf43aa0a4fe62f8"}, - {file = "psycopg_binary-3.1.16-cp37-cp37m-win_amd64.whl", hash = "sha256:1e197c3e8d88e984c1e0fcc9a0218947e5a14855939a00b158b428bc449b49e3"}, - {file = "psycopg_binary-3.1.16-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2b22e2dad291a79d7a31b304866fd125038ef7fe378aba9698de0e1804a863c9"}, - {file = "psycopg_binary-3.1.16-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d9e1768c46c595a8177cb709c99626c3cefbd12c2e46eb54323efd8ac4a7fc2d"}, - {file = "psycopg_binary-3.1.16-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8eaabc8dd2d364e1b43d3a25188356191a45abb687b77016544f6847b3fcd73a"}, - {file = "psycopg_binary-3.1.16-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cda744c43b09342b1a8b5aace13d3284c1f5ddbfcefa2d385f703337503a060"}, - {file = "psycopg_binary-3.1.16-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cdaf56adc9cc56df7a05e8f097a776939ba49d5e6afc907ba7b404d8bd21c89"}, - {file = "psycopg_binary-3.1.16-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7232116fc5d4e0274114f152bdb9df089895d4c70f7c03268cab0a4c48a28d04"}, - {file = "psycopg_binary-3.1.16-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6f03239d7c18666f5d6ca82ea972235de4d4d3604287098af6cdc256b76a0ca5"}, - {file = "psycopg_binary-3.1.16-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:edd1b630652bdfff84662b46d11878fbab8ab2966003c1876fcde56650e99e3f"}, - {file = "psycopg_binary-3.1.16-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:481e9dafca1ed9532552e097105e6664ee7f14686270ed0ee0b1d6c78c2cdb11"}, - {file = "psycopg_binary-3.1.16-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d43aa3aa55b5fa964ffa78cf6abdbd51ff33a759f290e9159a9f974ffa3178fa"}, - {file = "psycopg_binary-3.1.16-cp38-cp38-win_amd64.whl", hash = "sha256:51e66b282d8689bc33d81bde3a1e14d0c88a39200c2d9436b028b394d24f1f99"}, - {file = "psycopg_binary-3.1.16-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bfae154f3c88e67f3ed592765ad56531b6076acfe80796e28cccc05727c1cf5b"}, - {file = "psycopg_binary-3.1.16-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f9f4bc3d366951359a68833c8031cc83faf5084b3bc80dd2d24f0add593d4418"}, - {file = "psycopg_binary-3.1.16-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a37d682d7ff57cc2573b1011740ef1566749fc94ae6ac1456405510592735c0a"}, - {file = "psycopg_binary-3.1.16-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0be876e3a8ee359f6a985b662c6b02a094a50b37adf1bd756a655004bddf167a"}, - {file = "psycopg_binary-3.1.16-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f79192b0edd60ef24acb0af5b83319cbb65d4187576757b690646b290de8307"}, - {file = "psycopg_binary-3.1.16-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcc5996b1db4e7fb948ea47b610456df317625d92474c779a20f92ca8cbcec92"}, - {file = "psycopg_binary-3.1.16-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3f2ceb04f8137462f9312a324bea5402de0a4f0503cd5442f4264911e4b6265b"}, - {file = "psycopg_binary-3.1.16-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:47517d2da63bb10c80c2cf35c80a936db79636534849524fd57940b5f0bbd7bd"}, - {file = "psycopg_binary-3.1.16-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:2a6bd83d0b934aa03897e93acb6897972ccc3827ae61c903589bc92ed423f75d"}, - {file = "psycopg_binary-3.1.16-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:08fb94928e785571ac90d3ab9e09f2721e0d895c2504ecfb8de91c5ea807b267"}, - {file = "psycopg_binary-3.1.16-cp39-cp39-win_amd64.whl", hash = "sha256:cf13807b61315130a59ea8d0950bda2ac875bae9fadc0b1a9aca9b4ef6d62c7b"}, + {file = "psycopg_binary-3.1.17-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9ba559eabb0ba1afd4e0504fa0b10e00a212cac0c4028b8a1c3b087b5c1e5de"}, + {file = "psycopg_binary-3.1.17-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2b2a689eaede08cf91a36b10b0da6568dd6e4669200f201e082639816737992b"}, + {file = "psycopg_binary-3.1.17-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a16abab0c1abc58feb6ab11d78d0f8178a67c3586bd70628ec7c0218ec04c4ef"}, + {file = "psycopg_binary-3.1.17-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73e7097b81cad9ae358334e3cec625246bb3b8013ae6bb287758dd6435e12f65"}, + {file = "psycopg_binary-3.1.17-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:67a5b93101bc85a95a189c0a23d02a29cf06c1080a695a0dedfdd50dd734662a"}, + {file = "psycopg_binary-3.1.17-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:751b31c2faae0348f87f22b45ef58f704bdcfc2abdd680fa0c743c124071157e"}, + {file = "psycopg_binary-3.1.17-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b447ea765e71bc33a82cf070bba814b1efa77967442d116b95ccef8ce5da7631"}, + {file = "psycopg_binary-3.1.17-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d2e9ed88d9a6a475c67bf70fc8285e88ccece0391727c7701e5a512e0eafbb05"}, + {file = "psycopg_binary-3.1.17-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a89f36bf7b612ff6ed3e789bd987cbd0787cf0d66c49386fa3bad816dd7bee87"}, + {file = "psycopg_binary-3.1.17-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5ccbe8b2ec444763a51ecb1213befcbb75defc1ef36e7dd5dff501a23d7ce8cf"}, + {file = "psycopg_binary-3.1.17-cp310-cp310-win_amd64.whl", hash = "sha256:adb670031b27949c9dc5cf585c4a5a6b4469d3879fd2fb9d39b6d53e5f66b9bc"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0227885686c2cc0104ceb22d6eebc732766e9ad48710408cb0123237432e5435"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9124b6db07e8d8b11f4512b8b56cbe136bf1b7d0417d1280e62291a9dcad4408"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8a46f77ba0ca7c5a5449b777170a518fa7820e1710edb40e777c9798f00d033"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f5f5bcbb772d8c243d605fc7151beec760dd27532d42145a58fb74ef9c5fbf2"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:267a82548c21476120e43dc72b961f1af52c380c0b4c951bdb34cf14cb26bd35"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b20013051f1fd7d02b8d0766cfe8d009e8078babc00a6d39bc7e2d50a7b96af"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c5c38129cc79d7e3ba553035b9962a442171e9f97bb1b8795c0885213f206f3"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d01c4faae66de60fcd3afd3720dcc8ffa03bc2087f898106da127774db12aac5"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e6ae27b0617ad3809449964b5e901b21acff8e306abacb8ba71d5ee7c8c47eeb"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:40af298b209dd77ca2f3e7eb3fbcfb87a25999fc015fcd14140bde030a164c7e"}, + {file = "psycopg_binary-3.1.17-cp311-cp311-win_amd64.whl", hash = "sha256:7b4e4c2b05f3b431e9026e82590b217e87696e7a7548f512ae8059d59fa8af3b"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ea425a8dcd808a7232a5417d2633bfa543da583a2701b5228e9e29989a50deda"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3f1196d76860e72d338fab0d2b6722e8d47e2285d693e366ae36011c4a5898a"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1e867c2a729348df218a14ba1b862e627177fd57c7b4f3db0b4c708f6d03696"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0711e46361ea3047cd049868419d030c8236a9dea7e9ed1f053cbd61a853ec9"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1c0115bdf80cf6c8c9109cb10cf6f650fd1a8d841f884925e8cb12f34eb5371"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d0d154c780cc7b28a3a0886e8a4b18689202a1dbb522b3c771eb3a1289cf7c3"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f4028443bf25c1e04ecffdc552c0a98d826903dec76a1568dfddf5ebbbb03db7"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bf424d92dd7e94705b31625b02d396297a7c8fab4b6f7de8dba6388323a7b71c"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:00377f6963ee7e4bf71cab17c2c235ef0624df9483f3b615d86aa24cde889d42"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9690a535d9ccd361bbc3590bfce7fe679e847f44fa7cc97f3b885f4744ca8a2c"}, + {file = "psycopg_binary-3.1.17-cp312-cp312-win_amd64.whl", hash = "sha256:6b2ae342d69684555bfe77aed5546d125b4a99012e0b83a8b3da68c8829f0935"}, + {file = "psycopg_binary-3.1.17-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:86bb3656c8d744cc1e42003414cd6c765117d70aa23da6c0f4ff2b826e0fd0fd"}, + {file = "psycopg_binary-3.1.17-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c10b7713e3ed31df7319c2a72d5fea5a2536476d7695a3e1d18a1f289060997c"}, + {file = "psycopg_binary-3.1.17-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12eab8bc91b4ba01b2ecee3b5b80501934b198f6e1f8d4b13596f3f38ba6e762"}, + {file = "psycopg_binary-3.1.17-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6a728beefd89b430ebe2729d04ba10e05036b5e9d01648da60436000d2fcd242"}, + {file = "psycopg_binary-3.1.17-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61104b8e7a43babf2bbaa36c08e31a12023e2f967166e99d6b052b11a4c7db06"}, + {file = "psycopg_binary-3.1.17-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:02cd2eb62ffc56f8c847d68765cbf461b3d11b438fe48951e44b6c563ec27d18"}, + {file = "psycopg_binary-3.1.17-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ca1757a6e080086f7234dc45684e81a47a66a6dd492a37d6ce38c58a1a93e9ff"}, + {file = "psycopg_binary-3.1.17-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:6e3543edc18553e31a3884af3cd7eea43d6c44532d8b9b16f3e743cdf6cfe6c5"}, + {file = "psycopg_binary-3.1.17-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:914254849486e14aa931b0b3382cd16887f1507068ffba775cbdc5a55fe9ef19"}, + {file = "psycopg_binary-3.1.17-cp37-cp37m-win_amd64.whl", hash = "sha256:92fad8f1aa80a5ab316c0493dc6d1b54c1dba21937e43eea7296ff4a0ccc071e"}, + {file = "psycopg_binary-3.1.17-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6d4f2e15d33ed4f9776fdf23683512d76f4e7825c4b80677e9e3ce6c1b193ff2"}, + {file = "psycopg_binary-3.1.17-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4fa26836ce074a1104249378727e1f239a01530f36bae16e77cf6c50968599b4"}, + {file = "psycopg_binary-3.1.17-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d54bcf2dfc0880bf13f38512d44b194c092794e4ee9e01d804bc6cd3eed9bfb7"}, + {file = "psycopg_binary-3.1.17-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e28024204dc0c61094268c682041d2becfedfea2e3b46bed5f6138239304d98"}, + {file = "psycopg_binary-3.1.17-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b1ec6895cab887b92c303565617f994c9b9db53befda81fa2a31b76fe8a3ab1"}, + {file = "psycopg_binary-3.1.17-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:420c1eb1626539c261cf3fbe099998da73eb990f9ce1a34da7feda414012ea5f"}, + {file = "psycopg_binary-3.1.17-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:83404a353240fdff5cfe9080665fdfdcaa2d4d0c5112e15b0a2fe2e59200ed57"}, + {file = "psycopg_binary-3.1.17-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a0c4ba73f9e7721dd6cc3e6953016652dbac206f654229b7a1a8ac182b16e689"}, + {file = "psycopg_binary-3.1.17-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f6898bf1ca5aa01115807643138e3e20ec603b17a811026bc4a49d43055720a7"}, + {file = "psycopg_binary-3.1.17-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6b40fa54a02825d3d6a8009d9a82a2b4fad80387acf2b8fd6d398fd2813cb2d9"}, + {file = "psycopg_binary-3.1.17-cp38-cp38-win_amd64.whl", hash = "sha256:78ebb43dca7d5b41eee543cd005ee5a0256cecc74d84acf0fab4f025997b837e"}, + {file = "psycopg_binary-3.1.17-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:02ac573f5a6e79bb6df512b3a6279f01f033bbd45c47186e8872fee45f6681d0"}, + {file = "psycopg_binary-3.1.17-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:704f6393d758b12a4369887fe956b2a8c99e4aced839d9084de8e3f056015d40"}, + {file = "psycopg_binary-3.1.17-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0340ef87a888fd940796c909e038426f4901046f61856598582a817162c64984"}, + {file = "psycopg_binary-3.1.17-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a880e4113af3ab84d6a0991e3f85a2424924c8a182733ab8d964421df8b5190a"}, + {file = "psycopg_binary-3.1.17-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93921178b9a40c60c26e47eb44970f88c49fe484aaa3bb7ec02bb8b514eab3d9"}, + {file = "psycopg_binary-3.1.17-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a05400e9314fc30bc1364865ba9f6eaa2def42b5e7e67f71f9a4430f870023e"}, + {file = "psycopg_binary-3.1.17-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3e2cc2bbf37ff1cf11e8b871c294e3532636a3cf7f0c82518b7537158923d77b"}, + {file = "psycopg_binary-3.1.17-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a343261701a8f63f0d8268f7fd32be40ffe28d24b65d905404ca03e7281f7bb5"}, + {file = "psycopg_binary-3.1.17-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:dceb3930ec426623c0cacc78e447a90882981e8c49d6fea8d1e48850e24a0170"}, + {file = "psycopg_binary-3.1.17-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d613a23f8928f30acb2b6b2398cb7775ba9852e8968e15df13807ba0d3ebd565"}, + {file = "psycopg_binary-3.1.17-cp39-cp39-win_amd64.whl", hash = "sha256:d90c0531e9d591bde8cea04e75107fcddcc56811b638a34853436b23c9a3cb7d"}, ] [[package]] name = "psycopg-pool" -version = "3.2.0" +version = "3.2.1" description = "Connection Pool for Psycopg" optional = false python-versions = ">=3.8" files = [ - {file = "psycopg-pool-3.2.0.tar.gz", hash = "sha256:2e857bb6c120d012dba240e30e5dff839d2d69daf3e962127ce6b8e40594170e"}, - {file = "psycopg_pool-3.2.0-py3-none-any.whl", hash = "sha256:73371d4e795d9363c7b496cbb2dfce94ee8fbf2dcdc384d0a937d1d9d8bdd08d"}, + {file = "psycopg-pool-3.2.1.tar.gz", hash = "sha256:6509a75c073590952915eddbba7ce8b8332a440a31e77bba69561483492829ad"}, + {file = "psycopg_pool-3.2.1-py3-none-any.whl", hash = "sha256:060b551d1b97a8d358c668be58b637780b884de14d861f4f5ecc48b7563aafb7"}, ] [package.dependencies] -typing-extensions = ">=3.10" +typing-extensions = ">=4.4" [[package]] name = "pyasn1" @@ -1885,3 +1885,4 @@ files = [ lock-version = "2.0" python-versions = "^3.9" content-hash = "cae6f54e57292b2269f04c5841188588494b5c95b06bd9bc90d5680113aceac8" + diff --git a/pyproject.toml b/pyproject.toml index 58a1596..55c35e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "geneweaver-api" -version = "0.0.1a6" +version = "0.0.1a7" description = "description" authors = ["Jax Computational Sciences "] packages = [ diff --git a/src/geneweaver/api/controller/genesets.py b/src/geneweaver/api/controller/genesets.py index e454169..695f0fc 100644 --- a/src/geneweaver/api/controller/genesets.py +++ b/src/geneweaver/api/controller/genesets.py @@ -1,10 +1,16 @@ """Endpoints related to genesets.""" +import json +import os +import time +from tempfile import TemporaryDirectory from typing import Optional -from fastapi import APIRouter, Depends, HTTPException, Security +from fastapi import APIRouter, Depends, HTTPException, Query, Security +from fastapi.responses import FileResponse from geneweaver.api import dependencies as deps from geneweaver.api.schemas.auth import UserInternal from geneweaver.api.services import geneset as genset_service +from geneweaver.core.enum import GeneIdentifier from geneweaver.core.schema.geneset import GenesetUpload from geneweaver.db import geneset as db_geneset from geneweaver.db import geneset_value as db_geneset_value @@ -12,6 +18,7 @@ from . import message as api_message router = APIRouter(prefix="/genesets") +gene_id_type_options = [f"{choice.name} ({choice.value})" for choice in GeneIdentifier] @router.get("") @@ -29,19 +36,79 @@ def get_geneset( geneset_id: int, user: UserInternal = Security(deps.full_user), cursor: Optional[deps.Cursor] = Depends(deps.cursor), + # using int type and adding doc options here as using GeneIdentifier + # won't produce the right docs for gene identifier options + gene_id_type: Optional[int] = Query( + None, description=f"Options: {gene_id_type_options}" + ), ) -> dict: - """Get a geneset by ID.""" - response = genset_service.get_geneset(cursor, geneset_id, user) + """Get a geneset by ID. Optional filter results by gene identifier type.""" + if gene_id_type: + gene_identifier_type = get_gene_identifier_type(gene_id_type) + response = genset_service.get_geneset_w_gene_id_type( + cursor, geneset_id, user, gene_identifier_type + ) + else: + response = genset_service.get_geneset(cursor, geneset_id, user) if "error" in response: - if response.get("message") == api_message.ACCESS_FORBIDEN: - raise HTTPException(status_code=403, detail=api_message.ACCESS_FORBIDEN) + if response.get("message") == api_message.ACCESS_FORBIDDEN: + raise HTTPException(status_code=403, detail=api_message.ACCESS_FORBIDDEN) else: raise HTTPException(status_code=500, detail=api_message.UNEXPECTED_ERROR) return response +@router.get("/{geneset_id}/file", response_class=FileResponse) +def get_export_geneset_by_id_type( + geneset_id: int, + user: UserInternal = Security(deps.full_user), + cursor: Optional[deps.Cursor] = Depends(deps.cursor), + temp_dir: TemporaryDirectory = Depends(deps.get_temp_dir), + # using int type and adding doc options here as using + # GeneIdentifier won't produce the right docs for gene identifier options + gene_id_type: Optional[int] = Query( + None, description=f"Options: {gene_id_type_options}" + ), +) -> dict: + """Export geneset into JSON file. Search by ID and optional gene identifier type.""" + timestr = time.strftime("%Y%m%d-%H%M%S") + + # Validate gene identifier type + if gene_id_type: + gene_identifier_type = get_gene_identifier_type(gene_id_type) + response = genset_service.get_geneset_w_gene_id_type( + cursor, geneset_id, user, gene_identifier_type + ) + else: + response = genset_service.get_geneset(cursor, geneset_id, user) + + if "error" in response: + if response.get("message") == api_message.ACCESS_FORBIDDEN: + raise HTTPException(status_code=403, detail=api_message.ACCESS_FORBIDDEN) + else: + raise HTTPException(status_code=500, detail=api_message.UNEXPECTED_ERROR) + + id_type = response.get("gene_identifier_type") + if id_type: + geneset_filename = f"geneset_{geneset_id}_{id_type}_{timestr}.json" + else: + geneset_filename = f"geneset_{geneset_id}_{timestr}.json" + + # Write the data to temp file + temp_file_path = os.path.join(temp_dir, geneset_filename) + with open(temp_file_path, "w") as f: + json.dump(response, f, default=str) + + # Return as a download + return FileResponse( + path=temp_file_path, + media_type="application/octet-stream", + filename=geneset_filename, + ) + + @router.post("") def upload_geneset( geneset: GenesetUpload, @@ -51,3 +118,20 @@ def upload_geneset( """Upload a geneset.""" db_geneset_value.format_geneset_values_for_file_insert(geneset.gene_list) return {"geneset_id": 0} + + +def get_gene_identifier_type(gene_id_type: int) -> GeneIdentifier: + """Get a valid GeneIdentifier object. Raise HTTP exception if invalid value. + + @param gene_id_type: gene identifier type + @return: GeneIdentifier obj or HTTP exception if invalid id value. + """ + try: + gene_identifier = GeneIdentifier(gene_id_type) + except ValueError as err: + raise HTTPException( + status_code=400, + detail=f"{api_message.GENE_IDENTIFIER_TYPE_VALUE_ERROR}, " + f"valid options= {gene_id_type_options}", + ) from err + return gene_identifier diff --git a/src/geneweaver/api/controller/message.py b/src/geneweaver/api/controller/message.py index 553f50f..4444ae5 100644 --- a/src/geneweaver/api/controller/message.py +++ b/src/geneweaver/api/controller/message.py @@ -2,5 +2,6 @@ ##Errors -ACCESS_FORBIDEN = "Forbidden" +ACCESS_FORBIDDEN = "Forbidden" UNEXPECTED_ERROR = "Unexpected Error" +GENE_IDENTIFIER_TYPE_VALUE_ERROR = "Invalid gene identifier type" diff --git a/src/geneweaver/api/dependencies.py b/src/geneweaver/api/dependencies.py index c2e7a1a..98a6cf4 100644 --- a/src/geneweaver/api/dependencies.py +++ b/src/geneweaver/api/dependencies.py @@ -1,5 +1,6 @@ """Dependency injection capabilities for the GeneWeaver API.""" # ruff: noqa: B008 +from tempfile import TemporaryDirectory from typing import Generator import psycopg @@ -27,11 +28,20 @@ def cursor() -> Generator: yield cur -def full_user( +async def full_user( cursor: Cursor = Depends(cursor), user: UserInternal = Depends(auth.get_user_strict), ) -> UserInternal: - """Get the full user object.""" "" + """Get the full user object. + + Since there are external dependencies to wait for, + the recommendation is to use async + Also, Workaround FASTAPI issue, where logs hide exact place of errors + https://github.com/tiangolo/fastapi/discussions/8428 + Geneweaver issue: G3-96. + @param cursor: DB cursor + @param user: GW user. + """ try: user.id = db_user.by_sso_id_and_email(cursor, user.sso_id, user.email)[0][ "usr_id" @@ -49,3 +59,12 @@ def full_user( ) yield user + + +async def get_temp_dir() -> TemporaryDirectory: + """Get a temp directory.""" + temp_dir = TemporaryDirectory() + try: + yield temp_dir.name + finally: + del temp_dir diff --git a/src/geneweaver/api/services/geneset.py b/src/geneweaver/api/services/geneset.py index ce710b7..dbf1faa 100644 --- a/src/geneweaver/api/services/geneset.py +++ b/src/geneweaver/api/services/geneset.py @@ -3,6 +3,7 @@ from fastapi.logger import logger from geneweaver.api.controller import message from geneweaver.api.schemas.auth import User +from geneweaver.core.enum import GeneIdentifier from geneweaver.db import geneset as db_geneset from geneweaver.db import geneset_value as db_geneset_value from geneweaver.db.geneset import is_readable as db_is_readable @@ -10,10 +11,16 @@ def get_geneset(cursor: Cursor, geneset_id: int, user: User) -> dict: - """Get a geneset by ID.""" + """Get a geneset by ID. + + @param cursor: DB cursor + @param geneset_id: geneset identifier + @param user: GW user + @return: dictionary response (geneset and genset values). + """ try: if not is_geneset_readable_by_user(cursor, geneset_id, user): - return {"error": True, "message": message.ACCESS_FORBIDEN} + return {"error": True, "message": message.ACCESS_FORBIDDEN} geneset = db_geneset.by_id(cursor, geneset_id) geneset_values = db_geneset_value.by_geneset_id(cursor, geneset_id) @@ -24,8 +31,44 @@ def get_geneset(cursor: Cursor, geneset_id: int, user: User) -> dict: raise err +def get_geneset_w_gene_id_type( + cursor: Cursor, geneset_id: int, user: User, gene_id_type: GeneIdentifier +) -> dict: + """Get a geneset by ID and filter with gene identifier type. + + @param cursor: DB cursor + @param geneset_id: geneset identifier + @param user: GW user + @param gene_id_type: gene identifier type object + @return: Dictionary response (geneset identifier, geneset, and genset values). + """ + try: + if not is_geneset_readable_by_user(cursor, geneset_id, user): + return {"error": True, "message": message.ACCESS_FORBIDDEN} + + geneset = db_geneset.by_id(cursor, geneset_id) + geneset_values = db_geneset_value.by_geneset_id( + cursor, geneset_id, gene_id_type + ) + return { + "gene_identifier_type": gene_id_type.name, + "geneset": geneset, + "geneset_values": geneset_values, + } + + except Exception as err: + logger.error(err) + raise err + + def is_geneset_readable_by_user(cursor: Cursor, geneset_id: int, user: User) -> bool: - """Check if the user can read the geneset from DB.""" + """Check if the user can read the geneset from DB. + + @param cursor: DB cursor object + @param geneset_id: geneset identifier + @param user: GW user + @return: True if geneset is readable by user. + """ readable: bool = False try: readable = db_is_readable(cursor, user.id, geneset_id) diff --git a/tests/controllers/conftest.py b/tests/controllers/conftest.py index 2643700..2eba450 100644 --- a/tests/controllers/conftest.py +++ b/tests/controllers/conftest.py @@ -1,6 +1,4 @@ """Fixtures for the controller tests.""" -import importlib.resources -import json from unittest.mock import Mock import psycopg @@ -8,16 +6,6 @@ from fastapi.testclient import TestClient from geneweaver.api.core.config_class import GeneweaverAPIConfig -# Load test data -# Opening JSON file -str_json = importlib.resources.read_text("tests.data", "response_geneset_1234.json") -# returns JSON string as a dictionary -test_data = json.loads(str_json) - -response_mock = Mock() -response_mock.status_code = 200 -response_mock.json.return_value = test_data - # Mock dependencies def mock_full_user() -> Mock: diff --git a/tests/controllers/test_genesets.py b/tests/controllers/test_genesets.py index 219dbf6..e525169 100644 --- a/tests/controllers/test_genesets.py +++ b/tests/controllers/test_genesets.py @@ -2,8 +2,12 @@ from unittest.mock import patch import pytest +from geneweaver.api.controller import message -from tests.controllers.conftest import test_data +from tests.data import test_geneset_data + +geneset_by_id_resp = test_geneset_data.get("geneset_by_id_resp") +geneset_w_gene_id_type_resp = test_geneset_data.get("geneset_w_gene_id_type_resp") @patch("geneweaver.api.services.geneset.get_geneset") @@ -11,11 +15,11 @@ def test_get_geneset_response(mock_genset_is_readable, mock_get_genenset, client): """Test get geneset ID data response.""" mock_genset_is_readable.return_value = True - mock_get_genenset.return_value = test_data + mock_get_genenset.return_value = geneset_by_id_resp response = client.get("/api/genesets/1234") assert response.status_code == 200 - assert response.json() == test_data + assert response.json() == geneset_by_id_resp @patch("geneweaver.api.services.geneset.db_is_readable") @@ -35,3 +39,44 @@ def test_get_geneset_unexpected_error(mock_genset_is_readable, client): with pytest.raises(expected_exception=Exception): client.get("/api/genesets/1234") + + +@patch("geneweaver.api.services.geneset.get_geneset_w_gene_id_type") +def test_get_geneset_w_gene_id_type(mock_service_get_geneset_w_gene_id_type, client): + """Test get geneset with gene id type response.""" + mock_service_get_geneset_w_gene_id_type.return_value = geneset_w_gene_id_type_resp + response = client.get("/api/genesets/1234?gene_id_type=2") + + assert response.json() == geneset_w_gene_id_type_resp + assert response.status_code == 200 + + +@patch("geneweaver.api.services.geneset.db_is_readable") +def test_get_geneset_export_forbidden(mock_genset_is_readable, client): + """Test export forbidden response.""" + mock_genset_is_readable.return_value = False + response = client.get("/api/genesets/1234/file?gene_id_type=2") + + assert response.json() == {"detail": "Forbidden"} + assert response.status_code == 403 + + +@patch("geneweaver.api.services.geneset.get_geneset_w_gene_id_type") +def test_export_geneset_w_gene_id_type(mock_service_get_geneset_w_gene_id_type, client): + """Test geneset file export.""" + mock_service_get_geneset_w_gene_id_type.return_value = geneset_w_gene_id_type_resp + response = client.get("/api/genesets/1234/file?gene_id_type=2") + + assert response.headers.get("content-type") == "application/octet-stream" + assert int(response.headers.get("content-length")) > 0 + assert response.status_code == 200 + + +@patch("geneweaver.api.services.geneset.get_geneset_w_gene_id_type") +def test_invalid_gene_type_id(mock_service_get_geneset_w_gene_id_type, client): + """Test geneset file export.""" + mock_service_get_geneset_w_gene_id_type.return_value = geneset_w_gene_id_type_resp + response = client.get("/api/genesets/1234/file?gene_id_type=25") + + assert message.GENE_IDENTIFIER_TYPE_VALUE_ERROR in response.json()["detail"] + assert response.status_code == 400 diff --git a/tests/data/__init__.py b/tests/data/__init__.py index 2d1c0a9..8aa53ca 100644 --- a/tests/data/__init__.py +++ b/tests/data/__init__.py @@ -1 +1,19 @@ """Data package for tests.""" + +import importlib.resources +import json + +## Load test data +# Opening JSON files +geneset_response_json = importlib.resources.read_text( + "tests.data", "response_geneset_1234.json" +) +geneset_w_gene_id_type_json = importlib.resources.read_text( + "tests.data", "response_geneset_w_gene_id_type.json" +) + +# returns JSON string as a dictionary +test_geneset_data = { + "geneset_by_id_resp": json.loads(geneset_response_json), + "geneset_w_gene_id_type_resp": json.loads(geneset_w_gene_id_type_json), +} diff --git a/tests/data/response_geneset_1234.json b/tests/data/response_geneset_1234.json index 8b8b931..82063fb 100644 --- a/tests/data/response_geneset_1234.json +++ b/tests/data/response_geneset_1234.json @@ -1,5 +1,33 @@ { - "geneset": null, + "geneset": { + "gs_id": 1234, + "usr_id": 51, + "file_id": 1715, + "gs_name": "Differential expression in heroin and cocaine abusers-Down-regulated Cocaine, Up-regulated Heroin", + "gs_abbreviation": "UpRegHeroinDwnRegCocaine", + "pub_id": 6, + "res_id": null, + "cur_id": 3, + "gs_description": "From the initial set of differentially expressed genes in post mortum nucleus accumbens of chronic heroin and cocaine abusers, this set contains genes upregulated in cocaine abusers but downregulated in heroin abusers.", + "sp_id": 2, + "gs_count": 3, + "gs_threshold_type": 3, + "gs_threshold": "0.5", + "gs_groups": "0", + "gs_attribution_old": null, + "gs_uri": null, + "gs_gene_id_type": -7, + "_searchtext": "'abus':8A,34B,42B,47B 'abusers-down-regul':7A 'accumben':28B 'chronic':30B 'cocain':6A,11A,33B,41B 'contain':37B 'differenti':1A,21B 'downregul':44B 'express':2A,22B 'gene':23B,38B 'heroin':4A,15A,31B,46B 'initi':18B 'mortum':26B 'nucleus':27B 'post':25B 'regul':10A,14A 'set':19B,36B 'up-regul':12A 'upregul':39B", + "gs_created": "2008-04-22", + "admin_flag": null, + "gs_updated": "2020-05-06T09:19:44.883323", + "gs_status": "normal", + "gsv_qual": "{}", + "_comments_author": null, + "_comments_curator": null, + "gs_attribution": null, + "gs_is_edgelist": false + }, "geneset_values": [ { "gs_id": 1234, @@ -14,7 +42,7 @@ ], "gsv_in_threshold": true, "gsv_date": "2020-05-05", - "ode_ref_id": "PDE4DIP" + "ode_ref_id": "Hs.456585" }, { "gs_id": 1234, @@ -29,7 +57,7 @@ ], "gsv_in_threshold": true, "gsv_date": "2020-05-05", - "ode_ref_id": "PMEPA1" + "ode_ref_id": "HGNC:14107" }, { "gs_id": 1234, @@ -44,7 +72,7 @@ ], "gsv_in_threshold": true, "gsv_date": "2020-05-05", - "ode_ref_id": "PREPL" + "ode_ref_id": "Hs.541341" } ] -} \ No newline at end of file +} diff --git a/tests/data/response_geneset_w_gene_id_type.json b/tests/data/response_geneset_w_gene_id_type.json new file mode 100644 index 0000000..a667041 --- /dev/null +++ b/tests/data/response_geneset_w_gene_id_type.json @@ -0,0 +1,143 @@ +{ + "gene_identifier_type": "ENSEMBLE_GENE", + "geneset": { + "gs_id": 1234, + "usr_id": 51, + "file_id": 1715, + "gs_name": "Differential expression in heroin and cocaine abusers-Down-regulated Cocaine, Up-regulated Heroin", + "gs_abbreviation": "UpRegHeroinDwnRegCocaine", + "pub_id": 6, + "res_id": null, + "cur_id": 3, + "gs_description": "From the initial set of differentially expressed genes in post mortum nucleus accumbens of chronic heroin and cocaine abusers, this set contains genes upregulated in cocaine abusers but downregulated in heroin abusers.", + "sp_id": 2, + "gs_count": 3, + "gs_threshold_type": 3, + "gs_threshold": "0.5", + "gs_groups": "0", + "gs_attribution_old": null, + "gs_uri": null, + "gs_gene_id_type": -7, + "_searchtext": "'abus':8A,34B,42B,47B 'abusers-down-regul':7A 'accumben':28B 'chronic':30B 'cocain':6A,11A,33B,41B 'contain':37B 'differenti':1A,21B 'downregul':44B 'express':2A,22B 'gene':23B,38B 'heroin':4A,15A,31B,46B 'initi':18B 'mortum':26B 'nucleus':27B 'post':25B 'regul':10A,14A 'set':19B,36B 'up-regul':12A 'upregul':39B", + "gs_created": "2008-04-22", + "admin_flag": null, + "gs_updated": "2020-05-06T09:19:44.883323", + "gs_status": "normal", + "gsv_qual": "{}", + "_comments_author": null, + "_comments_curator": null, + "gs_attribution": null, + "gs_is_edgelist": false + }, + "geneset_values": [ + { + "gs_id": 1234, + "ode_gene_id": 70495, + "gsv_value": 1, + "gsv_hits": 1, + "gsv_source_list": [ + "PDE4DIP" + ], + "gsv_value_list": [ + 1 + ], + "gsv_in_threshold": true, + "gsv_date": "2020-05-05", + "hom_id": 66961, + "gene_rank": 0, + "ode_ref_id": "ENSG00000178104", + "gdb_id": 2 + }, + { + "gs_id": 1234, + "ode_gene_id": 70495, + "gsv_value": 1, + "gsv_hits": 1, + "gsv_source_list": [ + "PDE4DIP" + ], + "gsv_value_list": [ + 1 + ], + "gsv_in_threshold": true, + "gsv_date": "2020-05-05", + "hom_id": 66961, + "gene_rank": 0, + "ode_ref_id": "ENSG00000178104", + "gdb_id": 2 + }, + { + "gs_id": 1234, + "ode_gene_id": 83819, + "gsv_value": 1, + "gsv_hits": 1, + "gsv_source_list": [ + "TMEPAI" + ], + "gsv_value_list": [ + 1 + ], + "gsv_in_threshold": true, + "gsv_date": "2020-05-05", + "hom_id": 10608, + "gene_rank": 0, + "ode_ref_id": "ENSG00000124225", + "gdb_id": 2 + }, + { + "gs_id": 1234, + "ode_gene_id": 83819, + "gsv_value": 1, + "gsv_hits": 1, + "gsv_source_list": [ + "TMEPAI" + ], + "gsv_value_list": [ + 1 + ], + "gsv_in_threshold": true, + "gsv_date": "2020-05-05", + "hom_id": 10608, + "gene_rank": 0, + "ode_ref_id": "ENSG00000124225", + "gdb_id": 2 + }, + { + "gs_id": 1234, + "ode_gene_id": 90284, + "gsv_value": 1, + "gsv_hits": 1, + "gsv_source_list": [ + "PREPL" + ], + "gsv_value_list": [ + 1 + ], + "gsv_in_threshold": true, + "gsv_date": "2020-05-05", + "hom_id": 15481, + "gene_rank": 0, + "ode_ref_id": "ENSG00000138078", + "gdb_id": 2 + }, + { + "gs_id": 1234, + "ode_gene_id": 90284, + "gsv_value": 1, + "gsv_hits": 1, + "gsv_source_list": [ + "PREPL" + ], + "gsv_value_list": [ + 1 + ], + "gsv_in_threshold": true, + "gsv_date": "2020-05-05", + "hom_id": 15481, + "gene_rank": 0, + "ode_ref_id": "ENSG00000138078", + "gdb_id": 2 + } + ] +} + diff --git a/tests/services/test_genset.py b/tests/services/test_genset.py index 2db35f8..87abfec 100644 --- a/tests/services/test_genset.py +++ b/tests/services/test_genset.py @@ -1,18 +1,16 @@ """Tests for geneset Service.""" -import importlib.resources -import json from unittest.mock import patch import pytest from geneweaver.api.controller import message from geneweaver.api.services import geneset +from geneweaver.core.enum import GeneIdentifier -## Load test data -# Opening JSON file -str_json = importlib.resources.read_text("tests.data", "response_geneset_1234.json") -# returns JSON string as a dictionary -test_data = json.loads(str_json) +from tests.data import test_geneset_data + +geneset_by_id_resp = test_geneset_data.get("geneset_by_id_resp") +geneset_w_gene_id_type_resp = test_geneset_data.get("geneset_w_gene_id_type_resp") @patch("geneweaver.api.services.geneset.db_geneset") @@ -33,7 +31,7 @@ def test_get_geneset_no_user_access(mock_genset_readable_func): mock_genset_readable_func.return_value = False response = geneset.get_geneset(None, 1234, None) assert response.get("error") is True - assert response.get("message") == message.ACCESS_FORBIDEN + assert response.get("message") == message.ACCESS_FORBIDDEN @patch("geneweaver.api.services.geneset.db_geneset") @@ -44,12 +42,14 @@ def test_get_geneset_returned_values( ): """Test get geneset by ID data response structure.""" mock_genset_readable_func.return_value = True - mock_db_geneset.by_id.return_value = test_data.get("geneset") - mock_db_genset_value.by_geneset_id.return_value = test_data.get("geneset_values") + mock_db_geneset.by_id.return_value = geneset_by_id_resp.get("geneset") + mock_db_genset_value.by_geneset_id.return_value = geneset_by_id_resp.get( + "geneset_values" + ) response = geneset.get_geneset(None, 1234, None) - assert response.get("genset") == test_data["geneset"] - assert response.get("geneset_values") == test_data["geneset_values"] + assert response.get("geneset") == geneset_by_id_resp["geneset"] + assert response.get("geneset_values") == geneset_by_id_resp["geneset_values"] @patch("geneweaver.api.services.geneset.db_is_readable") @@ -69,3 +69,28 @@ def test_is_redable_by_user_error(mock_user, mock_genset_is_readable): with pytest.raises(expected_exception=Exception): geneset.is_geneset_readable_by_user(None, 1234, mock_user) + + +@patch("geneweaver.api.services.geneset.db_geneset") +@patch("geneweaver.api.services.geneset.db_geneset_value") +@patch("geneweaver.api.services.geneset.is_geneset_readable_by_user") +def test_get_geneset_w_gene_id_type_reponse( + mock_genset_readable_func, mock_db_genset_value, mock_db_geneset +): + """Test get geneset by ID with gene identifier type data response.""" + mock_genset_readable_func.return_value = True + mock_db_geneset.by_id.return_value = geneset_w_gene_id_type_resp.get("geneset") + mock_db_genset_value.by_geneset_id.return_value = geneset_w_gene_id_type_resp.get( + "geneset_values" + ) + + response = geneset.get_geneset_w_gene_id_type(None, 1234, None, GeneIdentifier(2)) + + assert response.get("geneset") == geneset_w_gene_id_type_resp["geneset"] + assert ( + response.get("gene_identifier_type") + == geneset_w_gene_id_type_resp["gene_identifier_type"] + ) + assert ( + response.get("geneset_values") == geneset_w_gene_id_type_resp["geneset_values"] + )