Browse Source

Use postponed evaluation of type annotations

The __future__ import will be able to be removed as of Python 3.10.
merge-requests/126/merge
Deimos 4 years ago
parent
commit
8144a8b789
  1. 3
      tildes/tildes/lib/datetime.py
  2. 7
      tildes/tildes/lib/ratelimit.py
  3. 7
      tildes/tildes/models/comment/comment_notification_query.py
  4. 15
      tildes/tildes/models/comment/comment_query.py
  5. 5
      tildes/tildes/models/group/group_query.py
  6. 21
      tildes/tildes/models/model_query.py
  7. 13
      tildes/tildes/models/pagination.py
  8. 7
      tildes/tildes/models/topic/topic.py
  9. 31
      tildes/tildes/models/topic/topic_query.py

3
tildes/tildes/lib/datetime.py

@ -3,6 +3,7 @@
"""Functions/classes related to dates and times.""" """Functions/classes related to dates and times."""
from __future__ import annotations
import re import re
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from typing import Any, Optional from typing import Any, Optional
@ -30,7 +31,7 @@ class SimpleHoursPeriod:
raise ValueError("Time period is too large") raise ValueError("Time period is too large")
@classmethod @classmethod
def from_short_form(cls, short_form: str) -> "SimpleHoursPeriod":
def from_short_form(cls, short_form: str) -> SimpleHoursPeriod:
"""Initialize a period from a "short form" string (e.g. "2h", "4d").""" """Initialize a period from a "short form" string (e.g. "2h", "4d")."""
if not cls._SHORT_FORM_REGEX.match(short_form): if not cls._SHORT_FORM_REGEX.match(short_form):
raise ValueError("Invalid time period") raise ValueError("Invalid time period")

7
tildes/tildes/lib/ratelimit.py

@ -3,6 +3,7 @@
"""Classes and constants related to rate-limited actions.""" """Classes and constants related to rate-limited actions."""
from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from ipaddress import ip_address from ipaddress import ip_address
from typing import Any, List, Optional, Sequence from typing import Any, List, Optional, Sequence
@ -58,7 +59,7 @@ class RateLimitResult:
) )
@classmethod @classmethod
def unlimited_result(cls) -> "RateLimitResult":
def unlimited_result(cls) -> RateLimitResult:
"""Return a "blank" result representing an unlimited action.""" """Return a "blank" result representing an unlimited action."""
return cls( return cls(
is_allowed=True, is_allowed=True,
@ -68,7 +69,7 @@ class RateLimitResult:
) )
@classmethod @classmethod
def from_redis_cell_result(cls, result: List[int]) -> "RateLimitResult":
def from_redis_cell_result(cls, result: List[int]) -> RateLimitResult:
"""Convert the response from CL.THROTTLE command to a RateLimitResult. """Convert the response from CL.THROTTLE command to a RateLimitResult.
CL.THROTTLE responds with an array of 5 integers: CL.THROTTLE responds with an array of 5 integers:
@ -98,7 +99,7 @@ class RateLimitResult:
) )
@classmethod @classmethod
def merged_result(cls, results: Sequence["RateLimitResult"]) -> "RateLimitResult":
def merged_result(cls, results: Sequence["RateLimitResult"]) -> RateLimitResult:
"""Merge any number of RateLimitResults into a single result. """Merge any number of RateLimitResults into a single result.
Basically, the merged result should be the "most restrictive" combination of all Basically, the merged result should be the "most restrictive" combination of all

7
tildes/tildes/models/comment/comment_notification_query.py

