We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
importing fails when calling python -OO
This was discovered by `xarray`'s `upstream-dev` CI ([environment](https://dev.azure.com/xarray/xarray/_build/results?buildId=2996&view=logs&j=2280efed-fda1-53bd-9213-1fa8ec9b4fa8&t=031ddd67-e55f-5fbd-2283-1ff4dfed6587)) a few days ago, but we were a bit slow in reporting so this also happens with the newly released `2.18.0`.

The problem is this:
```
$ python -OO -c 'import dask.array'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File ".../lib/python3.8/site-packages/dask/array/__init__.py", line 26, in <module>
    from .routines import (
  File ".../lib/python3.8/site-packages/dask/array/routines.py", line 18, in <module>
    from .creation import arange, diag, empty, indices
  File ".../lib/python3.8/site-packages/dask/array/creation.py", line 26, in <module>
    from .wrap import empty, ones, zeros, full
  File ".../lib/python3.8/site-packages/dask/array/wrap.py", line 173, in <module>
    full.__name__ = _full.__name__
AttributeError: 'functools.partial' object has no attribute '__name__'
```
without the optimization, the import obviously works.

See also pydata/xarray#4124

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `dask/array/wrap.py`
Content:
```
1 from functools import partial
2 from itertools import product
3 
4 import numpy as np
5 
6 from tlz import curry
7 
8 from ..base import tokenize
9 from ..utils import funcname
10 from .core import Array, normalize_chunks
11 from .utils import meta_from_array
12 
13 
14 def _parse_wrap_args(func, args, kwargs, shape):
15     if isinstance(shape, np.ndarray):
16         shape = shape.tolist()
17 
18     if not isinstance(shape, (tuple, list)):
19         shape = (shape,)
20 
21     name = kwargs.pop("name", None)
22     chunks = kwargs.pop("chunks", "auto")
23 
24     dtype = kwargs.pop("dtype", None)
25     if dtype is None:
26         dtype = func(shape, *args, **kwargs).dtype
27     dtype = np.dtype(dtype)
28 
29     chunks = normalize_chunks(chunks, shape, dtype=dtype)
30 
31     name = name or funcname(func) + "-" + tokenize(
32         func, shape, chunks, dtype, args, kwargs
33     )
34 
35     return {
36         "shape": shape,
37         "dtype": dtype,
38         "kwargs": kwargs,
39         "chunks": chunks,
40         "name": name,
41     }
42 
43 
44 def wrap_func_shape_as_first_arg(func, *args, **kwargs):
45     """
46     Transform np creation function into blocked version
47     """
48     if "shape" not in kwargs:
49         shape, args = args[0], args[1:]
50     else:
51         shape = kwargs.pop("shape")
52 
53     if isinstance(shape, Array):
54         raise TypeError(
55             "Dask array input not supported. "
56             "Please use tuple, list, or a 1D numpy array instead."
57         )
58 
59     parsed = _parse_wrap_args(func, args, kwargs, shape)
60     shape = parsed["shape"]
61     dtype = parsed["dtype"]
62     chunks = parsed["chunks"]
63     name = parsed["name"]
64     kwargs = parsed["kwargs"]
65 
66     keys = product([name], *[range(len(bd)) for bd in chunks])
67     shapes = product(*chunks)
68     func = partial(func, dtype=dtype, **kwargs)
69     vals = ((func,) + (s,) + args for s in shapes)
70 
71     dsk = dict(zip(keys, vals))
72     return Array(dsk, name, chunks, dtype=dtype)
73 
74 
75 def wrap_func_like(func, *args, **kwargs):
76     """
77     Transform np creation function into blocked version
78     """
79     x = args[0]
80     meta = meta_from_array(x)
81     shape = kwargs.get("shape", x.shape)
82 
83     parsed = _parse_wrap_args(func, args, kwargs, shape)
84     shape = parsed["shape"]
85     dtype = parsed["dtype"]
86     chunks = parsed["chunks"]
87     name = parsed["name"]
88     kwargs = parsed["kwargs"]
89 
90     keys = product([name], *[range(len(bd)) for bd in chunks])
91     shapes = product(*chunks)
92     shapes = list(shapes)
93     kw = [kwargs for _ in shapes]
94     for i, s in enumerate(list(shapes)):
95         kw[i]["shape"] = s
96     vals = ((partial(func, dtype=dtype, **k),) + args for (k, s) in zip(kw, shapes))
97 
98     dsk = dict(zip(keys, vals))
99 
100     return Array(dsk, name, chunks, meta=meta.astype(dtype))
101 
102 
103 def wrap_func_like_safe(func, func_like, *args, **kwargs):
104     """
105     Safe implementation for wrap_func_like(), attempts to use func_like(),
106     if the shape keyword argument, falls back to func().
107     """
108     try:
109         return func_like(*args, **kwargs)
110     except TypeError:
111         return func(*args, **kwargs)
112 
113 
114 @curry
115 def wrap(wrap_func, func, **kwargs):
116     func_like = kwargs.pop("func_like", None)
117     if func_like is None:
118         f = partial(wrap_func, func, **kwargs)
119     else:
120         f = partial(wrap_func, func_like, **kwargs)
121     template = """
122     Blocked variant of %(name)s
123 
124     Follows the signature of %(name)s exactly except that it also features
125     optional keyword arguments ``chunks: int, tuple, or dict`` and ``name: str``.
126 
127     Original signature follows below.
128     """
129     if func.__doc__ is not None:
130         f.__doc__ = template % {"name": func.__name__} + func.__doc__
131         f.__name__ = "blocked_" + func.__name__
132     return f
133 
134 
135 w = wrap(wrap_func_shape_as_first_arg)
136 
137 ones = w(np.ones, dtype="f8")
138 zeros = w(np.zeros, dtype="f8")
139 empty = w(np.empty, dtype="f8")
140 
141 
142 w_like = wrap(wrap_func_like_safe)
143 
144 
145 empty_like = w_like(np.empty, func_like=np.empty_like)
146 
147 
148 # full and full_like require special casing due to argument check on fill_value
149 # Generate wrapped functions only once
150 _full = w(np.full)
151 _full_like = w_like(np.full, func_like=np.full_like)
152 
153 
154 def full(shape, fill_value, *args, **kwargs):
155     # np.isscalar has somewhat strange behavior:
156     # https://docs.scipy.org/doc/numpy/reference/generated/numpy.isscalar.html
157     if np.ndim(fill_value) != 0:
158         raise ValueError(
159             f"fill_value must be scalar. Received {type(fill_value).__name__} instead."
160         )
161     return _full(shape=shape, fill_value=fill_value, *args, **kwargs)
162 
163 
164 def full_like(a, fill_value, *args, **kwargs):
165     if np.ndim(fill_value) != 0:
166         raise ValueError(
167             f"fill_value must be scalar. Received {type(fill_value).__name__} instead."
168         )
169     return _full_like(a=a, fill_value=fill_value, *args, **kwargs,)
170 
171 
172 full.__doc__ = _full.__doc__
173 full.__name__ = _full.__name__
174 full_like.__doc__ = _full_like.__doc__
175 full_like.__name__ = _full_like.__name__
176
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/dask/array/wrap.py b/dask/array/wrap.py
--- a/dask/array/wrap.py
+++ b/dask/array/wrap.py
@@ -170,6 +170,4 @@
 
 
 full.__doc__ = _full.__doc__
-full.__name__ = _full.__name__
 full_like.__doc__ = _full_like.__doc__
-full_like.__name__ = _full_like.__name__

{"golden_diff": "diff --git a/dask/array/wrap.py b/dask/array/wrap.py\n--- a/dask/array/wrap.py\n+++ b/dask/array/wrap.py\n@@ -170,6 +170,4 @@\n \n \n full.__doc__ = _full.__doc__\n-full.__name__ = _full.__name__\n full_like.__doc__ = _full_like.__doc__\n-full_like.__name__ = _full_like.__name__\n", "issue": "importing fails when calling python -OO\nThis was discovered by `xarray`'s `upstream-dev` CI ([environment](https://dev.azure.com/xarray/xarray/_build/results?buildId=2996&view=logs&j=2280efed-fda1-53bd-9213-1fa8ec9b4fa8&t=031ddd67-e55f-5fbd-2283-1ff4dfed6587)) a few days ago, but we were a bit slow in reporting so this also happens with the newly released `2.18.0`.\r\n\r\nThe problem is this:\r\n```\r\n$ python -OO -c 'import dask.array'\r\nTraceback (most recent call last):\r\n  File \"<string>\", line 1, in <module>\r\n  File \".../lib/python3.8/site-packages/dask/array/__init__.py\", line 26, in <module>\r\n    from .routines import (\r\n  File \".../lib/python3.8/site-packages/dask/array/routines.py\", line 18, in <module>\r\n    from .creation import arange, diag, empty, indices\r\n  File \".../lib/python3.8/site-packages/dask/array/creation.py\", line 26, in <module>\r\n    from .wrap import empty, ones, zeros, full\r\n  File \".../lib/python3.8/site-packages/dask/array/wrap.py\", line 173, in <module>\r\n    full.__name__ = _full.__name__\r\nAttributeError: 'functools.partial' object has no attribute '__name__'\r\n```\r\nwithout the optimization, the import obviously works.\r\n\r\nSee also pydata/xarray#4124\n", "before_files": [{"content": "from functools import partial\nfrom itertools import product\n\nimport numpy as np\n\nfrom tlz import curry\n\nfrom ..base import tokenize\nfrom ..utils import funcname\nfrom .core import Array, normalize_chunks\nfrom .utils import meta_from_array\n\n\ndef _parse_wrap_args(func, args, kwargs, shape):\n    if isinstance(shape, np.ndarray):\n        shape = shape.tolist()\n\n    if not isinstance(shape, (tuple, list)):\n        shape = (shape,)\n\n    name = kwargs.pop(\"name\", None)\n    chunks = kwargs.pop(\"chunks\", \"auto\")\n\n    dtype = kwargs.pop(\"dtype\", None)\n    if dtype is None:\n        dtype = func(shape, *args, **kwargs).dtype\n    dtype = np.dtype(dtype)\n\n    chunks = normalize_chunks(chunks, shape, dtype=dtype)\n\n    name = name or funcname(func) + \"-\" + tokenize(\n        func, shape, chunks, dtype, args, kwargs\n    )\n\n    return {\n        \"shape\": shape,\n        \"dtype\": dtype,\n        \"kwargs\": kwargs,\n        \"chunks\": chunks,\n        \"name\": name,\n    }\n\n\ndef wrap_func_shape_as_first_arg(func, *args, **kwargs):\n    \"\"\"\n    Transform np creation function into blocked version\n    \"\"\"\n    if \"shape\" not in kwargs:\n        shape, args = args[0], args[1:]\n    else:\n        shape = kwargs.pop(\"shape\")\n\n    if isinstance(shape, Array):\n        raise TypeError(\n            \"Dask array input not supported. \"\n            \"Please use tuple, list, or a 1D numpy array instead.\"\n        )\n\n    parsed = _parse_wrap_args(func, args, kwargs, shape)\n    shape = parsed[\"shape\"]\n    dtype = parsed[\"dtype\"]\n    chunks = parsed[\"chunks\"]\n    name = parsed[\"name\"]\n    kwargs = parsed[\"kwargs\"]\n\n    keys = product([name], *[range(len(bd)) for bd in chunks])\n    shapes = product(*chunks)\n    func = partial(func, dtype=dtype, **kwargs)\n    vals = ((func,) + (s,) + args for s in shapes)\n\n    dsk = dict(zip(keys, vals))\n    return Array(dsk, name, chunks, dtype=dtype)\n\n\ndef wrap_func_like(func, *args, **kwargs):\n    \"\"\"\n    Transform np creation function into blocked version\n    \"\"\"\n    x = args[0]\n    meta = meta_from_array(x)\n    shape = kwargs.get(\"shape\", x.shape)\n\n    parsed = _parse_wrap_args(func, args, kwargs, shape)\n    shape = parsed[\"shape\"]\n    dtype = parsed[\"dtype\"]\n    chunks = parsed[\"chunks\"]\n    name = parsed[\"name\"]\n    kwargs = parsed[\"kwargs\"]\n\n    keys = product([name], *[range(len(bd)) for bd in chunks])\n    shapes = product(*chunks)\n    shapes = list(shapes)\n    kw = [kwargs for _ in shapes]\n    for i, s in enumerate(list(shapes)):\n        kw[i][\"shape\"] = s\n    vals = ((partial(func, dtype=dtype, **k),) + args for (k, s) in zip(kw, shapes))\n\n    dsk = dict(zip(keys, vals))\n\n    return Array(dsk, name, chunks, meta=meta.astype(dtype))\n\n\ndef wrap_func_like_safe(func, func_like, *args, **kwargs):\n    \"\"\"\n    Safe implementation for wrap_func_like(), attempts to use func_like(),\n    if the shape keyword argument, falls back to func().\n    \"\"\"\n    try:\n        return func_like(*args, **kwargs)\n    except TypeError:\n        return func(*args, **kwargs)\n\n\n@curry\ndef wrap(wrap_func, func, **kwargs):\n    func_like = kwargs.pop(\"func_like\", None)\n    if func_like is None:\n        f = partial(wrap_func, func, **kwargs)\n    else:\n        f = partial(wrap_func, func_like, **kwargs)\n    template = \"\"\"\n    Blocked variant of %(name)s\n\n    Follows the signature of %(name)s exactly except that it also features\n    optional keyword arguments ``chunks: int, tuple, or dict`` and ``name: str``.\n\n    Original signature follows below.\n    \"\"\"\n    if func.__doc__ is not None:\n        f.__doc__ = template % {\"name\": func.__name__} + func.__doc__\n        f.__name__ = \"blocked_\" + func.__name__\n    return f\n\n\nw = wrap(wrap_func_shape_as_first_arg)\n\nones = w(np.ones, dtype=\"f8\")\nzeros = w(np.zeros, dtype=\"f8\")\nempty = w(np.empty, dtype=\"f8\")\n\n\nw_like = wrap(wrap_func_like_safe)\n\n\nempty_like = w_like(np.empty, func_like=np.empty_like)\n\n\n# full and full_like require special casing due to argument check on fill_value\n# Generate wrapped functions only once\n_full = w(np.full)\n_full_like = w_like(np.full, func_like=np.full_like)\n\n\ndef full(shape, fill_value, *args, **kwargs):\n    # np.isscalar has somewhat strange behavior:\n    # https://docs.scipy.org/doc/numpy/reference/generated/numpy.isscalar.html\n    if np.ndim(fill_value) != 0:\n        raise ValueError(\n            f\"fill_value must be scalar. Received {type(fill_value).__name__} instead.\"\n        )\n    return _full(shape=shape, fill_value=fill_value, *args, **kwargs)\n\n\ndef full_like(a, fill_value, *args, **kwargs):\n    if np.ndim(fill_value) != 0:\n        raise ValueError(\n            f\"fill_value must be scalar. Received {type(fill_value).__name__} instead.\"\n        )\n    return _full_like(a=a, fill_value=fill_value, *args, **kwargs,)\n\n\nfull.__doc__ = _full.__doc__\nfull.__name__ = _full.__name__\nfull_like.__doc__ = _full_like.__doc__\nfull_like.__name__ = _full_like.__name__\n", "path": "dask/array/wrap.py"}], "after_files": [{"content": "from functools import partial\nfrom itertools import product\n\nimport numpy as np\n\nfrom tlz import curry\n\nfrom ..base import tokenize\nfrom ..utils import funcname\nfrom .core import Array, normalize_chunks\nfrom .utils import meta_from_array\n\n\ndef _parse_wrap_args(func, args, kwargs, shape):\n    if isinstance(shape, np.ndarray):\n        shape = shape.tolist()\n\n    if not isinstance(shape, (tuple, list)):\n        shape = (shape,)\n\n    name = kwargs.pop(\"name\", None)\n    chunks = kwargs.pop(\"chunks\", \"auto\")\n\n    dtype = kwargs.pop(\"dtype\", None)\n    if dtype is None:\n        dtype = func(shape, *args, **kwargs).dtype\n    dtype = np.dtype(dtype)\n\n    chunks = normalize_chunks(chunks, shape, dtype=dtype)\n\n    name = name or funcname(func) + \"-\" + tokenize(\n        func, shape, chunks, dtype, args, kwargs\n    )\n\n    return {\n        \"shape\": shape,\n        \"dtype\": dtype,\n        \"kwargs\": kwargs,\n        \"chunks\": chunks,\n        \"name\": name,\n    }\n\n\ndef wrap_func_shape_as_first_arg(func, *args, **kwargs):\n    \"\"\"\n    Transform np creation function into blocked version\n    \"\"\"\n    if \"shape\" not in kwargs:\n        shape, args = args[0], args[1:]\n    else:\n        shape = kwargs.pop(\"shape\")\n\n    if isinstance(shape, Array):\n        raise TypeError(\n            \"Dask array input not supported. \"\n            \"Please use tuple, list, or a 1D numpy array instead.\"\n        )\n\n    parsed = _parse_wrap_args(func, args, kwargs, shape)\n    shape = parsed[\"shape\"]\n    dtype = parsed[\"dtype\"]\n    chunks = parsed[\"chunks\"]\n    name = parsed[\"name\"]\n    kwargs = parsed[\"kwargs\"]\n\n    keys = product([name], *[range(len(bd)) for bd in chunks])\n    shapes = product(*chunks)\n    func = partial(func, dtype=dtype, **kwargs)\n    vals = ((func,) + (s,) + args for s in shapes)\n\n    dsk = dict(zip(keys, vals))\n    return Array(dsk, name, chunks, dtype=dtype)\n\n\ndef wrap_func_like(func, *args, **kwargs):\n    \"\"\"\n    Transform np creation function into blocked version\n    \"\"\"\n    x = args[0]\n    meta = meta_from_array(x)\n    shape = kwargs.get(\"shape\", x.shape)\n\n    parsed = _parse_wrap_args(func, args, kwargs, shape)\n    shape = parsed[\"shape\"]\n    dtype = parsed[\"dtype\"]\n    chunks = parsed[\"chunks\"]\n    name = parsed[\"name\"]\n    kwargs = parsed[\"kwargs\"]\n\n    keys = product([name], *[range(len(bd)) for bd in chunks])\n    shapes = product(*chunks)\n    shapes = list(shapes)\n    kw = [kwargs for _ in shapes]\n    for i, s in enumerate(list(shapes)):\n        kw[i][\"shape\"] = s\n    vals = ((partial(func, dtype=dtype, **k),) + args for (k, s) in zip(kw, shapes))\n\n    dsk = dict(zip(keys, vals))\n\n    return Array(dsk, name, chunks, meta=meta.astype(dtype))\n\n\ndef wrap_func_like_safe(func, func_like, *args, **kwargs):\n    \"\"\"\n    Safe implementation for wrap_func_like(), attempts to use func_like(),\n    if the shape keyword argument, falls back to func().\n    \"\"\"\n    try:\n        return func_like(*args, **kwargs)\n    except TypeError:\n        return func(*args, **kwargs)\n\n\n@curry\ndef wrap(wrap_func, func, **kwargs):\n    func_like = kwargs.pop(\"func_like\", None)\n    if func_like is None:\n        f = partial(wrap_func, func, **kwargs)\n    else:\n        f = partial(wrap_func, func_like, **kwargs)\n    template = \"\"\"\n    Blocked variant of %(name)s\n\n    Follows the signature of %(name)s exactly except that it also features\n    optional keyword arguments ``chunks: int, tuple, or dict`` and ``name: str``.\n\n    Original signature follows below.\n    \"\"\"\n    if func.__doc__ is not None:\n        f.__doc__ = template % {\"name\": func.__name__} + func.__doc__\n        f.__name__ = \"blocked_\" + func.__name__\n    return f\n\n\nw = wrap(wrap_func_shape_as_first_arg)\n\nones = w(np.ones, dtype=\"f8\")\nzeros = w(np.zeros, dtype=\"f8\")\nempty = w(np.empty, dtype=\"f8\")\n\n\nw_like = wrap(wrap_func_like_safe)\n\n\nempty_like = w_like(np.empty, func_like=np.empty_like)\n\n\n# full and full_like require special casing due to argument check on fill_value\n# Generate wrapped functions only once\n_full = w(np.full)\n_full_like = w_like(np.full, func_like=np.full_like)\n\n\ndef full(shape, fill_value, *args, **kwargs):\n    # np.isscalar has somewhat strange behavior:\n    # https://docs.scipy.org/doc/numpy/reference/generated/numpy.isscalar.html\n    if np.ndim(fill_value) != 0:\n        raise ValueError(\n            f\"fill_value must be scalar. Received {type(fill_value).__name__} instead.\"\n        )\n    return _full(shape=shape, fill_value=fill_value, *args, **kwargs)\n\n\ndef full_like(a, fill_value, *args, **kwargs):\n    if np.ndim(fill_value) != 0:\n        raise ValueError(\n            f\"fill_value must be scalar. Received {type(fill_value).__name__} instead.\"\n        )\n    return _full_like(a=a, fill_value=fill_value, *args, **kwargs,)\n\n\nfull.__doc__ = _full.__doc__\nfull_like.__doc__ = _full_like.__doc__\n", "path": "dask/array/wrap.py"}]}