devrev-Python-SDK 3.0.0__py3-none-any.whl → 3.0.1__py3-none-any.whl
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.
- devrev/services/_pagination.py +54 -0
- devrev/services/conversations.py +3 -29
- devrev/services/works.py +3 -27
- {devrev_python_sdk-3.0.0.dist-info → devrev_python_sdk-3.0.1.dist-info}/METADATA +1 -1
- {devrev_python_sdk-3.0.0.dist-info → devrev_python_sdk-3.0.1.dist-info}/RECORD +7 -6
- {devrev_python_sdk-3.0.0.dist-info → devrev_python_sdk-3.0.1.dist-info}/WHEEL +0 -0
- {devrev_python_sdk-3.0.0.dist-info → devrev_python_sdk-3.0.1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Shared pagination helpers for cursor-streaming list helpers.
|
|
2
|
+
|
|
3
|
+
The DevRev ``*.list`` endpoints cap per-page responses at 100 items and the
|
|
4
|
+
corresponding ``*ListRequest.limit`` fields are pydantic-constrained to
|
|
5
|
+
``le=100``. Any service that drives cursor pagination from a user-supplied
|
|
6
|
+
``overall_limit`` / ``page_size`` pair must therefore clamp the value it puts
|
|
7
|
+
on the request body before construction, or the request will fail validation
|
|
8
|
+
locally before it is ever sent.
|
|
9
|
+
|
|
10
|
+
:func:`resolve_page_limit` centralises that clamping so every ``list_*_since``
|
|
11
|
+
helper resolves the per-page ``limit`` identically.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from typing import Final
|
|
17
|
+
|
|
18
|
+
_MAX_PAGE: Final[int] = 100
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def resolve_page_limit(
|
|
22
|
+
overall_limit: int | None,
|
|
23
|
+
collected: int,
|
|
24
|
+
page_size: int | None,
|
|
25
|
+
) -> int | None:
|
|
26
|
+
"""Compute the ``limit`` to send for the next page request.
|
|
27
|
+
|
|
28
|
+
The returned value is always clamped to :data:`_MAX_PAGE` so callers using
|
|
29
|
+
an ``overall_limit`` greater than the server maximum (e.g. ``limit=200,
|
|
30
|
+
page_size=None``) still paginate correctly. When both ``overall_limit`` and
|
|
31
|
+
``page_size`` are supplied the tightest of ``{page_size, remaining,
|
|
32
|
+
_MAX_PAGE}`` wins.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
overall_limit: Caller-supplied hard cap on total items to return across
|
|
36
|
+
all pages, or ``None`` to stream until the server runs out of
|
|
37
|
+
results.
|
|
38
|
+
collected: Number of items already accumulated across prior pages.
|
|
39
|
+
page_size: Caller-supplied per-page size, or ``None`` to defer to the
|
|
40
|
+
server default (still clamped to :data:`_MAX_PAGE`).
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
The ``limit`` to put on the next ``*ListRequest``, or ``None`` to omit
|
|
44
|
+
it entirely (only when both ``overall_limit`` and ``page_size`` are
|
|
45
|
+
``None``).
|
|
46
|
+
"""
|
|
47
|
+
if overall_limit is None:
|
|
48
|
+
if page_size is None:
|
|
49
|
+
return None
|
|
50
|
+
return min(page_size, _MAX_PAGE)
|
|
51
|
+
remaining = overall_limit - collected
|
|
52
|
+
if page_size is None:
|
|
53
|
+
return min(remaining, _MAX_PAGE)
|
|
54
|
+
return min(page_size, remaining, _MAX_PAGE)
|
devrev/services/conversations.py
CHANGED
|
@@ -23,6 +23,7 @@ from devrev.models.conversations import (
|
|
|
23
23
|
ConversationsUpdateRequest,
|
|
24
24
|
ConversationsUpdateResponse,
|
|
25
25
|
)
|
|
26
|
+
from devrev.services._pagination import resolve_page_limit
|
|
26
27
|
from devrev.services.base import AsyncBaseService, BaseService
|
|
27
28
|
|
|
28
29
|
|
|
@@ -47,33 +48,6 @@ def _normalize_sort_by(sort_by: Sequence[str] | None) -> list[str] | None:
|
|
|
47
48
|
return normalized
|
|
48
49
|
|
|
49
50
|
|
|
50
|
-
# ``ConversationsListRequest.limit`` is pydantic-constrained to ``le=100``;
|
|
51
|
-
# clamp any computed per-page limit so pagination loops do not construct a
|
|
52
|
-
# request body that fails validation before it is ever sent.
|
|
53
|
-
_CONVERSATIONS_MAX_PAGE = 100
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def _resolve_page_limit(
|
|
57
|
-
overall_limit: int | None,
|
|
58
|
-
collected: int,
|
|
59
|
-
page_size: int | None,
|
|
60
|
-
) -> int | None:
|
|
61
|
-
"""Compute the ``limit`` to send for the next page request.
|
|
62
|
-
|
|
63
|
-
The returned value is always clamped to ``_CONVERSATIONS_MAX_PAGE`` so
|
|
64
|
-
callers using an ``overall_limit`` greater than the server maximum (e.g.
|
|
65
|
-
``limit=200, page_size=None``) still paginate correctly.
|
|
66
|
-
"""
|
|
67
|
-
if overall_limit is None:
|
|
68
|
-
if page_size is None:
|
|
69
|
-
return None
|
|
70
|
-
return min(page_size, _CONVERSATIONS_MAX_PAGE)
|
|
71
|
-
remaining = overall_limit - collected
|
|
72
|
-
if page_size is None:
|
|
73
|
-
return min(remaining, _CONVERSATIONS_MAX_PAGE)
|
|
74
|
-
return min(page_size, remaining, _CONVERSATIONS_MAX_PAGE)
|
|
75
|
-
|
|
76
|
-
|
|
77
51
|
def _is_before_cutoff(modified_date: datetime | None, cutoff: datetime) -> bool:
|
|
78
52
|
"""Return True if ``modified_date`` is strictly older than ``cutoff``.
|
|
79
53
|
|
|
@@ -135,7 +109,7 @@ class ConversationsService(BaseService):
|
|
|
135
109
|
while True:
|
|
136
110
|
if limit is not None and len(results) >= limit:
|
|
137
111
|
break
|
|
138
|
-
request_limit =
|
|
112
|
+
request_limit = resolve_page_limit(limit, len(results), page_size)
|
|
139
113
|
request = ConversationsListRequest(
|
|
140
114
|
cursor=cursor,
|
|
141
115
|
limit=request_limit,
|
|
@@ -267,7 +241,7 @@ class AsyncConversationsService(AsyncBaseService):
|
|
|
267
241
|
while True:
|
|
268
242
|
if limit is not None and len(results) >= limit:
|
|
269
243
|
break
|
|
270
|
-
request_limit =
|
|
244
|
+
request_limit = resolve_page_limit(limit, len(results), page_size)
|
|
271
245
|
request = ConversationsListRequest(
|
|
272
246
|
cursor=cursor,
|
|
273
247
|
limit=request_limit,
|
devrev/services/works.py
CHANGED
|
@@ -31,6 +31,7 @@ from devrev.models.works import (
|
|
|
31
31
|
WorksUpdateResponse,
|
|
32
32
|
WorkType,
|
|
33
33
|
)
|
|
34
|
+
from devrev.services._pagination import resolve_page_limit
|
|
34
35
|
from devrev.services.base import AsyncBaseService, BaseService
|
|
35
36
|
|
|
36
37
|
if TYPE_CHECKING:
|
|
@@ -58,31 +59,6 @@ def _is_before_cutoff(timestamp: datetime | None, cutoff: datetime) -> bool:
|
|
|
58
59
|
return False
|
|
59
60
|
|
|
60
61
|
|
|
61
|
-
# ``WorksListRequest.limit`` is pydantic-constrained to ``le=100``; clamp any
|
|
62
|
-
# computed per-page limit so pagination loops do not construct a request body
|
|
63
|
-
# that fails validation before it is ever sent.
|
|
64
|
-
_WORKS_MAX_PAGE = 100
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def _resolve_page_limit(
|
|
68
|
-
overall_limit: int | None,
|
|
69
|
-
collected: int,
|
|
70
|
-
page_size: int | None,
|
|
71
|
-
) -> int | None:
|
|
72
|
-
"""Compute the ``limit`` to send for the next page request.
|
|
73
|
-
|
|
74
|
-
The returned value is always clamped to ``_WORKS_MAX_PAGE`` so callers using
|
|
75
|
-
an ``overall_limit`` greater than the server maximum (e.g. ``limit=200,
|
|
76
|
-
page_size=None``) still paginate correctly.
|
|
77
|
-
"""
|
|
78
|
-
if page_size is not None:
|
|
79
|
-
return min(page_size, _WORKS_MAX_PAGE)
|
|
80
|
-
if overall_limit is None:
|
|
81
|
-
return None
|
|
82
|
-
remaining = overall_limit - collected
|
|
83
|
-
return min(remaining, _WORKS_MAX_PAGE)
|
|
84
|
-
|
|
85
|
-
|
|
86
62
|
def _normalize_sort_by(sort_by: Sequence[str] | None) -> _StrList | None:
|
|
87
63
|
"""Normalize sort_by entries to the server-expected ``field:direction`` form.
|
|
88
64
|
|
|
@@ -351,7 +327,7 @@ class WorksService(BaseService):
|
|
|
351
327
|
owned_by=owned_by,
|
|
352
328
|
applies_to_part=applies_to_part,
|
|
353
329
|
cursor=cursor,
|
|
354
|
-
limit=
|
|
330
|
+
limit=resolve_page_limit(limit, len(collected), page_size),
|
|
355
331
|
sort_by=sort_by,
|
|
356
332
|
)
|
|
357
333
|
stop = False
|
|
@@ -577,7 +553,7 @@ class AsyncWorksService(AsyncBaseService):
|
|
|
577
553
|
owned_by=owned_by,
|
|
578
554
|
applies_to_part=applies_to_part,
|
|
579
555
|
cursor=cursor,
|
|
580
|
-
limit=
|
|
556
|
+
limit=resolve_page_limit(limit, len(collected), page_size),
|
|
581
557
|
sort_by=sort_by,
|
|
582
558
|
)
|
|
583
559
|
stop = False
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devrev-Python-SDK
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.1
|
|
4
4
|
Summary: A modern, type-safe Python SDK for the DevRev API
|
|
5
5
|
Project-URL: Homepage, https://github.com/mgmonteleone/py-dev-rev
|
|
6
6
|
Project-URL: Documentation, https://github.com/mgmonteleone/py-dev-rev
|
|
@@ -36,13 +36,14 @@ devrev/models/webhooks.py,sha256=DzrLJiW1GYWvfaB-aVPcYCf4XkEGHz3dkyzbBKKdhFI,365
|
|
|
36
36
|
devrev/models/widgets.py,sha256=7WWN17_ySqnu1pjYSIS5B8J5dEaqkoB8X8GWzvI0ZYc,4577
|
|
37
37
|
devrev/models/works.py,sha256=sHZ_eJ6eCadWxPkM6HGcmbkiGRDYT2RnH3QZRO4T3tY,11198
|
|
38
38
|
devrev/services/__init__.py,sha256=LWy_0xGNH692d6Wc4S4E9v6AoxjgfExFMzFmbrL2NTY,3975
|
|
39
|
+
devrev/services/_pagination.py,sha256=J6AXu1P3iNRyC8_nH709Z8nOLhHeSctOLRmY_eYI6QA,2100
|
|
39
40
|
devrev/services/accounts.py,sha256=X7FgcODex0XKLiV_VvXKDl2Jm8XsNpn9qp40oRjZqME,9704
|
|
40
41
|
devrev/services/articles.py,sha256=xOpJOG9f29a5W3IFROplL1a9eJdGucbUFkK-MAIIYlc,41637
|
|
41
42
|
devrev/services/artifacts.py,sha256=SJzIi5M4np0ENoOTTGEAcoqoRFMVd8pe-BCo9vvhYzk,14124
|
|
42
43
|
devrev/services/base.py,sha256=pzUOkOA0kc7yxQQS8AP65L-inpW1WxpsYwtZwA_LXk4,7174
|
|
43
44
|
devrev/services/brands.py,sha256=W6FB9XXTtEzGOfm9IBI6dqY8WXrMeH6urwjiZKrDVgI,5679
|
|
44
45
|
devrev/services/code_changes.py,sha256=ahDniXCz54GGmTFmNh88heUg0mHQcIAgaqwlqm1CP6E,3199
|
|
45
|
-
devrev/services/conversations.py,sha256=
|
|
46
|
+
devrev/services/conversations.py,sha256=Xw8hDZuwte57fH2Z3D19gd5nrm91OURcWkBrKAcbqAQ,12716
|
|
46
47
|
devrev/services/dev_users.py,sha256=YDJUNk6Crz2TN_uwkWQIBmztIYrLd8EX3toNLdb_HEk,11870
|
|
47
48
|
devrev/services/engagements.py,sha256=nT6AElHbFO40utp6R_QCGwTGunXjVci73I8YAtkqu8A,9094
|
|
48
49
|
devrev/services/groups.py,sha256=0VpOKTwHiRjrKXrO1kdHo8V_z2I02GphYQhyDFnImxg,4960
|
|
@@ -62,7 +63,7 @@ devrev/services/timeline_entries.py,sha256=6nbVPcWlE3-ohLhvkM421eqYS5ztKtHmGsPek
|
|
|
62
63
|
devrev/services/track_events.py,sha256=lI4wXkWu3uUuXtuRg1MGNkTZ7B0Lc1PjM8Kw-6sUnWc,1439
|
|
63
64
|
devrev/services/uoms.py,sha256=AA3ymoHj24FIbsZpYC4tg2elSdQ3iINTVOz7MraZcj8,8163
|
|
64
65
|
devrev/services/webhooks.py,sha256=-TSkcaya1y48WB24_vHd-bqO5xSqxRsCLiilncNzQZU,3917
|
|
65
|
-
devrev/services/works.py,sha256=
|
|
66
|
+
devrev/services/works.py,sha256=hAK7ZUqLph5Db15p4RDbeRFLZUALAF5tCFOQSYytj_g,20456
|
|
66
67
|
devrev/utils/__init__.py,sha256=NOrbpkjDVLH8n9xf-xpZJiIIa_GVI_6vqTm3E8L3Udw,857
|
|
67
68
|
devrev/utils/content_converter.py,sha256=emRBLiVoOfDGpPDzrMRnqQr4-QkqN13OdWlYOyU_LCg,28141
|
|
68
69
|
devrev/utils/deprecation.py,sha256=7qB2Dx531oP7mNi7q2txOYsOKC9YwdHqlKPMFHOW9Ws,1275
|
|
@@ -116,7 +117,7 @@ devrev_mcp/utils/don_id.py,sha256=PAVzOSgaiqJQSdo1fwohFHq2x7PDNUZoBTN4LFGYM48,62
|
|
|
116
117
|
devrev_mcp/utils/errors.py,sha256=5mRAo76rJvvEVi6b1ZokPxDtX5JKkptaqmiYDLCkwBE,2110
|
|
117
118
|
devrev_mcp/utils/formatting.py,sha256=6JssG5x1BxjdgSiQ8Ou3H-9Wo3wgWTWmejsrGez4wKc,2431
|
|
118
119
|
devrev_mcp/utils/pagination.py,sha256=EOUgL-ZdSToM1Q-ydXmjhibsef5K1u1g3CaS9K8I2fY,1286
|
|
119
|
-
devrev_python_sdk-3.0.
|
|
120
|
-
devrev_python_sdk-3.0.
|
|
121
|
-
devrev_python_sdk-3.0.
|
|
122
|
-
devrev_python_sdk-3.0.
|
|
120
|
+
devrev_python_sdk-3.0.1.dist-info/METADATA,sha256=lTWWDMuQ7SvBTLsT1ape1IhGmY4b8OixjrHpqvkQL2o,40906
|
|
121
|
+
devrev_python_sdk-3.0.1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
122
|
+
devrev_python_sdk-3.0.1.dist-info/entry_points.txt,sha256=XiV4J_yy0yzVZVxg7T66YERVIlqdPNp3O-NHTHkllqQ,63
|
|
123
|
+
devrev_python_sdk-3.0.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|