tusk-drift-python-sdk 0.1.22__tar.gz → 0.1.23__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 (166) hide show
  1. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/PKG-INFO +9 -9
  2. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/README.md +5 -5
  3. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/drift_sdk.py +41 -16
  4. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/mode_utils.py +3 -1
  5. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/rust_core_binding.py +18 -7
  6. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/otel_converter.py +3 -6
  7. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/aiohttp/e2e-tests/src/app.py +23 -0
  8. tusk_drift_python_sdk-0.1.23/drift/instrumentation/django/e2e-tests/src/views.py +216 -0
  9. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/instrumentation.py +43 -5
  10. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/middleware.py +3 -0
  11. tusk_drift_python_sdk-0.1.23/drift/instrumentation/e2e_common/external_http.py +55 -0
  12. tusk_drift_python_sdk-0.1.23/drift/instrumentation/e2e_common/mock_upstream/mock_server.py +348 -0
  13. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/fastapi/e2e-tests/src/app.py +31 -11
  14. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/fastapi/instrumentation.py +3 -0
  15. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/flask/e2e-tests/src/app.py +39 -9
  16. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/e2e-tests/src/greeter_pb2_grpc.py +1 -1
  17. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/httpx/e2e-tests/src/app.py +40 -0
  18. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg/e2e-tests/src/app.py +30 -8
  19. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg/instrumentation.py +3 -1
  20. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg2/e2e-tests/src/app.py +64 -0
  21. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg2/e2e-tests/src/test_requests.py +3 -0
  22. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg2/instrumentation.py +2 -1
  23. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/requests/e2e-tests/src/app.py +25 -0
  24. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/socket/instrumentation.py +18 -3
  25. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib/e2e-tests/src/app.py +25 -2
  26. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib/instrumentation.py +11 -7
  27. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib3/e2e-tests/src/app.py +147 -22
  28. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib3/e2e-tests/src/test_requests.py +22 -11
  29. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib3/instrumentation.py +207 -90
  30. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/utils/psycopg_utils.py +63 -0
  31. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/utils/serialization.py +11 -1
  32. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/wsgi/handler.py +3 -0
  33. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/pyproject.toml +6 -4
  34. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/tusk_drift_python_sdk.egg-info/PKG-INFO +9 -9
  35. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/tusk_drift_python_sdk.egg-info/SOURCES.txt +2 -0
  36. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/tusk_drift_python_sdk.egg-info/requires.txt +3 -3
  37. tusk_drift_python_sdk-0.1.22/drift/instrumentation/django/e2e-tests/src/views.py +0 -153
  38. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/LICENSE +0 -0
  39. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/__init__.py +0 -0
  40. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/__init__.py +0 -0
  41. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/batch_processor.py +0 -0
  42. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/communication/__init__.py +0 -0
  43. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/communication/communicator.py +0 -0
  44. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/communication/types.py +0 -0
  45. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/config.py +0 -0
  46. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/content_type_utils.py +0 -0
  47. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/data_normalization.py +0 -0
  48. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/json_schema_helper.py +0 -0
  49. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/logger.py +0 -0
  50. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/metrics.py +0 -0
  51. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/mock_utils.py +0 -0
  52. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/protobuf_utils.py +0 -0
  53. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/resilience.py +0 -0
  54. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/sampling.py +0 -0
  55. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/span_serialization.py +0 -0
  56. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/trace_blocking_manager.py +0 -0
  57. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/__init__.py +0 -0
  58. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/adapters/__init__.py +0 -0
  59. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/adapters/api.py +0 -0
  60. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/adapters/base.py +0 -0
  61. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/adapters/filesystem.py +0 -0
  62. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/adapters/memory.py +0 -0
  63. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/span_exporter.py +0 -0
  64. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/span_utils.py +0 -0
  65. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/td_attributes.py +0 -0
  66. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/tracing/td_span_processor.py +0 -0
  67. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/core/types.py +0 -0
  68. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/__init__.py +0 -0
  69. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/aiohttp/__init__.py +0 -0
  70. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/aiohttp/e2e-tests/entrypoint.py +0 -0
  71. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/aiohttp/e2e-tests/src/test_requests.py +0 -0
  72. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/aiohttp/instrumentation.py +0 -0
  73. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/base.py +0 -0
  74. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/datetime/__init__.py +0 -0
  75. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/datetime/instrumentation.py +0 -0
  76. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/__init__.py +0 -0
  77. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/e2e-tests/entrypoint.py +0 -0
  78. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/e2e-tests/src/app.py +0 -0
  79. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/e2e-tests/src/settings.py +0 -0
  80. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/e2e-tests/src/test_requests.py +0 -0
  81. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/e2e-tests/src/urls.py +0 -0
  82. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/django/html_utils.py +0 -0
  83. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/e2e_common/__init__.py +0 -0
  84. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/e2e_common/base_runner.py +0 -0
  85. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/e2e_common/test_utils.py +0 -0
  86. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/fastapi/__init__.py +0 -0
  87. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/fastapi/e2e-tests/entrypoint.py +0 -0
  88. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/fastapi/e2e-tests/src/test_requests.py +0 -0
  89. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/flask/__init__.py +0 -0
  90. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/flask/e2e-tests/entrypoint.py +0 -0
  91. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/flask/e2e-tests/src/test_requests.py +0 -0
  92. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/flask/instrumentation.py +0 -0
  93. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/__init__.py +0 -0
  94. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/e2e-tests/entrypoint.py +0 -0
  95. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/e2e-tests/src/app.py +0 -0
  96. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/e2e-tests/src/greeter_pb2.py +0 -0
  97. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/e2e-tests/src/grpc_server.py +0 -0
  98. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/e2e-tests/src/test_requests.py +0 -0
  99. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/instrumentation.py +0 -0
  100. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/types.py +0 -0
  101. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/grpc/utils.py +0 -0
  102. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/http/__init__.py +0 -0
  103. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/http/transform_engine.py +0 -0
  104. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/httpx/__init__.py +0 -0
  105. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/httpx/e2e-tests/entrypoint.py +0 -0
  106. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/httpx/e2e-tests/src/test_requests.py +0 -0
  107. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/httpx/instrumentation.py +0 -0
  108. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/kinde/__init__.py +0 -0
  109. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/kinde/instrumentation.py +0 -0
  110. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg/__init__.py +0 -0
  111. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg/e2e-tests/entrypoint.py +0 -0
  112. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg/e2e-tests/src/test_requests.py +0 -0
  113. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg/mocks.py +0 -0
  114. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg/wrappers.py +0 -0
  115. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg2/__init__.py +0 -0
  116. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/psycopg2/e2e-tests/entrypoint.py +0 -0
  117. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/pyjwt/__init__.py +0 -0
  118. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/pyjwt/instrumentation.py +0 -0
  119. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/redis/__init__.py +0 -0
  120. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/redis/e2e-tests/entrypoint.py +0 -0
  121. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/redis/e2e-tests/src/app.py +0 -0
  122. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/redis/e2e-tests/src/test_requests.py +0 -0
  123. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/redis/instrumentation.py +0 -0
  124. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/registry.py +0 -0
  125. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/requests/__init__.py +0 -0
  126. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/requests/e2e-tests/entrypoint.py +0 -0
  127. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/requests/e2e-tests/src/test_requests.py +0 -0
  128. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/requests/instrumentation.py +0 -0
  129. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/socket/__init__.py +0 -0
  130. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/sqlalchemy/__init__.py +0 -0
  131. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/sqlalchemy/context.py +0 -0
  132. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/sqlalchemy/e2e-tests/entrypoint.py +0 -0
  133. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/sqlalchemy/e2e-tests/src/app.py +0 -0
  134. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/sqlalchemy/e2e-tests/src/test_requests.py +0 -0
  135. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/sqlalchemy/instrumentation.py +0 -0
  136. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib/__init__.py +0 -0
  137. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib/e2e-tests/entrypoint.py +0 -0
  138. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib/e2e-tests/src/test_requests.py +0 -0
  139. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib3/__init__.py +0 -0
  140. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/urllib3/e2e-tests/entrypoint.py +0 -0
  141. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/wsgi/__init__.py +0 -0
  142. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/wsgi/instrumentation.py +0 -0
  143. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/wsgi/response_capture.py +0 -0
  144. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/instrumentation/wsgi/utilities.py +0 -0
  145. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-postgres/entrypoint.py +0 -0
  146. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-postgres/src/app.py +0 -0
  147. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-postgres/src/settings.py +0 -0
  148. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-postgres/src/test_requests.py +0 -0
  149. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-postgres/src/urls.py +0 -0
  150. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-postgres/src/views.py +0 -0
  151. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-redis/entrypoint.py +0 -0
  152. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-redis/src/app.py +0 -0
  153. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-redis/src/settings.py +0 -0
  154. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-redis/src/test_requests.py +0 -0
  155. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-redis/src/urls.py +0 -0
  156. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/django-redis/src/views.py +0 -0
  157. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/fastapi-postgres/entrypoint.py +0 -0
  158. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/fastapi-postgres/src/app.py +0 -0
  159. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/fastapi-postgres/src/test_requests.py +0 -0
  160. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/fastapi-sqlalchemy/entrypoint.py +0 -0
  161. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/fastapi-sqlalchemy/src/app.py +0 -0
  162. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/stack-tests/fastapi-sqlalchemy/src/test_requests.py +0 -0
  163. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/drift/version.py +0 -0
  164. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/setup.cfg +0 -0
  165. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/tusk_drift_python_sdk.egg-info/dependency_links.txt +0 -0
  166. {tusk_drift_python_sdk-0.1.22 → tusk_drift_python_sdk-0.1.23}/tusk_drift_python_sdk.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tusk-drift-python-sdk
