Skip to content

Commit 78a1db4

Browse files
authored
Merge pull request #316 from praw-dev/selftext
Add support for selftext in link, image, gallery, and video posts
2 parents 702d6d6 + 8c45f17 commit 78a1db4

File tree

9 files changed

+3675
-20
lines changed

9 files changed

+3675
-20
lines changed

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,5 @@ Source Contributors
9494
- zacc `@zacc <https://github.com/zacc>`_
9595
- Arkadiy Illarionov `@qarkai <https://github.com/qarkai>`_
9696
- c0d3rman `@c0d3rman <https://github.com/c0d3rman>`
97+
- Aaron Becker `@aaronjbecker <https://github.com/aaronjbecker>`_
9798
- Add "Name <email (optional)> and github profile link" above this line.

CHANGES.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ Unreleased
99
**Added**
1010

1111
- Add support for Python 3.13.
12+
- Add support for optional Markdown-formatted ``selftext`` when submitting link, image,
13+
gallery and video posts.
1214
- Support delayed session creation in asyncprawcore 2.5.0+.
1315
- Add parameter ``fetch`` to :meth:`.get_rule` to control whether to fetch the rule data
1416
when initializing the rule object.
@@ -26,6 +28,14 @@ Unreleased
2628
must now be passed by keyword.
2729
- The ``flair_type`` argument to :class:`.SubredditFlairTemplates` must be passed by
2830
keyword.
31+
- The ``selftext`` and ``url`` arguments to :meth:`.Subreddit.submit` are no longer
32+
mutually exclusive. When ``url`` is provided ``selftext`` will be used as optional
33+
body text to accompany the link submission. An exception is raised when trying to use
34+
``inline_media`` with ``selftext`` for a ``url`` submission because Reddit does not
35+
support inline media in body text for link submissions.
36+
- :meth:`.Subreddit.submit_video`, :meth:`.Subreddit.submit_gallery`, and
37+
:meth:`.Subreddit.submit_image` now accept an optional Markdown-formatted ``selftext``
38+
parameter.
2939
- :meth:`.CommentForest.list` no longer needs to be awaited.
3040
- The keyword argument ``lazy`` has been replace by ``fetch`` to consolidate the keyword
3141
argument used to explicitly perform a fetch when initializing an object.
@@ -49,6 +59,10 @@ Unreleased
4959
- :meth:`.SubredditCollections.__call__`
5060
- :meth:`.SubredditHelper.__call__`
5161

62+
**Fixed**
63+
64+
- An issue where submitting a gallery post with websockets enabled would fail.
65+
5266
**Removed**
5367

5468
- Remove ``Reddit.random_subreddit``, ``Subreddit.random``, and

asyncpraw/models/reddit/subreddit.py

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3073,22 +3073,27 @@ async def _upload_media(
30733073
self,
30743074
*,
30753075
expected_mime_prefix: str | None = None,
3076-
media_path: str,
3076+
media_path: str | None,
30773077
upload_type: str = "link",
30783078
) -> str:
30793079
"""Upload media and return its URL and a websocket (Undocumented endpoint).
30803080
30813081
:param expected_mime_prefix: If provided, enforce that the media has a mime type
30823082
that starts with the provided prefix.
3083+
:param media_path: The path to the media file to upload. Default is the PRAW
3084+
logo.
30833085
:param upload_type: One of ``"link"``, ``"gallery"'', or ``"selfpost"``
30843086
(default: ``"link"``).
30853087
30863088
:returns: The link to the uploaded media.
30873089
30883090
"""
30893091
if media_path is None:
3090-
file = Path(__file__).absolute()
3091-
media_path = file.parent.parent.parent / "images" / "PRAW logo.png"
3092+
# if we're uploading without a media path, assume we're uploading a PRAW logo
3093+
# this default is commonly used when ``video_poster_url`` is not provided in ``submit_video``
3094+
module_path = Path(__file__).absolute()
3095+
logo_path = module_path.parent.parent.parent / "images" / "PRAW logo.png"
3096+
file = Path(logo_path)
30923097
else:
30933098
file = Path(media_path)
30943099

