Source code for redditwarp.models.comment
from __future__ import annotations
from typing import Mapping, Any, Optional, Sequence
from datetime import datetime, timezone
from ..core.const import AUTHORIZATION_BASE_URL
from .datamemento import DatamementoBase
from .report import ModReport, UserReport
from ..model_loaders.report import load_mod_report, load_user_report
[docs]class Comment(DatamementoBase):
@property
def submission(self) -> Comment.Submission:
"""Information related to the comment's submission."""
return self.__submission
@property
def subreddit(self) -> Comment.Subreddit:
"""Information related to the comment's subreddit."""
return self.__subreddit
[docs] class Me:
def __init__(self, d: Mapping[str, Any]) -> None:
self.saved: bool = d['saved']
("""
Whether the current user has saved the comment.
Value false if there is no user context.
""")
self.reply_notifications: bool = d['send_replies']
("""
Whether an inbox message will be sent to you when the submission receives a new top-level comment.
Value true if you are not the author of the submission.
Value true if there is no user context.
""")
self.voted: int = {False: -1, None: 0, True: 1}[d['likes']]
("""
Value `1` if upvoted, `0` if not voted on, `-1` if downvoted.
""")
[docs] class Author:
[docs] class AuthorFlair:
def __init__(self, d: Mapping[str, Any]) -> None:
flair_text: Optional[str] = d['author_flair_text']
flair_css_class: Optional[str] = d['author_flair_css_class']
self.template_uuid: Optional[str] = x if (x := d['author_flair_template_id']) else None
("""
The author's flair template UUID.
Value is null if no flair template is being used.
""")
self.text_mode: str = d['author_flair_type']
("""
Either `text` or `richtext`.
""")
self.text: str = flair_text or ''
("""
Flair text.
Check if the value is an empty string to tell if a flair is being used.
""")
self.css_class: str = flair_css_class or ''
("""
The author's flair CSS class.
When a flair template is being used, the value of this field will be
that of the CSS class designated by the template. If the flair template
does not specify a CSS class then the value will be an empty string.
""")
self.bg_color: str = '' if (x := d['author_flair_background_color']) == 'transparent' else x
("""
A background color hex string. E.g., `#46d160`.
If a flair template is not being used then the value is an empty string.
If a flair template is being used and the background color is unset then
the value is an empty string.
""")
self.fg_color_scheme: str = d['author_flair_text_color'] or ''
("""
Either `dark` or `light`, or empty string.
Value is empty string if a flair template is not being used.
""")
self.has_had_flair_assigned_before_in_subreddit: bool = flair_text is not None
("""
Because of quirks in the API, we can tell if the user has ever had a flair assigned before in the subreddit.
""")
self.has_had_flair_css_class_assigned_before_in_subreddit_when_no_flair_template_assigned: bool = flair_css_class is not None
("""
Because of quirks in the API, we can tell if the user has ever had a flair CSS class
assigned before in the subreddit. This only works if a flair template is not being used.
""")
def __init__(self, d: Mapping[str, Any]) -> None:
self.name: str = d['author']
("")
self.id36: str = d['author_fullname'].split('_', 1)[-1]
("")
self.idn: int = int(self.id36, 36)
("")
self.id: int = self.idn
("")
self.has_premium: bool = d['author_premium']
("")
self.flair: Comment.Author.AuthorFlair = self.AuthorFlair(d)
("""
Attributes related to the author's flair.
""")
[docs] class Submission:
def __init__(self, d: Mapping[str, Any]) -> None:
self.id36: str = d['link_id'].split('_', 1)[-1]
("")
self.idn: int = int(self.id36, 36)
("")
self.id: int = self.idn
("")
self.archived: bool = d['archived']
("""
Whether the post is archived.
Archived posts cannot be commented on,
but the author can still edit the OP.
""")
[docs] class Subreddit:
def __init__(self, d: Mapping[str, Any]) -> None:
self.id36: str = d['subreddit_id'].split('_', 1)[-1]
("")
self.idn: int = int(self.id36, 36)
("")
self.id: int = self.idn
("")
self.name: str = d['subreddit']
("")
self.openness: str = d['subreddit_type']
("""
One of: `public`, `private`, `restricted`, `archived`,
`employees_only`, `gold_only`, `gold_restricted`, or `user`.
""")
[docs] class Moderation:
[docs] class Approved:
def __init__(self, d: Mapping[str, Any]) -> None:
self.by: str = d['approved_by']
("""
Name of the moderator who approved this comment.
""")
self.ut: int = d['approved_at_utc']
("")
self.at: datetime = datetime.fromtimestamp(self.ut, timezone.utc)
("")
[docs] class Removed:
def __init__(self, d: Mapping[str, Any]) -> None:
self.by: str = d['banned_by']
("""
Name of the moderator who removed this comment.
""")
self.ut: int = d['banned_at_utc']
("")
self.at: datetime = datetime.fromtimestamp(self.ut, timezone.utc)
("")
[docs] class Reports:
def __init__(self, d: Mapping[str, Any]) -> None:
self.ignoring: bool = d['ignore_reports']
("")
self.num_reports: int = d['num_reports']
("")
self.mod_reports: Sequence[ModReport] = [load_mod_report(m) for m in d['mod_reports']]
("")
self.user_reports: Sequence[UserReport] = [load_user_report(m) for m in d['user_reports']]
("")
[docs] class RemovalReason:
def __init__(self, d: Mapping[str, Any]) -> None:
self.by: str = d['mod_reason_by'] or ''
("")
self.title: str = d['mod_reason_title'] or ''
("")
self.note: str = d['mod_note'] or ''
("")
def __init__(self, d: Mapping[str, Any]) -> None:
self.spam: bool = d['spam']
("")
self.approved: Optional[Comment.Moderation.Approved] = None
("")
if d['approved_by']:
self.approved = self.Approved(d)
self.removed: Optional[Comment.Moderation.Removed] = None
("")
if d['banned_by']:
self.removed = self.Removed(d)
self.reports: Comment.Moderation.Reports = self.Reports(d)
("")
self.removal_reason: Optional[Comment.Moderation.RemovalReason] = None
("")
if d['mod_reason_by']:
self.removal_reason = self.RemovalReason(d)
[docs] class Edited:
def __init__(self, outer: Comment) -> None:
self.ut: int = outer.edited_ut
("")
self.at: datetime = outer.edited_at
("")
def __init__(self, d: Mapping[str, Any]) -> None:
super().__init__(d)
self.id36: str = d['id']
("""
ID of the comment as a base 36 number.
""")
self.idn: int = int(self.id36, 36)
("")
self.id: int = self.idn
("")
self.created_ut: int = int(d['created_utc'])
("""
Unix timestamp of when the comment was made.
""")
self.created_at: datetime = datetime.fromtimestamp(self.created_ut, timezone.utc)
("""
When the comment was made.
""")
self.body: str = d['body']
("""
Body text of the comment. In markdown format.
""")
self.body_html: str = d.get('body_html', '')
("""
HTML of the comment.
""")
self.score: int = d['score']
("""
Number of upvotes (minus downvotes).
""")
self.score_hidden: bool = d['score_hidden']
("""
Whether the score should be hidden.
""")
self.permalink_path: str = d['permalink']
("""
URL of the comment, without the domain.
""")
self.permalink: str = AUTHORIZATION_BASE_URL + self.permalink_path
("""
URL of the comment.
""")
edited: Any = d['edited']
self.is_edited: bool = bool(edited)
("""
True if the comment was edited.
""")
self.edited_ut: int = int(edited) if edited else 0
("""
Unix timestamp of when the comment was edited.
Value is `0` if :attr:`is_edited` is false.
""")
self.edited_at: datetime = datetime.min
("""
When the comment was edited.
Value is `datetime.min` if :attr:`is_edited` is false.
""")
if self.is_edited:
self.edited_at = datetime.fromtimestamp(self.edited_ut, timezone.utc)
self.edited: Optional[Comment.Edited] = None
("""
Value non-`None` if the comment was edited.
""")
if edited:
self.edited = self.Edited(self)
self.is_submitter: bool = d['is_submitter']
("""
True if the author of this comment is the submission author ("OP").
""")
self.stickied: bool = d['stickied']
("")
self.locked: bool = d['locked']
("")
self.collapsed: bool = d['collapsed']
("""
Whether the comment is collapsed by default, i.e., when it has been downvoted significantly.
""")
self.distinguished: str = d['distinguished'] or ''
("""
Empty string if not distinguished, otherwise `'moderator'` or `'admin'`.
""")
parent_id: str = d['parent_id']
self.is_top_level: bool = parent_id.startswith('t3_')
("""
Whether the comment is a direct child of the submission.
""")
self.has_parent_comment: bool = not self.is_top_level
("""
Same as `not self.is_top_level`.
""")
self.parent_comment_id36: str = ''
("""
Parent comment ID36.
Empty string if not applicable.
""")
self.parent_comment_idn: int = 0
("""
Parent comment ID.
Value is `0` if not applicable.
""")
if self.has_parent_comment:
self.parent_comment_id36 = parent_id.partition('_')[2]
self.parent_comment_idn = int(self.parent_comment_id36, 36)
self.parent_comment_id: int = self.parent_comment_idn
("""
Same as :attr:`parent_comment_idn`.
""")
self.me: Comment.Me = self.Me(d)
("""
Attributes relating to the current user.
If there is no user context, these values contain nonsense.
""")
self.__submission: Comment.Submission = self.Submission(d)
self.__subreddit: Comment.Subreddit = self.Subreddit(d)
s: str = d['author']
self.author_display_name: str = s
("""
The author's username.
Possibly `[removed]` if the comment was removed or
`[deleted]` if the comment was deleted by the author.
""")
self.author: Optional[Comment.Author] = None
("""
Information about the author.
Value is `None` if the comment was removed or deleted.
""")
if not s.startswith('['):
self.author = self.Author(d)
self.mod: Optional[Comment.Moderation] = None
("""
Attributes relating to moderation.
Value is `None` if the current user is not a moderator of the subreddit.
""")
if 'spam' in d:
self.mod = self.Moderation(d)
[docs]class LooseComment(Comment):
# For:
# * `GET /comments`
# * `GET /r/{subreddit}/comments`
# * `GET /user/{username}/overview` (and variants)
@property
def submission(self) -> LooseComment.Submission:
return self.__submission
@property
def subreddit(self) -> LooseComment.Subreddit:
return self.__subreddit
[docs] class Submission(Comment.Submission):
def __init__(self, d: Mapping[str, Any]) -> None:
super().__init__(d)
self.title: str = d['link_title']
("")
self.author_display_name: str = d['link_author']
("")
self.permalink_path: str = d['link_permalink']
("")
self.permalink: str = AUTHORIZATION_BASE_URL + self.permalink_path
("")
self.nsfw: bool = d['over_18']
("")
[docs] class Subreddit(Comment.Subreddit):
def __init__(self, d: Mapping[str, Any]) -> None:
super().__init__(d)
self.quarantined: bool = d['quarantine']
("")
def __init__(self, d: Mapping[str, Any]) -> None:
super().__init__(d)
self.__submission: LooseComment.Submission = self.Submission(d)
self.__subreddit: LooseComment.Subreddit = self.Subreddit(d)