This post has been de-listed
It is no longer included in search results and normal feeds (front page, hot posts, subreddit posts, etc). It remains visible only via the author's post history.
- đ GitHub
- đŚ PyPI
- đ ReadTheDocs
RedditWarp version 1.1 has just been released.
RedditWarp is a fully type annotated Python API wrapper for Reddit.
In this post we will go through some of the highlights of the changes. See the change log file in the repository for a fuller list of changes.
TL;DR: In this release, configuring post flairsâ post appearance is now supported; API procedures now accept base-36 string IDs; and a powerful new feature called âmiddleware injectionâ has been implemented.
New API procedure: configure post flair post appearance
The ability to configure a post flairâs post appearance has been added. Credit to u/Then_Marionberry_259 for raising this question in r/redditdev.
To set a background image on posts with a particular post flair, use code like the following.
from io import BytesIO
from mimetypes import guess_extension
import redditwarp.SYNC
client = redditwarp.SYNC.Client.from_praw_config('Pyprohly')
subreddit = 'Pyprohly_test3'
post_flair_uuid = 'eeabd02a-af76-11ed-bfea-aaa3af62397b'
title_color = "#C0C0C0"
image_url = "https://placekitten.com/g/864/121"
resp = client.http.request('GET', image_url)
ext = guess_extension(resp.headers['content-type']) or '.jpeg'
filename = 'file' ext
file = BytesIO(resp.data)
with file:
lease = client.p.flair.post_appearance.upload_background(
file,
sr=subreddit,
uuid=post_flair_uuid,
filepath=filename,
)
client.p.flair.post_appearance.config(
subreddit,
post_flair_uuid,
title_color=title_color,
background_image_url=lease.location,
)
When testing this feature, I noticed that the post appearances donât show when using the dark theme of the web UI, except for the custom icon image. Be sure to turn off dark mode to see the changes.
API procedures now accept string IDs
The API procedures have been overloaded to accept string IDs in addition to integer IDs.
So you no longer have to write int(x, 36)
so much.
client.p.submission.fetch(int('10gudzi', 36))
# <== Functionally identical ==>
client.p.submission.fetch('10gudzi')
Accompanying this change, model objects having id36
now have an idn
attribute to access the integer ID, and this is preferred over id
which is considered deprecated.
Renamed submission creation API procedures
The string ID support is part of a larger change in RedditWarp making it more impartial to integer IDs. One of the challenges in making this change was figuring out what to do with the submission creation methods, like client.p.submission.create_*_post()
, that return integer IDs.
Since changing the return type of the client.p.submission.create_*_post()
methods is a breaking change, I decided to add new methods like client.p.submission.create.*()
instead. These new methods take a generic type parameter that allows you select the overload with the right return type for your uses.
# Functionally identical.
idn: int = client.p.submission.create_text_post('test', 'title', 'body')
idn: int = client.p.submission.create.text[int]('test', 'title', 'body')
# Return a string ID instead.
id36: str = client.p.submission.create.text[str]('test', 'title', 'body')
# No return value.
client.p.submission.create.text('test', 'title', 'body')
Middleware injection
A cool new feature has landed called âmiddleware injectionâ. It allows you to easily add temporary request handlers to the HTTP client request handler pipeline. This is a useful concept because can be used to essentially rewrite API procedures âon the spotâ without having to reimplement them.
The feature is accessible through client.http.having_additional_middleware()
and is used like so:
import redditwarp.SYNC
from redditwarp.http.misc.apply_params_and_headers_SYNC import ApplyParams
client = redditwarp.SYNC.Client.from_praw_config('Pyprohly')
with client.http.having_additional_middleware(lambda h: ApplyParams(h, {'my_param': '12345'})):
client.p.ping()
print(client.http.last.requisition_queue[-1].params)
# ~> {'scopes': 'read', 'my_param': '12345', 'raw_json': '1', 'api_type': 'json'}
The most common use case for this feature is to add support for unimplemented parameters to API procedures.
For example, for the submission creation endpoint, there is actually a special parameter called ad
which RedditWarp nor PRAW directly support through its high-level API procedure methods. When true, this ad
parameter creates an unlisted submission, only accessible by permalink.
Hereâs how we can use middleware injection to create an unlisted submission to r/test:
import redditwarp.SYNC
from redditwarp.http.misc.apply_params_and_headers_SYNC import ApplyParams
client = redditwarp.SYNC.Client.from_praw_config('PyprohlyTest')
with client.http.having_additional_middleware(lambda h: ApplyParams(h, {'ad': '1'})):
id36 = client.p.submission.create.text[str]('test', 'title', 'body')
subm = client.p.submission.fetch(id36)
print(subm.permalink)
I thought about adding this feature in for v1.0 but I wanted to see a legit use case for it before implementing it. The thing that motivated me to add it was u/LeMushroomScoopâs question here where he asks, in passing, how to get the âpfpâ, which I assume stands for âprofile picâ, when traversing a comment tree.
Thatâs a good question on its own. How does, for instance, the Reddit mobile client know how to get the userâs profile display picture when the comment resource data doesnât seem to include it? The answer is that it sends a secret profile_img
parameter during comment tree endpoint calls which populates the comment objects with a profile_img
attribute containing the link to the comment authorâs profile picture image.
We can obtain usersâ profile pictures while traversing comment trees like so:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from collections.abc import Iterator
from redditwarp.models.comment_tree_SYNC import CommentSubtreeTreeNode
import redditwarp.SYNC
from redditwarp.models.comment_SYNC import Comment
from redditwarp.http.misc.apply_params_and_headers_SYNC import ApplyParams
def traversal(node: CommentSubtreeTreeNode[object]) -> Iterator[tuple[int, Comment]]:
def traverse(root: CommentSubtreeTreeNode[object], level: int = 0) -> Iterator[tuple[int, Comment]]:
value = root.value
if isinstance(value, Comment):
yield (level, value)
for child in root.children:
yield from traverse(child, level 1)
if root.more:
yield from traverse(root.more(), level)
return traverse(node)
client = redditwarp.SYNC.Client()
with client.http.having_additional_middleware(lambda h: ApplyParams(h, {'profile_img': '1'})):
tree_node = client.p.comment_tree.fetch('12ldtgq')
for depth, c in traversal(tree_node):
print(f"{depth*'.'} u/{c.author_display_name} | {c.d.get('profile_img')}")
Modmail stream bug fixed
While attempting to help u/key_equivalent0 with their modmail streaming question, I noticed there was a subtle but significant bug with RedditWarpâs modmail streaming logic wherein old conversation messages could theoretically be repeated in the stream if a conversation thread had lots of activity.
The way entries are added to modmail listings is actually a little different to other listings, because with modmail listings, older entries could be removed and moved to the top. Having not accounted for this, this meant that if one conversation thread had a lot of activity and got lots of messages, the streamâs memory could become saturated with expired entries and thus forget about other the conversations it has already seen and eventually start to repeat messages.
Modmail streams output a tuple of modmail conversations and their most recent message. The streaming mechanism remembers the entries by storing a tuple of the conversation ID and the message ID.
For example, say we have this in the streamâs memory:
(1, 10)
(2, 20)
(3, 30)
Letâs say conversation 2
got a new message 21
. The listing would not look like this:
(2, 21)
(1, 10)
(2, 20)
(3, 30)
But instead look like:
(2, 21)
(1, 10)
(3, 30)
So the entry with conversation ID 2
was moved to the top and has a new message ID of 21
. The previous faulty stream logic was still storing the entry (2, 20)
in its memory, taking up space (in its capacity of 2000). So you can imagine how the streamâs memory could become saturated with a bunch of entries that no longer exist if there were a particular conversation thread that was very active.
While PRAW doesnât share this bug, PRAW doesnât support streaming modmail messages, only modmail conversations.
Thanks for reading.
Please join the RedditWarp Discord :)
Subreddit
Post Details
- Posted
- 1 year ago
- Reddit URL
- View post on reddit.com
- External URL
- reddit.com/r/redditdev/c...