text: """Provide the Comment class."""
  from typing import TYPE_CHECKING, Any, Dict, Optional, Union
  
  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 .... import praw
  
  
  class Comment(InboxableMixin, UserContentMixin, FullnameMixin, RedditBase):
      """A class that represents a reddit comments.
  
      **Typical Attributes**
  
      This table describes attributes that typically belong to objects of this class.
      Since attributes are dynamically provided (see
      :ref:`determine-available-attributes-of-an-object`), there is not a guarantee that
      these attributes will always be present, nor is this list necessarily complete.
  
      ================= ==================================================================
      Attribute         Description
      ================= ==================================================================
      ``author``        Provides an instance of :class:`.Redditor`.
      ``body``          The body of the comment, as Markdown.
      ``body_html``     The body of the comment, as HTML.
      ``created_utc``   Time the comment was created, represented in `Unix Time`_.
      ``distinguished`` Whether or not the comment is distinguished.
      ``edited``        Whether or not the comment has been edited.
      ``id``            The ID of the comment.
      ``is_submitter``  Whether or not the comment author is also the author of the
                        submission.
      ``link_id``       The submission ID that the comment belongs to.
      ``parent_id``     The ID of the parent comment (prefixed with ``t1_``). If it is a
                        top-level comment, this returns the submission ID instead
                        (prefixed with ``t3_``).
      ``permalink``     A permalink for the comment. Comment objects from the inbox have a
                        ``context`` attribute instead.
      ``replies``       Provides an instance of :class:`.CommentForest`.
      ``saved``         Whether or not the comment is saved.
      ``score``         The number of upvotes for the comment.
      ``stickied``      Whether or not the comment is stickied.
      ``submission``    Provides an instance of :class:`.Submission`. The submission that
                        the comment belongs to.
      ``subreddit``     Provides an instance of :class:`.Subreddit`. The subreddit that
                        the comment belongs to.
      ``subreddit_id``  The subreddit ID that the comment belongs to.
      ================= ==================================================================
  
      .. _unix time: https://en.wikipedia.org/wiki/Unix_time
  
      """
  
      MISSING_COMMENT_MESSAGE = "This comment does not appear to be in the comment tree"
      STR_FIELD = "id"
  
      @staticmethod
      def id_from_url(url: str) -> str:
          """Get the ID of a comment from the full URL."""
          parts = RedditBase._url_parts(url)
          try:
              comment_index = parts.index("comments")
          except ValueError:
              raise InvalidURL(url)
  
          if len(parts) - 4 != comment_index:
              raise InvalidURL(url)
          return parts[-1]
  
      @property
      def _kind(self) -> str:
          """Return the class's kind."""
          return self._reddit.config.kinds["comment"]
  
      @property
      def is_root(self) -> bool:
          """Return True when the comment is a top level comment."""
          parent_type = self.parent_id.split("_", 1)[0]
          return parent_type == self._reddit.config.kinds["submission"]
  
      @cachedproperty
      def mod(self) -> "praw.models.reddit.comment.CommentModeration":
          """Provide an instance of :class:`.CommentModeration`.
  
          Example usage:
  
          .. code-block:: python
  
              comment = reddit.comment("dkk4qjd")
              comment.mod.approve()
  
          """
          return CommentModeration(self)
  
      @property
      def replies(self) -> CommentForest:
          """Provide an instance of :class:`.CommentForest`.
  
          This property may return an empty list if the comment has not been refreshed
          with :meth:`.refresh()`
  
          Sort order and reply limit can be set with the ``reply_sort`` and
          ``reply_limit`` attributes before replies are fetched, including any call to
          :meth:`.refresh`:
  
          .. code-block:: python
  
              comment.reply_sort = "new"
              comment.refresh()
              replies = comment.replies
  
          .. note::
  
              The appropriate values for ``reply_sort`` include ``confidence``,
              ``controversial``, ``new``, ``old``, ``q&a``, and ``top``.
  
          """
          if isinstance(self._replies, list):
              self._replies = CommentForest(self.submission, self._replies)
          return self._replies
  
      @property
      def submission(self) -> "praw.models.Submission":
          """Return the Submission object this comment belongs to."""
          if not self._submission:  # Comment not from submission
              self._submission = self._reddit.submission(self._extract_submission_id())
          return self._submission
  
      @submission.setter
      def submission(self, submission: "praw.models.Submission"):
          """Update the Submission associated with the Comment."""
          submission._comments_by_id[self.fullname] = self
          self._submission = submission
          # pylint: disable=not-an-iterable
          for reply in getattr(self, "replies", []):
              reply.submission = submission
  
      def __init__(
          self,
          reddit: "praw.Reddit",
          id: Optional[str] = None,  # pylint: disable=redefined-builtin
          url: Optional[str] = None,
          _data: Optional[Dict[str, Any]] = None,
      ):
          """Construct an instance of the Comment object."""
          if (id, url, _data).count(None) != 2:
              raise TypeError("Exactly one of `id`, `url`, or `_data` must be provided.")
          fetched = False
          self._replies = []
          self._submission = None
          if id:
              self.id = id
          elif url:
              self.id = self.id_from_url(url)
          else:
              fetched = True
          super().__init__(reddit, _data=_data, _fetched=fetched)
  
      def __setattr__(
          self,
          attribute: str,
          value: Union[str, Redditor, CommentForest, "praw.models.Subreddit"],
      ):
          """Objectify author, replies, and subreddit."""
          if attribute == "author":
              value = Redditor.from_data(self._reddit, value)
          elif attribute == "replies":
              if value == "":
                  value = []
              else:
                  value = self._reddit._objector.objectify(value).children
              attribute = "_replies"
          elif attribute == "subreddit":
              value = self._reddit.subreddit(value)
          super().__setattr__(attribute, value)
  
      def _fetch_info(self):
          return "info", {}, {"id": self.fullname}
  
      def _fetch_data(self):
          name, fields, params = self._fetch_info()
          path = API_PATH[name].format(**fields)
          return self._reddit.request("GET", path, params)
  
      def _fetch(self):
          data = self._fetch_data()
          data = data["data"]
  
          if not data["children"]:
              raise ClientException(f"No data returned for comment {self.fullname}")
  
          comment_data = data["children"][0]["data"]
          other = type(self)(self._reddit, _data=comment_data)
          self.__dict__.update(other.__dict__)
          self._fetched = True
  
      def _extract_submission_id(self):
          if "context" in self.__dict__:
              return self.context.rsplit("/", 4)[1]
          return self.link_id.split("_", 1)[1]
  
      def parent(self) -> Union["Comment", "praw.models.Submission"]:
          """Return the parent of the comment.
  
          The returned parent will be an instance of either :class:`.Comment`, or
          :class:`.Submission`.
  
          If this comment was obtained through a :class:`.Submission`, then its entire
          ancestry should be immediately available, requiring no extra network requests.
          However, if this comment was obtained through other means, e.g.,
          ``reddit.comment("COMMENT_ID")``, or ``reddit.inbox.comment_replies``, then the
          returned parent may be a lazy instance of either :class:`.Comment`, or
          :class:`.Submission`.
  
          Lazy comment example:
  
          .. code-block:: python
  
              comment = reddit.comment("cklhv0f")
              parent = comment.parent()
              # `replies` is empty until the comment is refreshed
              print(parent.replies)  # Output: []
              parent.refresh()
              print(parent.replies)  # Output is at least: [Comment(id="cklhv0f")]
  
          .. warning::
  
              Successive calls to :meth:`.parent()` may result in a network request per
              call when the comment is not obtained through a :class:`.Submission`. See
              below for an example of how to minimize requests.
  
          If you have a deeply nested comment and wish to most efficiently discover its
          top-most :class:`.Comment` ancestor you can chain successive calls to
          :meth:`.parent()` with calls to :meth:`.refresh()` at every 9 levels. For
          example:
  
          .. code-block:: python
  
              comment = reddit.comment("dkk4qjd")
              ancestor = comment
              refresh_counter = 0
              while not ancestor.is_root:
                  ancestor = ancestor.parent()
                  if refresh_counter % 9 == 0:
                      ancestor.refresh()
                  refresh_counter += 1
              print(f"Top-most Ancestor: {ancestor}")
  
          The above code should result in 5 network requests to Reddit. Without the calls
          to :meth:`.refresh()` it would make at least 31 network requests.
  
          """
          # pylint: disable=no-member
          if self.parent_id == self.submission.fullname:
              return self.submission
  
          if self.parent_id in self.submission._comments_by_id:
              # The Comment already exists, so simply return it
              return self.submission._comments_by_id[self.parent_id]
          # pylint: enable=no-member
  
          parent = Comment(self._reddit, self.parent_id.split("_", 1)[1])
          parent._submission = self.submission
          return parent
  
      def refresh(self):
          """Refresh the comment's attributes.
  
          If using :meth:`.Reddit.comment` this method must be called in order to obtain
          the comment's replies.
  
          Example usage:
  
          .. code-block:: python
  
              comment = reddit.comment("dkk4qjd")
              comment.refresh()
  
          """
          if "context" in self.__dict__:  # Using hasattr triggers a fetch
              comment_path = self.context.split("?", 1)[0]
          else:
              path = API_PATH["submission"].format(id=self.submission.id)
              comment_path = f"{path}_/{self.id}"
  
          # The context limit appears to be 8, but let's ask for more anyway.
          params = {"context": 100}
          if "reply_limit" in self.__dict__:
              params["limit"] = self.reply_limit
          if "reply_sort" in self.__dict__:
              params["sort"] = self.reply_sort
          comment_list = self._reddit.get(comment_path, params=params)[1].children
          if not comment_list:
              raise ClientException(self.MISSING_COMMENT_MESSAGE)
  
          # With context, the comment may be nested so we have to find it
          comment = None
          queue = comment_list[:]
          while queue and (comment is None or comment.id != self.id):
              comment = queue.pop()
              if isinstance(comment, Comment):
                  queue.extend(comment._replies)
  
          if comment.id != self.id:
              raise ClientException(self.MISSING_COMMENT_MESSAGE)
  
          if self._submission is not None:
              del comment.__dict__["_submission"]  # Don't replace if set
          self.__dict__.update(comment.__dict__)
  
          for reply in comment_list:
              reply.submission = self.submission
          return self
  
  
  class CommentModeration(ThingModerationMixin):
      """Provide a set of functions pertaining to Comment moderation.
  
      Example usage:
  
      .. code-block:: python
  
          comment = reddit.comment("dkk4qjd")
          comment.mod.approve()
  
      """
  
      REMOVAL_MESSAGE_API = "removal_comment_message"
  
      def __init__(self, comment: "praw.models.Comment"):
          """Create a CommentModeration instance.
  
          :param comment: The comment to moderate.
  
          """
          self.thing = comment
  
      def show(self):
          """Uncollapse a :class:`~.Comment` that has been collapsed by Crowd Control.
  
          Example usage:
  
          .. code-block:: python
  
              # Uncollapse a comment:
              comment = reddit.comment("dkk4qjd")
              comment.mod.show()
  
          """
          url = API_PATH["show_comment"]
  
          self.thing._reddit.post(url, data={"id": self.thing.fullname})
  