kiba-core 0.5.3.dev68__tar.gz → 0.5.3.dev69__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 (129) hide show
  1. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/CHANGELOG.md +1 -0
  2. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/PKG-INFO +1 -1
  3. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/requester/requester.py +19 -1
  4. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/kiba_core.egg-info/PKG-INFO +1 -1
  5. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/pyproject.toml +1 -1
  6. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/requester/test_requester.py +19 -0
  7. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/.github/pull_request_template.md +0 -0
  8. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/.github/workflows/deploy.yml +0 -0
  9. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/.github/workflows/pull-request.yml +0 -0
  10. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/.github/workflows/release.yml +0 -0
  11. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/.gitignore +0 -0
  12. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/Dockerfile +0 -0
  13. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/README.md +0 -0
  14. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/__init__.py +0 -0
  15. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/__init__.py +0 -0
  16. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/api_request.py +0 -0
  17. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/api_response.py +0 -0
  18. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/authorizer.py +0 -0
  19. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/default_routes.py +0 -0
  20. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/health.py +0 -0
  21. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/json_route.py +0 -0
  22. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/middleware/__init__.py +0 -0
  23. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/middleware/database_connection_middleware.py +0 -0
  24. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/middleware/exception_handling_middleware.py +0 -0
  25. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/middleware/logging_middleware.py +0 -0
  26. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/middleware/origin_ip_middleware.py +0 -0
  27. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/middleware/server_headers_middleware.py +0 -0
  28. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/openapi.py +0 -0
  29. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/rate_limit.py +0 -0
  30. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/request_context.py +0 -0
  31. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/route.py +0 -0
  32. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/route_auth.py +0 -0
  33. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/route_metadata.py +0 -0
  34. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/api/streaming_json_route.py +0 -0
  35. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/aws_requester.py +0 -0
  36. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/caching/__init__.py +0 -0
  37. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/caching/cache.py +0 -0
  38. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/caching/dict_cache.py +0 -0
  39. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/caching/file_cache.py +0 -0
  40. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/exceptions.py +0 -0
  41. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/http/__init__.py +0 -0
  42. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/http/basic_authentication.py +0 -0
  43. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/http/jwt.py +0 -0
  44. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/http/rest_method.py +0 -0
  45. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/locks/__init__.py +0 -0
  46. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/locks/lock.py +0 -0
  47. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/locks/model.py +0 -0
  48. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/locks/sql.py +0 -0
  49. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/logging.py +0 -0
  50. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/notifications/__init__.py +0 -0
  51. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/notifications/discord_client.py +0 -0
  52. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/notifications/notification_client.py +0 -0
  53. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/notifications/slack_client.py +0 -0
  54. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/py.typed +0 -0
  55. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/queues/__init__.py +0 -0
  56. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/queues/aqs.py +0 -0
  57. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/queues/cosmos.py +0 -0
  58. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/queues/message_queue.py +0 -0
  59. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/queues/message_queue_processor.py +0 -0
  60. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/queues/model.py +0 -0
  61. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/queues/sql.py +0 -0
  62. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/queues/sqs.py +0 -0
  63. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/requester/__init__.py +0 -0
  64. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/s3_manager.py +0 -0
  65. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/service_client.py +0 -0
  66. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/store/__init__.py +0 -0
  67. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/store/database.py +0 -0
  68. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/store/retriever.py +0 -0
  69. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/store/saver.py +0 -0
  70. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/util/__init__.py +0 -0
  71. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/util/async_util.py +0 -0
  72. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/util/chain_util.py +0 -0
  73. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/util/date_util.py +0 -0
  74. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/util/dict_util.py +0 -0
  75. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/util/file_util.py +0 -0
  76. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/util/hashing_util.py +0 -0
  77. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/util/http_util.py +0 -0
  78. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/util/json_util.py +0 -0
  79. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/util/list_util.py +0 -0
  80. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/util/process_util.py +0 -0
  81. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/util/string_util.py +0 -0
  82. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/util/typing_util.py +0 -0
  83. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/util/url_util.py +0 -0
  84. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/util/value_holder.py +0 -0
  85. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/web3/__init__.py +0 -0
  86. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/web3/eth_client.py +0 -0
  87. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/core/web3/multicall3.py +0 -0
  88. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/kiba_core.egg-info/SOURCES.txt +0 -0
  89. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/kiba_core.egg-info/dependency_links.txt +0 -0
  90. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/kiba_core.egg-info/requires.txt +0 -0
  91. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/kiba_core.egg-info/top_level.txt +0 -0
  92. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/makefile +0 -0
  93. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/setup.cfg +0 -0
  94. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/__init__.py +0 -0
  95. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/api/test_api_response.py +0 -0
  96. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/api/test_authorizer.py +0 -0
  97. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/api/test_exception_handling_middleware.py +0 -0
  98. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/api/test_json_route.py +0 -0
  99. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/api/test_openapi.py +0 -0
  100. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/api/test_origin_ip_middleware.py +0 -0
  101. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/api/test_rate_limit.py +0 -0
  102. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/api/test_request_context.py +0 -0
  103. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/api/test_route.py +0 -0
  104. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/api/test_streaming_json_route.py +0 -0
  105. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/caching/test_dict_cache.py +0 -0
  106. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/caching/test_file_cache.py +0 -0
  107. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/locks/test_sql_lock.py +0 -0
  108. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/queues/conftest.py +0 -0
  109. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/queues/test_aqs_queue.py +0 -0
  110. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/queues/test_cosmos_queue.py +0 -0
  111. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/queues/test_sql_queue.py +0 -0
  112. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/queues/test_sqs_queue.py +0 -0
  113. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/requester/__init__.py +0 -0
  114. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/test_database.py +0 -0
  115. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/test_exceptions.py +0 -0
  116. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/util/__init__.py +0 -0
  117. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/util/test_async_util.py +0 -0
  118. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/util/test_chain_util.py +0 -0
  119. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/util/test_date_util.py +0 -0
  120. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/util/test_dict_util.py +0 -0
  121. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/util/test_file_util.py +0 -0
  122. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/util/test_json_util.py +0 -0
  123. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/util/test_list_util.py +0 -0
  124. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/util/test_process_util.py +0 -0
  125. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/util/test_string_util.py +0 -0
  126. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/util/test_url_util.py +0 -0
  127. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/web3/__init__.py +0 -0
  128. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/tests/web3/test_rest_eth_client.py +0 -0
  129. {kiba_core-0.5.3.dev68 → kiba_core-0.5.3.dev69}/uv.lock +0 -0
