apitally 0.19.1__py3-none-any.whl → 0.20.1__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/blacksheep.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import time
2
2
  from typing import Any, Awaitable, Callable, Dict, List, Optional, Tuple, Union
3
+ from warnings import warn
3
4
 
4
5
  from blacksheep import Application, Headers, Request, Response
5
6
  from blacksheep.server.openapi.v3 import Info, OpenAPIHandler, Operation
@@ -12,21 +13,51 @@ from apitally.client.request_logging import (
12
13
  MAX_BODY_SIZE,
13
14
  RequestLogger,
14
15
  RequestLoggingConfig,
16
+ RequestLoggingKwargs,
15
17
  )
16
18
  from apitally.common import get_versions, parse_int
17
19
 
18
20
 
19
- __all__ = ["use_apitally", "ApitallyMiddleware", "ApitallyConsumer", "RequestLoggingConfig"]
21
+ try:
22
+ from typing import Unpack
23
+ except ImportError:
24
+ from typing_extensions import Unpack
25
+
26
+
27
+ __all__ = ["use_apitally", "ApitallyConsumer", "RequestLoggingConfig"]
20
28
 
21
29
 
22
30
  def use_apitally(
23
31
  app: Application,
24
32
  client_id: str,
25
33
  env: str = "dev",
26
- request_logging_config: Optional[RequestLoggingConfig] = None,
27
34
  app_version: Optional[str] = None,
35
+ consumer_callback: Optional[Callable[[Request], Union[str, ApitallyConsumer, None]]] = None,
28
36
  identify_consumer_callback: Optional[Callable[[Request], Union[str, ApitallyConsumer, None]]] = None,
37
+ request_logging_config: Optional[RequestLoggingConfig] = None,
38
+ **kwargs: Unpack[RequestLoggingKwargs],
29
39
  ) -> None:
40
+ """
41
+ Use the Apitally middleware for BlackSheep applications.
42
+
43
+ For more information, see:
44
+ - Setup guide: https://docs.apitally.io/frameworks/blacksheep
45
+ - Reference: https://docs.apitally.io/reference/python
46
+ """
47
+
48
+ if identify_consumer_callback is not None:
49
+ warn(
50
+ "The 'identify_consumer_callback' parameter is deprecated, use 'consumer_callback' instead.",
51
+ DeprecationWarning,
52
+ stacklevel=2,
53
+ )
54
+ if request_logging_config is not None:
55
+ warn(
56
+ "The 'request_logging_config' parameter is deprecated, use keyword arguments instead.",
57
+ DeprecationWarning,
58
+ stacklevel=2,
59
+ )
60
+
30
61
  original_get_match = app.router.get_match
31
62
 
32
63
  def _wrapped_router_get_match(request: Request) -> Optional[RouteMatch]:
@@ -37,13 +68,16 @@ def use_apitally(
37
68
 
38
69
  app.router.get_match = _wrapped_router_get_match # type: ignore[assignment,method-assign]
39
70
 
71
+ if kwargs and request_logging_config is None:
72
+ request_logging_config = RequestLoggingConfig.from_kwargs(kwargs)
73
+
40
74
  middleware = ApitallyMiddleware(
41
75
  app,
42
76
  client_id,
43
77
  env=env,
44
78
  request_logging_config=request_logging_config,
45
79
  app_version=app_version,
46
- identify_consumer_callback=identify_consumer_callback,
80
+ consumer_callback=consumer_callback or identify_consumer_callback,
47
81
  )
48
82
  app.middlewares.append(middleware)
49
83
 
@@ -56,11 +90,11 @@ class ApitallyMiddleware:
56
90
  env: str = "dev",
57
91
  request_logging_config: Optional[RequestLoggingConfig] = None,
58
92
  app_version: Optional[str] = None,
59
- identify_consumer_callback: Optional[Callable[[Request], Union[str, ApitallyConsumer, None]]] = None,
93
+ consumer_callback: Optional[Callable[[Request], Union[str, ApitallyConsumer, None]]] = None,
60
94
  ) -> None:
