fastapi-observer 1.3.1__tar.gz → 1.3.2__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 (120) hide show
  1. {fastapi_observer-1.3.1/src/fastapi_observer.egg-info → fastapi_observer-1.3.2}/PKG-INFO +1 -1
  2. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2/src/fastapi_observer.egg-info}/PKG-INFO +1 -1
  3. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapi_observer.egg-info/SOURCES.txt +1 -0
  4. fastapi_observer-1.3.2/src/fastapiobserver/_version.py +1 -0
  5. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/fastapi.py +8 -7
  6. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/logging/setup.py +51 -0
  7. fastapi_observer-1.3.2/tests/test_fork_queue_listener.py +61 -0
  8. fastapi_observer-1.3.1/src/fastapiobserver/_version.py +0 -1
  9. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/LICENSE +0 -0
  10. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/README.md +0 -0
  11. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/pyproject.toml +0 -0
  12. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/setup.cfg +0 -0
  13. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapi_observer.egg-info/dependency_links.txt +0 -0
  14. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapi_observer.egg-info/requires.txt +0 -0
  15. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapi_observer.egg-info/top_level.txt +0 -0
  16. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/__init__.py +0 -0
  17. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/audit/__init__.py +0 -0
  18. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/audit/formatter.py +0 -0
  19. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/audit/providers.py +0 -0
  20. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/audit/verify.py +0 -0
  21. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/config.py +0 -0
  22. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/control_plane.py +0 -0
  23. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/db_tracing.py +0 -0
  24. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/integrations/__init__.py +0 -0
  25. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/integrations/strawberry.py +0 -0
  26. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/logging/__init__.py +0 -0
  27. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/logging/circuit_breaker.py +0 -0
  28. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/logging/filters.py +0 -0
  29. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/logging/formatter.py +0 -0
  30. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/logging/queueing.py +0 -0
  31. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/logging/state.py +0 -0
  32. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/loguru.py +0 -0
  33. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/metrics/__init__.py +0 -0
  34. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/metrics/builder.py +0 -0
  35. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/metrics/contracts.py +0 -0
  36. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/metrics/endpoint.py +0 -0
  37. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/metrics/noop.py +0 -0
  38. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/metrics/pathing.py +0 -0
  39. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/metrics/prometheus/__init__.py +0 -0
  40. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/metrics/prometheus/backend.py +0 -0
  41. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/metrics/prometheus/client.py +0 -0
  42. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/metrics/prometheus/collector.py +0 -0
  43. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/metrics/prometheus/exemplars.py +0 -0
  44. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/metrics/prometheus/multiprocess.py +0 -0
  45. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/metrics/registry.py +0 -0
  46. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/middleware/__init__.py +0 -0
  47. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/middleware/body_capture.py +0 -0
  48. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/middleware/context.py +0 -0
  49. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/middleware/events.py +0 -0
  50. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/middleware/headers.py +0 -0
  51. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/middleware/ip.py +0 -0
  52. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/middleware/metrics.py +0 -0
  53. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/middleware/request_logging.py +0 -0
  54. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/middleware/span_errors.py +0 -0
  55. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/otel/__init__.py +0 -0
  56. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/otel/lifecycle.py +0 -0
  57. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/otel/logs.py +0 -0
  58. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/otel/metrics.py +0 -0
  59. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/otel/resource.py +0 -0
  60. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/otel/settings.py +0 -0
  61. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/otel/tracing.py +0 -0
  62. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/otel/types.py +0 -0
  63. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/plugins.py +0 -0
  64. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/profiles.py +0 -0
  65. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/propagation.py +0 -0
  66. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/py.typed +0 -0
  67. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/request_context.py +0 -0
  68. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/security/__init__.py +0 -0
  69. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/security/normalize.py +0 -0
  70. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/security/policy.py +0 -0
  71. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/security/proxies.py +0 -0
  72. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/security/redaction.py +0 -0
  73. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/sinks/__init__.py +0 -0
  74. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/sinks/builtin.py +0 -0
  75. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/sinks/discovery.py +0 -0
  76. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/sinks/factory.py +0 -0
  77. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/sinks/logtail/__init__.py +0 -0
  78. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/sinks/logtail/dlq.py +0 -0
  79. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/sinks/logtail/handler.py +0 -0
  80. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/sinks/logtail/sink.py +0 -0
  81. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/sinks/protocol.py +0 -0
  82. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/sinks/registry.py +0 -0
  83. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/sinks/stats.py +0 -0
  84. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/src/fastapiobserver/utils.py +0 -0
  85. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_audit_chain.py +0 -0
  86. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_body_media_allowlist.py +0 -0
  87. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_config_settings.py +0 -0
  88. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_db_tracing.py +0 -0
  89. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_dx_parity.py +0 -0
  90. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_excluded_url_precedence.py +0 -0
  91. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_fastapi_install.py +0 -0
  92. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_graphql_integrations.py +0 -0
  93. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_lifespan_teardown.py +0 -0
  94. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_log_queue_controls.py +0 -0
  95. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_logging_schema_contract.py +0 -0
  96. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_logtail_dlq.py +0 -0
  97. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_loguru_bridge.py +0 -0
  98. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_metrics_contracts.py +0 -0
  99. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_metrics_optional_dependency.py +0 -0
  100. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_middleware.py +0 -0
  101. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_negotiate_content_type.py +0 -0
  102. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_otel_integration.py +0 -0
  103. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_otel_lifecycle.py +0 -0
  104. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_otel_log_correlation.py +0 -0
  105. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_otel_logs_from_env.py +0 -0
  106. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_otel_logs_pipeline.py +0 -0
  107. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_otel_metrics_from_env.py +0 -0
  108. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_otlp_export_integration.py +0 -0
  109. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_plugin_isolation.py +0 -0
  110. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_profiles.py +0 -0
  111. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_propagation.py +0 -0
  112. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_redaction_presets.py +0 -0
  113. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_route_template_cardinality.py +0 -0
  114. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_runtime_control_auth.py +0 -0
  115. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_security_audit_fixes.py +0 -0
  116. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_security_redaction.py +0 -0
  117. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_sink_circuit_breaker.py +0 -0
  118. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_sinks.py +0 -0
  119. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_trust_boundary.py +0 -0
  120. {fastapi_observer-1.3.1 → fastapi_observer-1.3.2}/tests/test_utils_refactors.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-observer
