Skip to content

Commit 603e5ae

Browse files
committed
BUG: hack to enable zero-length data to be stored in HDFStore, close #1707
1 parent 65dde70 commit 603e5ae

File tree

3 files changed

+39
-16
lines changed

3 files changed

+39
-16
lines changed

RELEASE.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ pandas 0.8.2
6565
caused by SeriesBinGrouper (#1648, #1688)
6666
- When grouping by level, exclude unobserved levels (#1697)
6767
- Don't lose tzinfo in DatetimeIndex when shifting by different offset (#1683)
68+
- Hack to support storing data with a zero-length axis in HDFStore (#1707)
6869

6970
pandas 0.8.1
7071
============

pandas/io/pytables.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -556,10 +556,6 @@ def _read_wide_table(self, group, where=None):
556556

557557
def _write_index(self, group, key, index):
558558
if isinstance(index, MultiIndex):
559-
if len(index) == 0:
560-
raise ValueError('Can not write empty structure, '
561-
'axis length was 0')
562-
563559
setattr(group._v_attrs, '%s_variety' % key, 'multi')
564560
self._write_multi_index(group, key, index)
565561
elif isinstance(index, BlockIndex):
@@ -569,10 +565,6 @@ def _write_index(self, group, key, index):
569565
setattr(group._v_attrs, '%s_variety' % key, 'sparseint')
570566
self._write_sparse_intindex(group, key, index)
571567
else:
572-
if len(index) == 0:
573-
raise ValueError('Can not write empty structure, '
574-
'axis length was 0')
575-
576568
setattr(group._v_attrs, '%s_variety' % key, 'regular')
577569
converted, kind, _ = _convert_index(index)
578570
self._write_array(group, key, converted)
@@ -658,7 +650,7 @@ def _read_multi_index(self, group, key):
658650
names.append(name)
659651

660652
label_key = '%s_label%d' % (key, i)
661-
lab = getattr(group, label_key)[:]
653+
lab = _read_array(group, label_key)
662654
labels.append(lab)
663655

664656
return MultiIndex(levels=levels, labels=labels, names=names)
@@ -719,7 +711,14 @@ def _write_array(self, group, key, value):
719711
self.handle.createArray(group, key, value.view('i8'))
720712
getattr(group, key)._v_attrs.value_type = 'datetime64'
721713
else:
722-
self.handle.createArray(group, key, value)
714+
if any(x == 0 for x in value.shape):
715+
# ugly hack for length 0 axes
716+
arr = np.empty((1,) * value.ndim)
717+
self.handle.createArray(group, key, arr)
718+
getattr(group, key)._v_attrs.value_type = str(value.dtype)
719+
getattr(group, key)._v_attrs.shape = value.shape
720+
else:
721+
self.handle.createArray(group, key, value)
723722

724723
def _write_table(self, group, items=None, index=None, columns=None,
725724
values=None, append=False, compression=None):
@@ -805,7 +804,11 @@ def _read_group(self, group, where=None):
805804

806805
def _read_series(self, group, where=None):
807806
index = self._read_index(group, 'index')
808-
values = _read_array(group, 'values')
807+
if len(index) > 0:
808+
values = _read_array(group, 'values')
809+
else:
810+
values = []
811+
809812
name = getattr(group._v_attrs, 'name', None)
810813
return Series(values, index=index, name=name)
811814

@@ -959,7 +962,15 @@ def _read_array(group, key):
959962
if isinstance(node, tables.VLArray):
960963
return data[0]
961964
else:
962-
dtype = getattr(node._v_attrs, 'value_type', None)
965+
attrs = node._v_attrs
966+
967+
dtype = getattr(attrs, 'value_type', None)
968+
shape = getattr(attrs, 'shape', None)
969+
970+
if shape is not None:
971+
# length 0 axis
972+
return np.empty(shape, dtype=dtype)
973+
963974
if dtype == 'datetime64':
964975
return np.array(data, dtype='M8[ns]')
965976
return data

pandas/io/tests/test_pytables.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -338,8 +338,20 @@ def test_frame(self):
338338
self.assert_(recons._data.is_consolidated())
339339

340340
# empty
341-
self.assertRaises(ValueError, self._check_roundtrip, df[:0],
342-
tm.assert_frame_equal)
341+
self._check_roundtrip(df[:0], tm.assert_frame_equal)
342+
343+
def test_empty_series_frame(self):
344+
s0 = Series()
345+
s1 = Series(name='myseries')
346+
df0 = DataFrame()
347+
df1 = DataFrame(index=['a', 'b', 'c'])
348+
df2 = DataFrame(columns=['d', 'e', 'f'])
349+
350+
self._check_roundtrip(s0, tm.assert_series_equal)
351+
self._check_roundtrip(s1, tm.assert_series_equal)
352+
self._check_roundtrip(df0, tm.assert_frame_equal)
353+
self._check_roundtrip(df1, tm.assert_frame_equal)
354+
self._check_roundtrip(df2, tm.assert_frame_equal)
343355

344356
def test_can_serialize_dates(self):
345357
rng = [x.date() for x in bdate_range('1/1/2000', '1/30/2000')]
@@ -477,8 +489,7 @@ def _check(left, right):
477489
self._check_roundtrip(wp.to_frame(), _check)
478490

479491
# empty
480-
self.assertRaises(ValueError, self._check_roundtrip, wp.to_frame()[:0],
481-
_check)
492+
# self._check_roundtrip(wp.to_frame()[:0], _check)
482493

483494
def test_longpanel(self):
484495
pass

0 commit comments

Comments
 (0)