61
95
  self.app = app
62
96
  self.app_version = app_version
63
- self.identify_consumer_callback = identify_consumer_callback
97
+ self.consumer_callback = consumer_callback
64
98
  self.client = ApitallyClient(
65
99
  client_id=client_id,
66
100
  env=env,
@@ -88,13 +122,13 @@ class ApitallyMiddleware:
88
122
  identity = request.user or request.identity or None
89
123
  if identity is not None and identity.has_claim("apitally_consumer"):
90
124
  return ApitallyConsumer.from_string_or_object(identity.get("apitally_consumer"))
91
- if self.identify_consumer_callback is not None:
92
- consumer = self.identify_consumer_callback(request)
125
+ if self.consumer_callback is not None:
126
+ consumer = self.consumer_callback(request)
93
127
  return ApitallyConsumer.from_string_or_object(consumer)
94
128
  return None
95
129
 
96
130
  async def __call__(self, request: Request, handler: Callable[[Request], Awaitable[Response]]) -> Response:
97
- if not self.client.enabled:
131
+ if not self.client.enabled or request.method.upper() == "OPTIONS":
98
132
  return await handler(request)
99
133
 
100
134
  timestamp = time.time()
@@ -154,7 +188,7 @@ class ApitallyMiddleware:
154
188
  if response_size is None or response_size < 0:
155
189
  response_size = len(response_body)
156
190
 
157
- if route_pattern and request.method.upper() != "OPTIONS":
191
+ if route_pattern:
158
192
  self.client.request_counter.add_request(
159
193
  consumer=consumer_identifier,
160
194
  method=request.method.upper(),
@@ -217,7 +251,7 @@ def _get_startup_data(app: Application, app_version: Optional[str] = None) -> Di
217
251
  def _get_paths(app: Application) -> List[Dict[str, str]]:
218
252
  openapi = OpenAPIHandler(info=Info(title="", version=""))
219
253
  paths = []
220
- methods = ("get", "put", "post", "delete", "options", "head", "patch", "trace")
254
+ methods = ("get", "put", "post", "delete", "patch")
221
255
  for path, path_item in openapi.get_paths(app).items():
222
256
  for method in methods:
223
257
  operation: Operation = getattr(path_item, method, None)
@@ -118,28 +118,25 @@ class RequestLogItem(TypedDict):
118
118
  exception: NotRequired[ExceptionDict]
119
119
 
120
120
 
121
+ class RequestLoggingKwargs(TypedDict, total=False):
122
+ enable_request_logging: bool
123
+ log_query_params: bool
124
+ log_request_headers: bool
125
+ log_request_body: bool
126
+ log_response_headers: bool
127
+ log_response_body: bool
128
+ log_exception: bool
129
+ mask_query_params: List[str]
130
+ mask_headers: List[str]
131
+ mask_body_fields: List[str]
132
+ mask_request_body_callback: Optional[Callable[[RequestDict], Optional[bytes]]]
133
+ mask_response_body_callback: Optional[Callable[[RequestDict, ResponseDict], Optional[bytes]]]
134
+ exclude_paths: List[str]
135
+ exclude_callback: Optional[Callable[[RequestDict, ResponseDict], bool]]
136
+
137
+
121
138
  @dataclass
122
139
  class RequestLoggingConfig:
123
- """
124
- Configuration for request logging.
125
-
126
- Attributes:
127
- enabled: Whether request logging is enabled
128
- log_query_params: Whether to log query parameter values
129
- log_request_headers: Whether to log request header values
130
- log_request_body: Whether to log the request body (only if JSON or plain text)
131
- log_response_headers: Whether to log response header values
132
- log_response_body: Whether to log the response body (only if JSON or plain text)
133
- log_exception: Whether to log unhandled exceptions in case of server errors
134
- mask_query_params: Query parameter names to mask in logs. Expects regular expressions.
135
- mask_headers: Header names to mask in logs. Expects regular expressions.
136
- mask_body_fields: Body fields to mask in logs. Expects regular expressions.
137
- mask_request_body_callback: Callback to mask the request body. Expects `request: RequestDict` as argument and returns the masked body as bytes or None.
138
- mask_response_body_callback: Callback to mask the response body. Expects `request: RequestDict` and `response: ResponseDict` as arguments and returns the masked body as bytes or None.
139
- exclude_paths: Paths to exclude from logging. Expects regular expressions.
140
- exclude_callback: Callback to exclude requests from logging. Should expect two arguments, `request: RequestDict` and `response: ResponseDict`, and return True to exclude the request.
141
- """
142
-
143
140
  enabled: bool = False
144
141
  log_query_params: bool = True
145
142
  log_request_headers: bool = False
@@ -155,6 +152,12 @@ class RequestLoggingConfig:
155
152
  exclude_paths: List[str] = field(default_factory=list)
156
153
  exclude_callback: Optional[Callable[[RequestDict, ResponseDict], bool]] = None
157
154
 
155
+ @classmethod
156
+ def from_kwargs(cls, kwargs: RequestLoggingKwargs) -> "RequestLoggingConfig":
157
+ enabled = kwargs.get("enable_request_logging", False)
158
+ config_kwargs: dict[str, Any] = {k: v for k, v in kwargs.items() if k in cls.__dataclass_fields__}
159
+ return RequestLoggingConfig(enabled=enabled, **config_kwargs)
160
+
158
161
 
159
162
  class TempGzipFile:
160
163
  def __init__(self) -> None:
apitally/django.py CHANGED
@@ -23,16 +23,23 @@ from apitally.client.request_logging import (
23
23
  MAX_BODY_SIZE,
24
24
  RequestLogger,
25
25
  RequestLoggingConfig,
26
+ RequestLoggingKwargs,
26
27
  )
27
28
  from apitally.common import get_versions, parse_int, try_json_loads
28
29
 
29
30
 
31
+ try:
32
+ from typing import Unpack
33
+ except ImportError:
34
+ from typing_extensions import Unpack
35
+
30
36
  if TYPE_CHECKING:
31
37
  from django.http import HttpRequest, HttpResponse
32
38
  from ninja import NinjaAPI
33
39
 
34
40
 
35
41
  __all__ = ["ApitallyMiddleware", "ApitallyConsumer", "RequestLoggingConfig"]
42
+
36
43
  logger = get_logger(__name__)
37
44
 
38
45
 
@@ -40,9 +47,9 @@ logger = get_logger(__name__)
40
47
  class ApitallyMiddlewareConfig:
41
48
  client_id: str
42
49
  env: str
43
- request_logging_config: Optional[RequestLoggingConfig]
44
50
  app_version: Optional[str]
45
- identify_consumer_callback: Optional[Callable[[HttpRequest], Union[str, ApitallyConsumer, None]]]
51
+ request_logging_config: Optional[RequestLoggingConfig]
52
+ consumer_callback: Optional[Callable[[HttpRequest], Union[str, ApitallyConsumer, None]]]
46
53
  include_django_views: bool
47
54
  urlconfs: List[Optional[str]]
48
55
  proxy: Optional[str]
@@ -102,21 +109,39 @@ class ApitallyMiddleware:
102
109
  cls,
103
110
  client_id: str,
104
111
  env: str = "dev",
105
- request_logging_config: Optional[RequestLoggingConfig] = None,
106
112
  app_version: Optional[str] = None,
107
- identify_consumer_callback: Optional[str] = None,
113
+ consumer_callback: Optional[str] = None,
108
114
  include_django_views: bool = False,
109
115
  urlconf: Optional[Union[List[Optional[str]], str]] = None,
110
116
  proxy: Optional[str] = None,
117
+ identify_consumer_callback: Optional[str] = None,
118
+ request_logging_config: Optional[RequestLoggingConfig] = None,
119
+ **kwargs: Unpack[RequestLoggingKwargs],
111
120
  ) -> None:
121
+ if identify_consumer_callback is not None:
122
+ warn(
123
+ "The 'identify_consumer_callback' setting is deprecated, use 'consumer_callback' instead.",
124
+ DeprecationWarning,
125
+ stacklevel=2,
126
+ )
127
+ if request_logging_config is not None:
128
+ warn(
129
+ "The nested 'request_logging_config' setting is deprecated, use top-level settings instead.",
130
+ DeprecationWarning,
131
+ stacklevel=2,
132
+ )
133
+
134
+ if identify_consumer_callback and not consumer_callback:
135
+ consumer_callback = identify_consumer_callback
136
+ if kwargs and request_logging_config is None:
137
+ request_logging_config = RequestLoggingConfig.from_kwargs(kwargs)
138
+
112
139
  cls.config = ApitallyMiddlewareConfig(
113
140
  client_id=client_id,
114
141
  env=env,
115
142
  request_logging_config=request_logging_config,
116
143
  app_version=app_version,
117
- identify_consumer_callback=import_string(identify_consumer_callback)
118
- if identify_consumer_callback
119
- else None,
144
+ consumer_callback=import_string(consumer_callback) if consumer_callback else None,
120
145
  include_django_views=include_django_views,
121
146
  urlconfs=[urlconf] if urlconf is None or isinstance(urlconf, str) else urlconf,
122
147
  proxy=proxy,
@@ -270,8 +295,8 @@ class ApitallyMiddleware:
270
295
  DeprecationWarning,
271
296
  )
272
297
  return ApitallyConsumer.from_string_or_object(request.consumer_identifier)
273
- if self.config is not None and self.config.identify_consumer_callback is not None:
274
- consumer = self.config.identify_consumer_callback(request)
298
+ if self.config is not None and self.config.consumer_callback is not None:
299
+ consumer = self.config.consumer_callback(request)
275
300
  return ApitallyConsumer.from_string_or_object(consumer)
276
301
  return None
277
302
 
apitally/fastapi.py CHANGED
@@ -1,4 +1,17 @@
1
- from apitally.starlette import ApitallyConsumer, ApitallyMiddleware, RequestLoggingConfig, set_consumer
1
+ from apitally.starlette import ApitallyConsumer, RequestLoggingConfig, set_consumer
2
+ from apitally.starlette import ApitallyMiddleware as _ApitallyMiddlewareForStarlette
2
3
 
3
4
 
4
5
  __all__ = ["ApitallyMiddleware", "ApitallyConsumer", "RequestLoggingConfig", "set_consumer"]
6
+
7
+
8
+ class ApitallyMiddleware(_ApitallyMiddlewareForStarlette):
9
+ """
10
+ Apitally middleware for FastAPI applications.
11
+
12
+ For more information, see:
13
+ - Setup guide: https://docs.apitally.io/frameworks/fastapi
14
+ - Reference: https://docs.apitally.io/reference/python
15
+ """
16
+
17
+ pass
apitally/flask.py CHANGED
@@ -19,10 +19,17 @@ from apitally.client.request_logging import (
19
19
  MAX_BODY_SIZE,
20
20
  RequestLogger,
21
21
  RequestLoggingConfig,
22
+ RequestLoggingKwargs,
22
23
  )
23
24
  from apitally.common import get_versions
24
25
 
25
26
 
27
+ try:
28
+ from typing import Unpack
29
+ except ImportError:
30
+ from typing_extensions import Unpack
31
+
32
+
26
33
  if TYPE_CHECKING:
27
34
  from _typeshed.wsgi import StartResponse, WSGIApplication, WSGIEnvironment
28
35
  from werkzeug.routing.map import Map
@@ -32,19 +39,39 @@ __all__ = ["ApitallyMiddleware", "ApitallyConsumer", "RequestLoggingConfig", "se
32
39
 
33
40
 
34
41
  class ApitallyMiddleware:
42
+ """
43
+ Apitally middleware for Flask applications.
44
+
45
+ For more information, see:
46
+ - Setup guide: https://docs.apitally.io/frameworks/flask
47
+ - Reference: https://docs.apitally.io/reference/python
48
+ """
49
+
35
50
  def __init__(
36
51
  self,
37
52
  app: Flask,
38
53
  client_id: str,
39
54
  env: str = "dev",
40
- request_logging_config: Optional[RequestLoggingConfig] = None,
41
55
  app_version: Optional[str] = None,
42
56
  openapi_url: Optional[str] = None,
43
57
  proxy: Optional[str] = None,
58
+ request_logging_config: Optional[RequestLoggingConfig] = None,
59
+ **kwargs: Unpack[RequestLoggingKwargs],
44
60
  ) -> None:
61
+ if request_logging_config is not None:
62
+ warn(
63
+ "The 'request_logging_config' parameter is deprecated, use keyword arguments instead.",
64
+ DeprecationWarning,
65
+ stacklevel=2,
66
+ )
67
+
45
68
  self.app = app
46
69
  self.wsgi_app = app.wsgi_app
47
70
  self.patch_handle_exception()
71
+
72
+ if kwargs and request_logging_config is None:
73
+ request_logging_config = RequestLoggingConfig.from_kwargs(kwargs)
74
+
48
75
  self.client = ApitallyClient(
49
76
  client_id=client_id,
50
77
  env=env,
@@ -75,7 +102,7 @@ class ApitallyMiddleware:
75
102
  self.client.start_sync_loop()
76
103
 
77
104
  def __call__(self, environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]:
78
- if not self.client.enabled:
105
+ if not self.client.enabled or environ.get("REQUEST_METHOD") == "OPTIONS":
79
106
  return self.wsgi_app(environ, start_response)
80
107
 
81
108
  timestamp = time.time()
@@ -153,7 +180,7 @@ class ApitallyMiddleware:
153
180
  consumer_identifier = consumer.identifier if consumer else None
154
181
  self.client.consumer_registry.add_or_update_consumer(consumer)
155
182
 
156
- if path is not None and request.method != "OPTIONS":
183
+ if path is not None:
157
184
  self.client.request_counter.add_request(
158
185
  consumer=consumer_identifier,
159
186
  method=request.method,
apitally/litestar.py CHANGED
@@ -20,10 +20,17 @@ from apitally.client.request_logging import (
20
20
  MAX_BODY_SIZE,
21
21
  RequestLogger,
22
22
  RequestLoggingConfig,
23
+ RequestLoggingKwargs,
23
24
  )
24
25
  from apitally.common import get_versions, parse_int, try_json_loads
25
26
 
26
27
 
28
+ try:
29
+ from typing import Unpack
30
+ except ImportError:
31
+ from typing_extensions import Unpack
32
+
33
+
27
34
  __all__ = ["ApitallyPlugin", "ApitallyConsumer", "RequestLoggingConfig", "set_consumer"]
28
35
 
29
36
 
@@ -32,21 +39,40 @@ class ApitallyPlugin(InitPluginProtocol):
32
39
  self,
33
40
  client_id: str,
34
41
  env: str = "dev",
35
- request_logging_config: Optional[RequestLoggingConfig] = None,
36
42
  app_version: Optional[str] = None,
37
43
  filter_openapi_paths: bool = True,
38
- identify_consumer_callback: Optional[Callable[[Request], Union[str, ApitallyConsumer, None]]] = None,
44
+ consumer_callback: Optional[Callable[[Request], Union[str, ApitallyConsumer, None]]] = None,
39
45
  proxy: Optional[Union[str, Proxy]] = None,
46
+ identify_consumer_callback: Optional[Callable[[Request], Union[str, ApitallyConsumer, None]]] = None,
47
+ request_logging_config: Optional[RequestLoggingConfig] = None,
48
+ **kwargs: Unpack[RequestLoggingKwargs],
40
49
  ) -> None:
50
+ if identify_consumer_callback is not None:
51
+ warn(
52
+ "The 'identify_consumer_callback' parameter is deprecated, use 'consumer_callback' instead.",
53
+ DeprecationWarning,
54
+ stacklevel=2,
55
+ )
56
+ if request_logging_config is not None:
57
+ warn(
58
+ "The 'request_logging_config' parameter is deprecated, use keyword arguments instead.",
59
+ DeprecationWarning,
60
+ stacklevel=2,
61
+ )
62
+
63
+ if kwargs and request_logging_config is None:
64
+ request_logging_config = RequestLoggingConfig.from_kwargs(kwargs)
65
+
41
66
  self.client = ApitallyClient(
42
67
  client_id=client_id,
43
68
  env=env,
44
69
  request_logging_config=request_logging_config,
45
70
  proxy=proxy,
46
71
  )
72
+
47
73
  self.app_version = app_version
48
74
  self.filter_openapi_paths = filter_openapi_paths
49
- self.identify_consumer_callback = identify_consumer_callback
75
+ self.consumer_callback = consumer_callback or identify_consumer_callback
50
76
 
51
77
  self.openapi_path = "/schema"
52
78
  self.capture_request_body = (
@@ -86,9 +112,9 @@ class ApitallyPlugin(InitPluginProtocol):
86
112
 
87
113
  def middleware_factory(self, app: ASGIApp) -> ASGIApp:
88
114
  async def middleware(scope: Scope, receive: Receive, send: Send) -> None:
89
- if self.client.enabled and scope["type"] == "http" and scope["method"] != "OPTIONS":
115
+ if self.client.enabled and scope["type"] == ScopeType.HTTP and scope["method"] != "OPTIONS":
90
116
  timestamp = time.time()
91
- request = Request(scope)
117
+ request: Request = Request(scope)
92
118
  request_size = parse_int(request.headers.get("Content-Length"))
93
119
  request_body = b""
94
120
  request_body_too_large = request_size is not None and request_size > MAX_BODY_SIZE
@@ -102,7 +128,7 @@ class ApitallyPlugin(InitPluginProtocol):
102
128
  response_content_type: Optional[str] = None
103
129
  start_time = time.perf_counter()
104
130
 
105
- async def receive_wrapper() -> Message:
131
+ async def receive_wrapper():
106
132
  nonlocal request_body, request_body_too_large
107
133
  message = await receive()
108
134
  if message["type"] == "http.request" and self.capture_request_body and not request_body_too_large:
@@ -112,7 +138,7 @@ class ApitallyPlugin(InitPluginProtocol):
112
138
  request_body = b""
113
139
  return message
114
140
 
115
- async def send_wrapper(message: Message) -> None:
141
+ async def send_wrapper(message: Message):
116
142
  nonlocal \
117
143
  response_time, \
118
144
  response_status, \
@@ -281,8 +307,8 @@ class ApitallyPlugin(InitPluginProtocol):
281
307
  DeprecationWarning,
282
308
  )
283
309
  return ApitallyConsumer.from_string_or_object(request.state.consumer_identifier)
284
- if self.identify_consumer_callback is not None:
285
- consumer = self.identify_consumer_callback(request)
310
+ if self.consumer_callback is not None:
311
+ consumer = self.consumer_callback(request)
286
312
  return ApitallyConsumer.from_string_or_object(consumer)
287
313
  return None
288
314
 
@@ -301,5 +327,5 @@ def _get_routes(app: Litestar) -> List[Dict[str, str]]:
301
327
  {"method": method, "path": route.path}
302
328
  for route in app.routes
303
329
  for method in route.methods
304
- if route.scope_type == ScopeType.HTTP and method != "OPTIONS"
330
+ if route.scope_type == ScopeType.HTTP and method not in ["OPTIONS", "HEAD"]
305
331
  ]
apitally/starlette.py CHANGED
@@ -21,31 +21,65 @@ from apitally.client.request_logging import (
21
21
  MAX_BODY_SIZE,
22
22
  RequestLogger,
23
23
  RequestLoggingConfig,
24
+ RequestLoggingKwargs,
24
25
  )
25
26
  from apitally.common import get_versions, parse_int, try_json_loads
26
27
 
27
28
 
29
+ try:
30
+ from typing import Unpack
31
+ except ImportError:
32
+ from typing_extensions import Unpack
33
+
34
+
28
35
  __all__ = ["ApitallyMiddleware", "ApitallyConsumer", "RequestLoggingConfig", "set_consumer"]
29
36
 
30
37
 
31
38
  class ApitallyMiddleware:
39
+ """
40
+ Apitally middleware for Starlette applications.
41
+
42
+ For more information, see:
43
+ - Setup guide: https://docs.apitally.io/frameworks/starlette
44
+ - Reference: https://docs.apitally.io/reference/python
45
+ """
46
+
32
47
  def __init__(
33
48
  self,
34
49
  app: ASGIApp,
35
50
  client_id: str,
36
51
  env: str = "dev",
37
- request_logging_config: Optional[RequestLoggingConfig] = None,
38
52
  app_version: Optional[str] = None,
39
53
  openapi_url: Optional[str] = "/openapi.json",
40
- identify_consumer_callback: Optional[Callable[[Request], Union[str, ApitallyConsumer, None]]] = None,
54
+ consumer_callback: Optional[Callable[[Request], Union[str, ApitallyConsumer, None]]] = None,
41
55
  capture_client_disconnects: bool = False,
42
56
  proxy: Optional[Union[str, Proxy]] = None,
57
+ identify_consumer_callback: Optional[Callable[[Request], Union[str, ApitallyConsumer, None]]] = None,
58
+ request_logging_config: Optional[RequestLoggingConfig] = None,
59
+ **kwargs: Unpack[RequestLoggingKwargs],
43
60
  ) -> None:
61
+ if identify_consumer_callback is not None:
62
+ warn(
63
+ "The 'identify_consumer_callback' parameter is deprecated, use 'consumer_callback' instead.",
64
+ DeprecationWarning,
65
+ stacklevel=2,
66
+ )
67
+ if request_logging_config is not None:
68
+ warn(
69
+ "The 'request_logging_config' parameter is deprecated, use keyword arguments instead.",
70
+ DeprecationWarning,
71
+ stacklevel=2,
72
+ )
73
+
44
74
  self.app = app
45
75
  self.app_version = app_version
46
76
  self.openapi_url = openapi_url
47
- self.identify_consumer_callback = identify_consumer_callback
77
+ self.consumer_callback = consumer_callback or identify_consumer_callback
48
78
  self.capture_client_disconnects = capture_client_disconnects
79
+
80
+ if kwargs and request_logging_config is None:
81
+ request_logging_config = RequestLoggingConfig.from_kwargs(kwargs)
82
+
49
83
  self.client = ApitallyClient(
50
84
  client_id=client_id,
51
85
  env=env,
@@ -262,8 +296,8 @@ class ApitallyMiddleware:
262
296
  DeprecationWarning,
263
297
  )
264
298
  return ApitallyConsumer.from_string_or_object(request.state.consumer_identifier)
265
- if self.identify_consumer_callback is not None:
266
- consumer = self.identify_consumer_callback(request)
299
+ if self.consumer_callback is not None:
300
+ consumer = self.consumer_callback(request)
267
301
  return ApitallyConsumer.from_string_or_object(consumer)
268
302
  return None
269
303
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: apitally
3
- Version: 0.19.1
3
+ Version: 0.20.1
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
@@ -1,26 +1,26 @@
1
1
  apitally/__init__.py,sha256=ShXQBVjyiSOHxoQJS2BvNG395W4KZfqMxZWBAR0MZrE,22
2
- apitally/blacksheep.py,sha256=KvcPFeiwQgWZmRglbm8SLaN6_WRs5kZ3SymB1IuLR-A,9616
2
+ apitally/blacksheep.py,sha256=jAkK20OcmV--_Y-RsXDIApRj8bX2eKf_u7ClDtAPvBc,10644
3
3
  apitally/common.py,sha256=azDxepViH0QW0MuufTHxeSQyLGzCkocAX_KPziWTx8A,1605
4
- apitally/django.py,sha256=7eSh1tzuu0wRl9PxJgXMBSz9DfyohCDIqd4ecQTOJ1M,18499
4
+ apitally/django.py,sha256=hU3m1wf5E1qWAHsNjyZG1FEGcbsw3Tud8Vku0218C1Q,19412
5
5
  apitally/django_ninja.py,sha256=-CmrwFFRv7thFOUK_OrOSouhHL9bm5sIBNIQlpyE_2c,166
6
6
  apitally/django_rest_framework.py,sha256=-CmrwFFRv7thFOUK_OrOSouhHL9bm5sIBNIQlpyE_2c,166
7
- apitally/fastapi.py,sha256=813dGFl2eOSSYOYwuubFQYvpRikV3shu7bLR2TlwUC8,199
8
- apitally/flask.py,sha256=sqcsVmbfqpVSN409xDF8DeGOSNkWHI4SoyTFxNfWJ4w,9819
9
- apitally/litestar.py,sha256=fmcWNmvGvrjGG6J_q5lqB_qJpTk6PXFK9jam6bTWU8U,13678
7
+ apitally/fastapi.py,sha256=uLAftbIHUmZSCc3ZPpNblIFS9Se5lUhNyj3-nqFKuVU,555
8
+ apitally/flask.py,sha256=5sN6YvOqpfjTY8CPRw6FChfTp2-ax0lvHryQrbNeiSU,10606
9
+ apitally/litestar.py,sha256=-01nxP4ZM29vAXJCtqxmn4BucEHhXRwi84z_i0TZPbs,14600
10
10
  apitally/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- apitally/starlette.py,sha256=PnEwplG7i0qJpfEWKdJxGCIioLFp4kQfa-5Y6NWGSSg,14105
11
+ apitally/starlette.py,sha256=r3jVy-JEdc572BatOkHTCItY8jfj-AEFNYtpiAX6WfU,15240
12
12
  apitally/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  apitally/client/client_asyncio.py,sha256=rTsH5wlLHK3RmyIuEiT6vzjquU-l2OPC34JnC2U6uYw,6658
14
14
  apitally/client/client_base.py,sha256=DvivGeHd3dyOASRvkIo44Zh8RzdBMfH8_rROa2lFbgw,3799
15
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
- apitally/client/request_logging.py,sha256=yCF_CH8isp3gpQRVgakk6DNV60mtPZWG6z45pUNACOM,17644
18
+ apitally/client/request_logging.py,sha256=pzE0kUwGHe5pZ7mwPDSzKu6pnY-NYsNEKpjqB2C9gC4,17147
19
19
  apitally/client/requests.py,sha256=SDptGOg9XvaEKFj2o3oxJz-JAuZzUrqpHnbOQixf99o,3794
20
20
  apitally/client/sentry.py,sha256=dXW2zf-wexYSp4CJBsFFRKz9jWkPBy0ftqIk0o5Hkq8,1364
21
21
  apitally/client/server_errors.py,sha256=4B2BKDFoIpoWc55UVH6AIdYSgzj6zxCdMNUW77JjhZw,3423
22
22
  apitally/client/validation_errors.py,sha256=6G8WYWFgJs9VH9swvkPXJGuOJgymj5ooWA9OwjUTbuM,1964
23
- apitally-0.19.1.dist-info/METADATA,sha256=QE1kA2cHRaEPmxm3feYkfbeowkZMGnuAu5plkvfXDz0,9316
24
- apitally-0.19.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
25
- apitally-0.19.1.dist-info/licenses/LICENSE,sha256=vbLzC-4TddtXX-_AFEBKMYWRlxC_MN0g66QhPxo8PgY,1065
26
- apitally-0.19.1.dist-info/RECORD,,
23
+ apitally-0.20.1.dist-info/METADATA,sha256=HeXviknfeo_NLF27Xz1pi_oYRpW12mAr4HeQUbrE0wo,9316
24
+ apitally-0.20.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
25
+ apitally-0.20.1.dist-info/licenses/LICENSE,sha256=vbLzC-4TddtXX-_AFEBKMYWRlxC_MN0g66QhPxo8PgY,1065
26
+ apitally-0.20.1.dist-info/RECORD,,