workers-runtime-sdk 1.8.6__tar.gz → 1.9.1__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 (208) hide show
  1. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/CHANGELOG.md +22 -0
  2. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/PKG-INFO +1 -1
  3. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/pyproject.toml +1 -1
  4. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/_workers_sdk_entropy_import_context.py +1 -0
  5. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/workers/entrypoints.py +22 -2
  6. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/workers/utils.py +35 -1
  7. workers_runtime_sdk-1.9.1/src/workers/workflows.js +91 -0
  8. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/pyproject.toml +7 -2
  9. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/test_workflow.py +11 -1
  10. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/worker_workflow.py +20 -4
  11. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/conftest.py +11 -23
  12. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/test_in_workerd.py +23 -19
  13. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/pyproject.toml +3 -1
  14. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/pyproject.toml +3 -1
  15. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/worker.py +4 -11
  16. workers_runtime_sdk-1.9.1/tests/web-frameworks-test/flask-tests/pyproject.toml +9 -0
  17. workers_runtime_sdk-1.9.1/tests/workerd-test/asgi/pyproject.toml +9 -0
  18. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/asgi/worker.py +2 -20
  19. workers_runtime_sdk-1.9.1/tests/workerd-test/asgi-ws-disconnect/pyproject.toml +9 -0
  20. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/asgi-ws-disconnect/worker.py +2 -19
  21. workers_runtime_sdk-1.9.1/tests/workerd-test/durable-object/pyproject.toml +8 -0
  22. workers_runtime_sdk-1.9.1/tests/workerd-test/durable-object-abort/pyproject.toml +8 -0
  23. workers_runtime_sdk-1.9.1/tests/workerd-test/durable-object-inheritance/pyproject.toml +8 -0
  24. workers_runtime_sdk-1.9.1/tests/workerd-test/durable-object-websocket/pyproject.toml +8 -0
  25. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/entropy-patches/pyproject.toml +5 -0
  26. workers_runtime_sdk-1.9.1/tests/workerd-test/entropy-patches/tests/test_jsonschema.py +9 -0
  27. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/entropy-patches/worker.py +1 -0
  28. workers_runtime_sdk-1.9.1/tests/workerd-test/http-client/pyproject.toml +8 -0
  29. workers_runtime_sdk-1.9.1/tests/workerd-test/python-rpc/pyproject.toml +8 -0
  30. workers_runtime_sdk-1.9.1/tests/workerd-test/sdk/pyproject.toml +9 -0
  31. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/sdk/worker.py +2 -21
  32. workers_runtime_sdk-1.9.1/tests/workerd-test/workflow/worker.js +112 -0
  33. workers_runtime_sdk-1.9.1/tests/workerd-test/workflow/worker.py +72 -0
  34. workers_runtime_sdk-1.9.1/tests/workerd-test/workflow/workflow.wd-test +30 -0
  35. workers_runtime_sdk-1.9.1/tests/workerd-test/workflow/wrangler.jsonc +5 -0
  36. workers_runtime_sdk-1.9.1/tests/workerd-test/wsgi/pyproject.toml +9 -0
  37. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/wsgi/worker.py +2 -20
  38. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/uv.lock +12 -1
  39. workers_runtime_sdk-1.8.6/tests/web-frameworks-test/flask-tests/pyproject.toml +0 -8
  40. workers_runtime_sdk-1.8.6/tests/workerd-test/asgi/pyproject.toml +0 -5
  41. workers_runtime_sdk-1.8.6/tests/workerd-test/asgi-ws-disconnect/pyproject.toml +0 -5
  42. workers_runtime_sdk-1.8.6/tests/workerd-test/durable-object/pyproject.toml +0 -5
  43. workers_runtime_sdk-1.8.6/tests/workerd-test/durable-object-inheritance/pyproject.toml +0 -5
  44. workers_runtime_sdk-1.8.6/tests/workerd-test/durable-object-websocket/pyproject.toml +0 -5
  45. workers_runtime_sdk-1.8.6/tests/workerd-test/http-client/pyproject.toml +0 -5
  46. workers_runtime_sdk-1.8.6/tests/workerd-test/python-rpc/pyproject.toml +0 -5
  47. workers_runtime_sdk-1.8.6/tests/workerd-test/sdk/pyproject.toml +0 -5
  48. workers_runtime_sdk-1.8.6/tests/workerd-test/wsgi/pyproject.toml +0 -5
  49. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/.gitignore +0 -0
  50. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/AGENTS.md +0 -0
  51. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/README.md +0 -0
  52. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/_cloudflare_compat_flags.pyi +0 -0
  53. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/_pyodide_entrypoint_helper.pyi +0 -0
  54. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/_workers_sdk_package_patches.py +0 -0
  55. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/_workers_sdk_patch_loader.pth +0 -0
  56. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/_workers_sdk_patch_loader.py +0 -0
  57. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/asgi.py +0 -0
  58. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/workers/__init__.py +0 -0
  59. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/workers/asgi.py +0 -0
  60. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/workers/blob.py +0 -0
  61. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/workers/fetch.py +0 -0
  62. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/workers/formdata.py +0 -0
  63. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/workers/py.typed +0 -0
  64. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/workers/request.py +0 -0
  65. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/workers/response.py +0 -0
  66. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/workers/rpc.py +0 -0
  67. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/workers/types.py +0 -0
  68. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/workers/workflows.py +0 -0
  69. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/src/workers/wsgi.py +0 -0
  70. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/public/data.json +0 -0
  71. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/public/hello.txt +0 -0
  72. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/conftest.py +0 -0
  73. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/test_analytics_engine.py +0 -0
  74. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/test_assets.py +0 -0
  75. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/test_d1.py +0 -0
  76. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/test_do.py +0 -0
  77. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/test_hyperdrive_mysql.py +0 -0
  78. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/test_hyperdrive_postgresql.py +0 -0
  79. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/test_images.py +0 -0
  80. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/test_kv.py +0 -0
  81. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/test_mtls.py +0 -0
  82. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/test_queue.py +0 -0
  83. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/test_r2.py +0 -0
  84. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/test_ratelimit.py +0 -0
  85. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/test_vectorize.py +0 -0
  86. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/test_version_metadata.py +0 -0
  87. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/worker.py +0 -0
  88. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/src/worker_durable_object.py +0 -0
  89. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/bindings-test/wrangler.jsonc +0 -0
  90. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/test_bindings.py +0 -0
  91. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/test_fastapi.py +0 -0
  92. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/test_flask.py +0 -0
  93. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/test_web_frameworks.py +0 -0
  94. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/_client.py +0 -0
  95. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/conftest.py +0 -0
  96. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/django_app/__init__.py +0 -0
  97. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/django_app/api_urls.py +0 -0
  98. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/django_app/auth_backend.py +0 -0
  99. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/django_app/drf_auth.py +0 -0
  100. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/django_app/drf_serializers.py +0 -0
  101. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/django_app/drf_throttling.py +0 -0
  102. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/django_app/drf_views.py +0 -0
  103. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/django_app/forms.py +0 -0
  104. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/django_app/middleware.py +0 -0
  105. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/django_app/templatetags/__init__.py +0 -0
  106. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/django_app/templatetags/custom_tags.py +0 -0
  107. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/django_app/urls.py +0 -0
  108. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/django_app/views.py +0 -0
  109. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/templates/base.html +0 -0
  110. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/templates/context_test.html +0 -0
  111. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/templates/csrf_form.html +0 -0
  112. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/templates/hello.html +0 -0
  113. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_async_utilities.py +0 -0
  114. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_auth.py +0 -0
  115. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_caching.py +0 -0
  116. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_cors.py +0 -0
  117. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_csrf.py +0 -0
  118. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_drf_auth_permissions.py +0 -0
  119. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_drf_content_negotiation.py +0 -0
  120. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_drf_serializers.py +0 -0
  121. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_drf_throttling.py +0 -0
  122. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_drf_versioning.py +0 -0
  123. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_drf_views.py +0 -0
  124. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_error_handling.py +0 -0
  125. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_file_uploads.py +0 -0
  126. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_forms.py +0 -0
  127. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_middleware.py +0 -0
  128. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_pagination.py +0 -0
  129. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_request_response.py +0 -0
  130. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_sessions.py +0 -0
  131. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_signals.py +0 -0
  132. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_streaming.py +0 -0
  133. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_templates.py +0 -0
  134. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_url_routing.py +0 -0
  135. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/test_views_basic.py +0 -0
  136. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/src/worker.py +0 -0
  137. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/django-async/wrangler.jsonc +0 -0
  138. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/public/data.json +0 -0
  139. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/public/index.html +0 -0
  140. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/public/style.css +0 -0
  141. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/_client.py +0 -0
  142. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/conftest.py +0 -0
  143. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/static/app.css +0 -0
  144. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/static/data.json +0 -0
  145. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/static/hello.txt +0 -0
  146. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/static/index.html +0 -0
  147. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/test_assets.py +0 -0
  148. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/test_error_handling.py +0 -0
  149. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/test_platform_boundaries.py +0 -0
  150. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/test_platform_io.py +0 -0
  151. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/test_platform_lifecycle.py +0 -0
  152. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/test_response_types.py +0 -0
  153. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/test_routing.py +0 -0
  154. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/test_staticfiles.py +0 -0
  155. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/test_sync_handlers.py +0 -0
  156. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/src/test_websocket.py +0 -0
  157. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/fastapi-tests/wrangler.jsonc +0 -0
  158. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/flask-tests/src/test_response.py +0 -0
  159. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/flask-tests/src/worker.py +0 -0
  160. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/web-frameworks-test/flask-tests/wrangler.jsonc +0 -0
  161. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/asgi/asgi.wd-test +0 -0
  162. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/asgi/tests/test_asgi.py +0 -0
  163. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/asgi/wrangler.jsonc +0 -0
  164. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/asgi-ws-disconnect/asgi-ws-disconnect.wd-test +0 -0
  165. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/asgi-ws-disconnect/tests/test_ws_disconnect.py +0 -0
  166. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/asgi-ws-disconnect/wrangler.jsonc +0 -0
  167. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/durable-object/durable-object.wd-test +0 -0
  168. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/durable-object/worker.py +0 -0
  169. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/durable-object/wrangler.jsonc +0 -0
  170. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/durable-object-abort/durable-object-abort.wd-test +0 -0
  171. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/durable-object-abort/worker.py +0 -0
  172. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/durable-object-abort/wrangler.jsonc +0 -0
  173. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/durable-object-inheritance/durable-object-inheritance.wd-test +0 -0
  174. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/durable-object-inheritance/worker.py +0 -0
  175. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/durable-object-inheritance/wrangler.jsonc +0 -0
  176. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/durable-object-websocket/durable-object-websocket.wd-test +0 -0
  177. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/durable-object-websocket/tester.js +0 -0
  178. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/durable-object-websocket/worker.py +0 -0
  179. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/durable-object-websocket/wrangler.jsonc +0 -0
  180. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/entropy-patches/entropy-patches.wd-test +0 -0
  181. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/entropy-patches/tests/test_aiohttp_websocket.py +0 -0
  182. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/entropy-patches/tests/test_langsmith.py +0 -0
  183. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/entropy-patches/tests/test_litestar.py +0 -0
  184. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/entropy-patches/tests/test_mcp.py +0 -0
  185. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/entropy-patches/tests/test_numpy.py +0 -0
  186. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/entropy-patches/tests/test_opentelemetry.py +0 -0
  187. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/entropy-patches/tests/test_pydantic.py +0 -0
  188. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/entropy-patches/tests/test_rust_packages.py +0 -0
  189. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/entropy-patches/tests/test_ssl_avoidance.py +0 -0
  190. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/entropy-patches/wrangler.jsonc +0 -0
  191. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/http-client/http-client.wd-test +0 -0
  192. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/http-client/origin.py +0 -0
  193. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/http-client/tests/test_http_client.py +0 -0
  194. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/http-client/tests/test_urllib_request.py +0 -0
  195. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/http-client/worker.py +0 -0
  196. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/http-client/wrangler.jsonc +0 -0
  197. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/python-rpc/python-rpc.wd-test +0 -0
  198. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/python-rpc/worker.js +0 -0
  199. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/python-rpc/worker.py +0 -0
  200. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/python-rpc/wrangler.jsonc +0 -0
  201. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/sdk/sdk.wd-test +0 -0
  202. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/sdk/server.py +0 -0
  203. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/sdk/tests/test_sdk.py +0 -0
  204. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/sdk/wrangler.jsonc +0 -0
  205. {workers_runtime_sdk-1.8.6/tests/workerd-test/durable-object-abort → workers_runtime_sdk-1.9.1/tests/workerd-test/workflow}/pyproject.toml +0 -0
  206. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/wsgi/tests/test_wsgi.py +0 -0
  207. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/wsgi/wrangler.jsonc +0 -0
  208. {workers_runtime_sdk-1.8.6 → workers_runtime_sdk-1.9.1}/tests/workerd-test/wsgi/wsgi.wd-test +0 -0
