Fix custom plugin downloaders

Change get_as_dataframe call signature
This commit is contained in:
phil 2024-04-06 13:11:38 +05:30
parent 08c53cf894
commit 52e1d2135b
9 changed files with 156 additions and 105 deletions

107
pdm.lock generated
View file

@ -5,7 +5,7 @@
groups = ["default", "dev", "mqtt"] groups = ["default", "dev", "mqtt"]
strategy = ["cross_platform"] strategy = ["cross_platform"]
lock_version = "4.4.1" lock_version = "4.4.1"
content_hash = "sha256:07dee91945ef2f5557c7130b7ab9fee6bbba2763ce65a3cc18f0d3c89429c30f" content_hash = "sha256:0da68c7fed8db7a12e36002b8d6194c1651f9653fc7fbf7797c553774c9dbf32"
[[package]] [[package]]
name = "aiomqtt" name = "aiomqtt"
@ -380,17 +380,17 @@ files = [
[[package]] [[package]]
name = "fastapi" name = "fastapi"
version = "0.110.0" version = "0.110.1"
requires_python = ">=3.8" requires_python = ">=3.8"
summary = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" summary = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
dependencies = [ dependencies = [
"pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4", "pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4",
"starlette<0.37.0,>=0.36.3", "starlette<0.38.0,>=0.37.2",
"typing-extensions>=4.8.0", "typing-extensions>=4.8.0",
] ]
files = [ files = [
{file = "fastapi-0.110.0-py3-none-any.whl", hash = "sha256:87a1f6fb632a218222c5984be540055346a8f5d8a68e8f6fb647b1dc9934de4b"}, {file = "fastapi-0.110.1-py3-none-any.whl", hash = "sha256:5df913203c482f820d31f48e635e022f8cbfe7350e4830ef05a3163925b1addc"},
{file = "fastapi-0.110.0.tar.gz", hash = "sha256:266775f0dcc95af9d3ef39bad55cff525329a931d5fd51930aadd4f428bf7ff3"}, {file = "fastapi-0.110.1.tar.gz", hash = "sha256:6feac43ec359dfe4f45b2c18ec8c94edb8dc2dfc461d417d9e626590c071baad"},
] ]
[[package]] [[package]]
@ -447,7 +447,7 @@ files = [
[[package]] [[package]]
name = "geoalchemy2" name = "geoalchemy2"
version = "0.14.6" version = "0.14.7"
requires_python = ">=3.7" requires_python = ">=3.7"
summary = "Using SQLAlchemy with Spatial Databases" summary = "Using SQLAlchemy with Spatial Databases"
dependencies = [ dependencies = [
@ -455,8 +455,8 @@ dependencies = [
"packaging", "packaging",
] ]
files = [ files = [
{file = "GeoAlchemy2-0.14.6-py3-none-any.whl", hash = "sha256:649c70f9275aded0341ed0c879e140d77c16ec33023cc21352de2eb7bb5fd509"}, {file = "GeoAlchemy2-0.14.7-py3-none-any.whl", hash = "sha256:af592892c58da0b98aa284d400f207f08a643aeee4523f025cef74991f76af14"},
{file = "GeoAlchemy2-0.14.6.tar.gz", hash = "sha256:e940681a60571d692124f687ecfe605164675341dbbaf5adf5f0ee46932c337b"}, {file = "GeoAlchemy2-0.14.7.tar.gz", hash = "sha256:9ff731c4e5b955525cb128ee7173222365e7f084d4b99f6f68e491bac6b44d21"},
] ]
[[package]] [[package]]
@ -638,7 +638,7 @@ files = [
[[package]] [[package]]
name = "matplotlib" name = "matplotlib"
version = "3.8.3" version = "3.8.4"
requires_python = ">=3.9" requires_python = ">=3.9"
summary = "Python plotting package" summary = "Python plotting package"
dependencies = [ dependencies = [
@ -646,29 +646,29 @@ dependencies = [
"cycler>=0.10", "cycler>=0.10",
"fonttools>=4.22.0", "fonttools>=4.22.0",
"kiwisolver>=1.3.1", "kiwisolver>=1.3.1",
"numpy<2,>=1.21", "numpy>=1.21",
"packaging>=20.0", "packaging>=20.0",
"pillow>=8", "pillow>=8",
"pyparsing>=2.3.1", "pyparsing>=2.3.1",
"python-dateutil>=2.7", "python-dateutil>=2.7",
] ]
files = [ files = [
{file = "matplotlib-3.8.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5184e07c7e1d6d1481862ee361905b7059f7fe065fc837f7c3dc11eeb3f2f900"}, {file = "matplotlib-3.8.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:72f9322712e4562e792b2961971891b9fbbb0e525011e09ea0d1f416c4645661"},
{file = "matplotlib-3.8.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d7e7e0993d0758933b1a241a432b42c2db22dfa37d4108342ab4afb9557cbe3e"}, {file = "matplotlib-3.8.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:232ce322bfd020a434caaffbd9a95333f7c2491e59cfc014041d95e38ab90d1c"},
{file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04b36ad07eac9740fc76c2aa16edf94e50b297d6eb4c081e3add863de4bb19a7"}, {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6addbd5b488aedb7f9bc19f91cd87ea476206f45d7116fcfe3d31416702a82fa"},
{file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c42dae72a62f14982f1474f7e5c9959fc4bc70c9de11cc5244c6e766200ba65"}, {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc4ccdc64e3039fc303defd119658148f2349239871db72cd74e2eeaa9b80b71"},
{file = "matplotlib-3.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf5932eee0d428192c40b7eac1399d608f5d995f975cdb9d1e6b48539a5ad8d0"}, {file = "matplotlib-3.8.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b7a2a253d3b36d90c8993b4620183b55665a429da8357a4f621e78cd48b2b30b"},
{file = "matplotlib-3.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:40321634e3a05ed02abf7c7b47a50be50b53ef3eaa3a573847431a545585b407"}, {file = "matplotlib-3.8.4-cp311-cp311-win_amd64.whl", hash = "sha256:8080d5081a86e690d7688ffa542532e87f224c38a6ed71f8fbed34dd1d9fedae"},
{file = "matplotlib-3.8.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:09074f8057917d17ab52c242fdf4916f30e99959c1908958b1fc6032e2d0f6d4"}, {file = "matplotlib-3.8.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6485ac1f2e84676cff22e693eaa4fbed50ef5dc37173ce1f023daef4687df616"},
{file = "matplotlib-3.8.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5745f6d0fb5acfabbb2790318db03809a253096e98c91b9a31969df28ee604aa"}, {file = "matplotlib-3.8.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c89ee9314ef48c72fe92ce55c4e95f2f39d70208f9f1d9db4e64079420d8d732"},
{file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97653d869a71721b639714b42d87cda4cfee0ee74b47c569e4874c7590c55c5"}, {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50bac6e4d77e4262c4340d7a985c30912054745ec99756ce213bfbc3cb3808eb"},
{file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:242489efdb75b690c9c2e70bb5c6550727058c8a614e4c7716f363c27e10bba1"}, {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f51c4c869d4b60d769f7b4406eec39596648d9d70246428745a681c327a8ad30"},
{file = "matplotlib-3.8.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:83c0653c64b73926730bd9ea14aa0f50f202ba187c307a881673bad4985967b7"}, {file = "matplotlib-3.8.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b12ba985837e4899b762b81f5b2845bd1a28f4fdd1a126d9ace64e9c4eb2fb25"},
{file = "matplotlib-3.8.3-cp312-cp312-win_amd64.whl", hash = "sha256:ef6c1025a570354297d6c15f7d0f296d95f88bd3850066b7f1e7b4f2f4c13a39"}, {file = "matplotlib-3.8.4-cp312-cp312-win_amd64.whl", hash = "sha256:7a6769f58ce51791b4cb8b4d7642489df347697cd3e23d88266aaaee93b41d9a"},
{file = "matplotlib-3.8.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fa93695d5c08544f4a0dfd0965f378e7afc410d8672816aff1e81be1f45dbf2e"}, {file = "matplotlib-3.8.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c7064120a59ce6f64103c9cefba8ffe6fba87f2c61d67c401186423c9a20fd35"},
{file = "matplotlib-3.8.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9764df0e8778f06414b9d281a75235c1e85071f64bb5d71564b97c1306a2afc"}, {file = "matplotlib-3.8.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0e47eda4eb2614300fc7bb4657fced3e83d6334d03da2173b09e447418d499f"},
{file = "matplotlib-3.8.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5e431a09e6fab4012b01fc155db0ce6dccacdbabe8198197f523a4ef4805eb26"}, {file = "matplotlib-3.8.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:493e9f6aa5819156b58fce42b296ea31969f2aab71c5b680b4ea7a3cb5c07d94"},
{file = "matplotlib-3.8.3.tar.gz", hash = "sha256:7b416239e9ae38be54b028abbf9048aff5054a9aba5416bef0bd17f9162ce161"}, {file = "matplotlib-3.8.4.tar.gz", hash = "sha256:8aac397d5e9ec158960e31c381c5ffc52ddd52bd9a47717e2a694038167dffea"},
] ]
[[package]] [[package]]
@ -712,30 +712,31 @@ files = [
[[package]] [[package]]
name = "orjson" name = "orjson"
version = "3.9.15" version = "3.10.0"
requires_python = ">=3.8" requires_python = ">=3.8"
summary = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" summary = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
files = [ files = [
{file = "orjson-3.9.15-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c8e8fe01e435005d4421f183038fc70ca85d2c1e490f51fb972db92af6e047c2"}, {file = "orjson-3.10.0-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9587053e0cefc284e4d1cd113c34468b7d3f17666d22b185ea654f0775316a26"},
{file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87f1097acb569dde17f246faa268759a71a2cb8c96dd392cd25c668b104cad2f"}, {file = "orjson-3.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bef1050b1bdc9ea6c0d08468e3e61c9386723633b397e50b82fda37b3563d72"},
{file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff0f9913d82e1d1fadbd976424c316fbc4d9c525c81d047bbdd16bd27dd98cfc"}, {file = "orjson-3.10.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d16c6963ddf3b28c0d461641517cd312ad6b3cf303d8b87d5ef3fa59d6844337"},
{file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8055ec598605b0077e29652ccfe9372247474375e0e3f5775c91d9434e12d6b1"}, {file = "orjson-3.10.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4251964db47ef090c462a2d909f16c7c7d5fe68e341dabce6702879ec26d1134"},
{file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d6768a327ea1ba44c9114dba5fdda4a214bdb70129065cd0807eb5f010bfcbb5"}, {file = "orjson-3.10.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73bbbdc43d520204d9ef0817ac03fa49c103c7f9ea94f410d2950755be2c349c"},
{file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12365576039b1a5a47df01aadb353b68223da413e2e7f98c02403061aad34bde"}, {file = "orjson-3.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:414e5293b82373606acf0d66313aecb52d9c8c2404b1900683eb32c3d042dbd7"},
{file = "orjson-3.9.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:71c6b009d431b3839d7c14c3af86788b3cfac41e969e3e1c22f8a6ea13139404"}, {file = "orjson-3.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:feaed5bb09877dc27ed0d37f037ddef6cb76d19aa34b108db270d27d3d2ef747"},
{file = "orjson-3.9.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e18668f1bd39e69b7fed19fa7cd1cd110a121ec25439328b5c89934e6d30d357"}, {file = "orjson-3.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5127478260db640323cea131ee88541cb1a9fbce051f0b22fa2f0892f44da302"},
{file = "orjson-3.9.15-cp311-none-win32.whl", hash = "sha256:62482873e0289cf7313461009bf62ac8b2e54bc6f00c6fabcde785709231a5d7"}, {file = "orjson-3.10.0-cp311-none-win32.whl", hash = "sha256:b98345529bafe3c06c09996b303fc0a21961820d634409b8639bc16bd4f21b63"},
{file = "orjson-3.9.15-cp311-none-win_amd64.whl", hash = "sha256:b3d336ed75d17c7b1af233a6561cf421dee41d9204aa3cfcc6c9c65cd5bb69a8"}, {file = "orjson-3.10.0-cp311-none-win_amd64.whl", hash = "sha256:658ca5cee3379dd3d37dbacd43d42c1b4feee99a29d847ef27a1cb18abdfb23f"},
{file = "orjson-3.9.15-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:82425dd5c7bd3adfe4e94c78e27e2fa02971750c2b7ffba648b0f5d5cc016a73"}, {file = "orjson-3.10.0-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4329c1d24fd130ee377e32a72dc54a3c251e6706fccd9a2ecb91b3606fddd998"},
{file = "orjson-3.9.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c51378d4a8255b2e7c1e5cc430644f0939539deddfa77f6fac7b56a9784160a"}, {file = "orjson-3.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef0f19fdfb6553342b1882f438afd53c7cb7aea57894c4490c43e4431739c700"},
{file = "orjson-3.9.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6ae4e06be04dc00618247c4ae3f7c3e561d5bc19ab6941427f6d3722a0875ef7"}, {file = "orjson-3.10.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c4f60db24161534764277f798ef53b9d3063092f6d23f8f962b4a97edfa997a0"},
{file = "orjson-3.9.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcef128f970bb63ecf9a65f7beafd9b55e3aaf0efc271a4154050fc15cdb386e"}, {file = "orjson-3.10.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1de3fd5c7b208d836f8ecb4526995f0d5877153a4f6f12f3e9bf11e49357de98"},
{file = "orjson-3.9.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b72758f3ffc36ca566ba98a8e7f4f373b6c17c646ff8ad9b21ad10c29186f00d"}, {file = "orjson-3.10.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f93e33f67729d460a177ba285002035d3f11425ed3cebac5f6ded4ef36b28344"},
{file = "orjson-3.9.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c57bc7b946cf2efa67ac55766e41764b66d40cbd9489041e637c1304400494"}, {file = "orjson-3.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:237ba922aef472761acd697eef77fef4831ab769a42e83c04ac91e9f9e08fa0e"},
{file = "orjson-3.9.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:946c3a1ef25338e78107fba746f299f926db408d34553b4754e90a7de1d44068"}, {file = "orjson-3.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98c1bfc6a9bec52bc8f0ab9b86cc0874b0299fccef3562b793c1576cf3abb570"},
{file = "orjson-3.9.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2f256d03957075fcb5923410058982aea85455d035607486ccb847f095442bda"}, {file = "orjson-3.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:30d795a24be16c03dca0c35ca8f9c8eaaa51e3342f2c162d327bd0225118794a"},
{file = "orjson-3.9.15-cp312-none-win_amd64.whl", hash = "sha256:5bb399e1b49db120653a31463b4a7b27cf2fbfe60469546baf681d1b39f4edf2"}, {file = "orjson-3.10.0-cp312-none-win32.whl", hash = "sha256:6a3f53dc650bc860eb26ec293dfb489b2f6ae1cbfc409a127b01229980e372f7"},
{file = "orjson-3.9.15.tar.gz", hash = "sha256:95cae920959d772f30ab36d3b25f83bb0f3be671e986c72ce22f8fa700dae061"}, {file = "orjson-3.10.0-cp312-none-win_amd64.whl", hash = "sha256:983db1f87c371dc6ffc52931eb75f9fe17dc621273e43ce67bee407d3e5476e9"},
{file = "orjson-3.10.0.tar.gz", hash = "sha256:ba4d8cac5f2e2cff36bea6b6481cdb92b38c202bcec603d6f5ff91960595a1ed"},
] ]
[[package]] [[package]]
@ -1401,15 +1402,15 @@ files = [
[[package]] [[package]]
name = "starlette" name = "starlette"
version = "0.36.3" version = "0.37.2"
requires_python = ">=3.8" requires_python = ">=3.8"
summary = "The little ASGI library that shines." summary = "The little ASGI library that shines."
dependencies = [ dependencies = [
"anyio<5,>=3.4.0", "anyio<5,>=3.4.0",
] ]
files = [ files = [
{file = "starlette-0.36.3-py3-none-any.whl", hash = "sha256:13d429aa93a61dc40bf503e8c801db1f1bca3dc706b10ef2434a36123568f044"}, {file = "starlette-0.37.2-py3-none-any.whl", hash = "sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee"},
{file = "starlette-0.36.3.tar.gz", hash = "sha256:90a671733cfb35771d8cc605e0b679d23b992f8dcfad48cc60b38cb29aeb7080"}, {file = "starlette-0.37.2.tar.gz", hash = "sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823"},
] ]
[[package]] [[package]]
@ -1434,12 +1435,12 @@ files = [
[[package]] [[package]]
name = "types-passlib" name = "types-passlib"
version = "1.7.7.20240311" version = "1.7.7.20240327"
requires_python = ">=3.8" requires_python = ">=3.8"
summary = "Typing stubs for passlib" summary = "Typing stubs for passlib"
files = [ files = [
{file = "types-passlib-1.7.7.20240311.tar.gz", hash = "sha256:287dd27cec5421daf6be5c295f681baf343c146038c8bde4db783bcac1beccb7"}, {file = "types-passlib-1.7.7.20240327.tar.gz", hash = "sha256:4cce6a1a3a6afee9fc4728b4d9784300764ac2be747f5bcc01646d904b85f4bb"},
{file = "types_passlib-1.7.7.20240311-py3-none-any.whl", hash = "sha256:cd44166e9347ae516f4830046cd1673c1ef90a5cc7ddd1356cf8a14892f29249"}, {file = "types_passlib-1.7.7.20240327-py3-none-any.whl", hash = "sha256:3a3b7f4258b71034d2e2f4f307d6810f9904f906cdf375514c8bdbdb28a4ad23"},
] ]
[[package]] [[package]]

View file

@ -8,7 +8,7 @@ authors = [
dependencies = [ dependencies = [
"apscheduler>=3.10.4", "apscheduler>=3.10.4",
"asyncpg>=0.28.0", "asyncpg>=0.28.0",
"fastapi>=0.110", "fastapi>=0.110.1",
"geoalchemy2>=0.14.2", "geoalchemy2>=0.14.2",
"geopandas>=0.14.0", "geopandas>=0.14.0",
"itsdangerous>=2.1.2", "itsdangerous>=2.1.2",

View file

@ -1 +1 @@
__version__: str = '2023.4.dev56+g775030d.d20240325' __version__: str = '2023.4.dev62+g08c53cf.d20240405'

View file

@ -9,11 +9,13 @@ from sqlalchemy.orm import selectinload, joinedload
from gisaf.database import pandas_query, fastapi_db_session as db_session from gisaf.database import pandas_query, fastapi_db_session as db_session
from gisaf.models.geo_models_base import GeoModel, PlottableModel from gisaf.models.geo_models_base import GeoModel, PlottableModel
from gisaf.models.info import Downloader
from gisaf.security import ( from gisaf.security import (
Token, authenticate_user, get_current_active_user, create_access_token, Token, authenticate_user, get_current_active_user, create_access_token,
) )
from gisaf.models.authentication import (User, UserRead, Role, RoleRead) from gisaf.models.authentication import (User, UserRead, Role, RoleRead)
from gisaf.registry import registry, NotInRegistry from gisaf.registry import registry, NotInRegistry
from gisaf.plugins import DownloadResponse, manager as plugin_manager
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -47,7 +49,8 @@ async def download_csv(
if custom_getter: if custom_getter:
df = await custom_getter(model_id) df = await custom_getter(model_id)
else: else:
df = await values_model.get_as_dataframe(model_id=model_id, with_only_columns=[value]) item = await db_session.get(model, model_id)
df = await values_model.get_as_dataframe(item=item, with_only_columns=[value])
if len(df) == 0: if len(df) == 0:
raise HTTPException(status.HTTP_204_NO_CONTENT) raise HTTPException(status.HTTP_204_NO_CONTENT)
if resample and resample != '0': if resample and resample != '0':
@ -75,3 +78,49 @@ async def download_csv(
'Content-Disposition': f"attachment; filename={filename}" 'Content-Disposition': f"attachment; filename={filename}"
}) })
return response return response
@api.get('/plugin/{name}/{store}/{id}')
async def execute_action(
name: str,
store: str,
id: int,
db_session: db_session,
user: Annotated[UserRead, Depends(get_current_active_user)]
):
"""
Download the result of an action
"""
## TODO: implement permissions for actions
#await check_permission(info.context['request'], 'action')
try:
store_record = registry.stores.loc[store]
model: type[GeoModel] = store_record.model
values_model = registry.values_for_model[model][0]
except KeyError:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
item = await db_session.get(model, id)
dls: list[Downloader] = [dl for dl in plugin_manager.downloaders_stores[store]
if dl.name == name]
if len(dls) == 0:
raise HTTPException(status.HTTP_501_NOT_IMPLEMENTED,
detail=f'No downloader {name} for {store}')
elif len(dls) > 1:
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f'Too many downloaders ({len(dls)}) {name} for {store}')
downloader = dls[0]
result: DownloadResponse
try:
result = await downloader._plugin.execute(model, item)
except Exception as err:
logging.exception(err)
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f'Error in action: {err.args[0]}'
)
return StreamingResponse(
iter([result.content]),
headers = {
'Content-Disposition': f'attachment; filename="{result.file_name}"'
},
media_type=result.content_type,
)

View file

@ -178,11 +178,14 @@ async def get_model_list(
return resp return resp
@api.get('/{store_name}/values/{value}') @api.get('/{store_name}/values/{value}')
async def get_model_values(store_name: str, value: str, async def get_model_values(
response: Response, db_session: db_session,
where: str, store_name: str,
resample: str | None = None, value: str,
): response: Response,
where: str,
resample: str | None = None,
):
""" """
Get values Get values
""" """
@ -202,7 +205,8 @@ async def get_model_values(store_name: str, value: str,
if getter: if getter:
df = await getter(model_id) df = await getter(model_id)
else: else:
df = await values_model.get_as_dataframe(model_id=model_id, item = await db_session.get(model, model_id)
df = await values_model.get_as_dataframe(item=item,
with_only_columns=[value]) with_only_columns=[value])
if len(df) == 0: if len(df) == 0:

View file

@ -15,7 +15,7 @@ from gisaf.api.admin import api as admin_api
from gisaf.api.dashboard import api as dashboard_api from gisaf.api.dashboard import api as dashboard_api
from gisaf.api.map import api as map_api from gisaf.api.map import api as map_api
from gisaf.api.download import api as download_api from gisaf.api.download import api as download_api
from gisaf.plugins import manager as plugin_manger from gisaf.plugins import manager as plugin_manager
logging.basicConfig(level=conf.gisaf.debugLevel) logging.basicConfig(level=conf.gisaf.debugLevel)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -27,7 +27,7 @@ async def lifespan(app: FastAPI):
await setup_redis() await setup_redis()
await setup_redis_cache() await setup_redis_cache()
await setup_live() await setup_live()
await plugin_manger.scan_plugins() await plugin_manager.scan_plugins()
await admin_manager.setup_admin() await admin_manager.setup_admin()
await map_tile_registry.setup() await map_tile_registry.setup()
yield yield

View file

@ -1130,44 +1130,31 @@ class PlottableModel(Model):
values: ClassVar[list[dict[str, str]]] = [] values: ClassVar[list[dict[str, str]]] = []
@classmethod @classmethod
async def get_as_dataframe(cls, model_id=None, where=None, **kwargs): async def get_as_dataframe(cls, item, where=None, **kwargs):
""" """
Get a dataframe for the data. Get a dataframe for the data.
It's quite generic, so subclasses might want to subclass this. It's quite generic, so subclasses might want to subclass this.
""" """
if where is None: where_ = cls.ref_id == item.id
if model_id is None: if where is not None:
where_ = None where_ = and_(where_, where)
else: return await cls.get_df(where=where_, **kwargs)
where_ = cls.ref_id == model_id
else:
if model_id is None:
where_ = where
else:
where_ = and_(cls.ref_id == model_id, where)
if where_ is not None:
df = await cls.get_df(where=where_, **kwargs)
else:
df = await cls.get_df(**kwargs)
return df
class TimePlottableModel(PlottableModel): class TimePlottableModel(PlottableModel):
time: datetime time: datetime
@classmethod @classmethod
async def get_as_dataframe(cls, model_id=None, with_only_columns=None, **kwargs): async def get_as_dataframe(cls, item, with_only_columns=None, **kwargs):
""" """
Get the data as a time-indexed dataframe Get the data as a time-indexed dataframe
""" """
if with_only_columns == None: if with_only_columns is None:
with_only_columns = [val['name'] for val in cls.values] with_only_columns = [val['name'] for val in cls.values]
if 'time' not in with_only_columns: if 'time' not in with_only_columns:
with_only_columns.insert(0, 'time') with_only_columns.insert(0, 'time')
df = await super().get_as_dataframe(model_id=model_id, df = await super().get_as_dataframe(item=item,
with_only_columns=with_only_columns, with_only_columns=with_only_columns,
**kwargs) **kwargs)

View file

@ -1,6 +1,6 @@
from typing import Any from typing import Any
from pydantic import BaseModel from pydantic import BaseModel, PrivateAttr
from gisaf.models.info_item import Tag, InfoItem from gisaf.models.info_item import Tag, InfoItem
from gisaf.models.tags import Tags from gisaf.models.tags import Tags
@ -112,11 +112,15 @@ class ActionAction(BaseModel):
class Downloader(BaseModel): class Downloader(BaseModel):
# plugin: str _plugin: Any = PrivateAttr() # DownloadPlugin
# downloader: str
roles: list[str] = [] roles: list[str] = []
name: str name: str
icon: str | None = None icon: str | None
def __init__(self, _plugin, **data):
super().__init__(**data)
# We generate the value for our private attribute
self._plugin = _plugin
class LegendItem(BaseModel): class LegendItem(BaseModel):

View file

@ -12,9 +12,9 @@ from fastapi import HTTPException, status
from sqlalchemy import or_, and_ from sqlalchemy import or_, and_
# from geoalchemy2.shape import to_shape, from_shape # from geoalchemy2.shape import to_shape, from_shape
# from graphene import ObjectType, String, List, Boolean, Field, Float, InputObjectType # from graphene import ObjectType, String, List, Boolean, Field, Float, InputObjectType
import pandas as pd import pandas as pd
import shapely # type: ignore import shapely # type: ignore
from pydantic import BaseModel
from gisaf.config import conf from gisaf.config import conf
from gisaf.models.store import Store # noqa: F401 from gisaf.models.store import Store # noqa: F401
@ -106,6 +106,12 @@ class TagPlugin:
return self.key return self.key
class DownloadResponse(BaseModel):
file_name: str
content_type: str
content: str
class DownloadPlugin: class DownloadPlugin:
""" """
Base class for all download plugins. Base class for all download plugins.
@ -119,26 +125,26 @@ class DownloadPlugin:
self.roles = roles or [] self.roles = roles or []
self.icon = icon self.icon = icon
async def execute(self, model, item, request): async def execute(self, model, item) -> DownloadResponse:
raise NotImplementedError(f'Missing execute in downloader {self.name}') raise NotImplementedError(f'Missing execute in downloader {self.name}')
class DownloadCSVPlugin(DownloadPlugin): class DownloadCSVPlugin(DownloadPlugin):
async def execute(self, model, item, request): async def execute(self, model, item) -> DownloadResponse:
try: try:
values_models = registry.values_for_model[model] values_models = registry.values_for_model[model]
except KeyError: except KeyError:
raise NotInRegistry raise NotInRegistry
for value_model in values_models: for value_model in values_models:
df = await value_model.get_as_dataframe(model_id=item.id) df = await value_model.get_as_dataframe(item=item)
csv = df.to_csv(date_format='%d/%m/%Y %H:%M', float_format=value_model.float_format) csv = df.to_csv(date_format='%d/%m/%Y %H:%M', float_format=value_model.float_format)
## TODO: implement multiple values for a model (search for values_for_model) ## TODO: implement multiple values for a model (search for values_for_model)
break break
return { return DownloadResponse(
'file_name': '{:s}.csv'.format(item.caption), file_name=f'{model.__name__}-id-{item.id}.csv',
'content_type': 'text/csv', content_type='text/csv',
'content': csv content=csv
} )
class PluginManager: class PluginManager:
@ -171,7 +177,7 @@ class PluginManager:
self.actions_stores: dict[str, dict[str, list[ActionAction]]] = {} self.actions_stores: dict[str, dict[str, list[ActionAction]]] = {}
self.executors = defaultdict(list) self.executors = defaultdict(list)
self.downloaders = defaultdict(list) self.downloaders = defaultdict(list)
self.downloaders_stores = defaultdict(list) self.downloaders_stores: dict[str, list[Downloader]] = defaultdict(list)
registered_models = registry.geom registered_models = registry.geom
registered_stores = registered_models.keys() registered_stores = registered_models.keys()
@ -268,13 +274,13 @@ class PluginManager:
logger.warn(f'Downloader plugin {entry_point.name}: skip model {store}' logger.warn(f'Downloader plugin {entry_point.name}: skip model {store}'
', which is not found in registry') ', which is not found in registry')
continue continue
self.downloaders_stores[store].append( _store = Downloader(
Downloader( _plugin=downloader,
name=downloader.name, name=downloader.name,
roles=downloader.roles, roles=downloader.roles,
icon=downloader.icon, icon=downloader.icon,
)
) )
self.downloaders_stores[store].append(_store)
logger.info(f'Added downloader plugin {entry_point.name}') logger.info(f'Added downloader plugin {entry_point.name}')
self.tagsStores = TagsStores( self.tagsStores = TagsStores(