active-boxes 0.1.0__tar.gz → 0.2.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.
Files changed (24) hide show
  1. {active_boxes-0.1.0 → active_boxes-0.2.0}/PKG-INFO +76 -15
  2. {active_boxes-0.1.0 → active_boxes-0.2.0}/README.md +74 -14
  3. {active_boxes-0.1.0 → active_boxes-0.2.0}/active_boxes/activitypub.py +636 -101
  4. active_boxes-0.2.0/active_boxes/backend.py +252 -0
  5. active_boxes-0.2.0/active_boxes/collection.py +396 -0
  6. {active_boxes-0.1.0 → active_boxes-0.2.0}/active_boxes/content_helper.py +13 -14
  7. active_boxes-0.2.0/active_boxes/data_integrity.py +214 -0
  8. {active_boxes-0.1.0 → active_boxes-0.2.0}/active_boxes/errors.py +2 -3
  9. active_boxes-0.2.0/active_boxes/http_client.py +549 -0
  10. active_boxes-0.2.0/active_boxes/httpsig.py +933 -0
  11. active_boxes-0.2.0/active_boxes/key.py +205 -0
  12. {active_boxes-0.1.0 → active_boxes-0.2.0}/active_boxes/linked_data_sig.py +51 -9
  13. {active_boxes-0.1.0 → active_boxes-0.2.0}/active_boxes/plugin.py +2 -2
  14. {active_boxes-0.1.0 → active_boxes-0.2.0}/active_boxes/urlutils.py +3 -9
  15. active_boxes-0.2.0/active_boxes/webfinger.py +172 -0
  16. {active_boxes-0.1.0 → active_boxes-0.2.0}/pyproject.toml +3 -2
  17. active_boxes-0.1.0/active_boxes/backend.py +0 -140
  18. active_boxes-0.1.0/active_boxes/collection.py +0 -70
  19. active_boxes-0.1.0/active_boxes/httpsig.py +0 -159
  20. active_boxes-0.1.0/active_boxes/key.py +0 -65
  21. active_boxes-0.1.0/active_boxes/webfinger.py +0 -91
  22. {active_boxes-0.1.0 → active_boxes-0.2.0}/LICENSE +0 -0
  23. {active_boxes-0.1.0 → active_boxes-0.2.0}/active_boxes/__init__.py +0 -0
  24. {active_boxes-0.1.0 → active_boxes-0.2.0}/active_boxes/__version__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: active-boxes
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Tiny ActivityPub framework written in Python, both database and server agnostic.
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3.10
14
14
  Classifier: Programming Language :: Python :: 3.11
15
15
  Classifier: Programming Language :: Python :: 3.12
16
16
  Classifier: Programming Language :: Python :: Implementation :: CPython
17
+ Requires-Dist: aiohttp (>=3.9.0)
17
18
  Requires-Dist: bleach (>=6.0.0)
18
19
  Requires-Dist: html2text (>=2020.1.16)
19
20
  Requires-Dist: markdown (>=3.4.0)
@@ -29,7 +30,7 @@ Description-Content-Type: text/markdown
29
30
 