@@ -3262,12 +3267,14 @@ async def submit(
32623267
this value will set a custom text (default: ``None``). ``flair_id`` is
32633268
required when ``flair_text`` is provided.
32643269
:param inline_media: A dict of :class:`.InlineMedia` objects where the key is
3265-
the placeholder name in ``selftext``.
3270+
the placeholder name in ``selftext``. Link post selftext does not support
3271+
inline media.
32663272
:param nsfw: Whether the submission should be marked NSFW (default: ``False``).
32673273
:param resubmit: When ``False``, an error will occur if the URL has already been
32683274
submitted (default: ``True``).
3269-
:param selftext: The Markdown formatted content for a ``text`` submission. Use
3270-
an empty string, ``""``, to make a title-only submission.
3275+
:param selftext: The Markdown formatted content for a ``text`` submission or an
3276+
optional post body for ``link`` submissions. Use an empty string, ``""``, to
3277+
make a title-only submission.
32713278
:param send_replies: When ``True``, messages will be sent to the submission
32723279
author when comments are made to the submission (default: ``True``).
32733280
:param spoiler: Whether the submission should be marked as a spoiler (default:
@@ -3276,7 +3283,10 @@ async def submit(
32763283
32773284
:returns: A :class:`.Submission` object for the newly created submission.
32783285
3279-
Either ``selftext`` or ``url`` can be provided, but not both.
3286+
Provide ``selftext`` alone for a ``text`` submission. ``selftext`` can accompany
3287+
a ``url`` for a ``link`` submission. ``selftext`` that accompanies a ``link``
3288+
submission is optional. ``selftext`` for ``link`` submissions does not support
3289+
``inline_media``.
32803290
32813291
For example, to submit a URL to r/test do:
32823292
@@ -3334,6 +3344,16 @@ async def submit(
33343344
template_id = next(x for x in choices if x["flair_text"] == "news")["flair_template_id"]
33353345
await subreddit.submit("title", flair_id=template_id, url="https://www.news.com/")
33363346
3347+
.. note::
3348+
3349+
If you need to access any attributes of the submission after submitting it,
3350+
you must re-fetch the submission, like so:
3351+
3352+
.. code-block:: python
3353+
3354+
submission = await subreddit.submit(title, url=url)
3355+
await submission.load()
3356+
33373357
.. seealso::
33383358
33393359
- :meth:`~.Subreddit.submit_gallery` to submit more than one image in the
@@ -3343,8 +3363,10 @@ async def submit(
33433363
- :meth:`~.Subreddit.submit_video` to submit videos and videogifs
33443364
33453365
"""
3346-
if (bool(selftext) or selftext == "") == bool(url): # noqa: PLC1901
3347-
msg = "Either 'selftext' or 'url' must be provided."
3366+
# link posts can now include selftext (no longer exclusive)
3367+
# test for empty string in selftext for title-only submissions
3368+
if not url and not (bool(selftext) or selftext == ""): # noqa: PLC1901
3369+
msg = "Either 'selftext' and/or 'url' must be provided."
33483370
raise TypeError(msg)
33493371

33503372
data = {
@@ -3365,7 +3387,15 @@ async def submit(
33653387
):
33663388
if value is not None:
33673389
data[key] = value
3368-
if selftext is not None:
3390+
if url is not None:
3391+
data.update(kind="link", url=url)
3392+
if inline_media:
3393+
msg = "As of 2025-10-08, `inline_media` is not supported for link post selftext. Only Markdown text can be added to non-self posts."
3394+
raise TypeError(msg)
3395+
# we can ignore an empty string for selftext here b/c body text is optional for link posts
3396+
if selftext:
3397+
data.update(text=selftext)
3398+
elif selftext is not None:
33693399
data.update(kind="self")
33703400
if inline_media:
33713401
body = selftext.format(**{
@@ -3375,8 +3405,6 @@ async def submit(
33753405
data.update(richtext_json=dumps(converted))
33763406
else:
33773407
data.update(text=selftext)
3378-
else:
3379-
data.update(kind="link", url=url)
33803408

33813409
return await self._reddit.post(API_PATH["submit"], data=data)
33823410

@@ -3390,6 +3418,7 @@ async def submit_gallery(
33903418
flair_id: str | None = None,
33913419
flair_text: str | None = None,
33923420
nsfw: bool = False,
3421+
selftext: str | None = None,
33933422
send_replies: bool = True,
33943423
spoiler: bool = False,
33953424
) -> asyncpraw.models.Submission:
@@ -3408,6 +3437,8 @@ async def submit_gallery(
34083437
this value will set a custom text (default: ``None``). ``flair_id`` is
34093438
required when ``flair_text`` is provided.
34103439
:param nsfw: Whether the submission should be marked NSFW (default: ``False``).
3440+
:param selftext: Optional Markdown-formatted post body content (default:
3441+
``None``).
34113442
:param send_replies: When ``True``, messages will be sent to the submission
34123443
author when comments are made to the submission (default: ``True``).
34133444
:param spoiler: Whether the submission should be marked asa spoiler (default:
@@ -3466,6 +3497,7 @@ async def submit_gallery(
34663497
("flair_text", flair_text),
34673498
("collection_id", collection_id),
34683499
("discussion_type", discussion_type),
3500+
("text", selftext),
34693501
):
34703502
if value is not None:
34713503
data[key] = value
@@ -3479,7 +3511,7 @@ async def submit_gallery(
34793511
media_path=image["image_path"],
34803512
upload_type="gallery",
34813513
)
3482-
)[0],
3514+
),
34833515
})
34843516
response = await self._reddit.request(json=data, method="POST", path=API_PATH["submit_gallery_post"])
34853517
response = response["json"]
@@ -3498,6 +3530,7 @@ async def submit_image(
34983530
flair_text: str | None = None,
34993531
nsfw: bool = False,
35003532
resubmit: bool = True,
3533+
selftext: str | None = None,
35013534
send_replies: bool = True,
35023535
spoiler: bool = False,
35033536
timeout: int = 10,
@@ -3517,6 +3550,8 @@ async def submit_image(
35173550
:param nsfw: Whether the submission should be marked NSFW (default: ``False``).
35183551
:param resubmit: When ``False``, an error will occur if the URL has already been
35193552
submitted (default: ``True``).
3553+
:param selftext: Optional Markdown-formatted post body content (default:
3554+
``None``).
35203555
:param send_replies: When ``True``, messages will be sent to the submission
35213556
author when comments are made to the submission (default: ``True``).
35223557
:param spoiler: Whether the submission should be marked as a spoiler (default:
@@ -3579,6 +3614,7 @@ async def submit_image(
35793614
("flair_text", flair_text),
35803615
("collection_id", collection_id),
35813616
("discussion_type", discussion_type),
3617+
("text", selftext),
35823618
):
35833619
if value is not None:
35843620
data[key] = value
@@ -3680,6 +3716,7 @@ async def submit_video(
36803716
flair_text: str | None = None,
36813717
nsfw: bool = False,
36823718
resubmit: bool = True,
3719+
selftext: str | None = None,
36833720
send_replies: bool = True,
36843721
spoiler: bool = False,
36853722
thumbnail_path: str | None = None,
@@ -3702,6 +3739,8 @@ async def submit_video(
37023739
:param nsfw: Whether the submission should be marked NSFW (default: ``False``).
37033740
:param resubmit: When ``False``, an error will occur if the URL has already been
37043741
submitted (default: ``True``).
3742+
:param selftext: Optional Markdown-formatted post body content (default:
3743+
``None``).
37053744
:param send_replies: When ``True``, messages will be sent to the submission
37063745
author when comments are made to the submission (default: ``True``).
37073746
:param spoiler: Whether the submission should be marked as a spoiler (default:
@@ -3768,6 +3807,7 @@ async def submit_video(
37683807
("flair_text", flair_text),
37693808
("collection_id", collection_id),
37703809
("discussion_type", discussion_type),
3810+
("text", selftext),
37713811
):
37723812
if value is not None:
37733813
data[key] = value

0 commit comments

Comments
 (0)