Initial commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""Package providing models and mixins pertaining to Reddit listings."""
|
||||
25
backend/venv/Lib/site-packages/praw/models/listing/domain.py
Normal file
25
backend/venv/Lib/site-packages/praw/models/listing/domain.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""Provide the DomainListing class."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from ...const import API_PATH
|
||||
from .mixins import BaseListingMixin, RisingListingMixin
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
import praw
|
||||
|
||||
|
||||
class DomainListing(BaseListingMixin, RisingListingMixin):
|
||||
"""Provide a set of functions to interact with domain listings."""
|
||||
|
||||
def __init__(self, reddit: praw.Reddit, domain: str):
|
||||
"""Initialize a :class:`.DomainListing` instance.
|
||||
|
||||
:param reddit: An instance of :class:`.Reddit`.
|
||||
:param domain: The domain for which to obtain listings.
|
||||
|
||||
"""
|
||||
super().__init__(reddit, _data=None)
|
||||
self._path = API_PATH["domain"].format(domain=domain)
|
||||
102
backend/venv/Lib/site-packages/praw/models/listing/generator.py
Normal file
102
backend/venv/Lib/site-packages/praw/models/listing/generator.py
Normal file
@@ -0,0 +1,102 @@
|
||||
"""Provide the ListingGenerator class."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from copy import deepcopy
|
||||
from typing import TYPE_CHECKING, Any, Iterator
|
||||
|
||||
from ..base import PRAWBase
|
||||
from .listing import FlairListing, ModNoteListing
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
import praw
|
||||
|
||||
|
||||
class ListingGenerator(PRAWBase, Iterator):
|
||||
"""Instances of this class generate :class:`.RedditBase` instances.
|
||||
|
||||
.. warning::
|
||||
|
||||
This class should not be directly utilized. Instead, you will find a number of
|
||||
methods that return instances of the class here_.
|
||||
|
||||
.. _here: https://praw.readthedocs.io/en/latest/search.html?q=ListingGenerator
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
reddit: praw.Reddit,
|
||||
url: str,
|
||||
limit: int = 100,
|
||||
params: dict[str, str | int] | None = None,
|
||||
):
|
||||
"""Initialize a :class:`.ListingGenerator` instance.
|
||||
|
||||
:param reddit: An instance of :class:`.Reddit`.
|
||||
:param url: A URL returning a Reddit listing.
|
||||
:param limit: The number of content entries to fetch. If ``limit`` is ``None``,
|
||||
then fetch as many entries as possible. Most of Reddit's listings contain a
|
||||
maximum of 1000 items, and are returned 100 at a time. This class will
|
||||
automatically issue all necessary requests (default: ``100``).
|
||||
:param params: A dictionary containing additional query string parameters to
|
||||
send with the request.
|
||||
|
||||
"""
|
||||
super().__init__(reddit, _data=None)
|
||||
self._exhausted = False
|
||||
self._listing = None
|
||||
self._list_index = None
|
||||
self.limit = limit
|
||||
self.params = deepcopy(params) if params else {}
|
||||
self.params["limit"] = limit or 1024
|
||||
self.url = url
|
||||
self.yielded = 0
|
||||
|
||||
def __iter__(self) -> Any:
|
||||
"""Permit :class:`.ListingGenerator` to operate as an iterator."""
|
||||
return self
|
||||
|
||||
def __next__(self) -> Any:
|
||||
"""Permit :class:`.ListingGenerator` to operate as a generator."""
|
||||
if self.limit is not None and self.yielded >= self.limit:
|
||||
raise StopIteration
|
||||
|
||||
if self._listing is None or self._list_index >= len(self._listing):
|
||||
self._next_batch()
|
||||
|
||||
self._list_index += 1
|
||||
self.yielded += 1
|
||||
return self._listing[self._list_index - 1]
|
||||
|
||||
def _extract_sublist(self, listing: dict[str, Any] | list[Any]):
|
||||
if isinstance(listing, list):
|
||||
return listing[1] # for submission duplicates
|
||||
if isinstance(listing, dict):
|
||||
classes = [FlairListing, ModNoteListing]
|
||||
|
||||
for listing_type in classes:
|
||||
if listing_type.CHILD_ATTRIBUTE in listing:
|
||||
return listing_type(self._reddit, listing)
|
||||
else: # noqa: PLW0120
|
||||
msg = "The generator returned a dictionary PRAW didn't recognize. File a bug report at PRAW."
|
||||
raise ValueError(msg)
|
||||
return listing
|
||||
|
||||
def _next_batch(self):
|
||||
if self._exhausted:
|
||||
raise StopIteration
|
||||
|
||||
self._listing = self._reddit.get(self.url, params=self.params)
|
||||
self._listing = self._extract_sublist(self._listing)
|
||||
self._list_index = 0
|
||||
|
||||
if not self._listing:
|
||||
raise StopIteration
|
||||
|
||||
if self._listing.after and self._listing.after != self.params.get(
|
||||
self._listing.AFTER_PARAM
|
||||
):
|
||||
self.params[self._listing.AFTER_PARAM] = self._listing.after
|
||||
else:
|
||||
self._exhausted = True
|
||||
@@ -0,0 +1,73 @@
|
||||
"""Provide the Listing class."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from ..base import PRAWBase
|
||||
|
||||
|
||||
class Listing(PRAWBase):
|
||||
"""A listing is a collection of :class:`.RedditBase` instances."""
|
||||
|
||||
AFTER_PARAM = "after"
|
||||
CHILD_ATTRIBUTE = "children"
|
||||
|
||||
def __getitem__(self, index: int) -> Any:
|
||||
"""Return the item at position index in the list."""
|
||||
return getattr(self, self.CHILD_ATTRIBUTE)[index]
|
||||
|
||||
def __len__(self) -> int:
|
||||
"""Return the number of items in the Listing."""
|
||||
return len(getattr(self, self.CHILD_ATTRIBUTE))
|
||||
|
||||
def __setattr__(self, attribute: str, value: Any):
|
||||
"""Objectify the ``CHILD_ATTRIBUTE`` attribute."""
|
||||
if attribute == self.CHILD_ATTRIBUTE:
|
||||
value = self._reddit._objector.objectify(value)
|
||||
super().__setattr__(attribute, value)
|
||||
|
||||
|
||||
class FlairListing(Listing):
|
||||
"""Special Listing for handling flair lists."""
|
||||
|
||||
CHILD_ATTRIBUTE = "users"
|
||||
|
||||
@property
|
||||
def after(self) -> Any | None:
|
||||
"""Return the next attribute or ``None``."""
|
||||
return getattr(self, "next", None)
|
||||
|
||||
|
||||
class ModNoteListing(Listing):
|
||||
"""Special Listing for handling :class:`.ModNote` lists."""
|
||||
|
||||
AFTER_PARAM = "before"
|
||||
CHILD_ATTRIBUTE = "mod_notes"
|
||||
|
||||
@property
|
||||
def after(self) -> Any | None:
|
||||
"""Return the next attribute or None."""
|
||||
if not getattr(self, "has_next_page", True):
|
||||
return None
|
||||
return getattr(self, "end_cursor", None)
|
||||
|
||||
|
||||
class ModeratorListing(Listing):
|
||||
"""Special Listing for handling moderator lists."""
|
||||
|
||||
CHILD_ATTRIBUTE = "moderators"
|
||||
|
||||
|
||||
class ModmailConversationsListing(Listing):
|
||||
"""Special Listing for handling :class:`.ModmailConversation` lists."""
|
||||
|
||||
CHILD_ATTRIBUTE = "conversations"
|
||||
|
||||
@property
|
||||
def after(self) -> str | None:
|
||||
"""Return the next attribute or ``None``."""
|
||||
try:
|
||||
return self.conversations[-1].id
|
||||
except IndexError:
|
||||
return None
|
||||
@@ -0,0 +1,7 @@
|
||||
"""Package providing models that pertain to listing mixins."""
|
||||
|
||||
from .base import BaseListingMixin
|
||||
from .redditor import RedditorListingMixin
|
||||
from .rising import RisingListingMixin
|
||||
from .submission import SubmissionListingMixin
|
||||
from .subreddit import SubredditListingMixin
|
||||
@@ -0,0 +1,155 @@
|
||||
"""Provide the BaseListingMixin class."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Iterator
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from ....util import _deprecate_args
|
||||
from ...base import PRAWBase
|
||||
from ..generator import ListingGenerator
|
||||
|
||||
|
||||
class BaseListingMixin(PRAWBase):
|
||||
"""Adds minimum set of methods that apply to all listing objects."""
|
||||
|
||||
VALID_TIME_FILTERS = {"all", "day", "hour", "month", "week", "year"}
|
||||
|
||||
@staticmethod
|
||||
def _validate_time_filter(time_filter: str):
|
||||
"""Validate ``time_filter``.
|
||||
|
||||
:raises: :py:class:`ValueError` if ``time_filter`` is not valid.
|
||||
|
||||
"""
|
||||
if time_filter not in BaseListingMixin.VALID_TIME_FILTERS:
|
||||
valid_time_filters = ", ".join(
|
||||
map("{!r}".format, BaseListingMixin.VALID_TIME_FILTERS)
|
||||
)
|
||||
msg = f"'time_filter' must be one of: {valid_time_filters}"
|
||||
raise ValueError(msg)
|
||||
|
||||
def _prepare(self, *, arguments: dict[str, Any], sort: str) -> str:
|
||||
"""Fix for :class:`.Redditor` methods that use a query param rather than subpath."""
|
||||
if self.__dict__.get("_listing_use_sort"):
|
||||
self._safely_add_arguments(arguments=arguments, key="params", sort=sort)
|
||||
return self._path
|
||||
return urljoin(self._path, sort)
|
||||
|
||||
@_deprecate_args("time_filter")
|
||||
def controversial(
|
||||
self,
|
||||
*,
|
||||
time_filter: str = "all",
|
||||
**generator_kwargs: str | int | dict[str, str],
|
||||
) -> Iterator[Any]:
|
||||
"""Return a :class:`.ListingGenerator` for controversial items.
|
||||
|
||||
:param time_filter: Can be one of: ``"all"``, ``"day"``, ``"hour"``,
|
||||
``"month"``, ``"week"``, or ``"year"`` (default: ``"all"``).
|
||||
|
||||
:raises: :py:class:`ValueError` if ``time_filter`` is invalid.
|
||||
|
||||
Additional keyword arguments are passed in the initialization of
|
||||
:class:`.ListingGenerator`.
|
||||
|
||||
This method can be used like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
reddit.domain("imgur.com").controversial(time_filter="week")
|
||||
reddit.multireddit(redditor="samuraisam", name="programming").controversial(
|
||||
time_filter="day"
|
||||
)
|
||||
reddit.redditor("spez").controversial(time_filter="month")
|
||||
reddit.redditor("spez").comments.controversial(time_filter="year")
|
||||
reddit.redditor("spez").submissions.controversial(time_filter="all")
|
||||
reddit.subreddit("all").controversial(time_filter="hour")
|
||||
|
||||
"""
|
||||
self._validate_time_filter(time_filter)
|
||||
self._safely_add_arguments(
|
||||
arguments=generator_kwargs, key="params", t=time_filter
|
||||
)
|
||||
url = self._prepare(arguments=generator_kwargs, sort="controversial")
|
||||
return ListingGenerator(self._reddit, url, **generator_kwargs)
|
||||
|
||||
def hot(self, **generator_kwargs: str | int | dict[str, str]) -> Iterator[Any]:
|
||||
"""Return a :class:`.ListingGenerator` for hot items.
|
||||
|
||||
Additional keyword arguments are passed in the initialization of
|
||||
:class:`.ListingGenerator`.
|
||||
|
||||
This method can be used like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
reddit.domain("imgur.com").hot()
|
||||
reddit.multireddit(redditor="samuraisam", name="programming").hot()
|
||||
reddit.redditor("spez").hot()
|
||||
reddit.redditor("spez").comments.hot()
|
||||
reddit.redditor("spez").submissions.hot()
|
||||
reddit.subreddit("all").hot()
|
||||
|
||||
"""
|
||||
generator_kwargs.setdefault("params", {})
|
||||
url = self._prepare(arguments=generator_kwargs, sort="hot")
|
||||
return ListingGenerator(self._reddit, url, **generator_kwargs)
|
||||
|
||||
def new(self, **generator_kwargs: str | int | dict[str, str]) -> Iterator[Any]:
|
||||
"""Return a :class:`.ListingGenerator` for new items.
|
||||
|
||||
Additional keyword arguments are passed in the initialization of
|
||||
:class:`.ListingGenerator`.
|
||||
|
||||
This method can be used like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
reddit.domain("imgur.com").new()
|
||||
reddit.multireddit(redditor="samuraisam", name="programming").new()
|
||||
reddit.redditor("spez").new()
|
||||
reddit.redditor("spez").comments.new()
|
||||
reddit.redditor("spez").submissions.new()
|
||||
reddit.subreddit("all").new()
|
||||
|
||||
"""
|
||||
generator_kwargs.setdefault("params", {})
|
||||
url = self._prepare(arguments=generator_kwargs, sort="new")
|
||||
return ListingGenerator(self._reddit, url, **generator_kwargs)
|
||||
|
||||
@_deprecate_args("time_filter")
|
||||
def top(
|
||||
self,
|
||||
*,
|
||||
time_filter: str = "all",
|
||||
**generator_kwargs: str | int | dict[str, str],
|
||||
) -> Iterator[Any]:
|
||||
"""Return a :class:`.ListingGenerator` for top items.
|
||||
|
||||
:param time_filter: Can be one of: ``"all"``, ``"day"``, ``"hour"``,
|
||||
``"month"``, ``"week"``, or ``"year"`` (default: ``"all"``).
|
||||
|
||||
:raises: :py:class:`ValueError` if ``time_filter`` is invalid.
|
||||
|
||||
Additional keyword arguments are passed in the initialization of
|
||||
:class:`.ListingGenerator`.
|
||||
|
||||
This method can be used like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
reddit.domain("imgur.com").top(time_filter="week")
|
||||
reddit.multireddit(redditor="samuraisam", name="programming").top(time_filter="day")
|
||||
reddit.redditor("spez").top(time_filter="month")
|
||||
reddit.redditor("spez").comments.top(time_filter="year")
|
||||
reddit.redditor("spez").submissions.top(time_filter="all")
|
||||
reddit.subreddit("all").top(time_filter="hour")
|
||||
|
||||
"""
|
||||
self._validate_time_filter(time_filter)
|
||||
self._safely_add_arguments(
|
||||
arguments=generator_kwargs, key="params", t=time_filter
|
||||
)
|
||||
url = self._prepare(arguments=generator_kwargs, sort="top")
|
||||
return ListingGenerator(self._reddit, url, **generator_kwargs)
|
||||
@@ -0,0 +1,31 @@
|
||||
"""Provide the GildedListingMixin class."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Iterator
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from ...base import PRAWBase
|
||||
from ..generator import ListingGenerator
|
||||
|
||||
|
||||
class GildedListingMixin(PRAWBase):
|
||||
"""Mixes in the gilded method."""
|
||||
|
||||
def gilded(self, **generator_kwargs: str | int | dict[str, str]) -> Iterator[Any]:
|
||||
"""Return a :class:`.ListingGenerator` for gilded items.
|
||||
|
||||
Additional keyword arguments are passed in the initialization of
|
||||
:class:`.ListingGenerator`.
|
||||
|
||||
For example, to get gilded items in r/test:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
for item in reddit.subreddit("test").gilded():
|
||||
print(item.id)
|
||||
|
||||
"""
|
||||
return ListingGenerator(
|
||||
self._reddit, urljoin(self._path, "gilded"), **generator_kwargs
|
||||
)
|
||||
@@ -0,0 +1,224 @@
|
||||
"""Provide the RedditorListingMixin class."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Iterator
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from ....util.cache import cachedproperty
|
||||
from ..generator import ListingGenerator
|
||||
from .base import BaseListingMixin
|
||||
from .gilded import GildedListingMixin
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
import praw.models
|
||||
|
||||
|
||||
class SubListing(BaseListingMixin):
|
||||
"""Helper class for generating :class:`.ListingGenerator` objects."""
|
||||
|
||||
def __init__(self, reddit: praw.Reddit, base_path: str, subpath: str):
|
||||
"""Initialize a :class:`.SubListing` instance.
|
||||
|
||||
:param reddit: An instance of :class:`.Reddit`.
|
||||
:param base_path: The path to the object up to this point.
|
||||
:param subpath: The additional path to this sublisting.
|
||||
|
||||
"""
|
||||
super().__init__(reddit, _data=None)
|
||||
self._listing_use_sort = True
|
||||
self._reddit = reddit
|
||||
self._path = urljoin(base_path, subpath)
|
||||
|
||||
|
||||
class RedditorListingMixin(BaseListingMixin, GildedListingMixin):
|
||||
"""Adds additional methods pertaining to :class:`.Redditor` instances."""
|
||||
|
||||
@cachedproperty
|
||||
def comments(self) -> SubListing:
|
||||
r"""Provide an instance of :class:`.SubListing` for comment access.
|
||||
|
||||
For example, to output the first line of all new comments by u/spez try:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
for comment in reddit.redditor("spez").comments.new(limit=None):
|
||||
print(comment.body.split("\\n", 1)[0][:79])
|
||||
|
||||
"""
|
||||
return SubListing(self._reddit, self._path, "comments")
|
||||
|
||||
@cachedproperty
|
||||
def submissions(self) -> SubListing:
|
||||
"""Provide an instance of :class:`.SubListing` for submission access.
|
||||
|
||||
For example, to output the title's of top 100 of all time submissions for u/spez
|
||||
try:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
for submission in reddit.redditor("spez").submissions.top(time_filter="all"):
|
||||
print(submission.title)
|
||||
|
||||
"""
|
||||
return SubListing(self._reddit, self._path, "submitted")
|
||||
|
||||
def downvoted(
|
||||
self, **generator_kwargs: str | int | dict[str, str]
|
||||
) -> Iterator[praw.models.Comment | praw.models.Submission]:
|
||||
"""Return a :class:`.ListingGenerator` for items the user has downvoted.
|
||||
|
||||
:returns: A :class:`.ListingGenerator` object which yields :class:`.Comment` or
|
||||
:class:`.Submission` objects the user has downvoted.
|
||||
|
||||
:raises: ``prawcore.Forbidden`` if the user is not authorized to access the
|
||||
list.
|
||||
|
||||
.. note::
|
||||
|
||||
Since this function returns a :class:`.ListingGenerator` the exception
|
||||
may not occur until sometime after this function has returned.
|
||||
|
||||
|
||||
Additional keyword arguments are passed in the initialization of
|
||||
:class:`.ListingGenerator`.
|
||||
|
||||
For example, to get all downvoted items of the authenticated user:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
for item in reddit.user.me().downvoted():
|
||||
print(item.id)
|
||||
|
||||
"""
|
||||
return ListingGenerator(
|
||||
self._reddit, urljoin(self._path, "downvoted"), **generator_kwargs
|
||||
)
|
||||
|
||||
def gildings(
|
||||
self, **generator_kwargs: str | int | dict[str, str]
|
||||
) -> Iterator[praw.models.Comment | praw.models.Submission]:
|
||||
"""Return a :class:`.ListingGenerator` for items the user has gilded.
|
||||
|
||||
:returns: A :class:`.ListingGenerator` object which yields :class:`.Comment` or
|
||||
:class:`.Submission` objects the user has gilded.
|
||||
|
||||
:raises: ``prawcore.Forbidden`` if the user is not authorized to access the
|
||||
list.
|
||||
|
||||
.. note::
|
||||
|
||||
Since this function returns a :class:`.ListingGenerator` the exception
|
||||
may not occur until sometime after this function has returned.
|
||||
|
||||
|
||||
Additional keyword arguments are passed in the initialization of
|
||||
:class:`.ListingGenerator`.
|
||||
|
||||
For example, to get all gilded items of the authenticated user:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
for item in reddit.user.me().gildings():
|
||||
print(item.id)
|
||||
|
||||
"""
|
||||
return ListingGenerator(
|
||||
self._reddit, urljoin(self._path, "gilded/given"), **generator_kwargs
|
||||
)
|
||||
|
||||
def hidden(
|
||||
self, **generator_kwargs: str | int | dict[str, str]
|
||||
) -> Iterator[praw.models.Comment | praw.models.Submission]:
|
||||
"""Return a :class:`.ListingGenerator` for items the user has hidden.
|
||||
|
||||
:returns: A :class:`.ListingGenerator` object which yields :class:`.Comment` or
|
||||
:class:`.Submission` objects the user has hid.
|
||||
|
||||
:raises: ``prawcore.Forbidden`` if the user is not authorized to access the
|
||||
list.
|
||||
|
||||
.. note::
|
||||
|
||||
Since this function returns a :class:`.ListingGenerator` the exception
|
||||
may not occur until sometime after this function has returned.
|
||||
|
||||
|
||||
Additional keyword arguments are passed in the initialization of
|
||||
:class:`.ListingGenerator`.
|
||||
|
||||
For example, to get all hidden items of the authenticated user:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
for item in reddit.user.me().hidden():
|
||||
print(item.id)
|
||||
|
||||
"""
|
||||
return ListingGenerator(
|
||||
self._reddit, urljoin(self._path, "hidden"), **generator_kwargs
|
||||
)
|
||||
|
||||
def saved(
|
||||
self, **generator_kwargs: str | int | dict[str, str]
|
||||
) -> Iterator[praw.models.Comment | praw.models.Submission]:
|
||||
"""Return a :class:`.ListingGenerator` for items the user has saved.
|
||||
|
||||
:returns: A :class:`.ListingGenerator` object which yields :class:`.Comment` or
|
||||
:class:`.Submission` objects the user has saved.
|
||||
|
||||
:raises: ``prawcore.Forbidden`` if the user is not authorized to access the
|
||||
list.
|
||||
|
||||
.. note::
|
||||
|
||||
Since this function returns a :class:`.ListingGenerator` the exception
|
||||
may not occur until sometime after this function has returned.
|
||||
|
||||
|
||||
Additional keyword arguments are passed in the initialization of
|
||||
:class:`.ListingGenerator`.
|
||||
|
||||
For example, to get all saved items of the authenticated user:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
for item in reddit.user.me().saved(limit=None):
|
||||
print(item.id)
|
||||
|
||||
"""
|
||||
return ListingGenerator(
|
||||
self._reddit, urljoin(self._path, "saved"), **generator_kwargs
|
||||
)
|
||||
|
||||
def upvoted(
|
||||
self, **generator_kwargs: str | int | dict[str, str]
|
||||
) -> Iterator[praw.models.Comment | praw.models.Submission]:
|
||||
"""Return a :class:`.ListingGenerator` for items the user has upvoted.
|
||||
|
||||
:returns: A :class:`.ListingGenerator` object which yields :class:`.Comment` or
|
||||
:class:`.Submission` objects the user has upvoted.
|
||||
|
||||
:raises: ``prawcore.Forbidden`` if the user is not authorized to access the
|
||||
list.
|
||||
|
||||
.. note::
|
||||
|
||||
Since this function returns a :class:`.ListingGenerator` the exception
|
||||
may not occur until sometime after this function has returned.
|
||||
|
||||
|
||||
Additional keyword arguments are passed in the initialization of
|
||||
:class:`.ListingGenerator`.
|
||||
|
||||
For example, to get all upvoted items of the authenticated user:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
for item in reddit.user.me().upvoted():
|
||||
print(item.id)
|
||||
|
||||
"""
|
||||
return ListingGenerator(
|
||||
self._reddit, urljoin(self._path, "upvoted"), **generator_kwargs
|
||||
)
|
||||
@@ -0,0 +1,56 @@
|
||||
"""Provide the RisingListingMixin class."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Iterator
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from ...base import PRAWBase
|
||||
from ..generator import ListingGenerator
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
import praw.models
|
||||
|
||||
|
||||
class RisingListingMixin(PRAWBase):
|
||||
"""Mixes in the rising methods."""
|
||||
|
||||
def random_rising(
|
||||
self, **generator_kwargs: str | int | dict[str, str]
|
||||
) -> Iterator[praw.models.Submission]:
|
||||
"""Return a :class:`.ListingGenerator` for random rising submissions.
|
||||
|
||||
Additional keyword arguments are passed in the initialization of
|
||||
:class:`.ListingGenerator`.
|
||||
|
||||
For example, to get random rising submissions for r/test:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
for submission in reddit.subreddit("test").random_rising():
|
||||
print(submission.title)
|
||||
|
||||
"""
|
||||
return ListingGenerator(
|
||||
self._reddit, urljoin(self._path, "randomrising"), **generator_kwargs
|
||||
)
|
||||
|
||||
def rising(
|
||||
self, **generator_kwargs: str | int | dict[str, str]
|
||||
) -> Iterator[praw.models.Submission]:
|
||||
"""Return a :class:`.ListingGenerator` for rising submissions.
|
||||
|
||||
Additional keyword arguments are passed in the initialization of
|
||||
:class:`.ListingGenerator`.
|
||||
|
||||
For example, to get rising submissions for r/test:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
for submission in reddit.subreddit("test").rising():
|
||||
print(submission.title)
|
||||
|
||||
"""
|
||||
return ListingGenerator(
|
||||
self._reddit, urljoin(self._path, "rising"), **generator_kwargs
|
||||
)
|
||||
@@ -0,0 +1,42 @@
|
||||
"""Provide the SubmissionListingMixin class."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Iterator
|
||||
|
||||
from ....const import API_PATH
|
||||
from ...base import PRAWBase
|
||||
from ..generator import ListingGenerator
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
import praw.models
|
||||
|
||||
|
||||
class SubmissionListingMixin(PRAWBase):
|
||||
"""Adds additional methods pertaining to :class:`.Submission` instances."""
|
||||
|
||||
def duplicates(
|
||||
self, **generator_kwargs: str | int | dict[str, str]
|
||||
) -> Iterator[praw.models.Submission]:
|
||||
"""Return a :class:`.ListingGenerator` for the submission's duplicates.
|
||||
|
||||
Additional keyword arguments are passed in the initialization of
|
||||
:class:`.ListingGenerator`.
|
||||
|
||||
Example usage:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
submission = reddit.submission("5or86n")
|
||||
|
||||
for duplicate in submission.duplicates():
|
||||
# process each duplicate
|
||||
...
|
||||
|
||||
.. seealso::
|
||||
|
||||
:meth:`.upvote`
|
||||
|
||||
"""
|
||||
url = API_PATH["duplicates"].format(submission_id=self.id)
|
||||
return ListingGenerator(self._reddit, url, **generator_kwargs)
|
||||
@@ -0,0 +1,74 @@
|
||||
"""Provide the SubredditListingMixin class."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Iterator
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from ....util.cache import cachedproperty
|
||||
from ...base import PRAWBase
|
||||
from ..generator import ListingGenerator
|
||||
from .base import BaseListingMixin
|
||||
from .gilded import GildedListingMixin
|
||||
from .rising import RisingListingMixin
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
import praw.models
|
||||
|
||||
|
||||
class CommentHelper(PRAWBase):
|
||||
"""Provide a set of functions to interact with a :class:`.Subreddit`'s comments."""
|
||||
|
||||
@property
|
||||
def _path(self) -> str:
|
||||
return urljoin(self.subreddit._path, "comments/")
|
||||
|
||||
def __call__(
|
||||
self, **generator_kwargs: str | int | dict[str, str]
|
||||
) -> Iterator[praw.models.Comment]:
|
||||
"""Return a :class:`.ListingGenerator` for the :class:`.Subreddit`'s comments.
|
||||
|
||||
Additional keyword arguments are passed in the initialization of
|
||||
:class:`.ListingGenerator`.
|
||||
|
||||
This method should be used in a way similar to the example below:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
for comment in reddit.subreddit("test").comments(limit=25):
|
||||
print(comment.author)
|
||||
|
||||
"""
|
||||
return ListingGenerator(self._reddit, self._path, **generator_kwargs)
|
||||
|
||||
def __init__(self, subreddit: praw.models.Subreddit | SubredditListingMixin):
|
||||
"""Initialize a :class:`.CommentHelper` instance."""
|
||||
super().__init__(subreddit._reddit, _data=None)
|
||||
self.subreddit = subreddit
|
||||
|
||||
|
||||
class SubredditListingMixin(BaseListingMixin, GildedListingMixin, RisingListingMixin):
|
||||
"""Adds additional methods pertaining to subreddit-like instances."""
|
||||
|
||||
@cachedproperty
|
||||
def comments(self) -> CommentHelper:
|
||||
"""Provide an instance of :class:`.CommentHelper`.
|
||||
|
||||
For example, to output the author of the 25 most recent comments of r/test
|
||||
execute:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
for comment in reddit.subreddit("test").comments(limit=25):
|
||||
print(comment.author)
|
||||
|
||||
"""
|
||||
return CommentHelper(self)
|
||||
|
||||
def __init__(self, reddit: praw.Reddit, _data: dict[str, Any] | None):
|
||||
"""Initialize a :class:`.SubredditListingMixin` instance.
|
||||
|
||||
:param reddit: An instance of :class:`.Reddit`.
|
||||
|
||||
"""
|
||||
super().__init__(reddit, _data=_data)
|
||||
Reference in New Issue
Block a user