Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
5b6bd80
chore(deps): add pydantic and pyld to dependency
AmaseCocoa Nov 27, 2025
9351edf
feat: migrate to pydantic
AmaseCocoa Nov 28, 2025
3d953e4
Merge branch 'develop' into next
AmaseCocoa Nov 28, 2025
95eb3bb
feat: use pydantic-based dumper
AmaseCocoa Nov 28, 2025
c89ae6d
Merge branch 'next' of https://github.com/fedi-libs/apmodel into next
AmaseCocoa Nov 28, 2025
9ea90d7
chore: remove unused codes
AmaseCocoa Nov 28, 2025
325a3ad
feat: migrate to pydantic
AmaseCocoa Dec 19, 2025
48ac57d
fix: pydantic
AmaseCocoa Dec 19, 2025
ca05723
fix: allow extra value
AmaseCocoa Dec 19, 2025
4f26053
fix: rename custom_to_json to _inference_context for avoid recursion
AmaseCocoa Dec 19, 2025
344769a
fix: add serialize_by_alias
AmaseCocoa Dec 19, 2025
32b11e1
feat: add to_dict function
AmaseCocoa Dec 19, 2025
0a3ce22
fix(test): remove debug code
AmaseCocoa Dec 19, 2025
004794c
fix: use Unpack from typing_extensions
AmaseCocoa Dec 19, 2025
3a3c264
chore(deps): add typing-extensions
AmaseCocoa Dec 19, 2025
dc6c385
chore(ci): add 3.14 to test
AmaseCocoa Dec 19, 2025
a83c1f9
fix(ci): use uv v9
AmaseCocoa Dec 19, 2025
137d651
chore: add test
AmaseCocoa Dec 19, 2025
cd27f80
docs: create documents
AmaseCocoa Dec 19, 2025
c3c1abb
chore(ci): bump uv version
AmaseCocoa Dec 19, 2025
aadbf4a
feat: add extra models from litepub (EmojiReact)
AmaseCocoa Dec 20, 2025
fb3906c
fix: add _model_type to all models
AmaseCocoa Dec 20, 2025
8cdca6c
feat: preload apmodel's models for better performance
AmaseCocoa Dec 20, 2025
c145b1b
fix: fix circler import
AmaseCocoa Dec 20, 2025
42bad9f
perf: implement lazy loading for model registry
AmaseCocoa Dec 20, 2025
5535dd0
docs(registry): add documentation for model registry
AmaseCocoa Dec 20, 2025
44677af
chore: add task docs:dev
AmaseCocoa Dec 20, 2025
b0e294c
refactor(registry): accept preload_mapping in ModelRegistry constructor
AmaseCocoa Dec 21, 2025
8a8f3f9
test(registry): add comprehensive tests for ModelRegistry
AmaseCocoa Dec 21, 2025
eb251bb
fix: add core models to bootstrap type mapping
AmaseCocoa Dec 21, 2025
26e0aab
feat: include litepub-0.1.jsonld to preloaded schema
AmaseCocoa Dec 21, 2025
9715409
fix: fix type annotation
AmaseCocoa Dec 21, 2025
b3c0a34
fix: support litepub 0.1 schema
AmaseCocoa Dec 21, 2025
1a3dfbf
feat(tests): add Akkoma actor, note, and replies test data
AmaseCocoa Dec 21, 2025
88154a4
feat(core): implement likes and shares in Object model
AmaseCocoa Dec 21, 2025
a54f57f
chore: cleanup test code
AmaseCocoa Dec 21, 2025
1613af4
feat(tests): add test data from mastodon 4.x
AmaseCocoa Dec 21, 2025
0f056d0
feat(tests): setup codecov
AmaseCocoa Dec 21, 2025
235f040
chore: cleanup unused codes
AmaseCocoa Dec 21, 2025
206e6c5
fix(ci): update pytest coverage command
AmaseCocoa Dec 21, 2025
7dcdb54
fix: add TypeAlias to Literal
AmaseCocoa Dec 22, 2025
1f27920
docs(readme): Update README with detailed project info and usage
AmaseCocoa Dec 22, 2025
498c0ae
docs(readme): add pre-commit.ci status
AmaseCocoa Dec 22, 2025
75ff333
refactor(lint): fix lint error
AmaseCocoa Dec 22, 2025
551d317
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 22, 2025
8bd154a
fix(tests): remove skip and fix nodeinfo test
AmaseCocoa Dec 22, 2025
39e5f9b
feat(dev): setup pyrefly
AmaseCocoa Dec 22, 2025
1dd0bf1
Merge branch 'next' of https://github.com/fedi-libs/apmodel into next
AmaseCocoa Dec 22, 2025
f5e9308
fix(agents): fix to correct directory
AmaseCocoa Dec 22, 2025
fd1adaf
fix(core): merge field_validator into one function
AmaseCocoa Dec 22, 2025
8647242
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 22, 2025
dc18468
feat(pre-commit): add pyrefly to pre-commit config
AmaseCocoa Dec 22, 2025
9306165
fix(type): fix types
AmaseCocoa Dec 22, 2025
bfc8b28
fix(type): Resolve all pyrefly type errors
AmaseCocoa Dec 22, 2025
4fe5bf1
Merge branch 'next' of https://github.com/fedi-libs/apmodel into next
AmaseCocoa Dec 22, 2025
c397a2b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 22, 2025
6b51800
fix(pre-commit): use managed pyrefly install
AmaseCocoa Dec 22, 2025
7b5a348
Revert "[pre-commit.ci] auto fixes from pre-commit.com hooks"
AmaseCocoa Dec 22, 2025
6515fd1
Merge branch 'next' of https://github.com/fedi-libs/apmodel into next
AmaseCocoa Dec 22, 2025
6844d37
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 22, 2025
1cefea4
fix(collection): Properly load OrderedCollectionPage and handle ordered
AmaseCocoa Dec 23, 2025
cb209d6
Merge branch 'next' of https://github.com/fedi-libs/apmodel into next
AmaseCocoa Dec 23, 2025
32498ac
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 23, 2025
6251d07
fix(pre-commit): add dev-dependencies to additional_dependencies
AmaseCocoa Dec 23, 2025
293fe35
Merge branch 'next' of https://github.com/fedi-libs/apmodel into next
AmaseCocoa Dec 23, 2025
05d9c53
feat(pre-commit): automate sync dependencies from pyproject.toml
AmaseCocoa Dec 23, 2025
c6e75ae
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 23, 2025
1c30a38
fix(multibase): use correct format
AmaseCocoa Dec 23, 2025
bbfab5b
fix(multibase): use PKCS8
AmaseCocoa Dec 23, 2025
cb1ede4
feat(object): separate _inference_context
AmaseCocoa Dec 23, 2025
bbaa4f9
fix(jsonld): always serialize @context as a list
AmaseCocoa Dec 23, 2025
64de373
feat(models): add ActorEndpoints and expand model test coverage
AmaseCocoa Dec 23, 2025
0b1c493
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 23, 2025
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
29 changes: 29 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Documentation
on:
push:
branches:
- master
- main
permissions:
contents: read
pages: write
id-token: write
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- uses: actions/configure-pages@v5
- uses: actions/checkout@v5
- name: Setup uv
uses: astral-sh/setup-uv@v6
- run: |
uv sync --dev
zensical build --clean
- uses: actions/upload-pages-artifact@v4
with:
path: site
- uses: actions/deploy-pages@v4
id: deployment
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
- name: Setup uv
uses: astral-sh/setup-uv@v6
with:
version: ">=0.7.21,<0.8"
version: ">=0.9.13,<0.10"