@@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
8
8
  ## [Unreleased]
9
9
 
10
10
  ### Added
11
+ - [MAJOR] Updated `Requester` to raise `RequesterTimeoutException` (a `GatewayTimeoutException`, 504) instead of `httpx` timeout exceptions; it carries the method, the URL without credentials or query string, the timeout, how long the request ran and the `httpx` timeout type, and keeps the original exception as its cause. Code catching `httpx.TimeoutException` (or `ReadTimeout`, `ConnectTimeout`, …) around `Requester` calls must catch `RequesterTimeoutException` instead
11
12
  - [PATCH] Updated `MessageQueueProcessor` failure notifications to show the exception type before its message, so failures from exceptions without text (e.g. `httpx` timeouts) are still identifiable
12
13
  - [MINOR] Added `authorize_bearer_jwt_request` for validating bearer JWTs in `RouteAuthResolver` implementations; it and `authorize_bearer_jwt` now only strip the leading `Bearer ` prefix, let cancellation propagate, and log why a JWT was rejected
13
14
  - [MINOR] Made the `route` `authResolver` optional for routes without `auth`; setting `auth` without an `authResolver` raises `ValueError` at registration
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kiba-core
3
- Version: 0.5.3.dev68
3
+ Version: 0.5.3.dev69
4
4
  Summary: Kiba Labs' python utilities
5
5
  Project-URL: repository, https://github.com/kibalabs/core-py
6
6
  Requires-Python: <4,>=3.12
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import time
2
3
  import typing
3
4
  import urllib.parse as urlparse
4
5
  from collections.abc import Mapping
@@ -13,6 +14,7 @@ import httpx2 as httpx
13
14
 
14
15
  from core import logging
15
16
  from core.exceptions import HTTP_EXCEPTIONS_MAP
17
+ from core.exceptions import GatewayTimeoutException
16
18
  from core.exceptions import KibaException
17
19
  from core.util import dict_util
18
20
  from core.util import file_util
@@ -42,6 +44,18 @@ class ResponseException(KibaException):
42
44
  self.headers = headers
43
45
 
