karakeep-python-api 0.1.7__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.
- {karakeep_python_api-0.1.7/karakeep_python_api.egg-info → karakeep_python_api-0.2.0}/PKG-INFO +4 -3
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/README.md +3 -2
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/karakeep_python_api/__main__.py +130 -65
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/karakeep_python_api/datatypes.py +42 -41
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/karakeep_python_api/karakeep_api.py +251 -83
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/karakeep_python_api/openapi_reference.json +157 -7
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0/karakeep_python_api.egg-info}/PKG-INFO +4 -3
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/setup.py +1 -1
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/tests/test_karakeep_api.py +10 -6
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/LICENSE +0 -0
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/MANIFEST.in +0 -0
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/karakeep_python_api/__init__.py +0 -0
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/karakeep_python_api.egg-info/SOURCES.txt +0 -0
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/karakeep_python_api.egg-info/dependency_links.txt +0 -0
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/karakeep_python_api.egg-info/entry_points.txt +0 -0
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/karakeep_python_api.egg-info/requires.txt +0 -0
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/karakeep_python_api.egg-info/top_level.txt +0 -0
- {karakeep_python_api-0.1.7 → karakeep_python_api-0.2.0}/setup.cfg +0 -0
{karakeep_python_api-0.1.7/karakeep_python_api.egg-info → karakeep_python_api-0.2.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: karakeep_python_api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.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
|
|
@@ -97,14 +97,15 @@ Methods or CLI commands marked with ❌ should be used with caution as their beh
|
|
|
97
97
|
| `get_a_single_list` | ✅ | ❌ | |
|
|
98
98
|
| `delete_a_list` | ✅ | ❌ | |
|
|
99
99
|
| `update_a_list` | ❌ | ❌ | |
|
|
100
|
-
| `
|
|
100
|
+
| `get_bookmarks_in_the_list` | ❌ | ❌ | |
|
|
101
101
|
| `add_a_bookmark_to_a_list` | ❌ | ❌ | |
|
|
102
102
|
| `remove_a_bookmark_from_a_list` | ❌ | ❌ | |
|
|
103
103
|
| `get_all_tags` | ✅ | ✅ | |
|
|
104
|
+
| `create_a_new_tag` | ❌ | ❌ | |
|
|
104
105
|
| `get_a_single_tag` | ✅ | ❌ | |
|
|
105
106
|
| `delete_a_tag` | ✅ | ❌ | |
|
|
106
107
|
| `update_a_tag` | ✅ | ❌ | No output validation due to [server bug](https://github.com/karakeep-app/karakeep/issues/1365). |
|
|
107
|
-
| `
|
|
108
|
+
| `get_bookmarks_with_the_tag` | ❌ | ❌ | |
|
|
108
109
|
| `get_all_highlights` | ✅ | ✅ | Tested with pagination. |
|
|
109
110
|
| `create_a_new_highlight` | ❌ | ❌ | |
|
|
110
111
|
| `get_a_single_highlight` | ❌ | ❌ | |
|
|
@@ -62,14 +62,15 @@ Methods or CLI commands marked with ❌ should be used with caution as their beh
|
|
|
62
62
|
| `get_a_single_list` | ✅ | ❌ | |
|
|
63
63
|
| `delete_a_list` | ✅ | ❌ | |
|
|
64
64
|
| `update_a_list` | ❌ | ❌ | |
|
|
65
|
-
| `
|
|
65
|
+
| `get_bookmarks_in_the_list` | ❌ | ❌ | |
|
|
66
66
|
| `add_a_bookmark_to_a_list` | ❌ | ❌ | |
|
|
67
67
|
| `remove_a_bookmark_from_a_list` | ❌ | ❌ | |
|
|
68
68
|
| `get_all_tags` | ✅ | ✅ | |
|
|
69
|
+
| `create_a_new_tag` | ❌ | ❌ | |
|
|
69
70
|
| `get_a_single_tag` | ✅ | ❌ | |
|
|
70
71
|
| `delete_a_tag` | ✅ | ❌ | |
|
|
71
72
|
| `update_a_tag` | ✅ | ❌ | No output validation due to [server bug](https://github.com/karakeep-app/karakeep/issues/1365). |
|
|
72
|
-
| `
|
|
73
|
+
| `get_bookmarks_with_the_tag` | ❌ | ❌ | |
|
|
73
74
|
| `get_all_highlights` | ✅ | ✅ | Tested with pagination. |
|
|
74
75
|
| `create_a_new_highlight` | ❌ | ❌ | |
|
|
75
76
|
| `get_a_single_highlight` | ❌ | ❌ | |
|
|
@@ -7,7 +7,17 @@ import functools
|
|
|
7
7
|
import re # Import re module
|
|
8
8
|
import click
|
|
9
9
|
import traceback # Moved import to top
|
|
10
|
-
from typing import
|
|
10
|
+
from typing import (
|
|
11
|
+
Any,
|
|
12
|
+
List,
|
|
13
|
+
Dict,
|
|
14
|
+
Optional,
|
|
15
|
+
Callable,
|
|
16
|
+
Union,
|
|
17
|
+
get_origin,
|
|
18
|
+
get_args,
|
|
19
|
+
Literal,
|
|
20
|
+
)
|
|
11
21
|
from pydantic import BaseModel, ValidationError
|
|
12
22
|
from loguru import logger # Import logger
|
|
13
23
|
|
|
@@ -82,9 +92,9 @@ shared_options = [
|
|
|
82
92
|
),
|
|
83
93
|
click.option(
|
|
84
94
|
"--ascii",
|
|
85
|
-
"ensure_ascii",
|
|
95
|
+
"ensure_ascii", # Use 'ensure_ascii' as the destination variable name
|
|
86
96
|
is_flag=True,
|
|
87
|
-
default=False,
|
|
97
|
+
default=False, # Default is False, meaning ensure_ascii=False by default
|
|
88
98
|
envvar="KARAKEEP_PYTHON_API_ENSURE_ASCII",
|
|
89
99
|
help="Escape non-ASCII characters in the JSON output (default: keep Unicode).",
|
|
90
100
|
),
|
|
@@ -135,9 +145,19 @@ def print_openapi_spec(ctx, param, value):
|
|
|
135
145
|
is_eager=True, # Process this option before others
|
|
136
146
|
help="Dump the OpenAPI specification JSON to stdout and exit.",
|
|
137
147
|
)
|
|
138
|
-
@add_options(
|
|
148
|
+
@add_options(
|
|
149
|
+
shared_options
|
|
150
|
+
) # Apply shared options to the group (ensure_ascii is now included)
|
|
139
151
|
@click.pass_context
|
|
140
|
-
def cli(
|
|
152
|
+
def cli(
|
|
153
|
+
ctx,
|
|
154
|
+
base_url,
|
|
155
|
+
api_key,
|
|
156
|
+
verify_ssl,
|
|
157
|
+
verbose,
|
|
158
|
+
disable_response_validation,
|
|
159
|
+
ensure_ascii,
|
|
160
|
+
):
|
|
141
161
|
"""
|
|
142
162
|
Karakeep Python API Command Line Interface.
|
|
143
163
|
|
|
@@ -171,7 +191,7 @@ def cli(ctx, base_url, api_key, verify_ssl, verbose, disable_response_validation
|
|
|
171
191
|
ctx.obj["DISABLE_RESPONSE_VALIDATION"] = (
|
|
172
192
|
disable_response_validation # Store the flag
|
|
173
193
|
)
|
|
174
|
-
ctx.obj["ENSURE_ASCII"] = ensure_ascii
|
|
194
|
+
ctx.obj["ENSURE_ASCII"] = ensure_ascii # Store the ensure_ascii flag
|
|
175
195
|
|
|
176
196
|
# --- Configure Logger ---
|
|
177
197
|
log_level = "DEBUG" if verbose else "INFO"
|
|
@@ -184,7 +204,7 @@ def cli(ctx, base_url, api_key, verify_ssl, verbose, disable_response_validation
|
|
|
184
204
|
)
|
|
185
205
|
logger.debug("Verbose logging enabled with detailed format.")
|
|
186
206
|
else:
|
|
187
|
-
logger.add(sys.stderr, level=log_level)
|
|
207
|
+
logger.add(sys.stderr, level=log_level) # Default format for INFO
|
|
188
208
|
logger.debug("Logger configured for level: {}", log_level)
|
|
189
209
|
logger.debug("CLI context initialized.")
|
|
190
210
|
|
|
@@ -216,7 +236,7 @@ def create_click_command(
|
|
|
216
236
|
verify_ssl = ctx.obj["VERIFY_SSL"]
|
|
217
237
|
verbose = ctx.obj["VERBOSE"]
|
|
218
238
|
disable_validation = ctx.obj["DISABLE_RESPONSE_VALIDATION"] # Retrieve flag
|
|
219
|
-
ensure_ascii_output = ctx.obj["ENSURE_ASCII"]
|
|
239
|
+
ensure_ascii_output = ctx.obj["ENSURE_ASCII"] # Retrieve ensure_ascii flag
|
|
220
240
|
|
|
221
241
|
if not api_key:
|
|
222
242
|
click.echo(
|
|
@@ -253,9 +273,7 @@ def create_click_command(
|
|
|
253
273
|
# Remove arguments that are not part of the method signature
|
|
254
274
|
# (e.g., if extra options were somehow passed)
|
|
255
275
|
valid_arg_names = set(signature.parameters.keys())
|
|
256
|
-
call_args = {
|
|
257
|
-
k: v for k, v in call_args.items() if k in valid_arg_names
|
|
258
|
-
}
|
|
276
|
+
call_args = {k: v for k, v in call_args.items() if k in valid_arg_names}
|
|
259
277
|
|
|
260
278
|
# --- JSON Parsing for Dict/List Parameters ---
|
|
261
279
|
# Iterate through the expected parameters from the signature
|
|
@@ -268,13 +286,15 @@ def create_click_command(
|
|
|
268
286
|
# Check if the annotation is dict/list or typing.Dict/List
|
|
269
287
|
# and if the received value is a string (needs parsing)
|
|
270
288
|
if (
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
):
|
|
289
|
+
param_annotation in (dict, list)
|
|
290
|
+
or origin in (dict, list, Dict, List)
|
|
291
|
+
) and isinstance(param_value, str):
|
|
274
292
|
try:
|
|
275
293
|
# Attempt to parse the JSON string
|
|
276
294
|
call_args[param_name] = json.loads(param_value)
|
|
277
|
-
logger.debug(
|
|
295
|
+
logger.debug(
|
|
296
|
+
f"Parsed JSON string for parameter '{param_name}'."
|
|
297
|
+
)
|
|
278
298
|
except json.JSONDecodeError as json_err:
|
|
279
299
|
# Handle invalid JSON input from the user
|
|
280
300
|
click.echo(
|
|
@@ -287,89 +307,122 @@ def create_click_command(
|
|
|
287
307
|
# Call the API method
|
|
288
308
|
try:
|
|
289
309
|
if method_name == "get_all_bookmarks":
|
|
290
|
-
logger.debug(
|
|
291
|
-
|
|
310
|
+
logger.debug(
|
|
311
|
+
f"Special CLI pagination handling for '{method_name}'."
|
|
312
|
+
)
|
|
313
|
+
cli_total_limit = call_args.pop("limit", None)
|
|
292
314
|
# Other relevant params for get_all_bookmarks
|
|
293
|
-
archived_filter = call_args.get(
|
|
294
|
-
favourited_filter = call_args.get(
|
|
295
|
-
include_content_cli = call_args.get(
|
|
296
|
-
|
|
297
|
-
call_args.pop(
|
|
315
|
+
archived_filter = call_args.get("archived")
|
|
316
|
+
favourited_filter = call_args.get("favourited")
|
|
317
|
+
include_content_cli = call_args.get("include_content", True)
|
|
318
|
+
|
|
319
|
+
call_args.pop("cursor", None) # Ignore CLI cursor
|
|
298
320
|
|
|
299
321
|
all_bookmarks_data = []
|
|
300
322
|
current_page_api_cursor = None
|
|
301
323
|
fetched_count = 0
|
|
302
|
-
API_INTERNAL_PAGE_SIZE = 50
|
|
324
|
+
API_INTERNAL_PAGE_SIZE = 50 # Define a page size for API calls
|
|
303
325
|
|
|
304
326
|
while True:
|
|
305
327
|
api_call_limit = API_INTERNAL_PAGE_SIZE
|
|
306
328
|
if cli_total_limit is not None:
|
|
307
329
|
remaining_needed = cli_total_limit - fetched_count
|
|
308
330
|
if remaining_needed <= 0:
|
|
309
|
-
break
|
|
310
|
-
api_call_limit = min(
|
|
311
|
-
|
|
312
|
-
|
|
331
|
+
break # Reached or exceeded CLI total limit
|
|
332
|
+
api_call_limit = min(
|
|
333
|
+
API_INTERNAL_PAGE_SIZE, remaining_needed
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
if (
|
|
337
|
+
api_call_limit <= 0 and cli_total_limit is not None
|
|
338
|
+
): # Avoid asking for 0 or negative items unless fetching all
|
|
313
339
|
break
|
|
314
340
|
|
|
341
|
+
logger.debug(
|
|
342
|
+
f"Fetching page for '{method_name}' with cursor: {current_page_api_cursor}, api_limit: {api_call_limit}"
|
|
343
|
+
)
|
|
315
344
|
|
|
316
|
-
logger.debug(f"Fetching page for '{method_name}' with cursor: {current_page_api_cursor}, api_limit: {api_call_limit}")
|
|
317
|
-
|
|
318
345
|
page_call_args = {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
346
|
+
"archived": archived_filter,
|
|
347
|
+
"favourited": favourited_filter,
|
|
348
|
+
"limit": api_call_limit,
|
|
349
|
+
"cursor": current_page_api_cursor,
|
|
350
|
+
"include_content": include_content_cli,
|
|
351
|
+
}
|
|
352
|
+
page_call_args_filtered = {
|
|
353
|
+
k: v for k, v in page_call_args.items() if v is not None
|
|
324
354
|
}
|
|
325
|
-
page_call_args_filtered = {k: v for k, v in page_call_args.items() if v is not None}
|
|
326
355
|
|
|
327
356
|
try:
|
|
328
|
-
page_result_obj = instance_method(
|
|
357
|
+
page_result_obj = instance_method(
|
|
358
|
+
**page_call_args_filtered
|
|
359
|
+
)
|
|
329
360
|
except TypeError as call_error_page:
|
|
330
|
-
logger.error(
|
|
331
|
-
|
|
332
|
-
|
|
361
|
+
logger.error(
|
|
362
|
+
f"Error calling API method '{method_name}' (paginated): {call_error_page}"
|
|
363
|
+
)
|
|
364
|
+
logger.error(
|
|
365
|
+
f"Provided arguments for page: {page_call_args_filtered}"
|
|
366
|
+
)
|
|
367
|
+
if verbose:
|
|
368
|
+
logger.debug(traceback.format_exc())
|
|
333
369
|
ctx.exit(1)
|
|
334
370
|
|
|
335
371
|
bookmarks_on_this_page = []
|
|
336
372
|
next_api_cursor = None
|
|
337
373
|
|
|
338
374
|
# Convert Pydantic model to dict using model_dump if available
|
|
339
|
-
if hasattr(page_result_obj,
|
|
375
|
+
if hasattr(page_result_obj, "model_dump"):
|
|
340
376
|
result_dict = page_result_obj.model_dump()
|
|
341
377
|
elif isinstance(page_result_obj, dict):
|
|
342
378
|
result_dict = page_result_obj
|
|
343
379
|
else:
|
|
344
|
-
logger.warning(
|
|
380
|
+
logger.warning(
|
|
381
|
+
f"Unexpected result type: {type(page_result_obj)}"
|
|
382
|
+
)
|
|
345
383
|
result_dict = {}
|
|
346
384
|
|
|
347
385
|
# Extract data and cursor from the dict
|
|
348
386
|
bookmarks_on_this_page = result_dict.get("bookmarks", [])
|
|
349
387
|
next_api_cursor = result_dict.get("nextCursor")
|
|
350
388
|
|
|
351
|
-
logger.debug(
|
|
352
|
-
|
|
389
|
+
logger.debug(
|
|
390
|
+
f"Extracted {len(bookmarks_on_this_page)} bookmarks and cursor: {next_api_cursor}"
|
|
391
|
+
)
|
|
392
|
+
|
|
353
393
|
if not isinstance(bookmarks_on_this_page, list):
|
|
354
|
-
logger.warning(
|
|
394
|
+
logger.warning(
|
|
395
|
+
f"Expected a list of bookmarks, got {type(bookmarks_on_this_page)}. Stopping pagination."
|
|
396
|
+
)
|
|
355
397
|
break
|
|
356
|
-
|
|
398
|
+
|
|
357
399
|
all_bookmarks_data.extend(bookmarks_on_this_page)
|
|
358
400
|
fetched_count += len(bookmarks_on_this_page)
|
|
359
|
-
logger.debug(
|
|
401
|
+
logger.debug(
|
|
402
|
+
f"Fetched {len(bookmarks_on_this_page)} bookmarks this page. Total fetched: {fetched_count}."
|
|
403
|
+
)
|
|
360
404
|
|
|
361
405
|
current_page_api_cursor = next_api_cursor
|
|
362
406
|
if not current_page_api_cursor:
|
|
363
|
-
logger.debug(
|
|
407
|
+
logger.debug(
|
|
408
|
+
"No nextCursor from API, pagination complete."
|
|
409
|
+
)
|
|
364
410
|
break
|
|
365
|
-
if
|
|
366
|
-
|
|
411
|
+
if (
|
|
412
|
+
cli_total_limit is not None
|
|
413
|
+
and fetched_count >= cli_total_limit
|
|
414
|
+
):
|
|
415
|
+
logger.debug(
|
|
416
|
+
f"CLI total limit of {cli_total_limit} reached or exceeded."
|
|
417
|
+
)
|
|
367
418
|
break
|
|
368
419
|
if not bookmarks_on_this_page and api_call_limit > 0:
|
|
369
|
-
logger.debug(
|
|
420
|
+
logger.debug(
|
|
421
|
+
"API returned an empty list of bookmarks while a positive limit was set, assuming end of data."
|
|
422
|
+
)
|
|
370
423
|
break
|
|
371
|
-
|
|
372
|
-
result = all_bookmarks_data
|
|
424
|
+
|
|
425
|
+
result = all_bookmarks_data # This will be a list of Bookmark models or dicts
|
|
373
426
|
else:
|
|
374
427
|
# Original behavior for other commands
|
|
375
428
|
logger.debug(
|
|
@@ -393,7 +446,9 @@ def create_click_command(
|
|
|
393
446
|
output_data = serialize_output(result)
|
|
394
447
|
# Use ensure_ascii_output flag to control JSON encoding
|
|
395
448
|
click.echo(
|
|
396
|
-
json.dumps(
|
|
449
|
+
json.dumps(
|
|
450
|
+
output_data, indent=2, ensure_ascii=ensure_ascii_output
|
|
451
|
+
)
|
|
397
452
|
)
|
|
398
453
|
else:
|
|
399
454
|
# Handle None result (e.g., 204 No Content) gracefully
|
|
@@ -434,7 +489,9 @@ def create_click_command(
|
|
|
434
489
|
docstring = api_method.__doc__ or f"Execute the {api_method_name} API operation."
|
|
435
490
|
docstring = dedent(docstring)
|
|
436
491
|
docstring_lines = docstring.split("\n")
|
|
437
|
-
help_text = " ".join(
|
|
492
|
+
help_text = " ".join(
|
|
493
|
+
docstring.split("\n\n")[0].splitlines()
|
|
494
|
+
).strip() # First lines as short help
|
|
438
495
|
# Full docstring as help
|
|
439
496
|
full_help = docstring
|
|
440
497
|
|
|
@@ -452,9 +509,7 @@ def create_click_command(
|
|
|
452
509
|
stripped_line = line.strip()
|
|
453
510
|
if stripped_line == "Args:":
|
|
454
511
|
in_args_section = True
|
|
455
|
-
elif
|
|
456
|
-
stripped_line == "Returns:" or stripped_line == "Raises:"
|
|
457
|
-
):
|
|
512
|
+
elif stripped_line == "Returns:" or stripped_line == "Raises:":
|
|
458
513
|
in_args_section = False # Stop capturing when Returns/Raises section starts
|
|
459
514
|
elif in_args_section and stripped_line:
|
|
460
515
|
args_section_lines.append(stripped_line)
|
|
@@ -465,7 +520,9 @@ def create_click_command(
|
|
|
465
520
|
param_name = match.group(1)
|
|
466
521
|
description = match.group(2).strip()
|
|
467
522
|
param_descriptions[param_name] = description
|
|
468
|
-
logger.trace(
|
|
523
|
+
logger.trace(
|
|
524
|
+
f"Parsed docstring param: '{param_name}' -> '{description}'"
|
|
525
|
+
)
|
|
469
526
|
else:
|
|
470
527
|
param_descriptions[param_name] += " " + stripped_line
|
|
471
528
|
|
|
@@ -524,7 +581,7 @@ def create_click_command(
|
|
|
524
581
|
logger.warning(
|
|
525
582
|
f"Parameter '{param.name}' is Literal but contains non-string types. Treating as STRING."
|
|
526
583
|
)
|
|
527
|
-
click_type = click.STRING
|
|
584
|
+
click_type = click.STRING # Fallback
|
|
528
585
|
|
|
529
586
|
# Determine option name(s) and help text
|
|
530
587
|
option_names = [f"--{param_name_cli}"]
|
|
@@ -543,7 +600,7 @@ def create_click_command(
|
|
|
543
600
|
):
|
|
544
601
|
param_help += " (Provide as JSON string)"
|
|
545
602
|
elif isinstance(click_type, click.Choice):
|
|
546
|
-
|
|
603
|
+
param_help += f" (Choices: {', '.join(click_type.choices)})"
|
|
547
604
|
|
|
548
605
|
click_required = is_required_in_sig and default_value is None and not is_flag
|
|
549
606
|
|
|
@@ -551,14 +608,22 @@ def create_click_command(
|
|
|
551
608
|
current_param_help = param_help
|
|
552
609
|
current_click_required = click_required
|
|
553
610
|
current_default_value = default_value
|
|
554
|
-
current_is_flag =
|
|
555
|
-
|
|
611
|
+
current_is_flag = (
|
|
612
|
+
is_flag # Though is_flag interpretation might change help/required
|
|
613
|
+
)
|
|
614
|
+
|
|
556
615
|
# Special handling for 'get_all_bookmarks' command parameters
|
|
557
616
|
if api_method_name == "get_all_bookmarks":
|
|
558
617
|
if param.name == "cursor":
|
|
559
|
-
current_param_help =
|
|
560
|
-
|
|
561
|
-
|
|
618
|
+
current_param_help = (
|
|
619
|
+
"[Ignored by CLI for get-all-bookmarks] " + param_help
|
|
620
|
+
)
|
|
621
|
+
current_click_required = (
|
|
622
|
+
False # Cursor is handled by CLI, not required from user
|
|
623
|
+
)
|
|
624
|
+
current_default_value = (
|
|
625
|
+
None # Explicitly set default to None for ignored param
|
|
626
|
+
)
|
|
562
627
|
elif param.name == "limit":
|
|
563
628
|
current_param_help = "Total maximum number of bookmarks to fetch across pages for get-all-bookmarks. If omitted, all are fetched."
|
|
564
629
|
# For 'limit', required status and default remain as derived from its Optional[int] type hint
|
|
@@ -22,11 +22,11 @@ class ListId(RootModel[str]):
|
|
|
22
22
|
root: str = Field(..., example="ieidlxygmwj87oxz5hxttoc8")
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
class
|
|
25
|
+
class HighlightId(RootModel[str]):
|
|
26
26
|
root: str = Field(..., example="ieidlxygmwj87oxz5hxttoc8")
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
class
|
|
29
|
+
class TagId(RootModel[str]):
|
|
30
30
|
root: str = Field(..., example="ieidlxygmwj87oxz5hxttoc8")
|
|
31
31
|
|
|
32
32
|
|
|
@@ -41,12 +41,19 @@ class AttachedBy(str, Enum):
|
|
|
41
41
|
human = "human"
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
class
|
|
44
|
+
class TagShort(BaseModel):
|
|
45
45
|
id: str
|
|
46
46
|
name: str
|
|
47
47
|
attachedBy: AttachedBy
|
|
48
48
|
|
|
49
49
|
|
|
50
|
+
class Tag(BaseModel):
|
|
51
|
+
id: str
|
|
52
|
+
name: str
|
|
53
|
+
numBookmarks: float
|
|
54
|
+
numBookmarksByAttachedType: NumBookmarksByAttachedType
|
|
55
|
+
|
|
56
|
+
|
|
50
57
|
class Type(str, Enum):
|
|
51
58
|
link = "link"
|
|
52
59
|
|
|
@@ -71,28 +78,36 @@ class Content(BaseModel):
|
|
|
71
78
|
dateModified: Optional[str] = None
|
|
72
79
|
|
|
73
80
|
|
|
74
|
-
class
|
|
81
|
+
class TypeText(str, Enum):
|
|
75
82
|
text = "text"
|
|
76
83
|
|
|
77
84
|
|
|
78
|
-
class
|
|
79
|
-
|
|
80
|
-
text: str
|
|
81
|
-
sourceUrl: Optional[str] = None
|
|
85
|
+
class TypeAsset(str, Enum):
|
|
86
|
+
asset = "asset"
|
|
82
87
|
|
|
83
88
|
|
|
84
|
-
class
|
|
85
|
-
|
|
89
|
+
class TypeUnknown(str, Enum):
|
|
90
|
+
unknown = "unknown"
|
|
86
91
|
|
|
87
92
|
|
|
88
|
-
class
|
|
93
|
+
class ContentUnknown(BaseModel):
|
|
94
|
+
type: TypeUnknown
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class AssetTypeAssetType(str, Enum):
|
|
89
98
|
image = "image"
|
|
90
99
|
pdf = "pdf"
|
|
91
100
|
|
|
92
101
|
|
|
93
|
-
class
|
|
94
|
-
type:
|
|
95
|
-
|
|
102
|
+
class ContentTypeText(BaseModel):
|
|
103
|
+
type: TypeText
|
|
104
|
+
text: str
|
|
105
|
+
sourceUrl: Optional[str] = None
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class ContentTypeAsset(BaseModel):
|
|
109
|
+
type: TypeAsset
|
|
110
|
+
assetType: AssetTypeAssetType
|
|
96
111
|
assetId: str
|
|
97
112
|
fileName: Optional[str] = None
|
|
98
113
|
sourceUrl: Optional[str] = None
|
|
@@ -100,15 +115,7 @@ class Content2(BaseModel):
|
|
|
100
115
|
content: Optional[str] = None
|
|
101
116
|
|
|
102
117
|
|
|
103
|
-
class
|
|
104
|
-
unknown = "unknown"
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
class Content3(BaseModel):
|
|
108
|
-
type: Type3
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
class AssetType1(str, Enum):
|
|
118
|
+
class AssetType(str, Enum):
|
|
112
119
|
screenshot = "screenshot"
|
|
113
120
|
assetScreenshot = "assetScreenshot"
|
|
114
121
|
bannerImage = "bannerImage"
|
|
@@ -121,27 +128,28 @@ class AssetType1(str, Enum):
|
|
|
121
128
|
|
|
122
129
|
class Asset(BaseModel):
|
|
123
130
|
id: str
|
|
124
|
-
assetType:
|
|
131
|
+
assetType: AssetType
|
|
125
132
|
|
|
126
133
|
|
|
127
134
|
class Bookmark(BaseModel):
|
|
128
135
|
id: str
|
|
129
136
|
createdAt: str
|
|
130
|
-
modifiedAt: str
|
|
137
|
+
modifiedAt: Optional[str]
|
|
131
138
|
title: Optional[str] = None
|
|
132
139
|
archived: bool
|
|
133
140
|
favourited: bool
|
|
134
141
|
taggingStatus: TaggingStatus
|
|
142
|
+
summarizationStatus: Optional[TaggingStatus] = None
|
|
135
143
|
note: Optional[str] = None
|
|
136
144
|
summary: Optional[str] = None
|
|
137
|
-
tags: List[
|
|
138
|
-
content: Union[Content,
|
|
145
|
+
tags: List[TagShort]
|
|
146
|
+
content: Union[Content, ContentTypeText, ContentTypeAsset, ContentUnknown]
|
|
139
147
|
assets: List[Asset]
|
|
140
148
|
|
|
141
149
|
|
|
142
150
|
class PaginatedBookmarks(BaseModel):
|
|
143
151
|
bookmarks: List[Bookmark]
|
|
144
|
-
nextCursor: Optional[str]
|
|
152
|
+
nextCursor: Optional[str]
|
|
145
153
|
|
|
146
154
|
|
|
147
155
|
class Cursor(RootModel[str]):
|
|
@@ -160,14 +168,14 @@ class Highlight(BaseModel):
|
|
|
160
168
|
startOffset: float
|
|
161
169
|
endOffset: float
|
|
162
170
|
color: Optional[Color] = "yellow"
|
|
163
|
-
text: Optional[str]
|
|
164
|
-
note: Optional[str]
|
|
171
|
+
text: Optional[str]
|
|
172
|
+
note: Optional[str]
|
|
165
173
|
id: str
|
|
166
174
|
userId: str
|
|
167
175
|
createdAt: str
|
|
168
176
|
|
|
169
177
|
|
|
170
|
-
class
|
|
178
|
+
class ListType(str, Enum):
|
|
171
179
|
manual = "manual"
|
|
172
180
|
smart = "smart"
|
|
173
181
|
|
|
@@ -177,8 +185,8 @@ class ListModel(BaseModel):
|
|
|
177
185
|
name: str
|
|
178
186
|
description: Optional[str] = None
|
|
179
187
|
icon: str
|
|
180
|
-
parentId: Optional[str]
|
|
181
|
-
type: Optional[
|
|
188
|
+
parentId: Optional[str]
|
|
189
|
+
type: Optional[ListType] = "manual"
|
|
182
190
|
query: Optional[str] = None
|
|
183
191
|
|
|
184
192
|
|
|
@@ -187,13 +195,6 @@ class NumBookmarksByAttachedType(BaseModel):
|
|
|
187
195
|
human: Optional[float] = None
|
|
188
196
|
|
|
189
197
|
|
|
190
|
-
class Tag1(BaseModel):
|
|
191
|
-
id: str
|
|
192
|
-
name: str
|
|
193
|
-
numBookmarks: float
|
|
194
|
-
numBookmarksByAttachedType: NumBookmarksByAttachedType
|
|
195
|
-
|
|
196
|
-
|
|
197
198
|
class PaginatedHighlights(BaseModel):
|
|
198
199
|
highlights: List[Highlight]
|
|
199
|
-
nextCursor: Optional[str]
|
|
200
|
+
nextCursor: Optional[str]
|