debugbundle-python 1.1.0__tar.gz → 1.1.3__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 (42) hide show
  1. {debugbundle_python-1.1.0/src/debugbundle_python.egg-info → debugbundle_python-1.1.3}/PKG-INFO +1 -1
  2. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/pyproject.toml +1 -1
  3. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/core.py +16 -4
  4. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/relay.py +10 -2
  5. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3/src/debugbundle_python.egg-info}/PKG-INFO +1 -1
  6. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/tests/test_relay.py +24 -1
  7. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/tests/test_repository_metadata.py +17 -1
  8. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/tests/test_smoke_script.py +2 -2
  9. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/LICENSE +0 -0
  10. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/README.md +0 -0
  11. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/setup.cfg +0 -0
  12. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/__init__.py +0 -0
  13. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/config.py +0 -0
  14. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/integrations/__init__.py +0 -0
  15. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/integrations/common.py +0 -0
  16. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/integrations/django.py +0 -0
  17. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/integrations/fastapi.py +0 -0
  18. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/integrations/flask.py +0 -0
  19. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/integrations/relay_django.py +0 -0
  20. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/integrations/relay_fastapi.py +0 -0
  21. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/integrations/relay_flask.py +0 -0
  22. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/logger_integrations.py +0 -0
  23. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/py.typed +0 -0
  24. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/redaction.py +0 -0
  25. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/relay_delivery.py +0 -0
  26. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/suppression.py +0 -0
  27. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/transport.py +0 -0
  28. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle/trigger_token.py +0 -0
  29. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle_python.egg-info/SOURCES.txt +0 -0
  30. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle_python.egg-info/dependency_links.txt +0 -0
  31. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle_python.egg-info/requires.txt +0 -0
  32. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/src/debugbundle_python.egg-info/top_level.txt +0 -0
  33. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/tests/test_contracts.py +0 -0
  34. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/tests/test_framework_integrations.py +0 -0
  35. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/tests/test_hooks.py +0 -0
  36. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/tests/test_http_integration.py +0 -0
  37. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/tests/test_optional_imports.py +0 -0
  38. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/tests/test_relay_delivery.py +0 -0
  39. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/tests/test_remote_config.py +0 -0
  40. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/tests/test_schema_validation.py +0 -0
  41. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/tests/test_sdk.py +0 -0
  42. {debugbundle_python-1.1.0 → debugbundle_python-1.1.3}/tests/test_trigger_token.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: debugbundle-python
3
- Version: 1.1.0
3
+ Version: 1.1.3
4
4
  Summary: DebugBundle SDK for Python
5
5
  Author: DebugBundle
6
6
  License-Expression: AGPL-3.0-only
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "debugbundle-python"
7
- version = "1.1.0"
7
+ version = "1.1.3"
8
8
  description = "DebugBundle SDK for Python"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -528,23 +528,27 @@ class DebugBundleSdk:
528
528
  payload: dict[str, object],
529
529
  context: Mapping[str, object] | None = None,
530
530
  ) -> dict[str, object]:
531
- return {
531
+ merged_context = self._merged_context(context)
532
+ event: dict[str, object] = {
532
533
  "schema_version": SCHEMA_VERSION,
533
534
  "event_id": str(uuid.uuid4()),
534
535
  "event_type": event_type,
535
536
  "occurred_at": _iso_now(self._time_provider),
536
537
  "sdk_name": "debugbundle-python",
537
538
  "sdk_version": _sdk_version(),
538
- "sdk_language": "python",
539
539
  "service": {
540
540
  "name": self._service,
541
541
  "runtime": "python",
542
542
  "framework": None,
543
543
  "environment": self._environment,
544
544
  },
545
- "correlation": _correlation_payload(self._merged_context(context)),
545
+ "correlation": _correlation_payload(merged_context),
546
546
  "payload": payload,
547
547
  }
548
+ envelope_context = _event_context(merged_context)
549
+ if envelope_context:
550
+ event["context"] = envelope_context
551
+ return event
548
552
 
549
553
  def _merged_context(self, context: Mapping[str, object] | None = None) -> dict[str, object]:
550
554
  merged = dict(self._context)
@@ -861,6 +865,14 @@ def _correlation_payload(context: Mapping[str, object]) -> dict[str, str | None]
861
865
  }
862
866
 
863
867
 
868
+ def _event_context(context: Mapping[str, object]) -> dict[str, object]:
869
+ return {
870
+ str(key): value
871
+ for key, value in context.items()
872
+ if key not in {"request", "response", "correlation", "request_id", "trace_id", "session_id", "user_id_hash"}
873
+ }
874
+
875
+
864
876
  def _coerce_optional_string(value: object) -> str | None:
865
877
  if value is None:
866
878
  return None
@@ -942,7 +954,7 @@ def _sdk_version() -> str:
942
954
  try:
943
955
  return metadata.version("debugbundle-python")
944
956
  except metadata.PackageNotFoundError:
945
- return "1.1.0"
957
+ return "1.1.3"
946
958
 
947
959
 
948
960
  def _sdk_config_endpoint(events_endpoint: str) -> str:
@@ -25,6 +25,7 @@ ACCEPTED_EVENT_TYPES = frozenset(
25
25
  "frontend_breadcrumb",
26
26
  "request_event",
27
27
  "probe_event",
28
+ "analytics_event",
28
29
  }
29
30
  )
30
31
 
