apitally 0.16.1__py3-none-any.whl → 0.16.3__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/client/client_asyncio.py +1 -7
- apitally/client/client_threading.py +1 -3
- apitally/django.py +1 -1
- apitally/flask.py +1 -1
- apitally/starlette.py +40 -20
- {apitally-0.16.1.dist-info → apitally-0.16.3.dist-info}/METADATA +4 -4
- {apitally-0.16.1.dist-info → apitally-0.16.3.dist-info}/RECORD +9 -9
- {apitally-0.16.1.dist-info → apitally-0.16.3.dist-info}/WHEEL +0 -0
- {apitally-0.16.1.dist-info → apitally-0.16.3.dist-info}/licenses/LICENSE +0 -0
@@ -41,7 +41,6 @@ class ApitallyClient(ApitallyClientBase):
|
|
41
41
|
self._stop_sync_loop = False
|
42
42
|
self._sync_loop_task: Optional[asyncio.Task] = None
|
43
43
|
self._sync_data_queue: asyncio.Queue[Dict[str, Any]] = asyncio.Queue()
|
44
|
-
self._set_startup_data_task: Optional[asyncio.Task] = None
|
45
44
|
|
46
45
|
def get_http_client(self) -> httpx.AsyncClient:
|
47
46
|
if httpx.__version__ >= "0.26.0":
|
@@ -67,7 +66,7 @@ class ApitallyClient(ApitallyClientBase):
|
|
67
66
|
try:
|
68
67
|
async with self.get_http_client() as client:
|
69
68
|
tasks = [self.send_sync_data(client), self.send_log_data(client)]
|
70
|
-
if not self._startup_data_sent
|
69
|
+
if not self._startup_data_sent:
|
71
70
|
tasks.append(self.send_startup_data(client))
|
72
71
|
await asyncio.gather(*tasks)
|
73
72
|
last_sync_time = now
|
@@ -92,11 +91,6 @@ class ApitallyClient(ApitallyClientBase):
|
|
92
91
|
def set_startup_data(self, data: Dict[str, Any]) -> None:
|
93
92
|
self._startup_data_sent = False
|
94
93
|
self._startup_data = self.add_uuids_to_data(data)
|
95
|
-
self._set_startup_data_task = asyncio.create_task(self._set_startup_data())
|
96
|
-
|
97
|
-
async def _set_startup_data(self) -> None:
|
98
|
-
async with self.get_http_client() as client:
|
99
|
-
await self.send_startup_data(client)
|
100
94
|
|
101
95
|
async def send_startup_data(self, client: httpx.AsyncClient) -> None:
|
102
96
|
if self._startup_data is not None:
|
@@ -80,7 +80,7 @@ class ApitallyClient(ApitallyClientBase):
|
|
80
80
|
if (now - last_sync_time) >= self.sync_interval:
|
81
81
|
try:
|
82
82
|
with requests.Session() as session:
|
83
|
-
if not self._startup_data_sent
|
83
|
+
if not self._startup_data_sent:
|
84
84
|
self.send_startup_data(session)
|
85
85
|
self.send_sync_data(session)
|
86
86
|
self.send_log_data(session)
|
@@ -105,8 +105,6 @@ class ApitallyClient(ApitallyClientBase):
|
|
105
105
|
def set_startup_data(self, data: Dict[str, Any]) -> None:
|
106
106
|
self._startup_data_sent = False
|
107
107
|
self._startup_data = self.add_uuids_to_data(data)
|
108
|
-
with requests.Session() as session:
|
109
|
-
self.send_startup_data(session)
|
110
108
|
|
111
109
|
def send_startup_data(self, session: requests.Session) -> None:
|
112
110
|
if self._startup_data is not None:
|
apitally/django.py
CHANGED
@@ -75,13 +75,13 @@ class ApitallyMiddleware:
|
|
75
75
|
request_logging_config=self.config.request_logging_config,
|
76
76
|
proxy=self.config.proxy,
|
77
77
|
)
|
78
|
-
self.client.start_sync_loop()
|
79
78
|
self.client.set_startup_data(
|
80
79
|
_get_startup_data(
|
81
80
|
app_version=self.config.app_version,
|
82
81
|
urlconfs=self.config.urlconfs,
|
83
82
|
)
|
84
83
|
)
|
84
|
+
self.client.start_sync_loop()
|
85
85
|
|
86
86
|
self.capture_request_body = (
|
87
87
|
self.client.request_logger.config.enabled and self.client.request_logger.config.log_request_body
|
apitally/flask.py
CHANGED
@@ -51,7 +51,6 @@ class ApitallyMiddleware:
|
|
51
51
|
request_logging_config=request_logging_config,
|
52
52
|
proxy=proxy,
|
53
53
|
)
|
54
|
-
self.client.start_sync_loop()
|
55
54
|
self.delayed_set_startup_data(app_version, openapi_url)
|
56
55
|
|
57
56
|
self.capture_request_body = (
|
@@ -73,6 +72,7 @@ class ApitallyMiddleware:
|
|
73
72
|
def _delayed_set_startup_data(self, app_version: Optional[str] = None, openapi_url: Optional[str] = None) -> None:
|
74
73
|
data = _get_startup_data(self.app, app_version, openapi_url)
|
75
74
|
self.client.set_startup_data(data)
|
75
|
+
self.client.start_sync_loop()
|
76
76
|
|
77
77
|
def __call__(self, environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]:
|
78
78
|
if not self.client.enabled:
|
apitally/starlette.py
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
import asyncio
|
4
3
|
import time
|
5
|
-
from
|
4
|
+
from contextlib import asynccontextmanager
|
5
|
+
from typing import Any, Awaitable, Callable, Dict, List, Optional, Union
|
6
6
|
from warnings import warn
|
7
7
|
|
8
8
|
from httpx import HTTPStatusError, Proxy
|
9
|
+
from starlette.applications import Starlette
|
9
10
|
from starlette.datastructures import Headers
|
10
11
|
from starlette.requests import Request
|
11
12
|
from starlette.routing import BaseRoute, Match, Router
|
12
13
|
from starlette.schemas import EndpointInfo, SchemaGenerator
|
13
14
|
from starlette.testclient import TestClient
|
14
|
-
from starlette.types import ASGIApp, Message, Receive, Scope, Send
|
15
|
+
from starlette.types import ASGIApp, Lifespan, Message, Receive, Scope, Send
|
15
16
|
|
16
17
|
from apitally.client.client_asyncio import ApitallyClient
|
17
18
|
from apitally.client.consumers import Consumer as ApitallyConsumer
|
@@ -40,6 +41,8 @@ class ApitallyMiddleware:
|
|
40
41
|
proxy: Optional[Union[str, Proxy]] = None,
|
41
42
|
) -> None:
|
42
43
|
self.app = app
|
44
|
+
self.app_version = app_version
|
45
|
+
self.openapi_url = openapi_url
|
43
46
|
self.identify_consumer_callback = identify_consumer_callback
|
44
47
|
self.client = ApitallyClient(
|
45
48
|
client_id=client_id,
|
@@ -47,10 +50,6 @@ class ApitallyMiddleware:
|
|
47
50
|
request_logging_config=request_logging_config,
|
48
51
|
proxy=proxy,
|
49
52
|
)
|
50
|
-
self.client.start_sync_loop()
|
51
|
-
self._delayed_set_startup_data_task: Optional[asyncio.Task] = None
|
52
|
-
self.delayed_set_startup_data(app_version, openapi_url)
|
53
|
-
_register_shutdown_handler(app, self.client.handle_shutdown)
|
54
53
|
|
55
54
|
self.capture_request_body = (
|
56
55
|
self.client.request_logger.config.enabled and self.client.request_logger.config.log_request_body
|
@@ -59,17 +58,16 @@ class ApitallyMiddleware:
|
|
59
58
|
self.client.request_logger.config.enabled and self.client.request_logger.config.log_response_body
|
60
59
|
)
|
61
60
|
|
62
|
-
|
63
|
-
|
64
|
-
self.
|
61
|
+
_inject_lifespan_handlers(
|
62
|
+
app,
|
63
|
+
on_startup=self.on_startup,
|
64
|
+
on_shutdown=self.client.handle_shutdown,
|
65
65
|
)
|
66
66
|
|
67
|
-
async def
|
68
|
-
self, app_version
|
69
|
-
) -> None:
|
70
|
-
await asyncio.sleep(1.0) # Short delay to allow app routes to be registered first
|
71
|
-
data = _get_startup_data(self.app, app_version, openapi_url)
|
67
|
+
async def on_startup(self) -> None:
|
68
|
+
data = _get_startup_data(self.app, app_version=self.app_version, openapi_url=self.openapi_url)
|
72
69
|
self.client.set_startup_data(data)
|
70
|
+
self.client.start_sync_loop()
|
73
71
|
|
74
72
|
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
|
75
73
|
if self.client.enabled and scope["type"] == "http" and scope["method"] != "OPTIONS":
|
@@ -296,8 +294,30 @@ def _get_routes(app: Union[ASGIApp, Router]) -> List[BaseRoute]:
|
|
296
294
|
return [] # pragma: no cover
|
297
295
|
|
298
296
|
|
299
|
-
def
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
297
|
+
def _inject_lifespan_handlers(
|
298
|
+
app: Union[ASGIApp, Router],
|
299
|
+
on_startup: Callable[[], Awaitable[Any]],
|
300
|
+
on_shutdown: Callable[[], Awaitable[Any]],
|
301
|
+
) -> None:
|
302
|
+
"""
|
303
|
+
Ensures the given startup and shutdown functions are called as part of the app's lifespan context manager.
|
304
|
+
"""
|
305
|
+
router = app
|
306
|
+
while not isinstance(router, Router) and hasattr(router, "app"):
|
307
|
+
router = router.app
|
308
|
+
if not isinstance(router, Router):
|
309
|
+
raise TypeError("app must be a Starlette or Router instance")
|
310
|
+
|
311
|
+
lifespan: Optional[Lifespan] = getattr(router, "lifespan_context", None)
|
312
|
+
|
313
|
+
@asynccontextmanager
|
314
|
+
async def wrapped_lifespan(app: Starlette):
|
315
|
+
await on_startup()
|
316
|
+
if lifespan is not None:
|
317
|
+
async with lifespan(app):
|
318
|
+
yield
|
319
|
+
else:
|
320
|
+
yield
|
321
|
+
await on_shutdown()
|
322
|
+
|
323
|
+
router.lifespan_context = wrapped_lifespan
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: apitally
|
3
|
-
Version: 0.16.
|
3
|
+
Version: 0.16.3
|
4
4
|
Summary: Simple API monitoring & analytics for REST APIs built with FastAPI, Flask, Django, Starlette, Litestar and BlackSheep.
|
5
5
|
Project-URL: Homepage, https://apitally.io
|
6
6
|
Project-URL: Documentation, https://docs.apitally.io
|
@@ -49,9 +49,9 @@ Requires-Dist: inflection>=0.5.1; extra == 'django-rest-framework'
|
|
49
49
|
Requires-Dist: requests>=2.26.0; extra == 'django-rest-framework'
|
50
50
|
Requires-Dist: uritemplate>=3.0.0; extra == 'django-rest-framework'
|
51
51
|
Provides-Extra: fastapi
|
52
|
-
Requires-Dist: fastapi>=0.
|
52
|
+
Requires-Dist: fastapi>=0.94.1; extra == 'fastapi'
|
53
53
|
Requires-Dist: httpx>=0.22.0; extra == 'fastapi'
|
54
|
-
Requires-Dist: starlette<1.0.0,>=0.
|
54
|
+
Requires-Dist: starlette<1.0.0,>=0.26.1; extra == 'fastapi'
|
55
55
|
Provides-Extra: flask
|
56
56
|
Requires-Dist: flask>=2.0.0; extra == 'flask'
|
57
57
|
Requires-Dist: requests>=2.26.0; extra == 'flask'
|
@@ -62,7 +62,7 @@ Provides-Extra: sentry
|
|
62
62
|
Requires-Dist: sentry-sdk>=2.2.0; extra == 'sentry'
|
63
63
|
Provides-Extra: starlette
|
64
64
|
Requires-Dist: httpx>=0.22.0; extra == 'starlette'
|
65
|
-
Requires-Dist: starlette<1.0.0,>=0.
|
65
|
+
Requires-Dist: starlette<1.0.0,>=0.26.1; extra == 'starlette'
|
66
66
|
Description-Content-Type: text/markdown
|
67
67
|
|
68
68
|
<p align="center">
|
@@ -1,18 +1,18 @@
|
|
1
1
|
apitally/__init__.py,sha256=ShXQBVjyiSOHxoQJS2BvNG395W4KZfqMxZWBAR0MZrE,22
|
2
2
|
apitally/blacksheep.py,sha256=KvcPFeiwQgWZmRglbm8SLaN6_WRs5kZ3SymB1IuLR-A,9616
|
3
3
|
apitally/common.py,sha256=azDxepViH0QW0MuufTHxeSQyLGzCkocAX_KPziWTx8A,1605
|
4
|
-
apitally/django.py,sha256=
|
4
|
+
apitally/django.py,sha256=f_k7yYlvvvhJMR53NcXCfmlLxLX3CeLO9ephF4bzKbo,16892
|
5
5
|
apitally/django_ninja.py,sha256=-CmrwFFRv7thFOUK_OrOSouhHL9bm5sIBNIQlpyE_2c,166
|
6
6
|
apitally/django_rest_framework.py,sha256=-CmrwFFRv7thFOUK_OrOSouhHL9bm5sIBNIQlpyE_2c,166
|
7
7
|
apitally/fastapi.py,sha256=IfKfgsmIY8_AtnuMTW2sW4qnkya61CAE2vBoIpcc9tk,169
|
8
|
-
apitally/flask.py,sha256=
|
8
|
+
apitally/flask.py,sha256=OoCEnjtnD51GUGq-adK80ebuiLj-5HXubxffCv5XTCM,9622
|
9
9
|
apitally/litestar.py,sha256=mHoMqBO_gyoopeHljY8e8GTcV29UDf3uhQMxY3GeNpA,13451
|
10
10
|
apitally/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
-
apitally/starlette.py,sha256=
|
11
|
+
apitally/starlette.py,sha256=081vXTNOy6-zZ8ugXknRtQZnFFqG7XKLW4Ho6oaHEUY,13525
|
12
12
|
apitally/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
-
apitally/client/client_asyncio.py,sha256=
|
13
|
+
apitally/client/client_asyncio.py,sha256=rTsH5wlLHK3RmyIuEiT6vzjquU-l2OPC34JnC2U6uYw,6658
|
14
14
|
apitally/client/client_base.py,sha256=DvivGeHd3dyOASRvkIo44Zh8RzdBMfH8_rROa2lFbgw,3799
|
15
|
-
apitally/client/client_threading.py,sha256=
|
15
|
+
apitally/client/client_threading.py,sha256=sxMRcxRgk1SxJjSq-qpIcDVmD3Q7Kv4CVT5zEUVt0KM,7257
|
16
16
|
apitally/client/consumers.py,sha256=w_AFQhVgdtJVt7pVySBvSZwQg-2JVqmD2JQtVBoMkus,2626
|
17
17
|
apitally/client/logging.py,sha256=QMsKIIAFo92PNBUleeTgsrsQa7SEal-oJa1oOHUr1wI,507
|
18
18
|
apitally/client/request_logging.py,sha256=SMvQd3WDolnb8u9rHVh2_OgXwFjL2jLZt-GpZNQ1XGk,14115
|
@@ -20,7 +20,7 @@ apitally/client/requests.py,sha256=SDptGOg9XvaEKFj2o3oxJz-JAuZzUrqpHnbOQixf99o,3
|
|
20
20
|
apitally/client/sentry.py,sha256=qMjHdI0V7c50ruo1WjmjWc8g6oGDv724vSCvcuZ8G9k,1188
|
21
21
|
apitally/client/server_errors.py,sha256=4B2BKDFoIpoWc55UVH6AIdYSgzj6zxCdMNUW77JjhZw,3423
|
22
22
|
apitally/client/validation_errors.py,sha256=6G8WYWFgJs9VH9swvkPXJGuOJgymj5ooWA9OwjUTbuM,1964
|
23
|
-
apitally-0.16.
|
24
|
-
apitally-0.16.
|
25
|
-
apitally-0.16.
|
26
|
-
apitally-0.16.
|
23
|
+
apitally-0.16.3.dist-info/METADATA,sha256=NbeWFQBfMfdu1Ao_0zGhBTMsNO3m1xmWZ6KNhGe2qNQ,9321
|
24
|
+
apitally-0.16.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
25
|
+
apitally-0.16.3.dist-info/licenses/LICENSE,sha256=vbLzC-4TddtXX-_AFEBKMYWRlxC_MN0g66QhPxo8PgY,1065
|
26
|
+
apitally-0.16.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|