- name: Set SETUPTOOLS_SCM_PRETEND_VERSION
run: echo "SETUPTOOLS_SCM_PRETEND_VERSION=${GITHUB_REF##*/}" >> $GITHUB_ENV
Expand Down
11 changes: 8 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,24 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup uv
uses: astral-sh/setup-uv@v6
with:
version: ">=0.7.21,<0.8"
version: ">=0.9.13,<0.10"
- name: Set up Python ${{ matrix.python-version }}
env:
PYTHON_VERSION: ${{ matrix.python-version }}
run: uv venv --python $PYTHON_VERSION
- name: Install Dependencies
run: uv sync --dev --locked
- name: Run Tests
run: uv run pytest
run: uv run pytest --cov=./src/apmodel --cov-branch --cov-report=xml

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
72 changes: 72 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
repos:
- hooks:
- additional_dependencies:
- cryptography>=45.0.6
- git-cliff>=2.10.0
- mkdocstrings-python>=2.0.1
- multiformats>=0.3.1.post4
- pydantic>=2.12.5
- pyld[aiohttp,requests]>=2.0.4
- pyrefly>=0.46.0
- pytest-cov>=7.0.0
- pytest>=8.4.1
- pyyaml>=6.0.3
- typing-extensions>=4.15.0
- zensical>=0.0.13
args:
- --fix
description: Run 'ruff' for extremely fast Python linting
entry: ruff check --force-exclude
id: ruff
language: python
minimum_pre_commit_version: 2.9.2
name: ruff
require_serial: true
types_or:
- python
- pyi
- additional_dependencies:
- cryptography>=45.0.6
- git-cliff>=2.10.0
- mkdocstrings-python>=2.0.1
- multiformats>=0.3.1.post4
- pydantic>=2.12.5
- pyld[aiohttp,requests]>=2.0.4
- pyrefly>=0.46.0
- pytest-cov>=7.0.0
- pytest>=8.4.1
- pyyaml>=6.0.3
- typing-extensions>=4.15.0
- zensical>=0.0.13
args: []
description: Run 'ruff format' for extremely fast Python formatting
entry: ruff format --force-exclude
id: ruff-format
language: python
minimum_pre_commit_version: 2.9.2
name: ruff-format
require_serial: true
types_or:
- python
- pyi
repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.6
- hooks:
- additional_dependencies:
- cryptography>=45.0.6
- git-cliff>=2.10.0
- mkdocstrings-python>=2.0.1
- multiformats>=0.3.1.post4
- pydantic>=2.12.5
- pyld[aiohttp,requests]>=2.0.4
- pyrefly>=0.46.0
- pytest-cov>=7.0.0
- pytest>=8.4.1
- pyyaml>=6.0.3
- typing-extensions>=4.15.0
- zensical>=0.0.13
id: pyrefly-check
name: Pyrefly (type checking)
pass_filenames: false
repo: https://github.com/facebook/pyrefly-pre-commit
rev: 0.46.0
36 changes: 36 additions & 0 deletions .zed/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"languages": {
"Python": {
"language_servers": ["ruff", "pyrefly"]
}
},
"lsp": {
"pyrefly": {
"binary": {
"path": ".venv/bin/pyrefly",
"arguments": ["lsp"]
},
"settings": {
"python": {
"pythonPath": ".venv/bin/python"
},
"pyrefly": {
"project_includes": ["src/**/*.py", "tests/**/*.py"],
"project_excludes": ["**/.[!/.]*", "**/*venv/**"],
"search_path": ["src"],
"ignore_errors_in_generated_code": true
}
}
},
"ruff": {
"initialization_options": {
"settings": {
"lineLength": 80,
"lint": {
"extendSelect": ["I"]
}
}
}
}
}
}
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ apmodel provides model implementations for Activity Streams 2.0, CryptographicKe

