apitally 0.11.0__py3-none-any.whl → 0.11.2__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.
- apitally/__init__.py +1 -1
- apitally/client/asyncio.py +4 -3
- apitally/client/base.py +7 -4
- apitally/client/threading.py +1 -1
- apitally/django.py +3 -1
- apitally/starlette.py +4 -1
- {apitally-0.11.0.dist-info → apitally-0.11.2.dist-info}/METADATA +3 -2
- {apitally-0.11.0.dist-info → apitally-0.11.2.dist-info}/RECORD +10 -10
- {apitally-0.11.0.dist-info → apitally-0.11.2.dist-info}/LICENSE +0 -0
- {apitally-0.11.0.dist-info → apitally-0.11.2.dist-info}/WHEEL +0 -0
apitally/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.11.
|
1
|
+
__version__ = "0.11.2"
|
apitally/client/asyncio.py
CHANGED
@@ -28,8 +28,9 @@ class ApitallyClient(ApitallyClientBase):
|
|
28
28
|
def __init__(self, client_id: str, env: str) -> None:
|
29
29
|
super().__init__(client_id=client_id, env=env)
|
30
30
|
self._stop_sync_loop = False
|
31
|
-
self._sync_loop_task: Optional[asyncio.Task
|
31
|
+
self._sync_loop_task: Optional[asyncio.Task] = None
|
32
32
|
self._sync_data_queue: asyncio.Queue[Tuple[float, Dict[str, Any]]] = asyncio.Queue()
|
33
|
+
self._set_startup_data_task: Optional[asyncio.Task] = None
|
33
34
|
|
34
35
|
def get_http_client(self) -> httpx.AsyncClient:
|
35
36
|
return httpx.AsyncClient(base_url=self.hub_url, timeout=REQUEST_TIMEOUT)
|
@@ -67,9 +68,9 @@ class ApitallyClient(ApitallyClientBase):
|
|
67
68
|
def set_startup_data(self, data: Dict[str, Any]) -> None:
|
68
69
|
self._startup_data_sent = False
|
69
70
|
self._startup_data = self.add_uuids_to_data(data)
|
70
|
-
asyncio.create_task(self.
|
71
|
+
self._set_startup_data_task = asyncio.create_task(self._set_startup_data())
|
71
72
|
|
72
|
-
async def
|
73
|
+
async def _set_startup_data(self) -> None:
|
73
74
|
async with self.get_http_client() as client:
|
74
75
|
await self.send_startup_data(client)
|
75
76
|
|
apitally/client/base.py
CHANGED
@@ -244,6 +244,7 @@ class ServerErrorCounter:
|
|
244
244
|
self.error_counts: Counter[ServerError] = Counter()
|
245
245
|
self.sentry_event_ids: Dict[ServerError, str] = {}
|
246
246
|
self._lock = threading.Lock()
|
247
|
+
self._tasks: Set[asyncio.Task] = set()
|
247
248
|
|
248
249
|
def add_server_error(self, consumer: Optional[str], method: str, path: str, exception: BaseException) -> None:
|
249
250
|
if not isinstance(exception, BaseException):
|
@@ -267,20 +268,20 @@ class ServerErrorCounter:
|
|
267
268
|
from sentry_sdk.scope import Scope
|
268
269
|
except ImportError:
|
269
270
|
return # pragma: no cover
|
270
|
-
if not hasattr(Scope, "get_isolation_scope") or not hasattr(Scope, "
|
271
|
+
if not hasattr(Scope, "get_isolation_scope") or not hasattr(Scope, "_last_event_id"):
|
271
272
|
# sentry-sdk < 2.2.0 is not supported
|
272
273
|
return # pragma: no cover
|
273
274
|
if Hub.current.client is None:
|
274
275
|
return # sentry-sdk not initialized
|
275
276
|
|
276
277
|
scope = Scope.get_isolation_scope()
|
277
|
-
if event_id := scope.
|
278
|
+
if event_id := scope._last_event_id:
|
278
279
|
self.sentry_event_ids[server_error] = event_id
|
279
280
|
return
|
280
281
|
|
281
282
|
async def _wait_for_sentry_event_id(scope: Scope) -> None:
|
282
283
|
i = 0
|
283
|
-
while not (event_id := scope.
|
284
|
+
while not (event_id := scope._last_event_id) and i < 100:
|
284
285
|
i += 1
|
285
286
|
await asyncio.sleep(0.001)
|
286
287
|
if event_id:
|
@@ -288,7 +289,9 @@ class ServerErrorCounter:
|
|
288
289
|
|
289
290
|
with contextlib.suppress(RuntimeError): # ignore no running loop
|
290
291
|
loop = asyncio.get_running_loop()
|
291
|
-
loop.create_task(_wait_for_sentry_event_id(scope))
|
292
|
+
task = loop.create_task(_wait_for_sentry_event_id(scope))
|
293
|
+
self._tasks.add(task)
|
294
|
+
task.add_done_callback(self._tasks.discard)
|
292
295
|
|
293
296
|
def get_and_reset_server_errors(self) -> List[Dict[str, Any]]:
|
294
297
|
data: List[Dict[str, Any]] = []
|
apitally/client/threading.py
CHANGED
apitally/django.py
CHANGED
@@ -252,7 +252,9 @@ def _get_drf_schema(urlconfs: List[Optional[str]]) -> Optional[Dict[str, Any]]:
|
|
252
252
|
from rest_framework.schemas.openapi import SchemaGenerator
|
253
253
|
|
254
254
|
schemas = []
|
255
|
-
|
255
|
+
# AssertionError is raised if uritemplate or inflection are not installed (required for OpenAPI schema support)
|
256
|
+
# AttributeError is raised if app is using CoreAPI schema (deprecated) instead of OpenAPI
|
257
|
+
with contextlib.suppress(AssertionError, AttributeError):
|
256
258
|
for urlconf in urlconfs:
|
257
259
|
generator = SchemaGenerator(urlconf=urlconf)
|
258
260
|
schema = generator.get_schema()
|
apitally/starlette.py
CHANGED
@@ -44,12 +44,15 @@ class ApitallyMiddleware(BaseHTTPMiddleware):
|
|
44
44
|
self.identify_consumer_callback = identify_consumer_callback
|
45
45
|
self.client = ApitallyClient(client_id=client_id, env=env)
|
46
46
|
self.client.start_sync_loop()
|
47
|
+
self._delayed_set_startup_data_task: Optional[asyncio.Task] = None
|
47
48
|
self.delayed_set_startup_data(app_version, openapi_url)
|
48
49
|
_register_shutdown_handler(app, self.client.handle_shutdown)
|
49
50
|
super().__init__(app)
|
50
51
|
|
51
52
|
def delayed_set_startup_data(self, app_version: Optional[str] = None, openapi_url: Optional[str] = None) -> None:
|
52
|
-
asyncio.create_task(
|
53
|
+
self._delayed_set_startup_data_task = asyncio.create_task(
|
54
|
+
self._delayed_set_startup_data(app_version, openapi_url)
|
55
|
+
)
|
53
56
|
|
54
57
|
async def _delayed_set_startup_data(
|
55
58
|
self, app_version: Optional[str] = None, openapi_url: Optional[str] = None
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: apitally
|
3
|
-
Version: 0.11.
|
3
|
+
Version: 0.11.2
|
4
4
|
Summary: Simple API monitoring & analytics for REST APIs built with FastAPI, Flask, Django, Starlette and Litestar.
|
5
5
|
Home-page: https://apitally.io
|
6
6
|
License: MIT
|
@@ -29,7 +29,8 @@ Provides-Extra: litestar
|
|
29
29
|
Provides-Extra: sentry
|
30
30
|
Provides-Extra: starlette
|
31
31
|
Requires-Dist: backoff (>=2.0.0)
|
32
|
-
Requires-Dist: django (>=2.2) ; extra == "django-ninja" or extra == "django-rest-framework"
|
32
|
+
Requires-Dist: django (>=2.2) ; (python_version >= "3.10") and (extra == "django-ninja" or extra == "django-rest-framework")
|
33
|
+
Requires-Dist: django (>=2.2,<5) ; (python_version < "3.10") and (extra == "django-ninja" or extra == "django-rest-framework")
|
33
34
|
Requires-Dist: django-ninja (>=0.18.0) ; extra == "django-ninja"
|
34
35
|
Requires-Dist: djangorestframework (>=3.10.0) ; extra == "django-rest-framework"
|
35
36
|
Requires-Dist: fastapi (>=0.87.0) ; extra == "fastapi"
|
@@ -1,19 +1,19 @@
|
|
1
|
-
apitally/__init__.py,sha256=
|
1
|
+
apitally/__init__.py,sha256=bmMNWd6X6fx5JJd3CqzukH9Aez4xKCZuJNcmMU1pbEc,23
|
2
2
|
apitally/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
apitally/client/asyncio.py,sha256=
|
4
|
-
apitally/client/base.py,sha256=
|
3
|
+
apitally/client/asyncio.py,sha256=L8cnh2Pd_abC9Y5dnoH18kPHjcQ1n_ngmJJu7yU1G2Q,4774
|
4
|
+
apitally/client/base.py,sha256=v4LSOYNIOoeL3KTVyBlXBY5LCXc79Lvu9yK5Y_KILSQ,15442
|
5
5
|
apitally/client/logging.py,sha256=QMsKIIAFo92PNBUleeTgsrsQa7SEal-oJa1oOHUr1wI,507
|
6
|
-
apitally/client/threading.py,sha256=
|
6
|
+
apitally/client/threading.py,sha256=NhKgA8b9F1Sa0BdnTCcyVyWKI6vy9shGF9umG70kpfc,5113
|
7
7
|
apitally/common.py,sha256=GbVmnXxhRvV30d7CfCQ9r0AeXj14Mv9Jm_Yd1bRWP28,1088
|
8
|
-
apitally/django.py,sha256=
|
8
|
+
apitally/django.py,sha256=vqBloQH4WaxvIlVpDZoazPcj5ljFapi1kvUHRgkd0O4,13763
|
9
9
|
apitally/django_ninja.py,sha256=dqQtnz2s8YWYHCwvkK5BjokjvpZJpPNhP0vng4kFtrQ,120
|
10
10
|
apitally/django_rest_framework.py,sha256=dqQtnz2s8YWYHCwvkK5BjokjvpZJpPNhP0vng4kFtrQ,120
|
11
11
|
apitally/fastapi.py,sha256=hEyYZsvIaA3OXZSSFdey5iqeEjfBPHgfNbyX8pLm7GI,123
|
12
12
|
apitally/flask.py,sha256=KZxWN1xeXUazYYluu3aoKkZQ_aRljHmtjZi1AxvzpGw,6402
|
13
13
|
apitally/litestar.py,sha256=sQcrHw-JV9AlpnXlrczmaDe0k6tD9PYQsc8nyQul8Ko,8802
|
14
14
|
apitally/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
|
-
apitally/starlette.py,sha256=
|
16
|
-
apitally-0.11.
|
17
|
-
apitally-0.11.
|
18
|
-
apitally-0.11.
|
19
|
-
apitally-0.11.
|
15
|
+
apitally/starlette.py,sha256=tizWLlKMltKU1w3pUqa4EHfY3wjneUVZyvndmgl82c4,8747
|
16
|
+
apitally-0.11.2.dist-info/LICENSE,sha256=vbLzC-4TddtXX-_AFEBKMYWRlxC_MN0g66QhPxo8PgY,1065
|
17
|
+
apitally-0.11.2.dist-info/METADATA,sha256=enN-rzxB2Ooc8jFKhJrksz4cxrRH39f_43TkpW3ksrQ,6994
|
18
|
+
apitally-0.11.2.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
|
19
|
+
apitally-0.11.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|