diff --git a/docs/api.rst b/docs/api.rst index af368db3..bf04f025 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -160,6 +160,13 @@ Exceptions Subclass of :exc:`UserWarning`. +Type aliases +------------ + +.. autodata:: reader.types.TristateFilterInput + + + Constants --------- diff --git a/src/reader/core.py b/src/reader/core.py index 768d8717..8c5a898c 100644 --- a/src/reader/core.py +++ b/src/reader/core.py @@ -1142,7 +1142,10 @@ def get_entries( entry (tuple(str, str) or Entry or None): Only return the entry with this (feed URL, entry id) tuple. read (bool or None): Only return (un)read entries. - important (bool or None): Only return (un)important entries. + important (bool or None or str): + Only return (un)important entries. + For more precise filtering, use one of the + :data:`~reader.types.TristateFilterInput` string filters. has_enclosures (bool or None): Only return entries that (don't) have enclosures. feed_tags (None or bool or list(str or bool or list(str or bool))): @@ -1172,6 +1175,9 @@ def get_entries( .. versionadded:: 1.12 The ``limit`` and ``starting_after`` keyword arguments. + .. versionchanged:: 3.5 + The ``important`` argument also accepts string values. + """ # If we ever implement pagination, consider following the guidance in @@ -1278,7 +1284,10 @@ def get_entry_counts( entry (tuple(str, str) or Entry or None): Only count the entry with this (feed URL, entry id) tuple. read (bool or None): Only count (un)read entries. - important (bool or None): Only count (un)important entries. + important (bool or None or str): + Only count (un)important entries. + For more precise filtering, use one of the + :data:`~reader.types.TristateFilterInput` string filters. has_enclosures (bool or None): Only count entries that (don't) have enclosures. feed_tags (None or bool or list(str or bool or list(str or bool))): @@ -1292,6 +1301,9 @@ def get_entry_counts( .. versionadded:: 1.11 + .. versionchanged:: 3.5 + The ``important`` argument also accepts string values. + """ filter_options = EntryFilterOptions.from_args( @@ -1329,6 +1341,10 @@ def set_entry_read( .. versionchanged:: 3.0 The ``entry`` and ``read`` arguments are now positional-only. + .. versionchanged:: 3.5 + Do not coerce ``read`` to :class:`bool` anymore, + require it to be :const:`True` or :const:`False`. + """ if read not in (True, False): raise ValueError("read should be one of (True, False)") @@ -1415,6 +1431,13 @@ def set_entry_important( .. versionchanged:: 3.0 The ``entry`` and ``important`` arguments are now positional-only. + .. versionchanged:: 3.5 + ``important`` can now be :const:`None`. + + .. versionchanged:: 3.5 + Do not coerce ``important`` to :class:`bool` anymore, + require it to be :const:`True` or :const:`False` or :const:`None`. + """ if important not in (True, False, None): raise ValueError("important should be one of (True, False, None)") @@ -1710,7 +1733,10 @@ def search_entries( entry (tuple(str, str) or Entry or None): Only search for the entry with this (feed URL, entry id) tuple. read (bool or None): Only search (un)read entries. - important (bool or None): Only search (un)important entries. + important (bool or None or str): + Only search (un)important entries. + For more precise filtering, use one of the + :data:`~reader.types.TristateFilterInput` string filters. has_enclosures (bool or None): Only search entries that (don't) have enclosures. feed_tags (None or bool or list(str or bool or list(str or bool))): @@ -1746,6 +1772,9 @@ def search_entries( .. versionchanged:: 3.0 The ``query`` argument is now positional-only. + .. versionchanged:: 3.5 + The ``important`` argument also accepts string values. + """ filter_options = EntryFilterOptions.from_args( feed, entry, read, important, has_enclosures, feed_tags @@ -1795,7 +1824,10 @@ def search_entry_counts( feed (str or tuple(str) or Feed or None): Only count the entries for this feed. entry (tuple(str, str) or Entry or None): Only count the entry with this (feed URL, entry id) tuple. - read (bool or None): Only count (un)read entries. + read (bool or None or str): + Only count (un)read entries. + For more precise filtering, use one of the + :data:`~reader.types.TristateFilterInput` string filters. important (bool or None): Only count (un)important entries. has_enclosures (bool or None): Only count entries that (don't) have enclosures. @@ -1816,6 +1848,9 @@ def search_entry_counts( .. versionchanged:: 3.0 The ``query`` argument is now positional-only. + .. versionchanged:: 3.5 + The ``important`` argument also accepts string values. + """ filter_options = EntryFilterOptions.from_args( diff --git a/src/reader/plugins/mark_as_read.py b/src/reader/plugins/mark_as_read.py index dc9c7efd..a066945b 100644 --- a/src/reader/plugins/mark_as_read.py +++ b/src/reader/plugins/mark_as_read.py @@ -25,6 +25,13 @@ Feeds using the old metadata, ``.reader.mark_as_read``, will be migrated automatically on update until `reader` 3.0. +.. versionchanged:: 3.5 + Don't set :attr:`~reader.Entry.read_modified` and + :attr:`~reader.Entry.important_modified` anymore; + because :attr:`~reader.Entry.important` is now optional, + ``important = False`` is enough to mark an entry as unimportant. + Old unimportant entries will be migrated automatically. + .. todo:: diff --git a/src/reader/types.py b/src/reader/types.py index 105ccdc9..041b6656 100644 --- a/src/reader/types.py +++ b/src/reader/types.py @@ -266,6 +266,10 @@ def feed_url(self) -> str: #: Whether the entry is important or not. #: :const:`None` means not set. + #: + #: .. versionchanged:: 3.5 + #: :attr:`important` is now an optional :class:`bool`, + #: and defaults to :const:`None`. important: bool | None = None #: The date when :attr:`important` was last set by the user; @@ -769,7 +773,29 @@ def _resource_argument(resource: ResourceInput) -> ResourceId: None, bool, Sequence[Union[str, bool, Sequence[Union[str, bool]]]] ] - +#: Possible values for options that filter items by an optional boolean +#: attribute (one that can be either true, false, or not set). +#: +#: :const:`None` selects all items. +#: :const:`True` and :const:`False` select items based of the attribute's +#: truth value (a :const:`None` attribute is treated as false). +#: +#: For more precise filtering, use one of the following string filters: +#: +#: ==================== =============== ======================= +#: attribute values string filter optional bool filter +#: ==================== =============== ======================= +#: True istrue True +#: False isfalse +#: None notset +#: False, None nottrue False +#: True, None notfalse +#: True, False isset +#: True, False, None any None +#: ==================== =============== ======================= +#: +#: .. versionadded:: 3.5 +#: TristateFilterInput = Literal[ None, True,