@ -3,6 +3,7 @@
"""Contains the CommentNotificationQuery class.""" """Contains the CommentNotificationQuery class."""
from __future__ import annotations
from typing import Any from typing import Any
from pyramid.request import Request from pyramid.request import Request
@ -32,7 +33,7 @@ class CommentNotificationQuery(PaginatedQuery):
.subquery() .subquery()
) )
def _attach_extra_data(self) -> "CommentNotificationQuery":
def _attach_extra_data(self) -> CommentNotificationQuery:
"""Attach the user's comment votes to the query.""" """Attach the user's comment votes to the query."""
vote_subquery = ( vote_subquery = (
self.request.query(CommentVote) self.request.query(CommentVote)
@ -45,7 +46,7 @@ class CommentNotificationQuery(PaginatedQuery):
) )
return self.add_columns(vote_subquery) return self.add_columns(vote_subquery)
def join_all_relationships(self) -> "CommentNotificationQuery":
def join_all_relationships(self) -> CommentNotificationQuery:
"""Eagerly join the comment, topic, and group to the notification.""" """Eagerly join the comment, topic, and group to the notification."""
# pylint: disable=self-cls-assignment # pylint: disable=self-cls-assignment
self = self.options( self = self.options(
@ -69,7 +70,7 @@ class CommentNotificationQuery(PaginatedQuery):
return notification return notification
def get_page(self, per_page: int) -> "CommentNotificationResults":
def get_page(self, per_page: int) -> CommentNotificationResults:
"""Get a page worth of results from the query (`per page` items).""" """Get a page worth of results from the query (`per page` items)."""
return CommentNotificationResults(self, per_page) return CommentNotificationResults(self, per_page)

15
tildes/tildes/models/comment/comment_query.py

@ -3,6 +3,7 @@
"""Contains the CommentQuery class.""" """Contains the CommentQuery class."""
from __future__ import annotations
from typing import Any from typing import Any
from pyramid.request import Request from pyramid.request import Request
@ -31,7 +32,7 @@ class CommentQuery(PaginatedQuery):
self._only_bookmarked = False self._only_bookmarked = False
self._only_user_voted = False self._only_user_voted = False
def _attach_extra_data(self) -> "CommentQuery":
def _attach_extra_data(self) -> CommentQuery:
"""Attach the extra user data to the query.""" """Attach the extra user data to the query."""
# pylint: disable=protected-access # pylint: disable=protected-access
if not self.request.user: if not self.request.user:
@ -39,7 +40,7 @@ class CommentQuery(PaginatedQuery):
return self._attach_vote_data()._attach_bookmark_data() return self._attach_vote_data()._attach_bookmark_data()
def _attach_vote_data(self) -> "CommentQuery":
def _attach_vote_data(self) -> CommentQuery:
"""Join the data related to whether the user has voted on the comment.""" """Join the data related to whether the user has voted on the comment."""
query = self.join( query = self.join(
CommentVote, CommentVote,
@ -53,7 +54,7 @@ class CommentQuery(PaginatedQuery):
return query return query
def _attach_bookmark_data(self) -> "CommentQuery":
def _attach_bookmark_data(self) -> CommentQuery:
"""Join the data related to whether the user has bookmarked the comment.""" """Join the data related to whether the user has bookmarked the comment."""
query = self.join( query = self.join(
CommentBookmark, CommentBookmark,
@ -86,7 +87,7 @@ class CommentQuery(PaginatedQuery):
def apply_sort_option( def apply_sort_option(
self, sort: CommentSortOption, desc: bool = True self, sort: CommentSortOption, desc: bool = True
) -> "CommentQuery":
) -> CommentQuery:
"""Apply a CommentSortOption sorting method (generative).""" """Apply a CommentSortOption sorting method (generative)."""
if sort == CommentSortOption.VOTES: if sort == CommentSortOption.VOTES:
self._sort_column = Comment.num_votes self._sort_column = Comment.num_votes
@ -97,18 +98,18 @@ class CommentQuery(PaginatedQuery):
return self return self
def search(self, query: str) -> "CommentQuery":
def search(self, query: str) -> CommentQuery:
"""Restrict the comments to ones that match a search query (generative).""" """Restrict the comments to ones that match a search query (generative)."""
return self.filter( return self.filter(
Comment.search_tsv.op("@@")(func.websearch_to_tsquery(query)) Comment.search_tsv.op("@@")(func.websearch_to_tsquery(query))
) )
def only_bookmarked(self) -> "CommentQuery":
def only_bookmarked(self) -> CommentQuery:
"""Restrict the comments to ones that the user has bookmarked (generative).""" """Restrict the comments to ones that the user has bookmarked (generative)."""
self._only_bookmarked = True self._only_bookmarked = True
return self return self
def only_user_voted(self) -> "CommentQuery":
def only_user_voted(self) -> CommentQuery:
"""Restrict the comments to ones that the user has voted on (generative).""" """Restrict the comments to ones that the user has voted on (generative)."""
self._only_user_voted = True self._only_user_voted = True
return self return self

5
tildes/tildes/models/group/group_query.py

@ -3,6 +3,7 @@
"""Contains the GroupQuery class.""" """Contains the GroupQuery class."""
from __future__ import annotations
from typing import Any from typing import Any
from pyramid.request import Request from pyramid.request import Request
@ -24,14 +25,14 @@ class GroupQuery(ModelQuery):
""" """
super().__init__(Group, request) super().__init__(Group, request)
def _attach_extra_data(self) -> "GroupQuery":
def _attach_extra_data(self) -> GroupQuery:
"""Attach the extra user data to the query.""" """Attach the extra user data to the query."""
if not self.request.user: if not self.request.user:
return self return self
return self._attach_subscription_data() return self._attach_subscription_data()
def _attach_subscription_data(self) -> "GroupQuery":
def _attach_subscription_data(self) -> GroupQuery:
"""Add a subquery to include whether the user is subscribed.""" """Add a subquery to include whether the user is subscribed."""
subscription_subquery = ( subscription_subquery = (
self.request.query(GroupSubscription) self.request.query(GroupSubscription)

21
tildes/tildes/models/model_query.py

@ -4,6 +4,7 @@
"""Contains the ModelQuery class, a specialized SQLAlchemy Query subclass.""" """Contains the ModelQuery class, a specialized SQLAlchemy Query subclass."""
# pylint: disable=self-cls-assignment # pylint: disable=self-cls-assignment
from __future__ import annotations
from typing import Any, Iterator, TypeVar from typing import Any, Iterator, TypeVar
from pyramid.request import Request from pyramid.request import Request
@ -40,11 +41,11 @@ class ModelQuery(Query):
results = super().__iter__() results = super().__iter__()
return iter([self._process_result(result) for result in results]) return iter([self._process_result(result) for result in results])
def _attach_extra_data(self) -> "ModelQuery":
def _attach_extra_data(self) -> ModelQuery:
"""Override to attach extra data to query before execution.""" """Override to attach extra data to query before execution."""
return self return self
def _finalize(self) -> "ModelQuery":
def _finalize(self) -> ModelQuery:
"""Finalize the query before it's executed.""" """Finalize the query before it's executed."""
# pylint: disable=protected-access # pylint: disable=protected-access
@ -59,7 +60,7 @@ class ModelQuery(Query):
._filter_removed_if_necessary() ._filter_removed_if_necessary()
) )
def _before_compile_listener(self) -> "ModelQuery":
def _before_compile_listener(self) -> ModelQuery:
"""Do any final adjustments to the query before it's compiled. """Do any final adjustments to the query before it's compiled.
Note that this method cannot be overridden by subclasses because of the way it Note that this method cannot be overridden by subclasses because of the way it
@ -68,21 +69,21 @@ class ModelQuery(Query):
""" """
return self._finalize() return self._finalize()
def _filter_deleted_if_necessary(self) -> "ModelQuery":
def _filter_deleted_if_necessary(self) -> ModelQuery:
"""Filter out deleted rows unless they were explicitly included.""" """Filter out deleted rows unless they were explicitly included."""
if not self.filter_deleted: if not self.filter_deleted:
return self return self
return self.filter(self.model_cls.is_deleted == False) # noqa return self.filter(self.model_cls.is_deleted == False) # noqa
def _filter_removed_if_necessary(self) -> "ModelQuery":
def _filter_removed_if_necessary(self) -> ModelQuery:
"""Filter out removed rows unless they were explicitly included.""" """Filter out removed rows unless they were explicitly included."""
if not self.filter_removed: if not self.filter_removed:
return self return self
return self.filter(self.model_cls.is_removed == False) # noqa return self.filter(self.model_cls.is_removed == False) # noqa
def lock_based_on_request_method(self) -> "ModelQuery":
def lock_based_on_request_method(self) -> ModelQuery:
"""Lock the rows if request method implies it's needed (generative). """Lock the rows if request method implies it's needed (generative).
Applying this function to a query will cause the database to acquire a row-level Applying this function to a query will cause the database to acquire a row-level
@ -98,19 +99,19 @@ class ModelQuery(Query):
return self return self
def include_deleted(self) -> "ModelQuery":
def include_deleted(self) -> ModelQuery:
"""Specify that deleted rows should be included (generative).""" """Specify that deleted rows should be included (generative)."""
self.filter_deleted = False self.filter_deleted = False
return self return self
def include_removed(self) -> "ModelQuery":
def include_removed(self) -> ModelQuery:
"""Specify that removed rows should be included (generative).""" """Specify that removed rows should be included (generative)."""
self.filter_removed = False self.filter_removed = False
return self return self
def join_all_relationships(self) -> "ModelQuery":
def join_all_relationships(self) -> ModelQuery:
"""Eagerly join all lazy relationships (generative). """Eagerly join all lazy relationships (generative).
This is useful for being able to load an item "fully" in a single query and This is useful for being able to load an item "fully" in a single query and
@ -120,7 +121,7 @@ class ModelQuery(Query):
return self return self
def undefer_all_columns(self) -> "ModelQuery":
def undefer_all_columns(self) -> ModelQuery:
"""Undefer all columns (generative).""" """Undefer all columns (generative)."""
self = self.options(undefer("*")) self = self.options(undefer("*"))

13
tildes/tildes/models/pagination.py

@ -3,6 +3,7 @@
"""Contains the PaginatedQuery and PaginatedResults classes.""" """Contains the PaginatedQuery and PaginatedResults classes."""
from __future__ import annotations
from itertools import chain from itertools import chain
from typing import Any, Iterator, List, Optional, Sequence, TypeVar from typing import Any, Iterator, List, Optional, Sequence, TypeVar
@ -85,14 +86,14 @@ class PaginatedQuery(ModelQuery):
""" """
return bool(self.before_id) return bool(self.before_id)
def anchor_type(self, anchor_type: str) -> "PaginatedQuery":
def anchor_type(self, anchor_type: str) -> PaginatedQuery:
"""Set the type of the "anchor" (before/after item) (generative).""" """Set the type of the "anchor" (before/after item) (generative)."""
anchor_table_name = anchor_type + "s" anchor_table_name = anchor_type + "s"
self._anchor_table = self.model_cls.metadata.tables.get(anchor_table_name) self._anchor_table = self.model_cls.metadata.tables.get(anchor_table_name)
return self return self
def after_id36(self, id36: str) -> "PaginatedQuery":
def after_id36(self, id36: str) -> PaginatedQuery:
"""Restrict the query to results after an id36 (generative).""" """Restrict the query to results after an id36 (generative)."""
if self.before_id: if self.before_id:
raise ValueError("Can't set both before and after restrictions") raise ValueError("Can't set both before and after restrictions")
@ -101,7 +102,7 @@ class PaginatedQuery(ModelQuery):
return self return self
def before_id36(self, id36: str) -> "PaginatedQuery":
def before_id36(self, id36: str) -> PaginatedQuery:
"""Restrict the query to results before an id36 (generative).""" """Restrict the query to results before an id36 (generative)."""
if self.after_id: if self.after_id:
raise ValueError("Can't set both before and after restrictions") raise ValueError("Can't set both before and after restrictions")
@ -110,7 +111,7 @@ class PaginatedQuery(ModelQuery):
return self return self
def _apply_before_or_after(self) -> "PaginatedQuery":
def _apply_before_or_after(self) -> PaginatedQuery:
"""Apply the "before" or "after" restrictions if necessary.""" """Apply the "before" or "after" restrictions if necessary."""
# pylint: disable=assignment-from-no-return # pylint: disable=assignment-from-no-return
if not (self.after_id or self.before_id): if not (self.after_id or self.before_id):
@ -165,7 +166,7 @@ class PaginatedQuery(ModelQuery):
.subquery() .subquery()
) )
def _finalize(self) -> "PaginatedQuery":
def _finalize(self) -> PaginatedQuery:
"""Finalize the query before execution.""" """Finalize the query before execution."""
query = super()._finalize() query = super()._finalize()
@ -185,7 +186,7 @@ class PaginatedQuery(ModelQuery):
return query return query
def get_page(self, per_page: int) -> "PaginatedResults":
def get_page(self, per_page: int) -> PaginatedResults:
"""Get a page worth of results from the query (`per page` items).""" """Get a page worth of results from the query (`per page` items)."""
return PaginatedResults(self, per_page) return PaginatedResults(self, per_page)

7
tildes/tildes/models/topic/topic.py

@ -3,6 +3,7 @@
"""Contains the Topic class.""" """Contains the Topic class."""
from __future__ import annotations
from datetime import datetime, timedelta from datetime import datetime, timedelta
from itertools import chain from itertools import chain
from pathlib import PurePosixPath from pathlib import PurePosixPath
@ -217,7 +218,7 @@ class Topic(DatabaseModel):
return f'<Topic "{self.title}" ({self.topic_id})>' return f'<Topic "{self.title}" ({self.topic_id})>'
@classmethod @classmethod
def _create_base_topic(cls, group: Group, author: User, title: str) -> "Topic":
def _create_base_topic(cls, group: Group, author: User, title: str) -> Topic:
"""Create the "base" for a new topic.""" """Create the "base" for a new topic."""
new_topic = cls() new_topic = cls()
new_topic.group = group new_topic.group = group
@ -234,7 +235,7 @@ class Topic(DatabaseModel):
@classmethod @classmethod
def create_text_topic( def create_text_topic(
cls, group: Group, author: User, title: str, markdown: str = "" cls, group: Group, author: User, title: str, markdown: str = ""
) -> "Topic":
) -> Topic:
"""Create a new text topic.""" """Create a new text topic."""
new_topic = cls._create_base_topic(group, author, title) new_topic = cls._create_base_topic(group, author, title)
new_topic.topic_type = TopicType.TEXT new_topic.topic_type = TopicType.TEXT
@ -245,7 +246,7 @@ class Topic(DatabaseModel):
@classmethod @classmethod
def create_link_topic( def create_link_topic(
cls, group: Group, author: User, title: str, link: str cls, group: Group, author: User, title: str, link: str
) -> "Topic":
) -> Topic:
"""Create a new link topic.""" """Create a new link topic."""
new_topic = cls._create_base_topic(group, author, title) new_topic = cls._create_base_topic(group, author, title)
new_topic.topic_type = TopicType.LINK new_topic.topic_type = TopicType.LINK

31
tildes/tildes/models/topic/topic_query.py

@ -3,6 +3,7 @@
"""Contains the TopicQuery class.""" """Contains the TopicQuery class."""
from __future__ import annotations
from typing import Any, Sequence from typing import Any, Sequence
from pyramid.request import Request from pyramid.request import Request
@ -40,7 +41,7 @@ class TopicQuery(PaginatedQuery):
self.filter_ignored = False self.filter_ignored = False
def _attach_extra_data(self) -> "TopicQuery":
def _attach_extra_data(self) -> TopicQuery:
"""Attach the extra user data to the query.""" """Attach the extra user data to the query."""
if not self.request.user: if not self.request.user:
return self return self
@ -53,7 +54,7 @@ class TopicQuery(PaginatedQuery):
._attach_ignored_data() ._attach_ignored_data()
) )
def _finalize(self) -> "TopicQuery":
def _finalize(self) -> TopicQuery:
"""Finalize the query before it's executed.""" """Finalize the query before it's executed."""
# pylint: disable=self-cls-assignment # pylint: disable=self-cls-assignment
self = super()._finalize() self = super()._finalize()
@ -63,7 +64,7 @@ class TopicQuery(PaginatedQuery):
return self return self
def _attach_vote_data(self) -> "TopicQuery":
def _attach_vote_data(self) -> TopicQuery:
"""Join the data related to whether the user has voted on the topic.""" """Join the data related to whether the user has voted on the topic."""
query = self.join( query = self.join(
TopicVote, TopicVote,
@ -77,7 +78,7 @@ class TopicQuery(PaginatedQuery):
return query return query
def _attach_bookmark_data(self) -> "TopicQuery":
def _attach_bookmark_data(self) -> TopicQuery:
"""Join the data related to whether the user has bookmarked the topic.""" """Join the data related to whether the user has bookmarked the topic."""
query = self.join( query = self.join(
TopicBookmark, TopicBookmark,
@ -91,7 +92,7 @@ class TopicQuery(PaginatedQuery):
return query return query
def _attach_visit_data(self) -> "TopicQuery":
def _attach_visit_data(self) -> TopicQuery:
"""Join the data related to the user's last visit to the topic(s).""" """Join the data related to the user's last visit to the topic(s)."""
# subquery using LATERAL to select only the newest visit for each topic # subquery using LATERAL to select only the newest visit for each topic
lateral_subquery = ( lateral_subquery = (
@ -116,7 +117,7 @@ class TopicQuery(PaginatedQuery):
return query return query
def _attach_ignored_data(self) -> "TopicQuery":
def _attach_ignored_data(self) -> TopicQuery:
"""Join the data related to whether the user has ignored the topic.""" """Join the data related to whether the user has ignored the topic."""
query = self.join( query = self.join(
TopicIgnore, TopicIgnore,
@ -160,7 +161,7 @@ class TopicQuery(PaginatedQuery):
def apply_sort_option( def apply_sort_option(
self, sort: TopicSortOption, is_desc: bool = True self, sort: TopicSortOption, is_desc: bool = True
) -> "TopicQuery":
) -> TopicQuery:
"""Apply a TopicSortOption sorting method (generative).""" """Apply a TopicSortOption sorting method (generative)."""
if sort == TopicSortOption.VOTES: if sort == TopicSortOption.VOTES:
self._sort_column = Topic.num_votes self._sort_column = Topic.num_votes
@ -179,7 +180,7 @@ class TopicQuery(PaginatedQuery):
def inside_groups( def inside_groups(
self, groups: Sequence[Group], include_subgroups: bool = True self, groups: Sequence[Group], include_subgroups: bool = True
) -> "TopicQuery":
) -> TopicQuery:
"""Restrict the topics to inside specific groups (generative).""" """Restrict the topics to inside specific groups (generative)."""
if include_subgroups: if include_subgroups:
query_paths = [group.path for group in groups] query_paths = [group.path for group in groups]
@ -191,7 +192,7 @@ class TopicQuery(PaginatedQuery):
return self.filter(Topic.group_id.in_(group_ids)) # type: ignore return self.filter(Topic.group_id.in_(group_ids)) # type: ignore
def inside_time_period(self, period: SimpleHoursPeriod) -> "TopicQuery":
def inside_time_period(self, period: SimpleHoursPeriod) -> TopicQuery:
"""Restrict the topics to inside a time period (generative).""" """Restrict the topics to inside a time period (generative)."""
# if the time period is too long, this will crash by creating a datetime outside # if the time period is too long, this will crash by creating a datetime outside
# the valid range - catch that and just don't filter by time period at all if # the valid range - catch that and just don't filter by time period at all if
@ -203,7 +204,7 @@ class TopicQuery(PaginatedQuery):
return self.filter(Topic.created_time > start_time) return self.filter(Topic.created_time > start_time)
def has_tag(self, tag: str) -> "TopicQuery":
def has_tag(self, tag: str) -> TopicQuery:
"""Restrict the topics to ones with a specific tag (generative). """Restrict the topics to ones with a specific tag (generative).
Note that this method searches for topics that have any tag that contains Note that this method searches for topics that have any tag that contains
@ -214,7 +215,7 @@ class TopicQuery(PaginatedQuery):
# pylint: disable=protected-access # pylint: disable=protected-access
return self.filter(Topic.tags.lquery(query)) # type: ignore return self.filter(Topic.tags.lquery(query)) # type: ignore
def search(self, query: str) -> "TopicQuery":
def search(self, query: str) -> TopicQuery:
"""Restrict the topics to ones that match a search query (generative).""" """Restrict the topics to ones that match a search query (generative)."""
# Replace "." with space, since tags are stored as space-separated strings # Replace "." with space, since tags are stored as space-separated strings
# in the search index. # in the search index.
@ -223,24 +224,24 @@ class TopicQuery(PaginatedQuery):
return self.filter(Topic.search_tsv.op("@@")(func.websearch_to_tsquery(query))) return self.filter(Topic.search_tsv.op("@@")(func.websearch_to_tsquery(query)))
def only_bookmarked(self) -> "TopicQuery":
def only_bookmarked(self) -> TopicQuery:
"""Restrict the topics to ones that the user has bookmarked (generative).""" """Restrict the topics to ones that the user has bookmarked (generative)."""
self._only_bookmarked = True self._only_bookmarked = True
return self return self
def only_user_voted(self) -> "TopicQuery":
def only_user_voted(self) -> TopicQuery:
"""Restrict the topics to ones that the user has voted on (generative).""" """Restrict the topics to ones that the user has voted on (generative)."""
self._only_user_voted = True self._only_user_voted = True
return self return self
def only_ignored(self) -> "TopicQuery":
def only_ignored(self) -> TopicQuery:
"""Restrict the topics to ones that the user has ignored (generative).""" """Restrict the topics to ones that the user has ignored (generative)."""
# pylint: disable=self-cls-assignment # pylint: disable=self-cls-assignment
self._only_ignored = True self._only_ignored = True
return self return self
def exclude_ignored(self) -> "TopicQuery":
def exclude_ignored(self) -> TopicQuery:
"""Specify that ignored topics should be excluded (generative).""" """Specify that ignored topics should be excluded (generative)."""
self.filter_ignored = True self.filter_ignored = True

Loading…
Cancel
Save