workers-runtime-sdk 1.2.0__tar.gz → 1.3.0__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.
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/CHANGELOG.md +17 -0
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/PKG-INFO +1 -1
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/pyproject.toml +1 -1
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/src/workers/_workers.py +114 -13
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/.gitignore +0 -0
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/AGENTS.md +0 -0
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/README.md +0 -0
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/src/_cloudflare_compat_flags.pyi +0 -0
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/src/_pyodide_entrypoint_helper.pyi +0 -0
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/src/_workers_sdk_entropy_import_context.pth +0 -0
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/src/_workers_sdk_entropy_import_context.py +0 -0
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/src/_workers_sdk_entropy_import_context_loader.py +0 -0
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/src/asgi.py +0 -0
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/src/workers/__init__.py +0 -0
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/src/workers/py.typed +0 -0
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/src/workers/workflows.py +0 -0
- {workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/uv.lock +0 -0
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- version list -->
|
|
4
4
|
|
|
5
|
+
## v1.3.0 (2026-06-15)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
- **runtime-sdk**: Revise type conversion for Durable Object binding
|
|
10
|
+
([#112](https://github.com/cloudflare/workers-py/pull/112),
|
|
11
|
+
[`b12650e`](https://github.com/cloudflare/workers-py/commit/b12650ef91bb71f4ebebd9827bad2d1f0946fd62))
|
|
12
|
+
|
|
13
|
+
- **runtime-sdk**: Revise type conversion to support bindings more natively
|
|
14
|
+
([#112](https://github.com/cloudflare/workers-py/pull/112),
|
|
15
|
+
[`b12650e`](https://github.com/cloudflare/workers-py/commit/b12650ef91bb71f4ebebd9827bad2d1f0946fd62))
|
|
16
|
+
|
|
17
|
+
- **runtime-sdk**: Update js object conversion logic to support cloudflare bindings more natively.
|
|
18
|
+
([#112](https://github.com/cloudflare/workers-py/pull/112),
|
|
19
|
+
[`b12650e`](https://github.com/cloudflare/workers-py/commit/b12650ef91bb71f4ebebd9827bad2d1f0946fd62))
|
|
20
|
+
|
|
21
|
+
|
|
5
22
|
## v1.2.0 (2026-06-12)
|
|
6
23
|
|
|
7
24
|
### Features
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: workers-runtime-sdk
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
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
|
|
@@ -17,7 +17,6 @@ from collections.abc import (
|
|
|
17
17
|
from contextlib import ExitStack, contextmanager
|
|
18
18
|
from enum import StrEnum
|
|
19
19
|
from http import HTTPMethod, HTTPStatus
|
|
20
|
-
from types import LambdaType
|
|
21
20
|
from typing import TYPE_CHECKING, Any, Never, Protocol, TypedDict, Unpack
|
|
22
21
|
|
|
23
22
|
import _cloudflare_compat_flags
|
|
@@ -916,6 +915,9 @@ class Request:
|
|
|
916
915
|
|
|
917
916
|
|
|
918
917
|
def _python_from_rpc_default_converter(value, convert, cache):
|
|
918
|
+
if value is jsnull:
|
|
919
|
+
return None
|
|
920
|
+
|
|
919
921
|
if not hasattr(value, "constructor"):
|
|
920
922
|
# Assume that the object doesn't need conversion as it's not a JS object.
|
|
921
923
|
return value
|
|
@@ -947,6 +949,41 @@ def _python_from_rpc_default_converter(value, convert, cache):
|
|
|
947
949
|
return value
|
|
948
950
|
|
|
949
951
|
|
|
952
|
+
class JsDict(dict):
|
|
953
|
+
"""
|
|
954
|
+
Python dictionary that allows attribute access to keys.
|
|
955
|
+
|
|
956
|
+
This is used to convert JS objects to Python dictionaries while maintaining
|
|
957
|
+
the ability to access keys as attributes.
|
|
958
|
+
"""
|
|
959
|
+
|
|
960
|
+
def __getattr__(self, name):
|
|
961
|
+
# The limitation of this approach is that if there is a key that conflicts with a built-in
|
|
962
|
+
# method or attribute of the dict class, it will not be accessible through attribute access.
|
|
963
|
+
# But that is a reasonable trade-off for the convenience of being able to access keys as
|
|
964
|
+
# attributes.
|
|
965
|
+
try:
|
|
966
|
+
return self[name]
|
|
967
|
+
except KeyError:
|
|
968
|
+
raise AttributeError(name) from None
|
|
969
|
+
|
|
970
|
+
def __setattr__(self, name, value):
|
|
971
|
+
self[name] = value
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
def _replace_jsnull_with_none(obj):
|
|
975
|
+
"""
|
|
976
|
+
Recursively converts JS objects to Python objects.
|
|
977
|
+
"""
|
|
978
|
+
if obj is jsnull:
|
|
979
|
+
return None
|
|
980
|
+
if isinstance(obj, dict):
|
|
981
|
+
return JsDict({k: _replace_jsnull_with_none(v) for k, v in obj.items()})
|
|
982
|
+
if isinstance(obj, list):
|
|
983
|
+
return [_replace_jsnull_with_none(v) for v in obj]
|
|
984
|
+
return obj
|
|
985
|
+
|
|
986
|
+
|
|
950
987
|
def python_from_rpc(obj: "JsProxy"):
|
|
951
988
|
"""
|
|
952
989
|
Converts JS objects like Response, Request, Blob, etc. to equivalent Python objects defined in
|
|
@@ -956,6 +993,9 @@ def python_from_rpc(obj: "JsProxy"):
|
|
|
956
993
|
it does not support serializing all JS object types.
|
|
957
994
|
"""
|
|
958
995
|
|
|
996
|
+
if obj is jsnull:
|
|
997
|
+
return None
|
|
998
|
+
|
|
959
999
|
if not hasattr(obj, "constructor"):
|
|
960
1000
|
return obj
|
|
961
1001
|
|
|
@@ -966,14 +1006,20 @@ def python_from_rpc(obj: "JsProxy"):
|
|
|
966
1006
|
|
|
967
1007
|
result = obj.to_py(default_converter=_python_from_rpc_default_converter)
|
|
968
1008
|
|
|
969
|
-
return result
|
|
1009
|
+
return _replace_jsnull_with_none(result)
|
|
970
1010
|
|
|
971
1011
|
|
|
972
1012
|
def _raise_on_disabled_type(value):
|
|
1013
|
+
if isinstance(value, _BindingWrapper):
|
|
1014
|
+
return
|
|
1015
|
+
|
|
1016
|
+
if callable(value) and not isinstance(value, type):
|
|
1017
|
+
return
|
|
1018
|
+
|
|
973
1019
|
if _is_js_instance(value, "RegExp"):
|
|
974
1020
|
raise TypeError(f"{value.constructor.name} cannot be sent over RPC.")
|
|
975
1021
|
|
|
976
|
-
if isinstance(value, (tuple, bytearray
|
|
1022
|
+
if isinstance(value, (tuple, bytearray)):
|
|
977
1023
|
raise TypeError(f"{type(value)} cannot be sent over RPC.")
|
|
978
1024
|
|
|
979
1025
|
if inspect.isawaitable(value):
|
|
@@ -991,7 +1037,10 @@ def _raise_on_disabled_type(value):
|
|
|
991
1037
|
|
|
992
1038
|
def _python_to_rpc_default_converter(obj, convert, cache):
|
|
993
1039
|
if obj is None:
|
|
994
|
-
return
|
|
1040
|
+
return jsnull
|
|
1041
|
+
|
|
1042
|
+
if isinstance(obj, _BindingWrapper):
|
|
1043
|
+
return obj._binding
|
|
995
1044
|
|
|
996
1045
|
if hasattr(obj, "js_object"):
|
|
997
1046
|
return obj.js_object
|
|
@@ -1003,11 +1052,26 @@ def _python_to_rpc_default_converter(obj, convert, cache):
|
|
|
1003
1052
|
if isinstance(obj, Exception):
|
|
1004
1053
|
return js.Error.new(str(obj))
|
|
1005
1054
|
|
|
1055
|
+
if callable(obj) and not isinstance(obj, type):
|
|
1056
|
+
# Wrap function with create_proxy so that
|
|
1057
|
+
# it doesn't get garbage collected
|
|
1058
|
+
return create_proxy(obj)
|
|
1059
|
+
|
|
1006
1060
|
_raise_on_disabled_type(obj)
|
|
1007
1061
|
|
|
1008
1062
|
return obj
|
|
1009
1063
|
|
|
1010
1064
|
|
|
1065
|
+
def _replace_none_with_jsnull(value):
|
|
1066
|
+
if value is None:
|
|
1067
|
+
return jsnull
|
|
1068
|
+
if isinstance(value, dict):
|
|
1069
|
+
return {k: _replace_none_with_jsnull(v) for k, v in value.items()}
|
|
1070
|
+
if isinstance(value, list):
|
|
1071
|
+
return [_replace_none_with_jsnull(v) for v in value]
|
|
1072
|
+
return value
|
|
1073
|
+
|
|
1074
|
+
|
|
1011
1075
|
def python_to_rpc(value) -> JsProxy:
|
|
1012
1076
|
"""
|
|
1013
1077
|
Converts Python objects defined in this module (Response, Request, etc) and native Python types
|
|
@@ -1017,37 +1081,58 @@ def python_to_rpc(value) -> JsProxy:
|
|
|
1017
1081
|
it does not support serializing all Python object types.
|
|
1018
1082
|
"""
|
|
1019
1083
|
|
|
1084
|
+
if value is None:
|
|
1085
|
+
return jsnull
|
|
1086
|
+
|
|
1087
|
+
if isinstance(value, _BindingWrapper):
|
|
1088
|
+
return value._binding
|
|
1089
|
+
|
|
1090
|
+
value = _replace_none_with_jsnull(value)
|
|
1091
|
+
|
|
1020
1092
|
# `to_js` won't always call the default_converter, for example when a list of tuples is passed
|
|
1021
1093
|
_raise_on_disabled_type(value)
|
|
1022
1094
|
|
|
1023
1095
|
result = to_js(
|
|
1024
1096
|
value,
|
|
1025
1097
|
default_converter=_python_to_rpc_default_converter,
|
|
1026
|
-
dict_converter=
|
|
1098
|
+
dict_converter=Object.fromEntries,
|
|
1027
1099
|
)
|
|
1028
1100
|
|
|
1029
1101
|
return result
|
|
1030
1102
|
|
|
1031
1103
|
|
|
1032
|
-
class
|
|
1104
|
+
class _BindingWrapper:
|
|
1033
1105
|
def __init__(self, binding):
|
|
1034
1106
|
self._binding = binding
|
|
1035
1107
|
|
|
1108
|
+
def _convert_result(self, result):
|
|
1109
|
+
converted = python_from_rpc(result)
|
|
1110
|
+
if isinstance(converted, JsProxy):
|
|
1111
|
+
# If the RPC result is another JsProxy, we assume that
|
|
1112
|
+
# it is another RPC-wrapped object and wrap it as well.
|
|
1113
|
+
# for example, d1.bind() returns the same object as a result.
|
|
1114
|
+
# TODO: This is a bit of a hack. We should revisit when there are more
|
|
1115
|
+
# bindings to support with different patterns.
|
|
1116
|
+
return self.__class__(converted)
|
|
1117
|
+
return converted
|
|
1118
|
+
|
|
1036
1119
|
def _getattr_helper(self, name):
|
|
1037
1120
|
attr = getattr(self._binding, name)
|
|
1038
1121
|
|
|
1039
1122
|
if not callable(attr):
|
|
1040
|
-
return attr
|
|
1123
|
+
return self._convert_result(attr)
|
|
1041
1124
|
|
|
1042
|
-
|
|
1043
|
-
async def wrapper(*args, **kwargs):
|
|
1125
|
+
def wrapper(*args, **kwargs):
|
|
1044
1126
|
js_args = [python_to_rpc(arg) for arg in args]
|
|
1045
1127
|
js_kwargs = {k: python_to_rpc(v) for k, v in kwargs.items()}
|
|
1046
1128
|
result = attr(*js_args, **js_kwargs)
|
|
1047
1129
|
if hasattr(result, "then") and callable(result.then):
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1130
|
+
|
|
1131
|
+
async def await_and_convert():
|
|
1132
|
+
return self._convert_result(await result)
|
|
1133
|
+
|
|
1134
|
+
return await_and_convert()
|
|
1135
|
+
return self._convert_result(result)
|
|
1051
1136
|
|
|
1052
1137
|
return wrapper
|
|
1053
1138
|
|
|
@@ -1056,6 +1141,11 @@ class _FetcherWrapper:
|
|
|
1056
1141
|
setattr(self, name, result)
|
|
1057
1142
|
return result
|
|
1058
1143
|
|
|
1144
|
+
def __getitem__(self, key):
|
|
1145
|
+
return self._convert_result(getattr(self._binding, key))
|
|
1146
|
+
|
|
1147
|
+
|
|
1148
|
+
class _FetcherWrapper(_BindingWrapper):
|
|
1059
1149
|
def fetch(self, *args, **kwargs):
|
|
1060
1150
|
return fetch(*args, fetcher=self._binding.fetch, **kwargs)
|
|
1061
1151
|
|
|
@@ -1089,6 +1179,9 @@ class DurableObjectContext:
|
|
|
1089
1179
|
|
|
1090
1180
|
def __getattr__(self, name: str):
|
|
1091
1181
|
result = getattr(self._ctx, name)
|
|
1182
|
+
if _is_js_instance(result, "DurableObjectStorage"):
|
|
1183
|
+
# durable_object.ctx.storage
|
|
1184
|
+
result = _BindingWrapper(result)
|
|
1092
1185
|
setattr(self, name, result)
|
|
1093
1186
|
return result
|
|
1094
1187
|
|
|
@@ -1173,7 +1266,15 @@ class _EnvWrapper:
|
|
|
1173
1266
|
if _is_js_instance(binding, "WorkflowImpl"):
|
|
1174
1267
|
return _WorkflowBindingWrapper(binding)
|
|
1175
1268
|
|
|
1176
|
-
|
|
1269
|
+
if _is_js_instance(binding, "KvNamespace"):
|
|
1270
|
+
return _BindingWrapper(binding)
|
|
1271
|
+
|
|
1272
|
+
if _is_js_instance(binding, "R2Bucket"):
|
|
1273
|
+
return _BindingWrapper(binding)
|
|
1274
|
+
|
|
1275
|
+
if _is_js_instance(binding, "D1Database"):
|
|
1276
|
+
return _BindingWrapper(binding)
|
|
1277
|
+
|
|
1177
1278
|
return binding
|
|
1178
1279
|
|
|
1179
1280
|
def __getattr__(self, name):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/src/_workers_sdk_entropy_import_context.pth
RENAMED
|
File without changes
|
{workers_runtime_sdk-1.2.0 → workers_runtime_sdk-1.3.0}/src/_workers_sdk_entropy_import_context.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|