3
- Version: 0.1.22
3
+ Version: 0.1.23
4
4
  Summary: Python SDK for Tusk Drift instrumentation and replay
5
5
  Author-email: Tusk <support@usetusk.ai>
6
6
  License: Apache-2.0
@@ -23,9 +23,9 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
23
  Requires-Python: >=3.9
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE
26
- Requires-Dist: protobuf>=6.0
26
+ Requires-Dist: protobuf>=3.20.0
27
27
  Requires-Dist: PyYAML>=6.0
28
- Requires-Dist: requests>=2.32.5
28
+ Requires-Dist: requests>=2.28.0
29
29
  Requires-Dist: tusk-drift-schemas>=0.1.24
30
30
  Requires-Dist: aiohttp>=3.9.0
31
31
  Requires-Dist: aiofiles>=23.0.0
@@ -42,7 +42,7 @@ Requires-Dist: starlette<0.42.0; extra == "fastapi"
42
42
  Provides-Extra: django
43
43
  Requires-Dist: Django>=4.2; extra == "django"
44
44
  Provides-Extra: rust
45
- Requires-Dist: drift-core-python>=0.1.7; extra == "rust"
45
+ Requires-Dist: drift-core-python>=0.1.9; extra == "rust"
46
46
  Provides-Extra: dev
