From d4b175826261da703089a0ba21bde8c514ba24d4 Mon Sep 17 00:00:00 2001 From: Scott Lyons Date: Thu, 5 Sep 2024 14:33:45 -0700 Subject: [PATCH] docs(pydocs): full python wrapper documentation --- docs/Makefile | 28 ++ docs/client.rst | 63 ++++ docs/conf.py | 41 +++ docs/examples.rst | 113 +++++++ docs/fields.rst | 15 + docs/index.rst | 15 + docs/make.bat | 35 ++ docs/models.rst | 10 + docs/tokens.rst | 830 ++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 1150 insertions(+) create mode 100644 docs/Makefile create mode 100644 docs/client.rst create mode 100644 docs/conf.py create mode 100644 docs/examples.rst create mode 100644 docs/fields.rst create mode 100644 docs/index.rst create mode 100644 docs/make.bat create mode 100644 docs/models.rst create mode 100644 docs/tokens.rst diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..bfea5fd --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,28 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +serve: + python -m http.server -d $(BUILDDIR)/html + +clean: + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + pip uninstall -y szurubooru_client + maturin develop -F python -m ../szurubooru-client/Cargo.toml + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/client.rst b/docs/client.rst new file mode 100644 index 0000000..4c9588a --- /dev/null +++ b/docs/client.rst @@ -0,0 +1,63 @@ +Szurubooru Clients +================== + +These are the clients available for interacting with Szurubooru. There are two clients, ``SzurubooruSyncClient`` and ``SzurubooruAsyncClient`` . The only difference +between the two of them is that ``SzurubooruAsyncClient`` is compatible with ``asyncio`` for use in ``async`` scripts. + +.. contents:: Table of Contents + :depth: 3 + :local: + +Sync Client +----------- + +.. autoclass:: szurubooru_client.SzurubooruSyncClient + + +Async Client +------------ + +.. autoclass:: szurubooru_client.SzurubooruAsyncClient + + +Exceptions +---------- + +All exceptions that are thrown by the client are instances of the ``SzuruClientError`` class. It's a tuple of two items: An exception type (as a string) and a string with more details +about the exception. + +.. autoexception:: szurubooru_client.SzuruClientError + +.. _rver: + +Resource Versioning +------------------- + +Many of the ``update`` and other methods on the client classes accept a ``version`` argument. This is part of Szurubooru's optimistic locking. Each resource has its ``version`` retuned +to the client through any of the ``get`` methods. This value must be provided to any of the ``update`` or ``delete`` methods. If the version doesn't match at the time +(due to a modified resource) then the call will fail. + +Pagination +---------- + +Most of the ``list`` methods on the clients return a paged object that holds the results along with other details about the query: + +.. autoclass:: szurubooru_client.PagedResult + +Paging through the results of ``list`` methods are done using two parameters: + +.. _limits: + +Result Limits +^^^^^^^^^^^^^ + +Most of the ``list`` methods on the clients support a ``limit`` parameter. This parameter limits the number of resources returned by the method as part of +a :class:`~szurubooru_client.PagedResult` object + +.. _offsets: + +Result Offsets +^^^^^^^^^^^^^^ + +Most of the ``list`` methods on the clients support a ``offset`` parameter. This parameter skips through the results returned by the method as part of +a :class:`~szurubooru_client.PagedResult` object diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..8b907ad --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,41 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'Szurubooru Client' +copyright = '2024, Scott Lyons' +author = 'Scott Lyons' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + 'myst_parser', + 'sphinx.ext.autodoc', + "sphinx_codefence" +] + +autodoc_default_options = { + 'members': True, + 'show-inheritance': True, +} +autodoc_typehints = "description" + +templates_path = ['_templates'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +source_suffix = { + '.rst': 'restructuredtext', + '.txt': 'markdown', + '.md': 'markdown', +} + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'alabaster' +html_static_path = ['_static'] diff --git a/docs/examples.rst b/docs/examples.rst new file mode 100644 index 0000000..c1cec75 --- /dev/null +++ b/docs/examples.rst @@ -0,0 +1,113 @@ +======== +Examples +======== + +.. contents:: Table of Contents + :depth: 3 + :local: + +All of these examples are taken from the ``python-sync`` script in the ``tests`` directory of the repo. + +Before any of the examples will work, you need to import the right classes and functions: + +```python +from szurubooru_client import * +from szurubooru_client.tokens import * +from szurubooru_client.models import * +``` + +Creating a client +^^^^^^^^^^^^^^^^^ + +```python +client = SzurubooruSyncClient("http://localhost:9802", username="integration_user", + password="integration_password", allow_insecure=True) +``` + +Creating a new tag +^^^^^^^^^^^^^^^^^^ + +```python +foo_tag = client.create_tag("foo", category="default", description="The foo tag") +assert foo_tag.names == ["foo"] +``` + +Returning only a subset of fields +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +```python +# Omit the "description" field +tags = client.list_tags(fields=["version", "names", "category"]) +assert tags.results[0].description is None +``` + +Uploading from a file path +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +```python +folly1 = client.create_post(file_path="../folly1.jpg", + tags=["maine_coon", "cat", "folly1"], + safety=PostSafety.Safe) +``` + +Searching for an existing post using an image +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +```python +folly1_search = client.post_for_image("../folly1.jpg") +assert folly1_search is not None +``` + +Querying by an anonymous tag +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +```python +cat_posts = client.list_posts(query=[anonymous_token("cat")]) +``` + +Querying by a named tag +^^^^^^^^^^^^^^^^^^^^^^^ + +```python +mc_posts = client.list_posts(query=[named_token(PostNamedToken.Tag, "maine_coon")]) +``` + +Pagination +^^^^^^^^^^ + +```python +posts = client.list_posts(limit=1) +assert posts.total == 4 +assert len(posts.results) == 1 + +posts2 = client.list_posts(limit=1, offset=1) +assert posts.results != posts2.results +``` + +Commenting on a post +^^^^^^^^^^^^^^^^^^^^ + +```python +cat_results = client.list_posts([anonymous_token("cat")]) +post_id = cat_results.results[0].id + +comment = client.create_comment("Excellent cat!", post_id) +``` + +Getting all comments for a post +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +```python +comment_list = client.list_comments([named_token(CommentNamedToken.Post, post_id)]) +assert len(comment_list.results) != 0 +``` + +Downloading an image to a local path +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +```python +cat_results = client.list_posts([anonymous_token("cat")]) +post_id = cat_results.results[0].id + +client.download_image_to_path(post_id, "/tmp/cat.jpg") +``` diff --git a/docs/fields.rst b/docs/fields.rst new file mode 100644 index 0000000..34ae948 --- /dev/null +++ b/docs/fields.rst @@ -0,0 +1,15 @@ +Field selection +=============== + +The Szurubooru API supports *Field Selection*. This allows you to select only a subset of fields to return from the API. By default all fields are selected and returned, but if you +pass in a list of field names to any of the client methods that support it, only those fields will be populated in the models. + +Example +------- + +```python +tags = client.list_tags(fields=["version", "names", "category"]) +assert tags.results[0].description is None +``` + +Because the ``description`` field was not specified, it's set to ``None`` diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..65c9ffc --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,15 @@ +Szurubooru Client documentation +=============================== + +Welcome to the documentation for ``szurubooru_client`` . This library is a wrapper around a Rust library for interacting with the self-hosted +image site `Szurubooru `_ + +.. toctree:: + :maxdepth: 1 + :caption: Contents: + + client + tokens + models + fields + examples diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..32bb245 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/models.rst b/docs/models.rst new file mode 100644 index 0000000..adabf70 --- /dev/null +++ b/docs/models.rst @@ -0,0 +1,10 @@ +Szurubooru Models +================= + +.. contents:: Table of Contents + :depth: 3 + :local: + +.. automodule:: szurubooru_client.models + :members: + :undoc-members: diff --git a/docs/tokens.rst b/docs/tokens.rst new file mode 100644 index 0000000..d11ae2d --- /dev/null +++ b/docs/tokens.rst @@ -0,0 +1,830 @@ +Szurubooru Query Tokens +======================= + +.. contents:: Table of Contents + :depth: 3 + :local: + +Most of the ``list`` methods on the client support a ``query`` parameter. This parameter (a ``list`` of tokens) allows you to filter the results returned by the API. + +There's four kinds of tokens: ``Named``, ``Sort``, ``Anonymous`` and ``Special``. +Because this library is a wrapper around a Rust library, there's a group of type-safe ``Enum`` objects that allow you to +make sure you get the right field names when constructing the tokens. + +All tokens can be mixed and matched to filter the results how you'd prefer. + + +.. _named-tokens: + + +Named tokens +^^^^^^^^^^^^ + +.. autofunction:: szurubooru_client.tokens.named_token + +.. _sort-tokens: + + +Sort tokens +^^^^^^^^^^^ + +.. autofunction:: szurubooru_client.tokens.sort_token + + +Anonymous tokens +^^^^^^^^^^^^^^^^ + +.. autofunction:: szurubooru_client.tokens.anonymous_token + + +Special tokens +^^^^^^^^^^^^^^ + +.. autofunction:: szurubooru_client.tokens.special_token + + +Negating tokens +^^^^^^^^^^^^^^^ + +All query tokens can be negated using either ``.negate`` or by prefixing with the ``-`` operator. Negated tokens mean to *not* match that particular token. + +For example, to match the anonymous tag ``konosuba``, we would do the following: + +```python +client.list_posts(query=[anonymous_token("konosuba")]) +``` + +Now to match all posts that *don't* have the ``konosuba`` tag: + +```python +client.list_posts(query=[-anonymous_token("konosuba")]) +# or +client.list_posts(query=[anonymous_token("konosuba").negate()]) +``` + +.. _named-tokens-enums: + +Token Enums +^^^^^^^^^^^ + +----------------- +Named Token Enums +----------------- + +.. py:class:: szurubooru_client.tokens.TagNamedToken + + .. py:attribute:: Name + + Having given name (accepts wildcards) + + + .. py:attribute:: Category + + Having given category (accepts wildcards) + + + .. py:attribute:: CreationDate + + Created at given date + + + .. py:attribute:: LastEditDate + + Edited at given date + + + .. py:attribute:: LastEditTime + + Alias of :attr:`LastEditTime ` + + + .. py:attribute:: EditDate + + Alias of :attr:`LastEditTime ` + + + .. py:attribute:: EditTime + + Alias of :attr:`LastEditTime ` + + + .. py:attribute:: Usages + + Used in given number of posts + + + .. py:attribute:: UsageCount + + Alias of :attr:`Usages ` + + + .. py:attribute:: PostCount + + Alias of :attr:`Usages ` + + + .. py:attribute:: SuggestionCount + + With given number of suggestions + + + .. py:attribute:: ImplicationCount + + With given number of implications + +.. py:class:: szurubooru_client.tokens.PostNamedToken + + .. py:attribute:: Id + + Having given post number + + .. py:attribute:: Tag + + Having given tag (accepts wildcards) + + + .. py:attribute:: Score + + Having given score + + + .. py:attribute:: Uploader + + Uploaded by given user (accepts wildcards) + + + .. py:attribute:: Upload + + Alias of :attr:`Uploader ` + + + .. py:attribute:: Submit + + Alias of :attr:`Uploader ` + + + .. py:attribute:: Comment + + Commented by given user (accepts wildcards) + + + .. py:attribute:: Fav + + Favorited by given user (accepts wildcards) + + + .. py:attribute:: Pool + + Belonging to the pool with the given id + + + .. py:attribute:: TagCount + + Having given number of tags + + + .. py:attribute:: CommentCount + + Having given number of comments + + + .. py:attribute:: FavCount + + Favorited by given number of users + + + .. py:attribute:: NoteCount + + Having given number of annotations + + + .. py:attribute:: NoteText + + Having given note text (accepts wildcards) + + + .. py:attribute:: RelationCount + + Having given number of relations + + + .. py:attribute:: FeatureCount + + Having been featured given number of times + + + .. py:attribute:: Type + + ``flash`` (or ``swf``) or ``video`` (or ``webm``). Use :attr:`models.posttype` for type-safe values + + + .. py:attribute:: ContentChecksum + + Having given sha1 checksum + + + .. py:attribute:: FileSize + + Having given file size (in bytes) + + + .. py:attribute:: ImageWidth + + Having given image width (where applicable) + + + .. py:attribute:: ImageHeight + + Having given image height (where applicable) + + + .. py:attribute:: ImageArea + + Having given number of pixels (image width * image height) + + + .. py:attribute:: ImageAspectRatio + + Having given aspect ratio (image width / image height) + + + .. py:attribute:: ImageAr + + Alias of :attr:`ImageAspectRatio ` + + + .. py:attribute:: Width + + Alias of :attr:`ImageWidth ` + + + .. py:attribute:: Height + + Alias of :attr:`ImageHeight ` + + + .. py:attribute:: Ar + + Alias of :attr:`ImageAspectRatio ` + + + .. py:attribute:: AspectRatio + + Alias of :attr:`ImageAspectRatio ` + + + .. py:attribute:: CreationDate + + Posted at given date + + + .. py:attribute:: CreationTime + + Alias of :attr:`CreationDate ` + + + .. py:attribute:: Date + + Alias of :attr:`CreationDate ` + + + .. py:attribute:: Time + + Alias of :attr:`CreationDate ` + + + .. py:attribute:: LastEditDate + + Edited at given date + + + .. py:attribute:: LastEditTime + + Alias of :attr:`LastEditDate ` + + + .. py:attribute:: EditDate + + Alias of :attr:`LastEditDate ` + + + .. py:attribute:: EditTime + + Alias of :attr:`LastEditDate ` + + + .. py:attribute:: CommentDate + + Commented at given date + + + .. py:attribute:: CommentTime + + Alias of :attr:`CommentDate ` + + + .. py:attribute:: FavDate + + Last favorited at given time + + + .. py:attribute:: FavTime + + Alias of :attr:`FavDate ` + + + .. py:attribute:: FeatureDate + + Featured at given date + + + .. py:attribute:: FeatureTime + + Alias of :attr:`FeatureDate ` + + + .. py:attribute:: Safety + + Use :class:`PostSafety ` for the type-safe version + + + .. py:attribute:: Rating + + Alias of :attr:`Safety ` + +.. py:class:: szurubooru_client.tokens.CommentNamedToken + + .. py:attribute:: Id + + Specific comment id + + + .. py:attribute:: Post + + Specific post id + + + .. py:attribute:: User + + Created by given user (accepts wildcards) + + + .. py:attribute:: Author + + Alias of user + + + .. py:attribute:: Text + + Containing given text (accepts wildcards) + + + .. py:attribute:: CreationDate + + Created at given date + + + .. py:attribute:: CreationTime + + Alias of :attr:`CreationDate ` + + + .. py:attribute:: LastEditDate + + Whose most recent edit date matches given date + + + .. py:attribute:: LastEditTime + + Alias of :attr:`LastEditDate ` + + + .. py:attribute:: EditDate + + Alias of :attr:`LastEditDate ` + + + .. py:attribute:: EditTime + + Alias of :attr:`LastEditDate ` + +.. py:class:: szurubooru_client.tokens.UserNamedToken + + + .. py:attribute:: Name + + Having given name (accepts wildcards) + + + .. py:attribute:: CreationDate + + Registered at given date + + + .. py:attribute:: CreationTime + + Alias of :attr:`CreationDate ` + + + .. py:attribute:: LastLoginDate + + Whose most recent login date matches given date + + + .. py:attribute:: LastLoginTime + + Alias of :attr:`LastLoginDate ` + + + .. py:attribute:: LoginDate + + Alias of :attr:`LastLoginDate ` + + + .. py:attribute:: LoginTime + + Alias of :attr:`LastLoginDate ` + +.. py:class:: szurubooru_client.tokens.SnapshotNamedToken + + + .. py:attribute:: Type + + Involving given resource type + + + .. py:attribute:: Id + + Involving given resource id + + + .. py:attribute:: Date + + Created at given date + + + .. py:attribute:: Time + + Alias of :attr:`Date ` + + + .. py:attribute:: Operation + + ``modified``, ``created``, ``deleted`` or ``merged``. Use :attr:`SnapshotType ` for type-safe values + + + .. py:attribute:: User + + Name of the user that created given snapshot (accepts wildcards) + +.. _sort-tokens-enums: + +---------------- +Sort Token Enums +---------------- + +.. py:class:: szurubooru_client.tokens.PostSortToken + + .. py:attribute:: Random + + As random as it can get + + + .. py:attribute:: Id + + Highest to lowest post number + + + .. py:attribute:: Score + + Highest scored + + + .. py:attribute:: TagCount + + With most tags + + + .. py:attribute:: CommentCount + + Most commented first + + + .. py:attribute:: FavCount + + Loved by most + + + .. py:attribute:: NoteCount + + With most annotations + + + .. py:attribute:: RelationCount + + With most relations + + + .. py:attribute:: FeatureCount + + Most often featured + + + .. py:attribute:: FileSize + + Largest files first + + + .. py:attribute:: ImageWidth + + Widest images first + + + .. py:attribute:: ImageHeight + + Tallest images first + + + .. py:attribute:: ImageArea + + Largest images first + + + .. py:attribute:: Width + + Alias of :attr:`ImageWidth ` + + + .. py:attribute:: Height + + Alias of :attr:`ImageHeight ` + + + .. py:attribute:: Area + + Alias of :attr:`ImageArea ` + + + .. py:attribute:: CreationDate + + Newest to oldest (pretty much same as id) + + + .. py:attribute:: CreationTime + + Alias of :attr:`CreationDate ` + + + .. py:attribute:: Date + + Alias of :attr:`CreationDate ` + + + .. py:attribute:: Time + + Alias of :attr:`CreationDate ` + + + .. py:attribute:: LastEditDate + + Like :attr:`CreationDate `, only looks at last edit time instead + + + .. py:attribute:: LastEditTime + + Alias of :attr:`LastEditDate ` + + + .. py:attribute:: EditDate + + Alias of :attr:`LastEditDate ` + + + .. py:attribute:: EditTime + + Alias of :attr:`LastEditDate ` + + + .. py:attribute:: CommentDate + + Recently commented by anyone + + + .. py:attribute:: CommentTime + + Alias of :attr:`CommentDate ` + + + .. py:attribute:: FavDate + + Recently added to favorites by anyone + + + .. py:attribute:: FavTime + + Alias of :attr:`FavDate ` + + + .. py:attribute:: FeatureDate + + Recently featured + + + .. py:attribute:: FeatureTime + + Alias of :attr:`FeatureDate ` + + +.. py:class:: szurubooru_client.tokens.TagSortToken + + .. py:attribute:: Random + + As random as it can get + + + .. py:attribute:: Name + + A to Z + + + .. py:attribute:: Category + + Category (a to z) + + + .. py:attribute:: CreationDate + + Recently created first + + + .. py:attribute:: CreationTime + + Alias of :attr:`CreationDate ` + + + .. py:attribute:: LastEditDate + + Recently edited first + + + .. py:attribute:: LastEditTime + + Alias of :attr:`CreationDate ` + + + .. py:attribute:: EditDate + + Alias of :attr:`CreationDate ` + + + .. py:attribute:: EditTime + + Alias of :attr:`CreationDate ` + + + .. py:attribute:: Usages + + Used in most posts first + + + .. py:attribute:: UsageCount + + Alias of :attr:`Usages ` + + + .. py:attribute:: PostCount + + Alias of :attr:`Usages ` + + + .. py:attribute:: SuggestionCount + + With most suggestions first + + + .. py:attribute:: ImplicationCount + + With most implications first + + +.. py:class:: szurubooru_client.tokens.CommentSortToken + + + .. py:attribute:: Random + + As random as it can get + + + .. py:attribute:: User + + Author name, a to z + + + .. py:attribute:: Author + + Alias of user + + + .. py:attribute:: Post + + Post id, newest to oldest + + + .. py:attribute:: CreationDate + + Newest to oldest + + + .. py:attribute:: CreationTime + + Alias of :attr:`CreationDate ` + + + .. py:attribute:: LastEditDate + + Recently edited first + + + .. py:attribute:: LastEditTime + + Alias of :attr:`LastEditDate ` + + + .. py:attribute:: EditDate + + Alias of :attr:`LastEditDate ` + + + .. py:attribute:: EditTime + + Alias of :attr:`LastEditDate ` + + +.. py:class:: szurubooru_client.tokens.UserSortToken + + .. py:attribute:: Random + + As random as it can get + + + .. py:attribute:: Name + + A to z + + + .. py:attribute:: CreationDate + + Newest to oldest + + + .. py:attribute:: CreationTime + + Alias of :attr:`CreationDate ` + + + .. py:attribute:: LastLoginDate + + Recently active first + + + .. py:attribute:: LastLoginTime + + Alias of :attr:`LastLoginDate ` + + + .. py:attribute:: LoginDate + + Alias of :attr:`LastLoginDate ` + + + .. py:attribute:: LoginTime + + Alias of :attr:`LastLoginDate ` + +.. _special-tokens-enum: + +------------------- +Special Token Enums +------------------- + +.. py:class:: szurubooru_client.tokens.PostSpecialToken + + + .. py:attribute:: Liked + + Posts liked by currently logged-in user + + + .. py:attribute:: Disliked + + Posts disliked by currently logged in user + + + .. py:attribute:: Fav + + Posts added to favorites by currently logged-in user + + + .. py:attribute:: Tumbleweed + + Posts with score of 0, without comments and without favorites