Getting Started¶
Installation¶
Quick example¶
import asyncio
import httpx
from longwei import APClient
async def main():
async with httpx.AsyncClient() as client:
ap = await APClient.create(
instance="mastodon.social",
client=client,
access_token="your_access_token",
)
status = await ap.post_status("Hello, fediverse!")
print(f"Posted: {status.url}")
asyncio.run(main())
Creating an APClient¶
Recommended: async factory¶
APClient.create() is the recommended entry point. It calls determine_instance_type()
automatically, configuring server-specific parameters (status length limit, attachment limits,
supported MIME types) before any API call is made.
async with httpx.AsyncClient() as client:
ap = await APClient.create(
instance="mastodon.social", # domain or full URL; trailing slash is stripped
client=client, # httpx AsyncClient
access_token="your_token", # optional — omit for public endpoints
timeout=30, # optional — seconds; defaults to 120
)
The instance parameter is validated before any HTTP call:
- A bare hostname (e.g.
"mastodon.social") is automatically normalised to"https://mastodon.social". - Plain
http://URLs are rejected — HTTPS is required to protect credentials in transit. - Private, loopback, link-local, and reserved IP ranges are rejected (RFC 1918, 169.254.0.0/16, ::1, etc.).
- Blocked hostnames (
localhost,metadata.google.internal,metadata.internal) are rejected.
A ClientError is raised immediately if validation fails — no HTTP request is made.
Direct instantiation¶
You can also instantiate directly. The instance type defaults to INSTANCE_TYPE_MASTODON until
determine_instance_type() is called manually.
ap = APClient(
instance="mastodon.social",
client=client,
access_token="your_token",
)
await ap.determine_instance_type() # optional — only needed for accurate limits
Authentication¶
To authenticate, you need an access token. See the Authentication guide for how to obtain one using the password grant or the OAuth authorization code flow.
If you are building a tool that only reads public data (public timelines, public statuses),
you can omit the access_token parameter.
Basic operations¶
Read the home timeline¶
statuses = await ap.get_home_timeline(limit=20)
for status in statuses:
author = status.account.username if status.account else "?"
print(f"@{author}: {(status.content or '')[:80]}")
Post a status¶
from longwei import Visibility
status = await ap.post_status(
"Hello, fediverse!",
visibility=Visibility.PUBLIC, # default; see Enums for all options
)
print(f"Posted: {status.url}")
Delete a status¶
Search¶
from longwei import SearchType
results = await ap.search(query="python", query_type=SearchType.HASHTAGS)
for tag in results.get("hashtags", []):
print(tag["name"])
Pagination¶
Timeline methods that support pagination store the next/previous page cursors on the client instance after each call:
first_page = await ap.get_public_timeline(limit=20)
# Fetch the next page using max_id from the stored pagination state
next_max_id = ap.pagination["next"]["max_id"]
if next_max_id:
second_page = await ap.get_public_timeline(limit=20, max_id=next_max_id)
ap.pagination structure:
Values are None when there is no further page in that direction.
Rate limits¶
After each successful response the client tracks the server's rate limit headers:
| Attribute | Type | Description |
|---|---|---|
ap.ratelimit_limit |
int |
Total requests allowed per window (default 300) |
ap.ratelimit_remaining |
int |
Requests remaining in the current window |
ap.ratelimit_reset |
datetime |
When the window resets |
Pleroma and snac instances do not return rate limit headers; for those,
ratelimit_reset is set to a synthetic 5-minute window.
When the limit is exhausted, the next API call raises RatelimitError before contacting the
server. See Error Handling for how to handle it.
Context manager pattern¶
httpx.AsyncClient works as a context manager. The recommended pattern is:
async with httpx.AsyncClient() as client:
ap = await APClient.create(instance="mastodon.social", client=client, access_token="token")
# all API calls inside this block
statuses = await ap.get_home_timeline()
The client is closed automatically when the async with block exits.
Instance type detection¶
After APClient.create() (or after calling determine_instance_type() manually), the
following attributes are populated from the server's /api/v2/instance or /api/v1/instance
response:
| Attribute | Type | Description |
|---|---|---|
ap.instance_type |
str |
"Mastodon", "Pleroma", or "snac" |
ap.max_status_len |
int |
Maximum status length in characters |
ap.max_attachments |
int |
Maximum number of media attachments per status |
ap.max_att_size |
int |
Maximum attachment size in bytes |
ap.supported_mime_types |
list[str] |
MIME types accepted for media uploads |
Note — server-reported values, not security guarantees
These attributes are populated from the server's instance configuration response. They are clamped to reasonable bounds (status length ≤ 100 000 chars; attachment count ≤ 100; attachment size ≤ 100 MB; MIME type list capped at 200 entries), but they must not be used as hard security limits in your application. A server you do not control can return any value within those bounds. Use them only for UI hints (e.g. character counters) or soft pre-flight checks.
from longwei import INSTANCE_TYPE_MASTODON, INSTANCE_TYPE_PLEROMA, INSTANCE_TYPE_SNAC
if ap.instance_type == INSTANCE_TYPE_PLEROMA:
print("Connected to a Pleroma instance")
elif ap.instance_type == INSTANCE_TYPE_SNAC:
print("Connected to a snac instance")
print(f"Max status length: {ap.max_status_len} chars")
Note — snac does not support status deletion
snac implements no DELETE endpoints. Calling
delete_status()against a snac instance raisesClientErrorimmediately with a descriptive message.
Dependency security¶
longwei uses uv audit to check all resolved
packages for known CVEs before each release.
requests is not a direct runtime dependency of longwei but may be pulled in as a transitive
dependency by development or documentation tooling. The pyproject.toml constraint
ensures that uv-managed environments always resolve a patched version of requests.
GHSA-gc5v-m9x4-r6x2 describes credential leakage when following redirects to a different
host, patched in requests 2.32.0.
Note — scope of this constraint
This constraint is enforced only in
uv-managed environments. If you install longwei's development dependencies viapipinto an environment whererequestsis already pinned below 2.32.0 by another package, this constraint will not apply. In that case, pinrequests>=2.33.0in your own environment to ensure the fix is in effect.