workers-runtime-sdk 1.8.4__tar.gz → 1.8.6__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 (192) hide show
  1. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/CHANGELOG.md +29 -0
  2. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/PKG-INFO +1 -1
  3. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/pyproject.toml +1 -1
  4. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/_workers_sdk_entropy_import_context.py +48 -0
  5. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/workers/entrypoints.py +19 -12
  6. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/workers/utils.py +16 -3
  7. workers_runtime_sdk-1.8.6/tests/bindings-test/pyproject.toml +19 -0
  8. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/test_hyperdrive_mysql.py +21 -0
  9. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/test_hyperdrive_postgresql.py +65 -0
  10. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/test_workflow.py +26 -1
  11. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/worker_workflow.py +44 -0
  12. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/test_in_workerd.py +28 -10
  13. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/worker.py +1 -1
  14. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/asgi-ws-disconnect/tests/test_ws_disconnect.py +1 -3
  15. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/entropy-patches/pyproject.toml +2 -0
  16. workers_runtime_sdk-1.8.6/tests/workerd-test/entropy-patches/tests/test_mcp.py +10 -0
  17. workers_runtime_sdk-1.8.6/tests/workerd-test/entropy-patches/tests/test_opentelemetry.py +8 -0
  18. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/entropy-patches/worker.py +2 -0
  19. workers_runtime_sdk-1.8.6/tests/workerd-test/http-client/http-client.wd-test +45 -0
  20. workers_runtime_sdk-1.8.6/tests/workerd-test/http-client/origin.py +60 -0
  21. workers_runtime_sdk-1.8.6/tests/workerd-test/http-client/pyproject.toml +5 -0
  22. workers_runtime_sdk-1.8.6/tests/workerd-test/http-client/tests/test_http_client.py +162 -0
  23. workers_runtime_sdk-1.8.6/tests/workerd-test/http-client/tests/test_urllib_request.py +121 -0
  24. workers_runtime_sdk-1.8.6/tests/workerd-test/http-client/worker.py +14 -0
  25. workers_runtime_sdk-1.8.6/tests/workerd-test/http-client/wrangler.jsonc +5 -0
  26. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/uv.lock +1 -1
  27. workers_runtime_sdk-1.8.4/tests/bindings-test/pyproject.toml +0 -8
  28. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/.gitignore +0 -0
  29. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/AGENTS.md +0 -0
  30. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/README.md +0 -0
  31. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/_cloudflare_compat_flags.pyi +0 -0
  32. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/_pyodide_entrypoint_helper.pyi +0 -0
  33. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/_workers_sdk_package_patches.py +0 -0
  34. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/_workers_sdk_patch_loader.pth +0 -0
  35. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/_workers_sdk_patch_loader.py +0 -0
  36. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/asgi.py +0 -0
  37. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/workers/__init__.py +0 -0
  38. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/workers/asgi.py +0 -0
  39. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/workers/blob.py +0 -0
  40. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/workers/fetch.py +0 -0
  41. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/workers/formdata.py +0 -0
  42. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/workers/py.typed +0 -0
  43. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/workers/request.py +0 -0
  44. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/workers/response.py +0 -0
  45. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/workers/rpc.py +0 -0
  46. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/workers/types.py +0 -0
  47. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/workers/workflows.py +0 -0
  48. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/src/workers/wsgi.py +0 -0
  49. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/public/data.json +0 -0
  50. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/public/hello.txt +0 -0
  51. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/conftest.py +0 -0
  52. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/test_analytics_engine.py +0 -0
  53. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/test_assets.py +0 -0
  54. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/test_d1.py +0 -0
  55. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/test_do.py +0 -0
  56. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/test_images.py +0 -0
  57. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/test_kv.py +0 -0
  58. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/test_mtls.py +0 -0
  59. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/test_queue.py +0 -0
  60. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/test_r2.py +0 -0
  61. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/test_ratelimit.py +0 -0
  62. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/test_vectorize.py +0 -0
  63. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/test_version_metadata.py +0 -0
  64. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/worker.py +0 -0
  65. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/src/worker_durable_object.py +0 -0
  66. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/bindings-test/wrangler.jsonc +0 -0
  67. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/conftest.py +0 -0
  68. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/test_bindings.py +0 -0
  69. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/test_fastapi.py +0 -0
  70. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/test_flask.py +0 -0
  71. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/test_web_frameworks.py +0 -0
  72. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/pyproject.toml +0 -0
  73. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/_client.py +0 -0
  74. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/conftest.py +0 -0
  75. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/django_app/__init__.py +0 -0
  76. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/django_app/api_urls.py +0 -0
  77. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/django_app/auth_backend.py +0 -0
  78. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/django_app/drf_auth.py +0 -0
  79. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/django_app/drf_serializers.py +0 -0
  80. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/django_app/drf_throttling.py +0 -0
  81. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/django_app/drf_views.py +0 -0
  82. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/django_app/forms.py +0 -0
  83. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/django_app/middleware.py +0 -0
  84. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/django_app/templatetags/__init__.py +0 -0
  85. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/django_app/templatetags/custom_tags.py +0 -0
  86. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/django_app/urls.py +0 -0
  87. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/django_app/views.py +0 -0
  88. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/templates/base.html +0 -0
  89. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/templates/context_test.html +0 -0
  90. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/templates/csrf_form.html +0 -0
  91. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/templates/hello.html +0 -0
  92. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_async_utilities.py +0 -0
  93. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_auth.py +0 -0
  94. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_caching.py +0 -0
  95. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_cors.py +0 -0
  96. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_csrf.py +0 -0
  97. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_drf_auth_permissions.py +0 -0
  98. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_drf_content_negotiation.py +0 -0
  99. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_drf_serializers.py +0 -0
  100. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_drf_throttling.py +0 -0
  101. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_drf_versioning.py +0 -0
  102. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_drf_views.py +0 -0
  103. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_error_handling.py +0 -0
  104. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_file_uploads.py +0 -0
  105. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_forms.py +0 -0
  106. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_middleware.py +0 -0
  107. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_pagination.py +0 -0
  108. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_request_response.py +0 -0
  109. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_sessions.py +0 -0
  110. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_signals.py +0 -0
  111. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_streaming.py +0 -0
  112. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_templates.py +0 -0
  113. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_url_routing.py +0 -0
  114. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/test_views_basic.py +0 -0
  115. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/src/worker.py +0 -0
  116. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/django-async/wrangler.jsonc +0 -0
  117. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/public/data.json +0 -0
  118. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/public/index.html +0 -0
  119. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/public/style.css +0 -0
  120. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/pyproject.toml +0 -0
  121. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/_client.py +0 -0
  122. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/conftest.py +0 -0
  123. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/static/app.css +0 -0
  124. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/static/data.json +0 -0
  125. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/static/hello.txt +0 -0
  126. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/static/index.html +0 -0
  127. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/test_assets.py +0 -0
  128. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/test_error_handling.py +0 -0
  129. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/test_platform_boundaries.py +0 -0
  130. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/test_platform_io.py +0 -0
  131. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/test_platform_lifecycle.py +0 -0
  132. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/test_response_types.py +0 -0
  133. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/test_routing.py +0 -0
  134. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/test_staticfiles.py +0 -0
  135. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/test_sync_handlers.py +0 -0
  136. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/src/test_websocket.py +0 -0
  137. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/fastapi-tests/wrangler.jsonc +0 -0
  138. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/flask-tests/pyproject.toml +0 -0
  139. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/flask-tests/src/test_response.py +0 -0
  140. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/flask-tests/src/worker.py +0 -0
  141. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/web-frameworks-test/flask-tests/wrangler.jsonc +0 -0
  142. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/asgi/asgi.wd-test +0 -0
  143. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/asgi/pyproject.toml +0 -0
  144. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/asgi/tests/test_asgi.py +0 -0
  145. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/asgi/worker.py +0 -0
  146. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/asgi/wrangler.jsonc +0 -0
  147. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/asgi-ws-disconnect/asgi-ws-disconnect.wd-test +0 -0
  148. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/asgi-ws-disconnect/pyproject.toml +0 -0
  149. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/asgi-ws-disconnect/worker.py +0 -0
  150. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/asgi-ws-disconnect/wrangler.jsonc +0 -0
  151. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object/durable-object.wd-test +0 -0
  152. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object/pyproject.toml +0 -0
  153. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object/worker.py +0 -0
  154. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object/wrangler.jsonc +0 -0
  155. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object-abort/durable-object-abort.wd-test +0 -0
  156. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object-abort/pyproject.toml +0 -0
  157. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object-abort/worker.py +0 -0
  158. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object-abort/wrangler.jsonc +0 -0
  159. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object-inheritance/durable-object-inheritance.wd-test +0 -0
  160. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object-inheritance/pyproject.toml +0 -0
  161. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object-inheritance/worker.py +0 -0
  162. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object-inheritance/wrangler.jsonc +0 -0
  163. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object-websocket/durable-object-websocket.wd-test +0 -0
  164. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object-websocket/pyproject.toml +0 -0
  165. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object-websocket/tester.js +0 -0
  166. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object-websocket/worker.py +0 -0
  167. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/durable-object-websocket/wrangler.jsonc +0 -0
  168. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/entropy-patches/entropy-patches.wd-test +0 -0
  169. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/entropy-patches/tests/test_aiohttp_websocket.py +0 -0
  170. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/entropy-patches/tests/test_langsmith.py +0 -0
  171. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/entropy-patches/tests/test_litestar.py +0 -0
  172. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/entropy-patches/tests/test_numpy.py +0 -0
  173. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/entropy-patches/tests/test_pydantic.py +0 -0
  174. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/entropy-patches/tests/test_rust_packages.py +0 -0
  175. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/entropy-patches/tests/test_ssl_avoidance.py +0 -0
  176. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/entropy-patches/wrangler.jsonc +0 -0
  177. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/python-rpc/pyproject.toml +0 -0
  178. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/python-rpc/python-rpc.wd-test +0 -0
  179. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/python-rpc/worker.js +0 -0
  180. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/python-rpc/worker.py +0 -0
  181. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/python-rpc/wrangler.jsonc +0 -0
  182. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/sdk/pyproject.toml +0 -0
  183. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/sdk/sdk.wd-test +0 -0
  184. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/sdk/server.py +0 -0
  185. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/sdk/tests/test_sdk.py +0 -0
  186. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/sdk/worker.py +0 -0
  187. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/sdk/wrangler.jsonc +0 -0
  188. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/wsgi/pyproject.toml +0 -0
  189. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/wsgi/tests/test_wsgi.py +0 -0
  190. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/wsgi/worker.py +0 -0
  191. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/wsgi/wrangler.jsonc +0 -0
  192. {workers_runtime_sdk-1.8.4 → workers_runtime_sdk-1.8.6}/tests/workerd-test/wsgi/wsgi.wd-test +0 -0
