diff --git a/poetry.lock b/poetry.lock index 81ad6ea..8022d7e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,3 +1,21 @@ +[[package]] +category = "main" +description = "Async http client/server framework (asyncio)" +name = "aiohttp" +optional = false +python-versions = ">=3.5.3" +version = "3.6.2" + +[package.dependencies] +async-timeout = ">=3.0,<4.0" +attrs = ">=17.3.0" +chardet = ">=2.0,<4.0" +multidict = ">=4.5,<5.0" +yarl = ">=1.0,<2.0" + +[package.extras] +speedups = ["aiodns", "brotlipy", "cchardet"] + [[package]] category = "dev" description = "A configurable sidebar-enabled Sphinx theme" @@ -6,6 +24,25 @@ optional = false python-versions = "*" version = "0.7.12" +[[package]] +category = "main" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +name = "anyio" +optional = false +python-versions = ">=3.5.3" +version = "1.4.0" + +[package.dependencies] +async-generator = "*" +idna = ">=2.8" +sniffio = ">=1.1" + +[package.extras] +curio = ["curio (>=0.9)"] +doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] +test = ["coverage (>=4.5)", "hypothesis (>=4.0)", "pytest (>=3.7.2)", "uvloop"] +trio = ["trio (>=0.12)"] + [[package]] category = "dev" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." @@ -15,7 +52,36 @@ python-versions = "*" version = "1.4.4" [[package]] -category = "dev" +category = "main" +description = "asks - async http" +name = "asks" +optional = false +python-versions = "*" +version = "2.4.8" + +[package.dependencies] +anyio = "<2" +async_generator = "*" +h11 = "*" + +[[package]] +category = "main" +description = "Async generators and context managers for Python 3.5+" +name = "async-generator" +optional = false +python-versions = ">=3.5" +version = "1.10" + +[[package]] +category = "main" +description = "Timeout context manager for asyncio programs" +name = "async-timeout" +optional = false +python-versions = ">=3.5.3" +version = "3.0.1" + +[[package]] +category = "main" description = "Classes Without Boilerplate" name = "attrs" optional = false @@ -50,9 +116,9 @@ version = "1.6.2" [package.dependencies] GitPython = ">=1.0.1" PyYAML = ">=3.13" +colorama = ">=0.3.9" six = ">=1.10.0" stevedore = ">=1.20.0" -colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} [[package]] category = "dev" @@ -101,6 +167,7 @@ version = "7.1.2" [[package]] category = "dev" description = "Cross-platform colored terminal text." +marker = "platform_system == \"Windows\" or sys_platform == \"win32\"" name = "colorama" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -206,6 +273,7 @@ version = "0.18.1" [package.dependencies] pycodestyle = "*" +setuptools = "*" [[package]] category = "dev" @@ -259,6 +327,14 @@ version = "3.1.7" [package.dependencies] gitdb = ">=4.0.1,<5" +[[package]] +category = "main" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +name = "h11" +optional = false +python-versions = "*" +version = "0.9.0" + [[package]] category = "main" description = "Internationalized Domain Names in Applications (IDNA)" @@ -313,6 +389,14 @@ optional = false python-versions = "*" version = "0.6.1" +[[package]] +category = "main" +description = "multidict implementation" +name = "multidict" +optional = false +python-versions = ">=3.5" +version = "4.7.6" + [[package]] category = "dev" description = "Core utilities for Python packages" @@ -442,6 +526,14 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "3.0.4" +[[package]] +category = "main" +description = "Sniff out which async library your code is running under" +name = "sniffio" +optional = false +python-versions = ">=3.5" +version = "1.1.0" + [[package]] category = "dev" description = "This package provides 26 stemmers for 25 languages generated from Snowball algorithms." @@ -463,10 +555,12 @@ Jinja2 = ">=2.3" Pygments = ">=2.0" alabaster = ">=0.7,<0.8" babel = ">=1.3" +colorama = ">=0.3.5" docutils = ">=0.12" imagesize = "*" packaging = "*" requests = ">=2.5.0" +setuptools = "*" snowballstemmer = ">=1.1" sphinxcontrib-applehelp = "*" sphinxcontrib-devhelp = "*" @@ -474,7 +568,6 @@ sphinxcontrib-htmlhelp = "*" sphinxcontrib-jsmath = "*" sphinxcontrib-qthelp = "*" sphinxcontrib-serializinghtml = "*" -colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""} [package.extras] docs = ["sphinxcontrib-websupport"] @@ -641,19 +734,60 @@ version = "1.0.1" dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"] watchdog = ["watchdog"] +[[package]] +category = "main" +description = "Yet another URL library" +name = "yarl" +optional = false +python-versions = ">=3.5" +version = "1.5.1" + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" + [metadata] -content-hash = "7388d8240a2817695e502fb845922da8df699d77d143693ffe3285eca1df3495" +content-hash = "e4e37adaadf6628a7aeac64abcb6c944266a6565fe108ff29eb72e816edf6f33" python-versions = "^3.8" [metadata.files] +aiohttp = [ + {file = "aiohttp-3.6.2-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:1e984191d1ec186881ffaed4581092ba04f7c61582a177b187d3a2f07ed9719e"}, + {file = "aiohttp-3.6.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:50aaad128e6ac62e7bf7bd1f0c0a24bc968a0c0590a726d5a955af193544bcec"}, + {file = "aiohttp-3.6.2-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:65f31b622af739a802ca6fd1a3076fd0ae523f8485c52924a89561ba10c49b48"}, + {file = "aiohttp-3.6.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ae55bac364c405caa23a4f2d6cfecc6a0daada500274ffca4a9230e7129eac59"}, + {file = "aiohttp-3.6.2-cp36-cp36m-win32.whl", hash = "sha256:344c780466b73095a72c616fac5ea9c4665add7fc129f285fbdbca3cccf4612a"}, + {file = "aiohttp-3.6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:4c6efd824d44ae697814a2a85604d8e992b875462c6655da161ff18fd4f29f17"}, + {file = "aiohttp-3.6.2-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:2f4d1a4fdce595c947162333353d4a44952a724fba9ca3205a3df99a33d1307a"}, + {file = "aiohttp-3.6.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6206a135d072f88da3e71cc501c59d5abffa9d0bb43269a6dcd28d66bfafdbdd"}, + {file = "aiohttp-3.6.2-cp37-cp37m-win32.whl", hash = "sha256:b778ce0c909a2653741cb4b1ac7015b5c130ab9c897611df43ae6a58523cb965"}, + {file = "aiohttp-3.6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:32e5f3b7e511aa850829fbe5aa32eb455e5534eaa4b1ce93231d00e2f76e5654"}, + {file = "aiohttp-3.6.2-py3-none-any.whl", hash = "sha256:460bd4237d2dbecc3b5ed57e122992f60188afe46e7319116da5eb8a9dfedba4"}, + {file = "aiohttp-3.6.2.tar.gz", hash = "sha256:259ab809ff0727d0e834ac5e8a283dc5e3e0ecc30c4d80b3cd17a4139ce1f326"}, +] alabaster = [ {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, ] +anyio = [ + {file = "anyio-1.4.0-py3-none-any.whl", hash = "sha256:9ee67e8131853f42957e214d4531cee6f2b66dda164a298d9686a768b7161a4f"}, + {file = "anyio-1.4.0.tar.gz", hash = "sha256:95f60964fc4583f3f226f8dc275dfb02aefe7b39b85a999c6d14f4ec5323c1d8"}, +] appdirs = [ {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] +asks = [ + {file = "asks-2.4.8.tar.gz", hash = "sha256:dcf3b0e80b185430cac1e563a97b2630062893adbb73655d5e8600c83ab63342"}, +] +async-generator = [ + {file = "async_generator-1.10-py3-none-any.whl", hash = "sha256:01c7bf666359b4967d2cda0000cc2e4af16a0ae098cbffcb8472fb9e8ad6585b"}, + {file = "async_generator-1.10.tar.gz", hash = "sha256:6ebb3d106c12920aaae42ccb6f787ef5eefdcdd166ea3d628fa8476abe712144"}, +] +async-timeout = [ + {file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"}, + {file = "async_timeout-3.0.1-py3-none-any.whl", hash = "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"}, +] attrs = [ {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, @@ -736,6 +870,10 @@ gitpython = [ {file = "GitPython-3.1.7-py3-none-any.whl", hash = "sha256:fa3b92da728a457dd75d62bb5f3eb2816d99a7fe6c67398e260637a40e3fafb5"}, {file = "GitPython-3.1.7.tar.gz", hash = "sha256:2db287d71a284e22e5c2846042d0602465c7434d910406990d5b74df4afb0858"}, ] +h11 = [ + {file = "h11-0.9.0-py2.py3-none-any.whl", hash = "sha256:4bc6d6a1238b7615b266ada57e0618568066f57dd6fa967d1290ec9309b2f2f1"}, + {file = "h11-0.9.0.tar.gz", hash = "sha256:33d4bca7be0fa039f4e84d50ab00531047e53d6ee8ffbc83501ea602c169cae1"}, +] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, @@ -791,6 +929,25 @@ mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] +multidict = [ + {file = "multidict-4.7.6-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:275ca32383bc5d1894b6975bb4ca6a7ff16ab76fa622967625baeebcf8079000"}, + {file = "multidict-4.7.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1ece5a3369835c20ed57adadc663400b5525904e53bae59ec854a5d36b39b21a"}, + {file = "multidict-4.7.6-cp35-cp35m-win32.whl", hash = "sha256:5141c13374e6b25fe6bf092052ab55c0c03d21bd66c94a0e3ae371d3e4d865a5"}, + {file = "multidict-4.7.6-cp35-cp35m-win_amd64.whl", hash = "sha256:9456e90649005ad40558f4cf51dbb842e32807df75146c6d940b6f5abb4a78f3"}, + {file = "multidict-4.7.6-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:e0d072ae0f2a179c375f67e3da300b47e1a83293c554450b29c900e50afaae87"}, + {file = "multidict-4.7.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3750f2205b800aac4bb03b5ae48025a64e474d2c6cc79547988ba1d4122a09e2"}, + {file = "multidict-4.7.6-cp36-cp36m-win32.whl", hash = "sha256:f07acae137b71af3bb548bd8da720956a3bc9f9a0b87733e0899226a2317aeb7"}, + {file = "multidict-4.7.6-cp36-cp36m-win_amd64.whl", hash = "sha256:6513728873f4326999429a8b00fc7ceddb2509b01d5fd3f3be7881a257b8d463"}, + {file = "multidict-4.7.6-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:feed85993dbdb1dbc29102f50bca65bdc68f2c0c8d352468c25b54874f23c39d"}, + {file = "multidict-4.7.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fcfbb44c59af3f8ea984de67ec7c306f618a3ec771c2843804069917a8f2e255"}, + {file = "multidict-4.7.6-cp37-cp37m-win32.whl", hash = "sha256:4538273208e7294b2659b1602490f4ed3ab1c8cf9dbdd817e0e9db8e64be2507"}, + {file = "multidict-4.7.6-cp37-cp37m-win_amd64.whl", hash = "sha256:d14842362ed4cf63751648e7672f7174c9818459d169231d03c56e84daf90b7c"}, + {file = "multidict-4.7.6-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:c026fe9a05130e44157b98fea3ab12969e5b60691a276150db9eda71710cd10b"}, + {file = "multidict-4.7.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:51a4d210404ac61d32dada00a50ea7ba412e6ea945bbe992e4d7a595276d2ec7"}, + {file = "multidict-4.7.6-cp38-cp38-win32.whl", hash = "sha256:5cf311a0f5ef80fe73e4f4c0f0998ec08f954a6ec72b746f3c179e37de1d210d"}, + {file = "multidict-4.7.6-cp38-cp38-win_amd64.whl", hash = "sha256:7388d2ef3c55a8ba80da62ecfafa06a1c097c18032a501ffd4cabbc52d7f2b19"}, + {file = "multidict-4.7.6.tar.gz", hash = "sha256:fbb77a75e529021e7c4a8d4e823d88ef4d23674a202be4f5addffc72cbb91430"}, +] packaging = [ {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"}, @@ -875,6 +1032,10 @@ smmap = [ {file = "smmap-3.0.4-py2.py3-none-any.whl", hash = "sha256:54c44c197c819d5ef1991799a7e30b662d1e520f2ac75c9efbeb54a742214cf4"}, {file = "smmap-3.0.4.tar.gz", hash = "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"}, ] +sniffio = [ + {file = "sniffio-1.1.0-py3-none-any.whl", hash = "sha256:20ed6d5b46f8ae136d00b9dcb807615d83ed82ceea6b2058cecb696765246da5"}, + {file = "sniffio-1.1.0.tar.gz", hash = "sha256:8e3810100f69fe0edd463d02ad407112542a11ffdc29f67db2bf3771afb87a21"}, +] snowballstemmer = [ {file = "snowballstemmer-2.0.0-py2.py3-none-any.whl", hash = "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0"}, {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, @@ -959,3 +1120,22 @@ werkzeug = [ {file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"}, {file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"}, ] +yarl = [ + {file = "yarl-1.5.1-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:db6db0f45d2c63ddb1a9d18d1b9b22f308e52c83638c26b422d520a815c4b3fb"}, + {file = "yarl-1.5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:17668ec6722b1b7a3a05cc0167659f6c95b436d25a36c2d52db0eca7d3f72593"}, + {file = "yarl-1.5.1-cp35-cp35m-win32.whl", hash = "sha256:040b237f58ff7d800e6e0fd89c8439b841f777dd99b4a9cca04d6935564b9409"}, + {file = "yarl-1.5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:f18d68f2be6bf0e89f1521af2b1bb46e66ab0018faafa81d70f358153170a317"}, + {file = "yarl-1.5.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:c52ce2883dc193824989a9b97a76ca86ecd1fa7955b14f87bf367a61b6232511"}, + {file = "yarl-1.5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ce584af5de8830d8701b8979b18fcf450cef9a382b1a3c8ef189bedc408faf1e"}, + {file = "yarl-1.5.1-cp36-cp36m-win32.whl", hash = "sha256:df89642981b94e7db5596818499c4b2219028f2a528c9c37cc1de45bf2fd3a3f"}, + {file = "yarl-1.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:3a584b28086bc93c888a6c2aa5c92ed1ae20932f078c46509a66dce9ea5533f2"}, + {file = "yarl-1.5.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:da456eeec17fa8aa4594d9a9f27c0b1060b6a75f2419fe0c00609587b2695f4a"}, + {file = "yarl-1.5.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bc2f976c0e918659f723401c4f834deb8a8e7798a71be4382e024bcc3f7e23a8"}, + {file = "yarl-1.5.1-cp37-cp37m-win32.whl", hash = "sha256:4439be27e4eee76c7632c2427ca5e73703151b22cae23e64adb243a9c2f565d8"}, + {file = "yarl-1.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:48e918b05850fffb070a496d2b5f97fc31d15d94ca33d3d08a4f86e26d4e7c5d"}, + {file = "yarl-1.5.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:9b930776c0ae0c691776f4d2891ebc5362af86f152dd0da463a6614074cb1b02"}, + {file = "yarl-1.5.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b3b9ad80f8b68519cc3372a6ca85ae02cc5a8807723ac366b53c0f089db19e4a"}, + {file = "yarl-1.5.1-cp38-cp38-win32.whl", hash = "sha256:f379b7f83f23fe12823085cd6b906edc49df969eb99757f58ff382349a3303c6"}, + {file = "yarl-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:9102b59e8337f9874638fcfc9ac3734a0cfadb100e47d55c20d0dc6087fb4692"}, + {file = "yarl-1.5.1.tar.gz", hash = "sha256:c22c75b5f394f3d47105045ea551e08a3e804dc7e01b37800ca35b58f856c3d6"}, +] diff --git a/pyproject.toml b/pyproject.toml index 0d27088..6aeb8da 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,9 @@ python = "^3.8" requests = "^2.24.0" typing_extensions = "^3.7.4" flask = "^1.1.2" +werkzeug = "^1.0.1" +asks = "^2.4.8" +aiohttp = "^3.6.2" [tool.poetry.dev-dependencies] flake8 = "^3.8.3" diff --git a/src/replit/database/__init__.py b/src/replit/database/__init__.py index 6f7bea0..e64393c 100644 --- a/src/replit/database/__init__.py +++ b/src/replit/database/__init__.py @@ -1,11 +1,17 @@ """Interface with the Replit Database.""" import json +import aiohttp import os from sys import stderr from typing import Any, Callable, Dict, Tuple, Union -import requests +from . import _async +import asyncio + +asyncio.run = _async.run + +import requests JSON_TYPE = Union[str, int, float, bool, type(None), dict, list] @@ -20,12 +26,11 @@ class JSONKey: __slots__ = ("db", "key", "dtype", "get_default", "discard_bad_data") def __init__( - self, - db: Any, - key: str, - dtype: JSON_TYPE, - get_default: Callable = None, - discard_bad_data: bool = False, + self, + key: str, + dtype: JSON_TYPE, + get_default: Callable = None, + discard_bad_data: bool = False, ) -> None: """Initialize the key. @@ -53,10 +58,8 @@ class JSONKey: return self.dtype is Any or isinstance(data, self.dtype) def _type_mismatch_msg(self, data: Any) -> str: - return ( - f"Type mismatch: Got type {type(data).__name__}," - "expected {self.dtype.__name__}" - ) + return (f"Type mismatch: Got type {type(data).__name__}," + "expected {self.dtype.__name__}") def get(self) -> JSON_TYPE: """Get the value of the key. @@ -70,7 +73,9 @@ class JSONKey: try: read = self.db[self.key] except KeyError: - print(f"Database key {self.key} not set, setting it to default value") + print( + f"Database key {self.key} not set, setting it to default value" + ) default = self._default() self.db[self.key] = default return default @@ -81,7 +86,10 @@ class JSONKey: return self._error("Invalid JSON data read", read) if not self._is_valid_type(data): - return self._error(self._type_mismatch_msg(data), read,) + return self._error( + self._type_mismatch_msg(data), + read, + ) return data def _error(self, error: str, read: str) -> JSON_TYPE: @@ -97,8 +105,7 @@ class JSONKey: while True: choice = input( "d to use default, v to view the invalid data, c to insert custom " - "value, ^C to exit: " - ) + "value, ^C to exit: ") if choice.startswith("d"): print("Writing default...") val = self._default() @@ -109,8 +116,7 @@ class JSONKey: elif choice.startswith("c"): toset = input( f"Enter data to write, should be of type {self.dtype.__name__!r}" - " (leave blank to return to menu): " - ) + " (leave blank to return to menu): ") if not toset: continue try: @@ -152,7 +158,7 @@ class ReplitDb(dict): db_url (str): Database url to use. """ self.db_url = db_url - self.sess = requests.Session() + self.sess = _AsyncBackend(db_url) def __getitem__(self, key: str) -> str: """Get the value of an item from the database. @@ -166,12 +172,8 @@ class ReplitDb(dict): Returns: str: The value of the key """ - r = self.sess.get(f"{self.db_url}/{key}") - if r.status_code == 404: - raise KeyError(key) - - r.raise_for_status() - return r.text + r = asyncio.run(self.sess.view(key)) + return r def __setitem__(self, key: str, value: str) -> None: """Set a key in the database to value. @@ -180,8 +182,7 @@ class ReplitDb(dict): key (str): The key to set value (str): The value to set it to """ - r = self.sess.post(self.db_url, data={key: value}) - r.raise_for_status() + asyncio.run(self.sess.set(key, value)) def __delitem__(self, key: str) -> None: """Delete a key from the database. @@ -189,8 +190,7 @@ class ReplitDb(dict): Args: key (str): The key to delete """ - r = self.sess.delete(f"{self.db_url}/{key}") - r.raise_for_status() + asyncio.run(self.sess.delete(key)) def keys(self, prefix: str = "") -> Tuple[str]: """Return all of the keys in the database. @@ -202,13 +202,7 @@ class ReplitDb(dict): Returns: Tuple[str]: The keys found. """ - r = requests.get(f"{self.db_url}", params={"prefix": prefix}) - r.raise_for_status() - - if not r.text: - return tuple() - else: - return tuple(r.text.split("\n")) + return asyncio.run(self.sess.list(prefix)) def to_dict(self, prefix: str = "") -> Dict[str, str]: """Dump all data in the database into a dictionary. @@ -239,11 +233,11 @@ class ReplitDb(dict): return self.to_dict().items() def jsonkey( - self, - key: str, - dtype: JSON_TYPE, - get_default: Callable = None, - discard_bad_data: bool = False, + self, + key: str, + dtype: JSON_TYPE, + get_default: Callable = None, + discard_bad_data: bool = False, ) -> JSONKey: """Initialize a JSONKey instance. @@ -279,6 +273,46 @@ class ReplitDb(dict): return f"" +class AsyncClient(): + def __init__(self, db_url): + self.db_url = db_url + + +class _AsyncBackend(): + def __init__(self, db_url): + self.db_url = db_url + + async def set(self, key, val): + async with aiohttp.ClientSession() as session: + async with session.post(self.db_url, data={key: val}) as response: + response.raise_for_status() + return await response.text() + + async def view(self, key): + async with aiohttp.ClientSession() as session: + async with session.get(self.db_url + "/" + key) as response: + if response.status == 404: + raise KeyError(key) + response.raise_for_status() + return await response.text() + + async def delete(self, key): + async with aiohttp.ClientSession() as session: + async with session.delete(self.db_url + "/" + key) as response: + response.raise_for_status() + return await response.text() + + async def list(self, prefix): + async with aiohttp.ClientSession() as session: + async with session.get(self.db_url + "?prefix=" + + prefix) as response: + response.raise_for_status() + if not await response.text(): + return tuple() + else: + return tuple((await response.text()).split("\n")) + + db_url = os.environ.get("REPLIT_DB_URL") if db_url: db = ReplitDb(db_url) diff --git a/src/replit/database/_async.py b/src/replit/database/_async.py new file mode 100644 index 0000000..eafc32c --- /dev/null +++ b/src/replit/database/_async.py @@ -0,0 +1,44 @@ +import threading +import asyncio +import sys +asyncio._run = asyncio.run + + +class AsyncThread(threading.Thread): + def __init__(self, res, exc, func): + self.result = res + self.exc = exc + self.func = func + threading.Thread.__init__(self) + + def run(self): + def inner(func): + try: + res = asyncio.run(func) + except Exception as e: + self.exc[0] = sys.exc_info() + res = '' + return res + + self.result[0] = inner(self.func) + + +def run(func): + def error(): + ret = [None] + exc = [None] + thread = AsyncThread(ret, exc, func) + thread.start() + thread.join() + exc = exc[0] + if exc != None: + raise exc[1].with_traceback(exc[2]) + sys.exit(1) + return ret[0] + + try: + return asyncio._run(func) + except RuntimeError: + return error() + except RuntimeWarning: + return error()