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

256 lines
8.5 KiB
Python

"""Provide the Removal Reason class."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any, Iterator
from warnings import warn
from ...const import API_PATH
from ...exceptions import ClientException
from ...util import _deprecate_args, cachedproperty
from .base import RedditBase
if TYPE_CHECKING: # pragma: no cover
import praw
class RemovalReason(RedditBase):
"""An individual Removal Reason object.
.. include:: ../../typical_attributes.rst
=========== ==================================
Attribute Description
=========== ==================================
``id`` The ID of the removal reason.
``message`` The message of the removal reason.
``title`` The title of the removal reason.
=========== ==================================
"""
STR_FIELD = "id"
@staticmethod
def _warn_reason_id(
*, id_value: str | None, reason_id_value: str | None
) -> str | None:
"""Reason ID param is deprecated. Warns if it's used.
:param id_value: Returns the actual value of parameter ``id`` is parameter
``reason_id`` is not used.
:param reason_id_value: The value passed as parameter ``reason_id``.
"""
if reason_id_value is not None:
warn(
"Parameter 'reason_id' is deprecated. Either use positional arguments"
' (e.g., reason_id="x" -> "x") or change the parameter name to \'id\''
' (e.g., reason_id="x" -> id="x"). This parameter will be removed in'
" PRAW 8.",
category=DeprecationWarning,
stacklevel=3,
)
return reason_id_value
return id_value
def __eq__(self, other: str | RemovalReason) -> bool:
"""Return whether the other instance equals the current."""
if isinstance(other, str):
return other == str(self)
return isinstance(other, self.__class__) and str(self) == str(other)
def __hash__(self) -> int:
"""Return the hash of the current instance."""
return hash(self.__class__.__name__) ^ hash(str(self))
def __init__(
self,
reddit: praw.Reddit,
subreddit: praw.models.Subreddit,
id: str | None = None,
reason_id: str | None = None,
_data: dict[str, Any] | None = None,
):
"""Initialize a :class:`.RemovalReason` instance.
:param reddit: An instance of :class:`.Reddit`.
:param subreddit: An instance of :class:`.Subreddit`.
:param id: The ID of the removal reason.
:param reason_id: The original name of the ``id`` parameter. Used for backwards
compatibility. This parameter should not be used.
"""
reason_id = self._warn_reason_id(id_value=id, reason_id_value=reason_id)
if (reason_id, _data).count(None) != 1:
msg = "Either id or _data needs to be given."
raise ValueError(msg)
if reason_id:
self.id = reason_id
self.subreddit = subreddit
super().__init__(reddit, _data=_data)
def _fetch(self):
for removal_reason in self.subreddit.mod.removal_reasons:
if removal_reason.id == self.id:
self.__dict__.update(removal_reason.__dict__)
super()._fetch()
return
msg = f"Subreddit {self.subreddit} does not have the removal reason {self.id}"
raise ClientException(msg)
def delete(self):
"""Delete a removal reason from this subreddit.
To delete ``"141vv5c16py7d"`` from r/test try:
.. code-block:: python
reddit.subreddit("test").mod.removal_reasons["141vv5c16py7d"].delete()
"""
url = API_PATH["removal_reason"].format(subreddit=self.subreddit, id=self.id)
self._reddit.delete(url)
@_deprecate_args("message", "title")
def update(self, *, message: str | None = None, title: str | None = None):
"""Update the removal reason from this subreddit.
.. note::
Existing values will be used for any unspecified arguments.
:param message: The removal reason's new message.
:param title: The removal reason's new title.
To update ``"141vv5c16py7d"`` from r/test try:
.. code-block:: python
reddit.subreddit("test").mod.removal_reasons["141vv5c16py7d"].update(
title="New title", message="New message"
)
"""
url = API_PATH["removal_reason"].format(subreddit=self.subreddit, id=self.id)
data = {
name: getattr(self, name) if value is None else value
for name, value in {"message": message, "title": title}.items()
}
self._reddit.put(url, data=data)
class SubredditRemovalReasons:
"""Provide a set of functions to a :class:`.Subreddit`'s removal reasons."""
@cachedproperty
def _removal_reason_list(self) -> list[RemovalReason]:
"""Get a list of Removal Reason objects.
:returns: A list of instances of :class:`.RemovalReason`.
"""
response = self._reddit.get(
API_PATH["removal_reasons_list"].format(subreddit=self.subreddit)
)
return [
RemovalReason(
self._reddit, self.subreddit, _data=response["data"][reason_id]
)
for reason_id in response["order"]
]
def __getitem__(self, reason_id: str | int | slice) -> RemovalReason:
"""Return the Removal Reason with the ID/number/slice ``reason_id``.
:param reason_id: The ID or index of the removal reason
.. note::
Removal reasons fetched using a specific rule name are lazily loaded, so you
might have to access an attribute to get all the expected attributes.
This method is to be used to fetch a specific removal reason, like so:
.. code-block:: python
reason_id = "141vv5c16py7d"
reason = reddit.subreddit("test").mod.removal_reasons[reason_id]
print(reason)
You can also use indices to get a numbered removal reason. Since Python uses
0-indexing, the first removal reason is index 0, and so on.
.. note::
Both negative indices and slices can be used to interact with the removal
reasons.
:raises: :py:class:`IndexError` if a removal reason of a specific number does
not exist.
For example, to get the second removal reason of r/test:
.. code-block:: python
reason = reddit.subreddit("test").mod.removal_reasons[1]
To get the last three removal reasons in a subreddit:
.. code-block:: python
reasons = reddit.subreddit("test").mod.removal_reasons[-3:]
for reason in reasons:
print(reason)
"""
if not isinstance(reason_id, str):
return self._removal_reason_list[reason_id]
return RemovalReason(self._reddit, self.subreddit, reason_id)
def __init__(self, subreddit: praw.models.Subreddit):
"""Initialize a :class:`.SubredditRemovalReasons` instance.
:param subreddit: The subreddit whose removal reasons to work with.
"""
self.subreddit = subreddit
self._reddit = subreddit._reddit
def __iter__(self) -> Iterator[RemovalReason]:
"""Return a list of Removal Reasons for the subreddit.
This method is used to discover all removal reasons for a subreddit:
.. code-block:: python
for removal_reason in reddit.subreddit("test").mod.removal_reasons:
print(removal_reason)
"""
return iter(self._removal_reason_list)
@_deprecate_args("message", "title")
def add(self, *, message: str, title: str) -> RemovalReason:
"""Add a removal reason to this subreddit.
:param message: The message associated with the removal reason.
:param title: The title of the removal reason.
:returns: The :class:`.RemovalReason` added.
The message will be prepended with ``Hi u/username,`` automatically.
To add ``"Test"`` to r/test try:
.. code-block:: python
reddit.subreddit("test").mod.removal_reasons.add(title="Test", message="Foobar")
"""
data = {"message": message, "title": title}
url = API_PATH["removal_reasons_list"].format(subreddit=self.subreddit)
reason_id = self._reddit.post(url, data=data)
return RemovalReason(self._reddit, self.subreddit, reason_id)