comb-utils 0.2.8__tar.gz → 0.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.
- {comb_utils-0.2.8/src/comb_utils.egg-info → comb_utils-0.3.0}/PKG-INFO +2 -3
- {comb_utils-0.2.8 → comb_utils-0.3.0}/setup.cfg +2 -3
- {comb_utils-0.2.8 → comb_utils-0.3.0}/src/comb_utils/lib/api_callers.py +55 -3
- comb_utils-0.3.0/src/comb_utils/lib/errors.py +9 -0
- {comb_utils-0.2.8 → comb_utils-0.3.0/src/comb_utils.egg-info}/PKG-INFO +2 -3
- {comb_utils-0.2.8 → comb_utils-0.3.0}/src/comb_utils.egg-info/SOURCES.txt +2 -1
- {comb_utils-0.2.8 → comb_utils-0.3.0}/src/comb_utils.egg-info/requires.txt +1 -2
- {comb_utils-0.2.8 → comb_utils-0.3.0}/LICENSE +0 -0
- {comb_utils-0.2.8 → comb_utils-0.3.0}/README.md +0 -0
- {comb_utils-0.2.8 → comb_utils-0.3.0}/pyproject.toml +0 -0
- {comb_utils-0.2.8 → comb_utils-0.3.0}/src/comb_utils/__init__.py +0 -0
- {comb_utils-0.2.8 → comb_utils-0.3.0}/src/comb_utils/lib/__init__.py +0 -0
- {comb_utils-0.2.8 → comb_utils-0.3.0}/src/comb_utils/lib/constants.py +0 -0
- {comb_utils-0.2.8 → comb_utils-0.3.0}/src/comb_utils/lib/docs.py +0 -0
- {comb_utils-0.2.8 → comb_utils-0.3.0}/src/comb_utils.egg-info/dependency_links.txt +0 -0
- {comb_utils-0.2.8 → comb_utils-0.3.0}/src/comb_utils.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: comb_utils
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Handy utils for Python projects.
|
|
5
5
|
Author: Kaleb Coberly
|
|
6
6
|
Maintainer-email: kaleb.coberly@gmail.com
|
|
@@ -24,11 +24,10 @@ Requires-Dist: sphinx-autodoc-typehints; extra == "doc"
|
|
|
24
24
|
Provides-Extra: qc
|
|
25
25
|
Requires-Dist: bandit; extra == "qc"
|
|
26
26
|
Requires-Dist: black; extra == "qc"
|
|
27
|
-
Requires-Dist: black[jupyter]; extra == "qc"
|
|
28
27
|
Requires-Dist: flake8; extra == "qc"
|
|
29
28
|
Requires-Dist: flake8-annotations; extra == "qc"
|
|
30
29
|
Requires-Dist: flake8-bandit; extra == "qc"
|
|
31
|
-
Requires-Dist: flake8-black; extra == "qc"
|
|
30
|
+
Requires-Dist: flake8-black>=0.4.0; extra == "qc"
|
|
32
31
|
Requires-Dist: flake8-bugbear; extra == "qc"
|
|
33
32
|
Requires-Dist: flake8-docstrings; extra == "qc"
|
|
34
33
|
Requires-Dist: flake8-isort; extra == "qc"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[metadata]
|
|
2
2
|
name = comb_utils
|
|
3
|
-
version = 0.
|
|
3
|
+
version = 0.3.0
|
|
4
4
|
description = Handy utils for Python projects.
|
|
5
5
|
long_description = file: README.md
|
|
6
6
|
long_description_content_type = text/markdown
|
|
@@ -36,11 +36,10 @@ doc =
|
|
|
36
36
|
qc =
|
|
37
37
|
bandit
|
|
38
38
|
black
|
|
39
|
-
black[jupyter]
|
|
40
39
|
flake8
|
|
41
40
|
flake8-annotations
|
|
42
41
|
flake8-bandit
|
|
43
|
-
flake8-black
|
|
42
|
+
flake8-black>=0.4.0
|
|
44
43
|
flake8-bugbear
|
|
45
44
|
flake8-docstrings
|
|
46
45
|
flake8-isort
|
|
@@ -5,11 +5,13 @@ from abc import abstractmethod
|
|
|
5
5
|
from collections.abc import Callable
|
|
6
6
|
from time import sleep
|
|
7
7
|
from typing import Any
|
|
8
|
+
from urllib.parse import parse_qs, urlencode, urlparse, urlunparse
|
|
8
9
|
|
|
9
10
|
import requests
|
|
10
11
|
from requests.auth import HTTPBasicAuth
|
|
11
12
|
from typeguard import typechecked
|
|
12
13
|
|
|
14
|
+
from comb_utils.lib import errors
|
|
13
15
|
from comb_utils.lib.constants import RateLimits
|
|
14
16
|
|
|
15
17
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
|
|
@@ -338,21 +340,64 @@ class BasePagedResponseGetter(BaseGetCaller):
|
|
|
338
340
|
#: The URL for the page.
|
|
339
341
|
_page_url: str
|
|
340
342
|
|
|
343
|
+
#: The dictionary of query string parameters.
|
|
344
|
+
_params: dict[str, str] | None
|
|
345
|
+
|
|
341
346
|
@typechecked
|
|
342
|
-
def __init__(self, page_url: str) -> None:
|
|
347
|
+
def __init__(self, page_url: str, params: dict[str, str] | None = None) -> None:
|
|
343
348
|
"""Initialize the BasePagedResponseGetter object.
|
|
344
349
|
|
|
345
350
|
Args:
|
|
346
351
|
page_url: The URL for the page. (Optionally contains nextPageToken.)
|
|
352
|
+
params: The dictionary of query string parameters.
|
|
347
353
|
"""
|
|
348
354
|
self._page_url = page_url
|
|
355
|
+
self._params = params
|
|
349
356
|
super().__init__()
|
|
350
357
|
|
|
351
358
|
@typechecked
|
|
352
359
|
def _set_url(self) -> None:
|
|
353
360
|
"""Set the URL for the API call to the `page_url`."""
|
|
361
|
+
self._check_duplicates_in_URL()
|
|
362
|
+
self._add_params_to_URL()
|
|
354
363
|
self._url = self._page_url
|
|
355
364
|
|
|
365
|
+
@typechecked
|
|
366
|
+
def _check_duplicates_in_URL(self) -> None:
|
|
367
|
+
"""Check for duplicate values in query string parameters."""
|
|
368
|
+
parsed_url = urlparse(self._page_url)
|
|
369
|
+
query_str = parsed_url.query
|
|
370
|
+
query_params = parse_qs(query_str)
|
|
371
|
+
duplicate_entries = {key: val for key, val in query_params.items() if len(val) > 1}
|
|
372
|
+
if duplicate_entries:
|
|
373
|
+
raise errors.DuplicateKeysDetected(
|
|
374
|
+
f"Duplicate entries found in query string: {duplicate_entries}"
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
@typechecked
|
|
378
|
+
def _add_params_to_URL(self) -> None:
|
|
379
|
+
"""Add query string parameters to `page_url`."""
|
|
380
|
+
if self._params:
|
|
381
|
+
parsed_url = urlparse(self._page_url)
|
|
382
|
+
query_str = parsed_url.query
|
|
383
|
+
query_params = parse_qs(query_str)
|
|
384
|
+
for key, val in self._params.items():
|
|
385
|
+
if key in query_params:
|
|
386
|
+
query_params[key].append(val)
|
|
387
|
+
else:
|
|
388
|
+
query_params[key] = [val]
|
|
389
|
+
duplicate_entries = {
|
|
390
|
+
key: val for key, val in query_params.items() if len(val) > 1
|
|
391
|
+
}
|
|
392
|
+
if duplicate_entries:
|
|
393
|
+
raise errors.DuplicateKeysDetected(
|
|
394
|
+
f"Duplicate entries found in query string: {duplicate_entries}"
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
query_params = {key: val[0] for key, val in query_params.items()}
|
|
398
|
+
updated_query = urlencode(query_params)
|
|
399
|
+
self._page_url = urlunparse(parsed_url._replace(query=updated_query))
|
|
400
|
+
|
|
356
401
|
@typechecked
|
|
357
402
|
def _handle_200(self) -> None:
|
|
358
403
|
"""Handle a 200 response.
|
|
@@ -391,15 +436,20 @@ def get_response_dict(response: requests.Response) -> dict[str, Any]:
|
|
|
391
436
|
# TODO: bfb_delivery issue 59, comb_utils issue 24: move above issue to comb_utils.
|
|
392
437
|
# TODO: bfb_delivery issue 59, comb_utils issue 24:
|
|
393
438
|
# Switch to default getter if key retriever can be empty.
|
|
439
|
+
|
|
440
|
+
|
|
394
441
|
@typechecked
|
|
395
442
|
def get_responses(
|
|
396
|
-
url: str,
|
|
443
|
+
url: str,
|
|
444
|
+
paged_response_class: type[BasePagedResponseGetter],
|
|
445
|
+
params: dict[str, str] | None = None,
|
|
397
446
|
) -> list[dict[str, Any]]:
|
|
398
447
|
"""Get all responses from a paginated API endpoint.
|
|
399
448
|
|
|
400
449
|
Args:
|
|
401
450
|
url: The base URL of the API endpoint.
|
|
402
451
|
paged_response_class: The class used to get the paginated response.
|
|
452
|
+
params: The dictionary of query string parameters.
|
|
403
453
|
|
|
404
454
|
Returns:
|
|
405
455
|
A list of dictionaries containing the responses from all pages.
|
|
@@ -410,7 +460,9 @@ def get_responses(
|
|
|
410
460
|
responses = []
|
|
411
461
|
|
|
412
462
|
while next_page_salsa is not None:
|
|
413
|
-
paged_response_getter = paged_response_class(
|
|
463
|
+
paged_response_getter = paged_response_class(
|
|
464
|
+
page_url=url + str(next_page_cookie), params=params
|
|
465
|
+
)
|
|
414
466
|
paged_response_getter.call_api()
|
|
415
467
|
|
|
416
468
|
stops = paged_response_getter._response.json()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: comb_utils
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Handy utils for Python projects.
|
|
5
5
|
Author: Kaleb Coberly
|
|
6
6
|
Maintainer-email: kaleb.coberly@gmail.com
|
|
@@ -24,11 +24,10 @@ Requires-Dist: sphinx-autodoc-typehints; extra == "doc"
|
|
|
24
24
|
Provides-Extra: qc
|
|
25
25
|
Requires-Dist: bandit; extra == "qc"
|
|
26
26
|
Requires-Dist: black; extra == "qc"
|
|
27
|
-
Requires-Dist: black[jupyter]; extra == "qc"
|
|
28
27
|
Requires-Dist: flake8; extra == "qc"
|
|
29
28
|
Requires-Dist: flake8-annotations; extra == "qc"
|
|
30
29
|
Requires-Dist: flake8-bandit; extra == "qc"
|
|
31
|
-
Requires-Dist: flake8-black; extra == "qc"
|
|
30
|
+
Requires-Dist: flake8-black>=0.4.0; extra == "qc"
|
|
32
31
|
Requires-Dist: flake8-bugbear; extra == "qc"
|
|
33
32
|
Requires-Dist: flake8-docstrings; extra == "qc"
|
|
34
33
|
Requires-Dist: flake8-isort; extra == "qc"
|
|
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
|