karakeep-python-api 1.2.3__tar.gz → 1.3.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 (18) hide show
  1. {karakeep_python_api-1.2.3/karakeep_python_api.egg-info → karakeep_python_api-1.3.0}/PKG-INFO +13 -10
  2. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/README.md +12 -9
  3. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/karakeep_python_api/datatypes.py +26 -16
  4. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/karakeep_python_api/karakeep_api.py +156 -31
  5. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/karakeep_python_api/openapi_reference.json +409 -51
  6. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0/karakeep_python_api.egg-info}/PKG-INFO +13 -10
  7. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/setup.py +1 -1
  8. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/tests/test_karakeep_api.py +5 -1
  9. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/LICENSE +0 -0
  10. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/MANIFEST.in +0 -0
  11. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/karakeep_python_api/__init__.py +0 -0
  12. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/karakeep_python_api/__main__.py +0 -0
  13. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/karakeep_python_api.egg-info/SOURCES.txt +0 -0
  14. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/karakeep_python_api.egg-info/dependency_links.txt +0 -0
  15. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/karakeep_python_api.egg-info/entry_points.txt +0 -0
  16. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/karakeep_python_api.egg-info/requires.txt +0 -0
  17. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/karakeep_python_api.egg-info/top_level.txt +0 -0
  18. {karakeep_python_api-1.2.3 → karakeep_python_api-1.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: karakeep_python_api
3
- Version: 1.2.3
3
+ Version: 1.3.0
4
4
  Summary: Community python client for the Karakeep API.
5
5
  Home-page: https://github.com/thiswillbeyourgithub/karakeep_python_api/
6
6
  License: GPLv3
@@ -116,6 +116,7 @@ Methods or CLI commands marked with ❌ should be used with caution as their beh
116
116
  | `get_a_single_asset` | ✅ | ❌ | Tested in PDF asset lifecycle test. |
117
117
  | `get_current_user_info` | ✅ | ❌ | Pytest: Tested indirectly during client init. CLI not directly tested. |
118
118
  | `get_current_user_stats` | ✅ | ✅ | |
119
+ | `update_user` | ❌ | ❌ | |
119
120
 
120
121
  ## Installation
121
122
 
@@ -248,15 +249,17 @@ Community Scripts are a bunch of scripts made to solve specific issues. They are
248
249
 
249
250
  They can be found in the [./community_scripts](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts) folder. Don't hesitate to submit yours, the contribution guidelines are in the community_scripts directory README.md file.
250
251
 
251
- | Community Script | Description | Documentation |
252
- |----------------|--------------------------------------------------------------------------------------------------------------|---------------|
253
- | **Karakeep-Time-Tagger** | Automatically adds time-to-read tags (`0-5m`, `5-10m`, etc.) to bookmarks based on content length analysis. Includes systemd service and timer files for automated periodic execution. | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-time-tagger) |
254
- | **Karakeep-List-To-Tag** | Converts a Karakeep list into tags by adding a specified tag to all bookmarks within that list. | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-list-to-tag) |
255
- | **Omnivore2Karakeep-Highlights** | Imports highlights from Omnivore export data to Karakeep, with intelligent position detection and bookmark matching. Supports dry-run mode for testing. | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/omnivore2karakeep-highlights) |
256
- | **Omnivore2Karakeep-Archived** | (Should not be needed anymore) Fixes the archived status of bookmarks imported from Omnivore by reading export data and updating Karakeep accordingly. | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/omnivore2karakeep-archived) |
257
- | **pocket2karakeep-archived** by [@youenchene](https://github.com/youenchene) | (Should not be needed anymore) Fixes the archived status of bookmarks imported from Pocket by reading export data and updating Karakeep accordingly. | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/pocket2karakeep-archived) |
258
- | **Karakeep-Archive-Before-Date** by [@youenchene](https://github.com/youenchene) | Allow you to archive all not archived post before a given date | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-archive-before-date) |
259
- | **Freshrss-To-Karakeep** | Syncs some links from Freshrss to Karakeep | [`Link`](https://github.com/thiswillbeyourgithub/freshrss_to_karakeep) |
252
+ | Community Script | Description |
253
+ |----------------|--------------------------------------------------------------------------------------------------------------|
254
+ | [Karakeep-Time-Tagger](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-time-tagger) | Automatically adds time-to-read tags (`0-5m`, `5-10m`, etc.) to bookmarks based on content length analysis. Includes systemd service and timer files for automated periodic execution. |
255
+ | [Karakeep-List-To-Tag](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-list-to-tag) | Converts a Karakeep list into tags by adding a specified tag to all bookmarks within that list. |
256
+ | [Omnivore2Karakeep-Highlights](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/omnivore2karakeep-highlights) | Imports highlights from Omnivore export data to Karakeep, with intelligent position detection and bookmark matching. Supports dry-run mode for testing. |
257
+ | [Omnivore2Karakeep-Archived](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/omnivore2karakeep-archived) | (Should not be needed anymore) Fixes the archived status of bookmarks imported from Omnivore by reading export data and updating Karakeep accordingly. |
258
+ | [pocket2karakeep-archived](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/pocket2karakeep-archived) by [@youenchene](https://github.com/youenchene) | (Should not be needed anymore) Fixes the archived status of bookmarks imported from Pocket by reading export data and updating Karakeep accordingly. |
259
+ | [Karakeep-Archive-Before-Date](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-archive-before-date) by [@youenchene](https://github.com/youenchene) | Allow you to archive all not archived post before a given date |
260
+ | [Freshrss-To-Karakeep](https://github.com/thiswillbeyourgithub/freshrss_to_karakeep) | Syncs some links from Freshrss to Karakeep |
261
+ | [Karanki (WIP)](https://github.com/thiswillbeyourgithub/Karanki) | Bidirectional sync between anki notes and highlights |
262
+ | [Karakeep-remove-ai-tags](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-remove-ai-tags) by [@youenchene](https://github.com/youenchene) | Remove all tags attached by AI and not human attached |
260
263
 
261
264
  ## Development
262
265
 
@@ -81,6 +81,7 @@ Methods or CLI commands marked with ❌ should be used with caution as their beh
81
81
  | `get_a_single_asset` | ✅ | ❌ | Tested in PDF asset lifecycle test. |
82
82
  | `get_current_user_info` | ✅ | ❌ | Pytest: Tested indirectly during client init. CLI not directly tested. |
83
83
  | `get_current_user_stats` | ✅ | ✅ | |
84
+ | `update_user` | ❌ | ❌ | |
84
85
 
85
86
  ## Installation
86
87
 
@@ -213,15 +214,17 @@ Community Scripts are a bunch of scripts made to solve specific issues. They are
213
214
 
214
215
  They can be found in the [./community_scripts](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts) folder. Don't hesitate to submit yours, the contribution guidelines are in the community_scripts directory README.md file.
215
216
 
216
- | Community Script | Description | Documentation |
217
- |----------------|--------------------------------------------------------------------------------------------------------------|---------------|
218
- | **Karakeep-Time-Tagger** | Automatically adds time-to-read tags (`0-5m`, `5-10m`, etc.) to bookmarks based on content length analysis. Includes systemd service and timer files for automated periodic execution. | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-time-tagger) |
219
- | **Karakeep-List-To-Tag** | Converts a Karakeep list into tags by adding a specified tag to all bookmarks within that list. | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-list-to-tag) |
220
- | **Omnivore2Karakeep-Highlights** | Imports highlights from Omnivore export data to Karakeep, with intelligent position detection and bookmark matching. Supports dry-run mode for testing. | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/omnivore2karakeep-highlights) |
221
- | **Omnivore2Karakeep-Archived** | (Should not be needed anymore) Fixes the archived status of bookmarks imported from Omnivore by reading export data and updating Karakeep accordingly. | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/omnivore2karakeep-archived) |
222
- | **pocket2karakeep-archived** by [@youenchene](https://github.com/youenchene) | (Should not be needed anymore) Fixes the archived status of bookmarks imported from Pocket by reading export data and updating Karakeep accordingly. | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/pocket2karakeep-archived) |
223
- | **Karakeep-Archive-Before-Date** by [@youenchene](https://github.com/youenchene) | Allow you to archive all not archived post before a given date | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-archive-before-date) |
224
- | **Freshrss-To-Karakeep** | Syncs some links from Freshrss to Karakeep | [`Link`](https://github.com/thiswillbeyourgithub/freshrss_to_karakeep) |
217
+ | Community Script | Description |
218
+ |----------------|--------------------------------------------------------------------------------------------------------------|
219
+ | [Karakeep-Time-Tagger](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-time-tagger) | Automatically adds time-to-read tags (`0-5m`, `5-10m`, etc.) to bookmarks based on content length analysis. Includes systemd service and timer files for automated periodic execution. |
220
+ | [Karakeep-List-To-Tag](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-list-to-tag) | Converts a Karakeep list into tags by adding a specified tag to all bookmarks within that list. |
221
+ | [Omnivore2Karakeep-Highlights](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/omnivore2karakeep-highlights) | Imports highlights from Omnivore export data to Karakeep, with intelligent position detection and bookmark matching. Supports dry-run mode for testing. |
222
+ | [Omnivore2Karakeep-Archived](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/omnivore2karakeep-archived) | (Should not be needed anymore) Fixes the archived status of bookmarks imported from Omnivore by reading export data and updating Karakeep accordingly. |
223
+ | [pocket2karakeep-archived](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/pocket2karakeep-archived) by [@youenchene](https://github.com/youenchene) | (Should not be needed anymore) Fixes the archived status of bookmarks imported from Pocket by reading export data and updating Karakeep accordingly. |
224
+ | [Karakeep-Archive-Before-Date](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-archive-before-date) by [@youenchene](https://github.com/youenchene) | Allow you to archive all not archived post before a given date |
225
+ | [Freshrss-To-Karakeep](https://github.com/thiswillbeyourgithub/freshrss_to_karakeep) | Syncs some links from Freshrss to Karakeep |
226
+ | [Karanki (WIP)](https://github.com/thiswillbeyourgithub/Karanki) | Bidirectional sync between anki notes and highlights |
227
+ | [Karakeep-remove-ai-tags](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-remove-ai-tags) by [@youenchene](https://github.com/youenchene) | Remove all tags attached by AI and not human attached |
225
228
 
226
229
  ## Development
227
230
 
@@ -17,8 +17,8 @@ class StatusTypes(str, Enum):
17
17
 
18
18
 
19
19
  class NumBookmarksByAttachedType(BaseModel):
20
- ai: Optional[float] = None
21
- human: Optional[float] = None
20
+ ai: Optional[int] = None
21
+ human: Optional[int] = None
22
22
 
23
23
 
24
24
  class TagShort(BaseModel):
@@ -30,7 +30,7 @@ class TagShort(BaseModel):
30
30
  class Tag(BaseModel):
31
31
  id: str
32
32
  name: str
33
- numBookmarks: float
33
+ numBookmarks: int
34
34
  numBookmarksByAttachedType: NumBookmarksByAttachedType
35
35
 
36
36
 
@@ -112,6 +112,11 @@ class Bookmark(BaseModel):
112
112
  summarizationStatus: Optional[Literal["success", "failure", "pending"]] = None
113
113
  note: Optional[str] = None
114
114
  summary: Optional[str] = None
115
+ source: Optional[
116
+ Literal[
117
+ "api", "web", "cli", "mobile", "extension", "singlefile", "rss", "import"
118
+ ]
119
+ ] = None
115
120
  tags: List[TagShort]
116
121
  content: Union[
117
122
  ContentTypeLink, ContentTypeText, ContentTypeAsset, ContentTypeUnknown
@@ -121,7 +126,18 @@ class Bookmark(BaseModel):
121
126
 
122
127
  class PaginatedBookmarks(BaseModel):
123
128
  bookmarks: List[Bookmark]
124
- nextCursor: Optional[str]
129
+ nextCursor: Optional[str] = ""
130
+
131
+
132
+ class ListModel(BaseModel):
133
+ id: str
134
+ name: str
135
+ description: Optional[str] = None
136
+ icon: str
137
+ parentId: Optional[str]
138
+ type: Optional[Literal["manual", "smart"]] = "manual"
139
+ query: Optional[str] = None
140
+ public: bool
125
141
 
126
142
 
127
143
  class Highlight(BaseModel):
@@ -136,17 +152,11 @@ class Highlight(BaseModel):
136
152
  createdAt: str
137
153
 
138
154
 
139
- class ListModel(BaseModel):
140
- id: str
141
- name: str
142
- description: Optional[str] = None
143
- icon: str
144
- parentId: Optional[str]
145
- type: Optional[Literal["manual", "smart"]] = "manual"
146
- query: Optional[str] = None
147
- public: bool
148
-
149
-
150
155
  class PaginatedHighlights(BaseModel):
151
156
  highlights: List[Highlight]
152
- nextCursor: Optional[str]
157
+ nextCursor: Optional[str] = ""
158
+
159
+
160
+ class PaginatedTags(BaseModel):
161
+ tags: List[Tag]
162
+ nextCursor: Optional[str] = ""
@@ -85,7 +85,7 @@ class KarakeepAPI:
85
85
  """
86
86
 
87
87
  # Version reflects the client library version, updated by bumpver
88
- VERSION: str = "1.2.3"
88
+ VERSION: str = "1.3.0"
89
89
 
90
90
  def __init__(
91
91
  self,
@@ -757,6 +757,20 @@ class KarakeepAPI:
757
757
  note: Optional[str] = None,
758
758
  summary: Optional[str] = None,
759
759
  createdAt: Optional[str] = None, # ISO 8601 format string
760
+ crawlPriority: Optional[Literal["low", "normal"]] = None,
761
+ importSessionId: Optional[str] = None,
762
+ source: Optional[
763
+ Literal[
764
+ "api",
765
+ "web",
766
+ "cli",
767
+ "mobile",
768
+ "extension",
769
+ "singlefile",
770
+ "rss",
771
+ "import",
772
+ ]
773
+ ] = None,
760
774
  # Link specific
761
775
  url: Optional[str] = None,
762
776
  precrawledArchiveId: Optional[str] = None,
@@ -781,6 +795,9 @@ class KarakeepAPI:
781
795
  note: Optional note content for the bookmark.
782
796
  summary: Optional summary content for the bookmark.
783
797
  createdAt: Optional creation timestamp override (ISO 8601 format string).
798
+ crawlPriority: Optional either 'low' or 'normal'.
799
+ importSessionId: Optional import session ID for tracking imported bookmarks.
800
+ source: Optional source of the bookmark ("api", "web", "cli", "mobile", "extension", "singlefile", "rss", "import").
784
801
 
785
802
  --- Link Type Specific ---
786
803
  url: The URL for the link bookmark. Required if type='link'.
@@ -797,7 +814,9 @@ class KarakeepAPI:
797
814
  sourceUrl: Optional source URL where the asset originated.
798
815
 
799
816
  Returns:
800
- datatypes.Bookmark: The created bookmark.
817
+ datatypes.Bookmark: The bookmark object.
818
+ Returns with status 200 if the bookmark already exists,
819
+ or status 201 if the bookmark was newly created.
801
820
  If response validation is disabled, returns the raw API response (dict/list).
802
821
 
803
822
  Raises:
@@ -821,6 +840,12 @@ class KarakeepAPI:
821
840
  request_body["summary"] = summary
822
841
  if createdAt is not None:
823
842
  request_body["createdAt"] = createdAt
843
+ if crawlPriority is not None:
844
+ request_body["crawlPriority"] = crawlPriority
845
+ if importSessionId is not None:
846
+ request_body["importSessionId"] = importSessionId
847
+ if source is not None:
848
+ request_body["source"] = source
824
849
 
825
850
  # Add type-specific fields and perform validation
826
851
  if type == "link":
@@ -1165,6 +1190,54 @@ class KarakeepAPI:
1165
1190
  # No Pydantic validation applied here as the spec defines a simple dict response
1166
1191
  return response_data
1167
1192
 
1193
+ @optional_typecheck
1194
+ def get_lists_of_a_bookmark(
1195
+ self, bookmark_id: str
1196
+ ) -> Union[List[datatypes.ListModel], Dict[str, Any], List[Any]]:
1197
+ """
1198
+ Get all lists associated with a specific bookmark. Corresponds to GET /bookmarks/{bookmarkId}/lists.
1199
+
1200
+ Args:
1201
+ bookmark_id: The ID (string) of the bookmark.
1202
+
1203
+ Returns:
1204
+ List[datatypes.ListModel]: A list of list objects associated with the bookmark.
1205
+ If response validation is disabled, returns the raw API response (dict/list).
1206
+
1207
+ Raises:
1208
+ APIError: If the API request fails (e.g., 404 bookmark not found).
1209
+ pydantic.ValidationError: If response validation fails (and is not disabled).
1210
+ """
1211
+ endpoint = f"bookmarks/{bookmark_id}/lists"
1212
+ response_data = self._call("GET", endpoint)
1213
+
1214
+ if self.disable_response_validation:
1215
+ logger.debug("Skipping response validation as requested.")
1216
+ # Return raw data, which might be {"lists": [...]} or something else
1217
+ return response_data
1218
+ else:
1219
+ # Response schema is {"lists": [ListModel]}, extract the list and validate
1220
+ if (
1221
+ isinstance(response_data, dict)
1222
+ and "lists" in response_data
1223
+ and isinstance(response_data["lists"], list)
1224
+ ):
1225
+ try:
1226
+ return [
1227
+ datatypes.ListModel.model_validate(lst)
1228
+ for lst in response_data["lists"]
1229
+ ]
1230
+ except (
1231
+ Exception
1232
+ ) as e: # Catch validation errors during list comprehension
1233
+ logger.error(f"Validation failed for one or more lists: {e}")
1234
+ raise # Re-raise the validation error
1235
+ else:
1236
+ # Raise error if format is unexpected and validation is enabled
1237
+ raise APIError(
1238
+ f"Unexpected response format for get_lists_of_a_bookmark when validation is enabled: {response_data}"
1239
+ )
1240
+
1168
1241
  @optional_typecheck
1169
1242
  def get_highlights_of_a_bookmark(
1170
1243
  self, bookmark_id: str
@@ -1361,7 +1434,7 @@ class KarakeepAPI:
1361
1434
  Create a new list (manual or smart). Corresponds to POST /lists.
1362
1435
 
1363
1436
  Args:
1364
- name: The name of the list (required, max 40 characters).
1437
+ name: The name of the list (required, max 100 characters).
1365
1438
  icon: The icon for the list (required).
1366
1439
  description: Optional description for the list (max 100 characters).
1367
1440
  parent_id: Optional parent list ID for nested lists.
@@ -1470,8 +1543,8 @@ class KarakeepAPI:
1470
1543
 
1471
1544
  Args:
1472
1545
  list_id: The ID (string) of the list to update.
1473
- name: Optional new name for the list (1-40 characters).
1474
- description: Optional new description for the list (0-100 characters, can be None to clear).
1546
+ name: Optional new name for the list (1-100 characters).
1547
+ description: Optional new description for the list (0-500 characters, can be None to clear).
1475
1548
  icon: Optional new icon for the list.
1476
1549
  parent_id: Optional new parent list ID (can be None to remove parent relationship).
1477
1550
  query: Optional new query string for smart lists (minimum 1 character).
@@ -1597,46 +1670,47 @@ class KarakeepAPI:
1597
1670
  return None # Explicitly return None for 204
1598
1671
 
1599
1672
  @optional_typecheck
1600
- def get_all_tags(self) -> Union[List[datatypes.Tag], Dict[str, Any], List[Any]]:
1673
+ def get_all_tags(
1674
+ self,
1675
+ name_contains: Optional[str] = None,
1676
+ sort: Optional[Literal["name", "usage", "relevance"]] = None,
1677
+ attached_by: Optional[Literal["ai", "human", "none"]] = None,
1678
+ cursor: Optional[str] = None,
1679
+ limit: Optional[int] = None,
1680
+ ) -> Union[datatypes.PaginatedTags, Dict[str, Any], List[Any]]:
1601
1681
  """
1602
1682
  Get all tags for the current user. Corresponds to GET /tags.
1603
1683
 
1684
+ Args:
1685
+ name_contains: Filter tags by name substring (optional).
1686
+ sort: Sort order for tags ("name", "usage", "relevance"). Default from API is "usage" (optional).
1687
+ attached_by: Filter tags by how they were attached ("ai", "human", "none") (optional).
1688
+ cursor: Pagination cursor for the next page (optional).
1689
+ limit: Maximum number of tags to return (optional).
1690
+
1604
1691
  Returns:
1605
- List[datatypes.Tag]: A list of tag objects, including bookmark counts.
1692
+ datatypes.PaginatedTags: Paginated list of tags with nextCursor for pagination.
1606
1693
  If response validation is disabled, returns the raw API response (dict/list).
1607
1694
 
1608
1695
  Raises:
1609
1696
  APIError: If the API request fails.
1610
1697
  pydantic.ValidationError: If response validation fails (and is not disabled).
1611
1698
  """
1612
- response_data = self._call("GET", "tags")
1699
+ params = {
1700
+ "nameContains": name_contains,
1701
+ "sort": sort,
1702
+ "attachedBy": attached_by,
1703
+ "cursor": cursor,
1704
+ "limit": limit,
1705
+ }
1706
+ response_data = self._call("GET", "tags", params=params)
1613
1707
 
1614
1708
  if self.disable_response_validation:
1615
1709
  logger.debug("Skipping response validation as requested.")
1616
- # Return raw data, which might be {"tags": [...]} or something else
1617
1710
  return response_data
1618
1711
  else:
1619
- # Response schema is {"tags": [Tag]}, extract the list and validate
1620
- if (
1621
- isinstance(response_data, dict)
1622
- and "tags" in response_data
1623
- and isinstance(response_data["tags"], list)
1624
- ):
1625
- try:
1626
- return [
1627
- datatypes.Tag.model_validate(tag)
1628
- for tag in response_data["tags"]
1629
- ]
1630
- except (
1631
- Exception
1632
- ) as e: # Catch validation errors during list comprehension
1633
- logger.error(f"Validation failed for one or more tags: {e}")
1634
- raise # Re-raise the validation error
1635
- else:
1636
- # Raise error if format is unexpected and validation is enabled
1637
- raise APIError(
1638
- f"Unexpected response format for get_all_tags when validation is enabled: {response_data}"
1639
- )
1712
+ # Response should match PaginatedTags schema
1713
+ return datatypes.PaginatedTags.model_validate(response_data)
1640
1714
 
1641
1715
  @optional_typecheck
1642
1716
  def create_a_new_tag(self, name: str) -> Dict[str, Any]:
@@ -1966,7 +2040,7 @@ class KarakeepAPI:
1966
2040
  Get information about the current authenticated user. Corresponds to GET /users/me.
1967
2041
 
1968
2042
  Returns:
1969
- dict: A dictionary containing user information ('id', 'name', 'email').
2043
+ dict: A dictionary containing user information ('id', 'name', 'email', 'localUser').
1970
2044
  Validation is not performed on this response type by default.
1971
2045
 
1972
2046
  Raises:
@@ -1992,6 +2066,57 @@ class KarakeepAPI:
1992
2066
  # No Pydantic validation applied here as the spec defines a simple dict response
1993
2067
  return response_data
1994
2068
 
2069
+ @optional_typecheck
2070
+ def update_user(
2071
+ self,
2072
+ user_id: str,
2073
+ role: Optional[Literal["user", "admin"]] = None,
2074
+ bookmark_quota: Optional[int] = None,
2075
+ storage_quota: Optional[int] = None,
2076
+ browser_crawling_enabled: Optional[bool] = None,
2077
+ ) -> Dict[str, Any]:
2078
+ """
2079
+ Update a user's role, bookmark quota, or storage quota. Admin access required.
2080
+ Corresponds to PUT /admin/users/{userId}.
2081
+
2082
+ Args:
2083
+ user_id: The ID of the user to update.
2084
+ role: Optional new role for the user ("user", "admin").
2085
+ bookmark_quota: Optional new bookmark quota (minimum 0, can be None for unlimited).
2086
+ storage_quota: Optional new storage quota in bytes (minimum 0, can be None for unlimited).
2087
+ browser_crawling_enabled: Optional boolean to enable/disable browser crawling for the user.
2088
+
2089
+ Returns:
2090
+ dict: A dictionary containing success status.
2091
+ Example: `{"success": True}`
2092
+ Validation is not performed on this response type by default.
2093
+
2094
+ Raises:
2095
+ ValueError: If no fields are provided to update.
2096
+ APIError: If the API request fails (e.g., 400 bad request, 401 unauthorized, 403 forbidden, 404 user not found).
2097
+ """
2098
+ # Construct update_data from provided arguments, excluding None values
2099
+ update_data = {}
2100
+ if role is not None:
2101
+ update_data["role"] = role
2102
+ if bookmark_quota is not None:
2103
+ update_data["bookmarkQuota"] = bookmark_quota
2104
+ if storage_quota is not None:
2105
+ update_data["storageQuota"] = storage_quota
2106
+ if browser_crawling_enabled is not None:
2107
+ update_data["browserCrawlingEnabled"] = browser_crawling_enabled
2108
+
2109
+ # Ensure at least one field is being updated
2110
+ if not update_data:
2111
+ raise ValueError("At least one field must be provided to update.")
2112
+
2113
+ endpoint = f"admin/users/{user_id}"
2114
+ response_data = self._call("PUT", endpoint, data=update_data)
2115
+
2116
+ # Response schema is a simple dict with success field, return as dict
2117
+ # No Pydantic validation applied here as the spec defines a simple dict response
2118
+ return response_data
2119
+
1995
2120
  @optional_typecheck
1996
2121
  def upload_a_new_asset(
1997
2122
  self, file: str
@@ -94,6 +94,20 @@
94
94
  "type": "string",
95
95
  "nullable": true
96
96
  },
97
+ "source": {
98
+ "type": "string",
99
+ "nullable": true,
100
+ "enum": [
101
+ "api",
102
+ "web",
103
+ "cli",
104
+ "mobile",
105
+ "extension",
106
+ "singlefile",
107
+ "rss",
108
+ "import"
109
+ ]
110
+ },
97
111
  "tags": {
98
112
  "type": "array",
99
113
  "items": {
@@ -349,6 +363,50 @@
349
363
  "Cursor": {
350
364
  "type": "string"
351
365
  },
366
+ "List": {
367
+ "type": "object",
368
+ "properties": {
369
+ "id": {
370
+ "type": "string"
371
+ },
372
+ "name": {
373
+ "type": "string"
374
+ },
375
+ "description": {
376
+ "type": "string",
377
+ "nullable": true
378
+ },
379
+ "icon": {
380
+ "type": "string"
381
+ },
382
+ "parentId": {
383
+ "type": "string",
384
+ "nullable": true
385
+ },
386
+ "type": {
387
+ "type": "string",
388
+ "enum": [
389
+ "manual",
390
+ "smart"
391
+ ],
392
+ "default": "manual"
393
+ },
394
+ "query": {
395
+ "type": "string",
396
+ "nullable": true
397
+ },
398
+ "public": {
399
+ "type": "boolean"
400
+ }
401
+ },
402
+ "required": [
403
+ "id",
404
+ "name",
405
+ "icon",
406
+ "parentId",
407
+ "public"
408
+ ]
409
+ },
352
410
  "Highlight": {
353
411
  "type": "object",
354
412
  "properties": {
@@ -400,50 +458,6 @@
400
458
  "createdAt"
401
459
  ]
402
460
  },
403
- "List": {
404
- "type": "object",
405
- "properties": {
406
- "id": {
407
- "type": "string"
408
- },
409
- "name": {
410
- "type": "string"
411
- },
412
- "description": {
413
- "type": "string",
414
- "nullable": true
415
- },
416
- "icon": {
417
- "type": "string"
418
- },
419
- "parentId": {
420
- "type": "string",
421
- "nullable": true
422
- },
423
- "type": {
424
- "type": "string",
425
- "enum": [
426
- "manual",
427
- "smart"
428
- ],
429
- "default": "manual"
430
- },
431
- "query": {
432
- "type": "string",
433
- "nullable": true
434
- },
435
- "public": {
436
- "type": "boolean"
437
- }
438
- },
439
- "required": [
440
- "id",
441
- "name",
442
- "icon",
443
- "parentId",
444
- "public"
445
- ]
446
- },
447
461
  "Tag": {
448
462
  "type": "object",
449
463
  "properties": {
@@ -686,6 +700,29 @@
686
700
  "createdAt": {
687
701
  "type": "string",
688
702
  "nullable": true
703
+ },
704
+ "crawlPriority": {
705
+ "type": "string",
706
+ "enum": [
707
+ "low",
708
+ "normal"
709
+ ]
710
+ },
711
+ "importSessionId": {
712
+ "type": "string"
713
+ },
714
+ "source": {
715
+ "type": "string",
716
+ "enum": [
717
+ "api",
718
+ "web",
719
+ "cli",
720
+ "mobile",
721
+ "extension",
722
+ "singlefile",
723
+ "rss",
724
+ "import"
725
+ ]
689
726
  }
690
727
  }
691
728
  },
@@ -774,8 +811,18 @@
774
811
  }
775
812
  },
776
813
  "responses": {
814
+ "200": {
815
+ "description": "The bookmark already exists",
816
+ "content": {
817
+ "application/json": {
818
+ "schema": {
819
+ "$ref": "#/components/schemas/Bookmark"
820
+ }
821
+ }
822
+ }
823
+ },
777
824
  "201": {
778
- "description": "The created bookmark",
825
+ "description": "The bookmark got created",
779
826
  "content": {
780
827
  "application/json": {
781
828
  "schema": {
@@ -1128,6 +1175,20 @@
1128
1175
  "summary": {
1129
1176
  "type": "string",
1130
1177
  "nullable": true
1178
+ },
1179
+ "source": {
1180
+ "type": "string",
1181
+ "nullable": true,
1182
+ "enum": [
1183
+ "api",
1184
+ "web",
1185
+ "cli",
1186
+ "mobile",
1187
+ "extension",
1188
+ "singlefile",
1189
+ "rss",
1190
+ "import"
1191
+ ]
1131
1192
  }
1132
1193
  },
1133
1194
  "required": [
@@ -1238,6 +1299,20 @@
1238
1299
  "summary": {
1239
1300
  "type": "string",
1240
1301
  "nullable": true
1302
+ },
1303
+ "source": {
1304
+ "type": "string",
1305
+ "nullable": true,
1306
+ "enum": [
1307
+ "api",
1308
+ "web",
1309
+ "cli",
1310
+ "mobile",
1311
+ "extension",
1312
+ "singlefile",
1313
+ "rss",
1314
+ "import"
1315
+ ]
1241
1316
  }
1242
1317
  },
1243
1318
  "required": [
@@ -1462,6 +1537,70 @@
1462
1537
  }
1463
1538
  }
1464
1539
  },
1540
+ "/bookmarks/{bookmarkId}/lists": {
1541
+ "get": {
1542
+ "description": "Get lists of a bookmark",
1543
+ "summary": "Get lists of a bookmark",
1544
+ "tags": [
1545
+ "Bookmarks"
1546
+ ],
1547
+ "security": [
1548
+ {
1549
+ "bearerAuth": []
1550
+ }
1551
+ ],
1552
+ "parameters": [
1553
+ {
1554
+ "$ref": "#/components/parameters/BookmarkId"
1555
+ }
1556
+ ],
1557
+ "responses": {
1558
+ "200": {
1559
+ "description": "The list of highlights",
1560
+ "content": {
1561
+ "application/json": {
1562
+ "schema": {
1563
+ "type": "object",
1564
+ "properties": {
1565
+ "lists": {
1566
+ "type": "array",
1567
+ "items": {
1568
+ "$ref": "#/components/schemas/List"
1569
+ }
1570
+ }
1571
+ },
1572
+ "required": [
1573
+ "lists"
1574
+ ]
1575
+ }
1576
+ }
1577
+ }
1578
+ },
1579
+ "404": {
1580
+ "description": "Bookmark not found",
1581
+ "content": {
1582
+ "application/json": {
1583
+ "schema": {
1584
+ "type": "object",
1585
+ "properties": {
1586
+ "code": {
1587
+ "type": "string"
1588
+ },
1589
+ "message": {
1590
+ "type": "string"
1591
+ }
1592
+ },
1593
+ "required": [
1594
+ "code",
1595
+ "message"
1596
+ ]
1597
+ }
1598
+ }
1599
+ }
1600
+ }
1601
+ }
1602
+ }
1603
+ },
1465
1604
  "/bookmarks/{bookmarkId}/highlights": {
1466
1605
  "get": {
1467
1606
  "description": "Get highlights of a bookmark",
@@ -1806,12 +1945,12 @@
1806
1945
  "name": {
1807
1946
  "type": "string",
1808
1947
  "minLength": 1,
1809
- "maxLength": 40
1948
+ "maxLength": 100
1810
1949
  },
1811
1950
  "description": {
1812
1951
  "type": "string",
1813
1952
  "minLength": 0,
1814
- "maxLength": 100
1953
+ "maxLength": 500
1815
1954
  },
1816
1955
  "icon": {
1817
1956
  "type": "string"
@@ -1999,13 +2138,13 @@
1999
2138
  "name": {
2000
2139
  "type": "string",
2001
2140
  "minLength": 1,
2002
- "maxLength": 40
2141
+ "maxLength": 100
2003
2142
  },
2004
2143
  "description": {
2005
2144
  "type": "string",
2006
2145
  "nullable": true,
2007
2146
  "minLength": 0,
2008
- "maxLength": 100
2147
+ "maxLength": 500
2009
2148
  },
2010
2149
  "icon": {
2011
2150
  "type": "string"
@@ -2285,6 +2424,60 @@
2285
2424
  "bearerAuth": []
2286
2425
  }
2287
2426
  ],
2427
+ "parameters": [
2428
+ {
2429
+ "schema": {
2430
+ "type": "string"
2431
+ },
2432
+ "required": false,
2433
+ "name": "nameContains",
2434
+ "in": "query"
2435
+ },
2436
+ {
2437
+ "schema": {
2438
+ "type": "string",
2439
+ "enum": [
2440
+ "name",
2441
+ "usage",
2442
+ "relevance"
2443
+ ],
2444
+ "default": "usage"
2445
+ },
2446
+ "required": false,
2447
+ "name": "sort",
2448
+ "in": "query"
2449
+ },
2450
+ {
2451
+ "schema": {
2452
+ "type": "string",
2453
+ "enum": [
2454
+ "ai",
2455
+ "human",
2456
+ "none"
2457
+ ]
2458
+ },
2459
+ "required": false,
2460
+ "name": "attachedBy",
2461
+ "in": "query"
2462
+ },
2463
+ {
2464
+ "schema": {
2465
+ "type": "string"
2466
+ },
2467
+ "required": false,
2468
+ "name": "cursor",
2469
+ "in": "query"
2470
+ },
2471
+ {
2472
+ "schema": {
2473
+ "type": "number",
2474
+ "nullable": true
2475
+ },
2476
+ "required": false,
2477
+ "name": "limit",
2478
+ "in": "query"
2479
+ }
2480
+ ],
2288
2481
  "responses": {
2289
2482
  "200": {
2290
2483
  "description": "Object with all tags data.",
@@ -2298,10 +2491,15 @@
2298
2491
  "items": {
2299
2492
  "$ref": "#/components/schemas/Tag"
2300
2493
  }
2494
+ },
2495
+ "nextCursor": {
2496
+ "type": "string",
2497
+ "nullable": true
2301
2498
  }
2302
2499
  },
2303
2500
  "required": [
2304
- "tags"
2501
+ "tags",
2502
+ "nextCursor"
2305
2503
  ]
2306
2504
  }
2307
2505
  }
@@ -2996,10 +3194,14 @@
2996
3194
  "email": {
2997
3195
  "type": "string",
2998
3196
  "nullable": true
3197
+ },
3198
+ "localUser": {
3199
+ "type": "boolean"
2999
3200
  }
3000
3201
  },
3001
3202
  "required": [
3002
- "id"
3203
+ "id",
3204
+ "localUser"
3003
3205
  ]
3004
3206
  }
3005
3207
  }
@@ -3274,6 +3476,162 @@
3274
3476
  }
3275
3477
  }
3276
3478
  }
3479
+ },
3480
+ "/admin/users/{userId}": {
3481
+ "put": {
3482
+ "description": "Update a user's role, bookmark quota, or storage quota. Admin access required.",
3483
+ "summary": "Update user",
3484
+ "tags": [
3485
+ "Admin"
3486
+ ],
3487
+ "security": [
3488
+ {
3489
+ "bearerAuth": []
3490
+ }
3491
+ ],
3492
+ "parameters": [
3493
+ {
3494
+ "schema": {
3495
+ "type": "string",
3496
+ "description": "The ID of the user to update",
3497
+ "example": "user_123"
3498
+ },
3499
+ "required": true,
3500
+ "name": "userId",
3501
+ "in": "path"
3502
+ }
3503
+ ],
3504
+ "requestBody": {
3505
+ "content": {
3506
+ "application/json": {
3507
+ "schema": {
3508
+ "type": "object",
3509
+ "properties": {
3510
+ "role": {
3511
+ "type": "string",
3512
+ "enum": [
3513
+ "user",
3514
+ "admin"
3515
+ ]
3516
+ },
3517
+ "bookmarkQuota": {
3518
+ "type": "integer",
3519
+ "nullable": true,
3520
+ "minimum": 0
3521
+ },
3522
+ "storageQuota": {
3523
+ "type": "integer",
3524
+ "nullable": true,
3525
+ "minimum": 0
3526
+ },
3527
+ "browserCrawlingEnabled": {
3528
+ "type": "boolean",
3529
+ "nullable": true
3530
+ }
3531
+ },
3532
+ "description": "User update data",
3533
+ "example": {
3534
+ "role": "admin",
3535
+ "bookmarkQuota": 1000,
3536
+ "storageQuota": 5000000000
3537
+ }
3538
+ }
3539
+ }
3540
+ }
3541
+ },
3542
+ "responses": {
3543
+ "200": {
3544
+ "description": "User updated successfully",
3545
+ "content": {
3546
+ "application/json": {
3547
+ "schema": {
3548
+ "type": "object",
3549
+ "properties": {
3550
+ "success": {
3551
+ "type": "boolean"
3552
+ }
3553
+ },
3554
+ "required": [
3555
+ "success"
3556
+ ]
3557
+ }
3558
+ }
3559
+ }
3560
+ },
3561
+ "400": {
3562
+ "description": "Bad request - Invalid input data or cannot update own user",
3563
+ "content": {
3564
+ "application/json": {
3565
+ "schema": {
3566
+ "type": "object",
3567
+ "properties": {
3568
+ "error": {
3569
+ "type": "string"
3570
+ }
3571
+ },
3572
+ "required": [
3573
+ "error"
3574
+ ]
3575
+ }
3576
+ }
3577
+ }
3578
+ },
3579
+ "401": {
3580
+ "description": "Unauthorized - Authentication required",
3581
+ "content": {
3582
+ "application/json": {
3583
+ "schema": {
3584
+ "type": "object",
3585
+ "properties": {
3586
+ "error": {
3587
+ "type": "string"
3588
+ }
3589
+ },
3590
+ "required": [
3591
+ "error"
3592
+ ]
3593
+ }
3594
+ }
3595
+ }
3596
+ },
3597
+ "403": {
3598
+ "description": "Forbidden - Admin access required",
3599
+ "content": {
3600
+ "application/json": {
3601
+ "schema": {
3602
+ "type": "object",
3603
+ "properties": {
3604
+ "error": {
3605
+ "type": "string"
3606
+ }
3607
+ },
3608
+ "required": [
3609
+ "error"
3610
+ ]
3611
+ }
3612
+ }
3613
+ }
3614
+ },
3615
+ "404": {
3616
+ "description": "User not found",
3617
+ "content": {
3618
+ "application/json": {
3619
+ "schema": {
3620
+ "type": "object",
3621
+ "properties": {
3622
+ "error": {
3623
+ "type": "string"
3624
+ }
3625
+ },
3626
+ "required": [
3627
+ "error"
3628
+ ]
3629
+ }
3630
+ }
3631
+ }
3632
+ }
3633
+ }
3634
+ }
3277
3635
  }
3278
3636
  }
3279
3637
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: karakeep_python_api
3
- Version: 1.2.3
3
+ Version: 1.3.0
4
4
  Summary: Community python client for the Karakeep API.
5
5
  Home-page: https://github.com/thiswillbeyourgithub/karakeep_python_api/
6
6
  License: GPLv3
@@ -116,6 +116,7 @@ Methods or CLI commands marked with ❌ should be used with caution as their beh
116
116
  | `get_a_single_asset` | ✅ | ❌ | Tested in PDF asset lifecycle test. |
117
117
  | `get_current_user_info` | ✅ | ❌ | Pytest: Tested indirectly during client init. CLI not directly tested. |
118
118
  | `get_current_user_stats` | ✅ | ✅ | |
119
+ | `update_user` | ❌ | ❌ | |
119
120
 
120
121
  ## Installation
121
122
 
@@ -248,15 +249,17 @@ Community Scripts are a bunch of scripts made to solve specific issues. They are
248
249
 
249
250
  They can be found in the [./community_scripts](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts) folder. Don't hesitate to submit yours, the contribution guidelines are in the community_scripts directory README.md file.
250
251
 
251
- | Community Script | Description | Documentation |
252
- |----------------|--------------------------------------------------------------------------------------------------------------|---------------|
253
- | **Karakeep-Time-Tagger** | Automatically adds time-to-read tags (`0-5m`, `5-10m`, etc.) to bookmarks based on content length analysis. Includes systemd service and timer files for automated periodic execution. | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-time-tagger) |
254
- | **Karakeep-List-To-Tag** | Converts a Karakeep list into tags by adding a specified tag to all bookmarks within that list. | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-list-to-tag) |
255
- | **Omnivore2Karakeep-Highlights** | Imports highlights from Omnivore export data to Karakeep, with intelligent position detection and bookmark matching. Supports dry-run mode for testing. | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/omnivore2karakeep-highlights) |
256
- | **Omnivore2Karakeep-Archived** | (Should not be needed anymore) Fixes the archived status of bookmarks imported from Omnivore by reading export data and updating Karakeep accordingly. | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/omnivore2karakeep-archived) |
257
- | **pocket2karakeep-archived** by [@youenchene](https://github.com/youenchene) | (Should not be needed anymore) Fixes the archived status of bookmarks imported from Pocket by reading export data and updating Karakeep accordingly. | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/pocket2karakeep-archived) |
258
- | **Karakeep-Archive-Before-Date** by [@youenchene](https://github.com/youenchene) | Allow you to archive all not archived post before a given date | [`Link`](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-archive-before-date) |
259
- | **Freshrss-To-Karakeep** | Syncs some links from Freshrss to Karakeep | [`Link`](https://github.com/thiswillbeyourgithub/freshrss_to_karakeep) |
252
+ | Community Script | Description |
253
+ |----------------|--------------------------------------------------------------------------------------------------------------|
254
+ | [Karakeep-Time-Tagger](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-time-tagger) | Automatically adds time-to-read tags (`0-5m`, `5-10m`, etc.) to bookmarks based on content length analysis. Includes systemd service and timer files for automated periodic execution. |
255
+ | [Karakeep-List-To-Tag](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-list-to-tag) | Converts a Karakeep list into tags by adding a specified tag to all bookmarks within that list. |
256
+ | [Omnivore2Karakeep-Highlights](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/omnivore2karakeep-highlights) | Imports highlights from Omnivore export data to Karakeep, with intelligent position detection and bookmark matching. Supports dry-run mode for testing. |
257
+ | [Omnivore2Karakeep-Archived](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/omnivore2karakeep-archived) | (Should not be needed anymore) Fixes the archived status of bookmarks imported from Omnivore by reading export data and updating Karakeep accordingly. |
258
+ | [pocket2karakeep-archived](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/pocket2karakeep-archived) by [@youenchene](https://github.com/youenchene) | (Should not be needed anymore) Fixes the archived status of bookmarks imported from Pocket by reading export data and updating Karakeep accordingly. |
259
+ | [Karakeep-Archive-Before-Date](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-archive-before-date) by [@youenchene](https://github.com/youenchene) | Allow you to archive all not archived post before a given date |
260
+ | [Freshrss-To-Karakeep](https://github.com/thiswillbeyourgithub/freshrss_to_karakeep) | Syncs some links from Freshrss to Karakeep |
261
+ | [Karanki (WIP)](https://github.com/thiswillbeyourgithub/Karanki) | Bidirectional sync between anki notes and highlights |
262
+ | [Karakeep-remove-ai-tags](https://github.com/thiswillbeyourgithub/karakeep_python_api/tree/main/community_scripts/karakeep-remove-ai-tags) by [@youenchene](https://github.com/youenchene) | Remove all tags attached by AI and not human attached |
260
263
 
261
264
  ## Development
262
265
 
@@ -7,7 +7,7 @@ with open("README.md", "r") as readme:
7
7
 
8
8
  setup(
9
9
  name="karakeep_python_api",
10
- version="1.2.3",
10
+ version="1.3.0",
11
11
  description="Community python client for the Karakeep API.", # Simplified description
12
12
  long_description=long_description,
13
13
  long_description_content_type="text/markdown",
@@ -118,7 +118,11 @@ def test_get_all_tags(karakeep_client: KarakeepAPI):
118
118
  """Test retrieving all tags."""
119
119
  try:
120
120
  tags = karakeep_client.get_all_tags()
121
- assert isinstance(tags, list), "Response should be a list"
121
+ assert isinstance(
122
+ tags, datatypes.PaginatedTags
123
+ ), "Response should be of type PaginatedTags"
124
+ tags = tags.tags
125
+ assert isinstance(tags, list), "tags var should be of type list at this point"
122
126
  if tags: # Only check elements if the list is not empty
123
127
  assert all(
124
128
  isinstance(item, datatypes.Tag) for item in tags