30
31
  This project is a fork of [Little Boxes](https://github.com/tsileo/little-boxes) that has been modernized and relicensed from ISC to MIT.
31
32
 
32
- ⚠️ **Modernization Complete, ActivityPub Compliance In Progress** ⚠️
33
+ **Modernization Complete, ActivityPub Compliance In Progress**
33
34
 
34
35
  This project has been successfully modernized and updated to current Python packaging standards and Python 3.10+ features. Core ActivityPub functionality is implemented, with federation delivery features under development.
35
36
 
@@ -44,9 +45,10 @@ The original README can be found in [ORIGINAL-README.md](ORIGINAL-README.md).
44
45
  - [x] Created comprehensive modernization plans
45
46
  - [x] Modernized codebase to leverage Python 3.10+ features
46
47
  - [x] Created comprehensive test suite
47
- - [~] ActivityPub protocol compliance - Core 11 activities ✅, Extended activities ⚠️
48
+ - [x] ActivityPub protocol compliance - Core 11 activities, Extended activities
48
49
  - [x] Updated documentation and examples
49
50
  - [x] Prepared for stable release
51
+ - [x] **Async-by-default API** with sync wrappers for Flask/Django compatibility
50
52
 
51
53
  ## Modernization Features
52
54
 
@@ -62,49 +64,53 @@ The original README can be found in [ORIGINAL-README.md](ORIGINAL-README.md).
62
64
  ### Code Quality
63
65
 
64
66
  - 100% type hinting coverage
65
- - Comprehensive test suite with ~89% coverage
67
+ - Comprehensive test suite with ~89% code coverage
66
68
  - Modern code formatting with Black
67
69
  - Strict linting with Ruff
68
70
  - Type checking with MyPy
69
71
 
70
72
  ### Testing
71
73
 
72
- - ActivityPub protocol compliance testing (core activities)
74
+ - ActivityPub protocol compliance testing (core + extended activities)
73
75
  - Integration tests with mock servers
74
76
  - Property-based testing for robustness
75
77
  - Security-focused test suite (~89% coverage)
76
78
 
77
79
  ## Implemented ActivityPub Features
78
80
 
79
- ### Core Activities ✅
81
+ ### Core Activities [x]
80
82
 
81
83
  Create, Update, Delete, Follow, Accept, Reject, Add, Remove, Like, Block, Undo, Announce
82
84
 
83
- ### Actor Properties ✅
85
+ ### Extended Activities [x]
86
+
87
+ Flag, Move, Join, Leave, View, Listen, Read, Write, Travel, Arrive
88
+
89
+ ### Actor Properties [x]
84
90
 
85
91
  inbox, outbox, following, followers, preferredUsername, endpoints (sharedInbox)
86
92
 
87
- ### Collections ✅
93
+ ### Collections [x]
88
94
 
89
95
  Collection, OrderedCollection, CollectionPage, OrderedCollectionPage
90
96
 
91
- ### Security ✅
97
+ ### Security [x]
92
98
 
93
99
  HTTP Signatures (generation/verification), Linked Data Signatures
94
100
 
95
- ### Plugin Interface ✅
101
+ ### Plugin Interface [x]
96
102
 
97
103
  `active_boxes.plugin.ActivityPubPlugin` - Protocol defining app responsibilities
98
104
 
99
105
  ### Missing (Under Development)
100
106
 
101
- - Extended activities: Flag, Move, Join, Leave, View, Listen, Read, Write, Travel, Arrive
102
107
  - Per-object Likes/Shares collections
103
108
  - Backward pagination in collections
109
+ - Featured collection support
104
110
 
105
111
  ## Quick Start
106
112
 
107
- **This is an async library** - your plugin should use `asyncio` or any async framework (FastAPI, aiohttp, etc.).
113
+ **This is an async-first library** - the primary API uses `async`/`await`. Sync wrappers (e.g., `fetch_iri_sync()`) are available for Flask/Django compatibility.
108
114
 
109
115
  ### 1. Implement the Plugin Protocol
110
116
 
@@ -173,6 +179,8 @@ ap.use_backend(plugin)
173
179
 
174
180
  ### 3. Create and Send Activities
175
181
 
182
+ **Async (Recommended for FastAPI, aiohttp, etc.):**
183
+
176
184
  ```python
177
185
  # Create a note
178
186
  note = ap.Note(
@@ -188,12 +196,35 @@ create.set_id("https://myapp.example/activity/abc123", "abc123")
188
196
  # Get recipients and deliver
189
197
  recipients = create.recipients() # Computed by library
190
198
  for inbox in recipients:
191
- actor = fetch_actor(create.get_actor().id)
199
+ actor = await fetch_actor(create.get_actor().id)
192
200
  await plugin.deliver_activity(create.to_dict(), inbox, actor)
193
201
  ```
194
202
 
203
+ **Sync (For Flask, Django sync views):**
204
+
205
+ ```python
206
+ # Create a note
207
+ note = ap.Note(
208
+ content="Hello, federation!",
209
+ attributedTo="https://myapp.example/user/alice",
210
+ to=[ap.AS_PUBLIC],
211
+ )
212
+
213
+ # Create the activity wrapping the note
214
+ create = note.build_create()
215
+ create.set_id("https://myapp.example/activity/abc123", "abc123")
216
+
217
+ # Get recipients and deliver (sync wrapper)
218
+ recipients = create.recipients()
219
+ for inbox in recipients:
220
+ actor = fetch_actor_sync(create.get_actor_sync().id)
221
+ plugin.deliver_activity(create.to_dict(), inbox, actor)
222
+ ```
223
+
195
224
  ### 4. Receive Activities
196
225
 
226
+ **Async (FastAPI, aiohttp):**
227
+
197
228
  ```python
198
229
  # In your inbox endpoint handler
199
230
  async def inbox_handler(request):
@@ -202,6 +233,17 @@ async def inbox_handler(request):
202
233
  return web.Response(status=202)
203
234
  ```
204
235
 
236
+ **Sync (Flask, Django sync views):**
237
+
238
+ ```python
239
+ # In your Flask route
240
+ @app.post("/inbox")
241
+ def inbox():
242
+ activity = request.get_json()
243
+ plugin.receive_activity_sync(activity, source_inbox=request.url)
244
+ return "", 202
245
+ ```
246
+
205
247
  ### 5. Working with Actors
206
248
 
207
249
  ```python
@@ -230,10 +272,29 @@ outbox = ap.OrderedCollection(
230
272
  first="https://myapp.example/user/alice/outbox?page=1",
231
273
  )
232
274
 
233
- # Library handles parsing remote collections
234
- items = backend.parse_collection(url="https://example.com/user/bob/outbox")
275
+ # Library handles parsing remote collections (async)
276
+ items = await backend.parse_collection(url="https://example.com/user/bob/outbox")
277
+
278
+ # Or use sync wrapper
279
+ items = backend.parse_collection_sync(url="https://example.com/user/bob/outbox")
235
280
  ```
236
281
 
282
+ ## API Naming Convention
283
+
284
+ The library uses an **async-first** naming convention:
285
+
286
+ | Operation | Async (Primary) | Sync Wrapper |
287
+ |-----------|----------------|--------------|
288
+ | Fetch IRI | `fetch_iri()` | `fetch_iri_sync()` |
289
+ | Fetch JSON | `fetch_json()` | `fetch_json_sync()` |
290
+ | Get Actor | `get_actor()` | `get_actor_sync()` |
291
+ | Get Object | `get_object()` | `get_object_sync()` |
292
+ | WebFinger | `webfinger()` | `webfinger_sync()` |
293
+ | Verify Signature | `verify_request()` | `verify_request_sync()` |
294
+ | Parse Collection | `parse_collection()` | `parse_collection_sync()` |
295
+
296
+ **Guideline:** Use async methods by default. Use `_sync()` variants only when integrating with sync frameworks like Flask or Django sync views.
297
+
237
298
  ## Plugin Responsibilities
238
299
 
239
300
  | What Library Does | What Your App Does |
@@ -2,7 +2,7 @@
2
2
 
3
3
  This project is a fork of [Little Boxes](https://github.com/tsileo/little-boxes) that has been modernized and relicensed from ISC to MIT.
4
4
 
5
- ⚠️ **Modernization Complete, ActivityPub Compliance In Progress** ⚠️
5
+ **Modernization Complete, ActivityPub Compliance In Progress**
6
6
 
7
7
  This project has been successfully modernized and updated to current Python packaging standards and Python 3.10+ features. Core ActivityPub functionality is implemented, with federation delivery features under development.
8
8
 
@@ -17,9 +17,10 @@ The original README can be found in [ORIGINAL-README.md](ORIGINAL-README.md).
17
17
  - [x] Created comprehensive modernization plans
18
18
  - [x] Modernized codebase to leverage Python 3.10+ features
19
19
  - [x] Created comprehensive test suite
20
- - [~] ActivityPub protocol compliance - Core 11 activities ✅, Extended activities ⚠️
20
+ - [x] ActivityPub protocol compliance - Core 11 activities, Extended activities
21
21
  - [x] Updated documentation and examples
22
22
  - [x] Prepared for stable release
23
+ - [x] **Async-by-default API** with sync wrappers for Flask/Django compatibility
23
24
 
24
25
  ## Modernization Features
25
26
 
@@ -35,49 +36,53 @@ The original README can be found in [ORIGINAL-README.md](ORIGINAL-README.md).
35
36
  ### Code Quality
36
37
 
37
38
  - 100% type hinting coverage
38
- - Comprehensive test suite with ~89% coverage
39
+ - Comprehensive test suite with ~89% code coverage
39
40
  - Modern code formatting with Black
40
41
  - Strict linting with Ruff
41
42
  - Type checking with MyPy
42
43
 
43
44
  ### Testing
44
45
 
45
- - ActivityPub protocol compliance testing (core activities)
46
+ - ActivityPub protocol compliance testing (core + extended activities)
46
47
  - Integration tests with mock servers
47
48
  - Property-based testing for robustness
48
49
  - Security-focused test suite (~89% coverage)
49
50
 
50
51
  ## Implemented ActivityPub Features
51
52
 
52
- ### Core Activities ✅
53
+ ### Core Activities [x]
53
54
 
54
55
  Create, Update, Delete, Follow, Accept, Reject, Add, Remove, Like, Block, Undo, Announce
55
56
 
56
- ### Actor Properties ✅
57
+ ### Extended Activities [x]
58
+
59
+ Flag, Move, Join, Leave, View, Listen, Read, Write, Travel, Arrive
60
+
61
+ ### Actor Properties [x]
57
62
 
58
63
  inbox, outbox, following, followers, preferredUsername, endpoints (sharedInbox)
59
64
 
60
- ### Collections ✅
65
+ ### Collections [x]
61
66
 
62
67
  Collection, OrderedCollection, CollectionPage, OrderedCollectionPage
63
68
 
64
- ### Security ✅
69
+ ### Security [x]
65
70
 
66
71
  HTTP Signatures (generation/verification), Linked Data Signatures
67
72
 
68
- ### Plugin Interface ✅
73
+ ### Plugin Interface [x]
69
74
 
70
75
  `active_boxes.plugin.ActivityPubPlugin` - Protocol defining app responsibilities
71
76
 
72
77
  ### Missing (Under Development)
73
78
 
74
- - Extended activities: Flag, Move, Join, Leave, View, Listen, Read, Write, Travel, Arrive
75
79
  - Per-object Likes/Shares collections
76
80
  - Backward pagination in collections
81
+ - Featured collection support
77
82
 
78
83
  ## Quick Start
79
84
 
80
- **This is an async library** - your plugin should use `asyncio` or any async framework (FastAPI, aiohttp, etc.).
85
+ **This is an async-first library** - the primary API uses `async`/`await`. Sync wrappers (e.g., `fetch_iri_sync()`) are available for Flask/Django compatibility.
81
86
 
82
87
  ### 1. Implement the Plugin Protocol
83
88
 
@@ -146,6 +151,8 @@ ap.use_backend(plugin)
146
151
 
147
152
  ### 3. Create and Send Activities
148
153
 
154
+ **Async (Recommended for FastAPI, aiohttp, etc.):**
155
+
149
156
  ```python
150
157
  # Create a note
151
158
  note = ap.Note(
@@ -161,12 +168,35 @@ create.set_id("https://myapp.example/activity/abc123", "abc123")
161
168
  # Get recipients and deliver
162
169
  recipients = create.recipients() # Computed by library
163
170
  for inbox in recipients:
164
- actor = fetch_actor(create.get_actor().id)
171
+ actor = await fetch_actor(create.get_actor().id)
165
172
  await plugin.deliver_activity(create.to_dict(), inbox, actor)
166
173
  ```
167
174
 
175
+ **Sync (For Flask, Django sync views):**
176
+
177
+ ```python
178
+ # Create a note
179
+ note = ap.Note(
180
+ content="Hello, federation!",
181
+ attributedTo="https://myapp.example/user/alice",
182
+ to=[ap.AS_PUBLIC],
183
+ )
184
+
185
+ # Create the activity wrapping the note
186
+ create = note.build_create()
187
+ create.set_id("https://myapp.example/activity/abc123", "abc123")
188
+
189
+ # Get recipients and deliver (sync wrapper)
190
+ recipients = create.recipients()
191
+ for inbox in recipients:
192
+ actor = fetch_actor_sync(create.get_actor_sync().id)
193
+ plugin.deliver_activity(create.to_dict(), inbox, actor)
194
+ ```
195
+
168
196
  ### 4. Receive Activities
169
197
 
198
+ **Async (FastAPI, aiohttp):**
199
+
170
200
  ```python
171
201
  # In your inbox endpoint handler
172
202
  async def inbox_handler(request):
@@ -175,6 +205,17 @@ async def inbox_handler(request):
175
205
  return web.Response(status=202)
176
206
  ```
177
207
 
208
+ **Sync (Flask, Django sync views):**
209
+
210
+ ```python
211
+ # In your Flask route
212
+ @app.post("/inbox")
213
+ def inbox():
214
+ activity = request.get_json()
215
+ plugin.receive_activity_sync(activity, source_inbox=request.url)
216
+ return "", 202
217
+ ```
218
+
178
219
  ### 5. Working with Actors
179
220
 
180
221
  ```python
@@ -203,10 +244,29 @@ outbox = ap.OrderedCollection(
203
244
  first="https://myapp.example/user/alice/outbox?page=1",
204
245
  )
205
246
 
206
- # Library handles parsing remote collections
207
- items = backend.parse_collection(url="https://example.com/user/bob/outbox")
247
+ # Library handles parsing remote collections (async)
248
+ items = await backend.parse_collection(url="https://example.com/user/bob/outbox")
249
+
250
+ # Or use sync wrapper
251
+ items = backend.parse_collection_sync(url="https://example.com/user/bob/outbox")
208
252
  ```
209
253
 
254
+ ## API Naming Convention
255
+
256
+ The library uses an **async-first** naming convention:
257
+
258
+ | Operation | Async (Primary) | Sync Wrapper |
259
+ |-----------|----------------|--------------|
260
+ | Fetch IRI | `fetch_iri()` | `fetch_iri_sync()` |
261
+ | Fetch JSON | `fetch_json()` | `fetch_json_sync()` |
262
+ | Get Actor | `get_actor()` | `get_actor_sync()` |
263
+ | Get Object | `get_object()` | `get_object_sync()` |
264
+ | WebFinger | `webfinger()` | `webfinger_sync()` |
265
+ | Verify Signature | `verify_request()` | `verify_request_sync()` |
266
+ | Parse Collection | `parse_collection()` | `parse_collection_sync()` |
267
+
268
+ **Guideline:** Use async methods by default. Use `_sync()` variants only when integrating with sync frameworks like Flask or Django sync views.
269
+
210
270
  ## Plugin Responsibilities
211
271
 
212
272
  | What Library Does | What Your App Does |