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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: comb_utils
3
- Version: 0.2.8
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.2.8
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, paged_response_class: type[BasePagedResponseGetter]
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(page_url=url + str(next_page_cookie))
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()
@@ -0,0 +1,9 @@
1
+ """Module for custom exceptions."""
2
+
3
+
4
+ class CombUtilsError(Exception):
5
+ """Base class for exceptions in this module."""
6
+
7
+
8
+ class DuplicateKeysDetected(CombUtilsError):
9
+ """Raised when a user enters a query string key twice."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: comb_utils
3
- Version: 0.2.8
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"
@@ -11,4 +11,5 @@ src/comb_utils.egg-info/top_level.txt
11
11
  src/comb_utils/lib/__init__.py
12
12
  src/comb_utils/lib/api_callers.py
13
13
  src/comb_utils/lib/constants.py
14
- src/comb_utils/lib/docs.py
14
+ src/comb_utils/lib/docs.py
15
+ src/comb_utils/lib/errors.py
@@ -19,11 +19,10 @@ sphinx-autodoc-typehints
19
19
  [qc]
20
20
  bandit
21
21
  black
22
- black[jupyter]
23
22
  flake8
24
23
  flake8-annotations
25
24
  flake8-bandit
26
- flake8-black
25
+ flake8-black>=0.4.0
27
26
  flake8-bugbear
28
27
  flake8-docstrings
29
28
  flake8-isort
File without changes
File without changes
File without changes