python-kanka 2.4.1__tar.gz → 2.5.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.
- {python_kanka-2.4.1 → python_kanka-2.5.0}/.bumpversion.cfg +1 -1
- {python_kanka-2.4.1 → python_kanka-2.5.0}/PKG-INFO +1 -1
- {python_kanka-2.4.1 → python_kanka-2.5.0}/docs/api-reference.md +14 -2
- {python_kanka-2.4.1 → python_kanka-2.5.0}/docs/pagination.md +8 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/pyproject.toml +1 -1
- {python_kanka-2.4.1 → python_kanka-2.5.0}/src/kanka/_version.py +1 -1
- {python_kanka-2.4.1 → python_kanka-2.5.0}/src/kanka/client.py +38 -2
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/test_client.py +77 -1
- {python_kanka-2.4.1 → python_kanka-2.5.0}/uv.lock +1 -1
- {python_kanka-2.4.1 → python_kanka-2.5.0}/.github/renovate.json +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/.github/workflows/ci.yml +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/.github/workflows/publish.yml +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/.gitignore +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/.pre-commit-config.yaml +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/CHANGELOG.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/CLAUDE.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/LICENSE +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/MANIFEST.in +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/Makefile +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/PUBLISHING.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/README.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/docs/README.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/docs/assets-and-images.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/docs/core-concepts.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/docs/debug-mode.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/docs/entities.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/docs/entity-types-reference.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/docs/error-handling.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/docs/gallery.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/docs/getting-started.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/docs/known-limitations.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/docs/posts.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/docs/rate-limiting.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/docs/search-and-filtering.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/pytest.ini +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/src/kanka/__init__.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/src/kanka/exceptions.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/src/kanka/managers.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/src/kanka/models/__init__.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/src/kanka/models/base.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/src/kanka/models/common.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/src/kanka/models/entities.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/src/kanka/py.typed +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/src/kanka/types.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/__init__.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/README.md +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/__init__.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/base.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/run_integration_tests.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/setup_test_env.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_calendars_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_calendars_simple.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_characters_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_creatures_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_entities_api_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_entity_assets_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_entity_images_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_entity_tags_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_events_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_families_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_gallery_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_journals_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_locations_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_mentions_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_notes_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_organisations_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_posts_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_quests_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_races_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_rate_limiting.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_search_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_tag_colour.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_tags_integration.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/mypy.ini +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/test_client_advanced.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/test_entity_models.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/test_exceptions.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/test_managers.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/test_models.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/test_models_advanced.py +0 -0
- {python_kanka-2.4.1 → python_kanka-2.5.0}/tests/utils.py +0 -0
|
@@ -90,12 +90,21 @@ Get a single entity by its universal `entity_id`. Returns a raw dictionary.
|
|
|
90
90
|
#### entities
|
|
91
91
|
|
|
92
92
|
```python
|
|
93
|
-
entities(**filters) → list[dict[str, Any]]
|
|
93
|
+
entities(page: int = 1, limit: int = 15, **filters) → list[dict[str, Any]]
|
|
94
94
|
```
|
|
95
95
|
|
|
96
96
|
Query the generic `/entities` endpoint. Returns raw dictionaries.
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
| Parameter | Type | Default | Description |
|
|
99
|
+
|-----------|------|---------|-------------|
|
|
100
|
+
| `page` | `int` | `1` | Page number |
|
|
101
|
+
| `limit` | `int` | `15` | Results per page |
|
|
102
|
+
| `types` | `list[str]` | — | Filter by entity types |
|
|
103
|
+
| `name` | `str` | — | Filter by name |
|
|
104
|
+
| `tags` | `list[int]` | — | Filter by tag IDs |
|
|
105
|
+
| `is_private` | `bool` | — | Filter by privacy |
|
|
106
|
+
| `created_by` | `int` | — | Filter by creator ID |
|
|
107
|
+
| `updated_by` | `int` | — | Filter by updater ID |
|
|
99
108
|
|
|
100
109
|
#### gallery
|
|
101
110
|
|
|
@@ -137,6 +146,9 @@ Delete a gallery image by UUID.
|
|
|
137
146
|
|
|
138
147
|
| Property | Type | Description |
|
|
139
148
|
|----------|------|-------------|
|
|
149
|
+
| `last_entities_meta` | `dict` | Pagination metadata from last `entities()` |
|
|
150
|
+
| `last_entities_links` | `dict` | Pagination links from last `entities()` |
|
|
151
|
+
| `entities_has_next_page` | `bool` | Whether next page exists for `entities()` |
|
|
140
152
|
| `last_search_meta` | `dict` | Pagination metadata from last `search()` |
|
|
141
153
|
| `last_search_links` | `dict` | Pagination links from last `search()` |
|
|
142
154
|
| `last_gallery_meta` | `dict` | Pagination metadata from last `gallery()` |
|
|
@@ -83,6 +83,14 @@ Each list endpoint stores its own pagination state:
|
|
|
83
83
|
| `manager.last_assets_meta` | Metadata from last `list_assets()` |
|
|
84
84
|
| `manager.last_assets_links` | Links from last `list_assets()` |
|
|
85
85
|
|
|
86
|
+
### Entities
|
|
87
|
+
|
|
88
|
+
| Property | Description |
|
|
89
|
+
|----------|-------------|
|
|
90
|
+
| `client.last_entities_meta` | Metadata from last `entities()` |
|
|
91
|
+
| `client.last_entities_links` | Links from last `entities()` |
|
|
92
|
+
| `client.entities_has_next_page` | `True` if next page exists |
|
|
93
|
+
|
|
86
94
|
### Gallery
|
|
87
95
|
|
|
88
96
|
| Property | Description |
|
|
@@ -321,19 +321,29 @@ class KankaClient:
|
|
|
321
321
|
response = self._request("GET", f"entities/{entity_id}")
|
|
322
322
|
return response["data"] # type: ignore[no-any-return]
|
|
323
323
|
|
|
324
|
-
def entities(
|
|
324
|
+
def entities(
|
|
325
|
+
self, page: int = 1, limit: int = 15, **filters
|
|
326
|
+
) -> list[dict[str, Any]]:
|
|
325
327
|
"""Access the /entities endpoint with filters.
|
|
326
328
|
|
|
327
329
|
This endpoint provides a unified way to query entities across all types
|
|
328
330
|
with various filtering options.
|
|
329
331
|
|
|
330
332
|
Args:
|
|
333
|
+
page: Page number (default: 1)
|
|
334
|
+
limit: Number of results per page (default: 15)
|
|
331
335
|
**filters: Filter parameters like types, name, is_private, tags
|
|
332
336
|
|
|
333
337
|
Returns:
|
|
334
338
|
List of entity data
|
|
339
|
+
|
|
340
|
+
Note:
|
|
341
|
+
Pagination information is available after calling entities():
|
|
342
|
+
- client.last_entities_meta: Contains total count, current page, etc.
|
|
343
|
+
- client.last_entities_links: Contains URLs for first, last, prev, next
|
|
344
|
+
- client.entities_has_next_page: True if more pages are available
|
|
335
345
|
"""
|
|
336
|
-
params: dict[str, int | str] = {}
|
|
346
|
+
params: dict[str, int | str] = {"page": page, "limit": limit}
|
|
337
347
|
|
|
338
348
|
# Handle special filters
|
|
339
349
|
if "types" in filters and isinstance(filters["types"], list):
|
|
@@ -355,6 +365,8 @@ class KankaClient:
|
|
|
355
365
|
params[key] = filters[key]
|
|
356
366
|
|
|
357
367
|
response = self._request("GET", "entities", params=params)
|
|
368
|
+
self._last_entities_meta = response.get("meta", {})
|
|
369
|
+
self._last_entities_links = response.get("links", {})
|
|
358
370
|
return response["data"] # type: ignore[no-any-return]
|
|
359
371
|
|
|
360
372
|
def _parse_rate_limit_headers(self, response) -> float | None:
|
|
@@ -692,3 +704,27 @@ class KankaClient:
|
|
|
692
704
|
Dict[str, Any]: Links for pagination including first, last, prev, next URLs
|
|
693
705
|
"""
|
|
694
706
|
return getattr(self, "_last_search_links", {})
|
|
707
|
+
|
|
708
|
+
@property
|
|
709
|
+
def last_entities_meta(self) -> dict[str, Any]:
|
|
710
|
+
"""Get metadata from the last entities() call.
|
|
711
|
+
|
|
712
|
+
Returns:
|
|
713
|
+
Dict[str, Any]: Pagination metadata including current_page, from, to,
|
|
714
|
+
last_page, per_page, total
|
|
715
|
+
"""
|
|
716
|
+
return getattr(self, "_last_entities_meta", {})
|
|
717
|
+
|
|
718
|
+
@property
|
|
719
|
+
def last_entities_links(self) -> dict[str, Any]:
|
|
720
|
+
"""Get pagination links from the last entities() call.
|
|
721
|
+
|
|
722
|
+
Returns:
|
|
723
|
+
Dict[str, Any]: Links for pagination including first, last, prev, next URLs
|
|
724
|
+
"""
|
|
725
|
+
return getattr(self, "_last_entities_links", {})
|
|
726
|
+
|
|
727
|
+
@property
|
|
728
|
+
def entities_has_next_page(self) -> bool:
|
|
729
|
+
"""Check if more pages are available from the last entities() call."""
|
|
730
|
+
return bool(getattr(self, "_last_entities_links", {}).get("next"))
|
|
@@ -151,7 +151,7 @@ class TestKankaClient:
|
|
|
151
151
|
mock_session.request.assert_called_with(
|
|
152
152
|
"GET",
|
|
153
153
|
"https://api.kanka.io/1.0/campaigns/123/entities",
|
|
154
|
-
params={"types": "character,location"},
|
|
154
|
+
params={"page": 1, "limit": 15, "types": "character,location"},
|
|
155
155
|
)
|
|
156
156
|
|
|
157
157
|
assert len(results) == 2
|
|
@@ -181,6 +181,8 @@ class TestKankaClient:
|
|
|
181
181
|
"GET",
|
|
182
182
|
"https://api.kanka.io/1.0/campaigns/123/entities",
|
|
183
183
|
params={
|
|
184
|
+
"page": 1,
|
|
185
|
+
"limit": 15,
|
|
184
186
|
"types": "character",
|
|
185
187
|
"tags": "1,2,3",
|
|
186
188
|
"name": "test",
|
|
@@ -189,6 +191,80 @@ class TestKankaClient:
|
|
|
189
191
|
},
|
|
190
192
|
)
|
|
191
193
|
|
|
194
|
+
@patch("requests.Session")
|
|
195
|
+
def test_entities_pagination(self, mock_session_class):
|
|
196
|
+
"""Test entities endpoint pagination parameters and metadata."""
|
|
197
|
+
mock_session = MagicMock()
|
|
198
|
+
mock_session_class.return_value = mock_session
|
|
199
|
+
|
|
200
|
+
meta = {
|
|
201
|
+
"total": 50,
|
|
202
|
+
"current_page": 2,
|
|
203
|
+
"per_page": 15,
|
|
204
|
+
"last_page": 4,
|
|
205
|
+
"from": 16,
|
|
206
|
+
"to": 30,
|
|
207
|
+
}
|
|
208
|
+
links = {
|
|
209
|
+
"first": "https://api.kanka.io/1.0/campaigns/123/entities?page=1",
|
|
210
|
+
"last": "https://api.kanka.io/1.0/campaigns/123/entities?page=4",
|
|
211
|
+
"prev": "https://api.kanka.io/1.0/campaigns/123/entities?page=1",
|
|
212
|
+
"next": "https://api.kanka.io/1.0/campaigns/123/entities?page=3",
|
|
213
|
+
}
|
|
214
|
+
mock_response = MockResponse(
|
|
215
|
+
create_api_response(
|
|
216
|
+
[{"id": 1, "name": "Test", "type": "character"}],
|
|
217
|
+
meta=meta,
|
|
218
|
+
links=links,
|
|
219
|
+
),
|
|
220
|
+
status_code=200,
|
|
221
|
+
)
|
|
222
|
+
mock_session.request.return_value = mock_response
|
|
223
|
+
|
|
224
|
+
client = KankaClient(token="test_token", campaign_id=123)
|
|
225
|
+
results = client.entities(page=2, limit=15, types=["character"])
|
|
226
|
+
|
|
227
|
+
mock_session.request.assert_called_with(
|
|
228
|
+
"GET",
|
|
229
|
+
"https://api.kanka.io/1.0/campaigns/123/entities",
|
|
230
|
+
params={"page": 2, "limit": 15, "types": "character"},
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
assert len(results) == 1
|
|
234
|
+
assert client.last_entities_meta["total"] == 50
|
|
235
|
+
assert client.last_entities_meta["current_page"] == 2
|
|
236
|
+
assert client.last_entities_links["next"] is not None
|
|
237
|
+
assert client.entities_has_next_page is True
|
|
238
|
+
|
|
239
|
+
@patch("requests.Session")
|
|
240
|
+
def test_entities_no_next_page(self, mock_session_class):
|
|
241
|
+
"""Test entities_has_next_page is False on last page."""
|
|
242
|
+
mock_session = MagicMock()
|
|
243
|
+
mock_session_class.return_value = mock_session
|
|
244
|
+
|
|
245
|
+
mock_response = MockResponse(
|
|
246
|
+
create_api_response([{"id": 1, "name": "Test", "type": "character"}]),
|
|
247
|
+
status_code=200,
|
|
248
|
+
)
|
|
249
|
+
mock_session.request.return_value = mock_response
|
|
250
|
+
|
|
251
|
+
client = KankaClient(token="test_token", campaign_id=123)
|
|
252
|
+
client.entities()
|
|
253
|
+
|
|
254
|
+
assert client.entities_has_next_page is False
|
|
255
|
+
|
|
256
|
+
@patch("requests.Session")
|
|
257
|
+
def test_entities_pagination_defaults(self, mock_session_class):
|
|
258
|
+
"""Test entities pagination properties before any call."""
|
|
259
|
+
mock_session = MagicMock()
|
|
260
|
+
mock_session_class.return_value = mock_session
|
|
261
|
+
|
|
262
|
+
client = KankaClient(token="test_token", campaign_id=123)
|
|
263
|
+
|
|
264
|
+
assert client.last_entities_meta == {}
|
|
265
|
+
assert client.last_entities_links == {}
|
|
266
|
+
assert client.entities_has_next_page is False
|
|
267
|
+
|
|
192
268
|
@patch("requests.Session")
|
|
193
269
|
def test_request_error_handling(self, mock_session_class):
|
|
194
270
|
"""Test error handling in _request method."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_entities_api_integration.py
RENAMED
|
File without changes
|
{python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_entity_assets_integration.py
RENAMED
|
File without changes
|
{python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_entity_images_integration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_kanka-2.4.1 → python_kanka-2.5.0}/tests/integration/test_organisations_integration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|