2026-02-01 09:31:38 +01:00

380 lines
13 KiB
Python

"""Provide the helper classes."""
from __future__ import annotations
from json import dumps
from typing import TYPE_CHECKING, Any, Generator
from ..const import API_PATH
from ..util import _deprecate_args
from .base import PRAWBase
from .reddit.draft import Draft
from .reddit.live import LiveThread
from .reddit.multi import Multireddit, Subreddit
if TYPE_CHECKING: # pragma: no cover
import praw.models
class DraftHelper(PRAWBase):
r"""Provide a set of functions to interact with :class:`.Draft` instances.
.. note::
The methods provided by this class will only work on the currently authenticated
user's :class:`.Draft`\ s.
"""
def __call__(
self, draft_id: str | None = None
) -> list[praw.models.Draft] | praw.models.Draft:
"""Return a list of :class:`.Draft` instances.
:param draft_id: When provided, this returns a :class:`.Draft` instance
(default: ``None``).
:returns: A :class:`.Draft` instance if ``draft_id`` is provided. Otherwise, a
list of :class:`.Draft` objects.
.. note::
Drafts fetched using a specific draft ID are lazily loaded, so you might
have to access an attribute to get all the expected attributes.
This method can be used to fetch a specific draft by ID, like so:
.. code-block:: python
draft_id = "124862bc-e1e9-11eb-aa4f-e68667a77cbb"
draft = reddit.drafts(draft_id)
print(draft)
"""
if draft_id is not None:
return Draft(self._reddit, id=draft_id)
return self._draft_list()
def _draft_list(self) -> list[praw.models.Draft]:
"""Get a list of :class:`.Draft` instances.
:returns: A list of :class:`.Draft` instances.
"""
return self._reddit.get(API_PATH["drafts"], params={"md_body": True})
def create(
self,
*,
flair_id: str | None = None,
flair_text: str | None = None,
is_public_link: bool = False,
nsfw: bool = False,
original_content: bool = False,
selftext: str | None = None,
send_replies: bool = True,
spoiler: bool = False,
subreddit: (
str | praw.models.Subreddit | praw.models.UserSubreddit | None
) = None,
title: str | None = None,
url: str | None = None,
**draft_kwargs: Any,
) -> praw.models.Draft:
"""Create a new :class:`.Draft`.
:param flair_id: The flair template to select (default: ``None``).
:param flair_text: If the template's ``flair_text_editable`` value is ``True``,
this value will set a custom text (default: ``None``). ``flair_id`` is
required when ``flair_text`` is provided.
:param is_public_link: Whether to enable public viewing of the draft before it
is submitted (default: ``False``).
:param nsfw: Whether the draft should be marked NSFW (default: ``False``).
:param original_content: Whether the submission should be marked as original
content (default: ``False``).
:param selftext: The Markdown formatted content for a text submission draft. Use
``None`` to make a title-only submission draft (default: ``None``).
``selftext`` can not be provided if ``url`` is provided.
:param send_replies: When ``True``, messages will be sent to the submission
author when comments are made to the submission (default: ``True``).
:param spoiler: Whether the submission should be marked as a spoiler (default:
``False``).
:param subreddit: The subreddit to create the draft for. This accepts a
subreddit display name, :class:`.Subreddit` object, or
:class:`.UserSubreddit` object. If ``None``, the :class:`.UserSubreddit` of
currently authenticated user will be used (default: ``None``).
:param title: The title of the draft (default: ``None``).
:param url: The URL for a ``link`` submission draft (default: ``None``). ``url``
can not be provided if ``selftext`` is provided.
Additional keyword arguments can be provided to handle new parameters as Reddit
introduces them.
:returns: The new :class:`.Draft` object.
"""
if selftext and url:
msg = "Exactly one of 'selftext' or 'url' must be provided."
raise TypeError(msg)
if isinstance(subreddit, str):
subreddit = self._reddit.subreddit(subreddit)
data = Draft._prepare_data(
flair_id=flair_id,
flair_text=flair_text,
is_public_link=is_public_link,
nsfw=nsfw,
original_content=original_content,
selftext=selftext,
send_replies=send_replies,
spoiler=spoiler,
subreddit=subreddit,
title=title,
url=url,
**draft_kwargs,
)
return self._reddit.post(API_PATH["draft"], data=data)
class LiveHelper(PRAWBase):
r"""Provide a set of functions to interact with :class:`.LiveThread`\ s."""
def __call__(self, id: str) -> praw.models.LiveThread:
"""Return a new lazy instance of :class:`.LiveThread`.
This method is intended to be used as:
.. code-block:: python
livethread = reddit.live("ukaeu1ik4sw5")
:param id: A live thread ID, e.g., ``ukaeu1ik4sw5``.
"""
return LiveThread(self._reddit, id=id)
@_deprecate_args("title", "description", "nsfw", "resources")
def create(
self,
title: str,
*,
description: str | None = None,
nsfw: bool = False,
resources: str = None,
) -> praw.models.LiveThread:
"""Create a new :class:`.LiveThread`.
:param title: The title of the new :class:`.LiveThread`.
:param description: The new :class:`.LiveThread`'s description.
:param nsfw: Indicate whether this thread is not safe for work (default:
``False``).
:param resources: Markdown formatted information that is useful for the
:class:`.LiveThread`.
:returns: The new :class:`.LiveThread` object.
"""
return self._reddit.post(
API_PATH["livecreate"],
data={
"description": description,
"nsfw": nsfw,
"resources": resources,
"title": title,
},
)
def info(self, ids: list[str]) -> Generator[praw.models.LiveThread, None, None]:
"""Fetch information about each live thread in ``ids``.
:param ids: A list of IDs for a live thread.
:returns: A generator that yields :class:`.LiveThread` instances.
:raises: ``prawcore.ServerError`` if invalid live threads are requested.
Requests will be issued in batches for each 100 IDs.
.. note::
This method doesn't support IDs for live updates.
.. warning::
Unlike :meth:`.Reddit.info`, the output of this method may not reflect the
order of input.
Usage:
.. code-block:: python
ids = ["3rgnbke2rai6hen7ciytwcxadi", "sw7bubeycai6hey4ciytwamw3a", "t8jnufucss07"]
for thread in reddit.live.info(ids):
print(thread.title)
"""
if not isinstance(ids, list):
msg = "ids must be a list"
raise TypeError(msg)
def generator():
for position in range(0, len(ids), 100):
ids_chunk = ids[position : position + 100]
url = API_PATH["live_info"].format(ids=",".join(ids_chunk))
params = {"limit": 100} # 25 is used if not specified
yield from self._reddit.get(url, params=params)
return generator()
def now(self) -> praw.models.LiveThread | None:
"""Get the currently featured live thread.
:returns: The :class:`.LiveThread` object, or ``None`` if there is no currently
featured live thread.
Usage:
.. code-block:: python
thread = reddit.live.now() # LiveThread object or None
"""
return self._reddit.get(API_PATH["live_now"])
class MultiredditHelper(PRAWBase):
"""Provide a set of functions to interact with multireddits."""
@_deprecate_args("redditor", "name")
def __call__(
self, *, name: str, redditor: str | praw.models.Redditor
) -> praw.models.Multireddit:
"""Return a lazy instance of :class:`.Multireddit`.
:param name: The name of the multireddit.
:param redditor: A redditor name or :class:`.Redditor` instance who owns the
multireddit.
"""
path = f"/user/{redditor}/m/{name}"
return Multireddit(self._reddit, _data={"name": name, "path": path})
@_deprecate_args(
"display_name",
"subreddits",
"description_md",
"icon_name",
"key_color",
"visibility",
"weighting_scheme",
)
def create(
self,
*,
description_md: str | None = None,
display_name: str,
icon_name: str | None = None,
key_color: str | None = None,
subreddits: str | praw.models.Subreddit,
visibility: str = "private",
weighting_scheme: str = "classic",
) -> praw.models.Multireddit:
"""Create a new :class:`.Multireddit`.
:param display_name: The display name for the new multireddit.
:param subreddits: Subreddits to add to the new multireddit. Can be a list of
either :class:`.Subreddit` instances or subreddit display names.
:param description_md: Description for the new multireddit, formatted in
markdown.
:param icon_name: Can be one of: ``"art and design"``, ``"ask"``, ``"books"``,
``"business"``, ``"cars"``, ``"comics"``, ``"cute animals"``, ``"diy"``,
``"entertainment"``, ``"food and drink"``, ``"funny"``, ``"games"``,
``"grooming"``, ``"health"``, ``"life advice"``, ``"military"``, ``"models
pinup"``, ``"music"``, ``"news"``, ``"philosophy"``, ``"pictures and
gifs"``, ``"science"``, ``"shopping"``, ``"sports"``, ``"style"``,
``"tech"``, ``"travel"``, ``"unusual stories"``, ``"video"``, or ``None``.
:param key_color: RGB hex color code of the form ``"#FFFFFF"``.
:param visibility: Can be one of: ``"hidden"``, ``"private"``, or ``"public"``
(default: ``"private"``).
:param weighting_scheme: Can be one of: ``"classic"`` or ``"fresh"`` (default:
``"classic"``).
:returns: The new :class:`.Multireddit` object.
"""
model = {
"description_md": description_md,
"display_name": display_name,
"icon_name": icon_name,
"key_color": key_color,
"subreddits": [{"name": str(sub)} for sub in subreddits],
"visibility": visibility,
"weighting_scheme": weighting_scheme,
}
return self._reddit.post(
API_PATH["multireddit_base"], data={"model": dumps(model)}
)
class SubredditHelper(PRAWBase):
"""Provide a set of functions to interact with Subreddits."""
def __call__(self, display_name: str) -> praw.models.Subreddit:
"""Return a lazy instance of :class:`.Subreddit`.
:param display_name: The name of the subreddit.
"""
lower_name = display_name.lower()
if lower_name == "random":
return self._reddit.random_subreddit()
if lower_name == "randnsfw":
return self._reddit.random_subreddit(nsfw=True)
return Subreddit(self._reddit, display_name=display_name)
@_deprecate_args("name", "title", "link_type", "subreddit_type", "wikimode")
def create(
self,
name: str,
*,
link_type: str = "any",
subreddit_type: str = "public",
title: str | None = None,
wikimode: str = "disabled",
**other_settings: str | None,
) -> praw.models.Subreddit:
"""Create a new :class:`.Subreddit`.
:param name: The name for the new subreddit.
:param link_type: The types of submissions users can make. One of ``"any"``,
``"link"``, or ``"self"`` (default: ``"any"``).
:param subreddit_type: One of ``"archived"``, ``"employees_only"``,
``"gold_only"``, ``"gold_restricted"``, ``"private"``, ``"public"``, or
``"restricted"`` (default: ``"public"``).
:param title: The title of the subreddit. When ``None`` or ``""`` use the value
of ``name``.
:param wikimode: One of ``"anyone"``, ``"disabled"``, or ``"modonly"`` (default:
``"disabled"``).
Any keyword parameters not provided, or set explicitly to ``None``, will take on
a default value assigned by the Reddit server.
.. seealso::
:meth:`~.SubredditModeration.update` for documentation of other available
settings.
"""
Subreddit._create_or_update(
_reddit=self._reddit,
link_type=link_type,
name=name,
subreddit_type=subreddit_type,
title=title or name,
wikimode=wikimode,
**other_settings,
)
return self(name)