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

184 lines
6.3 KiB
Python

"""Provide the Subreddits class."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any, Iterator
from warnings import warn
from ..const import API_PATH
from ..util import _deprecate_args
from . import Subreddit
from .base import PRAWBase
from .listing.generator import ListingGenerator
from .util import stream_generator
if TYPE_CHECKING: # pragma: no cover
import praw.models
class Subreddits(PRAWBase):
"""Subreddits is a Listing class that provides various subreddit lists."""
@staticmethod
def _to_list(subreddit_list: list[str | praw.models.Subreddit]) -> str:
return ",".join([str(x) for x in subreddit_list])
def default(
self, **generator_kwargs: str | int | dict[str, str]
) -> Iterator[praw.models.Subreddit]:
"""Return a :class:`.ListingGenerator` for default subreddits.
Additional keyword arguments are passed in the initialization of
:class:`.ListingGenerator`.
"""
return ListingGenerator(
self._reddit, API_PATH["subreddits_default"], **generator_kwargs
)
def gold(self, **generator_kwargs: Any) -> Iterator[praw.models.Subreddit]:
"""Alias for :meth:`.premium` to maintain backwards compatibility."""
warn(
"'subreddits.gold' has be renamed to 'subreddits.premium'.",
category=DeprecationWarning,
stacklevel=2,
)
return self.premium(**generator_kwargs)
def new(
self, **generator_kwargs: str | int | dict[str, str]
) -> Iterator[praw.models.Subreddit]:
"""Return a :class:`.ListingGenerator` for new subreddits.
Additional keyword arguments are passed in the initialization of
:class:`.ListingGenerator`.
"""
return ListingGenerator(
self._reddit, API_PATH["subreddits_new"], **generator_kwargs
)
def popular(
self, **generator_kwargs: str | int | dict[str, str]
) -> Iterator[praw.models.Subreddit]:
"""Return a :class:`.ListingGenerator` for popular subreddits.
Additional keyword arguments are passed in the initialization of
:class:`.ListingGenerator`.
"""
return ListingGenerator(
self._reddit, API_PATH["subreddits_popular"], **generator_kwargs
)
def premium(
self, **generator_kwargs: str | int | dict[str, str]
) -> Iterator[praw.models.Subreddit]:
"""Return a :class:`.ListingGenerator` for premium subreddits.
Additional keyword arguments are passed in the initialization of
:class:`.ListingGenerator`.
"""
return ListingGenerator(
self._reddit, API_PATH["subreddits_gold"], **generator_kwargs
)
def recommended(
self,
subreddits: list[str | praw.models.Subreddit],
omit_subreddits: list[str | praw.models.Subreddit] | None = None,
) -> list[praw.models.Subreddit]:
"""Return subreddits recommended for the given list of subreddits.
:param subreddits: A list of :class:`.Subreddit` instances and/or subreddit
names.
:param omit_subreddits: A list of :class:`.Subreddit` instances and/or subreddit
names to exclude from the results (Reddit's end may not work as expected).
"""
if not isinstance(subreddits, list):
msg = "subreddits must be a list"
raise TypeError(msg)
if omit_subreddits is not None and not isinstance(omit_subreddits, list):
msg = "omit_subreddits must be a list or None"
raise TypeError(msg)
params = {"omit": self._to_list(omit_subreddits or [])}
url = API_PATH["sub_recommended"].format(subreddits=self._to_list(subreddits))
return [
Subreddit(self._reddit, sub["sr_name"])
for sub in self._reddit.get(url, params=params)
]
def search(
self, query: str, **generator_kwargs: str | int | dict[str, str]
) -> Iterator[praw.models.Subreddit]:
"""Return a :class:`.ListingGenerator` of subreddits matching ``query``.
Subreddits are searched by both their title and description.
:param query: The query string to filter subreddits by.
Additional keyword arguments are passed in the initialization of
:class:`.ListingGenerator`.
.. seealso::
:meth:`.search_by_name` to search by subreddit names
"""
self._safely_add_arguments(arguments=generator_kwargs, key="params", q=query)
return ListingGenerator(
self._reddit, API_PATH["subreddits_search"], **generator_kwargs
)
@_deprecate_args("query", "include_nsfw", "exact")
def search_by_name(
self,
query: str,
*,
include_nsfw: bool = True,
exact: bool = False,
) -> list[praw.models.Subreddit]:
r"""Return list of :class:`.Subreddit`\ s whose names begin with ``query``.
:param query: Search for subreddits beginning with this string.
:param exact: Return only exact matches to ``query`` (default: ``False``).
:param include_nsfw: Include subreddits labeled NSFW (default: ``True``).
"""
result = self._reddit.post(
API_PATH["subreddits_name_search"],
data={"include_over_18": include_nsfw, "exact": exact, "query": query},
)
return [self._reddit.subreddit(x) for x in result["names"]]
def search_by_topic(self, query: str) -> list[praw.models.Subreddit]:
"""Return list of Subreddits whose topics match ``query``.
:param query: Search for subreddits relevant to the search topic.
.. note::
As of 09/01/2020, this endpoint always returns 404.
"""
result = self._reddit.get(
API_PATH["subreddits_by_topic"], params={"query": query}
)
return [self._reddit.subreddit(x["name"]) for x in result if x.get("name")]
def stream(
self, **stream_options: str | int | dict[str, str]
) -> Iterator[praw.models.Subreddit]:
"""Yield new subreddits as they are created.
Subreddits are yielded oldest first. Up to 100 historical subreddits will
initially be returned.
Keyword arguments are passed to :func:`.stream_generator`.
"""
return stream_generator(self.new, **stream_options)