Repository: dask/dask
Pull request #11571 (2024-12-02 16:19:06)

Fix empty input for containers
Closes https://github.com/dask/distributed/issues/8953

wence-: *question*: Does one also want:

```diff
diff --git a/dask/_task_spec.py b/dask/_task_spec.py
index 82b896b6..cfbc09c5 100644
--- a/dask/_task_spec.py
+++ b/dask/_task_spec.py
@@ -110,7 +110,7 @@ def parse_input(obj: Any) -> object:
             return _wrap_namedtuple_task(None, obj, parse_input)
         return Tuple(*(parse_input(o) for o in obj))
     if isinstance(obj, dict):
-        return Dict(**{k: parse_input(v) for k, v in obj.items()})  # type: ignore
+        return Dict({k: parse_input(v) for k, v in obj.items()})
 
     if isinstance(obj, TaskRef):
         return Alias(obj.key)
```

To allow for the case where a nested dictionary doesn't have string keys (which I think used to be valid).

e.g. to support

```python
import distributed
def identity(*args, **kwargs):
    return args, kwargs

client = distributed.Client()

client.submit(identity, some_dict={1: 3, 4: "str"}).result()
```
fjetter: Yes, I believe I have this in https://github.com/dask/dask/pull/11568 already
github-actions[bot]: ## Unit Test Results
_See [test report](https://dask.github.io/dask/test_report.html) for an extended history of previous test failures. This is useful for diagnosing flaky tests._

     15 files  ± 0       15 suites  ±0   4h 14m 27s ⏱️ +34s
 13 259 tests + 4   12 197 ✅ + 4   1 062 💤 ±0  0 ❌ ±0 
164 491 runs  +60  141 572 ✅ +58  22 919 💤 +2  0 ❌ ±0 

Results for commit 0b5472ea. ± Comparison against base commit 307038b4.

[test-results]:data:application/gzip;base64,H4sIAI3mTWcC/03MSw6DIBSF4a0Yxh1wryDQzTSgkJD6aBBGpnsvUkWH/3eSsxHnR7uSZwP80ZA1+XjVkIKOfplLYycy5TWWvUWuzn6tqe93RFDiwrf/7Eg7rOa0H7PRCjaEJRwS0lyuO8YUHF2vGXCBFf/XiArUabfr0vfnfpkmH3MQajgTaDVKbRw3zFAH1qmh1Uy6AaxsgTuqJfn+ANb+MgYaAQAA


Patch:
diff --git a/dask/_task_spec.py b/dask/_task_spec.py
index 8a1712137..d239f8393 100644
--- a/dask/_task_spec.py
+++ b/dask/_task_spec.py
@@ -693,6 +693,8 @@ class NestedContainer(Task):
         _dependencies: set | frozenset | None = None,
         **kwargs: Any,
     ):
+        if len(args) == 1 and isinstance(args[0], self.klass):
+            args = args[0]  # type: ignore
         super().__init__(
             None,
             self.to_container,
@@ -728,8 +730,6 @@ class Dict(NestedContainer):
             if len(args) > 1:
                 raise ValueError("Dict can only take one positional argument")
             kwargs = args[0]
-        elif not kwargs:
-            raise ValueError("Dict needs at least one argument")
         super().__init__(
             *(Tuple(*it) for it in kwargs.items()), _dependencies=_dependencies
         )


Test patch:
diff --git a/dask/tests/test_task_spec.py b/dask/tests/test_task_spec.py
index 0b41e673b..1b6cecd5a 100644
--- a/dask/tests/test_task_spec.py
+++ b/dask/tests/test_task_spec.py
@@ -1033,3 +1033,8 @@ def test_nested_containers_different_types(task_type, python_type):
     t = task_type(Task("key-1", func, "a", TaskRef("b")), Task("key-2", func, "c", "d"))
     assert t.dependencies == {"b"}
     assert t({"b": "b"}) == python_type(("a-b", "c-d"))
+
+
+@pytest.mark.parametrize("Container", [Dict, List, Set, Tuple])
+def test_nested_containers_empty(Container):
+    assert Container(Container.klass())() == Container.klass()