## Features
- A `load` function that automatically reads the `type` key from JSON and converts it to the correct model. It returns the original JSON if no matching model is found.
- If a key from the JSON does not correspond to a field in the model, it is added to the model's `_extra` dictionary.
- If a key from the JSON does not correspond to a field in the model, it is added to the model's `model_extra` dictionary.

## How to run scripts
This project uses [Task](https://taskfile.dev/) for running scripts. You will need to install it to use the commands below.
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
- *(question)* Prevent side effects in Question.to_json
- *(tombstone)* Prevent side effects in Tombstone.to_json
- Use `ctx.full_context` instead of `ctx.json`
- Initialize aggregated_context as a new LDContext instance, copied from self._context
- Initialize aggregated_context as a new LDContext instance, copied from self.context
- Use PrivateFormat.PKCS1 instead of PrivateFormat.Raw in rsa-priv
- *(cid)* Handle 'Z' timezone in DataIntegrityProof
- Fixes for violation of the Liskov Substitution Principle
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ apmodel provides model implementations for Activity Streams 2.0, CryptographicKe

## Features
- A `load` function that automatically reads the `type` key from JSON and converts it to the correct model. It returns the original JSON if no matching model is found.
- If a key from the JSON does not correspond to a field in the model, it is added to the model's `_extra` dictionary.
- If a key from the JSON does not correspond to a field in the model, it is added to the model's `model_extra` dictionary.

## How to run scripts
This project uses [Task](https://taskfile.dev/) for running scripts. You will need to install it to use the commands below.
Expand Down
2 changes: 1 addition & 1 deletion GEMINI.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ apmodel provides model implementations for Activity Streams 2.0, CryptographicKe

## Features
- A `load` function that automatically reads the `type` key from JSON and converts it to the correct model. It returns the original JSON if no matching model is found.
- If a key from the JSON does not correspond to a field in the model, it is added to the model's `_extra` dictionary.
- If a key from the JSON does not correspond to a field in the model, it is added to the model's `model_extra` dictionary.

## How to run scripts
This project uses [Task](https://taskfile.dev/) for running scripts. You will need to install it to use the commands below.
Expand Down
110 changes: 104 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,105 @@
# apmodel
ActivityStreams 2.0 and nodeinfo 2.0/2.1 implementation for Python.
## Other ActivityPub Tools
- [apsig: Signature implementation used in ActivityPub](https://github.com/AmaseCocoa/apsig)
- [apkit: Powerful Toolkit for ActivityPub Implementations](https://github.com/AmaseCocoa/apkit)
## Links
- [Official Fedi Account](https://hollo.amase.cc/@apkit)

[![PyPI - Version](https://img.shields.io/pypi/v/apmodel)](https://pypi.org/project/apmodel)
[![Tests](https://github.com/fedi-libs/apmodel/actions/workflows/test.yml/badge.svg)](https://github.com/fedi-libs/apmodel/actions/workflows/test.yml)
[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/fedi-libs/apmodel/develop.svg)](https://results.pre-commit.ci/latest/github/fedi-libs/apmodel/develop)

apmodel is a Python library that provides model implementations for various decentralized social web protocols.

It is designed to easily parse and handle JSON data from sources like Mastodon, Misskey, and other Fediverse software.

## Features

- **Automatic Model Resolution**: The `apmodel.load` function automatically deserializes a JSON object into the appropriate Python object by reading its `type` field. If no matching model is found, the original dictionary is returned.
- **Flexible Deserialization**: Any properties in the JSON that do not have a corresponding field in the model are collected into an `model_extra` dictionary. This ensures no data is lost.
- **Type Hinting**: Fully type-hinted for a better development experience and robust static analysis.

## Installation

```bash
pip install apmodel

# uv
uv add apmodel
```

## Usage

Here is a basic example of how to parse an ActivityStreams 2.0 `Note` object from a JSON string.

```python
import apmodel

# Example JSON from a Fediverse server
json_data = {
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://example.com/users/alice/statuses/1",
"type": "Note",
"published": "2023-12-25T12:00:00Z",
"attributedTo": "https://example.com/users/alice",
"content": "<p>Hello, world!</p>",
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"cc": ["https://example.com/users/alice/followers"]
}

# Load the JSON into an apmodel object
obj = apmodel.load(json_data)

# Now you can access properties with type safety
if isinstance(obj, apmodel.vocab.Note):
print(f"Type: {obj.type}")
print(f"Content: {obj.content}")
print(f"Published: {obj.published}")

# >> Type: Note
# >> Content: <p>Hello, world!</p>
# >> Published: 2023-12-25 12:00:00+00:00
```

## Documentation

https://fedi-libs.github.io/apmodel

## Supported Specifications

`apmodel` provides models for the following specifications:

- **Activity Streams 2.0**: Core types like `Object`, `Activity`, `Collection`, and `Link`.
- **Activity Vocabulary**: All types.
- **Security Vocabulary v1**: `CryptographicKey` (`Key`).
- **Controlled Identifiers v1.0**: `Multikey` and `DataIntegrityProof`.
- **schema.org**: `PropertyValue`.
- **NodeInfo 2.0/2.1**
- **Litepub**: `EmojiReact`
- **Others**: `Emoji` and `Hashtag`

## Development

This project uses [Task](https://taskfile.dev/) for running scripts. You need to install it first.

- **Setup dev environment**:

```bash
task
```

- **Run tests with Pytest**:

```bash
task test
```

- **Build packages for PyPI**:

```bash
task build
```

- **Development Document**:
```bash
task docs:dev
```

## License

MIT License
6 changes: 5 additions & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ tasks:
silent: true
test:
cmds:
- uv run pytest
- uv run pytest --cov=./src/apmodel
silent: true
docs:dev:
cmds:
- uv run zensical serve
silent: true
build:
cmds:
Expand Down
35 changes: 35 additions & 0 deletions docs/api/core.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Core Types

This section documents the fundamental building blocks of the ActivityStreams models in `apmodel`.

::: apmodel.core.object.Object
options:
show_root_heading: true

::: apmodel.core.activity.Activity
options:
show_root_heading: true

::: apmodel.core.activity.IntransitiveActivity
options:
show_root_heading: true

::: apmodel.core.link.Link
options:
show_root_heading: true

::: apmodel.core.collection.Collection
options:
show_root_heading: true

::: apmodel.core.collection.OrderedCollection
options:
show_root_heading: true

::: apmodel.core.collection.CollectionPage
options:
show_root_heading: true

::: apmodel.core.collection.OrderedCollectionPage
options:
show_root_heading: true
Loading