Repository: scikit-hep/awkward

Issue:
Doubly jagged workaround broken in awkward 1.4.0rc2
There was a quick fix (made for KM3NeT data 😄) for doubly jagged arrays which were discussed here https://github.com/scikit-hep/uproot4/issues/90 and the it uses the `akward._io` submodule which is not accessible anymore directly (`AttributeError`) in `1.4.0rc2`.

See here:

https://github.com/scikit-hep/awkward-1.0/blob/main/src/awkward/_connect/_uproot.py#L35

I am not sure what the desired fix is, to import `_io` in `_connect/_uproot.py` or if this fix is now covered by further developments, so I thought I ask first before I do a PR 😉 

Here is the full MWE (needs `pip install km3net-testdata`, I am not sure if this test

```python
>>> import uproot

>>> uproot.__version__
'4.0.7'

>>> import awkward as ak

>>> ak.__version__
'1.4.0rc2'

>>> from km3net_testdata import data_path

>>> f = uproot.open(data_path("offline/mcv5.11r2.gsg_muonCChigherE-CC_50-5000GeV.km3_AAv1.jterbr00004695.jchain.aanet.498.root"))

>>> f["E/Evt/trks/trks.rec_stages"].array()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-18-80472509fad7> in <module>
----> 1 f["E/Evt/trks/trks.rec_stages"].array()

~/Dev/km3io/venv/lib/python3.9/site-packages/uproot/behaviors/TBranch.py in array(self, interpretation, entry_start, entry_stop, decompression_executor, interpretation_executor, array_cache, library)
   2076                         ranges_or_baskets.append((branch, basket_num, range_or_basket))
   2077
-> 2078         _ranges_or_baskets_to_arrays(
   2079             self,
   2080             ranges_or_baskets,

~/Dev/km3io/venv/lib/python3.9/site-packages/uproot/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, update_ranges_or_baskets)
   3476
   3477         elif isinstance(obj, tuple) and len(obj) == 3:
-> 3478             uproot.source.futures.delayed_raise(*obj)
   3479
   3480         else:

~/Dev/km3io/venv/lib/python3.9/site-packages/uproot/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.9/site-packages/uproot/behaviors/TBranch.py in basket_to_array(basket)
   3420             basket_arrays = branchid_arrays[branch.cache_key]
   3421
-> 3422             basket_arrays[basket.basket_num] = interpretation.basket_array(
   3423                 basket.data,
   3424                 basket.byte_offsets,

~/Dev/km3io/venv/lib/python3.9/site-packages/uproot/interpretation/objects.py in basket_array(self, data, byte_offsets, basket, branch, context, cursor_offset, library)
    151                     "cursor_offset": cursor_offset,
    152                 }
--> 153                 output = awkward._connect._uproot.basket_array(
    154                     form, data, byte_offsets, extra
    155                 )

~/Dev/km3io/venv/lib/python3.9/site-packages/awkward/_connect/_uproot.py in basket_array(form, data, byte_offsets, extra)
     36     # FIXME: uproot_issue_90 is just a placeholder, to show how it would be done
     37
---> 38     return ak._io.uproot_issue_90(
     39         form,
     40         ak.layout.NumpyArray(data),

AttributeError: module 'awkward' has no attribute '_io'
```





Discussion:
Tell me if this work-around works: do

```python
import awkward._io
```

before `f["E/Evt/trks/trks.rec_stages"].array()` in your example. If so, it's just that the module hasn't been explicitly imported. I guess the right place to do that (least potential for error) is in awkward/_connect/_uproot.py, so I'll do that before 1.4.0 goes out. I don't know what might have _changed_ here to make it work before and not now.

Also, this alternate code path isn't permanent. It was a first experiment that led to the development of AwkwardForth, and now AwkwardForth needs to be integrated into Uproot. Once that's done, this experimental back-door will be removed. From your perspective, nothing should change, including performance; I'm just giving you a heads-up.

Resolving patch:
diff --git a/src/awkward/_connect/_uproot.py b/src/awkward/_connect/_uproot.py
--- a/src/awkward/_connect/_uproot.py
+++ b/src/awkward/_connect/_uproot.py
@@ -33,9 +33,11 @@ def can_optimize(interpretation, form):
 
 
 def basket_array(form, data, byte_offsets, extra):
+    import awkward._io
+
     # FIXME: uproot_issue_90 is just a placeholder, to show how it would be done
 
-    return ak._io.uproot_issue_90(
+    return awkward._io.uproot_issue_90(
         form,
         ak.layout.NumpyArray(data),
         ak.layout.Index32(byte_offsets),


Test patch: