Repository: praw-dev/praw
Pull request #2053 (2025-02-11 17:03:39)

Resolve a ton of additional ruff warnings
~There's too many changes here to try to do them atomically.~ I split up the auto-changes into their own commit. I've updated CHANGES.rst for changes which are publicly breaking, and we're not going to go through a deprecation period for these.


Patch:
diff --git a/.coveragerc b/.coveragerc
index b1dd481d..2cfca0d1 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,5 +1,4 @@
 [report]
 exclude_lines =
-    @abstract
     if TYPE_CHECKING:
     pragma: no cover
diff --git a/CHANGES.rst b/CHANGES.rst
index f4edda2f..346eff3e 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -12,12 +12,17 @@ Unreleased
 
 **Changed**
 
-- Bumped prawcore to 3.0.1.
+- Bumped prawcore to 3.0.2.
 - Drop support for Python 3.8, which was end-of-life on 2024-10-07.
 - Change ``Reddit.user.me`` to raise :class:`.ReadOnlyException` when called in
   :attr:`.read_only` mode.
 - The ``subreddit`` attribute of :class:`.Redditor` is a :class:`.UserSubreddit`
   instance.
+- The ``data`` argument to ``Objector.objectify`` must now be passed by keyword.
+- The ``mark_read`` argument to ``subreddit.modmail`` (:class:`.ModmailConversation`)
+  must now be passed by keyword.
+- The ``flair_type`` argument to :class:`.SubredditFlairTemplates` must be passed by
+  keyword.
 
 **Removed**
 
diff --git a/praw/__init__.py b/praw/__init__.py
index 422aa8e1..a68bb6d7 100644
--- a/praw/__init__.py
+++ b/praw/__init__.py
@@ -9,5 +9,5 @@ More information about PRAW can be found at https://github.com/praw-dev/praw.
 
 """
 
-from .const import __version__
-from .reddit import Reddit
+from praw.const import __version__
+from praw.reddit import Reddit
diff --git a/praw/config.py b/praw/config.py
index cf681a83..bdbe4ee0 100644
--- a/praw/config.py
+++ b/praw/config.py
@@ -8,9 +8,10 @@ import importlib.resources
 import os
 from pathlib import Path
 from threading import Lock
+from types import MappingProxyType
 from typing import Any
 
-from .exceptions import ClientException
+from praw.exceptions import ClientException
 
 
 class _NotSet:
@@ -29,19 +30,19 @@ class Config:
     CONFIG = None
     CONFIG_NOT_SET = _NotSet()  # Represents a config value that is not set.
     LOCK = Lock()
-    INTERPOLATION_LEVEL = {
+    INTERPOLATION_LEVEL = MappingProxyType({
         "basic": configparser.BasicInterpolation,
         "extended": configparser.ExtendedInterpolation,
-    }
+    })
 
     @staticmethod
-    def _config_boolean(item: bool | str) -> bool:
+    def _config_boolean(*, item: bool | str) -> bool:
         if isinstance(item, bool):
             return item
         return item.lower() in {"1", "yes", "true", "on"}
 
     @classmethod
-    def _load_config(cls, *, config_interpolation: str | None = None):
+    def _load_config(cls, *, config_interpolation: str | None = None) -> None:
         """Attempt to load settings from various praw.ini files."""
         if config_interpolation is not None:
             interpolator_class = cls.INTERPOLATION_LEVEL[config_interpolation]()
@@ -86,7 +87,7 @@ class Config:
         site_name: str,
         config_interpolation: str | None = None,
         **settings: str,
-    ):
+    ) -> None:
         """Initialize a :class:`.Config` instance."""
         with Config.LOCK:
             if Config.CONFIG is None:
@@ -121,13 +122,13 @@ class Config:
         # Environment variables have higher priority than praw.ini settings
         return env_value or ini_value or self.CONFIG_NOT_SET
 
-    def _initialize_attributes(self):
+    def _initialize_attributes(self) -> None:
         self._short_url = self._fetch_default("short_url") or self.CONFIG_NOT_SET
-        self.check_for_async = self._config_boolean(self._fetch_default("check_for_async", default=True))
-        self.check_for_updates = self._config_boolean(self._fetch_or_not_set("check_for_updates"))
-        self.warn_comment_sort = self._config_boolean(self._fetch_default("warn_comment_sort", default=True))
+        self.check_for_async = self._config_boolean(item=self._fetch_default("check_for_async", default=True))
+        self.check_for_updates = self._config_boolean(item=self._fetch_or_not_set("check_for_updates"))
+        self.warn_comment_sort = self._config_boolean(item=self._fetch_default("warn_comment_sort", default=True))
         self.warn_additional_fetch_params = self._config_boolean(
-            self._fetch_default("warn_additional_fetch_params", default=True)
+            item=self._fetch_default("warn_additional_fetch_params", default=True)
         )
         self.window_size = self._fetch_default("window_size", default=600)
         self.kinds = {
diff --git a/praw/const.py b/praw/const.py
index a7bc9c2c..714e698b 100644
--- a/praw/const.py
+++ b/praw/const.py
@@ -1,6 +1,6 @@
 """PRAW constants."""
 
-from .endpoints import API_PATH  # noqa: F401
+from praw.endpoints import API_PATH  # noqa: F401
 
 __version__ = "7.8.2.dev0"
 
diff --git a/praw/exceptions.py b/praw/exceptions.py
index 05c46452..80677768 100644
--- a/praw/exceptions.py
+++ b/praw/exceptions.py
@@ -11,7 +11,7 @@ All other exceptions are subclassed from :class:`.ClientException`.
 from __future__ import annotations
 
 
-class PRAWException(Exception):
+class PRAWException(Exception):  # noqa: N818
     """The base PRAW Exception that all other exception classes extend."""
 
 
@@ -48,7 +48,7 @@ class RedditErrorItem:
         *,
         field: str | None = None,
         message: str | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.RedditErrorItem` instance.
 
         :param error_type: The error type set on Reddit's end.
@@ -78,7 +78,7 @@ class ClientException(PRAWException):
 class DuplicateReplaceException(ClientException):
     """Indicate exceptions that involve the replacement of :class:`.MoreComments`."""
 
-    def __init__(self):
+    def __init__(self) -> None:
         """Initialize a :class:`.DuplicateReplaceException` instance."""
         super().__init__(
             "A duplicate comment has been detected. Are you attempting to call 'replace_more_comments' more than once?"
@@ -88,7 +88,7 @@ class DuplicateReplaceException(ClientException):
 class InvalidFlairTemplateID(ClientException):
     """Indicate exceptions where an invalid flair template ID is given."""
 
-    def __init__(self, template_id: str):
+    def __init__(self, template_id: str) -> None:
         """Initialize an :class:`.InvalidFlairTemplateID` instance."""
         super().__init__(
             f"The flair template ID '{template_id}' is invalid. If you are trying to"
@@ -99,7 +99,7 @@ class InvalidFlairTemplateID(ClientException):
 class InvalidImplicitAuth(ClientException):
     """Indicate exceptions where an implicit auth type is used incorrectly."""
 
-    def __init__(self):
+    def __init__(self) -> None:
         """Initialize an :class:`.InvalidImplicitAuth` instance."""
         super().__init__("Implicit authorization can only be used with installed apps.")
 
@@ -107,7 +107,7 @@ class InvalidImplicitAuth(ClientException):
 class InvalidURL(ClientException):
     """Indicate exceptions where an invalid URL is entered."""
 
-    def __init__(self, url: str, *, message: str = "Invalid URL: {}"):
+    def __init__(self, url: str, *, message: str = "Invalid URL: {}") -> None:
         """Initialize an :class:`.InvalidURL` instance.
 
         :param url: The invalid URL.
@@ -129,7 +129,7 @@ class ReadOnlyException(ClientException):
 class TooLargeMediaException(ClientException):
     """Indicate exceptions from uploading media that's too large."""
 
-    def __init__(self, *, actual: int, maximum_size: int):
+    def __init__(self, *, actual: int, maximum_size: int) -> None:
         """Initialize a :class:`.TooLargeMediaException` instance.
 
         :param actual: The actual size of the uploaded media.
@@ -146,7 +146,7 @@ class TooLargeMediaException(ClientException):
 class WebSocketException(ClientException):
     """Indicate exceptions caused by use of WebSockets."""
 
-    def __init__(self, message: str):
+    def __init__(self, message: str) -> None:
         """Initialize a :class:`.WebSocketException` instance.
 
         :param message: The exception message.
@@ -158,7 +158,7 @@ class WebSocketException(ClientException):
 class MediaPostFailed(WebSocketException):
     """Indicate exceptions where media uploads failed.."""
 
-    def __init__(self):
+    def __init__(self) -> None:
         """Initialize a :class:`.MediaPostFailed` instance."""
         super().__init__(
             "The attempted media upload action has failed. Possible causes include the"
@@ -188,7 +188,7 @@ class RedditAPIException(PRAWException):
             for exception in exceptions
         ]
 
-    def __init__(self, items: list[RedditErrorItem | list[str] | str]):
+    def __init__(self, items: list[RedditErrorItem | list[str] | str]) -> None:
         """Initialize a :class:`.RedditAPIException` instance.
 
         :param items: Either a list of instances of :class:`.RedditErrorItem` or a list
diff --git a/praw/models/__init__.py b/praw/models/__init__.py
index d363c3da..daf6803c 100644
--- a/praw/models/__init__.py
+++ b/praw/models/__init__.py
@@ -1,38 +1,38 @@
 """Provide the PRAW models."""
 
-from .auth import Auth
-from .front import Front
-from .helpers import DraftHelper, LiveHelper, MultiredditHelper, SubredditHelper
-from .inbox import Inbox
-from .list.draft import DraftList
-from .list.moderated import ModeratedList
-from .list.redditor import RedditorList
-from .list.trophy import TrophyList
-from .listing.domain import DomainListing
-from .listing.generator import ListingGenerator
-from .listing.listing import Listing, ModeratorListing, ModmailConversationsListing
-from .mod_action import ModAction
-from .mod_note import ModNote
-from .mod_notes import RedditModNotes, RedditorModNotes, SubredditModNotes
-from .preferences import Preferences
-from .reddit.collections import Collection
-from .reddit.comment import Comment
-from .reddit.draft import Draft
-from .reddit.emoji import Emoji
-from .reddit.inline_media import InlineGif, InlineImage, InlineMedia, InlineVideo
-from .reddit.live import LiveThread, LiveUpdate
-from .reddit.message import Message, SubredditMessage
-from .reddit.modmail import ModmailAction, ModmailConversation, ModmailMessage
-from .reddit.more import MoreComments
-from .reddit.multi import Multireddit
-from .reddit.poll import PollData, PollOption
-from .reddit.redditor import Redditor
-from .reddit.removal_reasons import RemovalReason
-from .reddit.rules import Rule
-from .reddit.submission import Submission
-from .reddit.subreddit import Subreddit
-from .reddit.user_subreddit import UserSubreddit
-from .reddit.widgets import (
+from praw.models.auth import Auth
+from praw.models.front import Front
+from praw.models.helpers import DraftHelper, LiveHelper, MultiredditHelper, SubredditHelper
+from praw.models.inbox import Inbox
+from praw.models.list.draft import DraftList
+from praw.models.list.moderated import ModeratedList
+from praw.models.list.redditor import RedditorList
+from praw.models.list.trophy import TrophyList
+from praw.models.listing.domain import DomainListing
+from praw.models.listing.generator import ListingGenerator
+from praw.models.listing.listing import Listing, ModeratorListing, ModmailConversationsListing
+from praw.models.mod_action import ModAction
+from praw.models.mod_note import ModNote
+from praw.models.mod_notes import RedditModNotes, RedditorModNotes, SubredditModNotes
+from praw.models.preferences import Preferences
+from praw.models.reddit.collections import Collection
+from praw.models.reddit.comment import Comment
+from praw.models.reddit.draft import Draft
+from praw.models.reddit.emoji import Emoji
+from praw.models.reddit.inline_media import InlineGif, InlineImage, InlineMedia, InlineVideo
+from praw.models.reddit.live import LiveThread, LiveUpdate
+from praw.models.reddit.message import Message, SubredditMessage
+from praw.models.reddit.modmail import ModmailAction, ModmailConversation, ModmailMessage
+from praw.models.reddit.more import MoreComments
+from praw.models.reddit.multi import Multireddit
+from praw.models.reddit.poll import PollData, PollOption
+from praw.models.reddit.redditor import Redditor
+from praw.models.reddit.removal_reasons import RemovalReason
+from praw.models.reddit.rules import Rule
+from praw.models.reddit.submission import Submission
+from praw.models.reddit.subreddit import Subreddit
+from praw.models.reddit.user_subreddit import UserSubreddit
+from praw.models.reddit.widgets import (
     Button,
     ButtonWidget,
     Calendar,
@@ -57,9 +57,9 @@ from .reddit.widgets import (
     Widget,
     WidgetModeration,
 )
-from .reddit.wikipage import WikiPage
-from .redditors import Redditors
-from .stylesheet import Stylesheet
-from .subreddits import Subreddits
-from .trophy import Trophy
-from .user import User
+from praw.models.reddit.wikipage import WikiPage
+from praw.models.redditors import Redditors
+from praw.models.stylesheet import Stylesheet
+from praw.models.subreddits import Subreddits
+from praw.models.trophy import Trophy
+from praw.models.user import User
diff --git a/praw/models/auth.py b/praw/models/auth.py
index 96c1b241..06f01d7c 100644
--- a/praw/models/auth.py
+++ b/praw/models/auth.py
@@ -4,8 +4,8 @@ from __future__ import annotations
 
 from prawcore import Authorizer, ImplicitAuthorizer, UntrustedAuthenticator, session
 
-from ..exceptions import InvalidImplicitAuth, MissingRequiredAttributeException
-from .base import PRAWBase
+from praw.exceptions import InvalidImplicitAuth, MissingRequiredAttributeException
+from praw.models.base import PRAWBase
 
 
 class Auth(PRAWBase):
@@ -48,7 +48,7 @@ class Auth(PRAWBase):
         self._reddit._core = self._reddit._authorized_core = authorized_session
         return authorizer.refresh_token
 
-    def implicit(self, *, access_token: str, expires_in: int, scope: str):
+    def implicit(self, *, access_token: str, expires_in: int, scope: str) -> None:
         """Set the active authorization to be an implicit authorization.
 
         :param access_token: The access_token obtained from Reddit's callback.
diff --git a/praw/models/base.py b/praw/models/base.py
index 5535dde2..92d5d4f7 100644
--- a/praw/models/base.py
+++ b/praw/models/base.py
@@ -5,7 +5,7 @@ from __future__ import annotations
 from copy import deepcopy
 from typing import TYPE_CHECKING, Any
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw
 
 
@@ -13,7 +13,7 @@ class PRAWBase:
     """Superclass for all models in PRAW."""
 
     @staticmethod
-    def _safely_add_arguments(*, arguments: dict[str, Any], key: str, **new_arguments: Any):
+    def _safely_add_arguments(*, arguments: dict[str, Any], key: str, **new_arguments: Any) -> None:
         """Replace arguments[key] with a deepcopy and update.
 
         This method is often called when new parameters need to be added to a request.
@@ -35,7 +35,7 @@ class PRAWBase:
         """
         return cls(reddit, _data=data)
 
-    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any] | None):
+    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any] | None) -> None:
         """Initialize a :class:`.PRAWBase` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
diff --git a/praw/models/comment_forest.py b/praw/models/comment_forest.py
index aee1eb7d..2737abdc 100644
--- a/praw/models/comment_forest.py
+++ b/praw/models/comment_forest.py
@@ -5,10 +5,10 @@ from __future__ import annotations
 from heapq import heappop, heappush
 from typing import TYPE_CHECKING
 
-from ..exceptions import DuplicateReplaceException
-from .reddit.more import MoreComments
+from praw.exceptions import DuplicateReplaceException
+from praw.models.reddit.more import MoreComments
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw.models
 
 
@@ -43,7 +43,7 @@ class CommentForest:
         """Return the number of top-level comments in the forest."""
         return len(self._comments)
 
-    def _insert_comment(self, comment: praw.models.Comment):
+    def _insert_comment(self, comment: praw.models.Comment) -> None:
         if comment.name in self._submission._comments_by_id:
             raise DuplicateReplaceException
         comment.submission = self._submission
@@ -56,7 +56,7 @@ class CommentForest:
             parent = self._submission._comments_by_id[comment.parent_id]
             parent.replies._comments.append(comment)
 
-    def list(  # noqa: A003
+    def list(
         self,
     ) -> list[praw.models.Comment | praw.models.MoreComments]:
         """Return a flattened list of all comments.
@@ -100,7 +100,7 @@ class CommentForest:
         self,
         submission: praw.models.Submission,
         comments: list[praw.models.Comment] | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.CommentForest` instance.
 
         :param submission: An instance of :class:`.Submission` that is the parent of the
@@ -112,7 +112,7 @@ class CommentForest:
         self._comments = comments
         self._submission = submission
 
-    def _update(self, comments: list[praw.models.Comment]):
+    def _update(self, comments: list[praw.models.Comment]) -> None:
         self._comments = comments
         for comment in comments:
             comment.submission = self._submission
@@ -179,7 +179,7 @@ class CommentForest:
         # Fetch largest more_comments until reaching the limit or the threshold
         while more_comments:
             item = heappop(more_comments)
-            if remaining is not None and remaining <= 0 or item.count < threshold:
+            if (remaining is not None and remaining <= 0) or item.count < threshold:
                 skipped.append(item)
                 item._remove_from.remove(item)
                 continue
diff --git a/praw/models/front.py b/praw/models/front.py
index 5743b53f..4db4f0af 100644
--- a/praw/models/front.py
+++ b/praw/models/front.py
@@ -5,10 +5,10 @@ from __future__ import annotations
 from typing import TYPE_CHECKING
 from urllib.parse import urljoin
 
-from .listing.generator import ListingGenerator
-from .listing.mixins import SubredditListingMixin
+from praw.models.listing.generator import ListingGenerator
+from praw.models.listing.mixins import SubredditListingMixin
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     from collections.abc import Iterator
 
     import praw.models
@@ -17,7 +17,7 @@ if TYPE_CHECKING:  # pragma: no cover
 class Front(SubredditListingMixin):
     """Front is a Listing class that represents the front page."""
 
-    def __init__(self, reddit: praw.Reddit):
+    def __init__(self, reddit: praw.Reddit) -> None:
         """Initialize a :class:`.Front` instance."""
         super().__init__(reddit, _data=None)
         self._path = "/"
diff --git a/praw/models/helpers.py b/praw/models/helpers.py
index 5ff79f1b..c2e39942 100644
--- a/praw/models/helpers.py
+++ b/praw/models/helpers.py
@@ -5,14 +5,14 @@ from __future__ import annotations
 from json import dumps
 from typing import TYPE_CHECKING, Any
 
-from ..const import API_PATH
-from .base import PRAWBase
-from .reddit.draft import Draft
-from .reddit.live import LiveThread
-from .reddit.multi import Multireddit, Subreddit
+from praw.const import API_PATH
+from praw.models.base import PRAWBase
+from praw.models.reddit.draft import Draft
+from praw.models.reddit.live import LiveThread
+from praw.models.reddit.multi import Multireddit, Subreddit
 
-if TYPE_CHECKING:  # pragma: no cover
-    from collections.abc import Generator
+if TYPE_CHECKING:
+    from collections.abc import Iterator
 
     import praw.models
 
@@ -156,7 +156,7 @@ class LiveHelper(PRAWBase):
         *,
         description: str | None = None,
         nsfw: bool = False,
-        resources: str = None,
+        resources: str | None = None,
     ) -> praw.models.LiveThread:
         """Create a new :class:`.LiveThread`.
 
@@ -180,7 +180,7 @@ class LiveHelper(PRAWBase):
             },
         )
 
-    def info(self, ids: list[str]) -> Generator[praw.models.LiveThread, None, None]:
+    def info(self, ids: list[str]) -> Iterator[praw.models.LiveThread]:
         """Fetch information about each live thread in ``ids``.
 
         :param ids: A list of IDs for a live thread.
@@ -213,7 +213,7 @@ class LiveHelper(PRAWBase):
             msg = "ids must be a list"
             raise TypeError(msg)
 
-        def generator():
+        def generator() -> Iterator[praw.models.LiveThread]:
             for position in range(0, len(ids), 100):
                 ids_chunk = ids[position : position + 100]
                 url = API_PATH["live_info"].format(ids=",".join(ids_chunk))
diff --git a/praw/models/inbox.py b/praw/models/inbox.py
index 3e97e15a..9ab4530b 100644
--- a/praw/models/inbox.py
+++ b/praw/models/inbox.py
@@ -4,12 +4,12 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING
 
-from ..const import API_PATH
-from .base import PRAWBase
-from .listing.generator import ListingGenerator
-from .util import stream_generator
+from praw.const import API_PATH
+from praw.models.base import PRAWBase
+from praw.models.listing.generator import ListingGenerator
+from praw.models.util import stream_generator
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     from collections.abc import Iterator
 
     import praw.models
@@ -18,7 +18,7 @@ if TYPE_CHECKING:  # pragma: no cover
 class Inbox(PRAWBase):
     """Inbox is a Listing class that represents the inbox."""
 
-    def all(  # noqa: A003
+    def all(
         self, **generator_kwargs: str | int | dict[str, str]
     ) -> Iterator[praw.models.Message | praw.models.Comment]:
         """Return a :class:`.ListingGenerator` for all inbox comments and messages.
@@ -36,7 +36,7 @@ class Inbox(PRAWBase):
         """
         return ListingGenerator(self._reddit, API_PATH["inbox"], **generator_kwargs)
 
-    def collapse(self, items: list[praw.models.Message]):
+    def collapse(self, items: list[praw.models.Message]) -> None:
         """Mark an inbox message as collapsed.
 
         :param items: A list containing instances of :class:`.Message`.
@@ -81,7 +81,7 @@ class Inbox(PRAWBase):
         """
         return ListingGenerator(self._reddit, API_PATH["comment_replies"], **generator_kwargs)
 
-    def mark_all_read(self):
+    def mark_all_read(self) -> None:
         """Mark all messages as read with just one API call.
 
         Example usage:
@@ -98,7 +98,7 @@ class Inbox(PRAWBase):
         """
         self._reddit.post(API_PATH["read_all_messages"])
 
-    def mark_read(self, items: list[praw.models.Comment | praw.models.Message]):
+    def mark_read(self, items: list[praw.models.Comment | praw.models.Message]) -> None:
         """Mark Comments or Messages as read.
 
         :param items: A list containing instances of :class:`.Comment` and/or
@@ -130,7 +130,7 @@ class Inbox(PRAWBase):
             self._reddit.post(API_PATH["read_message"], data=data)
             items = items[25:]
 
-    def mark_unread(self, items: list[praw.models.Comment | praw.models.Message]):
+    def mark_unread(self, items: list[praw.models.Comment | praw.models.Message]) -> None:
         """Unmark Comments or Messages as read.
 
         :param items: A list containing instances of :class:`.Comment` and/or
@@ -189,7 +189,7 @@ class Inbox(PRAWBase):
 
         """
         listing = self._reddit.get(API_PATH["message"].format(id=message_id))
-        messages = {message.fullname: message for message in [listing[0]] + listing[0].replies}
+        messages = {message.fullname: message for message in [listing[0], *listing[0].replies]}
         for _fullname, message in messages.items():
             message.parent = messages.get(message.parent_id, None)
         return messages[f"t4_{message_id.lower()}"]
@@ -262,7 +262,7 @@ class Inbox(PRAWBase):
         """
         return ListingGenerator(self._reddit, API_PATH["submission_replies"], **generator_kwargs)
 
-    def uncollapse(self, items: list[praw.models.Message]):
+    def uncollapse(self, items: list[praw.models.Message]) -> None:
         """Mark an inbox message as uncollapsed.
 
         :param items: A list containing instances of :class:`.Message`.
@@ -295,7 +295,7 @@ class Inbox(PRAWBase):
         self,
         *,
         mark_read: bool = False,
-        **generator_kwargs: str | int | dict[str, str],
+        **generator_kwargs: str | int | dict[str, str] | None,
     ) -> Iterator[praw.models.Comment | praw.models.Message]:
         """Return a :class:`.ListingGenerator` for unread comments and messages.
 
diff --git a/praw/models/list/base.py b/praw/models/list/base.py
index b8f7bb29..27b6635d 100644
--- a/praw/models/list/base.py
+++ b/praw/models/list/base.py
@@ -4,9 +4,9 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, Any
 
-from ..base import PRAWBase
+from praw.models.base import PRAWBase
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     from collections.abc import Iterator
 
     import praw
@@ -25,7 +25,7 @@ class BaseList(PRAWBase):
         """Return the item at position index in the list."""
         return getattr(self, self.CHILD_ATTRIBUTE)[index]
 
-    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]):
+    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]) -> None:
         """Initialize a :class:`.BaseList` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
@@ -39,7 +39,7 @@ class BaseList(PRAWBase):
 
         child_list = getattr(self, self.CHILD_ATTRIBUTE)
         for index, item in enumerate(child_list):
-            child_list[index] = reddit._objector.objectify(item)
+            child_list[index] = reddit._objector.objectify(data=item)
 
     def __iter__(self) -> Iterator[Any]:
         """Return an iterator to the list."""
diff --git a/praw/models/list/draft.py b/praw/models/list/draft.py
index 1bdc6bad..06b2bc05 100644
--- a/praw/models/list/draft.py
+++ b/praw/models/list/draft.py
@@ -1,6 +1,6 @@
 """Provide the DraftList class."""
 
-from .base import BaseList
+from praw.models.list.base import BaseList
 
 
 class DraftList(BaseList):
diff --git a/praw/models/list/moderated.py b/praw/models/list/moderated.py
index d33960f4..c6e58a45 100644
--- a/praw/models/list/moderated.py
+++ b/praw/models/list/moderated.py
@@ -1,6 +1,6 @@
 """Provide the ModeratedList class."""
 
-from .base import BaseList
+from praw.models.list.base import BaseList
 
 
 class ModeratedList(BaseList):
diff --git a/praw/models/list/redditor.py b/praw/models/list/redditor.py
index a94e9b00..8d1af0e5 100644
--- a/praw/models/list/redditor.py
+++ b/praw/models/list/redditor.py
@@ -1,6 +1,6 @@
 """Provide the RedditorList class."""
 
-from .base import BaseList
+from praw.models.list.base import BaseList
 
 
 class RedditorList(BaseList):
diff --git a/praw/models/list/trophy.py b/praw/models/list/trophy.py
index ff6a734c..bc5245e3 100644
--- a/praw/models/list/trophy.py
+++ b/praw/models/list/trophy.py
@@ -1,6 +1,6 @@
 """Provide the TrophyList class."""
 
-from .base import BaseList
+from praw.models.list.base import BaseList
 
 
 class TrophyList(BaseList):
diff --git a/praw/models/listing/domain.py b/praw/models/listing/domain.py
index ea1aaef9..34ff67ed 100644
--- a/praw/models/listing/domain.py
+++ b/praw/models/listing/domain.py
@@ -4,17 +4,17 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING
 
-from ...const import API_PATH
-from .mixins import BaseListingMixin, RisingListingMixin
+from praw.const import API_PATH
+from praw.models.listing.mixins import BaseListingMixin, RisingListingMixin
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw
 
 
 class DomainListing(BaseListingMixin, RisingListingMixin):
     """Provide a set of functions to interact with domain listings."""
 
-    def __init__(self, reddit: praw.Reddit, domain: str):
+    def __init__(self, reddit: praw.Reddit, domain: str) -> None:
         """Initialize a :class:`.DomainListing` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
diff --git a/praw/models/listing/generator.py b/praw/models/listing/generator.py
index 50dd07ec..3074e53a 100644
--- a/praw/models/listing/generator.py
+++ b/praw/models/listing/generator.py
@@ -6,11 +6,12 @@ from collections.abc import Iterator
 from copy import deepcopy
 from typing import TYPE_CHECKING, Any
 
-from ..base import PRAWBase
-from .listing import FlairListing, ModNoteListing
+from praw.models.base import PRAWBase
+from praw.models.listing.listing import FlairListing, Listing, ModNoteListing
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw
+    from praw.models.reddit.base import RedditBase
 
 
 class ListingGenerator(PRAWBase, Iterator):
@@ -31,7 +32,7 @@ class ListingGenerator(PRAWBase, Iterator):
         url: str,
         limit: int = 100,
         params: dict[str, str | int] | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.ListingGenerator` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
@@ -47,30 +48,31 @@ class ListingGenerator(PRAWBase, Iterator):
         super().__init__(reddit, _data=None)
         self._exhausted = False
         self._listing = None
-        self._list_index = None
+        self._list_index: int
         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:
+    def __iter__(self) -> ListingGenerator:
         """Permit :class:`.ListingGenerator` to operate as an iterator."""
         return self
 
-    def __next__(self) -> Any:
+    def __next__(self) -> RedditBase:
         """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()
+        assert self._listing is not None
 
         self._list_index += 1
         self.yielded += 1
         return self._listing[self._list_index - 1]
 
-    def _extract_sublist(self, listing: dict[str, Any] | list[Any]):
+    def _extract_sublist(self, listing: dict[str, Any] | list[Listing]) -> Listing:
         if isinstance(listing, list):
             return listing[1]  # for submission duplicates
         if isinstance(listing, dict):
@@ -84,7 +86,7 @@ class ListingGenerator(PRAWBase, Iterator):
                 raise ValueError(msg)
         return listing
 
-    def _next_batch(self):
+    def _next_batch(self) -> None:
         if self._exhausted:
             raise StopIteration
 
diff --git a/praw/models/listing/listing.py b/praw/models/listing/listing.py
index 9ea4929f..f37de3d4 100644
--- a/praw/models/listing/listing.py
+++ b/praw/models/listing/listing.py
@@ -2,14 +2,20 @@
 
 from __future__ import annotations
 
-from typing import Any
+from typing import TYPE_CHECKING, Any
 
-from ..base import PRAWBase
+from praw.models.base import PRAWBase
+
+if TYPE_CHECKING:
+    from praw.models.reddit.base import RedditBase
 
 
 class Listing(PRAWBase):
     """A listing is a collection of :class:`.RedditBase` instances."""
 
+    if TYPE_CHECKING:
+        after: Any
+
     AFTER_PARAM = "after"
     CHILD_ATTRIBUTE = "children"
 
@@ -21,10 +27,10 @@ class Listing(PRAWBase):
         """Return the number of items in the Listing."""
         return len(getattr(self, self.CHILD_ATTRIBUTE))
 
-    def __setattr__(self, attribute: str, value: Any):
+    def __setattr__(self, attribute: str, value: Any) -> None:
         """Objectify the ``CHILD_ATTRIBUTE`` attribute."""
         if attribute == self.CHILD_ATTRIBUTE:
-            value = self._reddit._objector.objectify(value)
+            value = self._reddit._objector.objectify(data=value)
         super().__setattr__(attribute, value)
 
 
@@ -64,6 +70,9 @@ class ModmailConversationsListing(Listing):
 
     CHILD_ATTRIBUTE = "conversations"
 
+    if TYPE_CHECKING:
+        conversations: list[RedditBase]
+
     @property
     def after(self) -> str | None:
         """Return the next attribute or ``None``."""
diff --git a/praw/models/listing/mixins/__init__.py b/praw/models/listing/mixins/__init__.py
index 06fb5b38..ce5174c9 100644
--- a/praw/models/listing/mixins/__init__.py
+++ b/praw/models/listing/mixins/__init__.py
@@ -1,7 +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
+from praw.models.listing.mixins.base import BaseListingMixin
+from praw.models.listing.mixins.redditor import RedditorListingMixin
+from praw.models.listing.mixins.rising import RisingListingMixin
+from praw.models.listing.mixins.submission import SubmissionListingMixin
+from praw.models.listing.mixins.subreddit import SubredditListingMixin
diff --git a/praw/models/listing/mixins/base.py b/praw/models/listing/mixins/base.py
index bcc71fdb..ee5398ec 100644
--- a/praw/models/listing/mixins/base.py
+++ b/praw/models/listing/mixins/base.py
@@ -5,8 +5,8 @@ from __future__ import annotations
 from typing import TYPE_CHECKING, Any
 from urllib.parse import urljoin
 
-from ...base import PRAWBase
-from ..generator import ListingGenerator
+from praw.models.base import PRAWBase
+from praw.models.listing.generator import ListingGenerator
 
 if TYPE_CHECKING:
     from collections.abc import Iterator
@@ -15,10 +15,10 @@ if TYPE_CHECKING:
 class BaseListingMixin(PRAWBase):
     """Adds minimum set of methods that apply to all listing objects."""
 
-    VALID_TIME_FILTERS = {"all", "day", "hour", "month", "week", "year"}
+    VALID_TIME_FILTERS = frozenset({"all", "day", "hour", "month", "week", "year"})
 
     @staticmethod
-    def _validate_time_filter(time_filter: str):
+    def _validate_time_filter(time_filter: str) -> None:
         """Validate ``time_filter``.
 
         :raises: :py:class:`ValueError` if ``time_filter`` is not valid.
diff --git a/praw/models/listing/mixins/redditor.py b/praw/models/listing/mixins/redditor.py
index 2ef80761..5b93b1fd 100644
--- a/praw/models/listing/mixins/redditor.py
+++ b/praw/models/listing/mixins/redditor.py
@@ -5,11 +5,11 @@ from __future__ import annotations
 from typing import TYPE_CHECKING
 from urllib.parse import urljoin
 
-from ....util.cache import cachedproperty
-from ..generator import ListingGenerator
-from .base import BaseListingMixin
+from praw.models.listing.generator import ListingGenerator
+from praw.models.listing.mixins.base import BaseListingMixin
+from praw.util.cache import cachedproperty
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     from collections.abc import Iterator
 
     import praw.models
@@ -18,7 +18,7 @@ if TYPE_CHECKING:  # pragma: no cover
 class SubListing(BaseListingMixin):
     """Helper class for generating :class:`.ListingGenerator` objects."""
 
-    def __init__(self, reddit: praw.Reddit, base_path: str, subpath: str):
+    def __init__(self, reddit: praw.Reddit, base_path: str, subpath: str) -> None:
         """Initialize a :class:`.SubListing` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
diff --git a/praw/models/listing/mixins/rising.py b/praw/models/listing/mixins/rising.py
index 2d7ef313..e8a84c02 100644
--- a/praw/models/listing/mixins/rising.py
+++ b/praw/models/listing/mixins/rising.py
@@ -5,10 +5,10 @@ from __future__ import annotations
 from typing import TYPE_CHECKING
 from urllib.parse import urljoin
 
-from ...base import PRAWBase
-from ..generator import ListingGenerator
+from praw.models.base import PRAWBase
+from praw.models.listing.generator import ListingGenerator
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     from collections.abc import Iterator
 
     import praw.models
diff --git a/praw/models/listing/mixins/submission.py b/praw/models/listing/mixins/submission.py
index 29710dde..73a7f052 100644
--- a/praw/models/listing/mixins/submission.py
+++ b/praw/models/listing/mixins/submission.py
@@ -4,11 +4,11 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING
 
-from ....const import API_PATH
-from ...base import PRAWBase
-from ..generator import ListingGenerator
+from praw.const import API_PATH
+from praw.models.base import PRAWBase
+from praw.models.listing.generator import ListingGenerator
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     from collections.abc import Iterator
 
     import praw.models
diff --git a/praw/models/listing/mixins/subreddit.py b/praw/models/listing/mixins/subreddit.py
index 6ebabb0d..a9a799c4 100644
--- a/praw/models/listing/mixins/subreddit.py
+++ b/praw/models/listing/mixins/subreddit.py
@@ -5,13 +5,13 @@ from __future__ import annotations
 from typing import TYPE_CHECKING, Any
 from urllib.parse import urljoin
 
-from ....util.cache import cachedproperty
-from ...base import PRAWBase
-from ..generator import ListingGenerator
-from .base import BaseListingMixin
-from .rising import RisingListingMixin
+from praw.models.base import PRAWBase
+from praw.models.listing.generator import ListingGenerator
+from praw.models.listing.mixins.base import BaseListingMixin
+from praw.models.listing.mixins.rising import RisingListingMixin
+from praw.util.cache import cachedproperty
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     from collections.abc import Iterator
 
     import praw.models
@@ -40,7 +40,7 @@ class CommentHelper(PRAWBase):
         """
         return ListingGenerator(self._reddit, self._path, **generator_kwargs)
 
-    def __init__(self, subreddit: praw.models.Subreddit | SubredditListingMixin):
+    def __init__(self, subreddit: praw.models.Subreddit | SubredditListingMixin) -> None:
         """Initialize a :class:`.CommentHelper` instance."""
         super().__init__(subreddit._reddit, _data=None)
         self.subreddit = subreddit
@@ -64,7 +64,7 @@ class SubredditListingMixin(BaseListingMixin, RisingListingMixin):
         """
         return CommentHelper(self)
 
-    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any] | None):
+    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any] | None) -> None:
         """Initialize a :class:`.SubredditListingMixin` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
diff --git a/praw/models/mod_action.py b/praw/models/mod_action.py
index 9730445b..f36944f2 100644
--- a/praw/models/mod_action.py
+++ b/praw/models/mod_action.py
@@ -4,9 +4,9 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING
 
-from .base import PRAWBase
+from praw.models.base import PRAWBase
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw.models
 
 
@@ -19,5 +19,5 @@ class ModAction(PRAWBase):
         return self._reddit.redditor(self._mod)
 
     @mod.setter
-    def mod(self, value: str | praw.models.Redditor):
+    def mod(self, value: str | praw.models.Redditor) -> None:
         self._mod = value
diff --git a/praw/models/mod_note.py b/praw/models/mod_note.py
index bcbf8293..23bdf54a 100644
--- a/praw/models/mod_note.py
+++ b/praw/models/mod_note.py
@@ -2,8 +2,8 @@
 
 from __future__ import annotations
 
-from ..endpoints import API_PATH
-from .base import PRAWBase
+from praw.endpoints import API_PATH
+from praw.models.base import PRAWBase
 
 
 class ModNote(PRAWBase):
@@ -57,7 +57,7 @@ class ModNote(PRAWBase):
         """Return the hash of the current instance."""
         return hash(self.__class__.__name__) ^ hash(self.id)
 
-    def delete(self):
+    def delete(self) -> None:
         """Delete this note.
 
         For example, to delete the last note for u/spez from r/test, try:
diff --git a/praw/models/mod_notes.py b/praw/models/mod_notes.py
index 0942b13a..638bdf3e 100644
--- a/praw/models/mod_notes.py
+++ b/praw/models/mod_notes.py
@@ -5,19 +5,18 @@ from __future__ import annotations
 from itertools import islice
 from typing import TYPE_CHECKING, Any
 
-from ..const import API_PATH
-from .base import PRAWBase
-from .listing.generator import ListingGenerator
-from .reddit.comment import Comment
-from .reddit.submission import Submission
+from praw.const import API_PATH
+from praw.models.base import PRAWBase
+from praw.models.listing.generator import ListingGenerator
+from praw.models.reddit.comment import Comment
+from praw.models.reddit.submission import Submission
 
-if TYPE_CHECKING:  # pragma: no cover
-    from collections.abc import Generator
+if TYPE_CHECKING:
+    from collections.abc import Iterator
 
     import praw.models
-
-    from .reddit.redditor import Redditor
-    from .reddit.subreddit import Subreddit
+    from praw.models.reddit.redditor import Redditor
+    from praw.models.reddit.subreddit import Subreddit
 
 
 class BaseModNotes:
@@ -26,7 +25,7 @@ class BaseModNotes:
     def __init__(
         self,
         reddit: praw.Reddit,
-    ):
+    ) -> None:
         """Initialize a :class:`.BaseModNotes` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
@@ -39,7 +38,7 @@ class BaseModNotes:
         redditor: Redditor | str,
         subreddit: Subreddit | str,
         **generator_kwargs: Any,
-    ):
+    ) -> ListingGenerator:
         PRAWBase._safely_add_arguments(
             arguments=generator_kwargs,
             key="params",
@@ -50,7 +49,7 @@ class BaseModNotes:
 
     def _bulk_generator(
         self, redditors: list[Redditor | str], subreddits: list[Subreddit | str]
-    ) -> Generator[praw.models.ModNote, None, None]:
+    ) -> Iterator[praw.models.ModNote]:
         subreddits_iter = iter(subreddits)
         redditors_iter = iter(redditors)
         while True:
@@ -64,22 +63,23 @@ class BaseModNotes:
             }
             response = self._reddit.get(API_PATH["mod_notes_bulk"], params=params)
             for note_dict in response["mod_notes"]:
-                yield self._reddit._objector.objectify(note_dict)
+                yield self._reddit._objector.objectify(data=note_dict)
 
     def _ensure_attribute(self, error_message: str, **attributes: Any) -> Any:
-        attribute, _value = attributes.popitem()
-        value = _value or getattr(self, attribute, None)
+        attribute, value_ = attributes.popitem()
+        value = value_ or getattr(self, attribute, None)
         if value is None:
             raise TypeError(error_message)
         return value
 
     def _notes(
         self,
+        *,
         all_notes: bool,
         redditors: list[Redditor | str],
         subreddits: list[Subreddit | str],
         **generator_kwargs: Any,
-    ) -> Generator[praw.models.ModNote, None, None]:
+    ) -> Iterator[praw.models.ModNote]:
         if all_notes:
             for subreddit in subreddits:
                 for redditor in redditors:
@@ -187,7 +187,7 @@ class BaseModNotes:
         note_id: str | None = None,
         redditor: Redditor | str | None = None,
         subreddit: Subreddit | str | None = None,
-    ):
+    ) -> None:
         """Delete note(s) for a redditor.
 
         :param delete_all: When ``True``, delete all notes for the specified redditor in
@@ -260,7 +260,7 @@ class BaseModNotes:
             msg = "Either 'note_id' or 'delete_all' must be provided."
             raise TypeError(msg)
         if delete_all:
-            for note in self._notes(True, [redditor], [subreddit]):
+            for note in self._notes(all_notes=True, redditors=[redditor], subreddits=[subreddit]):
                 note.delete()
         else:
             params = {
@@ -289,7 +289,7 @@ class RedditorModNotes(BaseModNotes):
 
     """
 
-    def __init__(self, reddit: praw.Reddit, redditor: Redditor | str):
+    def __init__(self, reddit: praw.Reddit, redditor: Redditor | str) -> None:
         """Initialize a :class:`.RedditorModNotes` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
@@ -304,7 +304,7 @@ class RedditorModNotes(BaseModNotes):
         *subreddits: Subreddit | str,
         all_notes: bool | None = None,
         **generator_kwargs: Any,
-    ) -> Generator[praw.models.ModNote, None, None]:
+    ) -> Iterator[praw.models.ModNote]:
         """Return notes for this :class:`.Redditor` from one or more subreddits.
 
         :param subreddits: One or more subreddits to retrieve the notes from. Must be
@@ -360,9 +360,9 @@ class RedditorModNotes(BaseModNotes):
         if all_notes is None:
             all_notes = len(subreddits) == 1
         return self._notes(
-            all_notes,
-            [self.redditor] * len(subreddits),
-            list(subreddits),
+            all_notes=all_notes,
+            redditors=[self.redditor] * len(subreddits),
+            subreddits=list(subreddits),
             **generator_kwargs,
         )
 
@@ -385,7 +385,7 @@ class SubredditModNotes(BaseModNotes):
 
     """
 
-    def __init__(self, reddit: praw.Reddit, subreddit: Subreddit | str):
+    def __init__(self, reddit: praw.Reddit, subreddit: Subreddit | str) -> None:
         """Initialize a :class:`.SubredditModNotes` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
@@ -400,7 +400,7 @@ class SubredditModNotes(BaseModNotes):
         *redditors: Redditor | str,
         all_notes: bool | None = None,
         **generator_kwargs: Any,
-    ) -> Generator[praw.models.ModNote, None, None]:
+    ) -> Iterator[praw.models.ModNote]:
         """Return notes from this :class:`.Subreddit` for one or more redditors.
 
         :param redditors: One or more redditors to retrieve notes for. Must be either a
@@ -456,9 +456,9 @@ class SubredditModNotes(BaseModNotes):
         if all_notes is None:
             all_notes = len(redditors) == 1
         return self._notes(
-            all_notes,
-            list(redditors),
-            [self.subreddit] * len(redditors),
+            all_notes=all_notes,
+            redditors=list(redditors),
+            subreddits=[self.subreddit] * len(redditors),
             **generator_kwargs,
         )
 
@@ -494,7 +494,7 @@ class RedditModNotes(BaseModNotes):
         subreddits: list[Subreddit | str] | None = None,
         things: list[Comment | Submission] | None = None,
         **generator_kwargs: Any,
-    ) -> Generator[praw.models.ModNote, None, None]:
+    ) -> Iterator[praw.models.ModNote]:
         """Get note(s) for each subreddit/user pair, or ``None`` if they don't have any.
 
         :param all_notes: Whether to return all notes or only the latest note for each
@@ -626,15 +626,17 @@ class RedditModNotes(BaseModNotes):
                 merged_subreddits.append(subreddit)
             else:
                 msg = f"Cannot get subreddit and author fields from type {type(item)}"
-                raise ValueError(msg)
-        return self._notes(all_notes, merged_redditors, merged_subreddits, **generator_kwargs)
+                raise TypeError(msg)
+        return self._notes(
+            all_notes=all_notes, redditors=merged_redditors, subreddits=merged_subreddits, **generator_kwargs
+        )
 
     def things(
         self,
         *things: Comment | Submission,
         all_notes: bool | None = None,
         **generator_kwargs: Any,
-    ) -> Generator[praw.models.ModNote, None, None]:
+    ) -> Iterator[praw.models.ModNote]:
         """Return notes associated with the author of a :class:`.Comment` or :class:`.Submission`.
 
         :param things: One or more things to return notes on. Must be a
@@ -677,4 +679,4 @@ class RedditModNotes(BaseModNotes):
             redditors.append(thing.author)
         if all_notes is None:
             all_notes = len(things) == 1
-        return self._notes(all_notes, redditors, subreddits, **generator_kwargs)
+        return self._notes(all_notes=all_notes, redditors=redditors, subreddits=subreddits, **generator_kwargs)
diff --git a/praw/models/preferences.py b/praw/models/preferences.py
index 45330ca8..67a25a12 100644
--- a/praw/models/preferences.py
+++ b/praw/models/preferences.py
@@ -5,9 +5,9 @@ from __future__ import annotations
 from json import dumps
 from typing import TYPE_CHECKING
 
-from ..const import API_PATH
+from praw.const import API_PATH
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw
 
 
@@ -35,7 +35,7 @@ class Preferences:
         """
         return self._reddit.get(API_PATH["preferences"])
 
-    def __init__(self, reddit: praw.Reddit):
+    def __init__(self, reddit: praw.Reddit) -> None:
         """Initialize a :class:`.Preferences` instance.
 
         :param reddit: The :class:`.Reddit` instance.
diff --git a/praw/models/reddit/base.py b/praw/models/reddit/base.py
index 3a388dbc..d66c1fe7 100644
--- a/praw/models/reddit/base.py
+++ b/praw/models/reddit/base.py
@@ -5,11 +5,11 @@ from __future__ import annotations
 from typing import TYPE_CHECKING, Any
 from urllib.parse import urlparse
 
-from ...endpoints import API_PATH
-from ...exceptions import InvalidURL
-from ..base import PRAWBase
+from praw.endpoints import API_PATH
+from praw.exceptions import InvalidURL
+from praw.models.base import PRAWBase
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw
 
 
@@ -45,10 +45,11 @@ class RedditBase(PRAWBase):
         self,
         reddit: praw.Reddit,
         _data: dict[str, Any] | None,
+        *,
         _extra_attribute_to_check: str | None = None,
         _fetched: bool = False,
         _str_field: bool = True,
-    ):
+    ) -> None:
         """Initialize a :class:`.RedditBase` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
@@ -74,15 +75,15 @@ class RedditBase(PRAWBase):
         """Return a string representation of the instance."""
         return getattr(self, self.STR_FIELD)
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         self._fetched = True
 
-    def _fetch_data(self):
+    def _fetch_data(self) -> Any:
         name, fields, params = self._fetch_info()
         path = API_PATH[name].format(**fields)
         return self._reddit.request(method="GET", params=params, path=path)
 
-    def _reset_attributes(self, *attributes: str):
+    def _reset_attributes(self, *attributes: str) -> None:
         for attribute in attributes:
             if attribute in self.__dict__:
                 del self.__dict__[attribute]
diff --git a/praw/models/reddit/collections.py b/praw/models/reddit/collections.py
index 9d32a3b7..16f87732 100644
--- a/praw/models/reddit/collections.py
+++ b/praw/models/reddit/collections.py
@@ -4,15 +4,15 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, Any
 
-from ...const import API_PATH
-from ...exceptions import ClientException
-from ...util.cache import cachedproperty
-from ..base import PRAWBase
-from .base import RedditBase
-from .submission import Submission
-from .subreddit import Subreddit
-
-if TYPE_CHECKING:  # pragma: no cover
+from praw.const import API_PATH
+from praw.exceptions import ClientException
+from praw.models.base import PRAWBase
+from praw.models.reddit.base import RedditBase
+from praw.models.reddit.submission import Submission
+from praw.models.reddit.subreddit import Subreddit
+from praw.util.cache import cachedproperty
+
+if TYPE_CHECKING:
     from collections.abc import Iterator
 
     import praw.models
@@ -29,7 +29,7 @@ class CollectionModeration(PRAWBase):
 
     """
 
-    def __init__(self, reddit: praw.Reddit, collection_id: str):
+    def __init__(self, reddit: praw.Reddit, collection_id: str) -> None:
         """Initialize a :class:`.CollectionModeration` instance.
 
         :param collection_id: The ID of a :class:`.Collection`.
@@ -58,7 +58,7 @@ class CollectionModeration(PRAWBase):
         except ClientException:
             return self._reddit.submission(post).fullname
 
-    def add_post(self, submission: praw.models.Submission):
+    def add_post(self, submission: praw.models.Submission) -> None:
         """Add a post to the collection.
 
         :param submission: The post to add, a :class:`.Submission`, its permalink as a
@@ -83,7 +83,7 @@ class CollectionModeration(PRAWBase):
             data={"collection_id": self.collection_id, "link_fullname": link_fullname},
         )
 
-    def delete(self):
+    def delete(self) -> None:
         """Delete this collection.
 
         Example usage:
@@ -99,7 +99,7 @@ class CollectionModeration(PRAWBase):
         """
         self._reddit.post(API_PATH["collection_delete"], data={"collection_id": self.collection_id})
 
-    def remove_post(self, submission: praw.models.Submission):
+    def remove_post(self, submission: praw.models.Submission) -> None:
         """Remove a post from the collection.
 
         :param submission: The post to remove, a :class:`.Submission`, its permalink as
@@ -124,7 +124,7 @@ class CollectionModeration(PRAWBase):
             data={"collection_id": self.collection_id, "link_fullname": link_fullname},
         )
 
-    def reorder(self, links: list[str | praw.models.Submission]):
+    def reorder(self, links: list[str | praw.models.Submission]) -> None:
         r"""Reorder posts in the collection.
 
         :param links: A list of :class:`.Submission`\ s or a ``str`` that is either a
@@ -146,7 +146,7 @@ class CollectionModeration(PRAWBase):
             data={"collection_id": self.collection_id, "link_ids": link_ids},
         )
 
-    def update_description(self, description: str):
+    def update_description(self, description: str) -> None:
         """Update the collection's description.
 
         :param description: The new description.
@@ -168,7 +168,7 @@ class CollectionModeration(PRAWBase):
             data={"collection_id": self.collection_id, "description": description},
         )
 
-    def update_display_layout(self, display_layout: str):
+    def update_display_layout(self, display_layout: str) -> None:
         """Update the collection's display layout.
 
         :param display_layout: Either ``"TIMELINE"`` for events or discussions or
@@ -193,7 +193,7 @@ class CollectionModeration(PRAWBase):
             },
         )
 
-    def update_title(self, title: str):
+    def update_title(self, title: str) -> None:
         """Update the collection's title.
 
         :param title: The new title.
@@ -232,7 +232,7 @@ class SubredditCollectionsModeration(PRAWBase):
         reddit: praw.Reddit,
         sub_fullname: str,
         _data: dict[str, Any] | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.SubredditCollectionsModeration` instance."""
         super().__init__(reddit, _data)
         self.subreddit_fullname = sub_fullname
@@ -354,12 +354,12 @@ class SubredditCollections(PRAWBase):
         reddit: praw.Reddit,
         subreddit: praw.models.Subreddit,
         _data: dict[str, Any] | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.SubredditCollections` instance."""
         super().__init__(reddit, _data)
         self.subreddit = subreddit
 
-    def __iter__(self):
+    def __iter__(self) -> Iterator[Collection]:
         r"""Iterate over the :class:`.Subreddit`'s :class:`.Collection`\ s.
 
         Example usage:
@@ -454,10 +454,10 @@ class Collection(RedditBase):
     def __init__(
         self,
         reddit: praw.Reddit,
-        _data: dict[str, Any] = None,
+        _data: dict[str, Any] | None = None,
         collection_id: str | None = None,
         permalink: str | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.Collection` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
@@ -466,7 +466,7 @@ class Collection(RedditBase):
         :param permalink: The permalink of the :class:`.Collection`.
 
         """
-        if (_data, collection_id, permalink).count(None) != 2:
+        if sum(1 for value in (_data, collection_id, permalink) if value is not None) != 1:
             msg = "Exactly one of '_data', 'collection_id', or 'permalink' must be provided."
             raise TypeError(msg)
 
@@ -483,7 +483,7 @@ class Collection(RedditBase):
             "include_links": True,
         }
 
-    def __iter__(self) -> Iterator:
+    def __iter__(self) -> Iterator[praw.models.Submission]:
         """Provide a way to iterate over the posts in this :class:`.Collection`.
 
         Example usage:
@@ -510,15 +510,15 @@ class Collection(RedditBase):
         """
         return len(self.link_ids)
 
-    def __setattr__(self, attribute: str, value: Any):
+    def __setattr__(self, attribute: str, value: Any) -> None:
         """Objectify author, subreddit, and sorted_links attributes."""
         if attribute == "author_name":
             self.author = self._reddit.redditor(value)
         elif attribute == "sorted_links":
-            value = self._reddit._objector.objectify(value)
+            value = self._reddit._objector.objectify(data=value)
         super().__setattr__(attribute, value)
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         data = self._fetch_data()
         try:
             self._reddit._objector.check_error(data)
@@ -533,10 +533,10 @@ class Collection(RedditBase):
         self.__dict__.update(other.__dict__)
         super()._fetch()
 
-    def _fetch_info(self):
+    def _fetch_info(self) -> tuple[str, dict, dict[str, bool | str]]:
         return "collection", {}, self._info_params
 
-    def follow(self):
+    def follow(self) -> None:
         """Follow this :class:`.Collection`.
 
         Example usage:
@@ -555,7 +555,7 @@ class Collection(RedditBase):
             data={"collection_id": self.collection_id, "follow": True},
         )
 
-    def unfollow(self):
+    def unfollow(self) -> None:
         """Unfollow this :class:`.Collection`.
 
         Example usage:
diff --git a/praw/models/reddit/comment.py b/praw/models/reddit/comment.py
index 510fd484..eb47aab9 100644
--- a/praw/models/reddit/comment.py
+++ b/praw/models/reddit/comment.py
@@ -4,20 +4,15 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, Any
 
-from ...const import API_PATH
-from ...exceptions import ClientException, InvalidURL
-from ...util.cache import cachedproperty
-from ..comment_forest import CommentForest
-from .base import RedditBase
-from .mixins import (
-    FullnameMixin,
-    InboxableMixin,
-    ThingModerationMixin,
-    UserContentMixin,
-)
-from .redditor import Redditor
-
-if TYPE_CHECKING:  # pragma: no cover
+from praw.const import API_PATH
+from praw.exceptions import ClientException, InvalidURL
+from praw.models.comment_forest import CommentForest
+from praw.models.reddit.base import RedditBase
+from praw.models.reddit.mixins import FullnameMixin, InboxableMixin, ThingModerationMixin, UserContentMixin
+from praw.models.reddit.redditor import Redditor
+from praw.util.cache import cachedproperty
+
+if TYPE_CHECKING:
     import praw.models
 
 
@@ -90,7 +85,7 @@ class Comment(InboxableMixin, UserContentMixin, FullnameMixin, RedditBase):
         return CommentModeration(self)
 
     @property
-    def _kind(self):
+    def _kind(self) -> str:
         """Return the class's kind."""
         return self._reddit.config.kinds["comment"]
 
@@ -135,7 +130,7 @@ class Comment(InboxableMixin, UserContentMixin, FullnameMixin, RedditBase):
         return self._submission
 
     @submission.setter
-    def submission(self, submission: praw.models.Submission):
+    def submission(self, submission: praw.models.Submission) -> None:
         """Update the :class:`.Submission` associated with the :class:`.Comment`."""
         submission._comments_by_id[self.fullname] = self
         self._submission = submission
@@ -148,9 +143,9 @@ class Comment(InboxableMixin, UserContentMixin, FullnameMixin, RedditBase):
         id: str | None = None,
         url: str | None = None,
         _data: dict[str, Any] | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.Comment` instance."""
-        if (id, url, _data).count(None) != 2:
+        if sum(1 for value in (id, url, _data) if value is not None) != 1:
             msg = "Exactly one of 'id', 'url', or '_data' must be provided."
             raise TypeError(msg)
         fetched = False
@@ -168,23 +163,23 @@ class Comment(InboxableMixin, UserContentMixin, FullnameMixin, RedditBase):
         self,
         attribute: str,
         value: str | Redditor | CommentForest | praw.models.Subreddit,
-    ):
+    ) -> None:
         """Objectify author, replies, and subreddit."""
         if attribute == "author":
             value = Redditor.from_data(self._reddit, value)
         elif attribute == "replies":
-            value = [] if value == "" else self._reddit._objector.objectify(value).children  # noqa: PLC1901
+            value = [] if value == "" else self._reddit._objector.objectify(data=value).children  # noqa: PLC1901
             attribute = "_replies"
         elif attribute == "subreddit":
             value = self._reddit.subreddit(value)
         super().__setattr__(attribute, value)
 
-    def _extract_submission_id(self):
+    def _extract_submission_id(self) -> str:
         if "context" in self.__dict__:
             return self.context.rsplit("/", 4)[1]
         return self.link_id.split("_", 1)[1]
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         data = self._fetch_data()
         data = data["data"]
 
@@ -197,7 +192,7 @@ class Comment(InboxableMixin, UserContentMixin, FullnameMixin, RedditBase):
         self.__dict__.update(other.__dict__)
         super()._fetch()
 
-    def _fetch_info(self):
+    def _fetch_info(self) -> tuple[str, dict, dict[str, str]]:
         return "info", {}, {"id": self.fullname}
 
     def parent(
@@ -327,7 +322,7 @@ class CommentModeration(ThingModerationMixin):
 
     REMOVAL_MESSAGE_API = "removal_comment_message"
 
-    def __init__(self, comment: praw.models.Comment):
+    def __init__(self, comment: praw.models.Comment) -> None:
         """Initialize a :class:`.CommentModeration` instance.
 
         :param comment: The comment to moderate.
@@ -335,7 +330,7 @@ class CommentModeration(ThingModerationMixin):
         """
         self.thing = comment
 
-    def show(self):
+    def show(self) -> None:
         """Uncollapse a :class:`.Comment` that has been collapsed by Crowd Control.
 
         Example usage:
diff --git a/praw/models/reddit/draft.py b/praw/models/reddit/draft.py
index 0d66130e..c99a0d09 100644
--- a/praw/models/reddit/draft.py
+++ b/praw/models/reddit/draft.py
@@ -4,13 +4,13 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, Any
 
-from ...const import API_PATH
-from ...exceptions import ClientException
-from .base import RedditBase
-from .subreddit import Subreddit
-from .user_subreddit import UserSubreddit
+from praw.const import API_PATH
+from praw.exceptions import ClientException
+from praw.models.reddit.base import RedditBase
+from praw.models.reddit.subreddit import Subreddit
+from praw.models.reddit.user_subreddit import UserSubreddit
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw.models
 
 
@@ -81,7 +81,7 @@ class Draft(RedditBase):
         data.update(draft_kwargs)
         return data
 
-    def __init__(self, reddit: praw.Reddit, id: str | None = None, _data: dict[str, Any] = None):
+    def __init__(self, reddit: praw.Reddit, id: str | None = None, _data: dict[str, Any] | None = None) -> None:
         """Initialize a :class:`.Draft` instance."""
         if (id, _data).count(None) != 1:
             msg = "Exactly one of 'id' or '_data' must be provided."
@@ -105,7 +105,7 @@ class Draft(RedditBase):
             return f"{self.__class__.__name__}(id={self.id!r}{subreddit}{title})"
         return f"{self.__class__.__name__}(id={self.id!r})"
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         for draft in self._reddit.drafts():
             if draft.id == self.id:
                 self.__dict__.update(draft.__dict__)
@@ -114,7 +114,7 @@ class Draft(RedditBase):
         msg = f"The currently authenticated user not have a draft with an ID of {self.id}"
         raise ClientException(msg)
 
-    def delete(self):
+    def delete(self) -> None:
         """Delete the :class:`.Draft`.
 
         Example usage:
@@ -208,12 +208,12 @@ class Draft(RedditBase):
             if value is not None:
                 submit_kwargs[key] = value
         if isinstance(subreddit, str):
-            _subreddit = self._reddit.subreddit(subreddit)
+            subreddit_ = self._reddit.subreddit(subreddit)
         elif isinstance(subreddit, (Subreddit, UserSubreddit)):
-            _subreddit = subreddit
+            subreddit_ = subreddit
         else:
-            _subreddit = self.subreddit
-        return _subreddit.submit(**submit_kwargs)
+            subreddit_ = self.subreddit
+        return subreddit_.submit(**submit_kwargs)
 
     def update(
         self,
@@ -230,7 +230,7 @@ class Draft(RedditBase):
         title: str | None = None,
         url: str | None = None,
         **draft_kwargs: Any,
-    ):
+    ) -> None:
         """Update the :class:`.Draft`.
 
         .. note::
@@ -287,6 +287,6 @@ class Draft(RedditBase):
             **draft_kwargs,
         )
         data["id"] = self.id
-        _new_draft = self._reddit.put(API_PATH["draft"], data=data)
-        _new_draft._fetch()
-        self.__dict__.update(_new_draft.__dict__)
+        new_draft = self._reddit.put(API_PATH["draft"], data=data)
+        new_draft._fetch()
+        self.__dict__.update(new_draft.__dict__)
diff --git a/praw/models/reddit/emoji.py b/praw/models/reddit/emoji.py
index b35368d9..7eb476bc 100644
--- a/praw/models/reddit/emoji.py
+++ b/praw/models/reddit/emoji.py
@@ -5,11 +5,11 @@ from __future__ import annotations
 from pathlib import Path
 from typing import TYPE_CHECKING, Any
 
-from ...const import API_PATH
-from ...exceptions import ClientException
-from .base import RedditBase
+from praw.const import API_PATH
+from praw.exceptions import ClientException
+from praw.models.reddit.base import RedditBase
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw
 
 
@@ -50,13 +50,13 @@ class Emoji(RedditBase):
         subreddit: praw.models.Subreddit,
         name: str,
         _data: dict[str, Any] | None = None,
-    ):
+    ) -> None:
         """Initialize an :class:`.Emoji` instance."""
         self.name = name
         self.subreddit = subreddit
         super().__init__(reddit, _data=_data)
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         for emoji in self.subreddit.emoji:
             if emoji.name == self.name:
                 self.__dict__.update(emoji.__dict__)
@@ -65,7 +65,7 @@ class Emoji(RedditBase):
         msg = f"r/{self.subreddit} does not have the emoji {self.name}"
         raise ClientException(msg)
 
-    def delete(self):
+    def delete(self) -> None:
         """Delete an emoji from this subreddit by :class:`.Emoji`.
 
         To delete ``"emoji"`` as an emoji on r/test try:
@@ -84,7 +84,7 @@ class Emoji(RedditBase):
         mod_flair_only: bool | None = None,
         post_flair_allowed: bool | None = None,
         user_flair_allowed: bool | None = None,
-    ):
+    ) -> None:
         """Update the permissions of an emoji in this subreddit.
 
         :param mod_flair_only: Indicate whether the emoji is restricted to mod use only.
@@ -149,7 +149,7 @@ class SubredditEmoji:
         """
         return Emoji(self._reddit, self.subreddit, name)
 
-    def __init__(self, subreddit: praw.models.Subreddit):
+    def __init__(self, subreddit: praw.models.Subreddit) -> None:
         """Initialize a :class:`.SubredditEmoji` instance.
 
         :param subreddit: The subreddit whose emoji are affected.
diff --git a/praw/models/reddit/inline_media.py b/praw/models/reddit/inline_media.py
index 0f5266e6..1353a002 100644
--- a/praw/models/reddit/inline_media.py
+++ b/praw/models/reddit/inline_media.py
@@ -18,7 +18,7 @@ class InlineMedia:
             tuple(getattr(self, attr) for attr in ["TYPE", "path", "caption", "media_id"])
         )
 
-    def __init__(self, *, caption: str = None, path: str):
+    def __init__(self, *, caption: str | None = None, path: str) -> None:
         """Initialize an :class:`.InlineMedia` instance.
 
         :param caption: An optional caption to add to the image (default: ``None``).
diff --git a/praw/models/reddit/live.py b/praw/models/reddit/live.py
index 30633d63..b8ec371e 100644
--- a/praw/models/reddit/live.py
+++ b/praw/models/reddit/live.py
@@ -4,16 +4,16 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, Any
 
-from ...const import API_PATH
-from ...util.cache import cachedproperty
-from ..list.redditor import RedditorList
-from ..listing.generator import ListingGenerator
-from ..util import stream_generator
-from .base import RedditBase
-from .mixins import FullnameMixin
-from .redditor import Redditor
-
-if TYPE_CHECKING:  # pragma: no cover
+from praw.const import API_PATH
+from praw.models.list.redditor import RedditorList
+from praw.models.listing.generator import ListingGenerator
+from praw.models.reddit.base import RedditBase
+from praw.models.reddit.mixins import FullnameMixin
+from praw.models.reddit.redditor import Redditor
+from praw.models.util import stream_generator
+from praw.util.cache import cachedproperty
+
+if TYPE_CHECKING:
     from collections.abc import Iterable, Iterator
 
     import praw.models
@@ -43,7 +43,7 @@ class LiveContributorRelationship:
         temp = self.thread._reddit.get(url)
         return temp if isinstance(temp, RedditorList) else temp[0]
 
-    def __init__(self, thread: praw.models.LiveThread):
+    def __init__(self, thread: praw.models.LiveThread) -> None:
         """Initialize a :class:`.LiveContributorRelationship` instance.
 
         :param thread: An instance of :class:`.LiveThread`.
@@ -56,7 +56,7 @@ class LiveContributorRelationship:
         """
         self.thread = thread
 
-    def accept_invite(self):
+    def accept_invite(self) -> None:
         """Accept an invite to contribute the live thread.
 
         Usage:
@@ -75,7 +75,7 @@ class LiveContributorRelationship:
         redditor: str | praw.models.Redditor,
         *,
         permissions: list[str] | None = None,
-    ):
+    ) -> None:
         """Invite a redditor to be a contributor of the live thread.
 
         :param redditor: A redditor name or :class:`.Redditor` instance.
@@ -110,7 +110,7 @@ class LiveContributorRelationship:
         }
         self.thread._reddit.post(url, data=data)
 
-    def leave(self):
+    def leave(self) -> None:
         """Abdicate the live thread contributor position (use with care).
 
         Usage:
@@ -124,7 +124,7 @@ class LiveContributorRelationship:
         url = API_PATH["live_leave"].format(id=self.thread.id)
         self.thread._reddit.post(url)
 
-    def remove(self, redditor: str | praw.models.Redditor):
+    def remove(self, redditor: str | praw.models.Redditor) -> None:
         """Remove the redditor from the live thread contributors.
 
         :param redditor: A redditor fullname (e.g., ``"t2_1w72"``) or :class:`.Redditor`
@@ -145,7 +145,7 @@ class LiveContributorRelationship:
         url = API_PATH["live_remove_contrib"].format(id=self.thread.id)
         self.thread._reddit.post(url, data=data)
 
-    def remove_invite(self, redditor: str | praw.models.Redditor):
+    def remove_invite(self, redditor: str | praw.models.Redditor) -> None:
         """Remove the invite for redditor.
 
         :param redditor: A redditor fullname (e.g., ``"t2_1w72"``) or :class:`.Redditor`
@@ -176,7 +176,7 @@ class LiveContributorRelationship:
         redditor: str | praw.models.Redditor,
         *,
         permissions: list[str] | None = None,
-    ):
+    ) -> None:
         """Update the contributor permissions for ``redditor``.
 
         :param redditor: A redditor name or :class:`.Redditor` instance.
@@ -219,7 +219,7 @@ class LiveContributorRelationship:
         redditor: str | praw.models.Redditor,
         *,
         permissions: list[str] | None = None,
-    ):
+    ) -> None:
         """Update the contributor invite permissions for ``redditor``.
 
         :param redditor: A redditor name or :class:`.Redditor` instance.
@@ -377,7 +377,7 @@ class LiveThread(RedditBase):
         reddit: praw.Reddit,
         id: str | None = None,
         _data: dict[str, Any] | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.LiveThread` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
@@ -391,14 +391,14 @@ class LiveThread(RedditBase):
             self.id = id
         super().__init__(reddit, _data=_data)
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         data = self._fetch_data()
         data = data["data"]
         other = type(self)(self._reddit, _data=data)
         self.__dict__.update(other.__dict__)
         super()._fetch()
 
-    def _fetch_info(self):
+    def _fetch_info(self) -> tuple[str, dict[str, str], None]:
         return "liveabout", {"id": self.id}, None
 
     def discussions(self, **generator_kwargs: str | int | dict[str, str]) -> Iterator[praw.models.Submission]:
@@ -425,7 +425,7 @@ class LiveThread(RedditBase):
         url = API_PATH["live_discussions"].format(id=self.id)
         return ListingGenerator(self._reddit, url, **generator_kwargs)
 
-    def report(self, type: str):
+    def report(self, type: str) -> None:  # noqa: A002
         """Report the thread violating the Reddit rules.
 
         :param type: One of ``"spam"``, ``"vote-manipulation"``,
@@ -474,7 +474,7 @@ class LiveThread(RedditBase):
 class LiveThreadContribution:
     """Provides a set of contribution functions to a :class:`.LiveThread`."""
 
-    def __init__(self, thread: praw.models.LiveThread):
+    def __init__(self, thread: praw.models.LiveThread) -> None:
         """Initialize a :class:`.LiveThreadContribution` instance.
 
         :param thread: An instance of :class:`.LiveThread`.
@@ -490,7 +490,7 @@ class LiveThreadContribution:
         """
         self.thread = thread
 
-    def add(self, body: str):
+    def add(self, body: str) -> None:
         """Add an update to the live thread.
 
         :param body: The Markdown formatted content for the update.
@@ -506,7 +506,7 @@ class LiveThreadContribution:
         url = API_PATH["live_add_update"].format(id=self.thread.id)
         self.thread._reddit.post(url, data={"body": body})
 
-    def close(self):
+    def close(self) -> None:
         """Close the live thread permanently (cannot be undone).
 
         Usage:
@@ -528,7 +528,7 @@ class LiveThreadContribution:
         resources: str | None = None,
         title: str | None = None,
         **other_settings: str | None,
-    ):
+    ) -> None:
         """Update settings of the live thread.
 
         :param description: The live thread's description (default: ``None``).
@@ -594,7 +594,7 @@ class LiveThreadStream:
 
     """
 
-    def __init__(self, live_thread: praw.models.LiveThread):
+    def __init__(self, live_thread: praw.models.LiveThread) -> None:
         """Initialize a :class:`.LiveThreadStream` instance.
 
         :param live_thread: The live thread associated with the stream.
@@ -640,7 +640,7 @@ class LiveThreadStream:
 class LiveUpdateContribution:
     """Provides a set of contribution functions to :class:`.LiveUpdate`."""
 
-    def __init__(self, update: praw.models.LiveUpdate):
+    def __init__(self, update: praw.models.LiveUpdate) -> None:
         """Initialize a :class:`.LiveUpdateContribution` instance.
 
         :param update: An instance of :class:`.LiveUpdate`.
@@ -658,7 +658,7 @@ class LiveUpdateContribution:
         """
         self.update = update
 
-    def remove(self):
+    def remove(self) -> None:
         """Remove a live update.
 
         Usage:
@@ -674,7 +674,7 @@ class LiveUpdateContribution:
         data = {"id": self.update.fullname}
         self.update.thread._reddit.post(url, data=data)
 
-    def strike(self):
+    def strike(self) -> None:
         """Strike a content of a live update.
 
         .. code-block:: python
@@ -746,7 +746,7 @@ class LiveUpdate(FullnameMixin, RedditBase):
         thread_id: str | None = None,
         update_id: str | None = None,
         _data: dict[str, Any] | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.LiveUpdate` instance.
 
         Either ``thread_id`` and ``update_id``, or ``_data`` must be provided.
@@ -779,13 +779,13 @@ class LiveUpdate(FullnameMixin, RedditBase):
             msg = "Either 'thread_id' and 'update_id', or '_data' must be provided."
             raise TypeError(msg)
 
-    def __setattr__(self, attribute: str, value: Any):
+    def __setattr__(self, attribute: str, value: Any) -> None:
         """Objectify author."""
         if attribute == "author":
             value = Redditor(self._reddit, name=value)
         super().__setattr__(attribute, value)
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         url = API_PATH["live_focus"].format(thread_id=self.thread.id, update_id=self.id)
         other = self._reddit.get(url)[0]
         self.__dict__.update(other.__dict__)
diff --git a/praw/models/reddit/message.py b/praw/models/reddit/message.py
index f1bdd481..a3f0181e 100644
--- a/praw/models/reddit/message.py
+++ b/praw/models/reddit/message.py
@@ -4,13 +4,13 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, Any
 
-from ...const import API_PATH
-from .base import RedditBase
-from .mixins import FullnameMixin, InboxableMixin, ReplyableMixin
-from .redditor import Redditor
-from .subreddit import Subreddit
+from praw.const import API_PATH
+from praw.models.reddit.base import RedditBase
+from praw.models.reddit.mixins import FullnameMixin, InboxableMixin, ReplyableMixin
+from praw.models.reddit.redditor import Redditor
+from praw.models.reddit.subreddit import Subreddit
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw.models
 
 
@@ -58,7 +58,7 @@ class Message(InboxableMixin, ReplyableMixin, FullnameMixin, RedditBase):
 
         if data["replies"]:
             replies = data["replies"]
-            data["replies"] = reddit._objector.objectify(replies["data"]["children"])
+            data["replies"] = reddit._objector.objectify(data=replies["data"]["children"])
         else:
             data["replies"] = []
 
@@ -81,10 +81,10 @@ class Message(InboxableMixin, ReplyableMixin, FullnameMixin, RedditBase):
         return self._parent
 
     @parent.setter
-    def parent(self, value: praw.models.Message | None):
+    def parent(self, value: praw.models.Message | None) -> None:
         self._parent = value
 
-    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]):
+    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]) -> None:
         """Initialize a :class:`.Message` instance."""
         super().__init__(reddit, _data=_data, _fetched=True)
         self._parent = None
@@ -92,7 +92,7 @@ class Message(InboxableMixin, ReplyableMixin, FullnameMixin, RedditBase):
             if reply.parent_id == self.fullname:
                 reply.parent = self
 
-    def delete(self):
+    def delete(self) -> None:
         """Delete the message.
 
         .. note::
@@ -136,7 +136,7 @@ class SubredditMessage(Message):
 
     """
 
-    def mute(self):
+    def mute(self) -> None:
         """Mute the sender of this :class:`.SubredditMessage`.
 
         For example, to mute the sender of the first :class:`.SubredditMessage` in the
@@ -154,7 +154,7 @@ class SubredditMessage(Message):
         """
         self._reddit.post(API_PATH["mute_sender"], data={"id": self.fullname})
 
-    def unmute(self):
+    def unmute(self) -> None:
         """Unmute the sender of this :class:`.SubredditMessage`.
 
         For example, to unmute the sender of the first :class:`.SubredditMessage` in the
diff --git a/praw/models/reddit/mixins/__init__.py b/praw/models/reddit/mixins/__init__.py
index 7204e9e3..14d13955 100644
--- a/praw/models/reddit/mixins/__init__.py
+++ b/praw/models/reddit/mixins/__init__.py
@@ -5,19 +5,19 @@ from __future__ import annotations
 from json import dumps
 from typing import TYPE_CHECKING, Optional
 
-from ....const import API_PATH
-from .editable import EditableMixin
-from .fullname import FullnameMixin
-from .inboxable import InboxableMixin
-from .inboxtoggleable import InboxToggleableMixin
-from .messageable import MessageableMixin
-from .modnote import ModNoteMixin
-from .replyable import ReplyableMixin
-from .reportable import ReportableMixin
-from .savable import SavableMixin
-from .votable import VotableMixin
-
-if TYPE_CHECKING:  # pragma: no cover
+from praw.const import API_PATH
+from praw.models.reddit.mixins.editable import EditableMixin
+from praw.models.reddit.mixins.fullname import FullnameMixin
+from praw.models.reddit.mixins.inboxable import InboxableMixin
+from praw.models.reddit.mixins.inboxtoggleable import InboxToggleableMixin
+from praw.models.reddit.mixins.messageable import MessageableMixin
+from praw.models.reddit.mixins.modnote import ModNoteMixin
+from praw.models.reddit.mixins.replyable import ReplyableMixin
+from praw.models.reddit.mixins.reportable import ReportableMixin
+from praw.models.reddit.mixins.savable import SavableMixin
+from praw.models.reddit.mixins.votable import VotableMixin
+
+if TYPE_CHECKING:
     import praw.models
 
 
@@ -26,7 +26,7 @@ class ThingModerationMixin(ModNoteMixin):
 
     REMOVAL_MESSAGE_API = None
 
-    def _add_removal_reason(self, *, mod_note: str = "", reason_id: str | None = None):
+    def _add_removal_reason(self, *, mod_note: str = "", reason_id: str | None = None) -> None:
         """Add a removal reason for a :class:`.Comment` or :class:`.Submission`.
 
         :param mod_note: A message for the other moderators.
@@ -49,7 +49,7 @@ class ThingModerationMixin(ModNoteMixin):
         }
         self.thing._reddit.post(API_PATH["removal_reasons"], data={"json": dumps(data)})
 
-    def approve(self):
+    def approve(self) -> None:
         """Approve a :class:`.Comment` or :class:`.Submission`.
 
         Approving a comment or submission reverts a removal, resets the report counter,
@@ -70,7 +70,7 @@ class ThingModerationMixin(ModNoteMixin):
         """
         self.thing._reddit.post(API_PATH["approve"], data={"id": self.thing.fullname})
 
-    def distinguish(self, *, how: str = "yes", sticky: bool = False):
+    def distinguish(self, *, how: str = "yes", sticky: bool = False) -> None:
         """Distinguish a :class:`.Comment` or :class:`.Submission`.
 
         :param how: One of ``"yes"``, ``"no"``, ``"admin"``, or ``"special"``. ``"yes"``
@@ -102,7 +102,7 @@ class ThingModerationMixin(ModNoteMixin):
             data["sticky"] = True
         self.thing._reddit.post(API_PATH["distinguish"], data=data)
 
-    def ignore_reports(self):
+    def ignore_reports(self) -> None:
         """Ignore future reports on a :class:`.Comment` or :class:`.Submission`.
 
         Calling this method will prevent future reports on this :class:`.Comment` or
@@ -128,7 +128,7 @@ class ThingModerationMixin(ModNoteMixin):
         """
         self.thing._reddit.post(API_PATH["ignore_reports"], data={"id": self.thing.fullname})
 
-    def lock(self):
+    def lock(self) -> None:
         """Lock a :class:`.Comment` or :class:`.Submission`.
 
         Example usage:
@@ -149,7 +149,7 @@ class ThingModerationMixin(ModNoteMixin):
         """
         self.thing._reddit.post(API_PATH["lock"], data={"id": self.thing.fullname})
 
-    def remove(self, *, mod_note: str = "", spam: bool = False, reason_id: str | None = None):
+    def remove(self, *, mod_note: str = "", spam: bool = False, reason_id: str | None = None) -> None:
         """Remove a :class:`.Comment` or :class:`.Submission`.
 
         :param mod_note: A message for the other moderators.
@@ -186,7 +186,7 @@ class ThingModerationMixin(ModNoteMixin):
         *,
         message: str,
         title: str = "ignored",
-        type: str = "public",
+        type: str = "public",  # noqa: A002
     ) -> praw.models.Comment | None:
         """Send a removal message for a :class:`.Comment` or :class:`.Submission`.
 
@@ -230,7 +230,7 @@ class ThingModerationMixin(ModNoteMixin):
 
         return self.thing._reddit.post(url, data={"json": dumps(data)}) or None
 
-    def undistinguish(self):
+    def undistinguish(self) -> None:
         """Remove mod, admin, or special distinguishing from an object.
 
         Also unstickies the object if applicable.
@@ -253,7 +253,7 @@ class ThingModerationMixin(ModNoteMixin):
         """
         self.distinguish(how="no")
 
-    def unignore_reports(self):
+    def unignore_reports(self) -> None:
         """Resume receiving future reports on a :class:`.Comment` or :class:`.Submission`.
 
         Future reports on this :class:`.Comment` or :class:`.Submission` will cause
@@ -277,7 +277,7 @@ class ThingModerationMixin(ModNoteMixin):
         """
         self.thing._reddit.post(API_PATH["unignore_reports"], data={"id": self.thing.fullname})
 
-    def unlock(self):
+    def unlock(self) -> None:
         """Unlock a :class:`.Comment` or :class:`.Submission`.
 
         Example usage:
diff --git a/praw/models/reddit/mixins/editable.py b/praw/models/reddit/mixins/editable.py
index e4abad15..b597f301 100644
--- a/praw/models/reddit/mixins/editable.py
+++ b/praw/models/reddit/mixins/editable.py
@@ -4,16 +4,16 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING
 
-from ....const import API_PATH
+from praw.const import API_PATH
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw.models
 
 
 class EditableMixin:
     """Interface for classes that can be edited and deleted."""
 
-    def delete(self):
+    def delete(self) -> None:
         """Delete the object.
 
         Example usage:
diff --git a/praw/models/reddit/mixins/inboxable.py b/praw/models/reddit/mixins/inboxable.py
index 23c99975..50d627ba 100644
--- a/praw/models/reddit/mixins/inboxable.py
+++ b/praw/models/reddit/mixins/inboxable.py
@@ -1,12 +1,12 @@
 """Provide the InboxableMixin class."""
 
-from ....const import API_PATH
+from praw.const import API_PATH
 
 
 class InboxableMixin:
     """Interface for :class:`.RedditBase` subclasses that originate from the inbox."""
 
-    def block(self):
+    def block(self) -> None:
         """Block the user who sent the item.
 
         .. note::
@@ -27,7 +27,7 @@ class InboxableMixin:
         """
         self._reddit.post(API_PATH["block"], data={"id": self.fullname})
 
-    def collapse(self):
+    def collapse(self) -> None:
         """Mark the item as collapsed.
 
         .. note::
@@ -50,7 +50,7 @@ class InboxableMixin:
         """
         self._reddit.inbox.collapse([self])
 
-    def mark_read(self):
+    def mark_read(self) -> None:
         """Mark a single inbox item as read.
 
         .. note::
@@ -77,7 +77,7 @@ class InboxableMixin:
         """
         self._reddit.inbox.mark_read([self])
 
-    def mark_unread(self):
+    def mark_unread(self) -> None:
         """Mark the item as unread.
 
         .. note::
@@ -101,7 +101,7 @@ class InboxableMixin:
         """
         self._reddit.inbox.mark_unread([self])
 
-    def unblock_subreddit(self):
+    def unblock_subreddit(self) -> None:
         """Unblock a subreddit.
 
         .. note::
@@ -128,7 +128,7 @@ class InboxableMixin:
         """
         self._reddit.post(API_PATH["unblock_subreddit"], data={"id": self.fullname})
 
-    def uncollapse(self):
+    def uncollapse(self) -> None:
         """Mark the item as uncollapsed.
 
         .. note::
diff --git a/praw/models/reddit/mixins/inboxtoggleable.py b/praw/models/reddit/mixins/inboxtoggleable.py
index 68ed56fe..43b35d73 100644
--- a/praw/models/reddit/mixins/inboxtoggleable.py
+++ b/praw/models/reddit/mixins/inboxtoggleable.py
@@ -1,12 +1,12 @@
 """Provide the InboxToggleableMixin class."""
 
-from ....const import API_PATH
+from praw.const import API_PATH
 
 
 class InboxToggleableMixin:
     """Interface for classes that can optionally receive inbox replies."""
 
-    def disable_inbox_replies(self):
+    def disable_inbox_replies(self) -> None:
         """Disable inbox replies for the item.
 
         .. note::
@@ -30,7 +30,7 @@ class InboxToggleableMixin:
         """
         self._reddit.post(API_PATH["sendreplies"], data={"id": self.fullname, "state": False})
 
-    def enable_inbox_replies(self):
+    def enable_inbox_replies(self) -> None:
         """Enable inbox replies for the item.
 
         .. note::
diff --git a/praw/models/reddit/mixins/messageable.py b/praw/models/reddit/mixins/messageable.py
index b72663ea..6c133f2e 100644
--- a/praw/models/reddit/mixins/messageable.py
+++ b/praw/models/reddit/mixins/messageable.py
@@ -4,9 +4,9 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING
 
-from ....const import API_PATH
+from praw.const import API_PATH
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw
 
 
@@ -19,7 +19,7 @@ class MessageableMixin:
         from_subreddit: praw.models.Subreddit | str | None = None,
         message: str,
         subject: str,
-    ):
+    ) -> None:
         """Send a message to a :class:`.Redditor` or a :class:`.Subreddit`'s moderators (modmail).
 
         :param from_subreddit: A :class:`.Subreddit` instance or string to send the
diff --git a/praw/models/reddit/mixins/modnote.py b/praw/models/reddit/mixins/modnote.py
index 82786900..2ebd67d3 100644
--- a/praw/models/reddit/mixins/modnote.py
+++ b/praw/models/reddit/mixins/modnote.py
@@ -4,8 +4,8 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, Any
 
-if TYPE_CHECKING:  # pragma: no cover
-    from collections.abc import Generator
+if TYPE_CHECKING:
+    from collections.abc import Iterator
 
     import praw.models
 
@@ -13,7 +13,7 @@ if TYPE_CHECKING:  # pragma: no cover
 class ModNoteMixin:
     """Interface for classes that can have a moderator note set on them."""
 
-    def author_notes(self, **generator_kwargs: Any) -> Generator[praw.models.ModNote, None, None]:
+    def author_notes(self, **generator_kwargs: Any) -> Iterator[praw.models.ModNote]:
         """Get the moderator notes for the author of this object in the subreddit it's posted in.
 
         :param generator_kwargs: Additional keyword arguments are passed in the
diff --git a/praw/models/reddit/mixins/replyable.py b/praw/models/reddit/mixins/replyable.py
index 2b48d2c5..b66ab5ef 100644
--- a/praw/models/reddit/mixins/replyable.py
+++ b/praw/models/reddit/mixins/replyable.py
@@ -4,9 +4,9 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING
 
-from ....const import API_PATH
+from praw.const import API_PATH
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw.models
 
 
diff --git a/praw/models/reddit/mixins/reportable.py b/praw/models/reddit/mixins/reportable.py
index 2c432dab..b6ee42db 100644
--- a/praw/models/reddit/mixins/reportable.py
+++ b/praw/models/reddit/mixins/reportable.py
@@ -1,12 +1,12 @@
 """Provide the ReportableMixin class."""
 
-from ....const import API_PATH
+from praw.const import API_PATH
 
 
 class ReportableMixin:
     """Interface for :class:`.RedditBase` classes that can be reported."""
 
-    def report(self, reason: str):
+    def report(self, reason: str) -> None:
         """Report this object to the moderators of its subreddit.
 
         :param reason: The reason for reporting.
diff --git a/praw/models/reddit/mixins/savable.py b/praw/models/reddit/mixins/savable.py
index efc957ee..fddaf64c 100644
--- a/praw/models/reddit/mixins/savable.py
+++ b/praw/models/reddit/mixins/savable.py
@@ -2,13 +2,13 @@
 
 from __future__ import annotations
 
-from ....const import API_PATH
+from praw.const import API_PATH
 
 
 class SavableMixin:
     """Interface for :class:`.RedditBase` classes that can be saved."""
 
-    def save(self, *, category: str | None = None):
+    def save(self, *, category: str | None = None) -> None:
         """Save the object.
 
         :param category: The category to save to. If the authenticated user does not
@@ -31,7 +31,7 @@ class SavableMixin:
         """
         self._reddit.post(API_PATH["save"], data={"category": category, "id": self.fullname})
 
-    def unsave(self):
+    def unsave(self) -> None:
         """Unsave the object.
 
         Example usage:
diff --git a/praw/models/reddit/mixins/votable.py b/praw/models/reddit/mixins/votable.py
index ce032543..d6b4a340 100644
--- a/praw/models/reddit/mixins/votable.py
+++ b/praw/models/reddit/mixins/votable.py
@@ -2,16 +2,16 @@
 
 from __future__ import annotations
 
-from ....const import API_PATH
+from praw.const import API_PATH
 
 
 class VotableMixin:
     """Interface for :class:`.RedditBase` classes that can be voted on."""
 
-    def _vote(self, direction: int):
+    def _vote(self, direction: int) -> None:
         self._reddit.post(API_PATH["vote"], data={"dir": str(direction), "id": self.fullname})
 
-    def clear_vote(self):
+    def clear_vote(self) -> None:
         """Clear the authenticated user's vote on the object.
 
         .. note::
@@ -35,7 +35,7 @@ class VotableMixin:
         """
         self._vote(direction=0)
 
-    def downvote(self):
+    def downvote(self) -> None:
         """Downvote the object.
 
         .. note::
@@ -63,7 +63,7 @@ class VotableMixin:
         """
         self._vote(direction=-1)
 
-    def upvote(self):
+    def upvote(self) -> None:
         """Upvote the object.
 
         .. note::
diff --git a/praw/models/reddit/modmail.py b/praw/models/reddit/modmail.py
index 590ea224..4f9ace50 100644
--- a/praw/models/reddit/modmail.py
+++ b/praw/models/reddit/modmail.py
@@ -4,11 +4,11 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, Any
 
-from ...const import API_PATH
-from ...util import snake_case_keys
-from .base import RedditBase
+from praw.const import API_PATH
+from praw.models.reddit.base import RedditBase
+from praw.util import snake_case_keys
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw
 
 
@@ -18,10 +18,10 @@ class ModmailObject(RedditBase):
     AUTHOR_ATTRIBUTE = "author"
     STR_FIELD = "id"
 
-    def __setattr__(self, attribute: str, value: Any):
+    def __setattr__(self, attribute: str, value: Any) -> None:
         """Objectify the AUTHOR_ATTRIBUTE attribute."""
         if attribute == self.AUTHOR_ATTRIBUTE:
-            value = self._reddit._objector.objectify(value)
+            value = self._reddit._objector.objectify(data=value)
         super().__setattr__(attribute, value)
 
 
@@ -63,20 +63,21 @@ class ModmailConversation(RedditBase):
 
     """
 
+    DEFAULT_NUMBER_OF_MUTE_DAYS = 3
     STR_FIELD = "id"
 
     @staticmethod
-    def _convert_conversation_objects(data: dict[str, Any], reddit: praw.Reddit):
+    def _convert_conversation_objects(data: dict[str, Any], reddit: praw.Reddit) -> None:
         """Convert messages and mod actions to PRAW objects."""
         result = {"messages": [], "modActions": []}
         for thing in data["objIds"]:
             key = thing["key"]
             thing_data = data[key][thing["id"]]
-            result[key].append(reddit._objector.objectify(thing_data))
+            result[key].append(reddit._objector.objectify(data=thing_data))
         data.update(result)
 
     @staticmethod
-    def _convert_user_summary(data: dict[str, Any], reddit: praw.Reddit):
+    def _convert_user_summary(data: dict[str, Any], reddit: praw.Reddit) -> None:
         """Convert dictionaries of recent user history to PRAW objects."""
         parsers = {
             "recentComments": reddit._objector.parsers[reddit.config.kinds["comment"]],
@@ -107,13 +108,13 @@ class ModmailConversation(RedditBase):
         :param reddit: An instance of :class:`.Reddit`.
 
         """
-        data["authors"] = [reddit._objector.objectify(author) for author in data["authors"]]
+        data["authors"] = [reddit._objector.objectify(data=author) for author in data["authors"]]
         for entity in "owner", "participant":
-            data[entity] = reddit._objector.objectify(data[entity])
+            data[entity] = reddit._objector.objectify(data=data[entity])
 
         if data.get("user"):
             cls._convert_user_summary(data["user"], reddit)
-            data["user"] = reddit._objector.objectify(data["user"])
+            data["user"] = reddit._objector.objectify(data=data["user"])
 
         data = snake_case_keys(data)
 
@@ -123,9 +124,10 @@ class ModmailConversation(RedditBase):
         self,
         reddit: praw.Reddit,
         id: str | None = None,
+        *,
         mark_read: bool = False,
         _data: dict[str, Any] | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.ModmailConversation` instance.
 
         :param mark_read: If ``True``, conversation is marked as read (default:
@@ -148,16 +150,16 @@ class ModmailConversation(RedditBase):
         conversations = [self] + (other_conversations or [])
         return ",".join(conversation.id for conversation in conversations)
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         data = self._fetch_data()
-        other = self._reddit._objector.objectify(data)
+        other = self._reddit._objector.objectify(data=data)
         self.__dict__.update(other.__dict__)
         super()._fetch()
 
-    def _fetch_info(self):
+    def _fetch_info(self) -> tuple[str, dict[str, str], dict[str, bool] | None]:
         return "modmail_conversation", {"id": self.id}, self._info_params
 
-    def archive(self):
+    def archive(self) -> None:
         """Archive the conversation.
 
         For example:
@@ -169,7 +171,7 @@ class ModmailConversation(RedditBase):
         """
         self._reddit.post(API_PATH["modmail_archive"].format(id=self.id))
 
-    def highlight(self):
+    def highlight(self) -> None:
         """Highlight the conversation.
 
         For example:
@@ -181,7 +183,7 @@ class ModmailConversation(RedditBase):
         """
         self._reddit.post(API_PATH["modmail_highlight"].format(id=self.id))
 
-    def mute(self, *, num_days: int = 3):
+    def mute(self, *, num_days: int = DEFAULT_NUMBER_OF_MUTE_DAYS) -> None:
         """Mute the non-mod user associated with the conversation.
 
         :param num_days: Duration of mute in days. Valid options are ``3``, ``7``, or
@@ -200,14 +202,14 @@ class ModmailConversation(RedditBase):
             reddit.subreddit("test").modmail("2gmz").mute(num_days=7)
 
         """
-        params = {"num_hours": num_days * 24} if num_days != 3 else {}
+        params = {"num_hours": num_days * 24} if num_days != self.DEFAULT_NUMBER_OF_MUTE_DAYS else {}
         self._reddit.request(
             method="POST",
             params=params,
             path=API_PATH["modmail_mute"].format(id=self.id),
         )
 
-    def read(self, *, other_conversations: list[ModmailConversation] | None = None):
+    def read(self, *, other_conversations: list[ModmailConversation] | None = None) -> None:
         """Mark the conversation(s) as read.
 
         :param other_conversations: A list of other conversations to mark (default:
@@ -261,13 +263,13 @@ class ModmailConversation(RedditBase):
             # Reddit recently changed the response format, so we need to handle both in case they change it back
             message_id = response["conversation"]["objIds"][-1]["id"]
             message_data = response["messages"][message_id]
-            return self._reddit._objector.objectify(message_data)
+            return self._reddit._objector.objectify(data=message_data)
         for message in response.messages:
             if message.id == response.obj_ids[-1]["id"]:
                 break
         return message
 
-    def unarchive(self):
+    def unarchive(self) -> None:
         """Unarchive the conversation.
 
         For example:
@@ -279,7 +281,7 @@ class ModmailConversation(RedditBase):
         """
         self._reddit.post(API_PATH["modmail_unarchive"].format(id=self.id))
 
-    def unhighlight(self):
+    def unhighlight(self) -> None:
         """Un-highlight the conversation.
 
         For example:
@@ -291,7 +293,7 @@ class ModmailConversation(RedditBase):
         """
         self._reddit.delete(API_PATH["modmail_highlight"].format(id=self.id))
 
-    def unmute(self):
+    def unmute(self) -> None:
         """Unmute the non-mod user associated with the conversation.
 
         For example:
@@ -303,7 +305,7 @@ class ModmailConversation(RedditBase):
         """
         self._reddit.request(method="POST", path=API_PATH["modmail_unmute"].format(id=self.id))
 
-    def unread(self, *, other_conversations: list[ModmailConversation] | None = None):
+    def unread(self, *, other_conversations: list[ModmailConversation] | None = None) -> None:
         """Mark the conversation(s) as unread.
 
         :param other_conversations: A list of other conversations to mark (default:
diff --git a/praw/models/reddit/more.py b/praw/models/reddit/more.py
index 38144f3b..c917e478 100644
--- a/praw/models/reddit/more.py
+++ b/praw/models/reddit/more.py
@@ -4,16 +4,18 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, Any
 
-from ...const import API_PATH
-from ..base import PRAWBase
+from praw.const import API_PATH
+from praw.models.base import PRAWBase
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw.models
 
 
 class MoreComments(PRAWBase):
     """A class indicating there are more comments."""
 
+    MAX_COMMENTS_IN_REPR = 4
+
     def __eq__(self, other: str | MoreComments) -> bool:
         """Return ``True`` if these :class:`.MoreComments` instances are the same."""
         if isinstance(other, self.__class__):
@@ -24,7 +26,7 @@ class MoreComments(PRAWBase):
         """Return the hash of the current instance."""
         return hash(self.__class__.__name__) ^ hash(str(self))
 
-    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]):
+    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]) -> None:
         """Initialize a :class:`.MoreComments` instance."""
         self.count = self.parent_id = None
         self.children = []
@@ -41,12 +43,12 @@ class MoreComments(PRAWBase):
 
     def __repr__(self) -> str:
         """Return an object initialization representation of the instance."""
-        children = self.children[:4]
-        if len(self.children) > 4:
+        children = self.children[: self.MAX_COMMENTS_IN_REPR]
+        if len(self.children) > self.MAX_COMMENTS_IN_REPR:
             children[-1] = "..."
         return f"<{self.__class__.__name__} count={self.count}, children={children!r}>"
 
-    def _continue_comments(self, update: bool):
+    def _continue_comments(self, *, update: bool) -> list[praw.models.Comment]:
         assert not self.children, "Please file a bug report with PRAW."
         parent = self._load_comment(self.parent_id.split("_", 1)[1])
         self._comments = parent.replies
@@ -55,7 +57,7 @@ class MoreComments(PRAWBase):
                 comment.submission = self.submission
         return self._comments
 
-    def _load_comment(self, comment_id: str):
+    def _load_comment(self, comment_id: str) -> praw.models.Comment:
         path = f"{API_PATH['submission'].format(id=self.submission.id)}_/{comment_id}"
         _, comments = self._reddit.get(
             path,
@@ -71,7 +73,7 @@ class MoreComments(PRAWBase):
         """Fetch and return the comments for a single :class:`.MoreComments` object."""
         if self._comments is None:
             if self.count == 0:  # Handle "continue this thread"
-                return self._continue_comments(update)
+                return self._continue_comments(update=update)
             assert self.children, "Please file a bug report with PRAW."
             data = {
                 "children": ",".join(self.children),
diff --git a/praw/models/reddit/multi.py b/praw/models/reddit/multi.py
index bd0cdf37..f975f9f7 100644
--- a/praw/models/reddit/multi.py
+++ b/praw/models/reddit/multi.py
@@ -6,14 +6,14 @@ import re
 from json import dumps
 from typing import TYPE_CHECKING, Any
 
-from ...const import API_PATH
-from ...util import cachedproperty
-from ..listing.mixins import SubredditListingMixin
-from .base import RedditBase
-from .redditor import Redditor
-from .subreddit import Subreddit, SubredditStream
-
-if TYPE_CHECKING:  # pragma: no cover
+from praw.const import API_PATH
+from praw.models.listing.mixins import SubredditListingMixin
+from praw.models.reddit.base import RedditBase
+from praw.models.reddit.redditor import Redditor
+from praw.models.reddit.subreddit import Subreddit, SubredditStream
+from praw.util import cachedproperty
+
+if TYPE_CHECKING:
     import praw.models
 
 
@@ -47,6 +47,7 @@ class Multireddit(SubredditListingMixin, RedditBase):
 
     """
 
+    SLUG_CUTOFF_LENGTH = 21
     STR_FIELD = "path"
     RE_INVALID = re.compile(r"[\W_]+", re.UNICODE)
 
@@ -60,8 +61,8 @@ class Multireddit(SubredditListingMixin, RedditBase):
 
         """
         title = Multireddit.RE_INVALID.sub("_", title).strip("_").lower()
-        if len(title) > 21:  # truncate to nearest word
-            title = title[:21]
+        if len(title) > Multireddit.SLUG_CUTOFF_LENGTH:  # truncate to nearest word
+            title = title[: Multireddit.SLUG_CUTOFF_LENGTH]
             last_word = title.rfind("_")
             if last_word > 0:
                 title = title[:last_word]
@@ -92,7 +93,7 @@ class Multireddit(SubredditListingMixin, RedditBase):
         """
         return SubredditStream(self)
 
-    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]):
+    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]) -> None:
         """Initialize a :class:`.Multireddit` instance."""
         self.path = None
         super().__init__(reddit, _data=_data)
@@ -102,21 +103,21 @@ class Multireddit(SubredditListingMixin, RedditBase):
         if "subreddits" in self.__dict__:
             self.subreddits = [Subreddit(reddit, x["name"]) for x in self.subreddits]
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         data = self._fetch_data()
         data = data["data"]
         other = type(self)(self._reddit, _data=data)
         self.__dict__.update(other.__dict__)
         super()._fetch()
 
-    def _fetch_info(self):
+    def _fetch_info(self) -> tuple[str, dict[str, str], None]:
         return (
             "multireddit_api",
             {"multi": self.name, "user": self._author.name},
             None,
         )
 
-    def add(self, subreddit: praw.models.Subreddit):
+    def add(self, subreddit: praw.models.Subreddit) -> None:
         """Add a subreddit to this multireddit.
 
         :param subreddit: The subreddit to add to this multi.
@@ -159,7 +160,7 @@ class Multireddit(SubredditListingMixin, RedditBase):
         }
         return self._reddit.post(API_PATH["multireddit_copy"], data=data)
 
-    def delete(self):
+    def delete(self) -> None:
         """Delete this multireddit.
 
         For example, to delete multireddit ``bboe/test``:
@@ -172,7 +173,7 @@ class Multireddit(SubredditListingMixin, RedditBase):
         path = API_PATH["multireddit_api"].format(multi=self.name, user=self._author.name)
         self._reddit.delete(path)
 
-    def remove(self, subreddit: praw.models.Subreddit):
+    def remove(self, subreddit: praw.models.Subreddit) -> None:
         """Remove a subreddit from this multireddit.
 
         :param subreddit: The subreddit to remove from this multi.
@@ -192,7 +193,7 @@ class Multireddit(SubredditListingMixin, RedditBase):
     def update(
         self,
         **updated_settings: str | list[str | praw.models.Subreddit | dict[str, str]],
-    ):
+    ) -> None:
         """Update this multireddit.
 
         Keyword arguments are passed for settings that should be updated. They can any
diff --git a/praw/models/reddit/poll.py b/praw/models/reddit/poll.py
index 5e1497b6..6063d58b 100644
--- a/praw/models/reddit/poll.py
+++ b/praw/models/reddit/poll.py
@@ -4,8 +4,8 @@ from __future__ import annotations
 
 from typing import Any
 
-from ...util import cachedproperty
-from ..base import PRAWBase
+from praw.models.base import PRAWBase
+from praw.util import cachedproperty
 
 
 class PollOption(PRAWBase):
@@ -86,7 +86,7 @@ class PollData(PRAWBase):
             return None
         return self.option(self._user_selection)
 
-    def __setattr__(self, attribute: str, value: Any):
+    def __setattr__(self, attribute: str, value: Any) -> None:
         """Objectify the options attribute, and save user_selection."""
         if attribute == "options" and isinstance(value, list):
             value = [PollOption(self._reddit, option) for option in value]
diff --git a/praw/models/reddit/redditor.py b/praw/models/reddit/redditor.py
index 46410483..8c47ffc4 100644
--- a/praw/models/reddit/redditor.py
+++ b/praw/models/reddit/redditor.py
@@ -5,15 +5,15 @@ from __future__ import annotations
 from json import dumps
 from typing import TYPE_CHECKING, Any
 
-from ...const import API_PATH
-from ...util.cache import cachedproperty
-from ..listing.mixins import RedditorListingMixin
-from ..util import stream_generator
-from .base import RedditBase
-from .mixins import FullnameMixin, MessageableMixin
+from praw.const import API_PATH
+from praw.models.listing.mixins import RedditorListingMixin
+from praw.models.reddit.base import RedditBase
+from praw.models.reddit.mixins import FullnameMixin, MessageableMixin
+from praw.models.util import stream_generator
+from praw.util.cache import cachedproperty
 
-if TYPE_CHECKING:  # pragma: no cover
-    from collections.abc import Generator
+if TYPE_CHECKING:
+    from collections.abc import Iterator
 
     import praw.models
 
@@ -135,7 +135,7 @@ class Redditor(MessageableMixin, RedditorListingMixin, FullnameMixin, RedditBase
         name: str | None = None,
         fullname: str | None = None,
         _data: dict[str, Any] | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.Redditor` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
@@ -145,7 +145,7 @@ class Redditor(MessageableMixin, RedditorListingMixin, FullnameMixin, RedditBase
         Exactly one of ``name``, ``fullname`` or ``_data`` must be provided.
 
         """
-        if (name, fullname, _data).count(None) != 2:
+        if sum(1 for value in (name, fullname, _data) if value is not None) != 1:
             msg = "Exactly one of 'name', 'fullname', or '_data' must be provided."
             raise TypeError(msg)
         if _data:
@@ -159,34 +159,34 @@ class Redditor(MessageableMixin, RedditorListingMixin, FullnameMixin, RedditBase
             self._fullname = fullname
         super().__init__(reddit, _data=_data, _extra_attribute_to_check="_fullname")
 
-    def __setattr__(self, name: str, value: Any):
+    def __setattr__(self, name: str, value: Any) -> None:
         """Objectify the subreddit attribute."""
         if name == "subreddit" and value:
-            from .user_subreddit import UserSubreddit  # noqa: PLC0415
+            from praw.models.reddit.user_subreddit import UserSubreddit  # noqa: PLC0415
 
             value = UserSubreddit(reddit=self._reddit, _data=value)
         super().__setattr__(name, value)
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         data = self._fetch_data()
         data = data["data"]
         other = type(self)(self._reddit, _data=data)
         self.__dict__.update(other.__dict__)
         super()._fetch()
 
-    def _fetch_info(self):
+    def _fetch_info(self) -> tuple[str, dict[str, str], None]:
         if hasattr(self, "_fullname"):
             self.name = self._fetch_username(self._fullname)
         return "user_about", {"user": self.name}, None
 
-    def _fetch_username(self, fullname: str):
+    def _fetch_username(self, fullname: str) -> str:
         return self._reddit.get(API_PATH["user_by_fullname"], params={"ids": fullname})[fullname]["name"]
 
-    def _friend(self, *, data: dict[str, Any], method: str):
+    def _friend(self, *, data: dict[str, Any], method: str) -> None:
         url = API_PATH["friend_v1"].format(user=self)
         self._reddit.request(data=dumps(data), method=method, path=url)
 
-    def block(self):
+    def block(self) -> None:
         """Block the :class:`.Redditor`.
 
         For example, to block :class:`.Redditor` u/spez:
@@ -206,7 +206,7 @@ class Redditor(MessageableMixin, RedditorListingMixin, FullnameMixin, RedditBase
         """
         self._reddit.post(API_PATH["block_user"], params={"name": self.name})
 
-    def distrust(self):
+    def distrust(self) -> None:
         """Remove the :class:`.Redditor` from your whitelist of trusted users.
 
         For example, to remove :class:`.Redditor` u/spez from your whitelist:
@@ -222,7 +222,7 @@ class Redditor(MessageableMixin, RedditorListingMixin, FullnameMixin, RedditBase
         """
         self._reddit.post(API_PATH["remove_whitelisted"], data={"name": self.name})
 
-    def friend(self, *, note: str = None):
+    def friend(self, *, note: str | None = None) -> None:
         """Friend the :class:`.Redditor`.
 
         :param note: A note to save along with the relationship. Requires Reddit Premium
@@ -339,7 +339,7 @@ class Redditor(MessageableMixin, RedditorListingMixin, FullnameMixin, RedditBase
         """
         return list(self._reddit.get(API_PATH["trophies"].format(user=self)))
 
-    def trust(self):
+    def trust(self) -> None:
         """Add the :class:`.Redditor` to your whitelist of trusted users.
 
         Trusted users will always be able to send you PMs.
@@ -378,7 +378,7 @@ class Redditor(MessageableMixin, RedditorListingMixin, FullnameMixin, RedditBase
         """
         self._reddit.post(API_PATH["add_whitelisted"], data={"name": self.name})
 
-    def unblock(self):
+    def unblock(self) -> None:
         """Unblock the :class:`.Redditor`.
 
         For example, to unblock :class:`.Redditor` u/spez:
@@ -396,7 +396,7 @@ class Redditor(MessageableMixin, RedditorListingMixin, FullnameMixin, RedditBase
         url = API_PATH["unfriend"].format(subreddit="all")
         self._reddit.post(url, data=data)
 
-    def unfriend(self):
+    def unfriend(self) -> None:
         """Unfriend the :class:`.Redditor`.
 
         For example, to unfriend :class:`.Redditor` u/spez:
@@ -412,7 +412,7 @@ class Redditor(MessageableMixin, RedditorListingMixin, FullnameMixin, RedditBase
 class RedditorStream:
     """Provides submission and comment streams."""
 
-    def __init__(self, redditor: praw.models.Redditor):
+    def __init__(self, redditor: praw.models.Redditor) -> None:
         """Initialize a :class:`.RedditorStream` instance.
 
         :param redditor: The redditor associated with the streams.
@@ -420,7 +420,7 @@ class RedditorStream:
         """
         self.redditor = redditor
 
-    def comments(self, **stream_options: str | int | dict[str, str]) -> Generator[praw.models.Comment, None, None]:
+    def comments(self, **stream_options: str | int | dict[str, str]) -> Iterator[praw.models.Comment]:
         """Yield new comments as they become available.
 
         Comments are yielded oldest first. Up to 100 historical comments will initially
@@ -438,9 +438,7 @@ class RedditorStream:
         """
         return stream_generator(self.redditor.comments.new, **stream_options)
 
-    def submissions(
-        self, **stream_options: str | int | dict[str, str]
-    ) -> Generator[praw.models.Submission, None, None]:
+    def submissions(self, **stream_options: str | int | dict[str, str]) -> Iterator[praw.models.Submission]:
         """Yield new submissions as they become available.
 
         Submissions are yielded oldest first. Up to 100 historical submissions will
diff --git a/praw/models/reddit/removal_reasons.py b/praw/models/reddit/removal_reasons.py
index 05783f26..f0b9c799 100644
--- a/praw/models/reddit/removal_reasons.py
+++ b/praw/models/reddit/removal_reasons.py
@@ -4,12 +4,12 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, Any
 
-from ...const import API_PATH
-from ...exceptions import ClientException
-from ...util import cachedproperty
-from .base import RedditBase
+from praw.const import API_PATH
+from praw.exceptions import ClientException
+from praw.models.reddit.base import RedditBase
+from praw.util import cachedproperty
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     from collections.abc import Iterator
 
     import praw
@@ -48,7 +48,7 @@ class RemovalReason(RedditBase):
         subreddit: praw.models.Subreddit,
         id: str | None = None,
         _data: dict[str, Any] | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.RemovalReason` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
@@ -65,7 +65,7 @@ class RemovalReason(RedditBase):
         self.subreddit = subreddit
         super().__init__(reddit, _data=_data)
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         for removal_reason in self.subreddit.mod.removal_reasons:
             if removal_reason.id == self.id:
                 self.__dict__.update(removal_reason.__dict__)
@@ -74,7 +74,7 @@ class RemovalReason(RedditBase):
         msg = f"Subreddit {self.subreddit} does not have the removal reason {self.id}"
         raise ClientException(msg)
 
-    def delete(self):
+    def delete(self) -> None:
         """Delete a removal reason from this subreddit.
 
         To delete ``"141vv5c16py7d"`` from r/test try:
@@ -87,7 +87,7 @@ class RemovalReason(RedditBase):
         url = API_PATH["removal_reason"].format(subreddit=self.subreddit, id=self.id)
         self._reddit.delete(url)
 
-    def update(self, *, message: str | None = None, title: str | None = None):
+    def update(self, *, message: str | None = None, title: str | None = None) -> None:
         """Update the removal reason from this subreddit.
 
         .. note::
@@ -178,7 +178,7 @@ class SubredditRemovalReasons:
             return self._removal_reason_list[reason_id]
         return RemovalReason(self._reddit, self.subreddit, reason_id)
 
-    def __init__(self, subreddit: praw.models.Subreddit):
+    def __init__(self, subreddit: praw.models.Subreddit) -> None:
         """Initialize a :class:`.SubredditRemovalReasons` instance.
 
         :param subreddit: The subreddit whose removal reasons to work with.
diff --git a/praw/models/reddit/rules.py b/praw/models/reddit/rules.py
index 313ce6af..ad367768 100644
--- a/praw/models/reddit/rules.py
+++ b/praw/models/reddit/rules.py
@@ -5,12 +5,12 @@ from __future__ import annotations
 from typing import TYPE_CHECKING, Any
 from urllib.parse import quote
 
-from ...const import API_PATH
-from ...exceptions import ClientException
-from ...util import cachedproperty
-from .base import RedditBase
+from praw.const import API_PATH
+from praw.exceptions import ClientException
+from praw.models.reddit.base import RedditBase
+from praw.util import cachedproperty
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     from collections.abc import Iterator
 
     import praw.models
@@ -77,7 +77,7 @@ class Rule(RedditBase):
         subreddit: praw.models.Subreddit | None = None,
         short_name: str | None = None,
         _data: dict[str, str] | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.Rule` instance."""
         if (short_name, _data).count(None) != 1:
             msg = "Either short_name or _data needs to be given."
@@ -90,7 +90,7 @@ class Rule(RedditBase):
         self.subreddit = subreddit
         super().__init__(reddit, _data=_data)
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         for rule in self.subreddit.rules:
             if rule.short_name == self.short_name:
                 self.__dict__.update(rule.__dict__)
@@ -119,11 +119,11 @@ class RuleModeration:
 
     """
 
-    def __init__(self, rule: praw.models.Rule):
+    def __init__(self, rule: praw.models.Rule) -> None:
         """Initialize a :class:`.RuleModeration` instance."""
         self.rule = rule
 
-    def delete(self):
+    def delete(self) -> None:
         """Delete a rule from this subreddit.
 
         To delete ``"No spam"`` from r/test try:
@@ -287,7 +287,7 @@ class SubredditRules:
             return self._rule_list[short_name]
         return Rule(self._reddit, subreddit=self.subreddit, short_name=short_name)
 
-    def __init__(self, subreddit: praw.models.Subreddit):
+    def __init__(self, subreddit: praw.models.Subreddit) -> None:
         """Initialize a :class:`.SubredditRules` instance.
 
         :param subreddit: The subreddit whose rules to work with.
@@ -338,7 +338,7 @@ class SubredditRulesModeration:
 
     """
 
-    def __init__(self, subreddit_rules: SubredditRules):
+    def __init__(self, subreddit_rules: SubredditRules) -> None:
         """Initialize a :class:`.SubredditRulesModeration` instance."""
         self.subreddit_rules = subreddit_rules
 
diff --git a/praw/models/reddit/submission.py b/praw/models/reddit/submission.py
index 65e20015..82df997e 100644
--- a/praw/models/reddit/submission.py
+++ b/praw/models/reddit/submission.py
@@ -10,20 +10,20 @@ from warnings import warn
 
 from prawcore import Conflict
 
-from ...const import API_PATH
-from ...exceptions import InvalidURL
-from ...util import cachedproperty
-from ..comment_forest import CommentForest
-from ..listing.listing import Listing
-from ..listing.mixins import SubmissionListingMixin
-from .base import RedditBase
-from .mixins import FullnameMixin, ModNoteMixin, ThingModerationMixin, UserContentMixin
-from .poll import PollData
-from .redditor import Redditor
-from .subreddit import Subreddit
-
-if TYPE_CHECKING:  # pragma: no cover
-    from collections.abc import Generator
+from praw.const import API_PATH
+from praw.exceptions import InvalidURL
+from praw.models.comment_forest import CommentForest
+from praw.models.listing.listing import Listing
+from praw.models.listing.mixins import SubmissionListingMixin
+from praw.models.reddit.base import RedditBase
+from praw.models.reddit.mixins import FullnameMixin, ModNoteMixin, ThingModerationMixin, UserContentMixin
+from praw.models.reddit.poll import PollData
+from praw.models.reddit.redditor import Redditor
+from praw.models.reddit.subreddit import Subreddit
+from praw.util import cachedproperty
+
+if TYPE_CHECKING:
+    from collections.abc import Iterator
 
     import praw.models
 
@@ -40,7 +40,7 @@ MEDIA_TYPE_MAPPING = {
 class SubmissionFlair:
     """Provide a set of functions pertaining to :class:`.Submission` flair."""
 
-    def __init__(self, submission: praw.models.Submission):
+    def __init__(self, submission: praw.models.Submission) -> None:
         """Initialize a :class:`.SubmissionFlair` instance.
 
         :param submission: The :class:`.Submission` associated with the flair functions.
@@ -63,7 +63,7 @@ class SubmissionFlair:
         url = API_PATH["flairselector"].format(subreddit=self.submission.subreddit)
         return self.submission._reddit.post(url, data={"link": self.submission.fullname})["choices"]
 
-    def select(self, flair_template_id: str, *, text: str | None = None):
+    def select(self, flair_template_id: str, *, text: str | None = None) -> None:
         """Select flair for submission.
 
         :param flair_template_id: The flair template to select. The possible values can
@@ -104,7 +104,7 @@ class SubmissionModeration(ThingModerationMixin, ModNoteMixin):
 
     REMOVAL_MESSAGE_API = "removal_link_message"
 
-    def __init__(self, submission: praw.models.Submission):
+    def __init__(self, submission: praw.models.Submission) -> None:
         """Initialize a :class:`.SubmissionModeration` instance.
 
         :param submission: The submission to moderate.
@@ -112,7 +112,7 @@ class SubmissionModeration(ThingModerationMixin, ModNoteMixin):
         """
         self.thing = submission
 
-    def contest_mode(self, *, state: bool = True):
+    def contest_mode(self, *, state: bool = True) -> None:
         """Set contest mode for the comments of this submission.
 
         :param state: ``True`` enables contest mode and ``False`` disables (default:
@@ -142,7 +142,7 @@ class SubmissionModeration(ThingModerationMixin, ModNoteMixin):
         css_class: str = "",
         flair_template_id: str | None = None,
         text: str = "",
-    ):
+    ) -> None:
         """Set flair for the submission.
 
         :param css_class: The css class to associate with the flair html (default:
@@ -173,7 +173,7 @@ class SubmissionModeration(ThingModerationMixin, ModNoteMixin):
             url = API_PATH["select_flair"].format(subreddit=self.thing.subreddit)
         self.thing._reddit.post(url, data=data)
 
-    def nsfw(self):
+    def nsfw(self) -> None:
         """Mark as not safe for work.
 
         This method can be used both by the submission author and moderators of the
@@ -193,7 +193,7 @@ class SubmissionModeration(ThingModerationMixin, ModNoteMixin):
         """
         self.thing._reddit.post(API_PATH["marknsfw"], data={"id": self.thing.fullname})
 
-    def set_original_content(self):
+    def set_original_content(self) -> None:
         """Mark as original content.
 
         This method can be used by moderators of the subreddit that the submission
@@ -221,7 +221,7 @@ class SubmissionModeration(ThingModerationMixin, ModNoteMixin):
         }
         self.thing._reddit.post(API_PATH["set_original_content"], data=data)
 
-    def sfw(self):
+    def sfw(self) -> None:
         """Mark as safe for work.
 
         This method can be used both by the submission author and moderators of the
@@ -241,7 +241,7 @@ class SubmissionModeration(ThingModerationMixin, ModNoteMixin):
         """
         self.thing._reddit.post(API_PATH["unmarknsfw"], data={"id": self.thing.fullname})
 
-    def spoiler(self):
+    def spoiler(self) -> None:
         """Indicate that the submission contains spoilers.
 
         This method can be used both by the submission author and moderators of the
@@ -296,7 +296,7 @@ class SubmissionModeration(ThingModerationMixin, ModNoteMixin):
         except Conflict:
             pass
 
-    def suggested_sort(self, *, sort: str = "blank"):
+    def suggested_sort(self, *, sort: str = "blank") -> None:
         """Set the suggested sort for the comments of the submission.
 
         :param sort: Can be one of: ``"confidence"``, ``"top"``, ``"new"``,
@@ -306,7 +306,7 @@ class SubmissionModeration(ThingModerationMixin, ModNoteMixin):
         """
         self.thing._reddit.post(API_PATH["suggested_sort"], data={"id": self.thing.fullname, "sort": sort})
 
-    def unset_original_content(self):
+    def unset_original_content(self) -> None:
         """Indicate that the submission is not original content.
 
         This method can be used by moderators of the subreddit that the submission
@@ -334,7 +334,7 @@ class SubmissionModeration(ThingModerationMixin, ModNoteMixin):
         }
         self.thing._reddit.post(API_PATH["set_original_content"], data=data)
 
-    def unspoiler(self):
+    def unspoiler(self) -> None:
         """Indicate that the submission does not contain spoilers.
 
         This method can be used both by the submission author and moderators of the
@@ -354,7 +354,7 @@ class SubmissionModeration(ThingModerationMixin, ModNoteMixin):
         """
         self.thing._reddit.post(API_PATH["unspoiler"], data={"id": self.thing.fullname})
 
-    def update_crowd_control_level(self, level: int):
+    def update_crowd_control_level(self, level: int) -> None:
         """Change the Crowd Control level of the submission.
 
         :param level: An integer between 0 and 3.
@@ -369,7 +369,7 @@ class SubmissionModeration(ThingModerationMixin, ModNoteMixin):
                        automatically collapsed.
         2     Moderate Comments from new users and users with negative karma in the
                        subreddit are automatically collapsed.
-        3     Strict   Comments from users who haven’t joined the subreddit, new users,
+        3     Strict   Comments from users who haven't joined the subreddit, new users,
                        and users with negative karma in the subreddit are automatically
                        collapsed.
         ===== ======== ================================================================
@@ -566,7 +566,7 @@ class Submission(SubmissionListingMixin, UserContentMixin, FullnameMixin, Reddit
         id: str | None = None,
         url: str | None = None,
         _data: dict[str, Any] | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.Submission` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
@@ -576,7 +576,7 @@ class Submission(SubmissionListingMixin, UserContentMixin, FullnameMixin, Reddit
         Either ``id`` or ``url`` can be provided, but not both.
 
         """
-        if (id, url, _data).count(None) != 2:
+        if sum(1 for value in (id, url, _data) if value is not None) != 1:
             msg = "Exactly one of 'id', 'url', or '_data' must be provided."
             raise TypeError(msg)
         self.comment_limit = 2048
@@ -594,7 +594,7 @@ class Submission(SubmissionListingMixin, UserContentMixin, FullnameMixin, Reddit
         self._additional_fetch_params = {}
         self._comments_by_id = {}
 
-    def __setattr__(self, attribute: str, value: Any):
+    def __setattr__(self, attribute: str, value: Any) -> None:
         """Objectify author, subreddit, and poll data attributes."""
         if attribute == "author":
             value = Redditor.from_data(self._reddit, value)
@@ -621,7 +621,7 @@ class Submission(SubmissionListingMixin, UserContentMixin, FullnameMixin, Reddit
         *,
         chunk_size: int,
         other_submissions: list[praw.models.Submission] | None,
-    ) -> Generator[str, None, None]:
+    ) -> Iterator[str]:
         all_submissions = [self.fullname]
         if other_submissions:
             all_submissions += [x.fullname for x in other_submissions]
@@ -704,7 +704,7 @@ class Submission(SubmissionListingMixin, UserContentMixin, FullnameMixin, Reddit
             self.__dict__.update(updated)
         return self
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         data = self._fetch_data()
         submission_listing, comment_listing = data
         comment_listing = Listing(self._reddit, _data=comment_listing["data"])
@@ -719,20 +719,20 @@ class Submission(SubmissionListingMixin, UserContentMixin, FullnameMixin, Reddit
         self.comments._update(comment_listing.children)
         super()._fetch()
 
-    def _fetch_data(self):
+    def _fetch_data(self) -> dict:
         name, fields, params = self._fetch_info()
         params.update(self._additional_fetch_params.copy())
         path = API_PATH[name].format(**fields)
         return self._reddit.request(method="GET", params=params, path=path)
 
-    def _fetch_info(self):
+    def _fetch_info(self) -> tuple[str, dict[str, str], dict[str, int | str]]:
         return (
             "submission",
             {"id": self.id},
             {"limit": self.comment_limit, "sort": self.comment_sort},
         )
 
-    def _replace_richtext_links(self, richtext_json: dict):
+    def _replace_richtext_links(self, richtext_json: dict) -> None:
         parsed_media_types = {
             media_id: MEDIA_TYPE_MAPPING[value["e"]] for media_id, value in self.media_metadata.items()
         }
@@ -761,7 +761,7 @@ class Submission(SubmissionListingMixin, UserContentMixin, FullnameMixin, Reddit
                             correct_element["c"] = item["t"]
                         richtext_json["document"][index] = correct_element
 
-    def add_fetch_param(self, key: str, value: str):
+    def add_fetch_param(self, key: str, value: str) -> None:
         """Add a parameter to be used for the next fetch.
 
         :param key: The key of the fetch parameter.
@@ -852,7 +852,7 @@ class Submission(SubmissionListingMixin, UserContentMixin, FullnameMixin, Reddit
 
         return self._reddit.post(API_PATH["submit"], data=data)
 
-    def hide(self, *, other_submissions: list[praw.models.Submission] | None = None):
+    def hide(self, *, other_submissions: list[praw.models.Submission] | None = None) -> None:
         """Hide :class:`.Submission`.
 
         :param other_submissions: When provided, additionally hide this list of
@@ -874,7 +874,7 @@ class Submission(SubmissionListingMixin, UserContentMixin, FullnameMixin, Reddit
         for submissions in self._chunk(chunk_size=50, other_submissions=other_submissions):
             self._reddit.post(API_PATH["hide"], data={"id": submissions})
 
-    def mark_visited(self):
+    def mark_visited(self) -> None:
         """Mark submission as visited.
 
         This method requires a subscription to reddit premium.
@@ -890,7 +890,7 @@ class Submission(SubmissionListingMixin, UserContentMixin, FullnameMixin, Reddit
         data = {"links": self.fullname}
         self._reddit.post(API_PATH["store_visits"], data=data)
 
-    def unhide(self, *, other_submissions: list[praw.models.Submission] | None = None):
+    def unhide(self, *, other_submissions: list[praw.models.Submission] | None = None) -> None:
         """Unhide :class:`.Submission`.
 
         :param other_submissions: When provided, additionally unhide this list of
diff --git a/praw/models/reddit/subreddit.py b/praw/models/reddit/subreddit.py
index 6bdf6fd4..ad5a86f7 100644
--- a/praw/models/reddit/subreddit.py
+++ b/praw/models/reddit/subreddit.py
@@ -17,8 +17,8 @@ from prawcore import Redirect
 from prawcore.exceptions import ServerError
 from requests.exceptions import HTTPError
 
-from ...const import API_PATH, JPEG_HEADER
-from ...exceptions import (
+from praw.const import API_PATH, JPEG_HEADER
+from praw.exceptions import (
     ClientException,
     InvalidFlairTemplateID,
     MediaPostFailed,
@@ -26,20 +26,20 @@ from ...exceptions import (
     TooLargeMediaException,
     WebSocketException,
 )
-from ...util import cachedproperty
-from ..listing.generator import ListingGenerator
-from ..listing.mixins import SubredditListingMixin
-from ..util import permissions_string, stream_generator
-from .base import RedditBase
-from .emoji import SubredditEmoji
-from .mixins import FullnameMixin, MessageableMixin
-from .modmail import ModmailConversation
-from .removal_reasons import SubredditRemovalReasons
-from .rules import SubredditRules
-from .widgets import SubredditWidgets, WidgetEncoder
-from .wikipage import WikiPage
-
-if TYPE_CHECKING:  # pragma: no cover
+from praw.models.listing.generator import ListingGenerator
+from praw.models.listing.mixins import SubredditListingMixin
+from praw.models.reddit.base import RedditBase
+from praw.models.reddit.emoji import SubredditEmoji
+from praw.models.reddit.mixins import FullnameMixin, MessageableMixin
+from praw.models.reddit.modmail import ModmailConversation
+from praw.models.reddit.removal_reasons import SubredditRemovalReasons
+from praw.models.reddit.rules import SubredditRules
+from praw.models.reddit.widgets import SubredditWidgets, WidgetEncoder
+from praw.models.reddit.wikipage import WikiPage
+from praw.models.util import permissions_string, stream_generator
+from praw.util import cachedproperty
+
+if TYPE_CHECKING:
     from collections.abc import Generator, Iterator
 
     from requests import Response
@@ -59,7 +59,7 @@ class Modmail:
 
     """
 
-    def __call__(self, id: str | None = None, mark_read: bool = False) -> ModmailConversation:
+    def __call__(self, id: str | None = None, *, mark_read: bool = False) -> ModmailConversation:
         """Return an individual conversation.
 
         :param id: A reddit base36 conversation ID, e.g., ``"2gmz"``.
@@ -102,11 +102,11 @@ class Modmail:
         """
         return ModmailConversation(self.subreddit._reddit, id=id, mark_read=mark_read)
 
-    def __init__(self, subreddit: praw.models.Subreddit):
+    def __init__(self, subreddit: praw.models.Subreddit) -> None:
         """Initialize a :class:`.Modmail` instance."""
         self.subreddit = subreddit
 
-    def _build_subreddit_list(self, other_subreddits: list[praw.models.Subreddit] | None):
+    def _build_subreddit_list(self, other_subreddits: list[praw.models.Subreddit] | None) -> str:
         """Return a comma-separated list of subreddit display names."""
         subreddits = [self.subreddit] + (other_subreddits or [])
         return ",".join(str(subreddit) for subreddit in subreddits)
@@ -224,7 +224,7 @@ class Modmail:
         }
         return self.subreddit._reddit.post(API_PATH["modmail_conversations"], data=data)
 
-    def subreddits(self) -> Generator[praw.models.Subreddit, None, None]:
+    def subreddits(self) -> Iterator[praw.models.Subreddit]:
         """Yield subreddits using the new modmail that the user moderates.
 
         For example:
@@ -273,7 +273,7 @@ class SubredditFilters:
 
     """
 
-    def __init__(self, subreddit: praw.models.Subreddit):
+    def __init__(self, subreddit: praw.models.Subreddit) -> None:
         """Initialize a :class:`.SubredditFilters` instance.
 
         :param subreddit: The special subreddit whose filters to work with.
@@ -284,7 +284,7 @@ class SubredditFilters:
         """
         self.subreddit = subreddit
 
-    def __iter__(self) -> Generator[praw.models.Subreddit, None, None]:
+    def __iter__(self) -> Iterator[praw.models.Subreddit]:
         """Iterate through the special :class:`.Subreddit`'s filters.
 
         This method should be invoked as:
@@ -300,7 +300,7 @@ class SubredditFilters:
         response_data = self.subreddit._reddit.get(url, params=params)
         yield from response_data.subreddits
 
-    def add(self, subreddit: praw.models.Subreddit | str):
+    def add(self, subreddit: praw.models.Subreddit | str) -> None:
         """Add ``subreddit`` to the list of filtered subreddits.
 
         :param subreddit: The subreddit to add to the filter list.
@@ -325,7 +325,7 @@ class SubredditFilters:
         )
         self.subreddit._reddit.put(url, data={"model": dumps({"name": str(subreddit)})})
 
-    def remove(self, subreddit: praw.models.Subreddit | str):
+    def remove(self, subreddit: praw.models.Subreddit | str) -> None:
         """Remove ``subreddit`` from the list of filtered subreddits.
 
         :param subreddit: The subreddit to remove from the filter list.
@@ -406,7 +406,7 @@ class SubredditFlair:
         url = API_PATH["flairlist"].format(subreddit=self.subreddit)
         return ListingGenerator(self.subreddit._reddit, url, **generator_kwargs)
 
-    def __init__(self, subreddit: praw.models.Subreddit):
+    def __init__(self, subreddit: praw.models.Subreddit) -> None:
         """Initialize a :class:`.SubredditFlair` instance.
 
         :param subreddit: The subreddit whose flair to work with.
@@ -422,7 +422,7 @@ class SubredditFlair:
         position: str = "right",
         self_assign: bool = False,
         **settings: Any,
-    ):
+    ) -> None:
         """Update the :class:`.Subreddit`'s flair configuration.
 
         :param link_position: One of ``"left"``, ``"right"``, or ``False`` to disable
@@ -453,7 +453,7 @@ class SubredditFlair:
         url = API_PATH["flairconfig"].format(subreddit=self.subreddit)
         self.subreddit._reddit.post(url, data=data)
 
-    def delete(self, redditor: praw.models.Redditor | str):
+    def delete(self, redditor: praw.models.Redditor | str) -> None:
         """Delete flair for a :class:`.Redditor`.
 
         :param redditor: A redditor name or :class:`.Redditor` instance.
@@ -475,14 +475,14 @@ class SubredditFlair:
         """
         return self.update(x["user"] for x in self())
 
-    def set(  # noqa: A003
+    def set(
         self,
         redditor: praw.models.Redditor | str,
         *,
         css_class: str = "",
         flair_template_id: str | None = None,
         text: str = "",
-    ):
+    ) -> None:
         """Set flair for a :class:`.Redditor`.
 
         :param redditor: A redditor name or :class:`.Redditor` instance.
@@ -579,11 +579,11 @@ class SubredditFlairTemplates:
     """Provide functions to interact with a :class:`.Subreddit`'s flair templates."""
 
     @staticmethod
-    def flair_type(is_link: bool) -> str:
+    def flair_type(*, is_link: bool) -> str:
         """Return ``"LINK_FLAIR"`` or ``"USER_FLAIR"`` depending on ``is_link`` value."""
         return "LINK_FLAIR" if is_link else "USER_FLAIR"
 
-    def __init__(self, subreddit: praw.models.Subreddit):
+    def __init__(self, subreddit: praw.models.Subreddit) -> None:
         """Initialize a :class:`.SubredditFlairTemplates` instance.
 
         :param subreddit: The subreddit whose flair templates to work with.
@@ -597,7 +597,7 @@ class SubredditFlairTemplates:
         """
         self.subreddit = subreddit
 
-    def __iter__(self):
+    def __iter__(self) -> Iterator[None]:
         """Abstract method to return flair templates."""
         raise NotImplementedError
 
@@ -613,13 +613,13 @@ class SubredditFlairTemplates:
         text: str,
         text_color: str | None = None,
         text_editable: bool = False,
-    ):
+    ) -> None:
         url = API_PATH["flairtemplate_v2"].format(subreddit=self.subreddit)
         data = {
             "allowable_content": allowable_content,
             "background_color": background_color,
             "css_class": css_class,
-            "flair_type": self.flair_type(is_link),
+            "flair_type": self.flair_type(is_link=is_link),
             "max_emojis": max_emojis,
             "mod_only": bool(mod_only),
             "text": text,
@@ -628,22 +628,22 @@ class SubredditFlairTemplates:
         }
         self.subreddit._reddit.post(url, data=data)
 
-    def _clear(self, *, is_link: bool | None = None):
+    def _clear(self, *, is_link: bool | None = None) -> None:
         url = API_PATH["flairtemplateclear"].format(subreddit=self.subreddit)
-        self.subreddit._reddit.post(url, data={"flair_type": self.flair_type(is_link)})
+        self.subreddit._reddit.post(url, data={"flair_type": self.flair_type(is_link=is_link)})
 
-    def _reorder(self, flair_list: list, *, is_link: bool | None = None):
+    def _reorder(self, flair_list: list, *, is_link: bool | None = None) -> None:
         url = API_PATH["flairtemplatereorder"].format(subreddit=self.subreddit)
         self.subreddit._reddit.patch(
             url,
             params={
-                "flair_type": self.flair_type(is_link),
+                "flair_type": self.flair_type(is_link=is_link),
                 "subreddit": self.subreddit.display_name,
             },
             json=flair_list,
         )
 
-    def delete(self, template_id: str):
+    def delete(self, template_id: str) -> None:
         """Remove a flair template provided by ``template_id``.
 
         For example, to delete the first :class:`.Redditor` flair template listed, try:
@@ -670,7 +670,7 @@ class SubredditFlairTemplates:
         text: str | None = None,
         text_color: str | None = None,
         text_editable: bool | None = None,
-    ):
+    ) -> None:
         """Update the flair template provided by ``template_id``.
 
         :param template_id: The flair template to update. If not valid then an exception
@@ -723,10 +723,10 @@ class SubredditFlairTemplates:
             "text_editable": text_editable,
         }
         if fetch:
-            _existing_data = [template for template in iter(self) if template["id"] == template_id]
-            if len(_existing_data) != 1:
+            existing_data_ = [template for template in iter(self) if template["id"] == template_id]
+            if len(existing_data_) != 1:
                 raise InvalidFlairTemplateID(template_id)
-            existing_data = _existing_data[0]
+            existing_data = existing_data_[0]
             for key, value in existing_data.items():
                 if data.get(key) is None:
                     data[key] = value
@@ -745,7 +745,7 @@ class SubredditModeration:
     """
 
     @staticmethod
-    def _handle_only(*, generator_kwargs: dict[str, Any], only: str | None):
+    def _handle_only(*, generator_kwargs: dict[str, Any], only: str | None) -> None:
         if only is not None:
             if only == "submissions":
                 only = "links"
@@ -813,7 +813,7 @@ class SubredditModeration:
         """
         return SubredditModerationStream(self.subreddit)
 
-    def __init__(self, subreddit: praw.models.Subreddit):
+    def __init__(self, subreddit: praw.models.Subreddit) -> None:
         """Initialize a :class:`.SubredditModeration` instance.
 
         :param subreddit: The subreddit to moderate.
@@ -822,7 +822,7 @@ class SubredditModeration:
         self.subreddit = subreddit
         self._stream = None
 
-    def accept_invite(self):
+    def accept_invite(self) -> None:
         """Accept an invitation as a moderator of the community."""
         url = API_PATH["accept_mod_invite"].format(subreddit=self.subreddit)
         self.subreddit._reddit.post(url)
@@ -1102,7 +1102,7 @@ class SubredditModeration:
 class SubredditModerationStream:
     """Provides moderator streams."""
 
-    def __init__(self, subreddit: praw.models.Subreddit):
+    def __init__(self, subreddit: praw.models.Subreddit) -> None:
         """Initialize a :class:`.SubredditModerationStream` instance.
 
         :param subreddit: The moderated subreddit associated with the streams.
@@ -1112,7 +1112,7 @@ class SubredditModerationStream:
 
     def edited(
         self, *, only: str | None = None, **stream_options: Any
-    ) -> Generator[praw.models.Comment | praw.models.Submission, None, None]:
+    ) -> Iterator[praw.models.Comment | praw.models.Submission]:
         """Yield edited comments and submissions as they become available.
 
         :param only: If specified, one of ``"comments"`` or ``"submissions"`` to yield
@@ -1137,7 +1137,7 @@ class SubredditModerationStream:
         action: str | None = None,
         mod: str | praw.models.Redditor | None = None,
         **stream_options: Any,
-    ) -> Generator[praw.models.ModAction, None, None]:
+    ) -> Iterator[praw.models.ModAction]:
         """Yield moderator log entries as they become available.
 
         :param action: If given, only return log entries for the specified action.
@@ -1168,7 +1168,7 @@ class SubredditModerationStream:
         sort: str | None = None,
         state: str | None = None,
         **stream_options: Any,
-    ) -> Generator[ModmailConversation, None, None]:
+    ) -> Iterator[ModmailConversation]:
         """Yield new-modmail conversations as they become available.
 
         :param other_subreddits: A list of :class:`.Subreddit` instances for which to
@@ -1206,7 +1206,7 @@ class SubredditModerationStream:
 
     def modqueue(
         self, *, only: str | None = None, **stream_options: Any
-    ) -> Generator[praw.models.Comment | praw.models.Submission, None, None]:
+    ) -> Iterator[praw.models.Comment | praw.models.Submission]:
         r"""Yield :class:`.Comment`\ s and :class:`.Submission`\ s in the modqueue as they become available.
 
         :param only: If specified, one of ``"comments"`` or ``"submissions"`` to yield
@@ -1226,7 +1226,7 @@ class SubredditModerationStream:
 
     def reports(
         self, *, only: str | None = None, **stream_options: Any
-    ) -> Generator[praw.models.Comment | praw.models.Submission, None, None]:
+    ) -> Iterator[praw.models.Comment | praw.models.Submission]:
         r"""Yield reported :class:`.Comment`\ s and :class:`.Submission`\ s as they become available.
 
         :param only: If specified, one of ``"comments"`` or ``"submissions"`` to yield
@@ -1246,7 +1246,7 @@ class SubredditModerationStream:
 
     def spam(
         self, *, only: str | None = None, **stream_options: Any
-    ) -> Generator[praw.models.Comment | praw.models.Submission, None, None]:
+    ) -> Iterator[praw.models.Comment | praw.models.Submission]:
         r"""Yield spam :class:`.Comment`\ s and :class:`.Submission`\ s as they become available.
 
         :param only: If specified, one of ``"comments"`` or ``"submissions"`` to yield
@@ -1264,7 +1264,7 @@ class SubredditModerationStream:
         """
         return stream_generator(self.subreddit.mod.spam, only=only, **stream_options)
 
-    def unmoderated(self, **stream_options: Any) -> Generator[praw.models.Submission, None, None]:
+    def unmoderated(self, **stream_options: Any) -> Iterator[praw.models.Submission]:
         r"""Yield unmoderated :class:`.Submission`\ s as they become available.
 
         Keyword arguments are passed to :func:`.stream_generator`.
@@ -1291,7 +1291,7 @@ class SubredditQuarantine:
 
     """
 
-    def __init__(self, subreddit: praw.models.Subreddit):
+    def __init__(self, subreddit: praw.models.Subreddit) -> None:
         """Initialize a :class:`.SubredditQuarantine` instance.
 
         :param subreddit: The :class:`.Subreddit` associated with the quarantine.
@@ -1299,7 +1299,7 @@ class SubredditQuarantine:
         """
         self.subreddit = subreddit
 
-    def opt_in(self):
+    def opt_in(self) -> None:
         """Permit your user access to the quarantined subreddit.
 
         Usage:
@@ -1317,7 +1317,7 @@ class SubredditQuarantine:
         with contextlib.suppress(Redirect):
             self.subreddit._reddit.post(API_PATH["quarantine_opt_in"], data=data)
 
-    def opt_out(self):
+    def opt_out(self) -> None:
         """Remove access to the quarantined subreddit.
 
         Usage:
@@ -1370,7 +1370,7 @@ class SubredditRelationship:
         url = API_PATH[f"list_{self.relationship}"].format(subreddit=self.subreddit)
         return ListingGenerator(self.subreddit._reddit, url, **generator_kwargs)
 
-    def __init__(self, subreddit: praw.models.Subreddit, relationship: str):
+    def __init__(self, subreddit: praw.models.Subreddit, relationship: str) -> None:
         """Initialize a :class:`.SubredditRelationship` instance.
 
         :param subreddit: The :class:`.Subreddit` for the relationship.
@@ -1380,7 +1380,7 @@ class SubredditRelationship:
         self.relationship = relationship
         self.subreddit = subreddit
 
-    def add(self, redditor: str | praw.models.Redditor, **other_settings: Any):
+    def add(self, redditor: str | praw.models.Redditor, **other_settings: Any) -> None:
         """Add ``redditor`` to this relationship.
 
         :param redditor: A redditor name or :class:`.Redditor` instance.
@@ -1391,7 +1391,7 @@ class SubredditRelationship:
         url = API_PATH["friend"].format(subreddit=self.subreddit)
         self.subreddit._reddit.post(url, data=data)
 
-    def remove(self, redditor: str | praw.models.Redditor):
+    def remove(self, redditor: str | praw.models.Redditor) -> None:
         """Remove ``redditor`` from this relationship.
 
         :param redditor: A redditor name or :class:`.Redditor` instance.
@@ -1405,7 +1405,7 @@ class SubredditRelationship:
 class SubredditStream:
     """Provides submission and comment streams."""
 
-    def __init__(self, subreddit: praw.models.Subreddit):
+    def __init__(self, subreddit: praw.models.Subreddit) -> None:
         """Initialize a :class:`.SubredditStream` instance.
 
         :param subreddit: The subreddit associated with the streams.
@@ -1413,7 +1413,7 @@ class SubredditStream:
         """
         self.subreddit = subreddit
 
-    def comments(self, **stream_options: Any) -> Generator[praw.models.Comment, None, None]:
+    def comments(self, **stream_options: Any) -> Iterator[praw.models.Comment]:
         """Yield new comments as they become available.
 
         Comments are yielded oldest first. Up to 100 historical comments will initially
@@ -1445,7 +1445,7 @@ class SubredditStream:
         """
         return stream_generator(self.subreddit.comments, **stream_options)
 
-    def submissions(self, **stream_options: Any) -> Generator[praw.models.Submission, None, None]:
+    def submissions(self, **stream_options: Any) -> Iterator[praw.models.Submission]:
         r"""Yield new :class:`.Submission`\ s as they become available.
 
         Submissions are yielded oldest first. Up to 100 historical submissions will
@@ -1496,7 +1496,7 @@ class SubredditStylesheet:
         url = API_PATH["about_stylesheet"].format(subreddit=self.subreddit)
         return self.subreddit._reddit.get(url)
 
-    def __init__(self, subreddit: praw.models.Subreddit):
+    def __init__(self, subreddit: praw.models.Subreddit) -> None:
         """Initialize a :class:`.SubredditStylesheet` instance.
 
         :param subreddit: The :class:`.Subreddit` associated with the stylesheet.
@@ -1510,7 +1510,7 @@ class SubredditStylesheet:
         """
         self.subreddit = subreddit
 
-    def _update_structured_styles(self, style_data: dict[str, str | Any]):
+    def _update_structured_styles(self, style_data: dict[str, str | Any]) -> None:
         url = API_PATH["structured_styles"].format(subreddit=self.subreddit)
         self.subreddit._reddit.patch(url, data=style_data)
 
@@ -1551,7 +1551,7 @@ class SubredditStylesheet:
 
         return f"{upload_url}/{upload_data['key']}"
 
-    def delete_banner(self):
+    def delete_banner(self) -> None:
         """Remove the current :class:`.Subreddit` (redesign) banner image.
 
         Succeeds even if there is no banner image.
@@ -1566,7 +1566,7 @@ class SubredditStylesheet:
         data = {"bannerBackgroundImage": ""}
         self._update_structured_styles(data)
 
-    def delete_banner_additional_image(self):
+    def delete_banner_additional_image(self) -> None:
         """Remove the current :class:`.Subreddit` (redesign) banner additional image.
 
         Succeeds even if there is no additional image. Will also delete any configured
@@ -1582,7 +1582,7 @@ class SubredditStylesheet:
         data = {"bannerPositionedImage": "", "secondaryBannerPositionedImage": ""}
         self._update_structured_styles(data)
 
-    def delete_banner_hover_image(self):
+    def delete_banner_hover_image(self) -> None:
         """Remove the current :class:`.Subreddit` (redesign) banner hover image.
 
         Succeeds even if there is no hover image.
@@ -1597,7 +1597,7 @@ class SubredditStylesheet:
         data = {"secondaryBannerPositionedImage": ""}
         self._update_structured_styles(data)
 
-    def delete_header(self):
+    def delete_header(self) -> None:
         """Remove the current :class:`.Subreddit` header image.
 
         Succeeds even if there is no header image.
@@ -1612,7 +1612,7 @@ class SubredditStylesheet:
         url = API_PATH["delete_sr_header"].format(subreddit=self.subreddit)
         self.subreddit._reddit.post(url)
 
-    def delete_image(self, name: str):
+    def delete_image(self, name: str) -> None:
         """Remove the named image from the :class:`.Subreddit`.
 
         Succeeds even if the named image does not exist.
@@ -1627,7 +1627,7 @@ class SubredditStylesheet:
         url = API_PATH["delete_sr_image"].format(subreddit=self.subreddit)
         self.subreddit._reddit.post(url, data={"img_name": name})
 
-    def delete_mobile_banner(self):
+    def delete_mobile_banner(self) -> None:
         """Remove the current :class:`.Subreddit` (redesign) mobile banner.
 
         Succeeds even if there is no mobile banner.
@@ -1643,7 +1643,7 @@ class SubredditStylesheet:
         data = {"mobileBannerImage": ""}
         self._update_structured_styles(data)
 
-    def delete_mobile_header(self):
+    def delete_mobile_header(self) -> None:
         """Remove the current :class:`.Subreddit` mobile header.
 
         Succeeds even if there is no mobile header.
@@ -1658,7 +1658,7 @@ class SubredditStylesheet:
         url = API_PATH["delete_sr_header"].format(subreddit=self.subreddit)
         self.subreddit._reddit.post(url)
 
-    def delete_mobile_icon(self):
+    def delete_mobile_icon(self) -> None:
         """Remove the current :class:`.Subreddit` mobile icon.
 
         Succeeds even if there is no mobile icon.
@@ -1673,7 +1673,7 @@ class SubredditStylesheet:
         url = API_PATH["delete_sr_icon"].format(subreddit=self.subreddit)
         self.subreddit._reddit.post(url)
 
-    def update(self, stylesheet: str, *, reason: str | None = None):
+    def update(self, stylesheet: str, *, reason: str | None = None) -> None:
         """Update the :class:`.Subreddit`'s stylesheet.
 
         :param stylesheet: The CSS for the new stylesheet.
@@ -1717,7 +1717,7 @@ class SubredditStylesheet:
         """
         return self._upload_image(data={"name": name, "upload_type": "img"}, image_path=image_path)
 
-    def upload_banner(self, image_path: str):
+    def upload_banner(self, image_path: str) -> None:
         """Upload an image for the :class:`.Subreddit`'s (redesign) banner image.
 
         :param image_path: A path to a jpeg or png image.
@@ -1744,7 +1744,7 @@ class SubredditStylesheet:
         image_path: str,
         *,
         align: str | None = None,
-    ):
+    ) -> None:
         """Upload an image for the :class:`.Subreddit`'s (redesign) additional image.
 
         :param image_path: A path to a jpeg or png image.
@@ -1779,7 +1779,7 @@ class SubredditStylesheet:
             style_data.update(alignment)
         self._update_structured_styles(style_data)
 
-    def upload_banner_hover_image(self, image_path: str):
+    def upload_banner_hover_image(self, image_path: str) -> None:
         """Upload an image for the :class:`.Subreddit`'s (redesign) additional image.
 
         :param image_path: A path to a jpeg or png image.
@@ -1827,7 +1827,7 @@ class SubredditStylesheet:
         """
         return self._upload_image(data={"upload_type": "header"}, image_path=image_path)
 
-    def upload_mobile_banner(self, image_path: str):
+    def upload_mobile_banner(self, image_path: str) -> None:
         """Upload an image for the :class:`.Subreddit`'s (redesign) mobile banner.
 
         :param image_path: A path to a JPEG or PNG image.
@@ -1915,7 +1915,7 @@ class SubredditWiki:
         """
         return WikiPage(self.subreddit._reddit, self.subreddit, page_name.lower())
 
-    def __init__(self, subreddit: praw.models.Subreddit):
+    def __init__(self, subreddit: praw.models.Subreddit) -> None:
         """Initialize a :class:`.SubredditWiki` instance.
 
         :param subreddit: The subreddit whose wiki to work with.
@@ -1925,7 +1925,7 @@ class SubredditWiki:
         self.contributor = SubredditRelationship(subreddit, "wikicontributor")
         self.subreddit = subreddit
 
-    def __iter__(self) -> Generator[WikiPage, None, None]:
+    def __iter__(self) -> Iterator[WikiPage]:
         """Iterate through the pages of the wiki.
 
         This method is to be used to discover all wikipages for a subreddit:
@@ -2011,7 +2011,7 @@ class ContributorRelationship(SubredditRelationship):
 
     """
 