@@ -376,8 +377,15 @@ def _sanitize_event(
376
377
  correlation = event.get("correlation")
377
378
  if isinstance(correlation, dict):
378
379
  normalized_correlation: dict[str, Any] = {}
379
- for key in ("request_id", "trace_id", "session_id", "user_id_hash"):
380
- value = correlation.get(key)
380
+ correlation_keys = (
381
+ ("session_id", "visitor_id_hash", "user_id_hash", "trace_id", "deploy_id")
382
+ if event_type == "analytics_event"
383
+ else ("request_id", "trace_id", "session_id", "user_id_hash")
384
+ )
385
+ for key in correlation_keys:
386
+ if key not in correlation:
387
+ continue
388
+ value = correlation[key]
381
389
  if isinstance(value, str) or value is None:
382
390
  normalized_correlation[key] = value
383
391
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: debugbundle-python
3
- Version: 1.1.0
3
+ Version: 1.1.3
4
4
  Summary: DebugBundle SDK for Python
5
5
  Author: DebugBundle
6
6
  License-Expression: AGPL-3.0-only
@@ -72,6 +72,21 @@ def test_accepts_valid_batch() -> None:
72
72
  assert response.body["rejected"] == 0
73
73
 
74
74
 
75
+ def test_accepts_analytics_events_and_preserves_analytics_correlation() -> None:
76
+ fixture = _relay_compliance_fixture("valid-analytics-event")
77
+ accepted: list[BrowserRelayAcceptedBatch] = []
78
+ handler = BrowserRelayHandler(
79
+ allowed_origins=[fixture["request"]["headers"]["origin"]],
80
+ on_accept=lambda batch: accepted.append(batch),
81
+ )
82
+
83
+ response = handler.handle(_make_request_from_fixture(fixture["request"]))
84
+
85
+ assert response.status == 202
86
+ assert accepted[0].events[0] == fixture["expectedEventFile"][0]
87
+ assert "project_token" not in accepted[0].events[0]
88
+
89
+
75
90
  def test_rejects_non_post() -> None:
76
91
  handler = BrowserRelayHandler(allowed_origins=["https://example.com"])
77
92
  response = handler.handle(_make_request(method="GET"))
@@ -211,7 +226,15 @@ def test_preserves_correlation_trace_id() -> None:
211
226
 
212
227
  def test_accepts_all_supported_event_types() -> None:
213
228
  handler = BrowserRelayHandler(allowed_origins=["https://example.com"])
214
- for event_type in ("frontend_exception", "error_suppressed", "frontend_breadcrumb", "request_event", "probe_event"):
229
+ supported_event_types = (
230
+ "frontend_exception",
231
+ "error_suppressed",
232
+ "frontend_breadcrumb",
233
+ "request_event",
234
+ "probe_event",
235
+ "analytics_event",
236
+ )
237
+ for event_type in supported_event_types:
215
238
  evt = _valid_event(event_type)
216
239
  response = handler.handle(
217
240
  _make_request(body={"batch": [evt]}, ip_address=f"10.0.0.{hash(event_type) % 254 + 1}")
@@ -30,7 +30,23 @@ def test_standalone_changelog_and_security_policy_are_launch_ready() -> None:
30
30
  security = (REPO_ROOT / "SECURITY.md").read_text(encoding="utf-8")
31
31
 
32
32
  assert "## [Unreleased]" in changelog
33
- assert "## [1.1.0] - 2026-06-08" in changelog
33
+ assert (
34
+ "## [1.1.3] - 2026-07-17\n\n"
35
+ "### Added\n"
36
+ "- Added browser-relay support for `analytics_event` envelopes, preserving only the "
37
+ "analytics correlation fields needed for aggregation while continuing to strip "
38
+ "browser-supplied credentials.\n\n"
39
+ "## [1.1.2] - 2026-06-19\n\n"
40
+ "### Fixed\n"
41
+ "- Release packaging quality gates so the published Python SDK patch can ship cleanly "
42
+ "without changing runtime behavior.\n\n"
43
+ "## [1.1.1] - 2026-06-19\n\n"
44
+ "### Fixed\n"
45
+ "- Normalized canonical event-envelope emission so custom app context now stays in envelope `context`, "
46
+ "request events avoid legacy payload extras, and installed projects stop tripping malformed ingestion rejects "
47
+ "after upgrade.\n\n"
48
+ "## [1.1.0] - 2026-06-08" in changelog
49
+ )
34
50
  assert "https://github.com/debugbundle/debugbundle-python/security/advisories/new" in security
35
51
 
36
52
 
@@ -32,7 +32,7 @@ def test_install_with_retry_retries_until_success(monkeypatch) -> None:
32
32
  monkeypatch.setattr(SMOKE.time, "sleep", sleeps.append)
33
33
 
34
34
  SMOKE._install_with_retry(
35
- ["python", "-m", "pip", "install", "debugbundle-python==1.1.0"],
35
+ ["python", "-m", "pip", "install", "debugbundle-python==1.1.3"],
36
36
  retries=3,
37
37
  retry_delay_seconds=7,
38
38
  )
@@ -50,7 +50,7 @@ def test_install_with_retry_raises_after_final_attempt(monkeypatch) -> None:
50
50
 
51
51
  try:
52
52
  SMOKE._install_with_retry(
53
- ["python", "-m", "pip", "install", "debugbundle-python==1.1.0"],
53
+ ["python", "-m", "pip", "install", "debugbundle-python==1.1.3"],
54
54
  retries=2,
55
55
  retry_delay_seconds=1,
56
56
  )