@@ -2,6 +2,28 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v1.9.1 (2026-09-29)
6
+
7
+ ### Bug Fixes
8
+
9
+ - **runtime-sdk**: Add rpds to rust package entropy context
10
+ ([#277](https://github.com/cloudflare/workers-py/pull/277),
11
+ [`a097b7c`](https://github.com/cloudflare/workers-py/commit/a097b7c5d2e5bba17f34d46abb6e39039d4673d4))
12
+
13
+
14
+ ## v1.9.0 (2026-09-18)
15
+
16
+ ### Bug Fixes
17
+
18
+ - **runtime-sdk**: Make NonRetryableError raised in a workflow step non-retryable
19
+ ([`1c1980a`](https://github.com/cloudflare/workers-py/commit/1c1980afabaa27d39bf18d3fe19c7385c2890fa6))
20
+
21
+ ### Features
22
+
23
+ - **runtime-sdk**: Add helpers to import JavaScript modules shipped with the SDK
24
+ ([`caa9364`](https://github.com/cloudflare/workers-py/commit/caa9364f38a111d5496f81f6bc23ebb88d191928))
25
+
26
+
5
27
  ## v1.8.6 (2026-09-18)
6
28
 
7
29
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: workers-runtime-sdk
3
- Version: 1.8.6
3
+ Version: 1.9.1
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.6"
7
+ version = "1.9.1"
8
8
  description = "Python SDK for Cloudflare Workers"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -49,6 +49,7 @@ class STATE:
49
49
  @register_create_patch("tiktoken._tiktoken")
50
50
  @register_exec_patch("cryptography.exceptions")
51
51
  @register_exec_patch("jiter")
52
+ @register_exec_patch("rpds")
52
53
  @register_exec_patch("uuid_utils._uuid_utils")
53
54
  @contextmanager
54
55
  def rust_package_context(module):
@@ -17,7 +17,11 @@ from .rpc import (
17
17
  python_from_rpc,
18
18
  python_to_rpc,
19
19
  )
20
- from .utils import _from_js_error, _is_js_instance
20
+ from .utils import (
21
+ _from_js_error,
22
+ _is_js_instance,
23
+ import_sdk_javascript_module_async,
24
+ )
21
25
 
22
26
  if TYPE_CHECKING:
23
27
  from js import DurableObjectState, Env, ExecutionContext
@@ -294,6 +298,22 @@ def _wrap_class(cls):
294
298
  return cls
295
299
 
296
300
 
301
+ _workflows_js_module = None
302
+
303
+
304
+ async def _wrap_js_workflow_step(js_step):
305
+ """
306
+ Wrap the JS `WorkflowStep` stub with `wrapWorkflowStep` from the SDK's `workflows.js`.
307
+
308
+ The wrapper makes a Python `NonRetryableError` raised inside a step reach the Workflows
309
+ engine as a JS error the engine recognises as non-retryable (see `workflows.js`).
310
+ """
311
+ global _workflows_js_module # noqa: PLW0603
312
+ if _workflows_js_module is None:
313
+ _workflows_js_module = await import_sdk_javascript_module_async("workflows.js")
314
+ return _workflows_js_module.wrapWorkflowStep(js_step)
315
+
316
+
297
317
  def _wrap_workflow_step(cls):
298
318
  run_fn = cls.__dict__.get("run")
299
319
  if run_fn is None:
@@ -304,7 +324,7 @@ def _wrap_workflow_step(cls):
304
324
  if event is not None:
305
325
  event = python_from_rpc(event)
306
326
  if step is not None:
307
- step = _WorkflowStepWrapper(step)
327
+ step = _WorkflowStepWrapper(await _wrap_js_workflow_step(step))
308
328
 
309
329
  result = run_fn(self, event, step, *args, **kwargs)
310
330
 
@@ -126,6 +126,25 @@ def import_from_javascript(module_name: str) -> Any:
126
126
  raise
127
127
 
128
128
 
129
+ # Directory, relative to the worker bundle root, that `pywrangler sync` vendors Python packages
130
+ # into. wrangler registers `.js`/`.mjs` files found under `python_modules/workers/` as ES modules
131
+ # (everything else in `python_modules/` is opaque data), which is what lets them be imported via
132
+ # `import_from_javascript`.
133
+ _SDK_JS_MODULE_PREFIX = "python_modules/workers/"
134
+
135
+
136
+ async def import_sdk_javascript_module_async(name: str) -> Any:
137
+ """
138
+ Asynchronous function to import an sdk js module
139
+
140
+ This does not rely on JSPI, so it also works with Pyodide 0.26.0a2.
141
+ """
142
+ try:
143
+ return await _pyodide_entrypoint_helper.doAnImport(_SDK_JS_MODULE_PREFIX + name)
144
+ except JsException as e:
145
+ raise ImportError(f"Failed to import '{name}': {e}") from e
146
+
147
+
129
148
  @contextmanager
130
149
  def patch_env(
131
150
  d: dict[str, Any] | Sequence[tuple[str, Any]] | None = None, **kwds: dict[str, Any]
@@ -144,15 +163,30 @@ def _to_python_exception(exc: JsException) -> Exception:
144
163
  return exc
145
164
 
146
165
 
166
+ _NON_RETRYABLE_ERROR_NAME = "NonRetryableError"
167
+
168
+
147
169
  def _from_js_error(exc: JsException) -> Exception:
148
170
  # convert into Python exception after a full round trip
149
171
  # Python - JS - Python
150
172
  message = exc.message or ""
151
173
 
174
+ # A NonRetryableError raised inside a workflow step is translated by the
175
+ # runtime into a JS error named "NonRetryableError" before it reaches the
176
+ # Workflows engine, which is how the engine knows not to retry the step.
177
+ # When the engine rethrows it back to us the name either survives, or is
178
+ # folded into the message as a prefix.
179
+ if getattr(exc, "name", None) == _NON_RETRYABLE_ERROR_NAME:
180
+ return NonRetryableError(message)
181
+ if message == _NON_RETRYABLE_ERROR_NAME:
182
+ return NonRetryableError()
183
+ if message.startswith(_NON_RETRYABLE_ERROR_NAME + ": "):
184
+ return NonRetryableError(message[len(_NON_RETRYABLE_ERROR_NAME) + 2 :])
185
+
152
186
  # A Python exception that escaped to JS is a Pyodide `PythonError` whose
153
187
  # message is the formatted traceback. Depending on how it was serialized
154
188
  # over RPC it either keeps its name or arrives as a plain `Error` with
155
- # "PythonError: " folded into the message.
189
+ # "PythonError: " folded into the message
156
190
  if getattr(exc, "name", None) != "PythonError" and not message.startswith(
157
191
  "PythonError"
158
192
  ):
@@ -0,0 +1,91 @@
1
+ // JavaScript helpers for Python Workflows
2
+
3
+ const NON_RETRYABLE_ERROR_NAME = "NonRetryableError";
4
+
5
+ function isPythonError(e) {
6
+ return (
7
+ e instanceof Error &&
8
+ e.constructor?.name === "PythonError" &&
9
+ typeof e.type === "string"
10
+ );
11
+ }
12
+
13
+ // Extract the message the user passed to the Python exception from the
14
+ // traceback stored in `PythonError.message`.
15
+ //
16
+ // The last non-empty line of a formatted traceback is
17
+ // `<qualified.ExceptionType>: <message>`, or just `<qualified.ExceptionType>`
18
+ // when the exception was raised without a message. For example, given
19
+ //
20
+ // Traceback (most recent call last):
21
+ // File "/session/metadata/worker.py", line 19, in non_retryable
22
+ // raise NonRetryableError("do not retry")
23
+ // workers.workflows.NonRetryableError: do not retry
24
+ //
25
+ // this returns "do not retry", and given
26
+ //
27
+ // Traceback (most recent call last):
28
+ // File "/session/metadata/worker.py", line 34, in no_message
29
+ // raise NonRetryableError()
30
+ // workers.workflows.NonRetryableError
31
+ //
32
+ // it returns "".
33
+ function pythonExceptionMessage(e) {
34
+ const lines = e.message.split("\n").filter((line) => line.trim() !== "");
35
+ const last = lines.at(-1) ?? "";
36
+ const sep = last.indexOf(": ");
37
+ return sep === -1 ? "" : last.slice(sep + 2);
38
+ }
39
+
40
+ // Wraps a Python step callback passed to `WorkflowStep.do()`.
41
+ //
42
+ // If the error thrown is a Python NonRetryable error, translate it into a JS
43
+ // error that the engine will recognize as non retryable. Leave other errors
44
+ // alone.
45
+ export function wrapWorkflowStepCallback(pyCallback) {
46
+ return async function (...args) {
47
+ try {
48
+ return await pyCallback(...args);
49
+ } catch (e) {
50
+ if (isPythonError(e) && e.type === NON_RETRYABLE_ERROR_NAME) {
51
+ const err = new Error(pythonExceptionMessage(e));
52
+ err.name = NON_RETRYABLE_ERROR_NAME;
53
+ throw err;
54
+ }
55
+ throw e;
56
+ }
57
+ };
58
+ }
59
+
60
+ // Wraps the `WorkflowStep` RPC stub passed to a Python
61
+ // `WorkflowEntrypoint.run()` so that the callback given to `step.do()` goes
62
+ // through `wrapWorkflowStepCallback`.
63
+ //
64
+ // Because the wrapped `do` returns the stub's own promise, a Python callback
65
+ // passed to it keeps exactly the lifetime it would have had without the
66
+ // wrapper.
67
+ export function wrapWorkflowStep(step) {
68
+ // RPC stubs are callable, so `typeof step` is 'function'.
69
+ if (
70
+ step === null ||
71
+ (typeof step !== "object" && typeof step !== "function")
72
+ ) {
73
+ return step;
74
+ }
75
+ return new Proxy(step, {
76
+ apply(target, thisArg, args) {
77
+ return Reflect.apply(target, thisArg, args);
78
+ },
79
+ get(target, prop) {
80
+ if (prop !== "do") {
81
+ return Reflect.get(target, prop);
82
+ }
83
+ return function (name, ...rest) {
84
+ const args = rest.map((arg) =>
85
+ typeof arg === "function" ? wrapWorkflowStepCallback(arg) : arg
86
+ );
87
+ return target.do(name, ...args);
88
+ };
89
+ },
90
+ });
91
+ }
@@ -7,13 +7,18 @@ dependencies = [
7
7
  "pytest-asyncio<1.2.0",
8
8
  # These are for hyperdrive tests
9
9
  "pg8000",
10
- "pymysql",
10
+ # There is a regression in upstream pymysql.
11
+ # Remove when the following PR is merged and released.
12
+ # https://github.com/PyMySQL/PyMySQL/pull/1275
13
+ "pymysql<=1.2.0",
11
14
  "aiomysql",
12
15
  "psycopg[binary]; python_version >= '3.14'",
13
16
  "asyncpg; python_version >= '3.14'",
14
17
  "cryptography",
15
18
  "testlib",
19
+ "workers-runtime-sdk",
16
20
  ]
17
21
 
18
22
  [tool.uv.sources]
19
- testlib = { path = "../testlib/dist/testlib-0.0.0-py3-none-any.whl" }
23
+ testlib = { path = "../packages/testlib" }
24
+ workers-runtime-sdk = { path = "../packages/runtime-sdk" }
@@ -149,7 +149,17 @@ async def test_step_retry_config(env):
149
149
  async def test_non_retryable_error(env):
150
150
  instance = await env.MY_WORKFLOW.create({"params": {"mode": "non_retryable"}})
151
151
  status = await _poll(instance)
152
- assert status["status"] == "errored", f"unexpected status: {dict(status)!r}"
152
+ assert status["status"] == "complete", f"unexpected status: {dict(status)!r}"
153
+ out = status["output"]
154
+ # The step would succeed on attempt 2, so `retried` means the engine ignored
155
+ # the NonRetryableError.
156
+ assert out["retried"] is False, f"step was retried: {out!r}"
157
+ # ...and the error must come back to `run()` as a Python NonRetryableError.
158
+ assert out["caught"] == "NonRetryableError", out
159
+ # The message is preserved end to end in workerd, but miniflare currently
160
+ # truncates error messages crossing from the Python worker into its
161
+ # Workflows engine at the first ": " so accept an empty message here.
162
+ assert out["message"] in ("do not retry", ""), out
153
163
 
154
164
 
155
165
  async def test_error_handling_catch(env):
@@ -109,14 +109,30 @@ class TestWorkflow(WorkflowEntrypoint):
109
109
  return await flaky()
110
110
 
111
111
  async def _non_retryable(self, event, step):
112
+ # Fails on the first attempt with NonRetryableError and would succeed on a
113
+ # second attempt. If the engine honours NonRetryableError the step fails
114
+ # once and `run()` sees a NonRetryableError; if the engine retries, the step
115
+ # completes with `attempt == 2`.
112
116
  @step.do(
113
117
  "non-retryable-step",
114
- config={"retries": {"limit": 1, "delay": 0, "backoff": "constant"}},
118
+ config={"retries": {"limit": 3, "delay": 0, "backoff": "constant"}},
115
119
  )
116
- async def boom():
117
- raise NonRetryableError("do not retry")
120
+ async def boom(ctx):
121
+ if int(ctx["attempt"]) < 2:
122
+ raise NonRetryableError("do not retry")
123
+ return {"retried": True, "attempt": int(ctx["attempt"])}
118
124
 
119
- return await boom()
125
+ try:
126
+ result = await boom()
127
+ except NonRetryableError as exc:
128
+ return {
129
+ "retried": False,
130
+ "caught": "NonRetryableError",
131
+ "message": str(exc),
132
+ }
133
+ except Exception as exc:
134
+ return {"retried": False, "caught": type(exc).__name__, "message": str(exc)}
135
+ return result
120
136
 
121
137
  async def _duplicate_step_names(self, event, step):
122
138
  # The engine disambiguates repeated step names with a counter, so two
@@ -2,7 +2,6 @@
2
2
 
3
3
  import os
4
4
  import shutil
5
- import subprocess
6
5
  from collections.abc import Generator
7
6
  from pathlib import Path
8
7
  from typing import Any
@@ -12,6 +11,8 @@ from testlib.host import (
12
11
  COMPAT_CONFIGS,
13
12
  CompatConfig,
14
13
  configure_compatibility,
14
+ link_packages,
15
+ pywrangler_sync,
15
16
  )
16
17
  from testlib.host import (
17
18
  dev_server as run_dev_server,
@@ -21,9 +22,6 @@ from testlib.host import (
21
22
  )
22
23
 
23
24
  TEST_DIR: Path = Path(__file__).parent
24
- WORKERS_PY: Path = TEST_DIR.parent.parent / "cli"
25
- WORKERS_RUNTIME_SDK: Path = TEST_DIR.parent / "src"
26
- TESTLIB: Path = TEST_DIR.parent.parent / "testlib"
27
25
 
28
26
  DEV_STARTUP_TIMEOUT: int = 120
29
27
  OPT_IN_MARKERS: tuple[str, ...] = ("hyperdrive",)
@@ -43,11 +41,6 @@ def pytest_collection_modifyitems(
43
41
  item.add_marker(skip)
44
42
 
45
43
 
46
- @pytest.fixture(scope="session", autouse=True)
47
- def build_testlib():
48
- subprocess.run(["uv", "build"], cwd=TESTLIB, check=True)
49
-
50
-
51
44
  @pytest.fixture(
52
45
  scope="module",
53
46
  params=COMPAT_CONFIGS,
@@ -74,32 +67,27 @@ def dev_server(
74
67
  worker_project_dir: Path,
75
68
  compat_config: CompatConfig,
76
69
  ) -> Generator[str]:
77
- """Start a pywrangler dev server on a free port and yield its base URL."""
70
+ """Start a pywrangler dev server on a free port and yield its base URL.
71
+
72
+ The project is copied next to a ``packages`` symlink so that its
73
+ ``../packages/...`` sources resolve and ``sync`` vendors the working-tree
74
+ testlib and runtime-sdk.
75
+ """
78
76
  tmp_path = tmp_path_factory.mktemp(f"{worker_project_dir.name}_dev")
79
77
  target = tmp_path / worker_project_dir.name
80
78
  shutil.copytree(worker_project_dir, target, ignore=shutil.ignore_patterns(".venv"))
81
- shutil.copytree(TESTLIB, tmp_path / "testlib")
79
+ link_packages(tmp_path)
82
80
  env = os.environ | {"_PYODIDE_EXTRA_MOUNTS": str(tmp_path)}
83
81
 
84
82
  wrangler_jsonc = target / "wrangler.jsonc"
85
83
  configure_compatibility(wrangler_jsonc, compat_config)
86
84
 
87
- pywrangler_cmd = ["uv", "run", "--no-project", "--with", WORKERS_PY, "pywrangler"]
88
-
89
- subprocess.run(
90
- [*pywrangler_cmd, "sync"],
91
- cwd=target,
92
- check=True,
93
- env=env,
94
- )
95
-
96
- shutil.copytree(WORKERS_RUNTIME_SDK, target / "python_modules", dirs_exist_ok=True)
85
+ pywrangler_sync(target, env)
97
86
 
98
87
  with run_dev_server(
99
88
  target,
100
89
  tmp_path,
101
90
  env,
102
- pywrangler_cmd,
103
91
  startup_timeout=DEV_STARTUP_TIMEOUT,
104
92
  readiness_path="/health",
105
93
  require_success=True,
@@ -113,4 +101,4 @@ def register_in_worker_suites(
113
101
  src_dir: Path,
114
102
  marks: dict[str, pytest.MarkDecorator] | None = None,
115
103
  ) -> None:
116
- register_testlib_suites(namespace, src_dir, marks=marks, class_name=str.upper)
104
+ register_testlib_suites(namespace, src_dir, marks=marks)
@@ -8,12 +8,12 @@ from conftest import (
8
8
  COMPAT_CONFIGS,
9
9
  CompatConfig,
10
10
  configure_compatibility,
11
+ link_packages,
12
+ pywrangler_sync,
11
13
  )
12
14
 
13
15
  TEST_DIR = Path(__file__).parent
14
16
  WORKERD_TESTS = TEST_DIR / "workerd-test"
15
- WORKERS_PY = TEST_DIR.parent.parent / "cli"
16
- WORKERS_RUNTIME_SDK = TEST_DIR.parent / "src"
17
17
  DISK_SERVICE_NAME = "TEST_TMPDIR"
18
18
 
19
19
 
@@ -66,14 +66,27 @@ def embed(dir: Path, root: Path, level: int = 0):
66
66
  module_path = path.absolute().relative_to(module_path_root)
67
67
  embed_path = path.absolute().relative_to(root)
68
68
  if path.suffix == ".py":
69
- modules.append(
70
- f'(name = "{module_path}", pythonModule = embed "{embed_path}")'
71
- )
69
+ module_type = "pythonModule"
70
+ elif _is_sdk_js_module(path.relative_to(dir)):
71
+ module_type = "esModule"
72
72
  else:
73
- modules.append(f'(name = "{module_path}", data = embed "{embed_path}")')
73
+ module_type = "data"
74
+ modules.append(
75
+ f'(name = "{module_path}", {module_type} = embed "{embed_path}")'
76
+ )
74
77
  return modules
75
78
 
76
79
 
80
+ def _is_sdk_js_module(path_in_vendor_dir: Path) -> bool:
81
+ """Mirror wrangler: `.js`/`.mjs` files under `python_modules/workers/` are ES modules.
82
+
83
+ Other vendored packages may ship `.js` assets that are not valid ES modules, so wrangler
84
+ only applies this rule to the SDK's own `workers/` package. Everything else stays `data`.
85
+ """
86
+ in_sdk_package = path_in_vendor_dir.parts[:1] == ("workers",)
87
+ return in_sdk_package and path_in_vendor_dir.suffix in (".js", ".mjs")
88
+
89
+
77
90
  @pytest.fixture(scope="module")
78
91
  def bundle_cache_dir(tmp_path_factory):
79
92
  yield tmp_path_factory.mktemp("bundle_cache")
@@ -110,23 +123,14 @@ def test_in_workerd( # noqa: PLR0913, PLR0917 (too-many-arguments)
110
123
  target = tmp_path / test_dir.name
111
124
  disk_service_dir = target / DISK_SERVICE_NAME
112
125
  shutil.copytree(test_dir, target, ignore=shutil.ignore_patterns(".venv"))
126
+ # Makes the project's `../packages/{runtime-sdk,testlib}` sources resolve
127
+ # so `sync` vendors the working-tree SDK and testlib.
128
+ link_packages(tmp_path)
113
129
  disk_service_dir.mkdir(exist_ok=True)
114
130
 
115
131
  configure_compatibility(target / "wrangler.jsonc", compat_config)
116
132
 
117
- pywrangler_cmd = ["uv", "run", "--no-project", "--with", WORKERS_PY, "pywrangler"]
118
-
119
- subprocess.run(
120
- [*pywrangler_cmd, "sync"],
121
- cwd=target,
122
- check=True,
123
- env=os.environ | {"_PYODIDE_EXTRA_MOUNTS": str(tmp_path)},
124
- )
125
-
126
- # Copy runtime-sdk to the python modules as well
127
- # FIXME: remove this and pass runtime-sdk as a dependency explicitly after
128
- # https://github.com/cloudflare/workers-py/pull/81 is merged
129
- shutil.copytree(WORKERS_RUNTIME_SDK, target / "python_modules", dirs_exist_ok=True)
133
+ pywrangler_sync(target, os.environ | {"_PYODIDE_EXTRA_MOUNTS": str(tmp_path)})
130
134
 
131
135
  modules = embed(target / "python_modules", target, level=1) + embed(
132
136
  target / "tests", target, level=1
@@ -11,7 +11,9 @@ dependencies = [
11
11
  "pytest",
12
12
  "pytest-asyncio<1.2.0",
13
13
  "testlib",
14
+ "workers-runtime-sdk",
14
15
  ]
15
16
 
16
17
  [tool.uv.sources]
17
- testlib = { path = "../testlib/dist/testlib-0.0.0-py3-none-any.whl" }
18
+ testlib = { path = "../packages/testlib" }
19
+ workers-runtime-sdk = { path = "../packages/runtime-sdk" }
@@ -8,7 +8,9 @@ dependencies = [
8
8
  "pytest",
9
9
  "pytest-asyncio<1.2.0",
10
10
  "testlib",
11
+ "workers-runtime-sdk",
11
12
  ]
12
13
 
13
14
  [tool.uv.sources]
14
- testlib = { path = "../testlib/dist/testlib-0.0.0-py3-none-any.whl" }
15
+ testlib = { path = "../packages/testlib" }
16
+ workers-runtime-sdk = { path = "../packages/runtime-sdk" }
@@ -30,21 +30,12 @@ from fastapi.responses import (
30
30
  from fastapi.responses import Response as FastAPIResponse
31
31
  from fastapi.staticfiles import StaticFiles
32
32
  from pydantic import BaseModel
33
- from pyodide.webloop import WebLoop
34
33
  from starlette.background import BackgroundTask
35
34
  from starlette.middleware.gzip import GZipMiddleware
36
- from testlib.entrypoint import TestRunner
35
+ from testlib.entrypoint import RunSuiteRequest, TestRunner
37
36
 
38
37
  import asgi
39
38
 
40
-
41
- async def _noop(*args):
42
- pass
43
-
44
-
45
- WebLoop.shutdown_asyncgens = _noop
46
- WebLoop.shutdown_default_executor = _noop
47
-
48
39
  STATIC_DIR = Path(__file__).parent / "static"
49
40
 
50
41
 
@@ -603,7 +594,9 @@ class FastAPIAppPlugin:
603
594
  @app.get("/run-tests/{suite_name:path}")
604
595
  async def run_suite(suite_name: str, request: Request):
605
596
  runner = TestRunner(request.scope["env"], extra_plugins=[FastAPIAppPlugin()])
606
- result = runner.run_suite(suite_name)
597
+ result = runner.run_suite(
598
+ suite_name, RunSuiteRequest.from_query_params(request.query_params)
599
+ )
607
600
  return JSONResponse(result.payload, status_code=result.status)
608
601
 
609
602
 
@@ -0,0 +1,9 @@
1
+ [project]
2
+ name = "flask-tests"
3
+ version = "0.1.0"
4
+ requires-python = ">=3.12"
5
+ dependencies = ["flask", "pytest", "testlib", "workers-runtime-sdk"]
6
+
7
+ [tool.uv.sources]
8
+ testlib = { path = "../packages/testlib" }
9
+ workers-runtime-sdk = { path = "../packages/runtime-sdk" }
@@ -0,0 +1,9 @@
1
+ [project]
2
+ name = "test"
3
+ version = "0.0.0"
4
+ requires-python = ">=3.12"
5
+ dependencies = ["pytest", "pytest-asyncio<1.2.0", "testlib", "workers-runtime-sdk"]
6
+
7
+ [tool.uv.sources]
8
+ testlib = { path = "../packages/testlib" }
9
+ workers-runtime-sdk = { path = "../packages/runtime-sdk" }
@@ -1,28 +1,10 @@
1
- import asyncio
2
1
  import os
3
- import sys
4
2
 
5
- import pytest
6
- from pyodide.webloop import WebLoop
3
+ from testlib.entrypoint import run_pytest
7
4
 
8
5
  import asgi
9
6
  from workers import WorkerEntrypoint
10
7
 
11
-
12
- async def noop(*args):
13
- pass
14
-
15
-
16
- # pytest-asyncio relies on these but in Pyodide < 0.29 WebLoop does not implement them
17
- WebLoop.shutdown_asyncgens = noop
18
- WebLoop.shutdown_default_executor = noop
19
-
20
- # Pyodide 0.26.0a2's _cancel_all_tasks calls task.exception() on pending tasks,
21
- # which raises InvalidStateError under Pyodide's WebLoop.
22
- if sys.version_info < (3, 13):
23
- asyncio.runners._cancel_all_tasks = lambda loop: None # type: ignore[attr-defined]
24
-
25
-
26
8
  # ---------------------------------------------------------------------------
27
9
  # ASGI apps
28
10
  # ---------------------------------------------------------------------------
@@ -291,4 +273,4 @@ class Default(WorkerEntrypoint):
291
273
  async def test(self):
292
274
  os.chdir("/session/metadata/tests")
293
275
  args = [".", "-vv"]
294
- assert pytest.main(args) == 0
276
+ run_pytest(args)
@@ -0,0 +1,9 @@
1
+ [project]
2
+ name = "test"
3
+ version = "0.0.0"
4
+ requires-python = ">=3.12"
5
+ dependencies = ["pytest", "pytest-asyncio<1.2.0", "testlib", "workers-runtime-sdk"]
6
+
7
+ [tool.uv.sources]
8
+ testlib = { path = "../packages/testlib" }
9
+ workers-runtime-sdk = { path = "../packages/runtime-sdk" }
@@ -1,29 +1,12 @@
1
- import asyncio
2
1
  import os
3
- import sys
4
2
  from urllib.parse import urlsplit
5
3
 
6
- import pytest
7
- from pyodide.webloop import WebLoop
4
+ from testlib.entrypoint import run_pytest
8
5
 
9
6
  import asgi
10
7
  from workers import WorkerEntrypoint
11
8
 
12
9
 
13
- async def _noop(*args):
14
- pass
15
-
16
-
17
- # pytest-asyncio relies on these but in Pyodide < 0.29 WebLoop does not implement them
18
- WebLoop.shutdown_asyncgens = _noop
19
- WebLoop.shutdown_default_executor = _noop
20
-
21
- # Pyodide 0.26.0a2's _cancel_all_tasks calls task.exception() on pending tasks,
22
- # which raises InvalidStateError under Pyodide's WebLoop.
23
- if sys.version_info < (3, 13):
24
- asyncio.runners._cancel_all_tasks = lambda loop: None # type: ignore[attr-defined]
25
-
26
-
27
10
  async def _drain_lifespan(receive, send):
28
11
  message = await receive()
29
12
  if message["type"] == "lifespan.startup":
@@ -180,4 +163,4 @@ class Default(WorkerEntrypoint):
180
163
  async def test(self):
181
164
  os.chdir("/session/metadata/tests")
182
165
  args = [".", "-vv"]
183
- assert pytest.main(args) == 0
166
+ run_pytest(args)
@@ -0,0 +1,8 @@
1
+ [project]
2
+ name = "test"
3
+ version = "0.0.0"
4
+ requires-python = ">=3.12"
5
+ dependencies = ["workers-runtime-sdk"]
6
+
7
+ [tool.uv.sources]
8
+ workers-runtime-sdk = { path = "../packages/runtime-sdk" }