Repository: scikit-hep/uproot5

Issue:
Empty array of std::vector<std::string> raises AttributeError 
```python
>>> import uproot4
>>> uproot4.__version__
0.1.2
```

I stumbled upon a tiny bug. The `"E/Evt/AAObject/usr_names"` branch is a `std::vector<std::string>` and interpreted correctly in files where there is data, however if it's empty, it raises an `AttributeError` after hanging for a few seconds. It indicates that it's an empty array in the error message but then continues to call `_awkward_json_to_array` with a `form` data which is missing the `content`. Here is a sample file and the code to reproduce:

[sample.root.zip](https://github.com/scikit-hep/uproot4/files/5596382/sample.root.zip)

```python
import uproot4
f = uproot4.open("sample.root")
f["E/Evt/AAObject/usr_names"].show()
```
gives

```python
name                 | typename                 | interpretation                
---------------------+--------------------------+-------------------------------
usr_names            | std::vector<std::string> | AsObjects(AsVector(True, AsStr
```

The `"usr"` subbranch works fine with empty data and gives a jagged array of empty arrays:

```python
>>> f["E/Evt/AAObject/usr"].show()
name                 | typename                 | interpretation                
---------------------+--------------------------+-------------------------------
usr                  | std::vector<double>      | AsJagged(AsDtype('>f8'), heade
>>> f["E/Evt/AAObject/usr"].array()
<Array [[], [], [], [], ... [], [], [], []] type='307 * var * float64'>
```

Here is the full error when running `f["E/Evt/AAObject/usr_names"]`:

```
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-20-2ded08152b25> in <module>
----> 1 f["E/Evt/AAObject/usr_names"].array()

~/Dev/km3io/venv/lib/python3.8/site-packages/uproot4/behaviors/TBranch.py in array(self, interpretation, entry_start, entry_stop, decompression_executor, interpretation_executor, array_cache, library)
   2070                         ranges_or_baskets.append((branch, basket_num, range_or_basket))
   2071 
-> 2072         _ranges_or_baskets_to_arrays(
   2073             self,
   2074             ranges_or_baskets,

~/Dev/km3io/venv/lib/python3.8/site-packages/uproot4/behaviors/TBranch.py in _ranges_or_baskets_to_arrays(hasbranches, ranges_or_baskets, branchid_interpretation, entry_start, entry_stop, decompression_executor, interpretation_executor, library, arrays)
   3441 
   3442         elif isinstance(obj, tuple) and len(obj) == 3:
-> 3443             uproot4.source.futures.delayed_raise(*obj)
   3444 
   3445         else:

~/Dev/km3io/venv/lib/python3.8/site-packages/uproot4/source/futures.py in delayed_raise(exception_class, exception_value, traceback)
     44         exec("raise exception_class, exception_value, traceback")
     45     else:
---> 46         raise exception_value.with_traceback(traceback)
     47 
     48 

~/Dev/km3io/venv/lib/python3.8/site-packages/uproot4/behaviors/TBranch.py in basket_to_array(basket)
   3412 
   3413             if len(basket_arrays) == branchid_num_baskets[branch.cache_key]:
-> 3414                 arrays[branch.cache_key] = interpretation.final_array(
   3415                     basket_arrays,
   3416                     entry_start,

~/Dev/km3io/venv/lib/python3.8/site-packages/uproot4/interpretation/objects.py in final_array(self, basket_arrays, entry_start, entry_stop, entry_offsets, library, branch)
    228         )
    229 
--> 230         output = library.finalize(output, branch, self, entry_start, entry_stop)
    231 
    232         self.hook_after_final_array(

~/Dev/km3io/venv/lib/python3.8/site-packages/uproot4/interpretation/library.py in finalize(self, array, branch, interpretation, entry_start, entry_stop)
    506                 (_object_to_awkward_json(form, x) for x in array), highlevel=False
    507             )
--> 508             return awkward1.Array(_awkward_json_to_array(awkward1, form, unlabeled))
    509 
    510         elif array.dtype.names is not None:

~/Dev/km3io/venv/lib/python3.8/site-packages/uproot4/interpretation/library.py in _awkward_json_to_array(awkward1, form, array)
    370 
    371         else:
--> 372             content = _awkward_json_to_array(awkward1, form["content"], array.content)
    373             return type(array)(array.offsets, content, parameters=_awkward_p(form))
    374 

~/Dev/km3io/venv/lib/python3.8/site-packages/uproot4/interpretation/library.py in _awkward_json_to_array(awkward1, form, array)
    353     elif form["class"][:15] == "ListOffsetArray":
    354         if form["parameters"].get("__array__") == "string":
--> 355             content = _awkward_json_to_array(awkward1, form["content"], array.content)
    356             return type(array)(array.offsets, content, parameters=_awkward_p(form))
    357 

AttributeError: 'awkward1._ext.EmptyArray' object has no attribute 'content'
```




Discussion:

Resolving patch:
diff --git a/uproot4/interpretation/library.py b/uproot4/interpretation/library.py
--- a/uproot4/interpretation/library.py
+++ b/uproot4/interpretation/library.py
@@ -356,8 +356,21 @@ def _awkward_json_to_array(awkward1, form, array):
 
     elif form["class"][:15] == "ListOffsetArray":
         if form["parameters"].get("__array__") == "string":
-            content = _awkward_json_to_array(awkward1, form["content"], array.content)
-            return type(array)(array.offsets, content, parameters=_awkward_p(form))
+            if isinstance(array, awkward1.layout.EmptyArray):
+                content = awkward1.layout.NumpyArray(
+                    numpy.empty(0, dtype=numpy.uint8),
+                    parameters=_awkward_p(form["content"]),
+                )
+                return awkward1.layout.ListOffsetArray64(
+                    awkward1.layout.Index64(numpy.array([0], dtype=numpy.uint8)),
+                    content,
+                    parameters=_awkward_p(form),
+                )
+            else:
+                content = _awkward_json_to_array(
+                    awkward1, form["content"], array.content
+                )
+                return type(array)(array.offsets, content, parameters=_awkward_p(form))
 
         elif form["parameters"].get("__array__") == "sorted_map":
             key_form = form["content"]["contents"][0]


Test patch: