diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 42496169..83bc298e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: types: [ python ] - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-added-large-files - id: check-executables-have-shebangs @@ -33,7 +33,6 @@ repos: - id: name-tests-test args: [ --pytest-test-first ] files: ^tests/integration/.*\.py|tests/unit/.*\.py$ - - id: no-commit-to-branch - id: sort-simple-yaml files: ^(\.github/workflows/.*\.ya?ml|\.readthedocs.ya?ml)$ - id: trailing-whitespace @@ -45,7 +44,7 @@ repos: files: ^(.*\.toml)$ - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.286 + rev: v0.0.292 hooks: - id: ruff args: [ --exit-non-zero-on-fix, --fix ] diff --git a/asyncpraw/config.py b/asyncpraw/config.py index af2bafe9..de203fa5 100644 --- a/asyncpraw/config.py +++ b/asyncpraw/config.py @@ -6,6 +6,7 @@ import sys from pathlib import Path from threading import Lock +from typing import Any from .exceptions import ClientException @@ -44,6 +45,7 @@ def _load_config(cls, *, config_interpolation: str | None = None): interpolator_class = cls.INTERPOLATION_LEVEL[config_interpolation]() else: interpolator_class = None + config = configparser.ConfigParser(interpolation=interpolator_class) module_dir = Path(sys.modules[__name__].__file__).parent @@ -96,17 +98,19 @@ def __init__( self._initialize_attributes() - def _fetch(self, key): # noqa: ANN001 + def _fetch(self, key: str) -> Any: value = self.custom[key] del self.custom[key] return value - def _fetch_default(self, key, *, default=None): # noqa: ANN001 + def _fetch_default( + self, key: str, *, default: bool | str | int | None = None + ) -> Any: if key not in self.custom: return default return self._fetch(key) - def _fetch_or_not_set(self, key): # noqa: ANN001 + def _fetch_or_not_set(self, key: str) -> Any | _NotSet: if key in self._settings: # Passed in values have the highest priority return self._fetch(key) diff --git a/asyncpraw/endpoints.py b/asyncpraw/endpoints.py index d1b6a815..1c4f12df 100644 --- a/asyncpraw/endpoints.py +++ b/asyncpraw/endpoints.py @@ -1,5 +1,4 @@ """List of API endpoints PRAW knows about.""" -# flake8: noqa # fmt: off API_PATH = { "about_edited": "r/{subreddit}/about/edited/", diff --git a/asyncpraw/exceptions.py b/asyncpraw/exceptions.py index b28432ae..02131d0e 100644 --- a/asyncpraw/exceptions.py +++ b/asyncpraw/exceptions.py @@ -16,7 +16,7 @@ from .util import _deprecate_args -class AsyncPRAWException(Exception): # noqa: N818 +class AsyncPRAWException(Exception): """The base Async PRAW Exception that all other exception classes extend.""" @@ -27,7 +27,7 @@ class AsyncPRAWException(Exception): # noqa: N818 class ExceptionWrapper: """Wrapper to facilitate showing depreciation for PRAWException class rename.""" - def __getattr__(self, attribute): # noqa: ANN001,ANN204 + def __getattr__(self, attribute: str) -> Any: """Return the value of `attribute`.""" if attribute == "PRAWException": warn( @@ -312,7 +312,7 @@ def __init__( self.items = self.parse_exception_list(items) super().__init__(*self.items) - def _get_old_attr(self, attrname): # noqa: ANN001 + def _get_old_attr(self, attrname: str) -> Any: warn( f"Accessing attribute '{attrname}' through APIException is deprecated." " This behavior will be removed in Async PRAW 8.0. Check out" diff --git a/asyncpraw/models/base.py b/asyncpraw/models/base.py index f1dc1389..a7bf84ac 100644 --- a/asyncpraw/models/base.py +++ b/asyncpraw/models/base.py @@ -13,7 +13,7 @@ class AsyncPRAWBase: @staticmethod def _safely_add_arguments( - *, arguments, key, **new_arguments # noqa: ANN001,ANN003,ANN205 + *, arguments: dict[str, Any], key: str, **new_arguments: Any ): """Replace arguments[key] with a deepcopy and update. @@ -27,7 +27,7 @@ def _safely_add_arguments( arguments[key] = value @classmethod - def parse(cls, data: dict[str, Any], reddit: asyncpraw.Reddit) -> Any: + def parse(cls, data: dict[str, Any], reddit: asyncpraw.Reddit) -> AsyncPRAWBase: """Return an instance of ``cls`` from ``data``. :param data: The structured data. diff --git a/asyncpraw/models/comment_forest.py b/asyncpraw/models/comment_forest.py index 5d13bfeb..31ee0ef8 100644 --- a/asyncpraw/models/comment_forest.py +++ b/asyncpraw/models/comment_forest.py @@ -22,7 +22,11 @@ class CommentForest: """ @staticmethod - def _gather_more_comments(tree, *, parent_tree=None): # noqa: ANN001,ANN205 + def _gather_more_comments( + tree: list[asyncpraw.models.MoreComments], + *, + parent_tree: list[asyncpraw.models.MoreComments] | None = None, + ) -> list[MoreComments]: """Return a list of :class:`.MoreComments` objects obtained from tree.""" more_comments = [] queue = [(None, x) for x in tree] @@ -60,7 +64,7 @@ async def __aiter__(self) -> AsyncIterator[asyncpraw.models.Comment]: for comment in self: yield comment - async def __call__(self): # noqa: ANN204 + async def __call__(self) -> CommentForest: """Return the instance. This method is deprecated and will be removed in a future version. @@ -104,7 +108,7 @@ def __len__(self) -> int: """Return the number of top-level comments in the forest.""" return len(self._comments or []) - def _insert_comment(self, comment): # noqa: ANN001 + def _insert_comment(self, comment: asyncpraw.models.Comment): if comment.name in self._submission._comments_by_id: raise DuplicateReplaceException comment.submission = self._submission @@ -118,7 +122,7 @@ def _insert_comment(self, comment): # noqa: ANN001 parent = self._submission._comments_by_id[comment.parent_id] parent.replies._comments.append(comment) - def _update(self, comments): # noqa: ANN001 + def _update(self, comments: list[asyncpraw.models.Comment]): self._comments = comments for comment in comments: comment.submission = self._submission diff --git a/asyncpraw/models/listing/generator.py b/asyncpraw/models/listing/generator.py index 091bc0a9..9cfb81d8 100644 --- a/asyncpraw/models/listing/generator.py +++ b/asyncpraw/models/listing/generator.py @@ -23,7 +23,7 @@ class ListingGenerator(AsyncPRAWBase, AsyncIterator): """ - def __aiter__(self): # noqa: ANN204 + def __aiter__(self) -> Any: """Permit :class:`.ListingGenerator` to operate as an async iterator.""" return self @@ -68,7 +68,7 @@ def __init__( self.url = url self.yielded = 0 - def _extract_sublist(self, listing): # noqa: ANN001 + def _extract_sublist(self, listing: dict[str, Any] | list[Any]): if isinstance(listing, list): return listing[1] # for submission duplicates if isinstance(listing, dict): @@ -82,7 +82,7 @@ def _extract_sublist(self, listing): # noqa: ANN001 raise ValueError(msg) return listing - async def _next_batch(self): # noqa: ANN001 + async def _next_batch(self): if self._exhausted: raise StopAsyncIteration diff --git a/asyncpraw/models/listing/mixins/base.py b/asyncpraw/models/listing/mixins/base.py index b60c4b86..da1cff94 100644 --- a/asyncpraw/models/listing/mixins/base.py +++ b/asyncpraw/models/listing/mixins/base.py @@ -15,7 +15,7 @@ class BaseListingMixin(AsyncPRAWBase): VALID_TIME_FILTERS = {"all", "day", "hour", "month", "week", "year"} @staticmethod - def _validate_time_filter(time_filter): # noqa: ANN001 + def _validate_time_filter(time_filter: str): """Validate ``time_filter``. :raises: :py:class:`ValueError` if ``time_filter`` is not valid. @@ -28,7 +28,7 @@ def _validate_time_filter(time_filter): # noqa: ANN001 msg = f"'time_filter' must be one of: {valid_time_filters}" raise ValueError(msg) - def _prepare(self, *, arguments, sort): # noqa: ANN001 + 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) diff --git a/asyncpraw/models/mod_notes.py b/asyncpraw/models/mod_notes.py index 28ce28d1..4470f0cb 100644 --- a/asyncpraw/models/mod_notes.py +++ b/asyncpraw/models/mod_notes.py @@ -63,7 +63,7 @@ async def _bulk_generator( for note_dict in response["mod_notes"]: yield self._reddit._objector.objectify(note_dict) - def _ensure_attribute(self, error_message: str, **attributes: Any): # noqa: ANN001 + def _ensure_attribute(self, error_message: str, **attributes: Any) -> Any: attribute, _value = attributes.popitem() value = _value or getattr(self, attribute, None) if value is None: diff --git a/asyncpraw/models/reddit/base.py b/asyncpraw/models/reddit/base.py index c6c76288..ee0c4eed 100644 --- a/asyncpraw/models/reddit/base.py +++ b/asyncpraw/models/reddit/base.py @@ -16,7 +16,7 @@ class RedditBase(AsyncPRAWBase): """Base class that represents actual Reddit objects.""" @staticmethod - def _url_parts(url): # noqa: ANN001,ANN205 + def _url_parts(url: str) -> list[str]: parsed = urlparse(url) if not parsed.netloc: raise InvalidURL(url) @@ -84,12 +84,12 @@ def __str__(self) -> str: async def _fetch(self): # pragma: no cover self._fetched = True - async def _fetch_data(self): # noqa: ANN001 + async def _fetch_data(self): name, fields, params = self._fetch_info() path = API_PATH[name].format(**fields) return await self._reddit.request(method="GET", params=params, path=path) - def _reset_attributes(self, *attributes): # noqa: ANN001,ANN002 + def _reset_attributes(self, *attributes: str): for attribute in attributes: if attribute in self.__dict__: del self.__dict__[attribute] diff --git a/asyncpraw/models/reddit/collections.py b/asyncpraw/models/reddit/collections.py index cdebea27..df19a7bc 100644 --- a/asyncpraw/models/reddit/collections.py +++ b/asyncpraw/models/reddit/collections.py @@ -40,7 +40,7 @@ def __init__(self, reddit: asyncpraw.Reddit, collection_id: str): super().__init__(reddit, _data=None) self.collection_id = collection_id - def _post_fullname(self, post): # noqa: ANN001 + def _post_fullname(self, post: str | asyncpraw.models.Submission) -> str: """Get a post's fullname. :param post: A fullname, a :class:`.Submission`, a permalink, or an ID. @@ -565,7 +565,7 @@ async def _fetch(self): other = type(self)(self._reddit, _data=data) self.__dict__.update(other.__dict__) - self._fetched = True + await super()._fetch() def _fetch_info(self): return "collection", {}, self._info_params diff --git a/asyncpraw/models/reddit/comment.py b/asyncpraw/models/reddit/comment.py index 3c035387..5cb50c01 100644 --- a/asyncpraw/models/reddit/comment.py +++ b/asyncpraw/models/reddit/comment.py @@ -91,7 +91,7 @@ def mod(self) -> asyncpraw.models.reddit.comment.CommentModeration: return CommentModeration(self) @property - def _kind(self): # noqa: ANN001 + def _kind(self): """Return the class's kind.""" return self._reddit.config.kinds["comment"] @@ -209,7 +209,7 @@ async def _fetch(self): comment_data = data["children"][0]["data"] other = type(self)(self._reddit, _data=comment_data) self.__dict__.update(other.__dict__) - self._fetched = True + await super()._fetch() def _fetch_info(self): return "info", {}, {"id": self.fullname} diff --git a/asyncpraw/models/reddit/draft.py b/asyncpraw/models/reddit/draft.py index 163db1fd..8f2aa5fc 100644 --- a/asyncpraw/models/reddit/draft.py +++ b/asyncpraw/models/reddit/draft.py @@ -123,7 +123,7 @@ async def _fetch(self): async for draft in self._reddit.drafts: if draft.id == self.id: self.__dict__.update(draft.__dict__) - self._fetched = True + await super()._fetch() return msg = ( f"The currently authenticated user not have a draft with an ID of {self.id}" diff --git a/asyncpraw/models/reddit/emoji.py b/asyncpraw/models/reddit/emoji.py index 301aa762..d7bf4af7 100644 --- a/asyncpraw/models/reddit/emoji.py +++ b/asyncpraw/models/reddit/emoji.py @@ -57,11 +57,11 @@ def __init__( self.subreddit = subreddit super().__init__(reddit, _data=_data) - async def _fetch(self): # noqa: ANN001 + async def _fetch(self): async for emoji in self.subreddit.emoji: if emoji.name == self.name: self.__dict__.update(emoji.__dict__) - self._fetched = True + await super()._fetch() return msg = f"r/{self.subreddit} does not have the emoji {self.name}" raise ClientException(msg) @@ -239,9 +239,7 @@ async def add( return Emoji(self._reddit, self.subreddit, name) @deprecate_lazy - async def get_emoji( - self, name: str, fetch: bool = True, **kwargs: Any # noqa: ARG002 - ) -> Emoji: + async def get_emoji(self, name: str, fetch: bool = True, **_: Any) -> Emoji: """Return the :class:`.Emoji` for the subreddit named ``name``. :param name: The name of the emoji. diff --git a/asyncpraw/models/reddit/live.py b/asyncpraw/models/reddit/live.py index 5003b8ee..66902f5c 100644 --- a/asyncpraw/models/reddit/live.py +++ b/asyncpraw/models/reddit/live.py @@ -1,7 +1,7 @@ """Provide the LiveThread class.""" from __future__ import annotations -from typing import TYPE_CHECKING, Any, AsyncIterator +from typing import TYPE_CHECKING, Any, AsyncIterator, Iterable from ...const import API_PATH from ...util import _deprecate_args @@ -21,7 +21,7 @@ class LiveContributorRelationship: """Provide methods to interact with live threads' contributors.""" @staticmethod - def _handle_permissions(permissions): # noqa: ANN001,ANN205 + def _handle_permissions(permissions: Iterable[str]) -> str: permissions = {"all"} if permissions is None else set(permissions) return ",".join(f"+{x}" for x in permissions) @@ -384,7 +384,7 @@ async def _fetch(self): data = data["data"] other = type(self)(self._reddit, _data=data) self.__dict__.update(other.__dict__) - self._fetched = True + await super()._fetch() def _fetch_info(self): return "liveabout", {"id": self.id}, None @@ -417,7 +417,7 @@ def discussions( @deprecate_lazy async def get_update( - self, update_id: str, fetch: bool = True, **kwargs: Any # noqa: ARG002 + self, update_id: str, fetch: bool = True, **_: Any ) -> asyncpraw.models.LiveUpdate: """Return a :class:`.LiveUpdate` instance. @@ -826,4 +826,4 @@ async def _fetch(self): response = await self._reddit.get(url) other = response[0] self.__dict__.update(other.__dict__) - self._fetched = True + await super()._fetch() diff --git a/asyncpraw/models/reddit/message.py b/asyncpraw/models/reddit/message.py index 79c57210..104ed4ec 100644 --- a/asyncpraw/models/reddit/message.py +++ b/asyncpraw/models/reddit/message.py @@ -117,7 +117,7 @@ def __init__(self, reddit: asyncpraw.Reddit, _data: dict[str, Any]): async def _fetch(self): message = await self._reddit.inbox.message(self.id) self.__dict__.update(message.__dict__) - self._fetched = True + await super()._fetch() async def delete(self): """Delete the message. diff --git a/asyncpraw/models/reddit/mixins/votable.py b/asyncpraw/models/reddit/mixins/votable.py index bc4dcafc..c49a5755 100644 --- a/asyncpraw/models/reddit/mixins/votable.py +++ b/asyncpraw/models/reddit/mixins/votable.py @@ -7,7 +7,7 @@ class VotableMixin: """Interface for :class:`.RedditBase` classes that can be voted on.""" - async def _vote(self, direction): # noqa: ANN001 + async def _vote(self, direction: int): await self._reddit.post( API_PATH["vote"], data={"dir": str(direction), "id": self.fullname} ) diff --git a/asyncpraw/models/reddit/modmail.py b/asyncpraw/models/reddit/modmail.py index 7ed2460b..4f4f5071 100644 --- a/asyncpraw/models/reddit/modmail.py +++ b/asyncpraw/models/reddit/modmail.py @@ -65,7 +65,7 @@ class ModmailConversation(RedditBase): STR_FIELD = "id" @staticmethod - def _convert_conversation_objects(data, reddit): # noqa: ANN001 + def _convert_conversation_objects(data: dict[str, Any], reddit: asyncpraw.Reddit): """Convert messages and mod actions to Async PRAW objects.""" result = {"messages": [], "modActions": []} for thing in data["objIds"]: @@ -75,7 +75,7 @@ def _convert_conversation_objects(data, reddit): # noqa: ANN001 data.update(result) @staticmethod - def _convert_user_summary(data, reddit): # noqa: ANN001 + def _convert_user_summary(data: dict[str, Any], reddit: asyncpraw.Reddit): """Convert dictionaries of recent user history to Async PRAW objects.""" parsers = { "recentComments": reddit._objector.parsers[reddit.config.kinds["comment"]], @@ -145,7 +145,9 @@ def __init__( self._info_params = {"markRead": True} if mark_read else None - def _build_conversation_list(self, other_conversations): # noqa: ANN001 + def _build_conversation_list( + self, other_conversations: list[ModmailConversation] + ) -> str: """Return a comma-separated list of conversation IDs.""" conversations = [self] + (other_conversations or []) return ",".join(conversation.id for conversation in conversations) @@ -154,7 +156,7 @@ async def _fetch(self): data = await self._fetch_data() other = self._reddit._objector.objectify(data) self.__dict__.update(other.__dict__) - self._fetched = True + await super()._fetch() def _fetch_info(self): return "modmail_conversation", {"id": self.id}, self._info_params @@ -221,7 +223,7 @@ async def mute(self, *, num_days: int = 3): @_deprecate_args("other_conversations") async def read( self, *, other_conversations: list[ModmailConversation] | None = None - ): # noqa: D207, D301 + ): """Mark the conversation(s) as read. :param other_conversations: A list of other conversations to mark (default: @@ -333,7 +335,7 @@ async def unmute(self): @_deprecate_args("other_conversations") async def unread( self, *, other_conversations: list[ModmailConversation] | None = None - ): # noqa: D207, D301 + ): """Mark the conversation(s) as unread. :param other_conversations: A list of other conversations to mark (default: diff --git a/asyncpraw/models/reddit/more.py b/asyncpraw/models/reddit/more.py index 7c0f27e6..40d22fd2 100644 --- a/asyncpraw/models/reddit/more.py +++ b/asyncpraw/models/reddit/more.py @@ -42,7 +42,7 @@ def __repr__(self) -> str: children[-1] = "..." return f"<{self.__class__.__name__} count={self.count}, children={children!r}>" - async def _continue_comments(self, update): # noqa: ANN001 + async def _continue_comments(self, update: bool): assert not self.children, "Please file a bug report with Async PRAW." parent = await self._load_comment(self.parent_id.split("_", 1)[1]) self._comments = parent.replies @@ -51,7 +51,7 @@ async def _continue_comments(self, update): # noqa: ANN001 comment.submission = self.submission return self._comments - async def _load_comment(self, comment_id): # noqa: ANN001 + async def _load_comment(self, comment_id: str): path = f"{API_PATH['submission'].format(id=self.submission.id)}_/{comment_id}" _, comments = await self._reddit.get( path, diff --git a/asyncpraw/models/reddit/multi.py b/asyncpraw/models/reddit/multi.py index 23547126..416fb6e0 100644 --- a/asyncpraw/models/reddit/multi.py +++ b/asyncpraw/models/reddit/multi.py @@ -112,7 +112,7 @@ async def _fetch(self): data = data["data"] other = type(self)(self._reddit, _data=data) self.__dict__.update(other.__dict__) - self._fetched = True + await super()._fetch() def _fetch_info(self): return ( diff --git a/asyncpraw/models/reddit/redditor.py b/asyncpraw/models/reddit/redditor.py index 37cab5a2..1dfb3f55 100644 --- a/asyncpraw/models/reddit/redditor.py +++ b/asyncpraw/models/reddit/redditor.py @@ -187,18 +187,18 @@ async def _fetch(self): data = data["data"] other = type(self)(self._reddit, _data=data) self.__dict__.update(other.__dict__) - self._fetched = True + await super()._fetch() def _fetch_info(self): return "user_about", {"user": self.name}, None - async def _fetch_username(self, fullname): # noqa: ANN001 + async def _fetch_username(self, fullname: str): response = await self._reddit.get( API_PATH["user_by_fullname"], params={"ids": fullname} ) return response[fullname]["name"] - async def _friend(self, *, data, method): # noqa: ANN001 + async def _friend(self, *, data: dict[str:Any], method: str): url = API_PATH["friend_v1"].format(user=self) await self._reddit.request(data=dumps(data), method=method, path=url) diff --git a/asyncpraw/models/reddit/removal_reasons.py b/asyncpraw/models/reddit/removal_reasons.py index 7f3fe901..9aa0d582 100644 --- a/asyncpraw/models/reddit/removal_reasons.py +++ b/asyncpraw/models/reddit/removal_reasons.py @@ -32,9 +32,9 @@ class RemovalReason(RedditBase): STR_FIELD = "id" @staticmethod - def _warn_reason_id( # noqa: ANN205 + 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 @@ -95,7 +95,7 @@ async def _fetch(self): async for removal_reason in self.subreddit.mod.removal_reasons: if removal_reason.id == self.id: self.__dict__.update(removal_reason.__dict__) - self._fetched = True + await super()._fetch() return msg = f"Subreddit {self.subreddit} does not have the removal reason {self.id}" raise ClientException(msg) diff --git a/asyncpraw/models/reddit/rules.py b/asyncpraw/models/reddit/rules.py index a973b3dc..860e2d01 100644 --- a/asyncpraw/models/reddit/rules.py +++ b/asyncpraw/models/reddit/rules.py @@ -94,7 +94,7 @@ async def _fetch(self): async for rule in self.subreddit.rules: if rule.short_name == self.short_name: self.__dict__.update(rule.__dict__) - self._fetched = True + await super()._fetch() return msg = f"Subreddit {self.subreddit} does not have the rule {self.short_name}" raise ClientException(msg) diff --git a/asyncpraw/models/reddit/submission.py b/asyncpraw/models/reddit/submission.py index 938f19a0..b8f716cc 100644 --- a/asyncpraw/models/reddit/submission.py +++ b/asyncpraw/models/reddit/submission.py @@ -3,7 +3,7 @@ import re from json import dumps -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Generator from urllib.parse import urljoin from warnings import warn @@ -650,7 +650,12 @@ def __setattr__(self, attribute: str, value: Any): ) super().__setattr__(attribute, value) - def _chunk(self, *, chunk_size, other_submissions): # noqa: ANN001 + def _chunk( + self, + *, + chunk_size: int, + other_submissions: list[asyncpraw.models.Submission] | None, + ) -> Generator[str, None, None]: all_submissions = [self.fullname] if other_submissions: all_submissions += [x.fullname for x in other_submissions] @@ -748,8 +753,8 @@ async def _fetch(self): submission.comments = CommentForest(self) self.__dict__.update(submission.__dict__) - self._fetched = True self.comments._update(comment_listing.children) + await super()._fetch() async def _fetch_data(self): name, fields, params = self._fetch_info() diff --git a/asyncpraw/models/reddit/subreddit.py b/asyncpraw/models/reddit/subreddit.py index 9da3ca1a..861a1b85 100644 --- a/asyncpraw/models/reddit/subreddit.py +++ b/asyncpraw/models/reddit/subreddit.py @@ -68,7 +68,7 @@ class Modmail: async def __call__( self, id: str | None = None, mark_read: bool = False, fetch: bool = True - ) -> ModmailConversation: # noqa: D207, D301 + ) -> ModmailConversation: """Return an individual conversation. :param id: A reddit base36 conversation ID, e.g., ``"2gmz"``. @@ -195,7 +195,7 @@ def conversations( sort: str | None = None, state: str | None = None, **generator_kwargs: Any, - ) -> AsyncIterator[ModmailConversation]: # noqa: D207, D301 + ) -> AsyncIterator[ModmailConversation]: """Generate :class:`.ModmailConversation` objects for subreddit(s). :param after: A base36 modmail conversation id. When provided, the listing @@ -1237,7 +1237,7 @@ async def update(self, **settings: str | int | bool) -> dict[str, str | int | bo :param allow_polls: Allow users to post polls to the subreddit. :param allow_post_crossposts: Allow users to crosspost submissions from other subreddits. - :param allow_videos: Allow users to upload videos using the native image + :param allow_videos: Allow users to upload videos using the native image hosting. :param collapse_deleted_comments: Collapse deleted and removed comments on comments pages by default. @@ -1286,7 +1286,7 @@ async def update(self, **settings: str | int | bool) -> dict[str, str | int | bo :param submit_text: Text to show on submission page. :param submit_text_label: Custom label for submit text post button (``None`` for default). - :param subreddit_type: One of ``"archived"``, ``"employees_only"``, + :param subreddit_type: One of ``"archived"``, ``"employees_only"``, ``"gold_only"``, ``gold_restricted``, ``"private"``, ``"public"``, or ``"restricted"``. :param suggested_comment_sort: All comment threads will use this sorting method @@ -1436,7 +1436,7 @@ def modmail_conversations( async for message in subreddit.mod.stream.modmail_conversations(): print(f"From: {message.owner}, To: {message.participant}") - """ # noqa: E501 + """ if self.subreddit == "mod": self.subreddit = Subreddit(self.subreddit._reddit, "all") return stream_generator( @@ -2304,9 +2304,7 @@ async def create( return new @deprecate_lazy - async def get_page( - self, page_name: str, fetch: bool = True, **_: Any - ) -> WikiPage: # noqa: ARG002 + async def get_page(self, page_name: str, fetch: bool = True, **_: Any) -> WikiPage: """Return the :class:`.WikiPage` for the :class:`.Subreddit` named ``page_name``. :param page_name: Name of the wikipage. @@ -2403,11 +2401,11 @@ class ModeratorRelationship(SubredditRelationship): } @staticmethod - def _handle_permissions( # noqa: ANN205 + def _handle_permissions( *, other_settings: dict | None = None, permissions: list[str] | None = None, - ): + ) -> dict[str, Any]: other_settings = deepcopy(other_settings) if other_settings else {} other_settings["permissions"] = permissions_string( known_permissions=ModeratorRelationship.PERMISSIONS, permissions=permissions @@ -2761,41 +2759,41 @@ class Subreddit(MessageableMixin, SubredditListingMixin, FullnameMixin, RedditBa @staticmethod async def _create_or_update( *, - _reddit, # noqa: ANN001 - allow_images=None, # noqa: ANN001 - allow_post_crossposts=None, # noqa: ANN001 - allow_top=None, # noqa: ANN001 - collapse_deleted_comments=None, # noqa: ANN001 - comment_score_hide_mins=None, # noqa: ANN001 - description=None, # noqa: ANN001 - domain=None, # noqa: ANN001 - exclude_banned_modqueue=None, # noqa: ANN001 - header_hover_text=None, # noqa: ANN001 - hide_ads=None, # noqa: ANN001 - lang=None, # noqa: ANN001 - key_color=None, # noqa: ANN001 - link_type=None, # noqa: ANN001 - name=None, # noqa: ANN001 - over_18=None, # noqa: ANN001 - public_description=None, # noqa: ANN001 - public_traffic=None, # noqa: ANN001 - show_media=None, # noqa: ANN001 - show_media_preview=None, # noqa: ANN001 - spam_comments=None, # noqa: ANN001 - spam_links=None, # noqa: ANN001 - spam_selfposts=None, # noqa: ANN001 - spoilers_enabled=None, # noqa: ANN001 - sr=None, # noqa: ANN001 - submit_link_label=None, # noqa: ANN001 - submit_text=None, # noqa: ANN001 - submit_text_label=None, # noqa: ANN001 - subreddit_type=None, # noqa: ANN001 - suggested_comment_sort=None, # noqa: ANN001 - title=None, # noqa: ANN001 - wiki_edit_age=None, # noqa: ANN001 - wiki_edit_karma=None, # noqa: ANN001 - wikimode=None, # noqa: ANN001 - **other_settings, # noqa: ANN001,ANN003 + _reddit: asyncpraw.Reddit, + allow_images: bool | None = None, + allow_post_crossposts: bool | None = None, + allow_top: bool | None = None, + collapse_deleted_comments: bool | None = None, + comment_score_hide_mins: int | None = None, + description: str | None = None, + domain: str | None = None, + exclude_banned_modqueue: bool | None = None, + header_hover_text: str | None = None, + hide_ads: bool | None = None, + lang: str | None = None, + key_color: str | None = None, + link_type: str | None = None, + name: str | None = None, + over_18: bool | None = None, + public_description: str | None = None, + public_traffic: bool | None = None, + show_media: bool | None = None, + show_media_preview: bool | None = None, + spam_comments: bool | None = None, + spam_links: bool | None = None, + spam_selfposts: bool | None = None, + spoilers_enabled: bool | None = None, + sr: str | None = None, + submit_link_label: str | None = None, + submit_text: str | None = None, + submit_text_label: str | None = None, + subreddit_type: str | None = None, + suggested_comment_sort: str | None = None, + title: str | None = None, + wiki_edit_age: int | None = None, + wiki_edit_karma: int | None = None, + wikimode: str | None = None, + **other_settings: Any, ): model = { "allow_images": allow_images, @@ -2838,13 +2836,17 @@ async def _create_or_update( await _reddit.post(API_PATH["site_admin"], data=model) @staticmethod - def _subreddit_list(*, other_subreddits, subreddit): # noqa: ANN001,ANN205 + def _subreddit_list( + *, + other_subreddits: list[str | asyncpraw.models.Subreddit], + subreddit: asyncpraw.models.Subreddit, + ) -> str: if other_subreddits: return ",".join([str(subreddit)] + [str(x) for x in other_subreddits]) return str(subreddit) @staticmethod - def _validate_gallery(images): # noqa: ANN001,ANN205 + def _validate_gallery(images: list[dict[str, str]]): for image in images: image_path = image.get("image_path", "") if image_path: @@ -3254,12 +3256,12 @@ async def _fetch(self): data = data["data"] other = type(self)(self._reddit, _data=data) self.__dict__.update(other.__dict__) - self._fetched = True + await super()._fetch() def _fetch_info(self): return "subreddit_about", {"subreddit": self}, None - async def _parse_xml_response(self, response: ClientResponse): # noqa: ANN001 + async def _parse_xml_response(self, response: ClientResponse): """Parse the XML from a response and raise any errors found.""" xml = await response.text() root = XML(xml) @@ -3272,8 +3274,8 @@ async def _parse_xml_response(self, response: ClientResponse): # noqa: ANN001 ) async def _read_and_post_media( - self, media_path, upload_url, upload_data # noqa: ANN001 - ): + self, media_path: str, upload_url: str, upload_data: dict[str, Any] + ) -> ClientResponse: async with aiofiles.open(media_path, "rb") as media: upload_data["file"] = media return await self._reddit._core._requestor._http.post( @@ -3572,7 +3574,7 @@ async def submit( send_replies: bool = True, spoiler: bool = False, url: str | None = None, - ) -> asyncpraw.models.Submission: # noqa: D301 + ) -> asyncpraw.models.Submission: r"""Add a submission to the :class:`.Subreddit`. :param title: The title of the submission. diff --git a/asyncpraw/models/reddit/user_subreddit.py b/asyncpraw/models/reddit/user_subreddit.py index 6a0d63e2..0f548225 100644 --- a/asyncpraw/models/reddit/user_subreddit.py +++ b/asyncpraw/models/reddit/user_subreddit.py @@ -2,7 +2,7 @@ from __future__ import annotations import inspect -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Callable from warnings import warn from ...util.cache import cachedproperty @@ -53,7 +53,7 @@ class UserSubreddit(Subreddit): """ @staticmethod - def _dict_depreciated_wrapper(func): # noqa: ANN001,ANN205 + def _dict_deprecated_wrapper(func: Callable) -> Callable: """Show deprecation notice for dict only methods.""" def wrapper(*args: Any, **kwargs: Any): @@ -123,7 +123,7 @@ def predicate(item: str): setattr( self, name, - self._dict_depreciated_wrapper(getattr(self.__dict__, name)), + self._dict_deprecated_wrapper(getattr(self.__dict__, name)), ) super().__init__(reddit, *args, **kwargs) diff --git a/asyncpraw/models/reddit/wikipage.py b/asyncpraw/models/reddit/wikipage.py index 6f6ab911..774395ab 100644 --- a/asyncpraw/models/reddit/wikipage.py +++ b/asyncpraw/models/reddit/wikipage.py @@ -270,7 +270,7 @@ async def _fetch(self): self._reddit, _data=data["revision_by"]["data"] ) self.__dict__.update(data) - self._fetched = True + await super()._fetch() def _fetch_info(self): return ( diff --git a/asyncpraw/models/subreddits.py b/asyncpraw/models/subreddits.py index 081d0855..c09b708c 100644 --- a/asyncpraw/models/subreddits.py +++ b/asyncpraw/models/subreddits.py @@ -19,7 +19,7 @@ class Subreddits(AsyncPRAWBase): """Subreddits is a Listing class that provides various subreddit lists.""" @staticmethod - def _to_list(subreddit_list): # noqa: ANN001,ANN205 + def _to_list(subreddit_list: list[str | asyncpraw.models.Subreddit]) -> str: return ",".join([str(x) for x in subreddit_list]) def default( diff --git a/asyncpraw/models/util.py b/asyncpraw/models/util.py index b4c64a14..265ee4ba 100644 --- a/asyncpraw/models/util.py +++ b/asyncpraw/models/util.py @@ -15,7 +15,7 @@ def deprecate_lazy(func: Callable) -> Callable[..., Any]: """A decorator used for deprecating the ``lazy`` keyword argument.""" # noqa: D401 @wraps(func) - def wrapper(*args, **kwargs): # noqa: ANN002,ANN003 + def wrapper(*args: Any, **kwargs: Any): if "lazy" in kwargs: kwargs.setdefault("fetch", not kwargs.pop("lazy")) warn( diff --git a/asyncpraw/objector.py b/asyncpraw/objector.py index eeaecfb9..acc94b74 100644 --- a/asyncpraw/objector.py +++ b/asyncpraw/objector.py @@ -60,7 +60,9 @@ def __init__(self, reddit: asyncpraw.Reddit, parsers: dict[str, Any] | None = No self.parsers = {} if parsers is None else parsers self._reddit = reddit - def _objectify_dict(self, data): # noqa: ANN001,PLR0912,PLR0915 + def _objectify_dict( # noqa: PLR0912,PLR0915 + self, data: dict[str:Any] + ) -> RedditBase: """Create :class:`.RedditBase` objects from dicts. :param data: The structured data, assumed to be a dict. diff --git a/asyncpraw/reddit.py b/asyncpraw/reddit.py index 3fbaa09f..e20c2c13 100644 --- a/asyncpraw/reddit.py +++ b/asyncpraw/reddit.py @@ -146,11 +146,11 @@ async def __aenter__(self): # noqa: ANN204 """Handle the context manager open.""" return self - async def __aexit__(self, *_args): + async def __aexit__(self, *_: object): """Handle the context manager close.""" await self.close() - def __deepcopy__(self, memodict=None): # noqa: ANN001,ANN204 + def __deepcopy__(self, memodict: dict[str, Any] | None = None) -> Reddit: """Shallow copy on deepcopy. A shallow copied is performed on deepcopy as @@ -180,7 +180,7 @@ def __enter__(self): # noqa: ANN204 ) return self # pragma: no cover - def __exit__(self, *_args): + def __exit__(self, *_args: object): """Handle the context manager close.""" @_deprecate_args( @@ -199,7 +199,7 @@ def __init__( requestor_kwargs: dict[str, Any] | None = None, token_manager: BaseTokenManager | None = None, **config_settings: str | bool | int | None, - ): # noqa: D207, D301 + ): """Initialize a :class:`.Reddit` instance. :param site_name: The name of a section in your ``praw.ini`` file from which to @@ -576,8 +576,11 @@ async def _objectify_request( ) def _prepare_asyncprawcore( - self, *, requestor_class=None, requestor_kwargs=None # noqa: ANN001 - ): + self, + *, + requestor_class: type[Requestor] = None, + requestor_kwargs: Any | None = None, + ) -> Requestor: requestor_class = requestor_class or Requestor requestor_kwargs = requestor_kwargs or {} @@ -595,7 +598,9 @@ def _prepare_asyncprawcore( return requestor - def _prepare_common_authorizer(self, authenticator): # noqa: ANN001 + def _prepare_common_authorizer( + self, authenticator: asyncprawcore.auth.BaseAuthenticator + ): if self._token_manager is not None: warn( "Token managers have been deprecated and will be removed in the near" @@ -671,7 +676,7 @@ def _prepare_objector(self): } self._objector = Objector(self, mappings) - def _prepare_trusted_asyncprawcore(self, requestor): # noqa: ANN001 + def _prepare_trusted_asyncprawcore(self, requestor: Requestor): authenticator = TrustedAuthenticator( requestor, self.config.client_id, @@ -689,7 +694,7 @@ def _prepare_trusted_asyncprawcore(self, requestor): # noqa: ANN001 else: self._prepare_common_authorizer(authenticator) - def _prepare_untrusted_asyncprawcore(self, requestor): # noqa: ANN001 + def _prepare_untrusted_asyncprawcore(self, requestor: Requestor): authenticator = UntrustedAuthenticator( requestor, self.config.client_id, self.config.redirect_uri ) diff --git a/asyncpraw/util/__init__.py b/asyncpraw/util/__init__.py index 5b789169..064b8ff7 100644 --- a/asyncpraw/util/__init__.py +++ b/asyncpraw/util/__init__.py @@ -1,5 +1,5 @@ """Package imports for utilities.""" -from .cache import cachedproperty # noqa: F401 -from .deprecate_args import _deprecate_args # noqa: F401 -from .snake import camel_to_snake, snake_case_keys # noqa: F401 +from .cache import cachedproperty +from .deprecate_args import _deprecate_args +from .snake import camel_to_snake, snake_case_keys diff --git a/asyncpraw/util/cache.py b/asyncpraw/util/cache.py index bf771b5b..acd77761 100644 --- a/asyncpraw/util/cache.py +++ b/asyncpraw/util/cache.py @@ -22,13 +22,10 @@ class cachedproperty: # noqa: N801 """ # This to make sphinx run properly - # noqa: D102 def __call__(self, *args: Any, **kwargs: Any): # pragma: no cover """Empty method to make sphinx run properly.""" - def __get__( - self, obj: Any | None, objtype: Any | None = None - ) -> Any: # noqa: ANN401 + def __get__(self, obj: Any | None, objtype: Any | None = None) -> Any: """Implement descriptor getter. Calculate the property's value and then store it in the associated object's diff --git a/asyncpraw/util/deprecate_args.py b/asyncpraw/util/deprecate_args.py index 4f7cb291..f11cf436 100644 --- a/asyncpraw/util/deprecate_args.py +++ b/asyncpraw/util/deprecate_args.py @@ -8,8 +8,8 @@ from warnings import warn -def _deprecate_args(*old_args: str): # noqa: ANN001 - def _generate_arg_string(used_args: tuple[str, ...]) -> str: # noqa: ANN001 +def _deprecate_args(*old_args: str) -> Callable: + def _generate_arg_string(used_args: tuple[str, ...]) -> str: used_args = list(map(repr, used_args)) arg_count = len(used_args) arg_string = ( diff --git a/pyproject.toml b/pyproject.toml index 7c716365..17084b40 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,6 +98,7 @@ ignore = [ "D203", # 1 blank line required before class docstring "D213", # Multi-line docstring summary should start at the second line "E501", # line-length + "N818", # exception name should be named with an Error suffix "PLR0913", # too many arguments "PLR2004", # Magic value used in comparison, "S101" # use of assert