Conversation
- Handle 0-dimensional numpy arrays in get_type method - Handle 0-dimensional arrays in __list_fill__ method - Convert scalar compound data to shape=(1,) for backward compatibility - Wrap scalar compound data when writing to zarr dataset Co-authored-by: rly <310197+rly@users.noreply.github.com>
- Test writing scalar compound dtype without dtype spec - Test writing scalar compound dtype with dtype spec (like NWB) - Test reading scalar compound dtype Co-authored-by: rly <310197+rly@users.noreply.github.com>
|
@copilot For writing a scalar dataset with compound dtype, let's try to be as similar as possible to HDF5IO's approach in https://github.com/hdmf-dev/hdmf/blob/dev/src/hdmf/backends/hdf5/h5tools.py. Specifically, elif isinstance(options['dtype'], list):
# do some stuff to figure out what data is a reference
refs = list()
for i, dts in enumerate(options['dtype']):
if self.__is_ref(dts):
refs.append(i)
# If one or more of the parts of the compound data type are references then we need to deal with those
if len(refs) > 0:
try:
_dtype = self.__resolve_dtype__(options['dtype'], data)
except Exception as exc:
msg = 'cannot add %s to %s - could not determine type' % (name, parent.name)
raise Exception(msg) from exc
dset = parent.require_dataset(name, shape=(len(data),), dtype=_dtype, **options['io_settings'])
self.__set_written(builder)
self.logger.debug("Queueing reference resolution and set attribute on dataset '%s' containing "
"object references. attributes: %s"
% (name, list(attributes.keys())))
@self.__queue_ref
def _filler():
self.logger.debug("Resolving object references and setting attribute on dataset '%s' "
"containing attributes: %s"
% (name, list(attributes.keys())))
ret = list()
for item in data:
new_item = list(item)
for i in refs:
new_item[i] = self.__get_ref(item[i])
ret.append(tuple(new_item))
dset = parent[name]
dset[:] = ret
self.set_attributes(dset, attributes)
return
# If the compound data type contains only regular data (i.e., no references) then we can write it as usual
elif len(np.shape(data)) == 0:
dset = self.__scalar_fill__(parent, name, data, options)
else:
dset = self.__list_fill__(parent, name, data, options)where the branch to use |
- Add len(np.shape(data)) == 0 check in compound dtype handling - Add len(np.shape(data)) == 0 check before hasattr(__len__) check - Update __scalar_fill__ to handle scalar compound dtypes - Update get_type to handle 0-dimensional arrays Co-authored-by: rly <310197+rly@users.noreply.github.com>
Updated the implementation to match HDF5IO's approach. Added |
|
Merge #310 first, then update this PR |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## dev #307 +/- ##
==========================================
- Coverage 85.78% 85.57% -0.21%
==========================================
Files 5 5
Lines 1238 1248 +10
Branches 234 239 +5
==========================================
+ Hits 1062 1068 +6
- Misses 120 122 +2
- Partials 56 58 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Motivation
Writing scalar (0-dimensional) numpy arrays with compound dtypes fails with
IndexError: too many indices for array: array is 0-dimensional, but 1 were indexed. This occurs in PyNWB when writingElectrodeGroup.positionwhich uses a compound dtype(x, y, z).The fix follows HDF5IO's approach for handling scalar compound dtypes by using
len(np.shape(data)) == 0to detect scalars and routing them to__scalar_fill__instead of__list_fill__.How to test the behavior?
Changes:
elif len(np.shape(data)) == 0:check to route scalar compound dtypes to__scalar_fill__(matches HDF5IO approach)elif len(np.shape(data)) == 0:check beforehasattr(data, "__len__")to catch scalars without explicit dtype specification__scalar_fill__(): Update to properly wrap scalar compound data withnp.array([data], dtype=dtype)for writing to shape=(1,) datasetsget_type(): Detect 0-dimensional arrays viadata.ndim == 0and returndata.dtypedirectly to avoid TypeErrortest_write_scalar_compound,test_write_scalar_compound_with_dtype_spec, andtest_read_scalar_compoundChecklist
CHANGELOG.mdwith your changes?Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.