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:
- Username / password (recommended) — Pychive logs in to
pawchive.pw/account/loginand captures thesessioncookie:client = Pawchive(username="your_username", password="your_password")
- Session cookie — pass the
sessioncookie value directly:client = Pawchive("your_session_value") client = Pawchive("session=your_session_value") # prefix optional
- 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
dictkeyed by id, and accept an optionaldelaykeyword 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8bc0441264e1f00d40455114953ae32feae3f46d2cebf68687cf5c572d3474a
|
|
| MD5 |
e9f300001e860d4096ffd448fe66d6bc
|
|
| BLAKE2b-256 |
886a5a23d9d1341a52d2f28cd3aeef4e5171e459358e2bc03071a0cb7e3b96ee
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
911e6c20b91add50cb33230ebbba85223aaaeba0d43c07f12683201cb2373f5f
|
|
| MD5 |
869086aa4fef0300976e253eb141ac11
|
|
| BLAKE2b-256 |
d75978f9644a48dda38f49b7e07529fde5cd15af7e339f7d6df57fadf222a2ed
|