Skip to main content

Pychive

Unofficial Python wrapper for the Pawchive API. This project is not affiliated with, endorsed by, or associated with Pawchive.

Pychive provides a clean, typed, object-oriented interface to Pawchive's REST API — covering creators, posts, comments, announcements, fancards, post flagging, favorites, file-hash search, and app version info.

Documentation

Full documentation — installation, quick start, authentication, configuration, API reference, models, exceptions, error handling, pagination, cookbook, and changelog — lives in docs/index.md.

Installation

From PyPI

pip install pychive

From source (local build)

git clone https://gitlab.com/forgiving/pychive.git
cd Pychive
pip install .
Optional: use a virtual environment
git clone https://gitlab.com/forgiving/pychive.git
cd Pychive

python3 -m venv .venv
source .venv/bin/activate      # Linux / macOS
# .venv\Scripts\activate       # Windows

pip install .

Verify the install

python -c "import pychive; print(pychive.__version__)"

(Optional) Install dev tooling

pip install -e ".[dev]"

This adds pytest, responses, ruff, and mypy for testing/linting.


Quick start

import os
from pychive import Pawchive, AuthenticationError, NotFoundError

# Log in with username / password — Pychive captures the session cookie.
# Or pass a session cookie directly: Pawchive("your_session_value")
# Or run anonymously for public endpoints: Pawchive()
client = Pawchive(
    username=os.environ["PAWCHIVE_USERNAME"],
    password=os.environ["PAWCHIVE_PASSWORD"],
)

# Public endpoints (no auth needed)
creators = client.creators.list_all()
for c in creators:
    print(c.name, c.service, c.url)

# Recent posts across all creators (paginated)
posts = client.posts.list_recent(limit=50, offset=0)
for p in posts:
    print(p.title, p.published_at)

# Posts from a specific creator
fanbox_posts = client.posts.list_from_creator("fanbox", "12345", limit=20)

# A specific post + its revisions and comments
post = client.posts.get("fanbox", "12345", "67890")
revisions = client.posts.list_revisions("fanbox", "12345", "67890")
comments = client.comments.list("fanbox", "12345", "67890")

# Creator profile / links / tags / announcements / fancards
profile = client.creators.get_profile("fanbox", "12345")
links = client.creators.get_links("fanbox", "12345")
tags = client.creators.get_tags("fanbox", "12345")
announcements = client.creators.get_announcements("fanbox", "12345")
fancards = client.creators.get_fancards("fanbox", "12345")  # fanbox only

# Authorized endpoints (require valid credentials)
try:
    favs = client.favorites.list()
    client.favorites.add_post("fanbox", "12345", "67890")
    client.favorites.add_creator("fanbox", "12345")
    client.flags.flag("fanbox", "12345", "67890")
    flag_status = client.flags.get_status("fanbox", "12345", "67890")
except AuthenticationError:
    print("Session is invalid or expired.")

# File search by hash + app version
result = client.search.lookup_hash("abcdef1234567890")
version = client.misc.app_version()

client.close()

Authentication

Pychive supports three auth modes:

  1. Username / password (recommended) — Pychive logs in to pawchive.pw/account/login and captures the session cookie:
    client = Pawchive(username="your_username", password="your_password")
    
  2. Session cookie — pass the session cookie value directly:
    client = Pawchive("your_session_value")
    client = Pawchive("session=your_session_value")  # prefix optional
    
  3. Anonymous — no credentials; public endpoints only:
    client = Pawchive()
    

You can load credentials from environment variables:

import os
from pychive import Pawchive

client = Pawchive(
    username=os.environ["PAWCHIVE_USERNAME"],
    password=os.environ["PAWCHIVE_PASSWORD"],
)
export PAWCHIVE_USERNAME="your_username"
export PAWCHIVE_PASSWORD="your_password"

API surface

The Pawchive client exposes endpoint groups as properties:

Property Class Single-id methods Multi-id (*_many) methods Auth?
client.creators CreatorsEndpoint list_all(), get_profile(s,cid), get_links(s,cid), get_tags(s,cid), get_announcements(s,cid), get_fancards(s,cid) get_profile_many(s,cids), get_links_many(s,cids), get_tags_many(s,cids), get_announcements_many(s,cids), get_fancards_many(cids) No (fancards: fanbox only)
client.posts PostsEndpoint list_recent(l,o), list_from_creator(s,cid,l,o), get(s,cid,pid), list_revisions(s,cid,pid) list_from_creator_many(s,cids,l,o), get_many(s,cid,pids), list_revisions_many(s,cid,pids) No
client.comments CommentsEndpoint list(s,cid,pid) list_many(s,cid,pids) No
client.flags FlagsEndpoint flag(s,cid,pid), get_status(s,cid,pid) flag_many(s,cid,pids), get_status_many(s,cid,pids) Yes
client.favorites FavoritesEndpoint list(), add_post(s,cid,pid), remove_post(s,cid,pid), add_creator(s,cid), remove_creator(s,cid) add_post_many(s,cid,pids), remove_post_many(s,cid,pids), add_creator_many(s,cids), remove_creator_many(s,cids) Yes
client.search SearchEndpoint lookup_hash(hash) No
client.misc MiscEndpoint app_version() No

