From 81f00caa7ea2bb94ee3149ad08755d32ba44d86d Mon Sep 17 00:00:00 2001 From: retoor Date: Mon, 2 Dec 2024 17:41:02 +0100 Subject: [PATCH] Initial commit. --- .gitea/workflows/build.yaml | 16 ++ .gitignore | 4 + Makefile | 30 ++++ README.md | 31 ++++ dist/Retoorded-1.3.37-py3-none-any.whl | Bin 0 -> 1665 bytes dist/devranta-1.0.0-py3-none-any.whl | Bin 0 -> 3585 bytes dist/devranta-1.0.0.tar.gz | Bin 0 -> 2832 bytes dist/retoorded-1.3.37.tar.gz | Bin 0 -> 1261 bytes pyproject.toml | 3 + setup.cfg | 25 +++ src/Retoorded.egg-info/PKG-INFO | 12 ++ src/Retoorded.egg-info/SOURCES.txt | 10 ++ src/Retoorded.egg-info/dependency_links.txt | 1 + src/Retoorded.egg-info/entry_points.txt | 2 + src/Retoorded.egg-info/requires.txt | 3 + src/Retoorded.egg-info/top_level.txt | 1 + src/devranta.egg-info/PKG-INFO | 12 ++ src/devranta.egg-info/SOURCES.txt | 12 ++ src/devranta.egg-info/dependency_links.txt | 1 + src/devranta.egg-info/entry_points.txt | 2 + src/devranta.egg-info/requires.txt | 3 + src/devranta.egg-info/top_level.txt | 1 + src/devranta/__init__.py | 0 src/devranta/__main__.py | 21 +++ src/devranta/api.py | 167 ++++++++++++++++++++ src/devranta/tests.py | 31 ++++ 26 files changed, 388 insertions(+) create mode 100644 .gitea/workflows/build.yaml create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 dist/Retoorded-1.3.37-py3-none-any.whl create mode 100644 dist/devranta-1.0.0-py3-none-any.whl create mode 100644 dist/devranta-1.0.0.tar.gz create mode 100644 dist/retoorded-1.3.37.tar.gz create mode 100644 pyproject.toml create mode 100644 setup.cfg create mode 100644 src/Retoorded.egg-info/PKG-INFO create mode 100644 src/Retoorded.egg-info/SOURCES.txt create mode 100644 src/Retoorded.egg-info/dependency_links.txt create mode 100644 src/Retoorded.egg-info/entry_points.txt create mode 100644 src/Retoorded.egg-info/requires.txt create mode 100644 src/Retoorded.egg-info/top_level.txt create mode 100644 src/devranta.egg-info/PKG-INFO create mode 100644 src/devranta.egg-info/SOURCES.txt create mode 100644 src/devranta.egg-info/dependency_links.txt create mode 100644 src/devranta.egg-info/entry_points.txt create mode 100644 src/devranta.egg-info/requires.txt create mode 100644 src/devranta.egg-info/top_level.txt create mode 100644 src/devranta/__init__.py create mode 100644 src/devranta/__main__.py create mode 100644 src/devranta/api.py create mode 100644 src/devranta/tests.py diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml new file mode 100644 index 0000000..88bede9 --- /dev/null +++ b/.gitea/workflows/build.yaml @@ -0,0 +1,16 @@ +name: devranta build +run-name: devranta async devRant api client build and test +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v4 + - name: List files in the repository + run: | + ls ${{ gitea.workspace }} + - run: make build + - run: make run + - run: make test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c44fc3a --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.venv +.history +__pycache__ +*.pyc diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..24d33c9 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +PYTHON=./.venv/bin/python +PIP=./.venv/bin/pip +BIN=./.venv/bin + +all: format install build run test + +ensure_env: + -@python3 -m venv .venv + +install: ensure_env + $(PIP) install -e . + +build: ensure_env + $(PIP) install build + $(PYTHON) -m build . + +format: ensure_env + $(PIP) install shed + $(BIN)/shed src/devranta/*.py + +test: ensure_env + $(PYTHON) -m unittest devranta.tests + +run: ensure_env + $(BIN)/devranta + + + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..1a885be --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# devRanta + +## About +devRanta is an async devrant client written in and for Python. +Authentication is only needed for half of the functionality and thus username and password are optional parameters by constructing the main class of this package (Api). + +## Running +``` +make run +``` + +## Testing +Tests are only made for methods not requireing authentication. +I do not see value in mocking requests. +``` +make test +``` + +## How to use +Implementation: +``` +from devranta.api import Api + +api = Api(username="optional!", password="optional!") + +async def list_rants(): + async for rant in api.get_rants(): + print(rant["user_username"], ":", rant["text"]) +``` +See [tests](src/devranta/tests.py) for [examples](src/devranta/tests.py) on how to use. + diff --git a/dist/Retoorded-1.3.37-py3-none-any.whl b/dist/Retoorded-1.3.37-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..0db55fc5ed018e7a94b15928d4fe54ab9a8bd401 GIT binary patch literal 1665 zcmWIWW@Zs#U|`^2SX0py31l!Zfe0V~iKe8M6(#1CB26rKbm2{rHvxAp{1xDJxpGP4Qn}RgFQHzO zou++mGyiXF+bq*~M*aCC)os5n>RoAL+Fq5=k#gMc?lkV(H_}$xEfdfa%3z?T5iCnApMm665Pj4IZ&y81qitl5QJZgB(tZ&t4>%OIF-}0kPKO}yd*vh{Yq5zZ3)tR*OuxUG1V(2th(s28VCmjAhaecyvgWixgxxKsRT6Z<9G zeKv~?uJ9v*4HN|P87CFQ0KFa!#0vO>Al$>%)ra+9MoVQc)mtfk~k5B7-x0~>NG2^Z@ zt1NZDYd`a_b%y5sGsi8vXE}AvbE!vlnZdnn-;97RvH)Uj{4Pt)D=DgsFUZf#D=F41 zsVM38J9l3D+eJ~FqEnw0 zG9slVP@wGY+t0=gw2~8uHSk+ql3x&?lUkOV1G3lKQ&-#TjJD?!CNu+o2l&sl0wyvo zV5(NcZ(xwCvwx7w(zBLjO%4nU7w&Cl=*mf+$iyl*L1DJeSsSM2z5@+L5+A>;tno~p z%>5^R(QjRKlljgaoXZ4?{vP3ZUZZ(Ze$k?rarKP5ODAkLFu6Tr>Ka}t+b7r8etG#N zY>wn1ONs4*n`cbjA2d7p6aPu~EwA%bwIb&UTR1-SvI!8IylS>})rzdF75fsFN}b)t zbgnXgs~eBX`D1;vZ+c1`o7FUV{l6r!19N^Xo@3;FVE^LBbJx9(f2Y{}#XVB9rsd&< zlU>ul1RK12!N$EtwdVfzMXzrc@iGe-uHLSr^u_GpzQZkiGPM`37xaibPgmZmaK0ur zCNlccNv@RdZdwsL>y~xy{@%J(@ZO;*6Q7hbzpc8lz&h*Sr}oJfr#`Hzs;ap3hs$hk z&imKr)ofJ`1ap?EeAoJvmmSKwxoY|EU&p?hw$1zt40uK+5oX+F2{81*U`r#2!d9{% zn}Drkf#_#o*wSc%Y685RK{f$fIRi6cNn-|(NkplGZXkNDg&DY|F&mi5@E8cr!|0}= z=QNmUOBz{$=@pM@==l!aVDx;1Ft`D~!6>;3-Bk3<1T%F@<3;?YLb6tXH!B-R3p)@h K0yTKCfOr5$mn(7r literal 0 HcmV?d00001 diff --git a/dist/devranta-1.0.0-py3-none-any.whl b/dist/devranta-1.0.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..decff3223ddd1048b6dcb16585f38cd6d7a0f1db GIT binary patch literal 3585 zcmaKu2{=^iAIE3R$a)PzQFfzboovYx5iw*LTUo}=*q4!UB}*uT?vP2kWKAL4AUmNf zgDfE$CQBwu_N=-8aqqvI+8?a1fXc007Ve3NYbUDHi~$ z{R3s&zw6+5-PhI=Z7YdHqC8P(BvQgV5CkyzTO)KU{3@H}7P6J{tT*r<8V_5P=bsv@ zdwMa=QjC!s=OdRoqMFcFZJ9Ht)gHtnz>~c00c2+14NaJbbTGr@sgPgIC+;Co(ZZHL_PK5oF`0e(6*Vow78_}Z`23Hc~606@(S z06-2}W$TTixYT9d<@sKYxqcBrt5n!m&Xz3?qB3Gz$WfJ85T^xeX1Y6-v%-ytVjMf4 zf6utAot<6IO;fR96a9#@n;;*Ow55hO(n_k_xE9;xgcvY>N|tZ(l24_*iF|4ocxvu+ zENyAtsEjgCf_D2}BEFZ-3vmXc^Xq4GJcO>?T4SlcNAvaHLMIan z#k$Vc%NlK}e{5L}Kf5t2eGX;gU8Dk9SW{+RUJB*Y=r;U3RMn9th3j2NlO2iD6IKaQNf8?x)(RNG6z?oO-BzH&}_U65%WX5-ieO)bd%plYJEW z)_u-!*%{cD>oPAe^Xo_8hc6rRGSJ38MY%MtLHvkcU#0$8V!M-!pERo`i}Ow+yBF1# zNC2&zP!asnRZ!@)D|{6zuQ+kD(O@2l3L&V^8XOGSjNMs(F)o@hJHV!CLL6Ium6vkT zvu*=XbAK|o^8?^$2Yc+^rnOWC|Luw?gd4yv?jv=pxUqI%p}<=@LqAhthlp(X*|rR3 z1G)mi)Hwb%9emtNyDY7a@<|kT>5=cZ~QHlr%4>G(mS|IH&v|KO&b$ijJTuP&o;^RNxwH%?^MO^kIGhIORblvRd7YJ_Zcj4`J6+Lv4K zo1ahc4oUO2!86JOW=P{aUT0z&F}I?Kr2Aj#V2^G*sTw+VcW}L3>SpQj4@3V5WPG{vc3`tfI}0ir6aljZdK)etE>z*5`&~9hhL?>V+Ru zDHYxk$W963YajrC`T|gVzdv7U zL<*|4QXbW>i58XknB?^FkG&A=1Qf%ne4Y)+k#l6_7_nL7RWwRhH4fehdu;TqEJ|TP zzhtLZ$~Ye%Xy+BD8ZreL%0Ql&4az}VDljS+C4IDSZrdwyb&sP#>D4nai5lUs-B6DDRELYZ`g`FG&{5Y1{IHQz-#x@q7PNch;?z!x zccK&@`44y~4wI0g><%bDv^dJs$xBl2lCheGnz5SIJvBH;jWKd@RrDi-Fg&YfZeTf| zW0Ny5p*#C8 zu(pJjnHApgd*r_B4-Jf;uQSY**Vbwo5FtN0kq*RqTT&dbpfsMJIbnAB(j{H$CKx?s zk*9uR_2kVk<5{{4@lC263laVlt4%ymkoqc*?@oQ?*U&SfwF|i^Ph|Q)^pdt|Rs7p5 zPUXwfH}xuInAYSN0_6hzwTKr|niX9{#tE+#Vjo_NNz(}Vaa^&QPkqHHk)Msr z(G%?(i1hYCc~T}n8iS6#(%mE4-J=~Rc}1c_?6gSyw2rp8s189?+ql>y6t+Gw>339m zbz-tmmF?JpGG~8Q)WkO&VW9LyM`^-8>l5wejdXXs?&!YXA^iXNDXK#_tn*oT31xzn zQOYgepW%!ysp}hQ1iw*C%v1${NjE|m=2y5HNmOjc#!0}dzd6v`f;FtqHa8G#Ld1+Kc1sZFtmaz*a&w`AC7}tnX};*hp$?74!^8p2GSn-0@pODwz$oDpdkZ@9hk-dB7^MO8ED zEslNg-3j$9w2OlO9C&-0KC%53S9~!xPRMcQ;tfJREV|Yw=036wU^tCrY7$3{3$aw^ zj(NKZ4rV$j^jftmGp{eSpXSmjbchn9S7-9BZ^k|%q`WK)exea(RNe(Bx zp6b92ddL&uI!ZS`ZwF6yV~c6HM@R#{bWS&xt)5^)j{7M7mUoxy7p@(RfNt`&_Bp-! zIvx*Xx(R@-x=qY&ncQ92noRCny>6&Fz1@ n@elEFn0YugzA^D(u0Lb`l_3Uj>LdFCI?A3%i5>I(I0O6-eTd5K literal 0 HcmV?d00001 diff --git a/dist/devranta-1.0.0.tar.gz b/dist/devranta-1.0.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..58ae5f987740fe36b40fcc5484eab620bcd73aeb GIT binary patch literal 2832 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 XU@#aA27|$1`?Y@n64mSr0C)fZ9s;!= literal 0 HcmV?d00001 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..07de284 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" \ No newline at end of file diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..f2a2726 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,25 @@ +[metadata] +name = devranta +version = 1.0.0 +description = Async devRant API client made with aiohttp. +author = retoor +author_email = retoor@molodetz.nl +license = MIT +long_description = file: README.md +long_description_content_type = text/markdown + +[options] +packages = find: +package_dir = + = src +python_requires = >=3.7 +install_requires = + requests + aiohttp + dataset +[options.packages.find] +where = src + +[options.entry_points] +console_scripts = + devranta = devranta.__main__:main diff --git a/src/Retoorded.egg-info/PKG-INFO b/src/Retoorded.egg-info/PKG-INFO new file mode 100644 index 0000000..38f8448 --- /dev/null +++ b/src/Retoorded.egg-info/PKG-INFO @@ -0,0 +1,12 @@ +Metadata-Version: 2.1 +Name: Retoorded +Version: 1.3.37 +Summary: A LLM to devRant mapper +Author: Retoor +Author-email: retoor@molodetz.nl +License: MIT +Requires-Python: >=3.7 +Description-Content-Type: text/markdown +Requires-Dist: requests +Requires-Dist: aiohttp +Requires-Dist: dataset diff --git a/src/Retoorded.egg-info/SOURCES.txt b/src/Retoorded.egg-info/SOURCES.txt new file mode 100644 index 0000000..11f1114 --- /dev/null +++ b/src/Retoorded.egg-info/SOURCES.txt @@ -0,0 +1,10 @@ +pyproject.toml +setup.cfg +src/Retoorded.egg-info/PKG-INFO +src/Retoorded.egg-info/SOURCES.txt +src/Retoorded.egg-info/dependency_links.txt +src/Retoorded.egg-info/entry_points.txt +src/Retoorded.egg-info/requires.txt +src/Retoorded.egg-info/top_level.txt +src/devranta/__init__.py +src/devranta/__main__.py \ No newline at end of file diff --git a/src/Retoorded.egg-info/dependency_links.txt b/src/Retoorded.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/Retoorded.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/src/Retoorded.egg-info/entry_points.txt b/src/Retoorded.egg-info/entry_points.txt new file mode 100644 index 0000000..7a5037b --- /dev/null +++ b/src/Retoorded.egg-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +retoorded.service = retoorded.bot:run diff --git a/src/Retoorded.egg-info/requires.txt b/src/Retoorded.egg-info/requires.txt new file mode 100644 index 0000000..aaad898 --- /dev/null +++ b/src/Retoorded.egg-info/requires.txt @@ -0,0 +1,3 @@ +requests +aiohttp +dataset diff --git a/src/Retoorded.egg-info/top_level.txt b/src/Retoorded.egg-info/top_level.txt new file mode 100644 index 0000000..56059c8 --- /dev/null +++ b/src/Retoorded.egg-info/top_level.txt @@ -0,0 +1 @@ +devranta diff --git a/src/devranta.egg-info/PKG-INFO b/src/devranta.egg-info/PKG-INFO new file mode 100644 index 0000000..06c226e --- /dev/null +++ b/src/devranta.egg-info/PKG-INFO @@ -0,0 +1,12 @@ +Metadata-Version: 2.1 +Name: devranta +Version: 1.0.0 +Summary: Async devRant API client made with aiohttp. +Author: retoor +Author-email: retoor@molodetz.nl +License: MIT +Requires-Python: >=3.7 +Description-Content-Type: text/markdown +Requires-Dist: requests +Requires-Dist: aiohttp +Requires-Dist: dataset diff --git a/src/devranta.egg-info/SOURCES.txt b/src/devranta.egg-info/SOURCES.txt new file mode 100644 index 0000000..32eecdc --- /dev/null +++ b/src/devranta.egg-info/SOURCES.txt @@ -0,0 +1,12 @@ +pyproject.toml +setup.cfg +src/devranta/__init__.py +src/devranta/__main__.py +src/devranta/api.py +src/devranta/tests.py +src/devranta.egg-info/PKG-INFO +src/devranta.egg-info/SOURCES.txt +src/devranta.egg-info/dependency_links.txt +src/devranta.egg-info/entry_points.txt +src/devranta.egg-info/requires.txt +src/devranta.egg-info/top_level.txt \ No newline at end of file diff --git a/src/devranta.egg-info/dependency_links.txt b/src/devranta.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/devranta.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/src/devranta.egg-info/entry_points.txt b/src/devranta.egg-info/entry_points.txt new file mode 100644 index 0000000..fd6d778 --- /dev/null +++ b/src/devranta.egg-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +devranta = devranta.__main__:main diff --git a/src/devranta.egg-info/requires.txt b/src/devranta.egg-info/requires.txt new file mode 100644 index 0000000..aaad898 --- /dev/null +++ b/src/devranta.egg-info/requires.txt @@ -0,0 +1,3 @@ +requests +aiohttp +dataset diff --git a/src/devranta.egg-info/top_level.txt b/src/devranta.egg-info/top_level.txt new file mode 100644 index 0000000..56059c8 --- /dev/null +++ b/src/devranta.egg-info/top_level.txt @@ -0,0 +1 @@ +devranta diff --git a/src/devranta/__init__.py b/src/devranta/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/devranta/__main__.py b/src/devranta/__main__.py new file mode 100644 index 0000000..579435f --- /dev/null +++ b/src/devranta/__main__.py @@ -0,0 +1,21 @@ +import asyncio + +from devranta.api import Api + + +async def main_async(): + api = Api() + async for rant in api.get_rants(): + print( + "{}({}): {}".format( + rant["user_username"], rant["user_score"], rant["text"].split(".")[0] + ) + ) + + +def main(): + asyncio.run(main_async()) + + +if __name__ == "__main__": + main() diff --git a/src/devranta/api.py b/src/devranta/api.py new file mode 100644 index 0000000..8e529c3 --- /dev/null +++ b/src/devranta/api.py @@ -0,0 +1,167 @@ +import aiohttp + + +class Api: + + base_url = "https://www.devrant.io/api/" + + def __init__(self, username=None, password=None): + self.username = username + self.password = password + self.auth = None + self.app_id = 3 + self.user_id = None + self.token_id = None + self.token_Key = None + self.session = None + + def patch_auth(self, request_dict=None): + auth_dict = {"app": self.app_id} + if self.auth: + auth_dict.update( + user_id=self.user_id, token_id=self.token_id, token_key=self.token_key + ) + if not request_dict: + return auth_dict + request_dict.update(auth_dict) + return request_dict + + def patch_url(self, url: str): + return self.base_url.rstrip("/") + "/" + url.lstrip("/") + + async def login(self): + if not self.username or not self.password: + raise Exception("No authentication defails supplied.") + async with self as session: + response = await session.post( + url=self.patch_url("users/auth-token"), + data={ + "username": self.username, + "password": self.password, + "app": self.app_id, + }, + ) + obj = await response.json() + if not obj.get("success"): + return False + self.auth = obj.get("auth_token") + if not self.auth: + return False + self.user_id = self.auth.get("user_id") + self.token_id = self.auth.get("id") + self.token_key = self.auth.get("key") + return self.auth and True or False + + async def ensure_login(self): + if not self.auth: + return await self.login() + return True + + async def __aenter__(self): + self.session = aiohttp.ClientSession() + return self.session + + async def __aexit__(self, *args, **kwargs): + await self.session.close() + self.session = None + + async def post_comment(self, rant_id, comment): + response = None + if not await self.ensure_login(): + return False + async with self as session: + response = await session.post( + url=self.patch_url(f"devrant/rants/{rant_id}/comments"), + data=self.patch_auth({"comment": comment, "plat": 2}), + ) + obj = await response.json() + return obj.get("success", False) + + async def get_comment(self, id_): + response = None + async with self as session: + response = await session.get( + url=self.patch_url("comments/" + str(id_)), params=self.patch_auth() + ) + obj = await response.json() + + print(obj) + if not obj.get("success"): + return None + + return obj.get("comment") + + async def get_profile(self, id_): + response = None + async with self as session: + response = await session.get( + url=self.patch_url(f"users/{id_}"), params=self.patch_auth() + ) + obj = await response.json() + if not obj.get("success"): + return None + return obj.get("profile") + + async def search(self, term): + async with self as session: + response = await session.get( + url=self.patch_url("devrant/search"), + params=self.patch_auth({"term": term}), + ) + obj = await response.json() + if not obj.get("success"): + return + for result in obj.get("results", []): + yield result + + async def get_rant(self, id): + response = None + async with self as session: + response = await session.get( + self.patch_url(f"devrant/rants/{id}"), + params=self.patch_auth(), + ) + return await response.json() + + async def get_rants(self, sort="recent", limit=20, skip=0): + response = None + async with self as session: + response = await session.get( + url=self.patch_url("devrant/rants"), + params=self.patch_auth({"sort": sort, "limit": limit, "skip": skip}), + ) + obj = await response.json() + if not obj.get("success"): + return + for rant in obj.get("rants", []): + yield rant + + async def get_user_id(self, username): + response = None + async with self as session: + response = await session.get( + url=self.patch_url("get-user-id"), + params=self.patch_auth({"username": username}), + ) + obj = await response.json() + if not obj.get("success"): + return None + return obj.get("user_id") + + @property + async def mentions(self): + async for notif in self.notifs: + if notif["type"] == "comment_mention": + yield notif + + @property + async def notifs(self): + response = None + if not await self.ensure_login(): + return + async with self as session: + response = await session.get( + url=self.patch_url("users/me/notif-feed"), params=self.patch_auth() + ) + for item in (await response.json()).get("data", {}).get("items", []): + yield item diff --git a/src/devranta/tests.py b/src/devranta/tests.py new file mode 100644 index 0000000..e8ec7fb --- /dev/null +++ b/src/devranta/tests.py @@ -0,0 +1,31 @@ +import unittest + +from devranta.api import Api + + +class ApiTestCase(unittest.IsolatedAsyncioTestCase): + + def setUp(self): + self.api = Api() + + async def async_list(self, generator): + list_ = [] + async for v in generator: + list_.append(v) + return list_ + + async def async_len(self, generator): + return len(await self.async_list(generator)) + + async def test_get_rants(self): + self.assertTrue(await self.async_len(self.api.get_rants())) + + async def test_search(self): + self.assertTrue(await self.async_len(self.api.search("retoor"))) + + async def test_get_user_id(self): + self.assertTrue(await self.api.get_user_id("retoor")) + + async def test_get_profile(self): + user_id = await self.api.get_user_id("retoor") + self.assertTrue(await self.api.get_profile(user_id))