44
46
 
47
+ class RequesterTimeoutException(GatewayTimeoutException):
48
+ def __init__(self, method: str, url: str, timeoutSeconds: float | None, durationSeconds: float, timeoutType: str) -> None:
49
+ urlParts = urlparse.urlsplit(url)
50
+ # NOTE(krishan711): drop credentials and the query string (where api keys usually live) since this message ends up in logs and notifications
51
+ self.url = urlparse.urlunsplit((urlParts.scheme, urlParts.netloc.rpartition('@')[2], urlParts.path, '', ''))
52
+ self.method = method
53
+ self.timeoutSeconds = timeoutSeconds
54
+ self.durationSeconds = durationSeconds
55
+ self.timeoutType = timeoutType
56
+ super().__init__(message=f'{method} {self.url} timed out after {durationSeconds:.1f}s ({timeoutType}, timeout {timeoutSeconds}s)')
57
+
58
+
45
59
  class Requester:
46
60
  def __init__(self, headers: Mapping[str, str] | None = None, shouldFollowRedirects: bool = True) -> None:
47
61
  self.headers = headers or {}
@@ -136,7 +150,11 @@ class Requester:
136
150
  else:
137
151
  logging.error('Error: formFiles should only be passed into POST requests.')
138
152
  request = self.client.build_request(method=method, url=url, content=content, data=innerData, files=files, timeout=timeout, headers=requestHeaders)
139
- httpxResponse = await self.client.send(request=request)
153
+ startTime = time.monotonic()
154
+ try:
155
+ httpxResponse = await self.client.send(request=request)
156
+ except httpx.TimeoutException as exception:
157
+ raise RequesterTimeoutException(method=method, url=str(request.url), timeoutSeconds=timeout, durationSeconds=time.monotonic() - startTime, timeoutType=exception.__class__.__name__) from exception
140
158
  if 400 <= httpxResponse.status_code < 600: # noqa: PLR2004
141
159
  message = httpxResponse.text
142
160
  if not message and httpxResponse.status_code == 401 and httpxResponse.headers.get('www-authenticate'): # noqa: PLR2004
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kiba-core
3
- Version: 0.5.3.dev68
3
+ Version: 0.5.3.dev69
4
4
  Summary: Kiba Labs' python utilities
5
5
  Project-URL: repository, https://github.com/kibalabs/core-py
6
6
  Requires-Python: <4,>=3.12
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kiba-core"
3
- version = "0.5.3.dev68"
3
+ version = "0.5.3.dev69"
4
4
  description = "Kiba Labs' python utilities"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12, <4"
@@ -4,6 +4,7 @@ import pytest
4
4
  from core.exceptions import NotFoundException
5
5
  from core.exceptions import TooManyRequestsException
6
6
  from core.requester.requester import Requester
7
+ from core.requester.requester import RequesterTimeoutException
7
8
 
8
9
 
9
10
  class TestRequesterExceptionHeaders:
@@ -39,3 +40,21 @@ class TestRequesterExceptionHeaders:
39
40
  requester.client = httpx.AsyncClient(transport=httpx.MockTransport(handler))
40
41
  with pytest.raises(NotFoundException):
41
42
  await requester.get(url='https://example.com/resource')
43
+
44
+
45
+ class TestRequesterTimeouts:
46
+
47
+ @pytest.mark.asyncio
48
+ async def test_timeout_raises_requester_timeout_with_request_details(self):
49
+ def handler(request: httpx.Request) -> httpx.Response:
50
+ raise httpx.ReadTimeout('', request=request)
51
+
52
+ requester = Requester()
53
+ requester.client = httpx.AsyncClient(transport=httpx.MockTransport(handler))
54
+ with pytest.raises(RequesterTimeoutException) as excInfo:
55
+ await requester.post(url='https://user:secret@example.com/v1/rpc?apiKey=secret', timeout=5)
56
+ exception = excInfo.value
57
+ assert (exception.method, exception.url, exception.timeoutSeconds, exception.timeoutType, exception.statusCode) == ('POST', 'https://example.com/v1/rpc', 5, 'ReadTimeout', 504)
58
+ assert exception.message.startswith('POST https://example.com/v1/rpc timed out after ')
59
+ assert 'secret' not in exception.message
60
+ assert isinstance(exception.__cause__, httpx.ReadTimeout)
File without changes