workers-runtime-sdk 1.6.10__tar.gz → 1.6.12__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 (170) hide show
  1. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/CHANGELOG.md +17 -0
  2. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/PKG-INFO +2 -2
  3. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/pyproject.toml +1 -1
  4. workers_runtime_sdk-1.6.12/src/_workers_sdk_package_patches.py +45 -0
  5. workers_runtime_sdk-1.6.12/src/_workers_sdk_patch_loader.pth +1 -0
  6. workers_runtime_sdk-1.6.12/src/_workers_sdk_patch_loader.py +16 -0
  7. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/asgi.py +2 -2
  8. workers_runtime_sdk-1.6.12/tests/web-frameworks-test/fastapi-tests/src/static/app.css +4 -0
  9. workers_runtime_sdk-1.6.12/tests/web-frameworks-test/fastapi-tests/src/static/data.json +1 -0
  10. workers_runtime_sdk-1.6.12/tests/web-frameworks-test/fastapi-tests/src/static/hello.txt +1 -0
  11. workers_runtime_sdk-1.6.12/tests/web-frameworks-test/fastapi-tests/src/static/index.html +7 -0
  12. workers_runtime_sdk-1.6.12/tests/web-frameworks-test/fastapi-tests/src/test_staticfiles.py +117 -0
  13. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/fastapi-tests/src/worker.py +16 -0
  14. workers_runtime_sdk-1.6.12/tests/web-frameworks-test/fastapi-tests/wrangler.jsonc +21 -0
  15. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/asgi-ws-disconnect/tests/test_ws_disconnect.py +27 -0
  16. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/asgi-ws-disconnect/worker.py +23 -1
  17. workers_runtime_sdk-1.6.12/tests/workerd-test/wsgi/pyproject.toml +5 -0
  18. workers_runtime_sdk-1.6.12/tests/workerd-test/wsgi/tests/test_wsgi.py +105 -0
  19. workers_runtime_sdk-1.6.12/tests/workerd-test/wsgi/worker.py +131 -0
  20. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/wsgi/wsgi.wd-test +4 -0
  21. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/uv.lock +1 -1
  22. workers_runtime_sdk-1.6.10/src/_workers_sdk_entropy_import_context.pth +0 -1
  23. workers_runtime_sdk-1.6.10/src/_workers_sdk_entropy_import_context_loader.py +0 -13
  24. workers_runtime_sdk-1.6.10/tests/web-frameworks-test/fastapi-tests/wrangler.jsonc +0 -11
  25. workers_runtime_sdk-1.6.10/tests/workerd-test/wsgi/pyproject.toml +0 -5
  26. workers_runtime_sdk-1.6.10/tests/workerd-test/wsgi/worker.py +0 -205
  27. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/.gitignore +0 -0
  28. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/AGENTS.md +0 -0
  29. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/README.md +0 -0
  30. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/_cloudflare_compat_flags.pyi +0 -0
  31. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/_pyodide_entrypoint_helper.pyi +0 -0
  32. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/_workers_sdk_entropy_import_context.py +0 -0
  33. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/workers/__init__.py +0 -0
  34. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/workers/blob.py +0 -0
  35. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/workers/entrypoints.py +0 -0
  36. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/workers/fetch.py +0 -0
  37. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/workers/formdata.py +0 -0
  38. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/workers/py.typed +0 -0
  39. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/workers/request.py +0 -0
  40. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/workers/response.py +0 -0
  41. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/workers/rpc.py +0 -0
  42. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/workers/types.py +0 -0
  43. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/workers/utils.py +0 -0
  44. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/workers/workflows.py +0 -0
  45. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/src/workers/wsgi.py +0 -0
  46. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/public/data.json +0 -0
  47. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/public/hello.txt +0 -0
  48. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/pyproject.toml +0 -0
  49. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/conftest.py +0 -0
  50. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/test_analytics_engine.py +0 -0
  51. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/test_assets.py +0 -0
  52. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/test_d1.py +0 -0
  53. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/test_do.py +0 -0
  54. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/test_images.py +0 -0
  55. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/test_kv.py +0 -0
  56. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/test_mtls.py +0 -0
  57. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/test_queue.py +0 -0
  58. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/test_r2.py +0 -0
  59. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/test_ratelimit.py +0 -0
  60. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/test_vectorize.py +0 -0
  61. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/test_version_metadata.py +0 -0
  62. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/test_workflow.py +0 -0
  63. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/worker.py +0 -0
  64. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/worker_durable_object.py +0 -0
  65. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/src/worker_workflow.py +0 -0
  66. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/bindings-test/wrangler.jsonc +0 -0
  67. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/conftest.py +0 -0
  68. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/test_bindings.py +0 -0
  69. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/test_fastapi.py +0 -0
  70. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/test_in_workerd.py +0 -0
  71. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/test_web_frameworks.py +0 -0
  72. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/pyproject.toml +0 -0
  73. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/_client.py +0 -0
  74. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/conftest.py +0 -0
  75. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/django_app/__init__.py +0 -0
  76. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/django_app/api_urls.py +0 -0
  77. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/django_app/auth_backend.py +0 -0
  78. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/django_app/drf_auth.py +0 -0
  79. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/django_app/drf_serializers.py +0 -0
  80. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/django_app/drf_throttling.py +0 -0
  81. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/django_app/drf_views.py +0 -0
  82. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/django_app/forms.py +0 -0
  83. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/django_app/middleware.py +0 -0
  84. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/django_app/templatetags/__init__.py +0 -0
  85. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/django_app/templatetags/custom_tags.py +0 -0
  86. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/django_app/urls.py +0 -0
  87. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/django_app/views.py +0 -0
  88. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/templates/base.html +0 -0
  89. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/templates/context_test.html +0 -0
  90. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/templates/csrf_form.html +0 -0
  91. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/templates/hello.html +0 -0
  92. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_async_utilities.py +0 -0
  93. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_auth.py +0 -0
  94. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_caching.py +0 -0
  95. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_cors.py +0 -0
  96. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_csrf.py +0 -0
  97. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_drf_auth_permissions.py +0 -0
  98. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_drf_content_negotiation.py +0 -0
  99. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_drf_serializers.py +0 -0
  100. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_drf_throttling.py +0 -0
  101. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_drf_versioning.py +0 -0
  102. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_drf_views.py +0 -0
  103. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_error_handling.py +0 -0
  104. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_file_uploads.py +0 -0
  105. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_forms.py +0 -0
  106. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_middleware.py +0 -0
  107. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_pagination.py +0 -0
  108. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_request_response.py +0 -0
  109. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_sessions.py +0 -0
  110. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_signals.py +0 -0
  111. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_streaming.py +0 -0
  112. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_templates.py +0 -0
  113. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_url_routing.py +0 -0
  114. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/test_views_basic.py +0 -0
  115. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/src/worker.py +0 -0
  116. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/django-async/wrangler.jsonc +0 -0
  117. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/fastapi-tests/public/data.json +0 -0
  118. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/fastapi-tests/public/index.html +0 -0
  119. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/fastapi-tests/public/style.css +0 -0
  120. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/fastapi-tests/pyproject.toml +0 -0
  121. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/fastapi-tests/src/_client.py +0 -0
  122. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/fastapi-tests/src/conftest.py +0 -0
  123. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/web-frameworks-test/fastapi-tests/src/test_assets.py +0 -0
  124. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/asgi/asgi.wd-test +0 -0
  125. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/asgi/pyproject.toml +0 -0
  126. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/asgi/tests/test_asgi.py +0 -0
  127. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/asgi/worker.py +0 -0
  128. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/asgi/wrangler.jsonc +0 -0
  129. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/asgi-ws-disconnect/asgi-ws-disconnect.wd-test +0 -0
  130. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/asgi-ws-disconnect/pyproject.toml +0 -0
  131. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/asgi-ws-disconnect/wrangler.jsonc +0 -0
  132. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object/durable-object.wd-test +0 -0
  133. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object/pyproject.toml +0 -0
  134. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object/worker.py +0 -0
  135. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object/wrangler.jsonc +0 -0
  136. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object-abort/durable-object-abort.wd-test +0 -0
  137. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object-abort/pyproject.toml +0 -0
  138. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object-abort/worker.py +0 -0
  139. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object-abort/wrangler.jsonc +0 -0
  140. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object-inheritance/durable-object-inheritance.wd-test +0 -0
  141. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object-inheritance/pyproject.toml +0 -0
  142. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object-inheritance/worker.py +0 -0
  143. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object-inheritance/wrangler.jsonc +0 -0
  144. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object-websocket/durable-object-websocket.wd-test +0 -0
  145. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object-websocket/pyproject.toml +0 -0
  146. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object-websocket/tester.js +0 -0
  147. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object-websocket/worker.py +0 -0
  148. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/durable-object-websocket/wrangler.jsonc +0 -0
  149. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/entropy-patches/entropy-patches.wd-test +0 -0
  150. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/entropy-patches/pyproject.toml +0 -0
  151. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/entropy-patches/tests/test_aiohttp_websocket.py +0 -0
  152. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/entropy-patches/tests/test_langsmith.py +0 -0
  153. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/entropy-patches/tests/test_numpy.py +0 -0
  154. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/entropy-patches/tests/test_pydantic.py +0 -0
  155. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/entropy-patches/tests/test_rust_packages.py +0 -0
  156. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/entropy-patches/tests/test_ssl_avoidance.py +0 -0
  157. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/entropy-patches/worker.py +0 -0
  158. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/entropy-patches/wrangler.jsonc +0 -0
  159. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/python-rpc/pyproject.toml +0 -0
  160. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/python-rpc/python-rpc.wd-test +0 -0
  161. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/python-rpc/worker.js +0 -0
  162. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/python-rpc/worker.py +0 -0
  163. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/python-rpc/wrangler.jsonc +0 -0
  164. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/sdk/pyproject.toml +0 -0
  165. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/sdk/sdk.wd-test +0 -0
  166. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/sdk/server.py +0 -0
  167. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/sdk/tests/test_sdk.py +0 -0
  168. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/sdk/worker.py +0 -0
  169. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/sdk/wrangler.jsonc +0 -0
  170. {workers_runtime_sdk-1.6.10 → workers_runtime_sdk-1.6.12}/tests/workerd-test/wsgi/wrangler.jsonc +0 -0