-    def leave(self):
+    def leave(self) -> None:
         """Abdicate the contributor position."""
         self.subreddit._reddit.post(API_PATH["leavecontributor"], data={"id": self.subreddit.fullname})
 
@@ -2028,7 +2028,7 @@ class ModeratorRelationship(SubredditRelationship):
 
     """
 
-    PERMISSIONS = {
+    PERMISSIONS = frozenset({
         "access",
         "chat_config",
         "chat_operator",
@@ -2037,7 +2037,7 @@ class ModeratorRelationship(SubredditRelationship):
         "mail",
         "posts",
         "wiki",
-    }
+    })
 
     @staticmethod
     def _handle_permissions(
@@ -2097,7 +2097,7 @@ class ModeratorRelationship(SubredditRelationship):
         *,
         permissions: list[str] | None = None,
         **other_settings: Any,
-    ):
+    ) -> None:
         """Add or invite ``redditor`` to be a moderator of the :class:`.Subreddit`.
 
         :param redditor: A redditor name or :class:`.Redditor` instance.
@@ -2125,7 +2125,7 @@ class ModeratorRelationship(SubredditRelationship):
         *,
         permissions: list[str] | None = None,
         **other_settings: Any,
-    ):
+    ) -> None:
         """Invite ``redditor`` to be a moderator of the :class:`.Subreddit`.
 
         :param redditor: A redditor name or :class:`.Redditor` instance.
@@ -2181,7 +2181,7 @@ class ModeratorRelationship(SubredditRelationship):
         url = API_PATH["list_invited_moderator"].format(subreddit=self.subreddit)
         return ListingGenerator(self.subreddit._reddit, url, **generator_kwargs)
 
-    def leave(self):
+    def leave(self) -> None:
         """Abdicate the moderator position (use with care).
 
         For example:
@@ -2193,7 +2193,7 @@ class ModeratorRelationship(SubredditRelationship):
         """
         self.remove(self.subreddit._reddit.config.username or self.subreddit._reddit.user.me())
 
-    def remove_invite(self, redditor: str | praw.models.Redditor):
+    def remove_invite(self, redditor: str | praw.models.Redditor) -> None:
         """Remove the moderator invite for ``redditor``.
 
         :param redditor: A redditor name or :class:`.Redditor` instance.
@@ -2214,7 +2214,7 @@ class ModeratorRelationship(SubredditRelationship):
         redditor: str | praw.models.Redditor,
         *,
         permissions: list[str] | None = None,
-    ):
+    ) -> None:
         """Update the moderator permissions for ``redditor``.
 
         :param redditor: A redditor name or :class:`.Redditor` instance.
@@ -2248,7 +2248,7 @@ class ModeratorRelationship(SubredditRelationship):
         redditor: str | praw.models.Redditor,
         *,
         permissions: list[str] | None = None,
-    ):
+    ) -> None:
         """Update the moderator invite permissions for ``redditor``.
 
         :param redditor: A redditor name or :class:`.Redditor` instance.
@@ -2346,6 +2346,7 @@ class Subreddit(MessageableMixin, SubredditListingMixin, FullnameMixin, RedditBa
     """
 
     STR_FIELD = "display_name"
+    MAX_CAPTION_LENGTH = 180
     MESSAGE_PREFIX = "#"
 
     @staticmethod
@@ -2386,7 +2387,7 @@ class Subreddit(MessageableMixin, SubredditListingMixin, FullnameMixin, RedditBa
         wiki_edit_karma: int | None = None,
         wikimode: str | None = None,
         **other_settings: Any,
-    ):
+    ) -> None:
         model = {
             "allow_images": allow_images,
             "allow_post_crossposts": allow_post_crossposts,
@@ -2428,7 +2429,7 @@ class Subreddit(MessageableMixin, SubredditListingMixin, FullnameMixin, RedditBa
         _reddit.post(API_PATH["site_admin"], data=model)
 
     @staticmethod
-    def _parse_xml_response(response: Response):
+    def _parse_xml_response(response: Response) -> None:
         """Parse the XML from a response and raise any errors found."""
         xml = response.text
         root = ElementTree.fromstring(xml)
@@ -2449,7 +2450,7 @@ class Subreddit(MessageableMixin, SubredditListingMixin, FullnameMixin, RedditBa
         return str(subreddit)
 
     @staticmethod
-    def _validate_gallery(images: list[dict[str, str]]):
+    def _validate_gallery(images: list[dict[str, str]]) -> None:
         for image in images:
             image_path = image.get("image_path", "")
             if image_path:
@@ -2459,12 +2460,12 @@ class Subreddit(MessageableMixin, SubredditListingMixin, FullnameMixin, RedditBa
             else:
                 msg = "'image_path' is required."
                 raise TypeError(msg)
-            if not len(image.get("caption", "")) <= 180:
+            if not len(image.get("caption", "")) <= Subreddit.MAX_CAPTION_LENGTH:
                 msg = "Caption must be 180 characters or less."
                 raise TypeError(msg)
 
     @staticmethod
-    def _validate_inline_media(inline_media: praw.models.InlineMedia):
+    def _validate_inline_media(inline_media: praw.models.InlineMedia) -> None:
         if not Path(inline_media.path).is_file():
             msg = f"{inline_media.path!r} is not a valid file path."
             raise ValueError(msg)
@@ -2786,7 +2787,7 @@ class Subreddit(MessageableMixin, SubredditListingMixin, FullnameMixin, RedditBa
         reddit: praw.Reddit,
         display_name: str | None = None,
         _data: dict[str, Any] | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.Subreddit` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
@@ -2821,21 +2822,23 @@ class Subreddit(MessageableMixin, SubredditListingMixin, FullnameMixin, RedditBa
         text_data = {"output_mode": "rtjson", "markdown_text": markdown_text}
         return self._reddit.post(API_PATH["convert_rte_body"], data=text_data)["output"]
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         data = self._fetch_data()
         data = data["data"]
         other = type(self)(self._reddit, _data=data)
         self.__dict__.update(other.__dict__)
         super()._fetch()
 
-    def _fetch_info(self):
+    def _fetch_info(self) -> tuple[str, dict[str, RedditBase], None]:
         return "subreddit_about", {"subreddit": self}, None
 
     def _read_and_post_media(self, file: Path, upload_url: str, upload_data: dict[str, Any]) -> Response:
         with file.open("rb") as media:
             return self._reddit._core._requestor._http.post(upload_url, data=upload_data, files={"file": media})
 
-    def _submit_media(self, *, data: dict[Any, Any], timeout: int, without_websockets: bool):
+    def _submit_media(
+        self, *, data: dict[Any, Any], timeout: int, without_websockets: bool
+    ) -> praw.models.Submission | None:
         """Submit and return an ``image``, ``video``, or ``videogif``.
 
         This is a helper method for submitting posts that are not link posts or self
@@ -2872,7 +2875,7 @@ class Subreddit(MessageableMixin, SubredditListingMixin, FullnameMixin, RedditBa
         url = ws_update["payload"]["redirect"]
         return self._reddit.submission(url=url)
 
-    def _upload_inline_media(self, inline_media: praw.models.InlineMedia):
+    def _upload_inline_media(self, inline_media: praw.models.InlineMedia) -> praw.models.InlineMedia:
         """Upload media for use in self posts and return ``inline_media``.
 
         :param inline_media: An :class:`.InlineMedia` object to validate and upload.
@@ -2888,7 +2891,7 @@ class Subreddit(MessageableMixin, SubredditListingMixin, FullnameMixin, RedditBa
         expected_mime_prefix: str | None = None,
         media_path: str,
         upload_type: str = "link",
-    ):
+    ) -> str:
         """Upload media and return its URL and a websocket (Undocumented endpoint).
 
         :param expected_mime_prefix: If provided, enforce that the media has a mime type
@@ -2896,9 +2899,7 @@ class Subreddit(MessageableMixin, SubredditListingMixin, FullnameMixin, RedditBa
         :param upload_type: One of ``"link"``, ``"gallery"'', or ``"selfpost"``
             (default: ``"link"``).
 
-        :returns: A tuple containing ``(media_url, websocket_url)`` for the piece of
-            media. The websocket URL can be used to determine when media processing is
-            finished, or it can be ignored.
+        :returns: The link to the uploaded media.
 
         """
         if media_path is None:
@@ -2937,8 +2938,6 @@ class Subreddit(MessageableMixin, SubredditListingMixin, FullnameMixin, RedditBa
         except HTTPError as err:
             raise ServerError(response=err.response) from None
 
-        upload_response["asset"]["websocket_url"]
-
         if upload_type == "link":
             return f"{upload_url}/{upload_data['key']}"
         return upload_response["asset"]["asset_id"]
@@ -3586,7 +3585,7 @@ class Subreddit(MessageableMixin, SubredditListingMixin, FullnameMixin, RedditBa
         )
         return self._submit_media(data=data, timeout=timeout, without_websockets=without_websockets)
 
-    def subscribe(self, *, other_subreddits: list[praw.models.Subreddit] | None = None):
+    def subscribe(self, *, other_subreddits: list[praw.models.Subreddit] | None = None) -> None:
         """Subscribe to the subreddit.
 
         :param other_subreddits: When provided, also subscribe to the provided list of
@@ -3634,7 +3633,7 @@ class Subreddit(MessageableMixin, SubredditListingMixin, FullnameMixin, RedditBa
         """
         return self._reddit.get(API_PATH["about_traffic"].format(subreddit=self))
 
-    def unsubscribe(self, *, other_subreddits: list[praw.models.Subreddit] | None = None):
+    def unsubscribe(self, *, other_subreddits: list[praw.models.Subreddit] | None = None) -> None:
         """Unsubscribe from the subreddit.
 
         :param other_subreddits: When provided, also unsubscribe from the provided list
@@ -3662,7 +3661,7 @@ class SubredditLinkFlairTemplates(SubredditFlairTemplates):
 
     def __iter__(
         self,
-    ) -> Generator[dict[str, str | int | bool | list[dict[str, str]]], None, None]:
+    ) -> Iterator[dict[str, str | int | bool | list[dict[str, str]]]]:
         """Iterate through the link flair templates as a moderator.
 
         For example:
@@ -3687,7 +3686,7 @@ class SubredditLinkFlairTemplates(SubredditFlairTemplates):
         mod_only: bool | None = None,
         text_color: str | None = None,
         text_editable: bool = False,
-    ):
+    ) -> None:
         """Add a link flair template to the associated subreddit.
 
         :param text: The flair template's text.
@@ -3729,7 +3728,7 @@ class SubredditLinkFlairTemplates(SubredditFlairTemplates):
             text_editable=text_editable,
         )
 
-    def clear(self):
+    def clear(self) -> None:
         """Remove all link flair templates from the subreddit.
 
         For example:
@@ -3741,7 +3740,7 @@ class SubredditLinkFlairTemplates(SubredditFlairTemplates):
         """
         self._clear(is_link=True)
 
-    def reorder(self, flair_list: list[str]):
+    def reorder(self, flair_list: list[str]) -> None:
         """Reorder a list of flairs.
 
         :param flair_list: A list of flair IDs.
@@ -3759,7 +3758,7 @@ class SubredditLinkFlairTemplates(SubredditFlairTemplates):
 
     def user_selectable(
         self,
-    ) -> Generator[dict[str, str | bool], None, None]:
+    ) -> Iterator[dict[str, str | bool]]:
         """Iterate through the link flair templates as a regular user.
 
         For example:
@@ -3779,7 +3778,7 @@ class SubredditRedditorFlairTemplates(SubredditFlairTemplates):
 
     def __iter__(
         self,
-    ) -> Generator[dict[str, str | int | bool | list[dict[str, str]]], None, None]:
+    ) -> Iterator[dict[str, str | int | bool | list[dict[str, str]]]]:
         """Iterate through the user flair templates.
 
         For example:
@@ -3805,7 +3804,7 @@ class SubredditRedditorFlairTemplates(SubredditFlairTemplates):
         mod_only: bool | None = None,
         text_color: str | None = None,
         text_editable: bool = False,
-    ):
+    ) -> None:
         """Add a redditor flair template to the associated subreddit.
 
         :param text: The flair template's text.
@@ -3847,7 +3846,7 @@ class SubredditRedditorFlairTemplates(SubredditFlairTemplates):
             text_editable=text_editable,
         )
 
-    def clear(self):
+    def clear(self) -> None:
         """Remove all :class:`.Redditor` flair templates from the subreddit.
 
         For example:
@@ -3859,7 +3858,7 @@ class SubredditRedditorFlairTemplates(SubredditFlairTemplates):
         """
         self._clear(is_link=False)
 
-    def reorder(self, flair_list: list[str]):
+    def reorder(self, flair_list: list[str]) -> None:
         """Reorder a list of flairs.
 
         :param flair_list: A list of flair IDs.
diff --git a/praw/models/reddit/user_subreddit.py b/praw/models/reddit/user_subreddit.py
index 03b60027..c0933554 100644
--- a/praw/models/reddit/user_subreddit.py
+++ b/praw/models/reddit/user_subreddit.py
@@ -4,10 +4,10 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, Any
 
-from ...util.cache import cachedproperty
-from .subreddit import Subreddit, SubredditModeration
+from praw.models.reddit.subreddit import Subreddit, SubredditModeration
+from praw.util.cache import cachedproperty
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw.models
 
 
@@ -63,7 +63,7 @@ class UserSubreddit(Subreddit):
         """
         return UserSubredditModeration(self)
 
-    def __init__(self, reddit: praw.Reddit, *args: Any, **kwargs: Any):
+    def __init__(self, reddit: praw.Reddit, *args: Any, **kwargs: Any) -> None:
         """Initialize an :class:`.UserSubreddit` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
diff --git a/praw/models/reddit/widgets.py b/praw/models/reddit/widgets.py
index 920d3c24..238ad13d 100644
--- a/praw/models/reddit/widgets.py
+++ b/praw/models/reddit/widgets.py
@@ -6,12 +6,12 @@ from json import JSONEncoder, dumps
 from pathlib import Path
 from typing import TYPE_CHECKING, Any, TypeVar
 
-from ...const import API_PATH
-from ...util.cache import cachedproperty
-from ..base import PRAWBase
-from ..list.base import BaseList
+from praw.const import API_PATH
+from praw.models.base import PRAWBase
+from praw.models.list.base import BaseList
+from praw.util.cache import cachedproperty
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw.models
 
 WidgetType: TypeVar = TypeVar("WidgetType", bound="Widget")
@@ -266,7 +266,7 @@ class SubredditWidgets(PRAWBase):
         items = {}
         for item_name, data in self._raw_items.items():
             data["subreddit"] = self.subreddit
-            items[item_name] = self._reddit._objector.objectify(data)
+            items[item_name] = self._reddit._objector.objectify(data=data)
         return items
 
     @cachedproperty
@@ -305,7 +305,7 @@ class SubredditWidgets(PRAWBase):
         msg = f"{self.__class__.__name__!r} object has no attribute {attr!r}"
         raise AttributeError(msg)
 
-    def __init__(self, subreddit: praw.models.Subreddit):
+    def __init__(self, subreddit: praw.models.Subreddit) -> None:
         """Initialize a :class:`.SubredditWidgets` instance.
 
         :param subreddit: The :class:`.Subreddit` the widgets belong to.
@@ -322,7 +322,7 @@ class SubredditWidgets(PRAWBase):
         """Return an object initialization representation of the instance."""
         return f"SubredditWidgets(subreddit={self.subreddit!r})"
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         data = self._reddit.get(
             API_PATH["widgets"].format(subreddit=self.subreddit),
             params={"progressive_images": self.progressive_images},
@@ -344,7 +344,7 @@ class SubredditWidgets(PRAWBase):
 
         self._fetched = True
 
-    def refresh(self):
+    def refresh(self) -> None:
         """Refresh the :class:`.Subreddit`'s widgets.
 
         By default, PRAW will not request progressively loading images from Reddit. To
@@ -387,7 +387,7 @@ class Widget(PRAWBase):
         """Return the hash of the current instance."""
         return hash(self.__class__.__name__) ^ hash(self.id.lower())
 
-    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]):
+    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]) -> None:
         """Initialize a :class:`.Widget` instance."""
         self.subreddit = ""  # in case it isn't in _data
         self.id = ""  # in case it isn't in _data
@@ -704,7 +704,7 @@ class CustomWidget(Widget):
 
     """
 
-    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]):
+    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]) -> None:
         """Initialize a :class:`.CustomWidget` instance."""
         _data["imageData"] = [ImageData(reddit, data) for data in _data.pop("imageData")]
         super().__init__(reddit, _data=_data)
@@ -925,7 +925,7 @@ class ModeratorsWidget(Widget, BaseList):
 
     CHILD_ATTRIBUTE = "mods"
 
-    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]):
+    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]) -> None:
         """Initialize a :class:`.ModeratorsWidget` instance."""
         if self.CHILD_ATTRIBUTE not in _data:
             # .mod.update() sometimes returns payload without "mods" field
@@ -1041,7 +1041,7 @@ class RulesWidget(Widget, BaseList):
 
     CHILD_ATTRIBUTE = "data"
 
-    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]):
+    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]) -> None:
         """Initialize a :class:`.RulesWidget` instance."""
         if self.CHILD_ATTRIBUTE not in _data:
             # .mod.update() sometimes returns payload without "data" field
@@ -1124,13 +1124,13 @@ class WidgetModeration:
         widget: Widget,
         subreddit: praw.models.Subreddit | str,
         reddit: praw.Reddit,
-    ):
+    ) -> None:
         """Initialize a :class:`.WidgetModeration` instance."""
         self.widget = widget
         self._reddit = reddit
         self._subreddit = subreddit
 
-    def delete(self):
+    def delete(self) -> None:
         """Delete the widget.
 
         Example usage:
@@ -1167,8 +1167,7 @@ class WidgetModeration:
         path = API_PATH["widget_modify"].format(widget_id=self.widget.id, subreddit=self._subreddit)
         payload = {key: value for key, value in vars(self.widget).items() if not key.startswith("_")}
         del payload["subreddit"]  # not JSON serializable
-        if "mod" in payload:
-            del payload["mod"]
+        payload.pop("mod", None)
         payload.update(kwargs)
         widget = self._reddit.put(path, data={"json": dumps(payload, cls=WidgetEncoder)})
         widget.subreddit = self._subreddit
@@ -1196,7 +1195,7 @@ class SubredditWidgetsModeration:
 
     """
 
-    def __init__(self, subreddit: praw.models.Subreddit, reddit: praw.Reddit):
+    def __init__(self, subreddit: praw.models.Subreddit, reddit: praw.Reddit) -> None:
         """Initialize a :class:`.SubredditWidgetsModeration` instance."""
         self._subreddit = subreddit
         self._reddit = reddit
@@ -1772,7 +1771,7 @@ class SubredditWidgetsModeration:
         text_area.update(other_settings)
         return self._create_widget(text_area)
 
-    def reorder(self, new_order: list[Widget | str], *, section: str = "sidebar"):
+    def reorder(self, new_order: list[Widget | str], *, section: str = "sidebar") -> None:
         """Reorder the widgets.
 
         :param new_order: A list of widgets. Represented as a list that contains
diff --git a/praw/models/reddit/wikipage.py b/praw/models/reddit/wikipage.py
index 5264d343..4086b956 100644
--- a/praw/models/reddit/wikipage.py
+++ b/praw/models/reddit/wikipage.py
@@ -4,14 +4,14 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, Any
 
-from ...const import API_PATH
-from ...util.cache import cachedproperty
-from ..listing.generator import ListingGenerator
-from .base import RedditBase
-from .redditor import Redditor
+from praw.const import API_PATH
+from praw.models.listing.generator import ListingGenerator
+from praw.models.reddit.base import RedditBase
+from praw.models.reddit.redditor import Redditor
+from praw.util.cache import cachedproperty
 
-if TYPE_CHECKING:  # pragma: no cover
-    from collections.abc import Generator, Iterator
+if TYPE_CHECKING:
+    from collections.abc import Iterator
 
     import praw.models
 
@@ -27,7 +27,7 @@ class WikiPageModeration:
 
     """
 
-    def __init__(self, wikipage: WikiPage):
+    def __init__(self, wikipage: WikiPage) -> None:
         """Initialize a :class:`.WikiPageModeration` instance.
 
         :param wikipage: The wikipage to moderate.
@@ -35,7 +35,7 @@ class WikiPageModeration:
         """
         self.wikipage = wikipage
 
-    def add(self, redditor: praw.models.Redditor):
+    def add(self, redditor: praw.models.Redditor) -> None:
         """Add an editor to this :class:`.WikiPage`.
 
         :param redditor: A redditor name or :class:`.Redditor` instance.
@@ -51,7 +51,7 @@ class WikiPageModeration:
         url = API_PATH["wiki_page_editor"].format(subreddit=self.wikipage.subreddit, method="add")
         self.wikipage._reddit.post(url, data=data)
 
-    def remove(self, redditor: praw.models.Redditor):
+    def remove(self, redditor: praw.models.Redditor) -> None:
         """Remove an editor from this :class:`.WikiPage`.
 
         :param redditor: A redditor name or :class:`.Redditor` instance.
@@ -67,7 +67,7 @@ class WikiPageModeration:
         url = API_PATH["wiki_page_editor"].format(subreddit=self.wikipage.subreddit, method="del")
         self.wikipage._reddit.post(url, data=data)
 
-    def revert(self):
+    def revert(self) -> None:
         """Revert a wikipage back to a specific revision.
 
         To revert the page ``"praw_test"`` in r/test to revision ``"1234abc"``, try
@@ -174,7 +174,7 @@ class WikiPage(RedditBase):
         generator_kwargs: dict[str, Any],
         subreddit: praw.models.Subreddit,
         url: str,
-    ) -> Generator[dict[str, Redditor | WikiPage | str | int | bool | None], None, None]:
+    ) -> Iterator[dict[str, Redditor | WikiPage | str | int | bool | None]]:
         for revision in ListingGenerator(subreddit._reddit, url, **generator_kwargs):
             if revision["author"] is not None:
                 revision["author"] = Redditor(subreddit._reddit, _data=revision["author"]["data"])
@@ -201,7 +201,7 @@ class WikiPage(RedditBase):
         name: str,
         revision: str | None = None,
         _data: dict[str, Any] | None = None,
-    ):
+    ) -> None:
         """Initialize a :class:`.WikiPage` instance.
 
         :param revision: A specific revision ID to fetch. By default, fetches the most
@@ -221,7 +221,7 @@ class WikiPage(RedditBase):
         """Return a string representation of the instance."""
         return f"{self.subreddit}/{self.name}"
 
-    def _fetch(self):
+    def _fetch(self) -> None:
         data = self._fetch_data()
         data = data["data"]
         if data["revision_by"] is not None:
@@ -229,7 +229,7 @@ class WikiPage(RedditBase):
         self.__dict__.update(data)
         super()._fetch()
 
-    def _fetch_info(self):
+    def _fetch_info(self) -> tuple[str, dict[str, str], dict[str, str] | None]:
         return (
             "wiki_page",
             {"subreddit": self.subreddit, "page": self.name},
@@ -258,7 +258,7 @@ class WikiPage(RedditBase):
             **generator_kwargs,
         )
 