@@ -2,6 +2,35 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v1.8.6 (2026-09-18)
6
+
7
+ ### Bug Fixes
8
+
9
+ - **runtime-sdk**: Convert workflow step results with python_to_rpc
10
+ ([`4220da8`](https://github.com/cloudflare/workers-py/commit/4220da80451073afd7140e091811a8dd4b879aa5))
11
+
12
+ - **runtime-sdk**: Don't crash in _from_js_error on messages without a traceback
13
+ ([`a9159df`](https://github.com/cloudflare/workers-py/commit/a9159df2ede8f1a2ff420b8bac1d0e0199506e86))
14
+
15
+ - **runtime-sdk**: Key workflow step memoisation by closure instead of step name
16
+ ([`610d18f`](https://github.com/cloudflare/workers-py/commit/610d18f7ce350bbd40cd20312bb26334f67923f5))
17
+
18
+ - **runtime-sdk**: Raise a TypeError for invalid legacy `depends` entries
19
+ ([`10a2bcc`](https://github.com/cloudflare/workers-py/commit/10a2bccbe91d06e8c0fb187a661bb78a4d236342))
20
+
21
+ - **runtime-sdk**: Recover Python exception types under enhanced error serialization
22
+ ([`53be6db`](https://github.com/cloudflare/workers-py/commit/53be6db4a8ff62e03b2eb4e4896d45d6dd5d748b))
23
+
24
+
25
+ ## v1.8.5 (2026-09-17)
26
+
27
+ ### Bug Fixes
28
+
29
+ - **runtime-sdk**: Fix top-level import for opentelemetry package
30
+ ([#248](https://github.com/cloudflare/workers-py/pull/248),
31
+ [`338c12e`](https://github.com/cloudflare/workers-py/commit/338c12e5dc6aada9dd20968fdae6bb6e805ad33e))
32
+
33
+
5
34
  ## v1.8.4 (2026-09-08)
6
35
 
7
36
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: workers-runtime-sdk
3
- Version: 1.8.4
3
+ Version: 1.8.6
4
4
  Summary: Python SDK for Cloudflare Workers
5
5
  Project-URL: Homepage, https://github.com/cloudflare/workers-py
6
6
  Project-URL: Bug Tracker, https://github.com/cloudflare/workers-py/issues
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "workers-runtime-sdk"
7
- version = "1.8.4"
7
+ version = "1.8.6"
8
8
  description = "Python SDK for Cloudflare Workers"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -4,6 +4,7 @@ Top level entropy patches for packages
4
4
 
5
5
  import sys
6
6
  from contextlib import contextmanager
7
+ from importlib.metadata import PackageNotFoundError, version
7
8
 
8
9
  from _cloudflare.allow_entropy import (
9
10
  allow_bad_entropy_calls,
@@ -17,6 +18,29 @@ from _cloudflare.import_patch_manager import (
17
18
  )
18
19
 
19
20
 
21
+ @contextmanager
22
+ def allow_bad_entropy_calls_for_version(
23
+ package_name: str,
24
+ num_calls: int,
25
+ min_version: tuple[int, ...],
26
+ max_version: tuple[int, ...] | None = None,
27
+ ):
28
+ try:
29
+ package_version = tuple(map(int, version(package_name).split(".")))
30
+ except PackageNotFoundError:
31
+ yield
32
+ return
33
+
34
+ if package_version < min_version or (
35
+ max_version is not None and package_version > max_version
36
+ ):
37
+ yield
38
+ return
39
+
40
+ with allow_bad_entropy_calls(num_calls):
41
+ yield
42
+
43
+
20
44
  class STATE:
21
45
  imported_rust_package = False
22
46
  numpy_random = None
@@ -180,6 +204,30 @@ def langchain_openai_chat_models_base_context(module):
180
204
  yield
181
205
 
182
206
 
207
+ @register_exec_patch("opentelemetry.context")
208
+ @contextmanager
209
+ def opentelemetry_context(module):
210
+ # OpenTelemetry creates three UUID-backed keys.
211
+ with allow_bad_entropy_calls_for_version("opentelemetry-api", 3, (1, 40, 0)):
212
+ yield
213
+
214
+
215
+ @register_exec_patch("opentelemetry.trace.propagation")
216
+ @contextmanager
217
+ def opentelemetry_trace_propagation_context(module):
218
+ # OpenTelemetry creates a UUID-backed key.
219
+ with allow_bad_entropy_calls(1):
220
+ yield
221
+
222
+
223
+ @register_exec_patch("opentelemetry.baggage")
224
+ @contextmanager
225
+ def opentelemetry_baggage_context(module):
226
+ # OpenTelemetry creates a UUID-backed key.
227
+ with allow_bad_entropy_calls(1):
228
+ yield
229
+
230
+
183
231
  @register_exec_patch("litestar.openapi.controller")
184
232
  @register_exec_patch("litestar.constants")
185
233
  @contextmanager
@@ -116,7 +116,7 @@ class _WorkflowStepWrapper:
116
116
  func, depends, implicit
117
117
  )
118
118
  results = await self._gather_results(results_future_list, concurrent)
119
- return await _do_call(self, step_name, config, func, *results)
119
+ return await _do_call(self, step_name, wrapper, config, func, *results)
120
120
 
121
121
  wrapper._step_name = step_name
122
122
  self.step_closures[step_name] = wrapper
@@ -157,7 +157,13 @@ class _WorkflowStepWrapper:
157
157
  if p.name == "ctx":
158
158
  results_future_list.append(p)
159
159
  else:
160
- results_future_list.append(depends[curr])
160
+ dep = depends[curr]
161
+ if not hasattr(dep, "_step_name"):
162
+ raise TypeError(
163
+ f"'depends' entry for parameter {p.name!r} is not a "
164
+ "function decorated with step.do"
165
+ )
166
+ results_future_list.append(dep)
161
167
  curr += 1
162
168
 
163
169
  return results_future_list
@@ -194,17 +200,17 @@ class _WorkflowStepWrapper:
194
200
  )
195
201
 
196
202
  async def _resolve_dependency(self, dep):
197
- if hasattr(dep, "name") and dep.name == "ctx":
203
+ if isinstance(dep, inspect.Parameter) and dep.name == "ctx":
198
204
  return dep
199
- elif dep._step_name in self._memoized_dependencies:
200
- return self._memoized_dependencies[dep._step_name]
201
- elif dep._step_name in self._in_flight:
202
- return await self._in_flight[dep._step_name]
205
+ elif dep in self._memoized_dependencies:
206
+ return self._memoized_dependencies[dep]
207
+ elif dep in self._in_flight:
208
+ return await self._in_flight[dep]
203
209
 
204
210
  return await dep()
205
211
 
206
212
 
207
- async def _do_call(entrypoint, name, config, callback, *results):
213
+ async def _do_call(entrypoint, name, key, config, callback, *results):
208
214
  async def _callback(ctx=None):
209
215
  # deconstruct the actual ctx object
210
216
  resolved_results = tuple(
@@ -217,7 +223,8 @@ async def _do_call(entrypoint, name, config, callback, *results):
217
223
 
218
224
  if inspect.iscoroutine(result):
219
225
  result = await result
220
- return to_js(result, dict_converter=Object.fromEntries)
226
+ # The step result crosses the RPC boundary back to the Workflows engine
227
+ return python_to_rpc(result)
221
228
 
222
229
  async def _closure():
223
230
  try:
@@ -233,13 +240,13 @@ async def _do_call(entrypoint, name, config, callback, *results):
233
240
  raise _from_js_error(exc) from exc
234
241
 
235
242
  task = create_task(_closure())
236
- entrypoint._in_flight[name] = task
243
+ entrypoint._in_flight[key] = task
237
244
 
238
245
  try:
239
246
  result = await task
240
- entrypoint._memoized_dependencies[name] = result
247
+ entrypoint._memoized_dependencies[key] = result
241
248
  finally:
242
- del entrypoint._in_flight[name]
249
+ entrypoint._in_flight.pop(key, None)
243
250
 
244
251
  return result
245
252
 
@@ -147,11 +147,24 @@ def _to_python_exception(exc: JsException) -> Exception:
147
147
  def _from_js_error(exc: JsException) -> Exception:
148
148
  # convert into Python exception after a full round trip
149
149
  # Python - JS - Python
150
- if not exc.message or not exc.message.startswith("PythonError"):
150
+ message = exc.message or ""
151
+
152
+ # A Python exception that escaped to JS is a Pyodide `PythonError` whose
153
+ # message is the formatted traceback. Depending on how it was serialized
154
+ # over RPC it either keeps its name or arrives as a plain `Error` with
155
+ # "PythonError: " folded into the message.
156
+ if getattr(exc, "name", None) != "PythonError" and not message.startswith(
157
+ "PythonError"
158
+ ):
151
159
  return _to_python_exception(exc)
152
160
 
153
- # extract the Python exception type from the traceback
154
- error_message_last_line = exc.message.split("\n")[-2]
161
+ # extract the Python exception type from the last line of the traceback. The
162
+ # message may have been stripped down to just "PythonError" when crossing an RPC
163
+ # boundary, in which case there is no traceback to inspect.
164
+ lines = message.rstrip().split("\n")
165
+ if len(lines) < 2:
166
+ return _to_python_exception(exc)
167
+ error_message_last_line = lines[-1]
155
168
  if error_message_last_line.startswith("TypeError"):
156
169
  return TypeError(error_message_last_line)
157
170
  elif error_message_last_line.startswith("ValueError"):
@@ -0,0 +1,19 @@
1
+ [project]
2
+ name = "bindings-test"
3
+ version = "0.1.0"
4
+ requires-python = ">=3.12"
5
+ dependencies = [
6
+ "pytest",
7
+ "pytest-asyncio<1.2.0",
8
+ # These are for hyperdrive tests
9
+ "pg8000",
10
+ "pymysql",
11
+ "aiomysql",
12
+ "psycopg[binary]; python_version >= '3.14'",
13
+ "asyncpg; python_version >= '3.14'",
14
+ "cryptography",
15
+ "testlib",
16
+ ]
17
+
18
+ [tool.uv.sources]
19
+ testlib = { path = "../testlib/dist/testlib-0.0.0-py3-none-any.whl" }
@@ -24,6 +24,7 @@ uv run pytest tests/test_bindings.py -m hyperdrive -k mysql
24
24
 
25
25
  import sys
26
26
 
27
+ import aiomysql
27
28
  import pymysql
28
29
  import pytest
29
30
  from conftest import unique_table_name
@@ -58,6 +59,26 @@ async def test_connect(env):
58
59
  conn.close()
59
60
 
60
61
 
62
+ @pytest.mark.asyncio
63
+ async def test_connect_aiomysql(env):
64
+ hd = env.HYPERDRIVE_MYSQL
65
+ conn = await aiomysql.connect(
66
+ host=hd.host,
67
+ port=int(hd.port),
68
+ user=hd.user,
69
+ password=hd.password,
70
+ db=hd.database,
71
+ # Hyperdrive terminates TLS to the origin, so this hop is plaintext.
72
+ ssl=None,
73
+ )
74
+ try:
75
+ async with conn.cursor() as cur:
76
+ await cur.execute("SELECT %s", (1,))
77
+ assert await cur.fetchone() == (1,)
78
+ finally:
79
+ await conn.ensure_closed()
80
+
81
+
61
82
  @pytest.mark.asyncio
62
83
  async def test_create_insert_select(env):
63
84
  conn = _connect(env)
@@ -61,6 +61,71 @@ async def test_connect(env):
61
61
  conn.close()
62
62
 
63
63
 
64
+ @pytest.mark.asyncio
65
+ async def test_connect_psycopg(env):
66
+ import psycopg # noqa: PLC0415
67
+
68
+ assert psycopg.pq.__impl__ == "binary"
69
+ hd = env.HYPERDRIVE_PG
70
+ with psycopg.connect(
71
+ host=hd.host,
72
+ port=int(hd.port),
73
+ user=hd.user,
74
+ password=hd.password,
75
+ dbname=hd.database,
76
+ # Hyperdrive terminates TLS to the origin, so this hop is plaintext.
77
+ sslmode="disable",
78
+ ) as conn:
79
+ with conn.cursor() as cur:
80
+ cur.execute("SELECT %s", (1,))
81
+ assert cur.fetchone() == (1,)
82
+
83
+
84
+ @pytest.mark.asyncio
85
+ async def test_asyncpg_crud(env):
86
+ import asyncpg # noqa: PLC0415
87
+
88
+ hd = env.HYPERDRIVE_PG
89
+ conn = await asyncpg.connect(
90
+ host=hd.host,
91
+ port=int(hd.port),
92
+ user=hd.user,
93
+ password=hd.password,
94
+ database=hd.database,
95
+ # Hyperdrive terminates TLS to the origin, so this hop is plaintext.
96
+ ssl=False,
97
+ )
98
+ table = unique_table_name()
99
+ try:
100
+ await conn.execute(
101
+ f"CREATE TABLE {table} (id SERIAL PRIMARY KEY, name TEXT, value INT)"
102
+ )
103
+ await conn.execute(
104
+ f"INSERT INTO {table} (name, value) VALUES ($1, $2)", "alpha", 1
105
+ )
106
+
107
+ row = await conn.fetchrow(
108
+ f"SELECT name, value FROM {table} WHERE name = $1", "alpha"
109
+ )
110
+ assert tuple(row) == ("alpha", 1)
111
+
112
+ await conn.execute(
113
+ f"UPDATE {table} SET value = $1 WHERE name = $2", 11, "alpha"
114
+ )
115
+ assert (
116
+ await conn.fetchval(f"SELECT value FROM {table} WHERE name = $1", "alpha")
117
+ == 11
118
+ )
119
+
120
+ await conn.execute(f"DELETE FROM {table} WHERE name = $1", "alpha")
121
+ assert await conn.fetchval(f"SELECT COUNT(*) FROM {table}") == 0
122
+ finally:
123
+ try:
124
+ await conn.execute(f"DROP TABLE IF EXISTS {table}")
125
+ finally:
126
+ await conn.close()
127
+
128
+
64
129
  @pytest.mark.asyncio
65
130
  async def test_create_insert_select(env):
66
131
  conn = _connect(env)
@@ -159,11 +159,36 @@ async def test_error_handling_catch(env):
159
159
  # Per the docs, a step error propagates to run() and is catchable with
160
160
  # `except Exception`. Neither the concrete type nor the original message is
161
161
  # guaranteed to survive the RPC layer, so we assert the reliable contract:
162
- # the error was caught and a message was produced.
162
+ # the error was caught and a message was produced, and that the SDK's own
163
+ # error translation did not blow up (e.g. IndexError while parsing it).
163
164
  assert status["output"]["caught"] is not None
165
+ assert status["output"]["caught"] != "IndexError"
164
166
  assert status["output"]["message"]
165
167
 
166
168
 
169
+ async def test_duplicate_step_names(env):
170
+ instance = await env.MY_WORKFLOW.create(
171
+ {"params": {"mode": "duplicate_step_names"}}
172
+ )
173
+ status = await _poll(instance)
174
+ assert status["status"] == "complete", f"unexpected status: {dict(status)!r}"
175
+ assert status["output"]["concurrent"] == [1, 2]
176
+ assert status["output"]["uses"] == 20
177
+
178
+
179
+ async def test_step_output_conversion(env):
180
+ instance = await env.MY_WORKFLOW.create(
181
+ {"params": {"mode": "step_output_conversion"}}
182
+ )
183
+ status = await _poll(instance)
184
+ assert status["status"] == "complete", f"unexpected status: {dict(status)!r}"
185
+ out = status["output"]
186
+ assert out["when_is_datetime"] is True
187
+ assert out["year"] == 2026
188
+ assert out["nothing_is_none"] is True
189
+ assert out["nested_nothing_is_none"] is True
190
+
191
+
167
192
  # The tests below pass pre-converted (to_js) objects, the legacy pattern from the
168
193
  # Workflows docs, to ensure existing code keeps working now that the binding
169
194
  # auto-converts plain Python objects.
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  import datetime
2
3
 
3
4
  from workers import WorkflowEntrypoint
@@ -19,6 +20,8 @@ class TestWorkflow(WorkflowEntrypoint):
19
20
  "retry": self._retry,
20
21
  "non_retryable": self._non_retryable,
21
22
  "catch_error": self._catch_error,
23
+ "duplicate_step_names": self._duplicate_step_names,
24
+ "step_output_conversion": self._step_output_conversion,
22
25
  }
23
26
  handler = handlers.get(mode)
24
27
  if handler is None:
@@ -115,6 +118,47 @@ class TestWorkflow(WorkflowEntrypoint):
115
118
 
116
119
  return await boom()
117
120
 
121
+ async def _duplicate_step_names(self, event, step):
122
+ # The engine disambiguates repeated step names with a counter, so two
123
+ # steps sharing a name must not share memoised results or in-flight tasks.
124
+ @step.do("dup")
125
+ async def first():
126
+ return 1
127
+
128
+ @step.do("dup")
129
+ async def second():
130
+ return 2
131
+
132
+ # Implicit dependencies resolve by step name, so `dup` refers to the most
133
+ # recently registered closure (`second`) and must return its result.
134
+ @step.do()
135
+ async def uses(dup):
136
+ return dup * 10
137
+
138
+ # Run both same-named steps concurrently so they are in flight together.
139
+ concurrent = list(await asyncio.gather(first(), second()))
140
+ return {"concurrent": concurrent, "uses": await uses()}
141
+
142
+ async def _step_output_conversion(self, event, step):
143
+ @step.do("produce")
144
+ async def produce():
145
+ return {
146
+ "when": datetime.datetime(2026, 1, 2, 3, 4, 5),
147
+ "nothing": None,
148
+ "nested": {"nothing": None},
149
+ }
150
+
151
+ @step.do()
152
+ async def consume(produce):
153
+ return {
154
+ "when_is_datetime": isinstance(produce["when"], datetime.datetime),
155
+ "year": produce["when"].year,
156
+ "nothing_is_none": produce["nothing"] is None,
157
+ "nested_nothing_is_none": produce["nested"]["nothing"] is None,
158
+ }
159
+
160
+ return await consume()
161
+
118
162
  async def _catch_error(self, event, step):
119
163
  @step.do(
120
164
  "failing-step",
@@ -29,6 +29,30 @@ def discover_workerd_tests():
29
29
  return cases
30
30
 
31
31
 
32
+ def resolve_workerd(target: Path) -> str:
33
+ """Return the path to the workerd binary to use for tests.
34
+
35
+ If the ``WORKERD_PATH`` environment variable is set, it is used as-is (this
36
+ is useful for testing against a locally built workerd). Otherwise, workerd
37
+ is installed from npm into ``target`` and the installed binary is used.
38
+ """
39
+ workerd_path = os.environ.get("WORKERD_PATH")
40
+ if workerd_path:
41
+ workerd_bin = Path(workerd_path).expanduser().resolve()
42
+ if not workerd_bin.is_file():
43
+ raise FileNotFoundError(
44
+ f"WORKERD_PATH is set but does not point to a file: {workerd_bin}"
45
+ )
46
+ return str(workerd_bin)
47
+
48
+ subprocess.run(
49
+ ["npm", "i", "workerd"],
50
+ cwd=target,
51
+ check=True,
52
+ )
53
+ return "node_modules/workerd/bin/workerd"
54
+
55
+
32
56
  def embed(dir: Path, root: Path, level: int = 0):
33
57
  modules = []
34
58
  module_path_root = dir
@@ -79,10 +103,8 @@ def test_in_workerd( # noqa: PLR0913, PLR0917 (too-many-arguments)
79
103
  "wsgi requires pyodide.ffi.run_sync (JSPI), unavailable before 2026-01-01"
80
104
  )
81
105
 
82
- if test_dir.name == "entropy-patches" and python_version == "3.14":
83
- pytest.skip(
84
- "TODO: enable me after https://github.com/cloudflare/workerd/pull/7200 lands in wrangler"
85
- )
106
+ if test_dir.name == "http-client" and python_version < "3.14":
107
+ pytest.skip("HTTP client compatibility tests require Python 3.14 or newer")
86
108
 
87
109
  color = pytestconfig.get_terminal_writer().hasmarkup
88
110
  target = tmp_path / test_dir.name
@@ -120,13 +142,9 @@ def test_in_workerd( # noqa: PLR0913, PLR0917 (too-many-arguments)
120
142
  )
121
143
  configure_compatibility(wd_config, compat_config)
122
144
 
123
- subprocess.run(
124
- ["npm", "i", "workerd"],
125
- cwd=target,
126
- check=True,
127
- )
145
+ workerd_bin = resolve_workerd(target)
128
146
  workerd_common = [
129
- "node_modules/workerd/bin/workerd",
147
+ workerd_bin,
130
148
  "test",
131
149
  wd_test_file,
132
150
  "--experimental",
@@ -602,7 +602,7 @@ class FastAPIAppPlugin:
602
602
 
603
603
  @app.get("/run-tests/{suite_name:path}")
604
604
  async def run_suite(suite_name: str, request: Request):
605
- runner = TestRunner(request.scope["env"])
605
+ runner = TestRunner(request.scope["env"], extra_plugins=[FastAPIAppPlugin()])
606
606
  result = runner.run_suite(suite_name)
607
607
  return JSONResponse(result.payload, status_code=result.status)
608
608
 
@@ -1,5 +1,6 @@
1
1
  import asyncio
2
2
  import contextlib
3
+ import json
3
4
 
4
5
  import pytest
5
6
  from pyodide.ffi import create_proxy, to_js
@@ -61,9 +62,6 @@ async def _ws_connect(path):
61
62
  )
62
63
 
63
64
 
64
- import json
65
-
66
-
67
65
  async def _events():
68
66
  response = await asyncio.wait_for(
69
67
  env.SELF.fetch("http://example.com/ws-events"), TIMEOUT_S
@@ -18,4 +18,6 @@ dependencies = [
18
18
  # "langchain-openai",
19
19
  # "openai",
20
20
  "litestar",
21
+ "opentelemetry-api",
22
+ "mcp; python_version >= '3.14'",
21
23
  ]
@@ -0,0 +1,10 @@
1
+ # ruff: noqa: F401
2
+ import sys
3
+
4
+ if sys.version_info >= (3, 14):
5
+ import mcp
6
+
7
+
8
+ def test_import():
9
+ # make sure this file is collected by pytest
10
+ pass
@@ -0,0 +1,8 @@
1
+ # ruff: noqa: F401
2
+ import opentelemetry.context
3
+ import opentelemetry.trace
4
+
5
+
6
+ def test_import():
7
+ # make sure this file is collected by pytest
8
+ pass
@@ -4,7 +4,9 @@ from tests import ( # noqa: F401
4
4
  test_aiohttp_websocket,
5
5
  test_langsmith,
6
6
  test_litestar,
7
+ test_mcp,
7
8
  test_numpy,
9
+ test_opentelemetry,
8
10
  test_pydantic,
9
11
  test_rust_packages,
10
12
  test_ssl_avoidance,
@@ -0,0 +1,45 @@
1
+ using Workerd = import "/workerd/workerd.capnp";
2
+
3
+ const client :Workerd.Worker = (
4
+ modules = [
5
+ (name = "worker.py", pythonModule = embed "worker.py"),
6
+ %PYTHON_MODULES
7
+ ],
8
+ bindings = [
9
+ (name = "color", json = "%COLOR"),
10
+ ],
11
+ globalOutbound = "external",
12
+ compatibilityDate = "%COMPAT_DATE",
13
+ compatibilityFlags = ["python_workers", "service_binding_extra_handlers"],
14
+ );
15
+
16
+ const origin :Workerd.Worker = (
17
+ modules = [
18
+ (name = "origin.py", pythonModule = embed "origin.py"),
19
+ %PYTHON_MODULES
20
+ ],
21
+ compatibilityDate = "%COMPAT_DATE",
22
+ compatibilityFlags = ["python_workers"],
23
+ );
24
+
25
+ const unitTests :Workerd.Config = (
26
+ services = [
27
+ (
28
+ name = "external",
29
+ external = (
30
+ address = "loopback:raw-http-origin",
31
+ tcp = (),
32
+ ),
33
+ ),
34
+ (name = "http-client", worker = .client),
35
+ (name = "http-origin", worker = .origin),
36
+ ],
37
+ sockets = [
38
+ (
39
+ name = "raw-http-origin",
40
+ address = "loopback:raw-http-origin",
41
+ http = (),
42
+ service = "http-origin",
43
+ ),
44
+ ],
45
+ );