Repository: dask/dask

Issue:
Unbound local variable `index` referenced before assignment
<!-- Please include a self-contained copy-pastable example that generates the issue if possible.

Please be concise with code posted. See guidelines below on how to provide a good bug report:

- Craft Minimal Bug Reports http://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports
- Minimal Complete Verifiable Examples https://stackoverflow.com/help/mcve

Bug reports that follow these guidelines are easier to diagnose, and so are often handled much more quickly.
-->

**What happened**:

`UnboundLocalError: local variable 'index' referenced before assignment` originating from an unhandled case in https://github.com/dask/dask/blob/master/dask/dataframe/core.py#L2805-L2812. 

**What you expected to happen**:

A `RuntimeError`? Some other sort of exception. 

**Minimal Complete Verifiable Example**:

```python
import dask.dataframe as dd
import numpy as np

s = dd.from_array(np.arange(10))
np.repeat(s, 10)
```

**Anything else we need to know?**:

I don't expect `np.repeat(s, 10)` to actually work (I triggered this case debugging some broken code), but was surprised that it resulted in an `UnboundLocalError`. 

**Environment**:

- Dask version: 2.30.0
- Python version: 3.8.5
- Operating System: Ubuntu 18.04
- Install method (conda, pip, source): conda



Discussion:
Thanks for raising this! I can reproduce and see the issue. I think this is expected to work because of [NEP 18](https://numpy.org/neps/nep-0018-array-function-protocol.html). I am looking into it now.
I somehow missed that this is a series being passed in. I agree that that is not expected to work because the method still needs to be implemented on the dask side, which `repeat` isn't for dataframe/series. 

You might want to use dask.array:

```python
import dask.array as da
import numpy as np

a = da.from_array(np.arange(10))
np.repeat(a, 10)
```
Right - I fully agree that this isn't the "correct" way to do anything (I hit this accidentally). I was just surprised at the failure mode. 
Yep :+1: on the surprise, I am trying to figure out what the behavior should be.
@jrbourbeau I am wondering if you would be able to comment on what the behavior should be. I tried adding:

```python
if context is None:
    index = None
```

But the results in a pandas series being the output of `np.repeat(s)` which is definitely not expected. Poking around, I suspect that we need to do something before `__array_wrap__` is called, since in that method, `array` is already computed. 
related/same culprit (now [dask/dataframe/core.py#L4309-L4316](https://github.com/dask/dask/blob/dfd9a5cf901df6fb822d77f68945a93fb2966930/dask/dataframe/core.py#L4309-L4316)), and similar in that it is raised by an invalid use case. encountered on stackoverflow: https://stackoverflow.com/questions/72662467/np-transpose-keeps-on-returning-unbound-local-error

```python
import dask.dataframe as dd, pandas as pd, numpy as np
df = dd.from_pandas(pd.DataFrame({'A': np.arange(100, 200), 'B': np.random.random(size=100)}), npartitions=4)
np.transpose(df) # raises UnboundLocalsError
```

Resolving patch:
diff --git a/dask/dataframe/core.py b/dask/dataframe/core.py
--- a/dask/dataframe/core.py
+++ b/dask/dataframe/core.py
@@ -3377,6 +3377,16 @@ def __array_wrap__(self, array, context=None):
                 index = None
             else:
                 index = context[1][0].index
+        else:
+            try:
+                import inspect
+
+                method_name = f"`{inspect.stack()[3][3]}`"
+            except IndexError:
+                method_name = "This method"
+            raise NotImplementedError(
+                f"{method_name} is not implemented for `dask.dataframe.Series`."
+            )
 
         return pd.Series(array, index=index, name=self.name)
 
@@ -4312,6 +4322,17 @@ def __array_wrap__(self, array, context=None):
                 index = None
             else:
                 index = context[1][0].index
+        else:
+            try:
+                import inspect
+
+                method_name = f"`{inspect.stack()[3][3]}`"
+            except IndexError:
+                method_name = "This method"
+
+            raise NotImplementedError(
+                f"{method_name} is not implemented for `dask.dataframe.DataFrame`."
+            )
 
         return pd.DataFrame(array, index=index, columns=self.columns)
 


Test patch:
diff --git a/dask/dataframe/tests/test_ufunc.py b/dask/dataframe/tests/test_ufunc.py
--- a/dask/dataframe/tests/test_ufunc.py
+++ b/dask/dataframe/tests/test_ufunc.py
@@ -213,6 +213,28 @@ def test_ufunc_wrapped(ufunc):
     np.testing.assert_array_equal(dafunc(df), npfunc(df))
 
 
+def test_ufunc_wrapped_not_implemented():
+    s = pd.Series(
+        np.random.randint(1, 100, size=20), index=list("abcdefghijklmnopqrst")
+    )
+    ds = dd.from_pandas(s, 3)
+    with pytest.raises(NotImplementedError, match="`repeat` is not implemented"):
+        np.repeat(ds, 10)
+
+    df = pd.DataFrame(
+        {
+            "A": np.random.randint(1, 100, size=20),
+            "B": np.random.randint(1, 100, size=20),
+            "C": np.abs(np.random.randn(20)),
+        },
+        index=list("abcdefghijklmnopqrst"),
+    )
+    ddf = dd.from_pandas(df, 3)
+
+    with pytest.raises(NotImplementedError, match="`repeat` is not implemented"):
+        np.repeat(ddf, 10)
+
+
 _UFUNCS_2ARG = [
     "logaddexp",
     "logaddexp2",