@@ -2,6 +2,23 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v1.6.12 (2026-08-11)
6
+
7
+ ### Bug Fixes
8
+
9
+ - **runtime-sdk**: Send empty WebSocket frames instead of dropping them
10
+ ([#165](https://github.com/cloudflare/workers-py/pull/165),
11
+ [`a4128ce`](https://github.com/cloudflare/workers-py/commit/a4128cee402aa6f28f01e3e2268241d05d9fd393))
12
+
13
+
14
+ ## v1.6.11 (2026-08-10)
15
+
16
+ ### Bug Fixes
17
+
18
+ - Implements tests for FastAPI StaticFiles and anyio thread patch
19
+ ([`a30f53e`](https://github.com/cloudflare/workers-py/commit/a30f53e95edcf42fc93e5e2dc84251121881418b))
20
+
21
+
5
22
  ## v1.6.10 (2026-08-10)
6
23
 
7
24
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: workers-runtime-sdk
3
- Version: 1.6.10
3
+ Version: 1.6.12
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.6.10"
7
+ version = "1.6.12"
8
8
  description = "Python SDK for Cloudflare Workers"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -0,0 +1,45 @@
1
+ """
2
+ Top level runtime compatibility patches for packages.
3
+
4
+ These patches adapt packages that assume capabilities the workers runtime does
5
+ not provide. Unlike the entropy patches, they are not related to snapshotting.
6
+ """
7
+
8
+ from contextlib import contextmanager
9
+
10
+ from _cloudflare.import_patch_manager import (
11
+ register_exec_patch,
12
+ )
13
+
14
+
15
+ @register_exec_patch("anyio.to_thread")
16
+ @contextmanager
17
+ def anyio_to_thread_context(module):
18
+ """`anyio.to_thread.run_sync` dispatches blocking work to an OS thread, but the
19
+ workers runtime is single threaded, so starting a thread raises
20
+ `RuntimeError: can't start new thread`. Run the callable inline instead.
21
+
22
+ This function is the only caller of `run_sync_in_worker_thread`, which makes it
23
+ the single chokepoint for every blocking call anyio makes on behalf of a
24
+ framework. In starlette/fastapi that covers sync route handlers, sync
25
+ dependencies, `StaticFiles`, `FileResponse`, `UploadFile`, `BackgroundTask` and
26
+ `GZipMiddleware`, as well as `anyio.Path` and `anyio.open_file`.
27
+
28
+ Patching the module attribute is enough because every caller looks it up at
29
+ call time (e.g. `starlette.concurrency` and `anyio._core._fileio` both import
30
+ the module rather than the function).
31
+
32
+ We patch `anyio.to_thread` rather than the backend's
33
+ `run_sync_in_worker_thread` because `anyio._backends._asyncio` is imported
34
+ lazily by `get_async_backend()` during a request, by which point the import
35
+ patch manager is no longer installed.
36
+ """
37
+ yield
38
+
39
+ async def run_sync(func, *args, **kwargs):
40
+ # Callers pass the function's own arguments positionally and anyio's
41
+ # options (`limiter`, `abandon_on_cancel`, `cancellable`) as keywords.
42
+ # None of the options mean anything without threads, so drop them.
43
+ return func(*args)
44
+
45
+ module.run_sync = run_sync
@@ -0,0 +1 @@
1
+ import _workers_sdk_patch_loader
@@ -0,0 +1,16 @@
1
+ """
2
+ Loader shim for the top level package patches.
3
+
4
+ This module is imported by the .pth file on every Python startup. The patches
5
+ depend on the `_cloudflare` package, which only exists inside the workers
6
+ runtime. When running outside of the workers runtime, `_cloudflare` is not
7
+ available, so we silently skip loading the patches. Skipping is also what we
8
+ want in that case: the patches adapt packages to the workers runtime and should
9
+ not change how they behave under native Python.
10
+ """
11
+
12
+ import importlib.util
13
+
14
+ if importlib.util.find_spec("_cloudflare") is not None:
15
+ import _workers_sdk_entropy_import_context # noqa: F401
16
+ import _workers_sdk_package_patches # noqa: F401
@@ -352,12 +352,12 @@ async def process_websocket(app: Any, req: "Request | js.Request") -> js.Respons
352
352
  if got["type"] == "websocket.send":
353
353
  b = got.get("bytes", None)
354
354
  s = got.get("text", None)
355
- if b:
355
+ if b is not None:
356
356
  with acquire_js_buffer(b) as jsbytes:
357
357
  # Unlike the `Response` constructor, server.send seems to
358
358
  # eagerly copy the source buffer
359
359
  server.send(jsbytes)
360
- if s:
360
+ if s is not None:
361
361
  server.send(s)
362
362
 
363
363
  else:
@@ -0,0 +1,4 @@
1
+ body {
2
+ font-family: monospace;
3
+ color: rebeccapurple;
4
+ }
@@ -0,0 +1 @@
1
+ {"source": "staticfiles", "number": 7}
@@ -0,0 +1,7 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head><title>FastAPI StaticFiles Test</title></head>
4
+ <body>
5
+ <h1>Hello from StaticFiles</h1>
6
+ </body>
7
+ </html>
@@ -0,0 +1,117 @@
1
+ """Tests for FastAPI's native static file APIs (StaticFiles and FileResponse).
2
+
3
+ Unlike ``test_assets.py``, which proxies to the Workers Assets binding, these
4
+ tests exercise Starlette's own filesystem-backed static file serving against
5
+ files bundled into the worker under ``src/static/``.
6
+ """
7
+
8
+ import pytest
9
+ from _client import fetch, get_json, read_json
10
+
11
+
12
+ @pytest.mark.asyncio
13
+ async def test_staticfiles_serves_text(fastapi_app):
14
+ """Mounted StaticFiles app serves a bundled text file."""
15
+ resp = await fetch(fastapi_app, "/static/hello.txt")
16
+ assert resp.status == 200
17
+ text = await resp.text()
18
+ assert "Hello from StaticFiles" in text
19
+
20
+
21
+ @pytest.mark.asyncio
22
+ async def test_staticfiles_serves_html(fastapi_app):
23
+ """Mounted StaticFiles app serves a bundled HTML file."""
24
+ resp = await fetch(fastapi_app, "/static/index.html")
25
+ assert resp.status == 200
26
+ text = await resp.text()
27
+ assert "Hello from StaticFiles" in text
28
+ assert "<!doctype html>" in text.lower()
29
+
30
+
31
+ @pytest.mark.asyncio
32
+ async def test_staticfiles_guesses_content_type(fastapi_app):
33
+ """StaticFiles infers the content type from the file extension."""
34
+ resp = await fetch(fastapi_app, "/static/app.css")
35
+ assert resp.status == 200
36
+ assert "css" in resp.headers.get("content-type")
37
+
38
+
39
+ @pytest.mark.asyncio
40
+ async def test_staticfiles_serves_json(fastapi_app):
41
+ """StaticFiles serves a JSON file that is parseable and correctly typed."""
42
+ resp = await fetch(fastapi_app, "/static/data.json")
43
+ assert resp.status == 200
44
+ assert "application/json" in resp.headers.get("content-type")
45
+ data = await read_json(resp)
46
+ assert data["source"] == "staticfiles"
47
+ assert data["number"] == 7
48
+
49
+
50
+ @pytest.mark.asyncio
51
+ async def test_staticfiles_sets_content_length(fastapi_app):
52
+ """StaticFiles reports the on-disk size and sends exactly that many bytes."""
53
+ resp = await fetch(fastapi_app, "/static/hello.txt")
54
+ assert resp.status == 200
55
+ content_length = resp.headers.get("content-length")
56
+ assert content_length is not None
57
+ body = (await resp.text()).encode()
58
+ assert len(body) == int(content_length)
59
+
60
+
61
+ @pytest.mark.asyncio
62
+ async def test_staticfiles_sets_validators(fastapi_app):
63
+ """StaticFiles derives etag and last-modified headers from the file stat."""
64
+ resp = await fetch(fastapi_app, "/static/hello.txt")
65
+ assert resp.status == 200
66
+ assert resp.headers.get("etag")
67
+ assert resp.headers.get("last-modified")
68
+
69
+
70
+ @pytest.mark.asyncio
71
+ async def test_staticfiles_honours_if_none_match(fastapi_app):
72
+ """A conditional request matching the etag gets a 304 with no body."""
73
+ first = await fetch(fastapi_app, "/static/hello.txt")
74
+ etag = first.headers.get("etag")
75
+ assert etag
76
+
77
+ second = await fetch(
78
+ fastapi_app, "/static/hello.txt", headers={"if-none-match": etag}
79
+ )
80
+ assert second.status == 304
81
+ assert await second.text() == ""
82
+
83
+
84
+ @pytest.mark.asyncio
85
+ async def test_staticfiles_missing_file_returns_404(fastapi_app):
86
+ """StaticFiles returns 404 for a file that is not bundled."""
87
+ resp = await fetch(fastapi_app, "/static/nonexistent.txt")
88
+ assert resp.status == 404
89
+
90
+
91
+ @pytest.mark.asyncio
92
+ async def test_file_response_serves_file(fastapi_app):
93
+ """A route returning FileResponse streams the bundled file."""
94
+ resp = await fetch(fastapi_app, "/native-file")
95
+ assert resp.status == 200
96
+ assert "text/plain" in resp.headers.get("content-type")
97
+ text = await resp.text()
98
+ assert "Hello from StaticFiles" in text
99
+
100
+
101
+ @pytest.mark.asyncio
102
+ async def test_file_response_sets_content_length(fastapi_app):
103
+ """FileResponse reports the on-disk size and sends exactly that many bytes."""
104
+ resp = await fetch(fastapi_app, "/native-file")
105
+ assert resp.status == 200
106
+ content_length = resp.headers.get("content-length")
107
+ assert content_length is not None
108
+ body = (await resp.text()).encode()
109
+ assert len(body) == int(content_length)
110
+
111
+
112
+ @pytest.mark.asyncio
113
+ async def test_api_route_still_works(fastapi_app, env):
114
+ """API routes are unaffected by the StaticFiles mount."""
115
+ resp, data = await get_json(fastapi_app, "/api/hello", env=env)
116
+ assert resp.status == 200
117
+ assert data["message"] == "Hello from FastAPI"
@@ -1,9 +1,12 @@
1
1
  import asyncio
2
2
  import importlib.util
3
+ from pathlib import Path
3
4
 
4
5
  import pytest
5
6
  from fastapi import FastAPI, Request
7
+ from fastapi.responses import FileResponse
6
8
  from fastapi.responses import Response as FastAPIResponse
9
+ from fastapi.staticfiles import StaticFiles
7
10
  from pyodide.webloop import WebLoop
8
11
 
9
12
  import asgi
@@ -17,6 +20,8 @@ async def _noop(*args):
17
20
  WebLoop.shutdown_asyncgens = _noop
18
21
  WebLoop.shutdown_default_executor = _noop
19
22
 
23
+ STATIC_DIR = Path(__file__).parent / "static"
24
+
20
25
  app = FastAPI()
21
26
 
22
27
 
@@ -30,6 +35,17 @@ async def health():
30
35
  return {"ok": True}
31
36
 
32
37
 
38
+ @app.get("/native-file")
39
+ async def native_file():
40
+ """Serve a single bundled file with FastAPI's native FileResponse."""
41
+ return FileResponse(STATIC_DIR / "hello.txt", media_type="text/plain")
42
+
43
+
44
+ # Mounted before the catch-all below so `/static/*` is handled by Starlette's
45
+ # own filesystem-backed static file app rather than the Assets binding.
46
+ app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
47
+
48
+
33
49
  @app.get("/{path:path}")
34
50
  async def frontend(path: str, request: Request):
35
51
  """Proxy static asset requests to the Workers Assets binding."""
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "fastapi-tests",
3
+ "main": "src/worker.py",
4
+ "compatibility_date": "%COMPAT_DATE",
5
+ "compatibility_flags": ["python_workers"],
6
+ // Only `**/*.txt` and `**/*.html` are bundled as Text by default, so the
7
+ // other `src/static/` fixtures would never reach the Pyodide filesystem for
8
+ // StaticFiles to read. `fallthrough` keeps the default Text rule as well.
9
+ "rules": [
10
+ {
11
+ "type": "Text",
12
+ "globs": ["static/*.css", "static/*.json"],
13
+ "fallthrough": true
14
+ }
15
+ ],
16
+ "assets": {
17
+ "directory": "./public/",
18
+ "binding": "ASSETS",
19
+ "run_worker_first": true
20
+ }
21
+ }
@@ -26,6 +26,22 @@ def _listen(ws, event_type):
26
26
  return fut
27
27
 
28
28
 
29
+ def _collect(ws, count):
30
+ """Future resolved with the payloads of the first `count` messages."""
31
+ fut = asyncio.get_event_loop().create_future()
32
+ messages = []
33
+
34
+ def callback(evt):
35
+ messages.append(evt.data)
36
+ if len(messages) == count and not fut.done():
37
+ fut.set_result(messages)
38
+
39
+ proxy = create_proxy(callback)
40
+ _proxies.append(proxy)
41
+ ws.addEventListener("message", proxy)
42
+ return fut
43
+
44
+
29
45
  async def _ws_connect(path):
30
46
  # Upgrade through the raw JS binding (as durable-object-websocket's
31
47
  # tester.js does): the SDK fetch wrapper routes through pyfetch, whose
@@ -113,3 +129,14 @@ async def test_binary_frame_arrives_as_asgi_bytes():
113
129
  data = evt.data
114
130
  assert not isinstance(data, str), f"delivered to the app as text: {data!r}"
115
131
  assert data.to_bytes() == b"bytes=" + payload
132
+
133
+
134
+ @pytest.mark.asyncio
135
+ async def test_empty_frames_reach_the_client():
136
+ async with _ws_session("/ws-empty") as ws:
137
+ received = _collect(ws, 3)
138
+ ws.send("go")
139
+ messages = await asyncio.wait_for(received, TIMEOUT_S)
140
+ assert messages[0] == ""
141
+ assert messages[1].to_bytes() == b""
142
+ assert messages[2] == "done"
@@ -80,15 +80,37 @@ class WSEchoApp:
80
80
  await send({"type": "websocket.send", "text": reply})
81
81
 
82
82
 
83
+ class WSEmptyFrameApp:
84
+ """On each client frame, replies with an empty text frame, an empty binary
85
+ frame, and a sentinel, so a test can tell whether empty frames reach the
86
+ client at all."""
87
+
88
+ async def __call__(self, scope, receive, send):
89
+ if scope["type"] == "lifespan":
90
+ await _drain_lifespan(receive, send)
91
+ return
92
+ message = await receive()
93
+ assert message["type"] == "websocket.connect"
94
+ await send({"type": "websocket.accept"})
95
+ while True:
96
+ message = await receive()
97
+ if message["type"] == "websocket.disconnect":
98
+ return
99
+ await send({"type": "websocket.send", "text": ""})
100
+ await send({"type": "websocket.send", "bytes": b""})
101
+ await send({"type": "websocket.send", "text": "done"})
102
+
103
+
83
104
  ws_app = WSWatchApp()
84
105
  echo_app = WSEchoApp()
106
+ empty_frame_app = WSEmptyFrameApp()
85
107
 
86
108
 
87
109
  class Default(WorkerEntrypoint):
88
110
  async def fetch(self, request):
89
111
  if (request.headers.get("upgrade") or "").lower() == "websocket":
90
112
  path = urlsplit(request.url).path
91
- app = echo_app if path == "/ws-echo" else ws_app
113
+ app = {"/ws-echo": echo_app, "/ws-empty": empty_frame_app}.get(path, ws_app)
92
114
  return await asgi.websocket(app, request)
93
115
  import json
94
116
 
@@ -0,0 +1,5 @@
1
+ [project]
2
+ name = "test"
3
+ version = "0.0.0"
4
+ requires-python = ">=3.12"
5
+ dependencies = ["pytest", "pytest-asyncio<1.2.0"]
@@ -0,0 +1,105 @@
1
+ import json
2
+
3
+ import js
4
+ import pytest
5
+ from pyodide.ffi import to_js
6
+ from worker import (
7
+ STREAMING_CHUNK_SIZE,
8
+ STREAMING_NUM_CHUNKS,
9
+ crash_app,
10
+ example_hdr,
11
+ )
12
+
13
+ from workers import Request, env, wsgi
14
+
15
+
16
+ @pytest.mark.asyncio
17
+ async def test_headers():
18
+ response = await env.SELF.fetch("http://example.com/", headers=to_js(example_hdr))
19
+ assert response.status == 200
20
+ text = await response.text()
21
+ assert text == "Hello, World"
22
+ # Echoed-back headers should be present.
23
+ assert response.headers.get("header1") == "Value1"
24
+ assert response.headers.get("header2") == "Value2"
25
+
26
+
27
+ @pytest.mark.asyncio
28
+ async def test_echo_body():
29
+ response = await env.SELF.fetch(
30
+ "http://example.com/echo-body",
31
+ method="POST",
32
+ body="hello body",
33
+ )
34
+ assert response.status == 200
35
+ text = await response.text()
36
+ assert text == "hello body"
37
+
38
+
39
+ @pytest.mark.asyncio
40
+ async def test_meta():
41
+ response = await env.SELF.fetch("http://example.com/meta?foo=bar&baz=qux")
42
+ assert response.status == 200
43
+
44
+ payload = json.loads(await response.text())
45
+ assert payload["method"] == "GET"
46
+ assert payload["path"] == "/meta"
47
+ assert payload["query"] == "foo=bar&baz=qux"
48
+ assert payload["scheme"] == "http"
49
+ assert payload["has_env"] is True
50
+
51
+
52
+ @pytest.mark.asyncio
53
+ async def test_cookies():
54
+ response = await env.SELF.fetch("http://example.com/cookies")
55
+ assert response.status == 200
56
+ # `env.SELF.fetch` returns the SDK `FetchResponse`, whose `.headers` is an
57
+ # `http.client.HTTPMessage`. Repeated Set-Cookie headers are preserved as
58
+ # separate entries (see `python_request_headers_preserve_commas`), so use
59
+ # `get_all` to recover the individual values.
60
+ cookies = response.headers.get_all("Set-Cookie")
61
+ assert "a=1" in cookies
62
+ assert "b=2" in cookies
63
+
64
+
65
+ @pytest.mark.asyncio
66
+ async def test_streaming():
67
+ response = await env.SELF.fetch("http://example.com/stream")
68
+ assert response.status == 200
69
+ assert response.headers.get("content-type") == "application/octet-stream"
70
+
71
+ reader = response.body.getReader()
72
+ body_bytes = b""
73
+ while True:
74
+ result = await reader.read()
75
+ if result.done:
76
+ break
77
+ body_bytes += result.value.to_bytes()
78
+
79
+ expected_size = STREAMING_CHUNK_SIZE * STREAMING_NUM_CHUNKS
80
+ assert len(body_bytes) == expected_size, (
81
+ f"Expected {expected_size} bytes, got {len(body_bytes)}"
82
+ )
83
+ for i in range(STREAMING_NUM_CHUNKS):
84
+ start = i * STREAMING_CHUNK_SIZE
85
+ end = start + STREAMING_CHUNK_SIZE
86
+ expected_byte = i % 256
87
+ assert all(b == expected_byte for b in body_bytes[start:end])
88
+
89
+
90
+ @pytest.mark.asyncio
91
+ async def test_app_exception_is_raised():
92
+ req = js.Request.new("http://example.com/crash-test")
93
+ with pytest.raises(RuntimeError, match="app crash before response for testing"):
94
+ await wsgi.fetch(crash_app, req, env)
95
+
96
+
97
+ def test_build_environ_handles_js_and_python_requests():
98
+ # Verify `build_environ` handles JS-style and Python-style headers
99
+ # identically, mirroring the asgi `request_to_scope` check.
100
+ js_request = js.Request.new("http://example.com/", headers=to_js(example_hdr))
101
+ py_request = Request("http://example.com/", headers=example_hdr)
102
+ js_env = wsgi.build_environ(js_request, env, b"")
103
+ py_env = wsgi.build_environ(py_request, env, b"")
104
+ assert js_env["HTTP_HEADER1"] == py_env["HTTP_HEADER1"] == "Value1"
105
+ assert js_env["HTTP_HEADER2"] == py_env["HTTP_HEADER2"] == "Value2"
@@ -0,0 +1,131 @@
1
+ import asyncio
2
+ import os
3
+ import sys
4
+
5
+ import pytest
6
+ from pyodide.webloop import WebLoop
7
+
8
+ from workers import WorkerEntrypoint, wsgi
9
+
10
+
11
+ async def noop(*args):
12
+ pass
13
+
14
+
15
+ # pytest-asyncio relies on these but in Pyodide < 0.29 WebLoop does not implement them
16
+ WebLoop.shutdown_asyncgens = noop
17
+ WebLoop.shutdown_default_executor = noop
18
+
19
+ # Pyodide 0.26.0a2's _cancel_all_tasks calls task.exception() on pending tasks,
20
+ # which raises InvalidStateError under Pyodide's WebLoop.
21
+ # Ignore this error to prevent pytest-asyncio from crashing.
22
+ if sys.version_info < (3, 13):
23
+ asyncio.runners._cancel_all_tasks = lambda loop: None # type: ignore[attr-defined]
24
+
25
+
26
+ # ---------------------------------------------------------------------------
27
+ # WSGI apps
28
+ # ---------------------------------------------------------------------------
29
+
30
+
31
+ def header_echo_app(environ, start_response):
32
+ """WSGI app that echoes request headers back in the response body and headers."""
33
+ response_headers = [("Content-Type", "text/plain")]
34
+ # Echo each incoming header back out (HTTP_* keys).
35
+ for key, value in environ.items():
36
+ if key.startswith("HTTP_"):
37
+ name = key[len("HTTP_") :].replace("_", "-").title()
38
+ response_headers.append((name, value))
39
+
40
+ start_response("200 OK", response_headers)
41
+ return [b"Hello, World"]
42
+
43
+
44
+ def echo_body_app(environ, start_response):
45
+ """WSGI app that reads the request body and echoes it back."""
46
+ length = int(environ.get("CONTENT_LENGTH") or 0)
47
+ body = environ["wsgi.input"].read(length)
48
+ start_response(
49
+ "200 OK",
50
+ [("Content-Type", "application/octet-stream")],
51
+ )
52
+ return [body]
53
+
54
+
55
+ def echo_meta_app(environ, start_response):
56
+ """WSGI app that returns selected environ values so the test can assert on them."""
57
+ import json
58
+
59
+ payload = {
60
+ "method": environ["REQUEST_METHOD"],
61
+ "path": environ["PATH_INFO"],
62
+ "query": environ["QUERY_STRING"],
63
+ "scheme": environ["wsgi.url_scheme"],
64
+ "has_env": "workers.env" in environ,
65
+ }
66
+ body = json.dumps(payload).encode()
67
+ start_response("200 OK", [("Content-Type", "application/json")])
68
+ return [body]
69
+
70
+
71
+ def cookies_app(environ, start_response):
72
+ """WSGI app that sets multiple Set-Cookie headers (must not collapse)."""
73
+ start_response(
74
+ "200 OK",
75
+ [
76
+ ("Content-Type", "text/plain"),
77
+ ("Set-Cookie", "a=1"),
78
+ ("Set-Cookie", "b=2"),
79
+ ],
80
+ )
81
+ return [b"cookies"]
82
+
83
+
84
+ STREAMING_CHUNK_SIZE = 1024
85
+ STREAMING_NUM_CHUNKS = 5
86
+
87
+
88
+ def streaming_app(environ, start_response):
89
+ """WSGI app that returns multiple body chunks via a generator."""
90
+ start_response("200 OK", [("Content-Type", "application/octet-stream")])
91
+
92
+ def generate():
93
+ for i in range(STREAMING_NUM_CHUNKS):
94
+ yield bytes([i % 256]) * STREAMING_CHUNK_SIZE
95
+
96
+ return generate()
97
+
98
+
99
+ def crash_app(environ, start_response):
100
+ raise RuntimeError("app crash before response for testing")
101
+
102
+
103
+ example_hdr = {"Header1": "Value1", "Header2": "Value2"}
104
+
105
+
106
+ class Default(WorkerEntrypoint):
107
+ # Each path in this handler serves one of the WSGI apps above; the
108
+ # assertions live in tests/test_wsgi.py.
109
+ async def fetch(self, request):
110
+ from js import URL
111
+
112
+ url = URL.new(request.url)
113
+ path = url.pathname
114
+
115
+ if path == "/echo-body":
116
+ return await wsgi.fetch(echo_body_app, request, self.env)
117
+ elif path == "/meta":
118
+ return await wsgi.fetch(echo_meta_app, request, self.env)
119
+ elif path == "/cookies":
120
+ return await wsgi.fetch(cookies_app, request, self.env)
121
+ elif path == "/stream":
122
+ return await wsgi.fetch(streaming_app, request, self.env)
123
+
124
+ return await wsgi.fetch(header_echo_app, request, self.env)
125
+
126
+ async def test(self, ctrl):
127
+ os.chdir("/session/metadata/tests")
128
+ args = [".", "-vv"]
129
+ if self.env.color:
130
+ args.append("--color=yes")
131
+ assert pytest.main(args) == 0
@@ -10,6 +10,10 @@ const unitTests :Workerd.Config = (
10
10
  ],
11
11
  bindings = [
12
12
  ( name = "SELF", service = "python-wsgi" ),
13
+ (
14
+ name = "color",
15
+ json = "%COLOR"
16
+ ),
13
17
  ],
14
18
  compatibilityDate = "%COMPAT_DATE",
15
19
  compatibilityFlags = ["python_workers"],
@@ -345,7 +345,7 @@ wheels = [
345
345
 
346
346
  [[package]]
347
347
  name = "workers-runtime-sdk"
348
- version = "1.6.10"
348
+ version = "1.6.12"
349
349
  source = { editable = "." }
350
350
 
351
351
  [package.dev-dependencies]
@@ -1 +0,0 @@
1
- import _workers_sdk_entropy_import_context_loader