Multi-id methods accept a string or iterable of ids, return a dict keyed by id, and accept an optional delay keyword to throttle between requests. A bare string is treated as a single id (not character-split).

Constructor options

Pawchive(
    session=None,            # str | None: session cookie value
    *,
    username=None,           # str | None: Pawchive username
    password=None,           # str | None: Pawchive password
    login_url="https://pawchive.pw/account/login",
    base_url="https://pawchive.pw/api/v1",
    timeout=30,              # per-request timeout (seconds)
    max_retries=3,           # retries on 429 / 5xx
    backoff_base=0.5,        # exponential backoff base (seconds)
)

Error handling

All errors inherit from pychive.PawchiveError. Catch the base class or a specific subclass:

Exception When raised
PawchiveError Base class for all wrapper errors
AuthenticationError HTTP 401 (invalid/missing session)
NotFoundError HTTP 404
RateLimitError HTTP 429 after retries exhausted
ClientError Other HTTP 4xx
ServerError HTTP 5xx after retries exhausted
ValidationError Invalid arguments passed to a method
ConnectionError Network/timeout failures

Each HTTP exception carries .status_code and .response (the original requests.Response). RateLimitError also exposes .retry_after.

import os
from pychive import Pawchive, RateLimitError, AuthenticationError, NotFoundError

client = Pawchive(
    username=os.environ["PAWCHIVE_USERNAME"],
    password=os.environ["PAWCHIVE_PASSWORD"],
)
try:
    post = client.posts.get("fanbox", "12345", "67890")
except NotFoundError:
    print("Post not found.")
except AuthenticationError:
    print("Session expired.")
except RateLimitError as e:
    print(f"Rate limited; server suggested waiting {e.retry_after}s")
finally:
    client.close()

Retry behavior: the client automatically retries 429, 502, 503, and 504 responses up to max_retries times with exponential backoff. It honors the Retry-After header when present (capped at 60s).


Project layout

Pychive/
├── pyproject.toml          # packaging + tool config
├── README.md
├── AGENTS.md               # compact guide for AI coding sessions
├── docs/                   # full documentation (Markdown)
│   ├── index.md            # entry point + table of contents
│   ├── installation.md
│   ├── quickstart.md
│   ├── authentication.md
│   ├── configuration.md
│   ├── api-reference.md    # every endpoint, method, return type
│   ├── models.md           # every dataclass and its fields
│   ├── exceptions.md
│   ├── error-handling.md
│   ├── pagination.md
│   ├── cookbook.md         # complete examples
│   └── changelog.md
├── tests/                  # pytest test suite (responses for HTTP mocking)
│   ├── conftest.py         # shared fixtures (client with max_retries=0)
│   ├── test_session_parsing.py
│   ├── test_models.py
│   ├── test_validation.py
│   ├── test_endpoints.py
│   ├── test_error_handling.py
│   └── test_client.py
└── src/
    └── pychive/
        ├── __init__.py     # public exports (Pawchive, models, exceptions)
        ├── client.py       # Pawchive — main client class
        ├── http.py         # HttpClient — transport, auth, retry/backoff
        ├── exceptions.py   # exception hierarchy
        ├── models.py       # frozen dataclasses for API responses
        ├── py.typed        # PEP 561 marker (typed package)
        └── endpoints/
            ├── __init__.py
            ├── base.py        # BaseEndpoint
            ├── creators.py    # list_all, profile, links, tags, announcements, fancards
            ├── posts.py       # recent, creator posts, specific post, revisions
            ├── comments.py    # post comments
            ├── flags.py       # flag / flag status
            ├── favorites.py   # list / add / remove posts & creators
            ├── search.py      # hash lookup
            └── misc.py        # app version

Development

pip install -e ".[dev]"

# lint
ruff check src
# type-check
mypy src
# tests
pytest

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pychive-1.1.0.tar.gz (29.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pychive-1.1.0-py3-none-any.whl (24.7 kB view details)

Uploaded Python 3

File details

Details for the file pychive-1.1.0.tar.gz.

File metadata

  • Download URL: pychive-1.1.0.tar.gz
  • Upload date:
  • Size: 29.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.14.7

File hashes

Hashes for pychive-1.1.0.tar.gz
Algorithm Hash digest
SHA256 b8bc0441264e1f00d40455114953ae32feae3f46d2cebf68687cf5c572d3474a
MD5 e9f300001e860d4096ffd448fe66d6bc
BLAKE2b-256 886a5a23d9d1341a52d2f28cd3aeef4e5171e459358e2bc03071a0cb7e3b96ee

See more details on using hashes here.

File details

Details for the file pychive-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: pychive-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 24.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.14.7

File hashes

Hashes for pychive-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 911e6c20b91add50cb33230ebbba85223aaaeba0d43c07f12683201cb2373f5f
MD5 869086aa4fef0300976e253eb141ac11
BLAKE2b-256 d75978f9644a48dda38f49b7e07529fde5cd15af7e339f7d6df57fadf222a2ed

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page