workers-runtime-sdk 1.4.1__tar.gz → 1.4.3__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 (17) hide show
  1. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/CHANGELOG.md +18 -0
  2. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/PKG-INFO +1 -1
  3. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/pyproject.toml +1 -1
  4. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/src/workers/_workers.py +51 -5
  5. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/.gitignore +0 -0
  6. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/AGENTS.md +0 -0
  7. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/README.md +0 -0
  8. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/src/_cloudflare_compat_flags.pyi +0 -0
  9. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/src/_pyodide_entrypoint_helper.pyi +0 -0
  10. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/src/_workers_sdk_entropy_import_context.pth +0 -0
  11. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/src/_workers_sdk_entropy_import_context.py +0 -0
  12. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/src/_workers_sdk_entropy_import_context_loader.py +0 -0
  13. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/src/asgi.py +0 -0
  14. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/src/workers/__init__.py +0 -0
  15. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/src/workers/py.typed +0 -0
  16. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/src/workers/workflows.py +0 -0
  17. {workers_runtime_sdk-1.4.1 → workers_runtime_sdk-1.4.3}/uv.lock +0 -0
@@ -2,6 +2,24 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v1.4.3 (2026-06-18)
6
+
7
+ ### Bug Fixes
8
+
9
+ - Ensure Worker subclasses are wrapped only once
10
+ ([#126](https://github.com/cloudflare/workers-py/pull/126),
11
+ [`af8ec42`](https://github.com/cloudflare/workers-py/commit/af8ec42eed1e2bbe6da1dbd537eb7a475f7071fb))
12
+
13
+
14
+ ## v1.4.2 (2026-06-18)
15
+
16
+ ### Bug Fixes
17
+
18
+ - Make iterables work correctly when returned from rpc call
19
+ ([#127](https://github.com/cloudflare/workers-py/pull/127),
20
+ [`36dc659`](https://github.com/cloudflare/workers-py/commit/36dc659d6ba394d75e3d11b3e78e2b08fcd91c9f))
21
+
22
+
5
23
  ## v1.4.1 (2026-06-18)
6
24
 
7
25
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: workers-runtime-sdk
3
- Version: 1.4.1
3
+ Version: 1.4.3
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.4.1"
7
+ version = "1.4.3"
8
8
  description = "Python SDK for Cloudflare Workers"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -1122,6 +1122,14 @@ class _BindingWrapper:
1122
1122
  def __init__(self, binding):
1123
1123
  self._binding = binding
1124
1124
 
1125
+ @property
1126
+ def _real_name(self):
1127
+ js_name = _get_js_constructor_name(self._binding)
1128
+ if not js_name:
1129
+ # Should not happen, but just in case
1130
+ return type(self).__name__
1131
+ return js_name
1132
+
1125
1133
  def _should_wrap_nested_attribute(self, jsobj) -> bool:
1126
1134
  if not isinstance(jsobj, JsProxy):
1127
1135
  return False
@@ -1175,8 +1183,23 @@ class _BindingWrapper:
1175
1183
  return result
1176
1184
 
1177
1185
  def __getitem__(self, key):
1186
+ if isinstance(key, int):
1187
+ return self._convert_result(self._binding[key])
1178
1188
  return self._convert_result(getattr(self._binding, key))
1179
1189
 
1190
+ def __iter__(self):
1191
+ binding = self._binding
1192
+ if not hasattr(binding, "__iter__"):
1193
+ raise TypeError(f"'{self._real_name}' object is not iterable")
1194
+ for item in binding:
1195
+ yield self._convert_result(item)
1196
+
1197
+ def __len__(self):
1198
+ binding = self._binding
1199
+ if not hasattr(binding, "length"):
1200
+ raise TypeError(f"'{self._real_name}' object has no len()")
1201
+ return binding.length
1202
+
1180
1203
 
1181
1204
  class _FetcherWrapper(_BindingWrapper):
1182
1205
  def fetch(self, *args, **kwargs):
@@ -1509,6 +1532,26 @@ async def _do_call(entrypoint, name, config, callback, *results):
1509
1532
  return result
1510
1533
 
1511
1534
 
1535
+ def _is_direct_binding_subclass(cls: type, binding_cls: type) -> bool:
1536
+ """
1537
+ Checks if the class is a direct subclass of the binding class.
1538
+
1539
+ In order to prevent applying the wrapper multiple times,
1540
+ we only want to apply the wrapper if the class is directly inheriting
1541
+ from the binding class, not if it's inheriting from another class that
1542
+ inherits from the binding class.
1543
+
1544
+ Examples:
1545
+ - `class A(DurableObject)` -> True
1546
+ - `class B(A)` -> False
1547
+ - `class C(B)` -> False
1548
+ - `class D(C, DurableObject)` -> False
1549
+ """
1550
+ return not any(
1551
+ issubclass(b, binding_cls) for b in cls.__bases__ if b is not binding_cls
1552
+ )
1553
+
1554
+
1512
1555
  def _wrap_subclass(cls):
1513
1556
  # Override the class __init__ so that we can wrap the `env` in the constructor.
1514
1557
  original_init = cls.__init__
@@ -1567,7 +1610,8 @@ class DurableObject:
1567
1610
  self.env = env
1568
1611
 
1569
1612
  def __init_subclass__(cls, **_kwargs):
1570
- _wrap_subclass(cls)
1613
+ if _is_direct_binding_subclass(cls, DurableObject):
1614
+ _wrap_subclass(cls)
1571
1615
 
1572
1616
 
1573
1617
  class WorkerEntrypoint:
@@ -1583,8 +1627,9 @@ class WorkerEntrypoint:
1583
1627
  self.env = env
1584
1628
 
1585
1629
  def __init_subclass__(cls, **_kwargs: Any):
1586
- _wrap_subclass(cls)
1587
- _wrap_queue_handler(cls)
1630
+ if _is_direct_binding_subclass(cls, WorkerEntrypoint):
1631
+ _wrap_subclass(cls)
1632
+ _wrap_queue_handler(cls)
1588
1633
 
1589
1634
 
1590
1635
  class WorkflowEntrypoint:
@@ -1600,8 +1645,9 @@ class WorkflowEntrypoint:
1600
1645
  self.env = env
1601
1646
 
1602
1647
  def __init_subclass__(cls, **_kwargs: Any):
1603
- _wrap_subclass(cls)
1604
- _wrap_workflow_step(cls)
1648
+ if _is_direct_binding_subclass(cls, WorkflowEntrypoint):
1649
+ _wrap_subclass(cls)
1650
+ _wrap_workflow_step(cls)
1605
1651
 
1606
1652
 
1607
1653
  def _wrap_queue_handler(cls):