Repository: dask/dask
Pull request #10162 (2023-04-07 23:21:14)

Fix flaky `modf` operation in `test_arithmetic` 
Possibly fix an intermittent failure:

`FAILED dask/array/tests/test_array_core.py::test_arithmetic - RuntimeWarning: invalid value encountered in modf`

- [x] Passes `pre-commit run --all-files`



Patch:
diff --git a/dask/array/ufunc.py b/dask/array/ufunc.py
index ffb59fb9c..8554edf3e 100644
--- a/dask/array/ufunc.py
+++ b/dask/array/ufunc.py
@@ -327,7 +327,7 @@ def modf(x):
         for key in core.flatten(tmp.__dask_keys__())
     }
 
-    a = np.empty_like(getattr(x, "_meta", x), shape=(1,) * x.ndim, dtype=x.dtype)
+    a = np.ones_like(getattr(x, "_meta", x), shape=(1,) * x.ndim, dtype=x.dtype)
     l, r = np.modf(a)
 
     graph = HighLevelGraph.from_collections(left, ldsk, dependencies=[tmp])
diff --git a/dask/config.py b/dask/config.py
index c3a1836a7..6aee66f17 100644
--- a/dask/config.py
+++ b/dask/config.py
@@ -79,7 +79,12 @@ def canonical_name(k: str, config: dict) -> str:
     return k
 
 
-def update(old: dict, new: Mapping, priority: Literal["old", "new"] = "new") -> dict:
+def update(
+    old: dict,
+    new: Mapping,
+    priority: Literal["old", "new", "new-defaults"] = "new",
+    defaults: Mapping | None = None,
+) -> dict:
     """Update a nested dictionary with values from another
 
     This is like dict.update except that it smoothly merges nested values
@@ -88,9 +93,12 @@ def update(old: dict, new: Mapping, priority: Literal["old", "new"] = "new") ->
 
     Parameters
     ----------
-    priority: string {'old', 'new'}
+    priority: string {'old', 'new', 'new-defaults'}
         If new (default) then the new dictionary has preference.
         Otherwise the old dictionary does.
+        If 'new-defaults', a mapping should be given of the current defaults.
+        Only if a value in ``old`` matches the current default, it will be
+        updated with ``new``.
 
     Examples
     --------
@@ -104,6 +112,12 @@ def update(old: dict, new: Mapping, priority: Literal["old", "new"] = "new") ->
     >>> update(a, b, priority='old')  # doctest: +SKIP
     {'x': 1, 'y': {'a': 2, 'b': 3}}
 
+    >>> d = {'x': 0, 'y': {'a': 2}}
+    >>> a = {'x': 1, 'y': {'a': 2}}
+    >>> b = {'x': 2, 'y': {'a': 3, 'b': 3}}
+    >>> update(a, b, priority='new-defaults', defaults=d)  # doctest: +SKIP
+    {'x': 1, 'y': {'a': 3, 'b': 3}}
+
     See Also
     --------
     dask.config.merge
@@ -114,9 +128,23 @@ def update(old: dict, new: Mapping, priority: Literal["old", "new"] = "new") ->
         if isinstance(v, Mapping):
             if k not in old or old[k] is None:
                 old[k] = {}
-            update(old[k], v, priority=priority)
+            update(
+                old[k],
+                v,
+                priority=priority,
+                defaults=defaults.get(k) if defaults else None,
+            )
         else:
-            if priority == "new" or k not in old:
+            if (
+                priority == "new"
+                or k not in old
+                or (
+                    priority == "new-defaults"
+                    and defaults
+                    and k in defaults
+                    and defaults[k] == old[k]
+                )
+            ):
                 old[k] = v
 
     return old
@@ -568,11 +596,13 @@ def update_defaults(
     It does two things:
 
     1.  Add the defaults to a global collection to be used by refresh later
-    2.  Updates the global config with the new configuration
-        prioritizing older values over newer ones
+    2.  Updates the global config with the new configuration.
+        Old values are prioritized over new ones, unless the current value
+        is the old default, in which case it's updated to the new default.
     """
+    current_defaults = merge(*defaults)
     defaults.append(new)
-    update(config, new, priority="old")
+    update(config, new, priority="new-defaults", defaults=current_defaults)
 
 
 def expand_environment_variables(config: Any) -> Any:


Test patch:
diff --git a/dask/tests/test_config.py b/dask/tests/test_config.py
index 2d8836b99..762fccf1d 100644
--- a/dask/tests/test_config.py
+++ b/dask/tests/test_config.py
@@ -52,6 +52,42 @@ def test_update():
     assert b == {"x": 2, "y": {"a": 3, "b": 2}, "z": 3}
 
 
+def test_update_new_defaults():
+    d = {"x": 1, "y": 1, "z": {"a": 1, "b": 1}}
+    o = {"x": 1, "y": 2, "z": {"a": 1, "b": 2}, "c": 2, "c2": {"d": 2}}
+    n = {"x": 3, "y": 3, "z": OrderedDict({"a": 3, "b": 3}), "c": 3, "c2": {"d": 3}}
+    assert update(o, n, priority="new-defaults", defaults=d) == {
+        "x": 3,
+        "y": 2,
+        "z": {"a": 3, "b": 2},
+        "c": 2,
+        "c2": {"d": 2},
+    }
+    assert update(o, n, priority="new-defaults", defaults=o) == update(
+        o, n, priority="new"
+    )
+    assert update(o, n, priority="new-defaults", defaults=None) == update(
+        o, n, priority="old"
+    )
+
+
+def test_update_defaults():
+    defaults = [
+        {"a": 1, "b": {"c": 1}},
+        {"a": 2, "b": {"d": 2}},
+    ]
+    current = {"a": 2, "b": {"c": 1, "d": 3}, "extra": 0}
+    new = {"a": 0, "b": {"c": 0, "d": 0}, "new-extra": 0}
+    update_defaults(new, current, defaults=defaults)
+
+    assert defaults == [
+        {"a": 1, "b": {"c": 1}},
+        {"a": 2, "b": {"d": 2}},
+        {"a": 0, "b": {"c": 0, "d": 0}, "new-extra": 0},
+    ]
+    assert current == {"a": 0, "b": {"c": 0, "d": 3}, "extra": 0, "new-extra": 0}
+
+
 def test_merge():
     a = {"x": 1, "y": {"a": 1}}
     b = {"x": 2, "z": 3, "y": {"b": 2}}