3
- Version: 1.3.1
3
+ Version: 1.3.2
4
4
  Summary: Zero-glue FastAPI observability with security presets and runtime controls
5
5
  Author-email: Vitaee <opensource@vitaee.dev>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-observer
3
- Version: 1.3.1
3
+ Version: 1.3.2
4
4
  Summary: Zero-glue FastAPI observability with security presets and runtime controls
5
5
  Author-email: Vitaee <opensource@vitaee.dev>
6
6
  License-Expression: MIT
@@ -85,6 +85,7 @@ tests/test_db_tracing.py
85
85
  tests/test_dx_parity.py
86
86
  tests/test_excluded_url_precedence.py
87
87
  tests/test_fastapi_install.py
88
+ tests/test_fork_queue_listener.py
88
89
  tests/test_graphql_integrations.py
89
90
  tests/test_lifespan_teardown.py
90
91
  tests/test_log_queue_controls.py
@@ -0,0 +1 @@
1
+ __version__ = "1.3.2"
@@ -213,6 +213,9 @@ def _auto_discover_excluded_routes(app: FastAPI, settings: ObservabilitySettings
213
213
  """Auto-discover routes like /docs, /openapi.json, or include_in_schema=False."""
214
214
  # Build a set of paths to exclude
215
215
  excluded = set(settings.metrics_exclude_paths)
216
+ if settings.metrics_path:
217
+ excluded.update(_build_exclude_path_variants(settings.metrics_path))
218
+
216
219
  for route in app.routes:
217
220
  path = getattr(route, "path", None)
218
221
  if not path:
@@ -233,7 +236,10 @@ def _auto_discover_excluded_routes(app: FastAPI, settings: ObservabilitySettings
233
236
  while hasattr(current, "app"):
234
237
  # Check by name since we don't want a hard dependency
235
238
  if current.__class__.__name__ == "OpenTelemetryMiddleware":
236
- from opentelemetry.util.http import parse_excluded_urls
239
+ try:
240
+ from opentelemetry.util.http import parse_excluded_urls
241
+ except ImportError:
242
+ break
237
243
 
238
244
  current_excluded: set[str] = set()
239
245
  for attr_name in ("excluded_urls", "_excluded_urls"):
@@ -293,10 +299,7 @@ def _register_logging_shutdown_hook(app: FastAPI) -> None:
293
299
  async def auto_observability_lifespan(
294
300
  app_inst: FastAPI,
295
301
  ) -> typing.AsyncGenerator[typing.Any, None]:
296
- if hasattr(app_inst.state, "_observability_settings"):
297
- _auto_discover_excluded_routes(app_inst, app_inst.state._observability_settings)
298
-
299
- try:
302
+ async with observability_lifespan(app_inst):
300
303
  if original_lifespan:
301
304
  # If the user is explicitly using observability_lifespan inside their
302
305
  # original_lifespan, this will safely no-op during cleanup because
@@ -305,8 +308,6 @@ def _register_logging_shutdown_hook(app: FastAPI) -> None:
305
308
  yield state
306
309
  else:
307
310
  yield {}
308
- finally:
309
- _teardown_observability(app_inst)
310
311
 
311
312
  app.router.lifespan_context = auto_observability_lifespan
312
313
  _REGISTERED_APPS.add(app)
@@ -193,6 +193,7 @@ def setup_logging(
193
193
  state._QUEUE_LISTENER = listener
194
194
  state._MANAGED_OUTPUT_HANDLERS = managed_output_handlers
195
195
  _ensure_atexit_shutdown_hook_locked()
196
+ _ensure_fork_reinitialization_locked()
196
197
 
197
198
  for name in ("uvicorn", "uvicorn.error", "uvicorn.access"):
198
199
  uvicorn_logger = logging.getLogger(name)
@@ -217,6 +218,56 @@ def _ensure_atexit_shutdown_hook_locked() -> None:
217
218
  state._ATEXIT_SHUTDOWN_REGISTERED = True
218
219
 
219
220
 
221
+ def _ensure_fork_reinitialization_locked() -> None:
222
+ import os
223
+ import fastapiobserver.logging.state as state
224
+ if getattr(state, "_FORK_HOOK_REGISTERED", False):
225
+ return
226
+ if hasattr(os, "register_at_fork"):
227
+ os.register_at_fork(after_in_child=_restart_queue_listener_in_child)
228
+ setattr(state, "_FORK_HOOK_REGISTERED", True)
229
+
230
+
231
+ def _restart_queue_listener_in_child() -> None:
232
+ import fastapiobserver.logging.state as state
233
+
234
+ listener = state._QUEUE_LISTENER
235
+ if listener is not None:
236
+ # The inherited queue's Condition lock might be held by the parent
237
+ # or left in an inconsistent state across the fork. To reliably resume
238
+ # processing, we must create a fresh queue and manually drain any
239
+ # inherited records from the old queue.
240
+ old_queue = cast(queue.Queue[logging.LogRecord], listener.queue)
241
+ new_queue: queue.Queue[logging.LogRecord] = queue.Queue(maxsize=old_queue.maxsize)
242
+
243
+ while not old_queue.empty():
244
+ try:
245
+ record = old_queue.get_nowait()
246
+ new_queue.put_nowait(record)
247
+ except queue.Empty:
248
+ break
249
+ except queue.Full:
250
+ break
251
+
252
+ # Re-attach the new queue to the OverflowPolicyQueueHandler if present
253
+ for handler in state._MANAGED_HANDLERS:
254
+ from .queueing import OverflowPolicyQueueHandler
255
+
256
+ if (
257
+ isinstance(handler, OverflowPolicyQueueHandler)
258
+ and getattr(handler, "queue", None) is old_queue
259
+ ):
260
+ handler.queue = new_queue
261
+
262
+ new_listener = logging.handlers.QueueListener(
263
+ new_queue,
264
+ *listener.handlers,
265
+ respect_handler_level=listener.respect_handler_level,
266
+ )
267
+ state._QUEUE_LISTENER = new_listener
268
+ new_listener.start()
269
+
270
+
220
271
  def _wrap_sink_handlers(
221
272
  handlers_with_names: list[tuple[logging.Handler, str]],
222
273
  *,
@@ -0,0 +1,61 @@
1
+ import logging
2
+ import queue
3
+ from unittest.mock import Mock
4
+ from fastapiobserver.logging.setup import _restart_queue_listener_in_child
5
+ import fastapiobserver.logging.state as state
6
+ from fastapiobserver.logging.queueing import OverflowPolicyQueueHandler
7
+
8
+
9
+ def test_restart_queue_listener_in_child_drains_and_recreates_queue():
10
+ # Setup mock state
11
+ old_queue = queue.Queue(maxsize=10)
12
+ old_queue.put_nowait(
13
+ logging.LogRecord("test", logging.INFO, "path", 1, "test msg 1", None, None)
14
+ )
15
+ old_queue.put_nowait(
16
+ logging.LogRecord("test", logging.INFO, "path", 1, "test msg 2", None, None)
17
+ )
18
+
19
+ mock_queue_handler = Mock(spec=OverflowPolicyQueueHandler)
20
+ mock_queue_handler.queue = old_queue
21
+
22
+ mock_listener = Mock()
23
+ mock_listener.queue = old_queue
24
+ mock_listener.handlers = []
25
+ mock_listener.respect_handler_level = True
26
+
27
+ # Temporarily override state module
28
+ original_listener = state._QUEUE_LISTENER
29
+ original_handlers = state._MANAGED_HANDLERS
30
+
31
+ state._QUEUE_LISTENER = mock_listener
32
+ state._MANAGED_HANDLERS = {mock_queue_handler}
33
+
34
+ try:
35
+ # Action
36
+ _restart_queue_listener_in_child()
37
+
38
+ # Assertions
39
+ assert old_queue.empty()
40
+
41
+ # Verify the new listener was created and started
42
+ new_listener = state._QUEUE_LISTENER
43
+ assert new_listener is not mock_listener
44
+ assert new_listener.queue is not old_queue
45
+ assert isinstance(new_listener, logging.handlers.QueueListener)
46
+ # We cannot reliably assert new_listener.queue.qsize() == 2 because
47
+ # new_listener.start() spins up a thread that immediately begins consuming.
48
+
49
+ # Verify the managed handler got the new queue assigned to its .queue attribute
50
+ assert mock_queue_handler.queue is new_listener.queue
51
+
52
+ # The actual QueueListener thread isn't started in mock but the object is created
53
+ # new_listener.start() was called during _restart_queue_listener_in_child
54
+
55
+ finally:
56
+ # Cleanup threading if start started a thread, and restore state
57
+ if isinstance(state._QUEUE_LISTENER, logging.handlers.QueueListener):
58
+ state._QUEUE_LISTENER.stop()
59
+
60
+ state._QUEUE_LISTENER = original_listener
61
+ state._MANAGED_HANDLERS = original_handlers
@@ -1 +0,0 @@
1
- __version__ = "1.3.1"