47
47
  Requires-Dist: Flask>=3.1.2; extra == "dev"
48
48
  Requires-Dist: fastapi>=0.115.6; extra == "dev"
@@ -61,13 +61,13 @@ Dynamic: license-file
61
61
 
62
62
  <p align="center">
63
63
  <a href="https://pypi.org/project/tusk-drift-python-sdk/"><img src="https://img.shields.io/pypi/v/tusk-drift-python-sdk" alt="PyPI version"></a>
64
+ <a href="https://pypi.org/project/tusk-drift-python-sdk/"><img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/tusk-drift-python-sdk"></a>
64
65
  <a href="https://opensource.org/licenses/Apache-2.0"><img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg" alt="License: Apache 2.0"></a>
65
- <a href="https://github.com/Use-Tusk/drift-python-sdk/commits/main/"><img src="https://img.shields.io/github/last-commit/Use-Tusk/drift-python-sdk" alt="GitHub last commit"></a>
66
66
  <a href="https://x.com/usetusk"><img src="https://img.shields.io/twitter/url?url=https%3A%2F%2Fx.com%2Fusetusk&style=flat&logo=x&label=Tusk&color=BF40BF" alt="Tusk X account"></a>
67
67
  <a href="https://join.slack.com/t/tusk-community/shared_invite/zt-3fve1s7ie-NAAUn~UpHsf1m_2tdoGjsQ"><img src="https://img.shields.io/badge/slack-badge?style=flat&logo=slack&label=Tusk&color=BF40BF" alt="Tusk Community Slack"></a>
68
68
  </p>
69
69
 
