Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/release-notes/v2.0.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## moderation_api 2.0.0

A new major version of the Python SDK. Read the breaking changes before you upgrade.

```bash
pip install --upgrade "moderation_api>=2,<3"
```

### Python-specific changes

- Requires Python 3.10 or later (was 3.9).
- Use the client as a context manager: `with ModerationAPI() as client:`. Every method has an `_async` version, for example `await client.content.submit_async(...)`.
- Methods take keyword arguments in snake_case, for example `client.content.submit(content={...}, author_id="user-123")`.
- Verify webhooks with `moderation_api.webhook_signature.construct_event(payload, signature)`.
### What's new

- **Covers the whole API**, including the management API (`projects`, `channels`), wordlists and the review queue.
- **Automatic pagination.** List methods return an iterator that fetches the next page for you.
- **Clear errors.** One error class per HTTP status (`BadRequestError`, `NotFoundError`, `RateLimitError`, ...). Every error has a specific `code` (for example `invalid_api_key`, `quota_exceeded` or `author_not_found`), a `request_id` and a `doc_url`. See [Errors](https://docs.moderationapi.com/api-reference/errors).
- **Retries** with exponential backoff on `429` and `5xx`, and timeouts per client or per request.
- **Webhook verification** that reads the secret from `MODAPI_WEBHOOK_SECRET`.

### Breaking changes

The SDK is now generated from our OpenAPI spec with a new generator. Most calls keep their names, but check these:

- **List responses** are `{ data, pagination }` instead of a plain array or a resource-specific shape, and list methods take `page` and `pageSize`.
- **Errors** have a new body: `code` is the specific error code, not the HTTP category. The old `data` field is gone.
- **Renamed:** `account.list` is now `account.retrieve`, and `actions.execute.execute` is now `actions.execute`.
- **Removed:** `actions.execute.executeByID` (use `actions.execute` with `actionId` or `actionKey`), `auth.*`, and `content.stream` (see [Real-time voice](https://docs.moderationapi.com/content-moderation/real-time-voice)).
- **Organization keys** work only with `projects` and `channels`; project keys work with everything else. Use one client per key. See the README.

The license is unchanged: Apache-2.0.
46 changes: 34 additions & 12 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,51 @@
# Maintained in moderation-api/sdk-generator (custom/python). Edits here are overwritten.
# Every push to main whose package version has no release tag yet publishes
# that version and creates the GitHub release (notes: .github/release-notes/vX.Y.Z.md
# if present, otherwise generated from the merged pull requests).
name: Publish PyPI
on:
release:
types: [published]
push:
branches: [main]
workflow_dispatch:

concurrency: release

permissions:
contents: read
contents: write

jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Read the version
run: echo "VERSION=$(sed -n 's/^version = \"\(.*\)\"$/\1/p' pyproject.toml | head -n 1)" >> "$GITHUB_ENV"
- name: Check for an unreleased version
id: version
run: |
echo "VERSION=${VERSION}" >> "$GITHUB_ENV"
if git ls-remote --exit-code --tags origin "refs/tags/v${VERSION}" >/dev/null; then
echo "v${VERSION} is already released."
echo "release=false" >> "$GITHUB_OUTPUT"
else
echo "release=true" >> "$GITHUB_OUTPUT"
fi
- uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2
if: steps.version.outputs.release == 'true'
with:
version: "0.9.13"
- name: Check the release tag matches pyproject.toml
if: github.event_name == 'release'
run: |
version=$(sed -n 's/^version = "\(.*\)"$/\1/p' pyproject.toml | head -1)
if [ "${GITHUB_REF_NAME#v}" != "$version" ]; then
echo "::error::Release tag $GITHUB_REF_NAME does not match pyproject.toml version $version"
exit 1
fi
- run: bash scripts/publish.sh
- if: steps.version.outputs.release == 'true'
run: bash scripts/publish.sh
env:
PYPI_TOKEN: ${{ secrets.MODERATION_API_PYPI_TOKEN || secrets.PYPI_TOKEN }}
- name: Create the GitHub release
if: steps.version.outputs.release == 'true'
env:
GH_TOKEN: ${{ github.token }}
run: |
notes=".github/release-notes/v${VERSION}.md"
if [ -f "$notes" ]; then
gh release create "v${VERSION}" --target "$GITHUB_SHA" --title "v${VERSION}" --notes-file "$notes"
else
gh release create "v${VERSION}" --target "$GITHUB_SHA" --title "v${VERSION}" --generate-notes
fi
2 changes: 1 addition & 1 deletion .speakeasy/gen.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
lockVersion: 2.0.0
id: 9620bfba-8df9-4d0e-8796-8423b39f97f0
management:
docChecksum: 3320e8867e978fb3c091936a85b4b990
docChecksum: 9e61a5512adcd4b1e0a74112ed775731
docVersion: 1.1.0
speakeasyVersion: internal
generationVersion: internal
Expand Down
Loading