Repository: scikit-hep/awkward

Issue:
ak.fill_none does not accept a Record as a fill value
This should fill with a single, scalar record:

```python
>>> import awkward as ak
>>> array = ak.Array([{"x": 1}, {"x": 2}, None, {"x": 3}])
>>> ak.fill_none(array, array[0])
```

but it raises

```
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/jpivarski/irishep/awkward-1.0/awkward/operations/structure.py", line 2012, in fill_none
    valuelayout = ak.operations.convert.to_layout(
  File "/home/jpivarski/irishep/awkward-1.0/awkward/operations/convert.py", line 1618, in to_layout
    return from_iter(array, highlevel=False)
  File "/home/jpivarski/irishep/awkward-1.0/awkward/operations/convert.py", line 691, in from_iter
    out.fromiter(x)
  File "/home/jpivarski/irishep/awkward-1.0/awkward/highlevel.py", line 1765, in __getitem__
    return ak._util.wrap(self._layout[where], self._behavior)
ValueError: scalar Record can only be sliced by field name (string); try "0"

(https://github.com/scikit-hep/awkward-1.0/blob/main/src/libawkward/array/Record.cpp#L198)
```

because this `layout` is presumed to be a `Content` when it's really a `Record`. In `to_layout`, there should be a `allow_records=False` or special handling of the `ak.layout.Record` type further down in the function.


Discussion:

Resolving patch:
diff --git a/src/awkward/operations/structure.py b/src/awkward/operations/structure.py
--- a/src/awkward/operations/structure.py
+++ b/src/awkward/operations/structure.py
@@ -2011,9 +2011,12 @@ def fill_none(array, value, highlevel=True):
         )
 
     else:
-        if isinstance(value, Iterable) and not (
-            isinstance(value, (str, bytes))
-            or (ak._util.py27 and isinstance(value, ak._util.unicode))
+        if (
+            isinstance(value, Iterable) and not (
+                isinstance(value, (str, bytes))
+                or (ak._util.py27 and isinstance(value, ak._util.unicode))
+            )
+            or isinstance(value, (ak.highlevel.Record, ak.layout.Record))
         ):
             valuelayout = ak.operations.convert.to_layout(
                 value, allow_record=True, allow_other=False
@@ -2025,9 +2028,10 @@ def fill_none(array, value, highlevel=True):
                 valuelayout = ak.layout.ListOffsetArray64(offsets, valuelayout)
             else:
                 valuelayout = ak.layout.RegularArray(valuelayout, len(valuelayout), 1)
+
         else:
             valuelayout = ak.operations.convert.to_layout(
-                [value], allow_record=True, allow_other=False
+                [value], allow_record=False, allow_other=False
             )
 
         out = arraylayout.fillna(valuelayout)


Test patch:
diff --git a/tests/test_0634-fill_none-with-record.py b/tests/test_0634-fill_none-with-record.py
new file mode 100644
--- /dev/null
+++ b/tests/test_0634-fill_none-with-record.py
@@ -0,0 +1,17 @@
+# BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE
+
+from __future__ import absolute_import
+
+import pytest  # noqa: F401
+import numpy as np  # noqa: F401
+import awkward as ak  # noqa: F401
+
+
+def test():
+    array = ak.Array([{"x": 1}, {"x": 2}, None, {"x": 3}])
+    assert ak.fill_none(array, array[0]).tolist() == [
+        {"x": 1},
+        {"x": 2},
+        {"x": 1},
+        {"x": 3},
+    ]