70
- The Python Tusk Drift SDK enables fast and deterministic API testing by capturing and replaying API calls made to/from your service. Automatically record real-world API calls, then replay them as tests using the [Tusk CLI](https://github.com/Use-Tusk/tusk-drift-cli) to find regressions. During replay, all outbound requests are intercepted with recorded data to ensure consistent behavior without side-effects.
70
+ The Python Tusk Drift SDK enables fast and deterministic API testing by capturing and replaying API calls made to/from your service. Automatically record real-world API calls, then replay them as tests using the [Tusk CLI](https://github.com/Use-Tusk/tusk-cli) to find regressions. During replay, all outbound requests are intercepted with recorded data to ensure consistent behavior without side-effects.
71
71
 
72
72
  <div align="center">
73
73
 
@@ -124,7 +124,7 @@ If you're using packages or versions not listed above, please create an issue wi
124
124
 
125
125
  ### Step 1: Install the CLI
126
126
 
127
- First, install the Tusk Drift CLI by following our [CLI installation guide](https://github.com/Use-Tusk/tusk-drift-cli?tab=readme-ov-file#install).
127
+ First, install the Tusk Drift CLI by following our [CLI installation guide](https://github.com/Use-Tusk/tusk-cli?tab=readme-ov-file#install).
128
128
 
129
129
  ### Step 2: Set up Tusk Drift
130
130
 
@@ -135,7 +135,7 @@ Use our AI agent to automatically set up Tusk Drift for your service:
135
135
  ```bash
136
136
  cd path/to/your/service
137
137
  export ANTHROPIC_API_KEY=your-api-key
138
- tusk setup
138
+ tusk drift setup
139
139
  ```
140
140
 
141
141
  The agent will analyze your codebase, install the SDK, instrument it into your application, create configuration files, and test the setup with recording and replay.
@@ -156,7 +156,7 @@ Alternatively, you can set up Tusk Drift manually:
156
156
 
157
157
  *For more information about Rust acceleration, refer to [this doc](docs/rust-core-bindings).*
158
158
 
159
- 2. Create configuration: Run `tusk init` to create your `.tusk/config.yaml` config file interactively, or create it manually per the [configuration docs](https://github.com/Use-Tusk/tusk-drift-cli/blob/main/docs/configuration.md).
159
+ 2. Create configuration: Run `tusk init` to create your `.tusk/config.yaml` config file interactively, or create it manually per the [configuration docs](https://github.com/Use-Tusk/tusk-cli/blob/main/docs/drift/configuration.md).
160
160
 
161
161
  3. Initialize the SDK: Refer to the [initialization guide](docs/initialization.md) to instrument the SDK in your service.
162
162
 
@@ -4,13 +4,13 @@
4
4
 
5
5
  <p align="center">
6
6
  <a href="https://pypi.org/project/tusk-drift-python-sdk/"><img src="https://img.shields.io/pypi/v/tusk-drift-python-sdk" alt="PyPI version"></a>
7
+ <a href="https://pypi.org/project/tusk-drift-python-sdk/"><img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/tusk-drift-python-sdk"></a>
7
8
  <a href="https://opensource.org/licenses/Apache-2.0"><img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg" alt="License: Apache 2.0"></a>
8
- <a href="https://github.com/Use-Tusk/drift-python-sdk/commits/main/"><img src="https://img.shields.io/github/last-commit/Use-Tusk/drift-python-sdk" alt="GitHub last commit"></a>
9
9
  <a href="https://x.com/usetusk"><img src="https://img.shields.io/twitter/url?url=https%3A%2F%2Fx.com%2Fusetusk&style=flat&logo=x&label=Tusk&color=BF40BF" alt="Tusk X account"></a>
10
10
  <a href="https://join.slack.com/t/tusk-community/shared_invite/zt-3fve1s7ie-NAAUn~UpHsf1m_2tdoGjsQ"><img src="https://img.shields.io/badge/slack-badge?style=flat&logo=slack&label=Tusk&color=BF40BF" alt="Tusk Community Slack"></a>
11
11
  </p>
12
12
 
13
- The Python Tusk Drift SDK enables fast and deterministic API testing by capturing and replaying API calls made to/from your service. Automatically record real-world API calls, then replay them as tests using the [Tusk CLI](https://github.com/Use-Tusk/tusk-drift-cli) to find regressions. During replay, all outbound requests are intercepted with recorded data to ensure consistent behavior without side-effects.
13
+ The Python Tusk Drift SDK enables fast and deterministic API testing by capturing and replaying API calls made to/from your service. Automatically record real-world API calls, then replay them as tests using the [Tusk CLI](https://github.com/Use-Tusk/tusk-cli) to find regressions. During replay, all outbound requests are intercepted with recorded data to ensure consistent behavior without side-effects.
14
14
 
15
15
  <div align="center">
16
16
 
@@ -67,7 +67,7 @@ If you're using packages or versions not listed above, please create an issue wi
67
67
 
68
68
  ### Step 1: Install the CLI
69
69
 
70
- First, install the Tusk Drift CLI by following our [CLI installation guide](https://github.com/Use-Tusk/tusk-drift-cli?tab=readme-ov-file#install).
70
+ First, install the Tusk Drift CLI by following our [CLI installation guide](https://github.com/Use-Tusk/tusk-cli?tab=readme-ov-file#install).
71
71
 
72
72
  ### Step 2: Set up Tusk Drift
73
73
 
@@ -78,7 +78,7 @@ Use our AI agent to automatically set up Tusk Drift for your service:
78
78
  ```bash
79
79
  cd path/to/your/service
80
80
  export ANTHROPIC_API_KEY=your-api-key
81
- tusk setup
81
+ tusk drift setup
82
82
  ```
83
83
 
84
84
  The agent will analyze your codebase, install the SDK, instrument it into your application, create configuration files, and test the setup with recording and replay.
@@ -99,7 +99,7 @@ Alternatively, you can set up Tusk Drift manually:
99
99
 
100
100
  *For more information about Rust acceleration, refer to [this doc](docs/rust-core-bindings).*
101
101
 
102
- 2. Create configuration: Run `tusk init` to create your `.tusk/config.yaml` config file interactively, or create it manually per the [configuration docs](https://github.com/Use-Tusk/tusk-drift-cli/blob/main/docs/configuration.md).
102
+ 2. Create configuration: Run `tusk init` to create your `.tusk/config.yaml` config file interactively, or create it manually per the [configuration docs](https://github.com/Use-Tusk/tusk-cli/blob/main/docs/drift/configuration.md).
103
103
 
104
104
  3. Initialize the SDK: Refer to the [initialization guide](docs/initialization.md) to instrument the SDK in your service.
105
105
 
@@ -5,6 +5,7 @@ import atexit
5
5
  import json
6
6
  import logging
7
7
  import os
8
+ import platform
8
9
  import random
9
10
  import stat
10
11
  import time
@@ -17,10 +18,11 @@ from opentelemetry.sdk.trace import TracerProvider
17
18
  from opentelemetry.trace import SpanKind as OTelSpanKind
18
19
 
19
20
  from ..instrumentation.registry import install_hooks
21
+ from ..version import SDK_VERSION
20
22
  from .communication.communicator import CommunicatorConfig, ProtobufCommunicator
21
23
  from .communication.types import MockRequestInput, MockResponseOutput
22
24
  from .config import TuskConfig, TuskFileConfig, load_tusk_config
23
- from .logger import LogLevel, configure_logger
25
+ from .logger import LogLevel, configure_logger, get_log_level
24
26
  from .sampling import should_sample, validate_sampling_rate
25
27
  from .trace_blocking_manager import TraceBlockingManager, should_block_span
26
28
  from .tracing import TdSpanAttributes, TdSpanExporter, TdSpanExporterConfig
@@ -99,13 +101,40 @@ class TuskDrift:
99
101
  logger.info("Rust core path enabled at startup (env=%s, reason=%s).", env_display, status["reason"])
100
102
  return
101
103
 
102
- logger.warning(
103
- "Rust core path requested but binding unavailable; falling back to Python path (env=%s, reason=%s, error=%s).",
104
+ logger.info(
105
+ "Rust core path unavailable at startup; using Python path instead (env=%s, reason=%s, error=%s).",
104
106
  env_display,
105
107
  status["reason"],
106
108
  status["binding_error"],
107
109
  )
108
110
 
111
+ def _log_startup_summary(self, env: str, use_remote_export: bool) -> None:
112
+ service_name = (
113
+ self.file_config.service.name
114
+ if self.file_config and self.file_config.service and self.file_config.service.name
115
+ else "unknown"
116
+ )
117
+ service_id = (
118
+ self.file_config.service.id
119
+ if self.file_config and self.file_config.service and self.file_config.service.id
120
+ else "<unset>"
121
+ )
122
+
123
+ logger.info(
124
+ "SDK initialized successfully (version=%s, mode=%s, env=%s, service=%s, serviceId=%s, exportSpans=%s, samplingRate=%s, logLevel=%s, runtime=python %s, platform=%s/%s).",
125
+ SDK_VERSION,
126
+ self.mode,
127
+ env,
128
+ service_name,
129
+ service_id,
130
+ use_remote_export,
131
+ self._sampling_rate,
132
+ get_log_level(),
133
+ platform.python_version(),
134
+ platform.system().lower(),
135
+ platform.machine().lower(),
136
+ )
137
+
109
138
  @classmethod
110
139
  def initialize(
111
140
  cls,
@@ -216,8 +245,6 @@ class TuskDrift:
216
245
  export_spans_enabled and effective_api_key is not None and effective_observable_service_id is not None
217
246
  )
218
247
 
219
- from ..version import SDK_VERSION as sdk_version
220
-
221
248
  exporter_config = TdSpanExporterConfig(
222
249
  base_directory=base_dir,
223
250
  mode=instance.mode,
@@ -226,7 +253,7 @@ class TuskDrift:
226
253
  api_key=effective_api_key,
227
254
  tusk_backend_base_url=effective_backend_url,
228
255
  environment=env,
229
- sdk_version=sdk_version,
256
+ sdk_version=SDK_VERSION,
230
257
  sdk_instance_id=instance._sdk_instance_id,
231
258
  )
232
259
  instance.span_exporter = TdSpanExporter(exporter_config)
@@ -236,7 +263,7 @@ class TuskDrift:
236
263
  resource = Resource.create(
237
264
  {
238
265
  "service.name": service_name,
239
- "service.version": sdk_version,
266
+ "service.version": SDK_VERSION,
240
267
  "deployment.environment": env,
241
268
  }
242
269
  )
@@ -281,7 +308,7 @@ class TuskDrift:
281
308
  atexit.register(instance.shutdown)
282
309
 
283
310
  cls._initialized = True
284
- logger.info("SDK initialized in %s mode", instance.mode)
311
+ instance._log_startup_summary(env=env, use_remote_export=use_remote_export)
285
312
 
286
313
  return instance
287
314
 
@@ -416,7 +443,7 @@ class TuskDrift:
416
443
  pass
417
444
 
418
445
  try:
419
- import httpx # type: ignore[unresolved-import]
446
+ import httpx
420
447
 
421
448
  from ..instrumentation.httpx import HttpxInstrumentation
422
449
 
@@ -446,7 +473,7 @@ class TuskDrift:
446
473
  pass
447
474
 
448
475
  try:
449
- import sqlalchemy # type: ignore[unresolved-import]
476
+ import sqlalchemy
450
477
 
451
478
  from ..instrumentation.sqlalchemy import SqlAlchemyInstrumentation
452
479
 
@@ -463,7 +490,7 @@ class TuskDrift:
463
490
 
464
491
  # Try psycopg2 first
465
492
  try:
466
- import psycopg2 # type: ignore[unresolved-import]
493
+ import psycopg2
467
494
 
468
495
  from ..instrumentation.psycopg2 import Psycopg2Instrumentation
469
496
 
@@ -475,7 +502,7 @@ class TuskDrift:
475
502
 
476
503
  # Try psycopg (v3)
477
504
  try:
478
- import psycopg # type: ignore[unresolved-import]
505
+ import psycopg
479
506
 
480
507
  from ..instrumentation.psycopg import PsycopgInstrumentation
481
508
 
@@ -491,7 +518,7 @@ class TuskDrift:
491
518
  logger.debug("Both psycopg2 and psycopg available - instrumented both")
492
519
 
493
520
  try:
494
- import redis # type: ignore[unresolved-import]
521
+ import redis
495
522
 
496
523
  from ..instrumentation.redis import RedisInstrumentation
497
524
 
@@ -501,7 +528,7 @@ class TuskDrift:
501
528
  pass
502
529
 
503
530
  try:
504
- import grpc # type: ignore[unresolved-import]
531
+ import grpc
505
532
 
506
533
  from ..instrumentation.grpc import GrpcInstrumentation
507
534
 
@@ -619,8 +646,6 @@ class TuskDrift:
619
646
  if self._td_span_processor:
620
647
  self._td_span_processor.update_app_ready(True)
621
648
 
622
- logger.debug("Application marked as ready")
623
-
624
649
  if self.mode == TuskDriftMode.REPLAY:
625
650
  logger.debug("Replay mode active - ready to serve mocked responses")
626
651
  elif self.mode == TuskDriftMode.RECORD:
@@ -113,7 +113,9 @@ def handle_replay_mode(
113
113
 
114
114
  # Background request: App is ready + not within a trace (no parent span) + not a server request
115
115
  if is_app_ready and not current_span_info and not is_server_request:
116
- logger.debug("[ModeUtils] Handling no-op request")
116
+ logger.warning(
117
+ "[ModeUtils] Background request detected during replay (no active trace context). This typically means a background job, scheduled task, or middleware (e.g., rate limiters, message consumers) is running outside of a test trace. To avoid errors, disable these services when TUSK_DRIFT_MODE=REPLAY."
118
+ )
117
119
  return no_op_request_handler()
118
120
 
119
121
  return replay_mode_handler()
@@ -9,7 +9,10 @@ from __future__ import annotations
9
9
  import json
10
10
  import logging
11
11
  import os
12
- from typing import Any
12
+ from typing import TYPE_CHECKING, Any
13
+
14
+ if TYPE_CHECKING:
15
+ from .types import PackageType, SpanKind, StatusCode
13
16
 
14
17
  logger = logging.getLogger(__name__)
15
18
 
@@ -161,16 +164,16 @@ def build_span_proto_bytes(
161
164
  package_name: str,
162
165
  instrumentation_name: str,
163
166
  submodule_name: str,
164
- package_type: int,
167
+ package_type: PackageType,
165
168
  environment: str | None,
166
- kind: int,
169
+ kind: SpanKind,
167
170
  input_schema: dict[str, Any],
168
171
  output_schema: dict[str, Any],
169
172
  input_schema_hash: str,
170
173
  output_schema_hash: str,
171
174
  input_value_hash: str,
172
175
  output_value_hash: str,
173
- status_code: int,
176
+ status_code: StatusCode,
174
177
  status_message: str,
175
178
  is_pre_app_start: bool,
176
179
  is_root_span: bool,
@@ -190,6 +193,14 @@ def build_span_proto_bytes(
190
193
  if binding is None:
191
194
  return None
192
195
  try:
196
+ from .types import PackageType, SpanKind, StatusCode
197
+
198
+ if not isinstance(package_type, PackageType):
199
+ raise TypeError(f"package_type must be PackageType, got {type(package_type).__name__}")
200
+ if not isinstance(kind, SpanKind):
201
+ raise TypeError(f"kind must be SpanKind, got {type(kind).__name__}")
202
+ if not isinstance(status_code, StatusCode):
203
+ raise TypeError(f"status_code must be StatusCode, got {type(status_code).__name__}")
193
204
  return binding.build_span_proto_bytes_pyobject(
194
205
  trace_id,
195
206
  span_id,
@@ -198,16 +209,16 @@ def build_span_proto_bytes(
198
209
  package_name,
199
210
  instrumentation_name,
200
211
  submodule_name,
201
- package_type,
212
+ package_type.value,
202
213
  environment,
203
- kind,
214
+ kind.value,
204
215
  input_schema,
205
216
  output_schema,
206
217
  input_schema_hash,
207
218
  output_schema_hash,
208
219
  input_value_hash,
209
220
  output_value_hash,
210
- status_code,
221
+ status_code.value,
211
222
  status_message,
212
223
  is_pre_app_start,
213
224
  is_root_span,
@@ -420,9 +420,6 @@ def otel_span_to_clean_span_data(
420
420
  # Convert kind
421
421
  kind = otel_span_kind_to_drift(otel_span.kind)
422
422
 
423
- kind_value = kind.value if hasattr(kind, "value") else kind
424
- status_code_value = status.code.value if hasattr(status.code, "value") else status.code
425
- package_type_value = package_type.value if hasattr(package_type, "value") else package_type
426
423
  span_proto_bytes = build_span_proto_bytes(
427
424
  trace_id=trace_id,
428
425
  span_id=span_id,
@@ -431,16 +428,16 @@ def otel_span_to_clean_span_data(
431
428
  package_name=package_name,
432
429
  instrumentation_name=instrumentation_name,
433
430
  submodule_name=submodule_name,
434
- package_type=package_type_value,
431
+ package_type=package_type,
435
432
  environment=environment,
436
- kind=kind_value,
433
+ kind=kind,
437
434
  input_schema=input_schema,
438
435
  output_schema=output_schema,
439
436
  input_schema_hash=input_schema_hash,
440
437
  output_schema_hash=output_schema_hash,
441
438
  input_value_hash=input_value_hash,
442
439
  output_value_hash=output_value_hash,
443
- status_code=status_code_value,
440
+ status_code=status.code,
444
441
  status_message=status.message,
445
442
  is_pre_app_start=is_pre_app_start,
446
443
  is_root_span=is_root_span,
@@ -6,6 +6,10 @@ import aiohttp
6
6
  from flask import Flask, jsonify, request
7
7
 
8
8
  from drift import TuskDrift
9
+ from drift.instrumentation.e2e_common.external_http import (
10
+ external_http_timeout_seconds,
11
+ upstream_url,
12
+ )
9
13
 
10
14
  # Initialize SDK
11
15
  sdk = TuskDrift.initialize(
@@ -14,6 +18,25 @@ sdk = TuskDrift.initialize(
14
18
  )
15
19
 
16
20
  app = Flask(__name__)
21
+ EXTERNAL_HTTP_TIMEOUT_SECONDS = external_http_timeout_seconds()
22
+
23
+
24
+ def _configure_aiohttp_for_mock_and_timeouts():
25
+ original_request = aiohttp.ClientSession._request
26
+
27
+ async def patched_request(self, method, str_or_url, *args, **kwargs):
28
+ session_timeout = getattr(self, "_timeout", None)
29
+ default_timeout = getattr(aiohttp.client, "DEFAULT_TIMEOUT", None)
30
+ using_default_session_timeout = session_timeout is default_timeout or session_timeout == default_timeout
31
+ if "timeout" not in kwargs and using_default_session_timeout:
32
+ kwargs["timeout"] = aiohttp.ClientTimeout(total=EXTERNAL_HTTP_TIMEOUT_SECONDS)
33
+ rewritten = upstream_url(str(str_or_url))
34
+ return await original_request(self, method, rewritten, *args, **kwargs)
35
+
36
+ aiohttp.ClientSession._request = patched_request
37
+
38
+
39
+ _configure_aiohttp_for_mock_and_timeouts()
17
40
 
18
41
 
19
42
  # =============================================================================
@@ -0,0 +1,216 @@
1
+ """Django views for e2e test application."""
2
+
3
+ import json
4
+ from concurrent.futures import ThreadPoolExecutor
5
+
6
+ import requests
7
+ from django.http import HttpResponse, JsonResponse
8
+ from django.middleware.csrf import get_token
9
+ from django.views.decorators.csrf import csrf_exempt
10
+ from django.views.decorators.http import require_GET, require_http_methods, require_POST
11
+ from opentelemetry import context as otel_context
12
+
13
+ from drift.instrumentation.e2e_common.external_http import (
14
+ external_http_timeout_seconds,
15
+ upstream_url,
16
+ )
17
+
18
+ EXTERNAL_HTTP_TIMEOUT_SECONDS = external_http_timeout_seconds()
19
+
20
+
21
+ def _run_with_context(ctx, fn, *args, **kwargs):
22
+ """Helper to run a function with OpenTelemetry context in a thread pool."""
23
+ token = otel_context.attach(ctx)
24
+ try:
25
+ return fn(*args, **kwargs)
26
+ finally:
27
+ otel_context.detach(token)
28
+
29
+
30
+ @require_GET
31
+ def health(request):
32
+ """Health check endpoint."""
33
+ return JsonResponse({"status": "healthy"})
34
+
35
+
36
+ @require_GET
37
+ def get_weather(request):
38
+ """Fetch weather data from external API."""
39
+ try:
40
+ response = requests.get(
41
+ upstream_url("https://api.open-meteo.com/v1/forecast"),
42
+ params={
43
+ "latitude": 40.7128,
44
+ "longitude": -74.0060,
45
+ "current_weather": "true",
46
+ },
47
+ timeout=EXTERNAL_HTTP_TIMEOUT_SECONDS,
48
+ )
49
+ weather = response.json()
50
+
51
+ return JsonResponse(
52
+ {
53
+ "location": "New York",
54
+ "weather": weather.get("current_weather", {}),
55
+ }
56
+ )
57
+ except Exception as e:
58
+ return JsonResponse(
59
+ {
60
+ "location": "New York",
61
+ "weather": {},
62
+ "fallback": True,
63
+ "error": f"Failed to fetch weather: {str(e)}",
64
+ }
65
+ )
66
+
67
+
68
+ @require_GET
69
+ def get_user(request, user_id: str):
70
+ """Fetch user data from external API with seed."""
71
+ try:
72
+ response = requests.get(
73
+ upstream_url("https://randomuser.me/api/"),
74
+ params={"seed": user_id},
75
+ timeout=EXTERNAL_HTTP_TIMEOUT_SECONDS,
76
+ )
77
+ return JsonResponse(response.json())
78
+ except Exception as e:
79
+ return JsonResponse({"results": [], "fallback": True, "error": f"Failed to fetch user: {str(e)}"})
80
+
81
+
82
+ @csrf_exempt
83
+ @require_POST
84
+ def create_post(request):
85
+ """Create a new post via external API."""
86
+ data = {}
87
+ try:
88
+ data = json.loads(request.body)
89
+ response = requests.post(
90
+ upstream_url("https://jsonplaceholder.typicode.com/posts"),
91
+ json={
92
+ "title": data.get("title"),
93
+ "body": data.get("body"),
94
+ "userId": data.get("userId", 1),
95
+ },
96
+ timeout=EXTERNAL_HTTP_TIMEOUT_SECONDS,
97
+ )
98
+ return JsonResponse(response.json(), status=201)
99
+ except Exception as e:
100
+ return JsonResponse(
101
+ {
102
+ "id": -1,
103
+ "title": data.get("title", ""),
104
+ "body": data.get("body", ""),
105
+ "userId": data.get("userId", 1),
106
+ "fallback": True,
107
+ "error": f"Failed to create post: {str(e)}",
108
+ },
109
+ status=201,
110
+ )
111
+
112
+
113
+ @require_GET
114
+ def get_post(request, post_id: int):
115
+ """Fetch post and comments in parallel using ThreadPoolExecutor."""
116
+ try:
117
+ ctx = otel_context.get_current()
118
+
119
+ with ThreadPoolExecutor(max_workers=2) as executor:
120
+ post_future = executor.submit(
121
+ _run_with_context,
122
+ ctx,
123
+ requests.get,
124
+ upstream_url(f"https://jsonplaceholder.typicode.com/posts/{post_id}"),
125
+ timeout=EXTERNAL_HTTP_TIMEOUT_SECONDS,
126
+ )
127
+ comments_future = executor.submit(
128
+ _run_with_context,
129
+ ctx,
130
+ requests.get,
131
+ upstream_url(f"https://jsonplaceholder.typicode.com/posts/{post_id}/comments"),
132
+ timeout=EXTERNAL_HTTP_TIMEOUT_SECONDS,
133
+ )
134
+
135
+ post_response = post_future.result()
136
+ comments_response = comments_future.result()
137
+
138
+ return JsonResponse(
139
+ {
140
+ "post": post_response.json(),
141
+ "comments": comments_response.json(),
142
+ }
143
+ )
144
+ except Exception as e:
145
+ return JsonResponse(
146
+ {
147
+ "post": {},
148
+ "comments": [],
149
+ "fallback": True,
150
+ "error": f"Failed to fetch post: {str(e)}",
151
+ }
152
+ )
153
+
154
+
155
+ @csrf_exempt
156
+ @require_http_methods(["DELETE"])
157
+ def delete_post(request, post_id: int):
158
+ """Delete a post via external API."""
159
+ try:
160
+ requests.delete(
161
+ upstream_url(f"https://jsonplaceholder.typicode.com/posts/{post_id}"),
162
+ timeout=EXTERNAL_HTTP_TIMEOUT_SECONDS,
163
+ )
164
+ return JsonResponse({"message": f"Post {post_id} deleted successfully"})
165
+ except Exception as e:
166
+ return JsonResponse(
167
+ {
168
+ "message": f"Post {post_id} delete fallback",
169
+ "fallback": True,
170
+ "error": f"Failed to delete post: {str(e)}",
171
+ }
172
+ )
173
+
174
+
175
+ @require_GET
176
+ def get_activity(request):
177
+ """Fetch a random activity suggestion."""
178
+ try:
179
+ response = requests.get(
180
+ upstream_url("https://bored-api.appbrewery.com/random"),
181
+ timeout=EXTERNAL_HTTP_TIMEOUT_SECONDS,
182
+ )
183
+ return JsonResponse(response.json())
184
+ except Exception as e:
185
+ return JsonResponse(
186
+ {
187
+ "activity": "Take a short walk",
188
+ "type": "relaxation",
189
+ "participants": 1,
190
+ "fallback": True,
191
+ "error": f"Failed to fetch activity: {str(e)}",
192
+ }
193
+ )
194
+
195
+
196
+ @require_GET
197
+ def csrf_form(request):
198
+ """Return an HTML form with CSRF token for testing CSRF normalization.
199
+
200
+ This endpoint tests that CSRF tokens are properly normalized during
201
+ recording so that replay comparisons succeed.
202
+ """
203
+ csrf_token = get_token(request)
204
+ html = f"""<!DOCTYPE html>
205
+ <html>
206
+ <head><title>CSRF Test Form</title></head>
207
+ <body>
208
+ <h1>CSRF Test Form</h1>
209
+ <form method="POST" action="/api/submit">
210
+ <input type="hidden" name="csrfmiddlewaretoken" value="{csrf_token}">
211
+ <input type="text" name="message" placeholder="Enter message">
212
+ <button type="submit">Submit</button>
213
+ </form>
214
+ </body>
215
+ </html>"""
216
+ return HttpResponse(html, content_type="text/html")