diff --git a/Pipfile b/Pipfile index be8546512..b07bf895d 100644 --- a/Pipfile +++ b/Pipfile @@ -20,6 +20,8 @@ psycopg2-binary = "*" uvicorn = "*" email_validator = "*" sentry-sdk = "*" +geoalchemy2 = "*" +boto3 = "*" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index ea0bc65cb..ecd66a74c 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c7eec5cba8d2c0827d5b85dd94b4e0b2ecbfae145f261a664aad58f5ee4664ee" + "sha256": "86b16d9b9045d0ebf3d826df6fa6de84a31d3c07dcf765e963598af7fb268183" }, "pipfile-spec": 6, "requires": { @@ -16,76 +16,89 @@ ] }, "default": { - "aiocontextvars": { - "hashes": [ - "sha256:885daf8261818767d8f7cbd79f9d4482d118f024b6586ef6e67980236a27bfa3", - "sha256:f027372dc48641f683c559f247bd84962becaacdc9ba711d583c3871fb5652aa" - ], - "version": "==0.2.2" - }, "aioredis": { "hashes": [ - "sha256:71302cebeb7add86f1fe660b469068760ca4364504e75ee83dd6f6b7118bfe28", - "sha256:86da2748fb0652625a8346f413167f078ec72bdc76e217db7e605a059cd56e86" + "sha256:15f8af30b044c771aee6787e5ec24694c048184c7b9e54c3b60c750a4b93273a", + "sha256:b61808d7e97b7cd5a92ed574937a079c9387fdadd22bfbfa7ad2fd319ecc26e3" ], - "version": "==1.3.0" + "version": "==1.3.1" }, "alembic": { "hashes": [ - "sha256:9f907d7e8b286a1cfb22db9084f9ce4fde7ad7956bb496dc7c952e10ac90e36a" + "sha256:035ab00497217628bf5d0be82d664d8713ab13d37b630084da8e1f98facf4dbf" ], "index": "pypi", - "version": "==1.2.1" + "version": "==1.4.2" }, "arq": { "hashes": [ - "sha256:2d57685625b15d1dac20159c0032e8105d09ea701c854213b6fe1d75a937b8ee", - "sha256:dcdc07cfc38bfd3abb7ff7704d82a603c563b4b63f2d33ec5f104bdfad946870" + "sha256:46f6e128d605901260fd36ef6e2006b31021f875d8ccea127849a4b37b11fe4a", + "sha256:6d34ae96ed00c8641cf8de9ec07fb2ab8766cb1902166fbc61493e7c00432b90" ], "index": "pypi", - "version": "==0.18.1" + "version": "==0.18.4" }, "async-timeout": { "hashes": [ - "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f", - "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3" + "sha256:0b0e3079aaca061347d171961953782c97f7b9c5eb29310eb8e5150f7931dcba", + "sha256:9eefb0f98094f3e59e1d55fd782e048494ea27e046ff0ddca63a3b5f08f17db3" ], - "version": "==3.0.1" + "version": "==4.0.0a2" }, "asyncpg": { "hashes": [ - "sha256:0527cca24a1bb90b7872867518f25f51a431116075bebbe86149fef593630736", - "sha256:16c2accafda9410fd7e8ee561c2bcd1d3141118be81dc9eccc4e671877fecb72", - "sha256:35ce817f4a1cef966434e564b69e760d98f0fc2bac73c8786058bd6136ed304e", - "sha256:426eb401b760abb0ce670d1d09201f1ae5a58355d272c413d1f7d7b6e354b00d", - "sha256:45254bc128b175cec75c1cbc64de77bdf5593cbff4cdc58c4ca810878ddfe00b", - "sha256:6a9d9824c29a72dc109b9f9e7916c36bbb6ed15e1f3154aa976ac776caf9ad88", - "sha256:81431aac651d0386f483697d831cd9cb6efa816fd08dcedf0387602f52c1d4d0", - "sha256:8992efcda3022e82966857989c999d5da0e9fc76394f36099700ce544ef39621", - "sha256:8c5a9d6573940fe81de36af78459988b5672e427e95667323fe7dfd97f00cd09", - "sha256:aab3a90dba30fe9017b5326727b505e18fe024c2e205655d52e85f9b24f5b2ab", - "sha256:b253bbbe42eba8e00ad63939ff9d43a5f74e26a4e8f883de867920feb4a9e36a", - "sha256:ccad6b5a59b1c27623c48a840d1f6024994551f27ca0d6c253f64004eaf8a3e6", - "sha256:cebf06ac15626f3ccb6a537fe593460cdd581bf1aa33dbf3068a21dbef7e393a", - "sha256:d3ac4751ae5f77fc646cfeb3f9180f2561eb0876a6b7619cb4e4e290e3432811", - "sha256:e41c8ef26019c27f76cb280dfebad23f84af99ac846b19bcaea06f1b2a2f5fce", - "sha256:f3e9863510b4e54ade1d20af5ef18901dea44e4fd7259db516b73810c0a1ad2e" - ], - "version": "==0.19.0" + "sha256:058baec9d6b75612412baa872a1aa47317d0ff88c318a49f9c4a2389043d5a8d", + "sha256:0c336903c3b08e970f8af2f606332f1738dba156bca83ed0467dc2f5c70da796", + "sha256:1388caa456070dab102be874205e3ae8fd1de2577d5de9fa22e65ba5c0f8b110", + "sha256:25edb0b947eb632b6b53e5a4b36cba5677297bb34cbaba270019714d0a5fed76", + "sha256:2af6a5a705accd36e13292ea43d08c20b15e52d684beb522cb3a7d3c9c8f3f48", + "sha256:391aea89871df8c1560750af6c7170f2772c2d133b34772acf3637e3cf4db93e", + "sha256:394bf19bdddbba07a38cd6fb526ebf66e120444d6b3097332b78efd5b26495b0", + "sha256:5664d1bd8abe64fc60a0e701eb85fa1d8c9a4a8018a5a59164d27238f2caf395", + "sha256:57666dfae38f4dbf84ffbf0c5c0f78733fef0e8e083230275dcb9ccad1d5ee09", + "sha256:74510234c294c6a6767089ba9c938f09a491426c24405634eb357bd91dffd734", + "sha256:95cd2df61ee00b789bdcd04a080e6d9188693b841db2bf9a87ebaed9e53147e0", + "sha256:a981500bf6947926e53c48f4d60ae080af1b4ad7fa78e363465a5b5ad4f2b65e", + "sha256:a9e6fd6f0f9e8bd77e9a4e1ef9a4f83a80674d9136a754ae3603e915da96b627", + "sha256:ad5ba062e09673b1a4b8d0facaf5a6d9719bf7b337440d10b07fe994d90a9552", + "sha256:ba90d3578bc6dddcbce461875672fd9bdb34f0b8215b68612dd3b65a956ff51c", + "sha256:c773c7dbe2f4d3ebc9e3030e94303e45d6742e6c2fc25da0c46a56ea3d83caeb", + "sha256:da238592235717419a6a7b5edc8564da410ebfd056ca4ecc41e70b1b5df86fba", + "sha256:e39aac2b3a2f839ce65aa255ce416de899c58b7d38d601d24ca35558e13b48e3", + "sha256:ec6e7046c98730cb2ba4df41387e10cb8963a3ac2918f69ae416f8aab9ca7b1b", + "sha256:f0c9719ac00615f097fe91082b785bce36dbf02a5ec4115ede0ebfd2cd9500cb", + "sha256:f7184689177eeb5a11fa1b2baf3f6f2e26bfd7a85acf4de1a3adbd0867d7c0e2" + ], + "version": "==0.20.1" + }, + "boto3": { + "hashes": [ + "sha256:970bd7b332e73d7b51077ed36772c634811b38c81b0cc6ed0f910e50d7ebadf8", + "sha256:cdd79a3a7bbe1f33a365f0acfcc75c4405b482b3eb9ce3f4e6b16c418e201ac3" + ], + "index": "pypi", + "version": "==1.12.39" + }, + "botocore": { + "hashes": [ + "sha256:94232b44e1540b7e043e220bd43f855400d0a243e926b26b3fb72994e971d518", + "sha256:e20ba56476b1031ce5ac8e22b59dabc75bd0e03231f124ed6b9ff99fe0b0c96b" + ], + "version": "==1.15.39" }, "certifi": { "hashes": [ - "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50", - "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef" + "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304", + "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519" ], - "version": "==2019.9.11" + "version": "==2020.4.5.1" }, "click": { "hashes": [ - "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", - "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" + "sha256:8a18b4ea89d8820c5d0c7da8a64b2c324b4dabb695804dbfea19b9be9d88c0cc", + "sha256:e345d143d80bf5ee7534056164e5e112ea5e22716bbb1ce727941f4c8b471b9a" ], - "version": "==7.0" + "version": "==7.1.1" }, "dnspython": { "hashes": [ @@ -94,6 +107,14 @@ ], "version": "==1.16.0" }, + "docutils": { + "hashes": [ + "sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0", + "sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827", + "sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99" + ], + "version": "==0.15.2" + }, "email-validator": { "hashes": [ "sha256:e3e6ede1765d7c1e580d2050d834b2689361f7da2d50ce74df6a5968fca7cb13" @@ -103,165 +124,215 @@ }, "fastapi": { "hashes": [ - "sha256:38356cf424392142a561f32ab49113dec6e2ab7318862ae14d5e1d7ede16d14f", - "sha256:48cb522c1c993e238bfe272fbb18049cbd4bf5b9d6c0d4a4fa113cc790e8196c" + "sha256:1ee9a49f28d510b62b3b51a9452b274853bfc9c5d4b947ed054366e2d49f9efa", + "sha256:72f40f47e5235cb5cbbad1d4f97932ede6059290c07e12e9784028dcd1063d28" + ], + "index": "pypi", + "version": "==0.54.1" + }, + "geoalchemy2": { + "hashes": [ + "sha256:379b0fc4ca5f9b5ef625719f47e22c9b8abd347aa78344e85f99d32594cfccd4", + "sha256:ec2a6e9919b522631803ac5922e88b701081da7e5d56a68f10ff263f6592d552" ], "index": "pypi", - "version": "==0.42.0" + "version": "==0.7.0" }, "gino": { "hashes": [ - "sha256:187492619c347df41fdbc876b058b85e77f7c50739d552ad720ff439d3d83753", - "sha256:3aebbe8776efefa49b878f00b48d6ad483b0f4ebcd8630641ea7c3c9f63bb260" + "sha256:1a3ef763218b0b1041cb6c01958a901dcf90d438b37377af0a78a279870b0ec1", + "sha256:ce87a865d402547a9bc498e5301d56d97bec8a1d96e30d40059873557736901f" ], "index": "pypi", - "version": "==0.8.3" + "version": "==1.0.0rc4" }, "h11": { "hashes": [ - "sha256:acca6a44cb52a32ab442b1779adf0875c443c689e9e028f8d831a3769f9c5208", - "sha256:f2b1ca39bfed357d1f19ac732913d5f9faa54a5062eca7d2ec3a916cfb7ae4c7" + "sha256:33d4bca7be0fa039f4e84d50ab00531047e53d6ee8ffbc83501ea602c169cae1", + "sha256:4bc6d6a1238b7615b266ada57e0618568066f57dd6fa967d1290ec9309b2f2f1" ], - "version": "==0.8.1" + "version": "==0.9.0" }, "hiredis": { "hashes": [ - "sha256:0124911115f2cb7deb4f8e221e109a53d3d718174b238a2c5e2162175a3929a5", - "sha256:0656658d0448c2c82c4890ae933c2c2e51196101d3d06fc19cc92e062410c2fd", - "sha256:09d284619f7142ddd7a4ffa94c12a0445e834737f4ce8739a737f2b1ca0f6142", - "sha256:12299b7026e5dc22ed0ff603375c1bf583cf59adbb0e4d062df434e9140d72dd", - "sha256:12fc6210f8dc3e9c8ce4b95e8f5db404b838dbdeb25bca41e33497de6d89334f", - "sha256:197febe5e63c77f4ad19b36e15ed33152064dc606c8b7413c7a0ca3fd04672cc", - "sha256:20e48289fbffb59a5ac7cc677fc02c2726c1da22488e5f7636b9feb9afde199f", - "sha256:26bed296b92b88db02afe214aa1fefad7f9e8ba88a5a7c0e355b55c4b168d212", - "sha256:321b19d2a21fd576111032fe7694d317de2c11b265ef775f2e3f22734a6b94c8", - "sha256:32d5f2c461250f5fc7ccef647682651b1d9f69443f16c213d7fa5e183222b233", - "sha256:36bfcc86715d109a5ef6edefd52b893de97d555cb5cb0e9cab83eb9665942ccc", - "sha256:438ddfd1484e98110959dc4648c0ba22c3307c9c0ae7e2a856755067f9ce9cef", - "sha256:66f17c1633b2fb967bf4165f7b3d369a1bdfe3537d3646cf9a7c208506c96c49", - "sha256:94ab0fa3ac93ab36a5400c474439881d182b43fd38a2766d984470c57931ae88", - "sha256:955f12da861f2608c181049f623bbb52851769e10639c4919cc586395b89813f", - "sha256:b1fd831f96ce0f715e9356574f5184b840b59eb8901fc5f9124fedbe84ad2a59", - "sha256:b3813c641494fca2eda66c32a2117816472a5a39b12f59f7887c6d17bdb8c77e", - "sha256:bbc3ee8663024c82a1226a0d56ad882f42a2fd8c2999bf52d27bdd25f1320f4b", - "sha256:bd12c2774b574f5b209196e25b03b5d62c7919bf69046bc7b955ebe84e0ec1fe", - "sha256:c54d2b3d7a2206df35f3c1140ac20ca6faf7819ff92ea5be8bf4d1cbdb433216", - "sha256:c7b0bcaf2353a2ad387dd8b5e1b5f55991adc3a7713ac3345a4ef0de58276690", - "sha256:c9319a1503efb3b5a4ec13b2f8fae2c23610a645e999cb8954d330f0610b0f6d", - "sha256:cbe5c0273224babe2ec77058643312d07aa5e8fed08901b3f7bccaa744c5728e", - "sha256:cc884ea50185009d794b31314a144110efc76b71beb0a5827a8bff970ae6d248", - "sha256:d1e2e751327781ad81df5a5a29d7c7b19ee0ebfbeddf037fd8df19ec1c06e18b", - "sha256:d2ef58cece6cae4b354411df498350d836f10b814c8a890df0d8079aff30c518", - "sha256:e97c953f08729900a5e740f1760305434d62db9f281ac351108d6c4b5bf51795", - "sha256:fcdf2e10f56113e1cb4326dbca7bf7edbfdbd246cd6d7ec088688e5439129e2c" - ], - "version": "==1.0.0" + "sha256:01b577f84c20ecc9c07fc4c184231b08e3c3942de096fa99978e053de231c423", + "sha256:01ff0900134166961c9e339df77c33b72f7edc5cb41739f0babcd9faa345926e", + "sha256:03ed34a13316d0c34213c4fd46e0fa3a5299073f4d4f08e93fed8c2108b399b3", + "sha256:040436e91df5143aff9e0debb49530d0b17a6bd52200ce568621c31ef581b10d", + "sha256:091eb38fbf968d1c5b703e412bbbd25f43a7967d8400842cee33a5a07b33c27b", + "sha256:102f9b9dc6ed57feb3a7c9bdf7e71cb7c278fe8df1edfcfe896bc3e0c2be9447", + "sha256:2b4b392c7e3082860c8371fab3ae762139090f9115819e12d9f56060f9ede05d", + "sha256:2c9cc0b986397b833073f466e6b9e9c70d1d4dc2c2c1b3e9cae3a23102ff296c", + "sha256:2fa65a9df683bca72073cd77709ddeb289ea2b114d3775d225fbbcc5faf808c5", + "sha256:38437a681f17c975fd22349e72c29bc643f8e7eb2d6dc5df419eac59afa4d7ce", + "sha256:3b3428fa3cf1ee178807b52c9bee8950ab94cd4eaa9bfae8c1bbae3c49501d34", + "sha256:3dd8c2fae7f5494978facb0e93297dd627b1a3f536f3b070cf0a7d9157a07dcb", + "sha256:4414a96c212e732723b5c3d7c04d386ebbb2ec359e1de646322cbc3f875cbd0d", + "sha256:48c627581ad4ef60adbac980981407939acf13a0e18f093502c7b542223c4f19", + "sha256:4a60e71625a2d78d8ab84dfb2fa2cfd9458c964b6e6c04fea76d9ade153fb371", + "sha256:585ace09f434e43d8a8dbeb366865b1a044d7c06319b3c7372a0a00e63b860f4", + "sha256:74b364b3f06c9cf0a53f7df611045bc9437ed972a283fa1f0b12537236d23ddc", + "sha256:75c65c3850e89e9daa68d1b9bedd5806f177d60aa5a7b0953b4829481cfc1f72", + "sha256:7f052de8bf744730a9120dbdc67bfeb7605a01f69fb8e7ba5c475af33c24e145", + "sha256:8113a7d5e87ecf57cd4ae263cc9e429adb9a3e59f5a7768da5d3312a8d0a051a", + "sha256:84857ce239eb8ed191ac78e77ff65d52902f00f30f4ee83bf80eb71da73b70e6", + "sha256:8644a48ddc4a40b3e3a6b9443f396c2ee353afb2d45656c4fc68d04a82e8e3f7", + "sha256:936aa565e673536e8a211e43ec43197406f24cd1f290138bd143765079c8ba00", + "sha256:9afeb88c67bbc663b9f27385c496da056d06ad87f55df6e393e1516cfecb0461", + "sha256:9d62cc7880110e4f83b0a51d218f465d3095e2751fbddd34e553dbd106a929ff", + "sha256:a1fadd062fc8d647ff39220c57ea2b48c99bb73f18223828ec97f88fc27e7898", + "sha256:a7754a783b1e5d6f627c19d099b178059c62f782ab62b4d8ba165b9fbc2ee34c", + "sha256:aa59dd63bb3f736de4fc2d080114429d5d369dfb3265f771778e8349d67a97a4", + "sha256:ae2ee0992f8de249715435942137843a93db204dd7db1e7cc9bdc5a8436443e8", + "sha256:b36842d7cf32929d568f37ec5b3173b72b2ec6572dec4d6be6ce774762215aee", + "sha256:bcbf9379c553b5facc6c04c1e5569b44b38ff16bcbf354676287698d61ee0c92", + "sha256:cbccbda6f1c62ab460449d9c85fdf24d0d32a6bf45176581151e53cc26a5d910", + "sha256:d0caf98dfb8af395d6732bd16561c0a2458851bea522e39f12f04802dbf6f502", + "sha256:d6456afeddba036def1a36d8a2758eca53202308d83db20ab5d0b66590919627", + "sha256:dbaef9a21a4f10bc281684ee4124f169e62bb533c2a92b55f8c06f64f9af7b8f", + "sha256:dce84916c09aaece006272b37234ae84a8ed13abb3a4d341a23933b8701abfb5", + "sha256:eb8c9c8b9869539d58d60ff4a28373a22514d40495911451343971cb4835b7a9", + "sha256:efc98b14ee3a8595e40b1425e8d42f5fd26f11a7b215a81ef9259068931754f4", + "sha256:fa2dc05b87d97acc1c6ae63f3e0f39eae5246565232484b08db6bf2dc1580678", + "sha256:fe7d6ce9f6a5fbe24f09d95ea93e9c7271abc4e1565da511e1449b107b4d7848" + ], + "version": "==1.0.1" }, "httptools": { "hashes": [ - "sha256:e00cbd7ba01ff748e494248183abc6e153f49181169d8a3d41bb49132ca01dfc" - ], - "version": "==0.0.13" + "sha256:0a4b1b2012b28e68306575ad14ad5e9120b34fccd02a81eb08838d7e3bbb48be", + "sha256:3592e854424ec94bd17dc3e0c96a64e459ec4147e6d53c0a42d0ebcef9cb9c5d", + "sha256:41b573cf33f64a8f8f3400d0a7faf48e1888582b6f6e02b82b9bd4f0bf7497ce", + "sha256:56b6393c6ac7abe632f2294da53f30d279130a92e8ae39d8d14ee2e1b05ad1f2", + "sha256:86c6acd66765a934e8730bf0e9dfaac6fdcf2a4334212bd4a0a1c78f16475ca6", + "sha256:96da81e1992be8ac2fd5597bf0283d832287e20cb3cfde8996d2b00356d4e17f", + "sha256:96eb359252aeed57ea5c7b3d79839aaa0382c9d3149f7d24dd7172b1bcecb009", + "sha256:a2719e1d7a84bb131c4f1e0cb79705034b48de6ae486eb5297a139d6a3296dce", + "sha256:ac0aa11e99454b6a66989aa2d44bca41d4e0f968e395a0a8f164b401fefe359a", + "sha256:bc3114b9edbca5a1eb7ae7db698c669eb53eb8afbbebdde116c174925260849c", + "sha256:fa3cd71e31436911a44620473e873a256851e1f53dee56669dae403ba41756a4", + "sha256:fea04e126014169384dee76a153d4573d90d0cbd1d12185da089f73c78390437" + ], + "markers": "sys_platform != 'win32' and sys_platform != 'cygwin' and platform_python_implementation != 'PyPy'", + "version": "==0.1.1" }, "idna": { "hashes": [ - "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", - "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb", + "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa" + ], + "version": "==2.9" + }, + "importlib-metadata": { + "hashes": [ + "sha256:2a688cbaa90e0cc587f1df48bdc97a6eadccdcd9c35fb3f976a09e3b5016d90f", + "sha256:34513a8a0c4962bc66d35b359558fd8a5e10cd472d37aec5f66858addef32c1e" ], - "version": "==2.8" + "markers": "python_version < '3.8'", + "version": "==1.6.0" + }, + "jmespath": { + "hashes": [ + "sha256:695cb76fa78a10663425d5b73ddc5714eb711157e52704d69be03b1a02ba4fec", + "sha256:cca55c8d153173e21baa59983015ad0daf603f9cb799904ff057bfb8ff8dc2d9" + ], + "version": "==0.9.5" }, "mako": { "hashes": [ - "sha256:a36919599a9b7dc5d86a7a8988f23a9a3a3d083070023bab23d64f7f1d1e0a4b" + "sha256:3139c5d64aa5d175dbafb95027057128b5fbd05a40c53999f3905ceb53366d9d", + "sha256:8e8b53c71c7e59f3de716b6832c4e401d903af574f6962edbbbf6ecc2a5fe6c9" ], - "version": "==1.1.0" + "version": "==1.1.2" }, "markupsafe": { "hashes": [ - "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", - "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", - "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", - "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", - "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", - "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", - "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", - "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", - "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", - "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", - "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", - "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", - "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", - "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", - "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", - "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", - "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", - "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", - "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", - "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", - "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", - "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", - "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", - "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", - "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", - "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", - "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", - "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7" - ], - "version": "==1.1.1" + "sha256:06358015a4dee8ee23ae426bf885616ab3963622defd829eb45b44e3dee3515f", + "sha256:0b0c4fc852c5f02c6277ef3b33d23fcbe89b1b227460423e3335374da046b6db", + "sha256:267677fc42afed5094fc5ea1c4236bbe4b6a00fe4b08e93451e65ae9048139c7", + "sha256:303cb70893e2c345588fb5d5b86e0ca369f9bb56942f03064c5e3e75fa7a238a", + "sha256:3c9b624a0d9ed5a5093ac4edc4e823e6b125441e60ef35d36e6f4a6fdacd5054", + "sha256:42033e14cae1f6c86fc0c3e90d04d08ce73ac8e46ba420a0d22d545c2abd4977", + "sha256:4e4a99b6af7bdc0856b50020c095848ec050356a001e1f751510aef6ab14d0e0", + "sha256:4eb07faad54bb07427d848f31030a65a49ebb0cec0b30674f91cf1ddd456bfe4", + "sha256:63a7161cd8c2bc563feeda45df62f42c860dd0675e2b8da2667f25bb3c95eaba", + "sha256:68e0fd039b68d2945b4beb947d4023ca7f8e95b708031c345762efba214ea761", + "sha256:8092a63397025c2f655acd42784b2a1528339b90b987beb9253f22e8cdbb36c3", + "sha256:841218860683c0f2223e24756843d84cc49cccdae6765e04962607754a52d3e0", + "sha256:94076b2314bd2f6cfae508ad65b4d493e3a58a50112b7a2cbb6287bdbc404ae8", + "sha256:9d22aff1c5322e402adfb3ce40839a5056c353e711c033798cf4f02eb9f5124d", + "sha256:b0e4584f62b3e5f5c1a7bcefd2b52f236505e6ef032cc508caa4f4c8dc8d3af1", + "sha256:b1163ffc1384d242964426a8164da12dbcdbc0de18ea36e2c34b898ed38c3b45", + "sha256:beac28ed60c8e838301226a7a85841d0af2068eba2dcb1a58c2d32d6c05e440e", + "sha256:c29f096ce79c03054a1101d6e5fe6bf04b0bb489165d5e0e9653fb4fe8048ee1", + "sha256:c58779966d53e5f14ba393d64e2402a7926601d1ac8adeb4e83893def79d0428", + "sha256:cfe14b37908eaf7d5506302987228bff69e1b8e7071ccd4e70fd0283b1b47f0b", + "sha256:e834249c45aa9837d0753351cdca61a4b8b383cc9ad0ff2325c97ff7b69e72a6", + "sha256:eed1b234c4499811ee85bcefa22ef5e466e75d132502226ed29740d593316c1f" + ], + "version": "==2.0.0a1" }, "psycopg2-binary": { "hashes": [ - "sha256:040234f8a4a8dfd692662a8308d78f63f31a97e1c42d2480e5e6810c48966a29", - "sha256:086f7e89ec85a6704db51f68f0dcae432eff9300809723a6e8782c41c2f48e03", - "sha256:18ca813fdb17bc1db73fe61b196b05dd1ca2165b884dd5ec5568877cabf9b039", - "sha256:19dc39616850342a2a6db70559af55b22955f86667b5f652f40c0e99253d9881", - "sha256:2166e770cb98f02ed5ee2b0b569d40db26788e0bf2ec3ae1a0d864ea6f1d8309", - "sha256:3a2522b1d9178575acee4adf8fd9f979f9c0449b00b4164bb63c3475ea6528ed", - "sha256:3aa773580f85a28ffdf6f862e59cb5a3cc7ef6885121f2de3fca8d6ada4dbf3b", - "sha256:3b5deaa3ee7180585a296af33e14c9b18c218d148e735c7accf78130765a47e3", - "sha256:407af6d7e46593415f216c7f56ba087a9a42bd6dc2ecb86028760aa45b802bd7", - "sha256:4c3c09fb674401f630626310bcaf6cd6285daf0d5e4c26d6e55ca26a2734e39b", - "sha256:4c6717962247445b4f9e21c962ea61d2e884fc17df5ddf5e35863b016f8a1f03", - "sha256:50446fae5681fc99f87e505d4e77c9407e683ab60c555ec302f9ac9bffa61103", - "sha256:5057669b6a66aa9ca118a2a860159f0ee3acf837eda937bdd2a64f3431361a2d", - "sha256:5dd90c5438b4f935c9d01fcbad3620253da89d19c1f5fca9158646407ed7df35", - "sha256:659c815b5b8e2a55193ede2795c1e2349b8011497310bb936da7d4745652823b", - "sha256:69b13fdf12878b10dc6003acc8d0abf3ad93e79813fd5f3812497c1c9fb9be49", - "sha256:7a1cb80e35e1ccea3e11a48afe65d38744a0e0bde88795cc56a4d05b6e4f9d70", - "sha256:7e6e3c52e6732c219c07bd97fff6c088f8df4dae3b79752ee3a817e6f32e177e", - "sha256:7f42a8490c4fe854325504ce7a6e4796b207960dabb2cbafe3c3959cb00d1d7e", - "sha256:84156313f258eafff716b2961644a4483a9be44a5d43551d554844d15d4d224e", - "sha256:8578d6b8192e4c805e85f187bc530d0f52ba86c39172e61cd51f68fddd648103", - "sha256:890167d5091279a27e2505ff0e1fb273f8c48c41d35c5b92adbf4af80e6b2ed6", - "sha256:9aadff9032e967865f9778485571e93908d27dab21d0fdfdec0ca779bb6f8ad9", - "sha256:9f24f383a298a0c0f9b3113b982e21751a8ecde6615494a3f1470eb4a9d70e9e", - "sha256:a73021b44813b5c84eda4a3af5826dd72356a900bac9bd9dd1f0f81ee1c22c2f", - "sha256:afd96845e12638d2c44d213d4810a08f4dc4a563f9a98204b7428e567014b1cd", - "sha256:b73ddf033d8cd4cc9dfed6324b1ad2a89ba52c410ef6877998422fcb9c23e3a8", - "sha256:dbc5cd56fff1a6152ca59445178652756f4e509f672e49ccdf3d79c1043113a4", - "sha256:eac8a3499754790187bb00574ab980df13e754777d346f85e0ff6df929bcd964", - "sha256:eaed1c65f461a959284649e37b5051224f4db6ebdc84e40b5e65f2986f101a08" + "sha256:008da3ab51adc70a5f1cfbbe5db3a22607ab030eb44bcecf517ad11a0c2b3cac", + "sha256:07cf82c870ec2d2ce94d18e70c13323c89f2f2a2628cbf1feee700630be2519a", + "sha256:08507efbe532029adee21b8d4c999170a83760d38249936038bd0602327029b5", + "sha256:107d9be3b614e52a192719c6bf32e8813030020ea1d1215daa86ded9a24d8b04", + "sha256:17a0ea0b0eabf07035e5e0d520dabc7950aeb15a17c6d36128ba99b2721b25b1", + "sha256:3286541b9d85a340ee4ed42732d15fc1bb441dc500c97243a768154ab8505bb5", + "sha256:3939cf75fc89c5e9ed836e228c4a63604dff95ad19aed2bbf71d5d04c15ed5ce", + "sha256:40abc319f7f26c042a11658bf3dd3b0b3bceccf883ec1c565d5c909a90204434", + "sha256:51f7823f1b087d2020d8e8c9e6687473d3d239ba9afc162d9b2ab6e80b53f9f9", + "sha256:6bb2dd006a46a4a4ce95201f836194eb6a1e863f69ee5bab506673e0ca767057", + "sha256:702f09d8f77dc4794651f650828791af82f7c2efd8c91ae79e3d9fe4bb7d4c98", + "sha256:7036ccf715925251fac969f4da9ad37e4b7e211b1e920860148a10c0de963522", + "sha256:7b832d76cc65c092abd9505cc670c4e3421fd136fb6ea5b94efbe4c146572505", + "sha256:8f74e631b67482d504d7e9cf364071fc5d54c28e79a093ff402d5f8f81e23bfa", + "sha256:930315ac53dc65cbf52ab6b6d27422611f5fb461d763c531db229c7e1af6c0b3", + "sha256:96d3038f5bd061401996614f65d27a4ecb62d843eb4f48e212e6d129171a721f", + "sha256:a20299ee0ea2f9cca494396ac472d6e636745652a64a418b39522c120fd0a0a4", + "sha256:a34826d6465c2e2bbe9d0605f944f19d2480589f89863ed5f091943be27c9de4", + "sha256:a69970ee896e21db4c57e398646af9edc71c003bc52a3cc77fb150240fefd266", + "sha256:b9a8b391c2b0321e0cd7ec6b4cfcc3dd6349347bd1207d48bcb752aa6c553a66", + "sha256:ba13346ff6d3eb2dca0b6fa0d8a9d999eff3dcd9b55f3a890f12b0b6362b2b38", + "sha256:bb0608694a91db1e230b4a314e8ed00ad07ed0c518f9a69b83af2717e31291a3", + "sha256:c8830b7d5f16fd79d39b21e3d94f247219036b29b30c8270314c46bf8b732389", + "sha256:cac918cd7c4c498a60f5d2a61d4f0a6091c2c9490d81bc805c963444032d0dab", + "sha256:cc30cb900f42c8a246e2cb76539d9726f407330bc244ca7729c41a44e8d807fb", + "sha256:ccdc6a87f32b491129ada4b87a43b1895cf2c20fdb7f98ad979647506ffc41b6", + "sha256:d1a8b01f6a964fec702d6b6dac1f91f2b9f9fe41b310cbb16c7ef1fac82df06d", + "sha256:e004db88e5a75e5fdab1620fb9f90c9598c2a195a594225ac4ed2a6f1c23e162", + "sha256:eb2f43ae3037f1ef5e19339c41cf56947021ac892f668765cd65f8ab9814192e", + "sha256:fa466306fcf6b39b8a61d003123d442b23707d635a5cb05ac4e1b62cc79105cd" ], "index": "pypi", - "version": "==2.8.4" + "version": "==2.8.5" }, "pydantic": { "hashes": [ - "sha256:18598557f0d9ab46173045910ed50458c4fb4d16153c23346b504d7a5b679f77", - "sha256:6a9335c968e13295430a208487e74d69fef40168b72dea8d975765d14e2da660", - "sha256:6f5eb88fe4c21380aa064b7d249763fc6306f0b001d7e7d52d80866d1afc9ed3", - "sha256:bc6c6a78647d7a65a493e1107572d993f26a652c49183201e3c7d23924bf7311", - "sha256:e1a63b4e6bf8820833cb6fa239ffbe8eec57ccdd7d66359eff20e68a83c1deeb", - "sha256:ede2d65ae33788d4e26e12b330b4a32c53cb14131c65bca3a59f037c73f6ee7a" - ], - "version": "==0.32.2" + "sha256:012c422859bac2e03ab3151ea6624fecf0e249486be7eb8c6ee69c91740c6752", + "sha256:07911aab70f3bc52bb845ce1748569c5e70478ac977e106a150dd9d0465ebf04", + "sha256:47b8db7024ba3d46c3d4768535e1cf87b6c8cf92ccd81e76f4e1cb8ee47688b3", + "sha256:50e4e948892a6815649ad5a9a9379ad1e5f090f17842ac206535dfaed75c6f2f", + "sha256:51f11c8bbf794a68086540da099aae4a9107447c7a9d63151edbb7d50110cf21", + "sha256:6100d7862371115c40be55cc4b8d766a74b1d0dbaf99dbfe72bb4bac0faf89ed", + "sha256:61d22d36808087d3184ed6ac0d91dd71c533b66addb02e4a9930e1e30833202f", + "sha256:72184c1421103cca128300120f8f1185fb42a9ea73a1c9845b1c53db8c026a7d", + "sha256:831a0265a9e3933b3d0f04d1a81bba543bafbe4119c183ff2771871db70524ab", + "sha256:8848b4eb458469739126e4c1a202d723dd092e087f8dbe3104371335f87ba5df", + "sha256:bbbed364376f4a0aebb9ea452ff7968b306499a9e74f4db69b28ff2cd4043a11", + "sha256:e27559cedbd7f59d2375bfd6eea29a330ea1a5b0589c34d6b4e0d7bec6027bbf", + "sha256:f17ec336e64d4583311249fb179528e9a2c27c8a2eaf590ec6ec2c6dece7cb3f", + "sha256:f863456d3d4bf817f2e5248553dee3974c5dc796f48e6ddb599383570f4215ac" + ], + "version": "==1.4" }, "python-dateutil": { "hashes": [ - "sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", - "sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e" + "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", + "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" ], - "version": "==2.8.0" + "version": "==2.8.1" }, "python-editor": { "hashes": [ @@ -271,83 +342,138 @@ ], "version": "==1.0.4" }, + "s3transfer": { + "hashes": [ + "sha256:2482b4259524933a022d59da830f51bd746db62f047d6eb213f2f8855dcb8a13", + "sha256:921a37e2aefc64145e7b73d50c71bb4f26f46e4c9f414dc648c6245ff92cf7db" + ], + "version": "==0.3.3" + }, "sentry-sdk": { "hashes": [ - "sha256:cf4b0f8401f4d146e6b8c5579b24397273126c9a0576fa7eb9581ad27b330f13", - "sha256:f6e850f304382d87c5c52c01db8c0004d2ced6a0b073df2f2257168cf31b31aa" + "sha256:23808d571d2461a4ce3784ec12bbee5bdb8c026c143fe79d36cef8a6d653e71f", + "sha256:bb90a4e19c7233a580715fc986cc44be2c48fc10b31e71580a2037e1c94b6950" ], "index": "pypi", - "version": "==0.13.1" + "version": "==0.14.3" }, "six": { "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", + "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c" ], - "version": "==1.12.0" + "version": "==1.14.0" }, "sqlalchemy": { "hashes": [ - "sha256:0f0768b5db594517e1f5e1572c73d14cf295140756431270d89496dc13d5e46c" - ], - "version": "==1.3.10" + "sha256:083e383a1dca8384d0ea6378bd182d83c600ed4ff4ec8247d3b2442cf70db1ad", + "sha256:0a690a6486658d03cc6a73536d46e796b6570ac1f8a7ec133f9e28c448b69828", + "sha256:114b6ace30001f056e944cebd46daef38fdb41ebb98f5e5940241a03ed6cad43", + "sha256:128f6179325f7597a46403dde0bf148478f868df44841348dfc8d158e00db1f9", + "sha256:13d48cd8b925b6893a4e59b2dfb3e59a5204fd8c98289aad353af78bd214db49", + "sha256:211a1ce7e825f7142121144bac76f53ac28b12172716a710f4bf3eab477e730b", + "sha256:2dc57ee80b76813759cccd1a7affedf9c4dbe5b065a91fb6092c9d8151d66078", + "sha256:3e625e283eecc15aee5b1ef77203bfb542563fa4a9aa622c7643c7b55438ff49", + "sha256:43078c7ec0457387c79b8d52fff90a7ad352ca4c7aa841c366238c3e2cf52fdf", + "sha256:5b1bf3c2c2dca738235ce08079783ef04f1a7fc5b21cf24adaae77f2da4e73c3", + "sha256:6056b671aeda3fc451382e52ab8a753c0d5f66ef2a5ccc8fa5ba7abd20988b4d", + "sha256:68d78cf4a9dfade2e6cf57c4be19f7b82ed66e67dacf93b32bb390c9bed12749", + "sha256:7025c639ce7e170db845e94006cf5f404e243e6fc00d6c86fa19e8ad8d411880", + "sha256:7224e126c00b8178dfd227bc337ba5e754b197a3867d33b9f30dc0208f773d70", + "sha256:7d98e0785c4cd7ae30b4a451416db71f5724a1839025544b4edbd92e00b91f0f", + "sha256:8d8c21e9d4efef01351bf28513648ceb988031be4159745a7ad1b3e28c8ff68a", + "sha256:bbb545da054e6297242a1bb1ba88e7a8ffb679f518258d66798ec712b82e4e07", + "sha256:d00b393f05dbd4ecd65c989b7f5a81110eae4baea7a6a4cdd94c20a908d1456e", + "sha256:e18752cecaef61031252ca72031d4d6247b3212ebb84748fc5d1a0d2029c23ea" + ], + "version": "==1.3.16" }, "sqlalchemy-utils": { "hashes": [ - "sha256:6689b29d7951c5c7c4d79fa6b8c95f9ff9ec708b07aa53f82060599bd14dcc88" + "sha256:f268af5bc03597fe7690d60df3e5f1193254a83e07e4686f720f61587ec4493a" ], "index": "pypi", - "version": "==0.34.2" + "version": "==0.36.3" }, "starlette": { "hashes": [ - "sha256:c2ac9a42e0e0328ad20fe444115ac5e3760c1ee2ac1ff8cdb5ec915c4a453411" + "sha256:6169ee78ded501095d1dda7b141a1dc9f9934d37ad23196e180150ace2c6449b", + "sha256:a9bb130fa7aa736eda8a814b6ceb85ccf7a209ed53843d0d61e246b380afa10f" + ], + "version": "==0.13.2" + }, + "typing-extensions": { + "hashes": [ + "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5", + "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae", + "sha256:f8d2bd89d25bc39dabe7d23df520442fa1d8969b82544370e03d88b5a591c392" ], - "version": "==0.12.9" + "version": "==3.7.4.2" }, "urllib3": { "hashes": [ - "sha256:3de946ffbed6e6746608990594d08faac602528ac7015ac28d33cee6a45b7398", - "sha256:9a107b99a5393caf59c7aa3c1249c16e6879447533d0887f4336dde834c7be86" + "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc", + "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc" ], - "version": "==1.25.6" + "markers": "python_version != '3.4'", + "version": "==1.25.8" }, "uvicorn": { "hashes": [ - "sha256:33c7cfcf71450d2170c9a4c4c7559767329040a36b159e3889554132e4b89457" + "sha256:0f58170165c4495f563d8224b2f415a0829af0412baa034d6f777904613087fd", + "sha256:6fdaf8e53bf1b2ddf0fe9ed06079b5348d7d1d87b3365fe2549e6de0d49e631c" ], "index": "pypi", - "version": "==0.9.1" + "version": "==0.11.3" }, "uvloop": { "hashes": [ - "sha256:182617c2992a79b268bfd193691c4aacb93634e9d8d96edf560a842a6206411d", - "sha256:2a0268553d2920108b05250c9711060313851daa60b1052c38b6520320aa50b1", - "sha256:32d2fe6ee6be28a99661e1f02bf6cedb99711df1065a3fb7ba7dd73ccb85f768", - "sha256:448b13a1adfc47745b880b5d5b34c975c7851b1cd3b0eafe2569b2250190c797", - "sha256:469e0e3b80f245ed32f054174e6a69e6a01715dbbb24eb917733fe5af09ad306", - "sha256:682fa2ab24a758831f531dca122f128373c3dd95a3c8885b5fd1c48775d0024f", - "sha256:9967fd537f3164607d153900aaae036e9a18015d8478f84406ba58b183f5abfc", - "sha256:9ab030794432c47b78199d3f268ac2c898ae85fb9f09e10ae03dd7af62904b0e", - "sha256:c1d55b6926d956a29cf5d7cc891004602ea7cd006b0b80354b9b3d973ca9027f" - ], - "version": "==0.14.0rc1" + "sha256:08b109f0213af392150e2fe6f81d33261bb5ce968a288eb698aad4f46eb711bd", + "sha256:123ac9c0c7dd71464f58f1b4ee0bbd81285d96cdda8bc3519281b8973e3a461e", + "sha256:4315d2ec3ca393dd5bc0b0089d23101276778c304d42faff5dc4579cb6caef09", + "sha256:4544dcf77d74f3a84f03dd6278174575c44c67d7165d4c42c71db3fdc3860726", + "sha256:afd5513c0ae414ec71d24f6f123614a80f3d27ca655a4fcf6cabe50994cc1891", + "sha256:b4f591aa4b3fa7f32fb51e2ee9fea1b495eb75b0b3c8d0ca52514ad675ae63f7", + "sha256:bcac356d62edd330080aed082e78d4b580ff260a677508718f88016333e2c9c5", + "sha256:e7514d7a48c063226b7d06617cbb12a14278d4323a065a8d46a7962686ce2e95", + "sha256:f07909cd9fc08c52d294b1570bba92186181ca01fe3dc9ffba68955273dd7362" + ], + "markers": "sys_platform != 'win32' and sys_platform != 'cygwin' and platform_python_implementation != 'PyPy'", + "version": "==0.14.0" }, "websockets": { "hashes": [ - "sha256:049e694abe33f8a1d99969fee7bfc0ae6761f7fd5f297c58ea933b27dd6805f2", - "sha256:73ce69217e4655783ec72ce11c151053fcbd5b837cc39de7999e19605182e28a", - "sha256:83e63aa73331b9ca21af61df8f115fb5fbcba3f281bee650a4ad16a40cd1ef15", - "sha256:882a7266fa867a2ebb2c0baaa0f9159cabf131cf18c1b4270d79ad42f9208dc5", - "sha256:8c77f7d182a6ea2a9d09c2612059f3ad859a90243e899617137ee3f6b7f2b584", - "sha256:8d7a20a2f97f1e98c765651d9fb9437201a9ccc2c70e94b0270f1c5ef29667a3", - "sha256:a7affaeffbc5d55681934c16bb6b8fc82bb75b175e7fd4dcca798c938bde8dda", - "sha256:c82e286555f839846ef4f0fdd6910769a577952e1e26aa8ee7a6f45f040e3c2b", - "sha256:e906128532a14b9d264a43eb48f9b3080d53a9bda819ab45bf56b8039dc606ac", - "sha256:e9102043a81cdc8b7c8032ff4bce39f6229e4ac39cb2010946c912eeb84e2cb6", - "sha256:f5cb2683367e32da6a256b60929a3af9c29c212b5091cf5bace9358d03011bf5" - ], - "version": "==8.0.2" + "sha256:0e4fb4de42701340bd2353bb2eee45314651caa6ccee80dbd5f5d5978888fed5", + "sha256:1d3f1bf059d04a4e0eb4985a887d49195e15ebabc42364f4eb564b1d065793f5", + "sha256:20891f0dddade307ffddf593c733a3fdb6b83e6f9eef85908113e628fa5a8308", + "sha256:295359a2cc78736737dd88c343cd0747546b2174b5e1adc223824bcaf3e164cb", + "sha256:2db62a9142e88535038a6bcfea70ef9447696ea77891aebb730a333a51ed559a", + "sha256:3762791ab8b38948f0c4d281c8b2ddfa99b7e510e46bd8dfa942a5fff621068c", + "sha256:3db87421956f1b0779a7564915875ba774295cc86e81bc671631379371af1170", + "sha256:3ef56fcc7b1ff90de46ccd5a687bbd13a3180132268c4254fc0fa44ecf4fc422", + "sha256:4f9f7d28ce1d8f1295717c2c25b732c2bc0645db3215cf757551c392177d7cb8", + "sha256:5c01fd846263a75bc8a2b9542606927cfad57e7282965d96b93c387622487485", + "sha256:5c65d2da8c6bce0fca2528f69f44b2f977e06954c8512a952222cea50dad430f", + "sha256:751a556205d8245ff94aeef23546a1113b1dd4f6e4d102ded66c39b99c2ce6c8", + "sha256:7ff46d441db78241f4c6c27b3868c9ae71473fe03341340d2dfdbe8d79310acc", + "sha256:965889d9f0e2a75edd81a07592d0ced54daa5b0785f57dc429c378edbcffe779", + "sha256:9b248ba3dd8a03b1a10b19efe7d4f7fa41d158fdaa95e2cf65af5a7b95a4f989", + "sha256:9bef37ee224e104a413f0780e29adb3e514a5b698aabe0d969a6ba426b8435d1", + "sha256:c1ec8db4fac31850286b7cd3b9c0e1b944204668b8eb721674916d4e28744092", + "sha256:c8a116feafdb1f84607cb3b14aa1418424ae71fee131642fc568d21423b51824", + "sha256:ce85b06a10fc65e6143518b96d3dca27b081a740bae261c2fb20375801a9d56d", + "sha256:d705f8aeecdf3262379644e4b55107a3b55860eb812b673b28d0fbc347a60c55", + "sha256:e898a0863421650f0bebac8ba40840fc02258ef4714cb7e1fd76b6a6354bda36", + "sha256:f8a7bff6e8664afc4e6c28b983845c5bc14965030e3fb98789734d416af77c4b" + ], + "version": "==8.1" + }, + "zipp": { + "hashes": [ + "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b", + "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96" + ], + "version": "==3.1.0" } }, "develop": { @@ -375,18 +501,18 @@ }, "black": { "hashes": [ - "sha256:09a9dcb7c46ed496a9850b76e4e825d6049ecd38b611f1224857a79bd985a8cf", - "sha256:68950ffd4d9169716bcb8719a56c07a2f4485354fec061cdd5910aa07369731c" + "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b", + "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539" ], "index": "pypi", - "version": "==19.3b0" + "version": "==19.10b0" }, "click": { "hashes": [ - "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", - "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" + "sha256:8a18b4ea89d8820c5d0c7da8a64b2c324b4dabb695804dbfea19b9be9d88c0cc", + "sha256:e345d143d80bf5ee7534056164e5e112ea5e22716bbb1ce727941f4c8b471b9a" ], - "version": "==7.0" + "version": "==7.1.1" }, "entrypoints": { "hashes": [ @@ -403,19 +529,19 @@ "index": "pypi", "version": "==3.7.9" }, - "gitdb2": { + "gitdb": { "hashes": [ - "sha256:1b6df1433567a51a4a9c1a5a0de977aa351a405cc56d7d35f3388bad1f630350", - "sha256:96bbb507d765a7f51eb802554a9cfe194a174582f772e0d89f4e87288c288b7b" + "sha256:6f0ecd46f99bb4874e5678d628c3a198e2b4ef38daea2756a2bfd8df7dd5c1a5", + "sha256:ba1132c0912e8c917aa8aa990bee26315064c7b7f171ceaaac0afeb1dc656c6a" ], - "version": "==2.0.6" + "version": "==4.0.4" }, "gitpython": { "hashes": [ - "sha256:3237caca1139d0a7aa072f6735f5fd2520de52195e0fa1d8b83a9b212a2498b2", - "sha256:a7d6bef0775f66ba47f25911d285bcd692ce9053837ff48a120c2b8cf3a71389" + "sha256:6d4f10e2aaad1864bb0f17ec06a2c2831534140e5883c350d58b4e85189dab74", + "sha256:71b8dad7409efbdae4930f2b0b646aaeccce292484ffa0bc74f1195582578b3d" ], - "version": "==3.0.4" + "version": "==3.1.1" }, "mccabe": { "hashes": [ @@ -424,12 +550,19 @@ ], "version": "==0.6.1" }, + "pathspec": { + "hashes": [ + "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0", + "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061" + ], + "version": "==0.8.0" + }, "pbr": { "hashes": [ - "sha256:2c8e420cd4ed4cec4e7999ee47409e876af575d4c35a45840d59e8b5f3155ab8", - "sha256:b32c8ccaac7b1a20c0ce00ce317642e6cf231cf038f9875e0280e28af5bf7ac9" + "sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c", + "sha256:579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8" ], - "version": "==5.4.3" + "version": "==5.4.5" }, "pycodestyle": { "hashes": [ @@ -447,51 +580,75 @@ }, "pyyaml": { "hashes": [ - "sha256:0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9", - "sha256:01adf0b6c6f61bd11af6e10ca52b7d4057dd0be0343eb9283c878cf3af56aee4", - "sha256:5124373960b0b3f4aa7df1707e63e9f109b5263eca5976c66e08b1c552d4eaf8", - "sha256:5ca4f10adbddae56d824b2c09668e91219bb178a1eee1faa56af6f99f11bf696", - "sha256:7907be34ffa3c5a32b60b95f4d95ea25361c951383a894fec31be7252b2b6f34", - "sha256:7ec9b2a4ed5cad025c2278a1e6a19c011c80a3caaac804fd2d329e9cc2c287c9", - "sha256:87ae4c829bb25b9fe99cf71fbb2140c448f534e24c998cc60f39ae4f94396a73", - "sha256:9de9919becc9cc2ff03637872a440195ac4241c80536632fffeb6a1e25a74299", - "sha256:a5a85b10e450c66b49f98846937e8cfca1db3127a9d5d1e31ca45c3d0bef4c5b", - "sha256:b0997827b4f6a7c286c01c5f60384d218dca4ed7d9efa945c3e1aa623d5709ae", - "sha256:b631ef96d3222e62861443cc89d6563ba3eeb816eeb96b2629345ab795e53681", - "sha256:bf47c0607522fdbca6c9e817a6e81b08491de50f3766a7a0e6a5be7905961b41", - "sha256:f81025eddd0327c7d4cfe9b62cf33190e1e736cc6e97502b3ec425f574b3e7a8" - ], - "version": "==5.1.2" + "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97", + "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76", + "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2", + "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648", + "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf", + "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f", + "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2", + "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee", + "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d", + "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c", + "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a" + ], + "version": "==5.3.1" + }, + "regex": { + "hashes": [ + "sha256:08119f707f0ebf2da60d2f24c2f39ca616277bb67ef6c92b72cbf90cbe3a556b", + "sha256:0ce9537396d8f556bcfc317c65b6a0705320701e5ce511f05fc04421ba05b8a8", + "sha256:1cbe0fa0b7f673400eb29e9ef41d4f53638f65f9a2143854de6b1ce2899185c3", + "sha256:2294f8b70e058a2553cd009df003a20802ef75b3c629506be20687df0908177e", + "sha256:23069d9c07e115537f37270d1d5faea3e0bdded8279081c4d4d607a2ad393683", + "sha256:24f4f4062eb16c5bbfff6a22312e8eab92c2c99c51a02e39b4eae54ce8255cd1", + "sha256:295badf61a51add2d428a46b8580309c520d8b26e769868b922750cf3ce67142", + "sha256:2a3bf8b48f8e37c3a40bb3f854bf0121c194e69a650b209628d951190b862de3", + "sha256:4385f12aa289d79419fede43f979e372f527892ac44a541b5446617e4406c468", + "sha256:5635cd1ed0a12b4c42cce18a8d2fb53ff13ff537f09de5fd791e97de27b6400e", + "sha256:5bfed051dbff32fd8945eccca70f5e22b55e4148d2a8a45141a3b053d6455ae3", + "sha256:7e1037073b1b7053ee74c3c6c0ada80f3501ec29d5f46e42669378eae6d4405a", + "sha256:90742c6ff121a9c5b261b9b215cb476eea97df98ea82037ec8ac95d1be7a034f", + "sha256:a58dd45cb865be0ce1d5ecc4cfc85cd8c6867bea66733623e54bd95131f473b6", + "sha256:c087bff162158536387c53647411db09b6ee3f9603c334c90943e97b1052a156", + "sha256:c162a21e0da33eb3d31a3ac17a51db5e634fc347f650d271f0305d96601dc15b", + "sha256:c9423a150d3a4fc0f3f2aae897a59919acd293f4cb397429b120a5fcd96ea3db", + "sha256:ccccdd84912875e34c5ad2d06e1989d890d43af6c2242c6fcfa51556997af6cd", + "sha256:e91ba11da11cf770f389e47c3f5c30473e6d85e06d7fd9dcba0017d2867aab4a", + "sha256:ea4adf02d23b437684cd388d557bf76e3afa72f7fed5bbc013482cc00c816948", + "sha256:fb95debbd1a824b2c4376932f2216cc186912e389bdb0e27147778cf6acb3f89" + ], + "version": "==2020.4.4" }, "rope": { "hashes": [ - "sha256:6b728fdc3e98a83446c27a91fc5d56808a004f8beab7a31ab1d7224cecc7d969", - "sha256:c5c5a6a87f7b1a2095fb311135e2a3d1f194f5ecb96900fdd0a9100881f48aaf", - "sha256:f0dcf719b63200d492b85535ebe5ea9b29e0d0b8aebeb87fe03fc1a65924fdaf" + "sha256:52423a7eebb5306a6d63bdc91a7c657db51ac9babfb8341c9a1440831ecf3203", + "sha256:ae1fa2fd56f64f4cc9be46493ce54bed0dd12dee03980c61a4393d89d84029ad", + "sha256:d2830142c2e046f5fc26a022fe680675b6f48f81c7fc1f03a950706e746e9dfe" ], "index": "pypi", - "version": "==0.14.0" + "version": "==0.16.0" }, "six": { "hashes": [ - "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", - "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", + "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c" ], - "version": "==1.12.0" + "version": "==1.14.0" }, - "smmap2": { + "smmap": { "hashes": [ - "sha256:0555a7bf4df71d1ef4218e4807bbf9b201f910174e6e08af2e138d4e517b4dde", - "sha256:29a9ffa0497e7f2be94ca0ed1ca1aa3cd4cf25a1f6b4f5f87f74b46ed91d609a" + "sha256:52ea78b3e708d2c2b0cfe93b6fc3fbeec53db913345c26be6ed84c11ed8bebc1", + "sha256:b46d3fc69ba5f367df96d91f8271e8ad667a198d5a28e215a6c3d9acd133a911" ], - "version": "==2.0.5" + "version": "==3.0.2" }, "stevedore": { "hashes": [ - "sha256:01d9f4beecf0fbd070ddb18e5efb10567801ba7ef3ddab0074f54e3cd4e91730", - "sha256:e0739f9739a681c7a1fda76a102b65295e96a144ccdb552f2ae03c5f0abe8a14" + "sha256:18afaf1d623af5950cc0f7e75e70f917784c73b652a34a12d90b309451b5500b", + "sha256:a4e7dc759fb0f2e3e2f7d8ffe2358c19d45b9b8297f393ef1256858d82f69c9b" ], - "version": "==1.31.0" + "version": "==1.32.0" }, "toml": { "hashes": [ @@ -500,13 +657,39 @@ ], "version": "==0.10.0" }, + "typed-ast": { + "hashes": [ + "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355", + "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919", + "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa", + "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652", + "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75", + "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01", + "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d", + "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1", + "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907", + "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c", + "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3", + "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b", + "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614", + "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb", + "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b", + "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41", + "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6", + "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34", + "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe", + "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4", + "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7" + ], + "version": "==1.4.1" + }, "watchgod": { "hashes": [ - "sha256:30ffb90c692e0797d23a39d695928c57d8c01a4a9708434e9dca16d7bd4e24c7", - "sha256:78d44cbacf4fbbf7573d10fcf0f156f1b0d71598d32477c34f8cf66001bafc1f" + "sha256:59700dab7445aa8e6067a5b94f37bae90fc367554549b1ed2e9d0f4f38a90d2a", + "sha256:e9cca0ab9c63f17fc85df9fd8bd18156ff00aff04ebe5976cee473f4968c6858" ], "index": "pypi", - "version": "==0.5" + "version": "==0.6" } } } diff --git a/README.md b/README.md index fd2ca1221..fe70731cc 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,18 @@ -# fastapi-gino-arq-uvicorn -High-performance Async REST API, in Python. FastAPI + GINO + Arq + Uvicorn (powered by Redis & PostgreSQL). +# GFW Data API +High-performance Async REST API, in Python. FastAPI + GINO + Uvicorn (powered by PostgreSQL). ## Get Started ### Run Locally -_NOTE: You must have PostgreSQL & Redis running locally._ +_NOTE: You must have PostgreSQL running locally._ 1. Clone this Repository. `git clone https://github.com/leosussan/fastapi-gino-arq-uvicorn.git` 2. Run `pipenv install --dev` from root. (Run `pip install pipenv` first, if necessary.) -3. Make a copy of `.dist.env`, rename to `.env`. Fill in PostgreSQL, Redis connection vars. +3. Make a copy of `.dist.env`, rename to `.env`. Fill in PostgreSQL connection vars. 4. Generate DB Migrations: `alembic revision --autogenerate`. It will be applied when the application starts. You can trigger manually with `alembic upgrade head`. 5. Run: - FastAPI Application: * _For Active Development (w/ auto-reload):_ Run locally with `pipenv run uvicorn app.main:app --reload ` * _For Debugging (compatible w/ debuggers, no auto-reload):_ Configure debugger to run `python app/main.py`. - - Background Task Worker: - * _For Active Development:_ Run with `pipenv run arq app.worker.Worker --watch ./` ### Run Locally with Docker-Compose 1. Clone this Repository. `git clone https://github.com/leosussan/fastapi-gino-arq-uvicorn.git` @@ -30,15 +28,12 @@ _NOTE: You must have PostgreSQL & Redis running locally._ * Store complex db queries in `/app/models/orm/queries` * Store complex tasks in `app/tasks`. * Add / edit globals to `/.env`, expose & import them from `/app/settings/globals.py` - * Use any coroutine as a background function: store a reference in the `ARQ_BACKGROUND_FUNCTIONS` env. - * Set `SENTRY_DSN` in your environment to enable Sentry. * Define code to run before launch (migrations, setup, etc) in `/app/settings/prestart.sh` ## Features ### Core Dependencies * **FastAPI:** touts performance on-par with NodeJS & Go + automatic Swagger + ReDoc generation. * **GINO:** built on SQLAlchemy core. Lightweight, simple, asynchronous ORM for PostgreSQL. -* **Arq:** Asyncio + Redis = fast, resource-light job queuing & RPC. * **Uvicorn:** Lightning-fast, asynchronous ASGI server. * **Optimized Dockerfile:** Optimized Dockerfile for ASGI applications, from https://github.com/tiangolo/uvicorn-gunicorn-docker. @@ -46,6 +41,4 @@ _NOTE: You must have PostgreSQL & Redis running locally._ * **Pydantic:** Core to FastAPI. Define how data should be in pure, canonical python; validate it with pydantic. * **Alembic:** Handles database migrations. Compatible with GINO. * **SQLAlchemy_Utils:** Provides essential handles & datatypes. Compatible with GINO. -* **Sentry:** Open-source, cloud-hosted error + event monitoring. * **PostgreSQL:** Robust, fully-featured, scalable, open-source. -* **Redis:** Fast, simple, broker for the Arq task queue. diff --git a/alembic.ini b/alembic.ini index b1d0fa061..7091a0ed2 100644 --- a/alembic.ini +++ b/alembic.ini @@ -35,6 +35,9 @@ script_location = app/models/orm/migrations # are written from script.py.mako # output_encoding = utf-8 +[alembic:exclude] +tables = spatial_ref_sys + # Logging configuration [loggers] keys = root,sqlalchemy,alembic diff --git a/app/application.py b/app/application.py index 57c584c5c..19f76c000 100644 --- a/app/application.py +++ b/app/application.py @@ -1,13 +1,8 @@ from fastapi import FastAPI from gino.ext.starlette import Gino -from sentry_sdk import init as initialize_sentry -from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration from sqlalchemy.schema import MetaData -from .settings.globals import DATABASE_CONFIG, SENTRY_DSN - -if SENTRY_DSN not in (None, ""): - initialize_sentry(dsn=SENTRY_DSN, integrations=[SqlalchemyIntegration()]) +from .settings.globals import DATABASE_CONFIG app: FastAPI = FastAPI() db: MetaData = Gino(app, dsn=DATABASE_CONFIG.url) diff --git a/app/main.py b/app/main.py index 904a7c650..2bfa868d2 100644 --- a/app/main.py +++ b/app/main.py @@ -2,21 +2,15 @@ sys.path.extend(["./"]) -from sentry_sdk.integrations.asgi import SentryAsgiMiddleware - from app.application import app -from app.routes.users import router as user_router -from app.settings.globals import SENTRY_DSN +from app.routes import datasets, features, fields, geostore, query, sources, versions -ROUTERS = (user_router,) +ROUTERS = (datasets.router, versions.router, sources.router, fields.router, query.router, features.router, geostore.router) for r in ROUTERS: app.include_router(r) -if SENTRY_DSN not in (None, "", " "): - app.add_middleware(SentryAsgiMiddleware) - if __name__ == "__main__": import uvicorn diff --git a/app/models/orm/asset.py b/app/models/orm/asset.py new file mode 100644 index 000000000..760b7c774 --- /dev/null +++ b/app/models/orm/asset.py @@ -0,0 +1,12 @@ +from .base import Base, db + + +class Asset(Base): + __tablename__ = 'assets' + dataset = db.Column(db.String, primary_key=True) + version = db.Column(db.String, primary_key=True) + asset_type = db.Column(db.String, primary_key=True) + asset_uri = db.Column(db.String) + metadata = db.Column(db.JSONB) + + fk = db.ForeignKeyConstraint(["dataset", "version"], ["versions.dataset", "versions.version"], name="fk") diff --git a/app/models/orm/base.py b/app/models/orm/base.py index 0a89d11ae..3dc630e24 100644 --- a/app/models/orm/base.py +++ b/app/models/orm/base.py @@ -2,10 +2,11 @@ from sqlalchemy.dialects.postgresql import JSONB, UUID from sqlalchemy_utils import EmailType, generic_repr +from geoalchemy2 import Geometry from ...application import db -db.JSONB, db.UUID, db.EmailType = (JSONB, UUID, EmailType) +db.JSONB, db.UUID, db.EmailType, db.Geometry = (JSONB, UUID, EmailType, Geometry) @generic_repr @@ -14,4 +15,4 @@ class Base(db.Model): created_on = db.Column(db.DateTime, default=datetime.utcnow, server_default=db.func.now()) updated_on = db.Column( db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, server_default=db.func.now()) - id = db.Column(db.BigInteger, primary_key=True, autoincrement=True) + diff --git a/app/models/orm/dataset.py b/app/models/orm/dataset.py new file mode 100644 index 000000000..b634ae697 --- /dev/null +++ b/app/models/orm/dataset.py @@ -0,0 +1,8 @@ +from .base import Base, db + + +class Dataset(Base): + __tablename__ = 'datasets' + dataset = db.Column(db.String, primary_key=True) + metadata = db.Column(db.JSONB) + diff --git a/app/models/orm/geostore.py b/app/models/orm/geostore.py new file mode 100644 index 000000000..07f2ff7eb --- /dev/null +++ b/app/models/orm/geostore.py @@ -0,0 +1,12 @@ +from .base import Base, db + + +class Geostore(Base): + __tablename__ = 'geostore' + + gfw_geostore_id = db.Column(db.UUID, primary_key=True) + gfw_geojson = db.Column(db.String, nullable=False), + gfw_area__ha = db.Column(db.Numeric, nullable=False) + gfw_bbox = db.Column(db.Geometry("Polygon", 4326), nullable=False) # TODO check if this is the correct type + + _geostore_gfw_geostore_id_idx = db.Index("geostore_gfw_geostore_id_idx", "gfw_geostore_id", postgresql_using='hash') diff --git a/app/models/orm/migrations/env.py b/app/models/orm/migrations/env.py index 69d6e9e4e..184c03a6b 100644 --- a/app/models/orm/migrations/env.py +++ b/app/models/orm/migrations/env.py @@ -4,9 +4,13 @@ ######################## --- MODELS FOR MIGRATIONS --- ######################## from app.application import db -from app.models.orm.user import User # To include a model in migrations, add a line here. +from app.models.orm.dataset import Dataset +from app.models.orm.version import Version +from app.models.orm.asset import Asset +from app.models.orm.geostore import Geostore + ############################################################################### @@ -23,6 +27,24 @@ target_metadata = db +def exclude_tables_from_config(config_): + tables = None + tables_ = config_.get("tables", None) + if tables_ is not None: + tables = tables_.split(",") + return tables + + +exclude_tables = exclude_tables_from_config(config.get_section('alembic:exclude')) + + +def include_object(object, name, type_, reflected, compare_to): + if type_ == "table" and name in exclude_tables: + return False + else: + return True + + def run_migrations_offline(): """Run migrations in 'offline' mode. @@ -36,7 +58,7 @@ def run_migrations_offline(): """ context.configure( - url=ALEMBIC_CONFIG.url.__to_string__(hide_password=False), target_metadata=target_metadata, literal_binds=True + url=ALEMBIC_CONFIG.url.__to_string__(hide_password=False), target_metadata=target_metadata, literal_binds=True, include_object=include_object ) with context.begin_transaction(): @@ -57,7 +79,7 @@ def run_migrations_online(): ) with connectable.connect() as connection: context.configure( - connection=connection, target_metadata=target_metadata + connection=connection, target_metadata=target_metadata, include_object=include_object ) with context.begin_transaction(): diff --git a/app/models/orm/migrations/versions/.gitkeep b/app/models/orm/migrations/versions/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/app/models/orm/migrations/versions/86ae41de358d_.py b/app/models/orm/migrations/versions/86ae41de358d_.py new file mode 100644 index 000000000..3a3ddc9e5 --- /dev/null +++ b/app/models/orm/migrations/versions/86ae41de358d_.py @@ -0,0 +1,108 @@ +"""empty message + +Revision ID: 86ae41de358d +Revises: +Create Date: 2020-04-14 21:58:38.173605 + +""" +import json +import os + +import boto3 +import sqlalchemy as sa +import geoalchemy2 + +from alembic import op +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = 'e47ec2fc3c51' +down_revision = None +branch_labels = None +depends_on = None + +client = boto3.client("secretsmanager") +response = client.get_secret_value(SecretId=os.environ["SECRET_NAME"]) +secrets = json.loads(response["SecretString"]) + +USERNAME = secrets["username"] +PASSWORD = secrets["password"] +DBNAME = secrets["dbname"] + + +def upgrade(): + + #### Create read only user + op.execute(f""" + DO + $do$ + BEGIN + IF NOT EXISTS ( + SELECT -- SELECT list can stay empty for this + FROM pg_catalog.pg_roles + WHERE rolname = '{USERNAME}') THEN + CREATE ROLE {USERNAME} LOGIN PASSWORD '{PASSWORD}'; + END IF; + END + $do$; + """) + op.execute(f"GRANT CONNECT ON DATABASE {DBNAME} TO {USERNAME};") + op.execute(f"ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO {USERNAME};") + + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('datasets', + sa.Column('created_on', sa.DateTime(), server_default=sa.text('now()'), nullable=True), + sa.Column('updated_on', sa.DateTime(), server_default=sa.text('now()'), nullable=True), + sa.Column('dataset', sa.String(), nullable=False), + sa.Column('metadata', postgresql.JSONB(astext_type=sa.Text()), nullable=True), + sa.PrimaryKeyConstraint('dataset') + ) + op.create_table('geostore', + sa.Column('created_on', sa.DateTime(), server_default=sa.text('now()'), nullable=True), + sa.Column('updated_on', sa.DateTime(), server_default=sa.text('now()'), nullable=True), + sa.Column('gfw_geostore_id', postgresql.UUID(), nullable=False), + sa.Column('gfw_area__ha', sa.Numeric(), nullable=False), + sa.Column('gfw_bbox', geoalchemy2.types.Geometry(geometry_type='POLYGON', srid=4326), nullable=False), + sa.PrimaryKeyConstraint('gfw_geostore_id') + ) + op.create_index('geostore_gfw_geostore_id_idx', 'geostore', ['gfw_geostore_id'], unique=False, postgresql_using='hash') + op.create_table('versions', + sa.Column('created_on', sa.DateTime(), server_default=sa.text('now()'), nullable=True), + sa.Column('updated_on', sa.DateTime(), server_default=sa.text('now()'), nullable=True), + sa.Column('dataset', sa.String(), nullable=False), + sa.Column('version', sa.String(), nullable=False), + sa.Column('is_latest', sa.Boolean(), nullable=True), + sa.Column('source_type', sa.String(), nullable=False), + sa.Column('has_vector_tile_cache', sa.Boolean(), nullable=True), + sa.Column('has_raster_tile_cache', sa.Boolean(), nullable=True), + sa.Column('has_geostore', sa.Boolean(), nullable=True), + sa.Column('has_feature_info', sa.Boolean(), nullable=True), + sa.Column('has_10_40000_tiles', sa.Boolean(), nullable=True), + sa.Column('has_90_27008_tiles', sa.Boolean(), nullable=True), + sa.Column('has_90_9876_tiles', sa.Boolean(), nullable=True), + sa.Column('metadata', postgresql.JSONB(astext_type=sa.Text()), nullable=True), + sa.ForeignKeyConstraint(['dataset'], ['datasets.dataset'], name='fk'), + sa.PrimaryKeyConstraint('dataset', 'version') + ) + op.create_table('assets', + sa.Column('created_on', sa.DateTime(), server_default=sa.text('now()'), nullable=True), + sa.Column('updated_on', sa.DateTime(), server_default=sa.text('now()'), nullable=True), + sa.Column('dataset', sa.String(), nullable=False), + sa.Column('version', sa.String(), nullable=False), + sa.Column('asset_type', sa.String(), nullable=False), + sa.Column('asset_uri', sa.String(), nullable=True), + sa.Column('metadata', postgresql.JSONB(astext_type=sa.Text()), nullable=True), + sa.ForeignKeyConstraint(['dataset', 'version'], ['versions.dataset', 'versions.version'], name='fk'), + sa.PrimaryKeyConstraint('dataset', 'version', 'asset_type') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('assets') + op.drop_table('versions') + op.drop_index('geostore_gfw_geostore_id_idx', table_name='geostore') + op.drop_table('geostore') + op.drop_table('datasets') + # ### end Alembic commands ### diff --git a/app/models/orm/user.py b/app/models/orm/user.py deleted file mode 100644 index 1a8d3c0c5..000000000 --- a/app/models/orm/user.py +++ /dev/null @@ -1,9 +0,0 @@ -from .base import Base, db - - -class User(Base): - __tablename__ = 'users' - name = db.Column(db.String(255)) - email = db.Column(db.EmailType) - phone_number = db.Column(db.Unicode(20)) - country_code = db.Column(db.Unicode(8)) diff --git a/app/models/orm/version.py b/app/models/orm/version.py new file mode 100644 index 000000000..3dd84a846 --- /dev/null +++ b/app/models/orm/version.py @@ -0,0 +1,19 @@ +from .base import Base, db + + +class Version(Base): + __tablename__ = 'versions' + dataset = db.Column(db.String, primary_key=True) + version = db.Column(db.String, primary_key=True) + is_latest = db.Column(db.Boolean, default=False) + source_type = db.Column(db.String, nullable=False) + has_vector_tile_cache = db.Column(db.Boolean, default=False) + has_raster_tile_cache = db.Column(db.Boolean, default=False) + has_geostore = db.Column(db.Boolean, default=False) + has_feature_info = db.Column(db.Boolean, default=False) + has_10_40000_tiles = db.Column(db.Boolean, default=False) + has_90_27008_tiles = db.Column(db.Boolean, default=False) + has_90_9876_tiles = db.Column(db.Boolean, default=False) + metadata = db.Column(db.JSONB) + + fk = db.ForeignKeyConstraint(["dataset"], ["datasets.dataset"], name="fk") diff --git a/app/routes/__init__.py b/app/routes/__init__.py index e69de29bb..f956a7090 100644 --- a/app/routes/__init__.py +++ b/app/routes/__init__.py @@ -0,0 +1,18 @@ +from fastapi import Path + + +VERSION_REGEX = r"^v\d{1,8}\.?\d{1,3}\.?\d{1,3}$|^latest$" + + +async def dataset_dependency(dataset: str = Path(..., title="Dataset")): + return dataset + + +async def version_dependency( + version: str = Path(..., title="Dataset version", regex=VERSION_REGEX) +): + + # if version == "latest": + # version = ... + + return version diff --git a/app/routes/datasets.py b/app/routes/datasets.py new file mode 100644 index 000000000..9a6edb067 --- /dev/null +++ b/app/routes/datasets.py @@ -0,0 +1,47 @@ +from fastapi import APIRouter, Depends +from fastapi.responses import ORJSONResponse + +from app.routes import dataset_dependency + + +router = APIRouter() + + +@router.get("/", response_class=ORJSONResponse, tags=["Dataset"]) +async def get_datasets(): + """ + Get list of all datasets + """ + pass + + +@router.get("/{dataset}", response_class=ORJSONResponse, tags=["Dataset"]) +async def get_dataset(*, dataset: str = Depends(dataset_dependency)): + """ + Get basic metadata and available versions for a given dataset + """ + pass + + +@router.put("/{dataset}", response_class=ORJSONResponse, tags=["Dataset"]) +async def put_dataset(*, dataset: str = Depends(dataset_dependency)): + """ + Create or update a dataset + """ + pass + + +@router.patch("/{dataset}", response_class=ORJSONResponse, tags=["Dataset"]) +async def patch_dataset(*, dataset: str = Depends(dataset_dependency)): + """ + Partially update a dataset + """ + pass + + +@router.delete("/{dataset}", response_class=ORJSONResponse, tags=["Dataset"]) +async def delete_dataset(*, dataset: str = Depends(dataset_dependency)): + """ + Delete a dataset + """ + pass diff --git a/app/routes/features.py b/app/routes/features.py new file mode 100644 index 000000000..701adcdc4 --- /dev/null +++ b/app/routes/features.py @@ -0,0 +1,42 @@ +from fastapi import APIRouter, Path, Query, Depends +from fastapi.responses import ORJSONResponse + +from app.routes import dataset_dependency, version_dependency + +router = APIRouter() +VERSION_REGEX = r"^v\d{1,8}\.?\d{1,3}\.?\d{1,3}$|^latest$" + + +@router.get( + "/{dataset}/{version}/features", response_class=ORJSONResponse, tags=["Features"], +) +async def features( + *, + dataset: str = Depends(dataset_dependency), + version: str = Depends(version_dependency), + lat: float = Query(None, title="Latitude", ge=-90, le=90), + lng: float = Query(None, title="Longitude", ge=-180, le=180), + z: int = Query(None, title="Zoom level", ge=0, le=22) +): + """ + Retrieve list of features + Add optional spatial filter using a point buffer (for info tool). + """ + pass + + +@router.get( + "/{dataset}/{version}/feature/{feature_id}", + response_class=ORJSONResponse, + tags=["Features"], +) +async def get_feature( + *, + dataset: str = Depends(dataset_dependency), + version: str = Depends(version_dependency), + feature_id: int = Path(..., title="Feature ID", ge=0) +): + """ + Retrieve attribute values for a given feature + """ + pass diff --git a/app/routes/fields.py b/app/routes/fields.py new file mode 100644 index 000000000..f547bc59e --- /dev/null +++ b/app/routes/fields.py @@ -0,0 +1,20 @@ +from fastapi import APIRouter, Depends +from fastapi.responses import ORJSONResponse + +from app.routes import dataset_dependency, version_dependency + +router = APIRouter() + + +@router.get( + "/{dataset}/{version}/fields", response_class=ORJSONResponse, tags=["Features"], +) +async def get_fields( + *, + dataset: str = Depends(dataset_dependency), + version: str = Depends(version_dependency) +): + """ + Get fields (attribute names and types) for a given dataset version + """ + pass diff --git a/app/routes/geostore.py b/app/routes/geostore.py new file mode 100644 index 000000000..b397f4d7e --- /dev/null +++ b/app/routes/geostore.py @@ -0,0 +1,45 @@ +from fastapi import APIRouter, Path, Depends +from fastapi.responses import ORJSONResponse + +from app.routes import dataset_dependency, version_dependency + + +router = APIRouter() + + +@router.post( + "/geostore", response_class=ORJSONResponse, tags=["Geostore"], +) +async def post_geostore(): + """ + Add geostore feature to User geostore + """ + pass + + +@router.get( + "/geostore/{geostore_id}", response_class=ORJSONResponse, tags=["Geostore"], +) +async def get_geostore(*, geostore_id: str = Path(..., title="geostore_id")): + """ + Retrieve GeoJSON representation for a given geostore ID of any dataset + """ + pass + + +@router.get( + "/{dataset}/{version}/geostore/{geostore_id}", + response_class=ORJSONResponse, + tags=["Geostore"], +) +async def get_dataset_geostore( + *, + dataset: str = Depends(dataset_dependency), + version: str = Depends(version_dependency), + geostore_id: str = Path(..., title="geostore_id") +): + """ + Retrieve GeoJSON representation for a given geostore ID of a dataset version. + Obtain geostore ID from feature attributes. + """ + pass diff --git a/app/routes/query.py b/app/routes/query.py new file mode 100644 index 000000000..a8ea87a9f --- /dev/null +++ b/app/routes/query.py @@ -0,0 +1,22 @@ +from uuid import UUID + +from fastapi import APIRouter, Query, Depends +from fastapi.responses import ORJSONResponse + +from app.routes import dataset_dependency, version_dependency + +router = APIRouter() + + +@router.get("/{dataset}/{version}/query", response_class=ORJSONResponse, tags=["Query"]) +async def get_query( + *, + dataset: str = Depends(dataset_dependency), + version: str = Depends(version_dependency), + sql: str = Query(None, title="SQL query"), + geostore_id: UUID = Query(None, title="Geostore ID") +): + """ + Execute a read ONLY SQL query on the given dataset version (if implemented) + """ + pass diff --git a/app/routes/sources.py b/app/routes/sources.py new file mode 100644 index 000000000..ad8224441 --- /dev/null +++ b/app/routes/sources.py @@ -0,0 +1,62 @@ +from fastapi import APIRouter, Depends +from fastapi.responses import ORJSONResponse + +from app.routes import dataset_dependency, version_dependency + +router = APIRouter() + + +@router.get( + "/{dataset}/{version}/sources", response_class=ORJSONResponse, tags=["Sources"] +) +async def get_sources( + *, + dataset: str = Depends(dataset_dependency), + version: str = Depends(version_dependency) +): + """ + List all external source files used to seed dataset version + """ + pass + + +@router.post( + "/{dataset}/{version}/sources", response_class=ORJSONResponse, tags=["Sources"] +) +async def post_sources( + *, + dataset: str = Depends(dataset_dependency), + version: str = Depends(version_dependency) +): + """ + Add (appends) a new source to the dataset version + """ + pass + + +@router.patch( + "/{dataset}/{version}/sources", response_class=ORJSONResponse, tags=["Sources"] +) +async def patch_sources( + *, + dataset: str = Depends(dataset_dependency), + version: str = Depends(version_dependency) +): + """ + Overwrites existing data with data from new source + """ + pass + + +@router.delete( + "/{dataset}/{version}/sources", response_class=ORJSONResponse, tags=["Sources"] +) +async def delete_sources( + *, + dataset: str = Depends(dataset_dependency), + version: str = Depends(version_dependency) +): + """ + Deletes existing data + """ + pass diff --git a/app/routes/users.py b/app/routes/users.py deleted file mode 100644 index 975cf6174..000000000 --- a/app/routes/users.py +++ /dev/null @@ -1,40 +0,0 @@ -from arq.connections import create_pool, ArqRedis -from fastapi import APIRouter - -from ..models.orm.user import User as ORMUser -from ..models.pydantic.user import User, UserCreateIn, UserUpdateIn -from ..settings.arq import settings as redis_settings - -router = APIRouter() - - -@router.post("/users", tags=["Users"], response_model=User) -async def create_user(request: UserCreateIn): - new_user: ORMUser = await ORMUser.create(**request.dict()) - redis: ArqRedis = await create_pool(settings=redis_settings) - await redis.enqueue_job( - "send_message", - new_user.id, - "Congratulations! Your account has been created!", - ) - return User.from_orm(new_user) - - -@router.get("/users/{id}", tags=["Users"], response_model=User) -async def retrieve_user(id: int): - user: ORMUser = await ORMUser.get(id) - return User.from_orm(user) - - -@router.put("/users/{id}", tags=["Users"], response_model=User) -async def update_user(request: UserUpdateIn, id: int): - user: ORMUser = await ORMUser.get(id) - updated_fields: User = User.from_orm(request) - await user.update(**updated_fields.dict(skip_defaults=True)).apply() - return User.from_orm(user) - - -@router.delete("/users/{id}", tags=["Users"], response_model=User) -async def delete_user(id: int): - user: ORMUser = await ORMUser.get(id) - return await user.delete() diff --git a/app/routes/versions.py b/app/routes/versions.py new file mode 100644 index 000000000..af6e109d4 --- /dev/null +++ b/app/routes/versions.py @@ -0,0 +1,55 @@ +from fastapi import APIRouter, Depends +from fastapi.responses import ORJSONResponse + +from app.routes import dataset_dependency, version_dependency + + +router = APIRouter() + + +@router.get("/{dataset}/{version}", response_class=ORJSONResponse, tags=["Dataset"]) +async def get_version( + *, + dataset: str = Depends(dataset_dependency), + version: str = Depends(version_dependency) +): + """ + Get basic metadata for a given version + """ + pass + + +@router.put("/{dataset}/{version}", response_class=ORJSONResponse, tags=["Dataset"]) +async def put_version( + *, + dataset: str = Depends(dataset_dependency), + version: str = Depends(version_dependency) +): + """ + Create or update a version for a given dataset + """ + pass + + +@router.patch("/{dataset}/{version}", response_class=ORJSONResponse, tags=["Dataset"]) +async def patch_version( + *, + dataset: str = Depends(dataset_dependency), + version: str = Depends(version_dependency) +): + """ + Partially update a version of a given dataset + """ + pass + + +@router.delete("/{dataset}/{version}", response_class=ORJSONResponse, tags=["Dataset"]) +async def delete_version( + *, + dataset: str = Depends(dataset_dependency), + version: str = Depends(version_dependency) +): + """ + Delete a version + """ + pass diff --git a/app/settings/arq.py b/app/settings/arq.py deleted file mode 100644 index 8e36911e0..000000000 --- a/app/settings/arq.py +++ /dev/null @@ -1,5 +0,0 @@ -from arq.connections import RedisSettings - -from .globals import REDIS_IP, REDIS_PORT - -settings = RedisSettings(host=REDIS_IP, port=REDIS_PORT) diff --git a/app/settings/globals.py b/app/settings/globals.py index 264572be8..84551db05 100644 --- a/app/settings/globals.py +++ b/app/settings/globals.py @@ -2,7 +2,7 @@ from typing import Optional from starlette.config import Config -from starlette.datastructures import Secret, CommaSeparatedStrings +from starlette.datastructures import Secret from ..models.pydantic.database import DatabaseURL @@ -32,12 +32,3 @@ port=DB_PORT, database=DATABASE, ) - -REDIS_IP: str = config("REDIS_IP", cast=str, default="127.0.0.1") -REDIS_PORT: int = config("REDIS_PORT", cast=int, default=6379) - -SENTRY_DSN: Optional[Secret] = config("SENTRY_DSN", cast=Secret, default=None) - -ARQ_BACKGROUND_FUNCTIONS: Optional[CommaSeparatedStrings] = config( - "ARQ_BACKGROUND_FUNCTIONS", cast=CommaSeparatedStrings, default=None -) diff --git a/app/tasks/messaging.py b/app/tasks/messaging.py index 3067cb854..9e8205b0b 100644 --- a/app/tasks/messaging.py +++ b/app/tasks/messaging.py @@ -1,6 +1,6 @@ from ..application import db from ..models.pydantic.user import User -from ..models.orm.user import User as ORMUser +from ..models.orm.metadata import User as ORMUser async def send_message(ctx: dict, user_id: int, message: str): diff --git a/app/worker.py b/app/worker.py index 936588d54..b8ebd552e 100644 --- a/app/worker.py +++ b/app/worker.py @@ -1,14 +1,5 @@ -from pydantic.utils import import_string - from .application import db -from .settings.arq import settings -from .settings.globals import DATABASE_CONFIG, ARQ_BACKGROUND_FUNCTIONS - - -FUNCTIONS: list = [ - import_string(background_function) - for background_function in list(ARQ_BACKGROUND_FUNCTIONS) -] if ARQ_BACKGROUND_FUNCTIONS is not None else list() +from .settings.globals import DATABASE_CONFIG async def startup(ctx): @@ -32,5 +23,4 @@ class WorkerSettings: on_startup = startup on_shutdown = shutdown - redis_settings = settings - functions: list = FUNCTIONS +