-    def edit(self, *, content: str, reason: str | None = None, **other_settings: Any):
+    def edit(self, *, content: str, reason: str | None = None, **other_settings: Any) -> None:
         """Edit this wiki page's contents.
 
         :param content: The updated Markdown content of the page.
@@ -289,7 +289,7 @@ class WikiPage(RedditBase):
         """
         return WikiPage(self.subreddit._reddit, self.subreddit, self.name, revision)
 
-    def revisions(self, **generator_kwargs: str | int | dict[str, str]) -> Generator[WikiPage, None, None]:
+    def revisions(self, **generator_kwargs: str | int | dict[str, str]) -> Iterator[WikiPage]:
         """Return a :class:`.ListingGenerator` for page revisions.
 
         Additional keyword arguments are passed in the initialization of
diff --git a/praw/models/redditors.py b/praw/models/redditors.py
index f961046a..c922a10f 100644
--- a/praw/models/redditors.py
+++ b/praw/models/redditors.py
@@ -8,12 +8,12 @@ from typing import TYPE_CHECKING
 
 import prawcore
 
-from ..const import API_PATH
-from .base import PRAWBase
-from .listing.generator import ListingGenerator
-from .util import stream_generator
+from praw.const import API_PATH
+from praw.models.base import PRAWBase
+from praw.models.listing.generator import ListingGenerator
+from praw.models.util import stream_generator
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     from collections.abc import Iterable, Iterator
 
     import praw.models
diff --git a/praw/models/stylesheet.py b/praw/models/stylesheet.py
index 12fd5ff8..4791c885 100644
--- a/praw/models/stylesheet.py
+++ b/praw/models/stylesheet.py
@@ -1,6 +1,6 @@
 """Provide the Stylesheet class."""
 
-from .base import PRAWBase
+from praw.models.base import PRAWBase
 
 
 class Stylesheet(PRAWBase):
diff --git a/praw/models/subreddits.py b/praw/models/subreddits.py
index 8c317747..a749c940 100644
--- a/praw/models/subreddits.py
+++ b/praw/models/subreddits.py
@@ -4,13 +4,13 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING
 
-from ..const import API_PATH
-from . import Subreddit
-from .base import PRAWBase
-from .listing.generator import ListingGenerator
-from .util import stream_generator
+from praw.const import API_PATH
+from praw.models import Subreddit
+from praw.models.base import PRAWBase
+from praw.models.listing.generator import ListingGenerator
+from praw.models.util import stream_generator
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     from collections.abc import Iterator
 
     import praw.models
diff --git a/praw/models/trophy.py b/praw/models/trophy.py
index 933d6db6..0843c893 100644
--- a/praw/models/trophy.py
+++ b/praw/models/trophy.py
@@ -4,9 +4,9 @@ from __future__ import annotations
 
 from typing import TYPE_CHECKING, Any
 
-from .base import PRAWBase
+from praw.models.base import PRAWBase
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw
 
 
@@ -41,7 +41,7 @@ class Trophy(PRAWBase):
         """Return the hash of the current instance."""
         return hash(self.__class__.__name__) ^ hash(self.name)
 
-    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]):
+    def __init__(self, reddit: praw.Reddit, _data: dict[str, Any]) -> None:
         """Initialize a :class:`.Trophy` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
diff --git a/praw/models/user.py b/praw/models/user.py
index bd343ab9..479e576f 100644
--- a/praw/models/user.py
+++ b/praw/models/user.py
@@ -6,16 +6,16 @@ from typing import TYPE_CHECKING
 
 from prawcore import Conflict
 
-from ..const import API_PATH
-from ..exceptions import ReadOnlyException
-from ..models import Preferences
-from ..util.cache import cachedproperty
-from .base import PRAWBase
-from .listing.generator import ListingGenerator
-from .reddit.redditor import Redditor
-from .reddit.subreddit import Subreddit
-
-if TYPE_CHECKING:  # pragma: no cover
+from praw.const import API_PATH
+from praw.exceptions import ReadOnlyException
+from praw.models import Preferences
+from praw.models.base import PRAWBase
+from praw.models.listing.generator import ListingGenerator
+from praw.models.reddit.redditor import Redditor
+from praw.models.reddit.subreddit import Subreddit
+from praw.util.cache import cachedproperty
+
+if TYPE_CHECKING:
     from collections.abc import Iterator
 
     import praw.models
@@ -54,7 +54,7 @@ class User(PRAWBase):
         """
         return Preferences(self._reddit)
 
-    def __init__(self, reddit: praw.Reddit):
+    def __init__(self, reddit: praw.Reddit) -> None:
         """Initialize an :class:`.User` instance.
 
         This class is intended to be interfaced with through ``reddit.user``.
@@ -169,7 +169,9 @@ class User(PRAWBase):
         r"""Return a list of :class:`.Multireddit`\ s belonging to the user."""
         return self._reddit.get(API_PATH["my_multireddits"])
 
-    def pin(self, submission: praw.models.Submission, *, num: int = None, state: bool = True) -> praw.models.Submission:
+    def pin(
+        self, submission: praw.models.Submission, *, num: int | None = None, state: bool = True
+    ) -> praw.models.Submission:
         """Set the pin state of a submission on the authenticated user's profile.
 
         :param submission: An instance of :class:`.Submission` that will be
diff --git a/praw/models/util.py b/praw/models/util.py
index ee15233b..f267c873 100644
--- a/praw/models/util.py
+++ b/praw/models/util.py
@@ -8,7 +8,7 @@ from collections import OrderedDict
 from typing import TYPE_CHECKING, Any, Callable
 
 if TYPE_CHECKING:
-    from collections.abc import Generator
+    from collections.abc import Iterator
 
 
 def permissions_string(*, known_permissions: set[str], permissions: list[str] | None) -> str:
@@ -42,7 +42,7 @@ def stream_generator(
     pause_after: int | None = None,
     skip_existing: bool = False,
     **function_kwargs: Any,
-) -> Generator[Any, None, None]:
+) -> Iterator[Any]:
     """Yield new items from ``function`` as they become available.
 
     :param function: A callable that returns a :class:`.ListingGenerator`, e.g.,
@@ -175,16 +175,16 @@ class BoundedSet:
         self._access(item)
         return item in self._set
 
-    def __init__(self, max_items: int):
+    def __init__(self, max_items: int) -> None:
         """Initialize a :class:`.BoundedSet` instance."""
         self.max_items = max_items
         self._set = OrderedDict()
 
-    def _access(self, item: Any):
+    def _access(self, item: Any) -> None:
         if item in self._set:
             self._set.move_to_end(item)
 
-    def add(self, item: Any):
+    def add(self, item: Any) -> None:
         """Add an item to the set discarding the oldest item if necessary."""
         self._access(item)
         self._set[item] = None
@@ -195,7 +195,7 @@ class BoundedSet:
 class ExponentialCounter:
     """A class to provide an exponential counter with jitter."""
 
-    def __init__(self, max_counter: int):
+    def __init__(self, max_counter: int) -> None:
         """Initialize an :class:`.ExponentialCounter` instance.
 
         :param max_counter: The maximum base value.
@@ -215,6 +215,6 @@ class ExponentialCounter:
         self._base = min(self._base * 2, self._max)
         return value
 
-    def reset(self):
+    def reset(self) -> None:
         """Reset the counter to 1."""
         self._base = 1
diff --git a/praw/objector.py b/praw/objector.py
index 2855fce6..9bb2892e 100644
--- a/praw/objector.py
+++ b/praw/objector.py
@@ -6,20 +6,19 @@ from datetime import datetime
 from json import loads
 from typing import TYPE_CHECKING, Any
 
-from .exceptions import ClientException, RedditAPIException
-from .util import snake_case_keys
+from praw.exceptions import ClientException, RedditAPIException
+from praw.util import snake_case_keys
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     import praw
-
-    from .models.reddit.base import RedditBase
+    from praw.models.reddit.base import RedditBase
 
 
 class Objector:
     """The objector builds :class:`.RedditBase` objects."""
 
     @classmethod
-    def check_error(cls, data: list[Any] | dict[str, dict[str, str]]):
+    def check_error(cls, data: list[Any] | dict[str, dict[str, str]]) -> None:
         """Raise an error if the argument resolves to an error object."""
         if error := cls.parse_error(data):
             raise error
@@ -48,7 +47,7 @@ class Objector:
             raise ClientException(msg, data)
         return RedditAPIException(errors)
 
-    def __init__(self, reddit: praw.Reddit, parsers: dict[str, Any] | None = None):
+    def __init__(self, reddit: praw.Reddit, parsers: dict[str, Any] | None = None) -> None:
         """Initialize an :class:`.Objector` instance.
 
         :param reddit: An instance of :class:`.Reddit`.
@@ -57,9 +56,7 @@ class Objector:
         self.parsers = {} if parsers is None else parsers
         self._reddit = reddit
 
-    def _objectify_dict(  # noqa: PLR0912,PLR0915
-        self, data: dict[str, Any]
-    ) -> RedditBase:
+    def _objectify_dict(self, *, data: dict[str, Any]) -> RedditBase:
         """Create :class:`.RedditBase` objects from dicts.
 
         :param data: The structured data, assumed to be a dict.
@@ -92,7 +89,7 @@ class Objector:
                     obj for obj in conversation["objIds"] if obj["key"] == "messages"
                 ]):
                     conversation["messages"] = [
-                        self.objectify(data["messages"][obj_id["id"]]) for obj_id in conversation["objIds"]
+                        self.objectify(data=data["messages"][obj_id["id"]]) for obj_id in conversation["objIds"]
                     ]
                 conversations.append(conversation)
             data["conversations"] = conversations
@@ -195,7 +192,7 @@ class Objector:
             and {"mod_action_data", "user_note_data"}.issubset(data["created"])
         ):
             data = data["created"]
-            return self._objectify_dict(data)
+            return self._objectify_dict(data=data)
         else:
             if "user" in data:
                 parser = self.parsers[self._reddit.config.kinds["redditor"]]
@@ -203,8 +200,8 @@ class Objector:
             return data
         return parser.parse(data, self._reddit)
 
-    def objectify(  # noqa: PLR0911,PLR0912,PLR0915
-        self, data: dict[str, Any] | list[Any] | bool | None
+    def objectify(
+        self, *, data: dict[str, Any] | list[Any] | bool | None
     ) -> RedditBase | dict[str, Any] | list[Any] | bool | None:
         """Create :class:`.RedditBase` objects from data.
 
@@ -217,7 +214,7 @@ class Objector:
         if data is None:  # 204 no content
             return None
         if isinstance(data, list):
-            return [self.objectify(item) for item in data]
+            return [self.objectify(data=item) for item in data]
         if isinstance(data, bool):  # Reddit.username_available
             return data
         if "json" in data and "errors" in data["json"]:
@@ -237,9 +234,9 @@ class Objector:
             if "websocket_url" in data["json"]["data"]:
                 return data
             if "things" in data["json"]["data"]:  # Submission.reply
-                return self.objectify(data["json"]["data"]["things"])
+                return self.objectify(data=data["json"]["data"]["things"])
             if "rules" in data["json"]["data"]:
-                return self.objectify(loads(data["json"]["data"]["rules"]))
+                return self.objectify(data=loads(data["json"]["data"]["rules"]))
             if "drafts_count" in data["json"]["data"] and all(
                 key not in data["json"]["data"] for key in ["name", "url"]
             ):  # Draft
@@ -260,7 +257,7 @@ class Objector:
             parser = self.parsers["Draft"]
             return parser.parse(data, self._reddit)
         if "rules" in data:
-            return self.objectify(data["rules"])
+            return self.objectify(data=data["rules"])
         if isinstance(data, dict):
-            return self._objectify_dict(data)
+            return self._objectify_dict(data=data)
         return data
diff --git a/praw/reddit.py b/praw/reddit.py
index 65d031b8..02c01e0f 100644
--- a/praw/reddit.py
+++ b/praw/reddit.py
@@ -25,15 +25,11 @@ from prawcore import (
 )
 from prawcore.exceptions import BadRequest
 
-from . import models
-from .config import Config
-from .const import API_PATH, USER_AGENT_FORMAT, __version__
-from .exceptions import (
-    ClientException,
-    MissingRequiredAttributeException,
-    RedditAPIException,
-)
-from .objector import Objector
+from praw import models
+from praw.config import Config
+from praw.const import API_PATH, USER_AGENT_FORMAT, __version__
+from praw.exceptions import ClientException, MissingRequiredAttributeException, RedditAPIException
+from praw.objector import Objector
 
 try:
     from update_checker import update_check
@@ -43,7 +39,7 @@ except ImportError:  # pragma: no cover
     update_check = None
     UPDATE_CHECKER_MISSING = True
 
-if TYPE_CHECKING:  # pragma: no cover
+if TYPE_CHECKING:
     from collections.abc import Generator, Iterable
 
     import prawcore
@@ -93,7 +89,7 @@ class Reddit:
         return self._core == self._read_only_core
 
     @read_only.setter
-    def read_only(self, value: bool):
+    def read_only(self, value: bool) -> None:
         """Set or unset the use of the ReadOnlyAuthorizer.
 
         :raises: :class:`.ClientException` when attempting to unset ``read_only`` and
@@ -112,7 +108,7 @@ class Reddit:
         """Handle the context manager open."""
         return self
 
-    def __exit__(self, *_: object):
+    def __exit__(self, *_: object) -> None:
         """Handle the context manager close."""
 
     def __init__(
@@ -123,7 +119,7 @@ class Reddit:
         requestor_class: type[prawcore.requestor.Requestor] | None = None,
         requestor_kwargs: dict[str, Any] | None = None,
         **config_settings: str | bool | int | None,
-    ):
+    ) -> None:
         """Initialize a :class:`.Reddit` instance.
 
         :param site_name: The name of a section in your ``praw.ini`` file from which to
@@ -184,7 +180,7 @@ class Reddit:
 
         """
         self._core = self._authorized_core = self._read_only_core = None
-        self._objector = None
+        self._objector: Objector
         self._unique_counter = 0
 
         try:
@@ -389,7 +385,7 @@ class Reddit:
 
         """
 
-    def _check_for_async(self):
+    def _check_for_async(self) -> None:
         if self.config.check_for_async:  # pragma: no cover
             try:
                 # noinspection PyUnresolvedReferences
@@ -414,7 +410,7 @@ class Reddit:
                     " for more info.\n",
                 )
 
-    def _check_for_update(self):
+    def _check_for_update(self) -> None:
         if UPDATE_CHECKER_MISSING:
             return
         if not Reddit.update_checked and self.config.check_for_updates:
@@ -462,7 +458,7 @@ class Reddit:
 
         """
         return self._objector.objectify(
-            self.request(
+            data=self.request(
                 data=data,
                 files=files,
                 json=json,
@@ -472,7 +468,7 @@ class Reddit:
             )
         )
 
-    def _prepare_common_authorizer(self, authenticator: prawcore.auth.BaseAuthenticator):
+    def _prepare_common_authorizer(self, authenticator: prawcore.auth.BaseAuthenticator) -> None:
         if self.config.refresh_token:
             authorizer = Authorizer(authenticator, refresh_token=self.config.refresh_token)
         else:
@@ -480,7 +476,7 @@ class Reddit:
             return
         self._core = self._authorized_core = session(authorizer=authorizer, window_size=self.config.window_size)
 
-    def _prepare_objector(self):
+    def _prepare_objector(self) -> None:
         mappings = {
             self.config.kinds["comment"]: models.Comment,
             self.config.kinds["message"]: models.Message,
@@ -531,9 +527,9 @@ class Reddit:
     def _prepare_prawcore(
         self,
         *,
-        requestor_class: type[prawcore.requestor.Requestor] = None,
+        requestor_class: type[prawcore.requestor.Requestor] | None = None,
         requestor_kwargs: Any | None = None,
-    ):
+    ) -> None:
         requestor_class = requestor_class or Requestor
         requestor_kwargs = requestor_kwargs or {}
 
@@ -549,7 +545,7 @@ class Reddit:
         else:
             self._prepare_untrusted_prawcore(requestor)
 
-    def _prepare_trusted_prawcore(self, requestor: prawcore.requestor.Requestor):
+    def _prepare_trusted_prawcore(self, requestor: prawcore.requestor.Requestor) -> None:
         authenticator = TrustedAuthenticator(
             requestor,
             self.config.client_id,
@@ -567,7 +563,7 @@ class Reddit:
         else:
             self._prepare_common_authorizer(authenticator)
 
-    def _prepare_untrusted_prawcore(self, requestor: prawcore.requestor.Requestor):
+    def _prepare_untrusted_prawcore(self, requestor: prawcore.requestor.Requestor) -> None:
         authenticator = UntrustedAuthenticator(requestor, self.config.client_id, self.config.redirect_uri)
         read_only_authorizer = DeviceIDAuthorizer(authenticator)
         self._read_only_core = session(authorizer=read_only_authorizer, window_size=self.config.window_size)
@@ -679,8 +675,8 @@ class Reddit:
             ``"https://www.youtube.com"`` will provide a different set of submissions.
 
         """
-        none_count = (fullnames, url, subreddits).count(None)
-        if none_count != 2:
+        set_count = sum(1 for value in (fullnames, url, subreddits) if value is not None)
+        if set_count != 1:
             msg = "Either 'fullnames', 'url', or 'subreddits' must be provided."
             raise TypeError(msg)
 
@@ -694,7 +690,13 @@ class Reddit:
 
             api_parameter_name = "id" if is_using_fullnames else "sr_name"
 
-            def generator(names: Iterable[str | praw.models.Subreddit]):
+            def generator(
+                names: Iterable[str | praw.models.Subreddit],
+            ) -> Generator[
+                praw.models.Subreddit | praw.models.Comment | praw.models.Submission,
+                None,
+                None,
+            ]:
                 iterable = iter(names) if is_using_fullnames else iter([str(item) for item in names])
                 while True:
                     chunk = list(islice(iterable, 100))
@@ -705,7 +707,13 @@ class Reddit:
 
             return generator(ids_or_names)
 
-        def generator(_url: str):
+        def generator(
+            _url: str,
+        ) -> Generator[
+            praw.models.Subreddit | praw.models.Comment | praw.models.Submission,
+            None,
+            None,
+        ]:
             params = {"url": _url}
             yield from self.get(API_PATH["info"], params=params)
 
diff --git a/praw/util/__init__.py b/praw/util/__init__.py
index 1d85bbe5..6e07e1b4 100644
--- a/praw/util/__init__.py
+++ b/praw/util/__init__.py
@@ -1,4 +1,4 @@
 """Package imports for utilities."""
 
-from .cache import cachedproperty
-from .snake import camel_to_snake, snake_case_keys
+from praw.util.cache import cachedproperty
+from praw.util.snake import camel_to_snake, snake_case_keys
diff --git a/praw/util/cache.py b/praw/util/cache.py
index 8a49f865..f2def52f 100644
--- a/praw/util/cache.py
+++ b/praw/util/cache.py
@@ -22,8 +22,8 @@ class cachedproperty:  # noqa: N801
 
     """
 
-    # This to make sphinx run properly
-    def __call__(self, *args: Any, **kwargs: Any):  # pragma: no cover
+    # This definition prevents sphinx from outputting errors like `<cachedproperty <function ...>> is not a callable object`
+    def __call__(self, *args: Any, **kwargs: Any) -> Any:  # pragma: no cover
         """Empty method to make sphinx run properly."""
 
     def __get__(self, obj: Any | None, objtype: Any | None = None) -> Any:
@@ -39,7 +39,7 @@ class cachedproperty:  # noqa: N801
         value = obj.__dict__[self.func.__name__] = self.func(obj)
         return value
 
-    def __init__(self, func: Callable[[Any], Any], doc: str | None = None):
+    def __init__(self, func: Callable[[Any], Any], doc: str | None = None) -> None:
         """Initialize a :class:`.cachedproperty` instance."""
         self.func = self.__wrapped__ = func
 
diff --git a/pyproject.toml b/pyproject.toml
index 86f62811..3e54d5a0 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,11 @@
 [build-system]
-build-backend = "flit_core.buildapi"
-requires = ["flit_core >=3.4,<4"]
+build-backend = "hatchling.build"
+requires = ["hatchling"]
+
+[dependency-groups]
+dev = [
+  "tox-uv>=1.22.1"
+]
 
 [project]
 authors = [{name = "Bryce Boe", email = "bbzbryce@gmail.com"}]
@@ -22,7 +27,7 @@ classifiers = [
 ]
 dependencies = [
   "defusedxml ==0.7.1",
-  "prawcore >=3.0.1, <4",
+  "prawcore >=3.0.2, <4",
   "update_checker >=0.18",
   "websocket-client >=0.54.0"
 ]
@@ -71,26 +76,29 @@ test = [
 [tool.docstrfmt]
 extend_exclude = ['./docs/examples/']
 
+[tool.hatch.version]
+path = "praw/const.py"
+
 [tool.ruff]
 include = [
-  "praw/**/*.py"
+  "praw/**.py"
 ]
 line-length = 120
 preview = true
 
 [tool.ruff.lint]
 ignore = [
-  "A002", # shadowing built-in
-  "ANN202", # missing return type for private method
-  "ANN401", # typing.Any usage
-  "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
-  "PLR0904", # too many public methods
-  "PLR0913", # too many arguments
-  "PLR2004", # Magic value used in comparison,
-  "S101" # use of assert
+  "ANN401", # any-type
+  "D203", # incorrect-blank-line-before-class
+  "D213", # multi-line-summary-second-line
+  "E501", # Line too long
+  "PLR0904", # Too many public methods
+  "PLR0911", # Too many return statements
+  "PLR0912", # Too many branches
+  "PLR0913", # Too many arguments in function definition
+  "PLR0915", # Too many statements
+  "S101", # use of assert
+  "SLF001" # Private member accessed
 ]
 select = [
   "A", # flake8-builtins
@@ -101,18 +109,20 @@ select = [
   "C4", # flake8-comprehensions
   "D", # pydocstyle
   "DTZ", # flake8-datetimez
-  "E", # pycodestyle errors
+  "E", # pycodestyle
   "EM", # flake8-errmsg
   "ERA", # eradicate
   "EXE", # flake8-executable
   "F", # pyflakes
   "FA", # flake8-future-annotations
-  "FIX", # flake8-fix me
+  "FBT", # flake8-boolean-trap
+  "FIX", # flake8-fixme
   "FLY", # flynt
   "G", # flake8-logging-format
   "I", # isort
   "INP", # flake8-no-pep420
   "ISC", # flake8-implicit-str-concat
+  "LOG", # flake8-logging
   "N", # pep8-naming
   "PIE", # flake8-pie
   "PGH", # pygrep-hooks
@@ -123,25 +133,30 @@ select = [
   "Q", # flake8-quotes
   "RET", # flake8-return
   "RSE", # flake8-raise
+  "RUF", # ruff-specific
   "S", # bandit
   "SIM", # flake8-simplify
+  "SLF", # flake8-self
   "T10", # flake8-debugger
   "T20", # flake8-print
   "TCH", # flake8-type-checking
   "TD", # flake8-todos
-  "W", # pycodestyle warnings
-  "UP" # pyupgrade
+  "TID", # flake8-tidy-imports
+  "TRY", # tryceratops
+  "UP", # pyupgrade
+  "W" # pycodestyle
 ]
 
 [tool.ruff.lint.flake8-annotations]
 allow-star-arg-any = true
-mypy-init-return = true
 suppress-dummy-args = true
-suppress-none-returning = true
 
 [tool.ruff.lint.flake8-builtins]
 builtins-ignorelist = ["id"]
 
+[tool.ruff.lint.flake8-tidy-imports]
+ban-relative-imports = "all"
+
 [tool.ruff.lint.per-file-ignores]
 "__init__.py" = ["F401"]
 "praw/models/mod_notes.py" = ["FA100"]


Test patch:
diff --git a/tests/unit/models/list/test_base.py b/tests/unit/models/list/test_base.py
index d178624b..6136187c 100644
--- a/tests/unit/models/list/test_base.py
+++ b/tests/unit/models/list/test_base.py
@@ -12,8 +12,8 @@ class Dummy:
 
 class DummyObjector:
     @staticmethod
-    def objectify(value):
-        return value
+    def objectify(*, data):
+        return data
 
 
 class TestBaseList:
diff --git a/tests/unit/models/test_mod_notes.py b/tests/unit/models/test_mod_notes.py
index cfbd3484..23bbe899 100644
--- a/tests/unit/models/test_mod_notes.py
+++ b/tests/unit/models/test_mod_notes.py
@@ -24,7 +24,7 @@ class TestBaseModNotes(UnitTest):
 
 class TestRedditModNotes(UnitTest):
     def test__call__invalid_thing_type(self, reddit):
-        with pytest.raises(ValueError) as excinfo:
+        with pytest.raises(TypeError) as excinfo:
             reddit.notes(things=[1])
         assert (
             excinfo.value.args[0]
diff --git a/tests/unit/test_objector.py b/tests/unit/test_objector.py
index 4a0b9d85..32b85bda 100644
--- a/tests/unit/test_objector.py
+++ b/tests/unit/test_objector.py
@@ -17,7 +17,7 @@ class TestObjector(UnitTest):
             objector.check_error(error_response)
 
     def test_objectify_returns_None_for_None(self, reddit):
-        assert reddit._objector.objectify(None) is None
+        assert reddit._objector.objectify(data=None) is None
 
     def test_parse_error(self, reddit):
         objector = reddit._objector