longwei 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
longwei-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,135 @@
1
+ Metadata-Version: 2.3
2
+ Name: longwei
3
+ Version: 1.0.0
4
+ Summary: Python client library for ActivityPub-compatible servers
5
+ Author: marvin8
6
+ Author-email: marvin8 <marvin8@tuta.io>
7
+ License: AGPL-3.0-or-later
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Requires-Dist: httpx[http2,zstd]~=0.28.1
18
+ Requires-Dist: pydantic~=2.12.5
19
+ Requires-Dist: pytz~=2026.1.post1
20
+ Requires-Dist: whenever~=0.9.5
21
+ Requires-Python: >=3.11, <3.15
22
+ Project-URL: Changelog, https://codeberg.org/MarvinsMastodonTools/longwei/src/branch/main/CHANGELOG.md
23
+ Project-URL: Documentation, https://marvinsmastodontools.codeberg.page/longwei/latest/
24
+ Project-URL: Issues, https://codeberg.org/MarvinsMastodonTools/longwei/issues
25
+ Project-URL: Source, https://codeberg.org/MarvinsMastodonTools/longwei
26
+ Description-Content-Type: text/markdown
27
+
28
+ # longwei
29
+
30
+ [![Docs](https://img.shields.io/badge/docs-latest-blue)](https://marvinsmastodontools.codeberg.page/longwei/latest/ "Latest documentation")
31
+ [![Repo](https://img.shields.io/badge/repo-Codeberg.org-blue)](https://codeberg.org/MarvinsMastodonTools/longwei "Repo at Codeberg.org")
32
+ [![CI](https://ci.codeberg.org/api/badges/MarvinsMastodonTools/longwei/status.svg)](https://ci.codeberg.org/MarvinsMastodonTools/longwei "CI / Woodpecker")
33
+ [![Downloads](https://pepy.tech/badge/longwei)](https://pepy.tech/project/longwei "Download count")
34
+ [![uv_secure](https://img.shields.io/badge/uv--secure-checked-green)](https://docs.astral.sh/uv/guides/audit/ "Checked with uv-secure")
35
+ [![gitleaks](https://img.shields.io/badge/gitleaks-checked-green)](https://github.com/gitleaks/gitleaks "Checked with gitleaks")
36
+ [![pysentry](https://img.shields.io/badge/pysentry-checked-green)](https://github.com/astral-sh/pysentry "Checked with pysentry")
37
+ [![complexipy](https://img.shields.io/badge/complexipy-checked-green.svg)](https://github.com/rohaquinlop/complexipy "Checked with complexipy")
38
+ [![Codestyle](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff "Code style: ruff")
39
+ [![Version](https://img.shields.io/pypi/pyversions/longwei)](https://pypi.org/project/longwei "PyPI – Python Version")
40
+ [![Wheel](https://img.shields.io/pypi/wheel/longwei)](https://pypi.org/project/longwei "PyPI – Wheel")
41
+ [![License: AGPL-3.0-or-later](https://img.shields.io/badge/License-AGPL--3.0--or--later-blue.svg)](https://spdx.org/licenses/AGPL-3.0-or-later.html "AGPL 3 or later")
42
+
43
+ Longwei is a minimal Python implementation of the ActivityPub client REST API used by [Mastodon](https://joinmastodon.org/), [Pleroma](https://pleroma.social/), and [GotoSocial](https://gotosocial.org/). This implementation makes use of asyncio where appropriate. It is intended to be used as a library by other applications. No standalone functionality is provided.
44
+
45
+ So far Longwei only implements the ActivityPub API calls I need for my other projects [Fedinesia](https://codeberg.org/MarvinsMastodonTools/fedinesia), [Feed2Fedi](https://codeberg.org/marvinsmastodontools/feed2fedi), [FenLiu and Zhongli](https://codeberg.org/marvinsmastodontools/dujiangyan).
46
+
47
+ **DO NOT** expect a full or complete implementation of all [ActivityPub API](https://activitypub.rocks/) functionality.
48
+
49
+ ## Quick start
50
+
51
+ ```bash
52
+ pip install longwei
53
+ ```
54
+
55
+ ```python
56
+ import asyncio
57
+ import httpx
58
+ from longwei import APClient
59
+
60
+ async def main():
61
+ async with httpx.AsyncClient() as client:
62
+ ap = await APClient.create(
63
+ instance="mastodon.social",
64
+ client=client,
65
+ access_token="your_token",
66
+ )
67
+ status = await ap.post_status("Hello, fediverse!")
68
+ print(status.url)
69
+
70
+ asyncio.run(main())
71
+ ```
72
+
73
+ ## API References
74
+
75
+ - [Mastodon API](https://docs.joinmastodon.org/api/)
76
+ - [Pleroma API](https://api.pleroma.social)
77
+ - [GotoSocial API](https://docs.gotosocial.org/en/stable/api/swagger/)
78
+
79
+ ## Status
80
+
81
+ longwei is a fork of `minimal_activitypub`. The main breaking change from that package is the
82
+ class rename: `ActivityPub` → `APClient`. See the [Upgrading guide](https://marvinsmastodontools.codeberg.page/longwei/latest/upgrading/) for migration instructions.
83
+
84
+ It is **not** a drop-in replacement. I advise not to use this until at least version 1.0.0 (non-dev).
85
+
86
+
87
+ ## Contributing
88
+
89
+ Issues and pull requests are welcome.
90
+
91
+ longwei is using [pre-commit](https://pre-commit.com/) for code quality checks and [uv](https://docs.astral.sh/uv/) for dependency management. Please install and use both pre-commit and uv if you'd like to contribute.
92
+
93
+ ## Documentation
94
+
95
+ The live documentation is at **https://marvinsmastodontools.codeberg.page/longwei/latest/**
96
+
97
+ Built with [MkDocs](https://www.mkdocs.org/) and the [Material theme](https://squidfunk.github.io/mkdocs-material/). To build and serve locally:
98
+
99
+ ```bash
100
+ uv sync --group docs
101
+ mkdocs serve
102
+ ```
103
+
104
+ ## Development
105
+
106
+ This project uses [uv](https://docs.astral.sh/uv/) for dependency management and virtual environments. To set up the development environment:
107
+
108
+ ```bash
109
+ # Create and activate virtual environment
110
+ uv venv
111
+ source .venv/bin/activate
112
+
113
+ # Install all dependencies including development and documentation groups
114
+ uv sync --all-groups
115
+
116
+ # Run tests
117
+ uv run nox
118
+ ```
119
+
120
+ For more details on the development workflow, check the `noxfile.py` and `.woodpecker/` configuration files.
121
+
122
+ ## Licensing
123
+
124
+ longwei is licenced with the [GNU Affero General Public License v3.0](http://www.gnu.org/licenses/agpl-3.0.html)
125
+
126
+ ## Supporting longwei
127
+
128
+ There are a number of ways you can support longwei:
129
+
130
+ - Create an issue with problems or ideas you have with/for longwei
131
+ - You can [buy me a coffee](https://www.buymeacoffee.com/marvin8).
132
+ - You can send me small change in Monero to the address below:
133
+
134
+ ### Monero donation address
135
+ `8ADQkCya3orL178dADn4bnKuF1JuVGEG97HPRgmXgmZ2cZFSkWU9M2v7BssEGeTRNN2V5p6bSyHa83nrdu1XffDX3cnjKVu`
@@ -0,0 +1,108 @@
1
+ # longwei
2
+
3
+ [![Docs](https://img.shields.io/badge/docs-latest-blue)](https://marvinsmastodontools.codeberg.page/longwei/latest/ "Latest documentation")
4
+ [![Repo](https://img.shields.io/badge/repo-Codeberg.org-blue)](https://codeberg.org/MarvinsMastodonTools/longwei "Repo at Codeberg.org")
5
+ [![CI](https://ci.codeberg.org/api/badges/MarvinsMastodonTools/longwei/status.svg)](https://ci.codeberg.org/MarvinsMastodonTools/longwei "CI / Woodpecker")
6
+ [![Downloads](https://pepy.tech/badge/longwei)](https://pepy.tech/project/longwei "Download count")
7
+ [![uv_secure](https://img.shields.io/badge/uv--secure-checked-green)](https://docs.astral.sh/uv/guides/audit/ "Checked with uv-secure")
8
+ [![gitleaks](https://img.shields.io/badge/gitleaks-checked-green)](https://github.com/gitleaks/gitleaks "Checked with gitleaks")
9
+ [![pysentry](https://img.shields.io/badge/pysentry-checked-green)](https://github.com/astral-sh/pysentry "Checked with pysentry")
10
+ [![complexipy](https://img.shields.io/badge/complexipy-checked-green.svg)](https://github.com/rohaquinlop/complexipy "Checked with complexipy")
11
+ [![Codestyle](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff "Code style: ruff")
12
+ [![Version](https://img.shields.io/pypi/pyversions/longwei)](https://pypi.org/project/longwei "PyPI – Python Version")
13
+ [![Wheel](https://img.shields.io/pypi/wheel/longwei)](https://pypi.org/project/longwei "PyPI – Wheel")
14
+ [![License: AGPL-3.0-or-later](https://img.shields.io/badge/License-AGPL--3.0--or--later-blue.svg)](https://spdx.org/licenses/AGPL-3.0-or-later.html "AGPL 3 or later")
15
+
16
+ Longwei is a minimal Python implementation of the ActivityPub client REST API used by [Mastodon](https://joinmastodon.org/), [Pleroma](https://pleroma.social/), and [GotoSocial](https://gotosocial.org/). This implementation makes use of asyncio where appropriate. It is intended to be used as a library by other applications. No standalone functionality is provided.
17
+
18
+ So far Longwei only implements the ActivityPub API calls I need for my other projects [Fedinesia](https://codeberg.org/MarvinsMastodonTools/fedinesia), [Feed2Fedi](https://codeberg.org/marvinsmastodontools/feed2fedi), [FenLiu and Zhongli](https://codeberg.org/marvinsmastodontools/dujiangyan).
19
+
20
+ **DO NOT** expect a full or complete implementation of all [ActivityPub API](https://activitypub.rocks/) functionality.
21
+
22
+ ## Quick start
23
+
24
+ ```bash
25
+ pip install longwei
26
+ ```
27
+
28
+ ```python
29
+ import asyncio
30
+ import httpx
31
+ from longwei import APClient
32
+
33
+ async def main():
34
+ async with httpx.AsyncClient() as client:
35
+ ap = await APClient.create(
36
+ instance="mastodon.social",
37
+ client=client,
38
+ access_token="your_token",
39
+ )
40
+ status = await ap.post_status("Hello, fediverse!")
41
+ print(status.url)
42
+
43
+ asyncio.run(main())
44
+ ```
45
+
46
+ ## API References
47
+
48
+ - [Mastodon API](https://docs.joinmastodon.org/api/)
49
+ - [Pleroma API](https://api.pleroma.social)
50
+ - [GotoSocial API](https://docs.gotosocial.org/en/stable/api/swagger/)
51
+
52
+ ## Status
53
+
54
+ longwei is a fork of `minimal_activitypub`. The main breaking change from that package is the
55
+ class rename: `ActivityPub` → `APClient`. See the [Upgrading guide](https://marvinsmastodontools.codeberg.page/longwei/latest/upgrading/) for migration instructions.
56
+
57
+ It is **not** a drop-in replacement. I advise not to use this until at least version 1.0.0 (non-dev).
58
+
59
+
60
+ ## Contributing
61
+
62
+ Issues and pull requests are welcome.
63
+
64
+ longwei is using [pre-commit](https://pre-commit.com/) for code quality checks and [uv](https://docs.astral.sh/uv/) for dependency management. Please install and use both pre-commit and uv if you'd like to contribute.
65
+
66
+ ## Documentation
67
+
68
+ The live documentation is at **https://marvinsmastodontools.codeberg.page/longwei/latest/**
69
+
70
+ Built with [MkDocs](https://www.mkdocs.org/) and the [Material theme](https://squidfunk.github.io/mkdocs-material/). To build and serve locally:
71
+
72
+ ```bash
73
+ uv sync --group docs
74
+ mkdocs serve
75
+ ```
76
+
77
+ ## Development
78
+
79
+ This project uses [uv](https://docs.astral.sh/uv/) for dependency management and virtual environments. To set up the development environment:
80
+
81
+ ```bash
82
+ # Create and activate virtual environment
83
+ uv venv
84
+ source .venv/bin/activate
85
+
86
+ # Install all dependencies including development and documentation groups
87
+ uv sync --all-groups
88
+
89
+ # Run tests
90
+ uv run nox
91
+ ```
92
+
93
+ For more details on the development workflow, check the `noxfile.py` and `.woodpecker/` configuration files.
94
+
95
+ ## Licensing
96
+
97
+ longwei is licenced with the [GNU Affero General Public License v3.0](http://www.gnu.org/licenses/agpl-3.0.html)
98
+
99
+ ## Supporting longwei
100
+
101
+ There are a number of ways you can support longwei:
102
+
103
+ - Create an issue with problems or ideas you have with/for longwei
104
+ - You can [buy me a coffee](https://www.buymeacoffee.com/marvin8).
105
+ - You can send me small change in Monero to the address below:
106
+
107
+ ### Monero donation address
108
+ `8ADQkCya3orL178dADn4bnKuF1JuVGEG97HPRgmXgmZ2cZFSkWU9M2v7BssEGeTRNN2V5p6bSyHa83nrdu1XffDX3cnjKVu`
@@ -0,0 +1,85 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.8.7,<0.9.0"]
3
+ build-backend = "uv_build"
4
+
5
+ [project]
6
+ name = "longwei"
7
+ version = "1.0.0"
8
+ authors = [
9
+ { name = "marvin8", email = "marvin8@tuta.io" },
10
+ ]
11
+ classifiers = [
12
+ "Development Status :: 5 - Production/Stable",
13
+ "Intended Audience :: Developers",
14
+ "Operating System :: OS Independent",
15
+ "Programming Language :: Python",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Programming Language :: Python :: 3.14",
20
+ "Topic :: Software Development :: Libraries :: Python Modules"
21
+ ]
22
+ description = "Python client library for ActivityPub-compatible servers"
23
+ readme = "README.md"
24
+ license = { text = "AGPL-3.0-or-later" }
25
+ requires-python = ">=3.11, <3.15"
26
+ dependencies = [
27
+ "httpx[http2,zstd]~=0.28.1",
28
+ "pydantic~=2.12.5",
29
+ "pytz~=2026.1.post1",
30
+ "whenever~=0.9.5",
31
+ ]
32
+ [dependency-groups]
33
+ dev = [
34
+ "bump-my-version~=1.3.0",
35
+ "complexipy~=5.2.0",
36
+ "git-cliff~=2.12.0",
37
+ "prek~=0.3.8",
38
+ "ruff~=0.15.8",
39
+ "ty~=0.0.27",
40
+ "uv~=0.11.3",
41
+ ]
42
+ docs = [
43
+ "mkdocs~=1.6.1",
44
+ "mkdocs-material~=9.7.6",
45
+ "mkdocstrings~=1.0.3",
46
+ "mkdocstrings-python~=2.0.3",
47
+ "mike~=2.1.4",
48
+ ]
49
+ nox = [
50
+ "nox-uv~=0.7.1",
51
+ ]
52
+ pytest = [
53
+ "pytest~=9.0.2",
54
+ "pytest-asyncio~=1.3.0",
55
+ "pytest-cov~=7.1.0",
56
+ "pytest-httpx~=0.36.0",
57
+ ]
58
+
59
+ [tool.uv]
60
+ constraint-dependencies = [
61
+ "requests>=2.33.0", # Addresses vulnerability GHSA-gc5v-m9x4-r6x2
62
+ ]
63
+
64
+ [project.urls]
65
+ Documentation = "https://marvinsmastodontools.codeberg.page/longwei/latest/"
66
+ Issues = "https://codeberg.org/MarvinsMastodonTools/longwei/issues"
67
+ Source = "https://codeberg.org/MarvinsMastodonTools/longwei"
68
+ Changelog = "https://codeberg.org/MarvinsMastodonTools/longwei/src/branch/main/CHANGELOG.md"
69
+
70
+ [tool.bumpversion]
71
+ commit = true
72
+ tag = true
73
+ tag_name = "{new_version}"
74
+ parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
75
+ serialize = ["{major}.{minor}.{patch}"]
76
+ message = "bump: version {current_version} → {new_version}"
77
+ pre_commit_hooks = ["uv sync", "git add uv.lock"]
78
+
79
+ [[tool.bumpversion.files]]
80
+ filename = "pyproject.toml"
81
+ search = 'version = "{current_version}"'
82
+ replace = 'version = "{new_version}"'
83
+
84
+ [tool.pytest.ini_options]
85
+ asyncio_default_fixture_loop_scope = "session"
@@ -0,0 +1,138 @@
1
+ """Package 'longwei' level definitions."""
2
+
3
+ import logging
4
+
5
+ from httpx import AsyncClient
6
+ from whenever import Instant
7
+
8
+ from longwei._base import USER_AGENT
9
+ from longwei._base import __display_name__
10
+ from longwei._base import __version__
11
+ from longwei._mixin_auth import _AuthMixin
12
+ from longwei._mixin_credentials import _CredentialsMixin
13
+ from longwei._mixin_request_helpers import _RequestHelpersMixin
14
+ from longwei._mixin_statuses import _StatusesMixin
15
+ from longwei._mixin_timelines import _TimelinesMixin
16
+ from longwei.constants import INSTANCE_TYPE_MASTODON
17
+ from longwei.constants import INSTANCE_TYPE_PLEROMA
18
+ from longwei.constants import MAX_ATTACHMENTS_MASTODON
19
+ from longwei.enums import SearchType
20
+ from longwei.enums import Visibility
21
+ from longwei.exceptions import ActivityPubError
22
+ from longwei.exceptions import ApiError
23
+ from longwei.exceptions import ClientError
24
+ from longwei.exceptions import ConflictError
25
+ from longwei.exceptions import ForbiddenError
26
+ from longwei.exceptions import GoneError
27
+ from longwei.exceptions import NetworkError
28
+ from longwei.exceptions import NotFoundError
29
+ from longwei.exceptions import RatelimitError
30
+ from longwei.exceptions import ServerError
31
+ from longwei.exceptions import UnauthorizedError
32
+ from longwei.exceptions import UnprocessedError
33
+ from longwei.models import Account
34
+ from longwei.types import APClientClass
35
+ from longwei.types import Status
36
+
37
+ logger = logging.getLogger(__display_name__)
38
+
39
+
40
+ class APClient(_RequestHelpersMixin, _CredentialsMixin, _TimelinesMixin, _StatusesMixin, _AuthMixin):
41
+ """Simplifies interacting with an ActivityPub server / instance.
42
+
43
+ This is a minimal implementation only implementing methods needed
44
+ for the function of MastodonAmnesia
45
+ """
46
+
47
+ def __init__(
48
+ self: APClientClass,
49
+ instance: str,
50
+ client: AsyncClient,
51
+ access_token: str | None = None,
52
+ timeout: int | None = None,
53
+ ) -> None:
54
+ """Initialise APClient instance with reasonable default values.
55
+
56
+ :param instance: domain name or url to instance to connect to
57
+ :param client: httpx AsyncClient to use for communicating with instance
58
+ :param access_token: authentication token
59
+ :param timeout: Optional number of seconds to wait for a response from the instance server.
60
+ Defaults to None which equates to 120 seconds / 2 minutes timeout
61
+
62
+ """
63
+ self.instance = instance.rstrip("/")
64
+ self.headers: list[tuple[str, str]] = []
65
+ if access_token:
66
+ self.headers.append(("Authorization", f"Bearer {access_token}"))
67
+ self.client = client
68
+ self.pagination: dict[str, dict[str, str | None]] = {
69
+ "next": {"max_id": None, "min_id": None},
70
+ "prev": {"max_id": None, "min_id": None},
71
+ }
72
+ self.timeout = timeout if timeout else 120
73
+ self.instance_type = INSTANCE_TYPE_MASTODON # default until determined otherwise with determine_instance_type()
74
+ self.max_attachments = MAX_ATTACHMENTS_MASTODON
75
+ self.max_att_size = 10000000
76
+ self.supported_mime_types: list[str] = []
77
+ self.max_status_len = 500
78
+ self.ratelimit_limit = 300
79
+ self.ratelimit_remaining = 300
80
+ self.ratelimit_reset = Instant.now().py_datetime()
81
+ logger.debug(
82
+ "APClient(instance=%s, client=%s, access_token=<redacted>)",
83
+ instance,
84
+ client,
85
+ )
86
+ logger.debug("APClient() ... version=%s", __version__)
87
+
88
+ @classmethod
89
+ async def create(
90
+ cls,
91
+ instance: str,
92
+ client: AsyncClient,
93
+ access_token: str | None = None,
94
+ timeout: int | None = None,
95
+ ) -> "APClient":
96
+ """Create and initialise an APClient instance, auto-detecting the instance type.
97
+
98
+ This is the recommended entry point. Unlike direct instantiation, this factory
99
+ automatically calls :meth:`determine_instance_type` to configure server-specific
100
+ parameters (instance type, max status length, attachment limits, MIME types).
101
+
102
+ :param instance: domain name or url to instance to connect to
103
+ :param client: httpx AsyncClient to use for communicating with instance
104
+ :param access_token: authentication token
105
+ :param timeout: optional seconds to wait for a response (default: 120)
106
+ :returns: Fully initialised :class:`APClient` instance
107
+ :raises NetworkError: if the instance cannot be reached during type detection
108
+ """
109
+ ap = cls(instance=instance, client=client, access_token=access_token, timeout=timeout)
110
+ await ap.determine_instance_type()
111
+ return ap
112
+
113
+
114
+ __all__ = [ # noqa: RUF022
115
+ "Account",
116
+ "APClient",
117
+ "APClientClass",
118
+ "ActivityPubError",
119
+ "ApiError",
120
+ "ClientError",
121
+ "ConflictError",
122
+ "__display_name__",
123
+ "ForbiddenError",
124
+ "GoneError",
125
+ "INSTANCE_TYPE_MASTODON",
126
+ "INSTANCE_TYPE_PLEROMA",
127
+ "NetworkError",
128
+ "NotFoundError",
129
+ "RatelimitError",
130
+ "SearchType",
131
+ "ServerError",
132
+ "Status",
133
+ "UnauthorizedError",
134
+ "UnprocessedError",
135
+ "USER_AGENT",
136
+ "__version__",
137
+ "Visibility",
138
+ ]
@@ -0,0 +1,16 @@
1
+ """Internal base definitions shared across mixin modules.
2
+
3
+ This module exists to break the circular import that would arise if mixins
4
+ imported directly from the ``longwei`` package: package-level constants live
5
+ here so that ``__init__.py`` can import both this module and the mixins
6
+ without a cycle.
7
+ """
8
+
9
+ import sys
10
+ from importlib.metadata import version
11
+ from typing import Final
12
+
13
+ __display_name__: Final[str] = "Longwei"
14
+ __version__: Final[str] = version("longwei")
15
+
16
+ USER_AGENT: Final[str] = f"{__display_name__}_v{__version__}_Python_{sys.version.split()[0]}"