Skip to content

Commit 85e7db7

Browse files
committed
BUG/CLN: Exception in HDFStore are now ValueError or TypeError
A table will now raise if min_itemsize contains fields which are not queryables
1 parent 4b65859 commit 85e7db7

File tree

4 files changed

+111
-74
lines changed

4 files changed

+111
-74
lines changed

RELEASE.rst

+5-3
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,11 @@ pandas 0.11.0
167167
(so not using numexpr filtering, but isin filtering)
168168
- Internally, change all variables to be private-like (now have leading
169169
underscore)
170-
- fixes for query parsing to correctly interpret boolean and != (GH2849_, GH2973_)
171-
- fixes for pathological case on SparseSeries with 0-len array and compression (GH2931_)
172-
- fixes bug with writing rows if part of a block was all-nan (GH3012_)
170+
- Fixes for query parsing to correctly interpret boolean and != (GH2849_, GH2973_)
171+
- Fixes for pathological case on SparseSeries with 0-len array and compression (GH2931_)
172+
- Fixes bug with writing rows if part of a block was all-nan (GH3012_)
173+
- Exceptions are now ValueError or TypeError as needed
174+
- A table will now raise if min_itemsize contains fields which are not queryables
173175

174176
- Bug showing up in applymap where some object type columns are converted (GH2909_)
175177
had an incorrect default in convert_objects

pandas/io/pytables.py

+56-36
Original file line numberDiff line numberDiff line change
@@ -458,9 +458,9 @@ def select_as_multiple(self, keys, where=None, selector=None, columns=None, star
458458
nrows = tbls[0].nrows
459459
for t in tbls:
460460
if t.nrows != nrows:
461-
raise Exception("all tables must have exactly the same nrows!")
461+
raise ValueError("all tables must have exactly the same nrows!")
462462
if not t.is_table:
463-
raise Exception("object [%s] is not a table, and cannot be used in all select as multiple" % t.pathname)
463+
raise TypeError("object [%s] is not a table, and cannot be used in all select as multiple" % t.pathname)
464464

465465
# select coordinates from the selector table
466466
c = self.select_as_coordinates(selector, where, start=start, stop=stop)
@@ -526,7 +526,7 @@ def remove(self, key, where=None, start=None, stop=None):
526526
except:
527527

528528
if where is not None:
529-
raise Exception("trying to remove a node with a non-None where clause!")
529+
raise ValueError("trying to remove a node with a non-None where clause!")
530530

531531
# we are actually trying to remove a node (with children)
532532
s = self.get_node(key)
@@ -544,7 +544,7 @@ def remove(self, key, where=None, start=None, stop=None):
544544
# delete from the table
545545
else:
546546
if not s.is_table:
547-
raise Exception('can only remove with where on objects written as tables')
547+
raise ValueError('can only remove with where on objects written as tables')
548548
return s.delete(where = where, start=start, stop=stop)
549549

550550
def append(self, key, value, columns=None, **kwargs):
@@ -597,10 +597,10 @@ def append_to_multiple(self, d, value, selector, data_columns=None, axes=None, *
597597
raise Exception("axes is currently not accepted as a paremter to append_to_multiple; you can create the tables indepdently instead")
598598

599599
if not isinstance(d, dict):
600-
raise Exception("append_to_multiple must have a dictionary specified as the way to split the value")
600+
raise ValueError("append_to_multiple must have a dictionary specified as the way to split the value")
601601

602602
if selector not in d:
603-
raise Exception("append_to_multiple requires a selector that is in passed dict")
603+
raise ValueError("append_to_multiple requires a selector that is in passed dict")
604604

605605
# figure out the splitting axis (the non_index_axis)
606606
axis = list(set(range(value.ndim)) - set(_AXES_MAP[type(value)]))[0]
@@ -611,7 +611,7 @@ def append_to_multiple(self, d, value, selector, data_columns=None, axes=None, *
611611
for k, v in d.items():
612612
if v is None:
613613
if remain_key is not None:
614-
raise Exception("append_to_multiple can only have one value in d that is None")
614+
raise ValueError("append_to_multiple can only have one value in d that is None")
615615
remain_key = k
616616
else:
617617
remain_values.extend(v)
@@ -655,7 +655,7 @@ def create_table_index(self, key, **kwargs):
655655
if s is None: return
656656

657657
if not s.is_table:
658-
raise Exception("cannot create table index on a non-table")
658+
raise TypeError("cannot create table index on a non-table")
659659
s.create_index(**kwargs)
660660

661661
def groups(self):
@@ -727,8 +727,8 @@ def _create_storer(self, group, value = None, table = False, append = False, **k
727727
""" return a suitable Storer class to operate """
728728

729729
def error(t):
730-
raise NotImplementedError("cannot properly create the storer for: [%s] [group->%s,value->%s,table->%s,append->%s,kwargs->%s]" %
731-
(t,group,type(value),table,append,kwargs))
730+
raise TypeError("cannot properly create the storer for: [%s] [group->%s,value->%s,table->%s,append->%s,kwargs->%s]" %
731+
(t,group,type(value),table,append,kwargs))
732732

733733
pt = getattr(group._v_attrs,'pandas_type',None)
734734
tt = getattr(group._v_attrs,'table_type',None)
@@ -742,7 +742,7 @@ def error(t):
742742
pt = 'frame_table'
743743
tt = 'generic_table'
744744
else:
745-
raise Exception("cannot create a storer if the object is not existing nor a value are passed")
745+
raise TypeError("cannot create a storer if the object is not existing nor a value are passed")
746746
else:
747747

748748
try:
@@ -1044,8 +1044,10 @@ def validate_col(self, itemsize=None):
10441044
if itemsize is None:
10451045
itemsize = self.itemsize
10461046
if c.itemsize < itemsize:
1047-
raise Exception("[%s] column has a min_itemsize of [%s] but itemsize [%s] is required!"
1048-
% (self.cname, itemsize, c.itemsize))
1047+
raise ValueError("Trying to store a string with len [%s] in [%s] column but\n"
1048+
"this column has a limit of [%s]!\n"
1049+
"Consider using min_itemsize to preset the sizes on these columns"
1050+
% (itemsize,self.cname, c.itemsize))
10491051
return c.itemsize
10501052

10511053
return None
@@ -1176,11 +1178,11 @@ def set_atom(self, block, existing_col, min_itemsize, nan_rep, **kwargs):
11761178
if inferred_type == 'datetime64':
11771179
self.set_atom_datetime64(block)
11781180
elif inferred_type == 'date':
1179-
raise NotImplementedError(
1180-
"date is not implemented as a table column")
1181+
raise TypeError(
1182+
"[date] is not implemented as a table column")
11811183
elif inferred_type == 'unicode':
1182-
raise NotImplementedError(
1183-
"unicode is not implemented as a table column")
1184+
raise TypeError(
1185+
"[unicode] is not implemented as a table column")
11841186

11851187
# this is basically a catchall; if say a datetime64 has nans then will
11861188
# end up here ###
@@ -1209,9 +1211,9 @@ def set_atom_string(self, block, existing_col, min_itemsize, nan_rep):
12091211
col = block.get(item)
12101212
inferred_type = lib.infer_dtype(col.ravel())
12111213
if inferred_type != 'string':
1212-
raise NotImplementedError("cannot serialize the column [%s] because "
1213-
"its data contents are [%s] object dtype" %
1214-
(item,inferred_type))
1214+
raise TypeError("Cannot serialize the column [%s] because\n"
1215+
"its data contents are [%s] object dtype" %
1216+
(item,inferred_type))
12151217

12161218

12171219
# itemsize is the maximum length of a string (along any dimension)
@@ -1268,13 +1270,13 @@ def validate_attr(self, append):
12681270
existing_fields = getattr(self.attrs, self.kind_attr, None)
12691271
if (existing_fields is not None and
12701272
existing_fields != list(self.values)):
1271-
raise Exception("appended items do not match existing items"
1273+
raise ValueError("appended items do not match existing items"
12721274
" in table!")
12731275

12741276
existing_dtype = getattr(self.attrs, self.dtype_attr, None)
12751277
if (existing_dtype is not None and
12761278
existing_dtype != self.dtype):
1277-
raise Exception("appended items dtype do not match existing items dtype"
1279+
raise ValueError("appended items dtype do not match existing items dtype"
12781280
" in table!")
12791281

12801282
def convert(self, values, nan_rep):
@@ -1497,7 +1499,7 @@ def delete(self, where = None, **kwargs):
14971499
self._handle.removeNode(self.group, recursive=True)
14981500
return None
14991501

1500-
raise NotImplementedError("cannot delete on an abstract storer")
1502+
raise TypeError("cannot delete on an abstract storer")
15011503

15021504
class GenericStorer(Storer):
15031505
""" a generified storer version """
@@ -2045,7 +2047,7 @@ def validate(self, other):
20452047

20462048
for c in ['index_axes','non_index_axes','values_axes']:
20472049
if getattr(self,c,None) != getattr(other,c,None):
2048-
raise Exception("invalid combinate of [%s] on appending data [%s] vs current table [%s]" % (c,getattr(self,c,None),getattr(other,c,None)))
2050+
raise ValueError("invalid combinate of [%s] on appending data [%s] vs current table [%s]" % (c,getattr(self,c,None),getattr(other,c,None)))
20492051

20502052
@property
20512053
def nrows_expected(self):
@@ -2132,6 +2134,21 @@ def validate_version(self, where = None):
21322134
ws = incompatibility_doc % '.'.join([ str(x) for x in self.version ])
21332135
warnings.warn(ws, IncompatibilityWarning)
21342136

2137+
def validate_min_itemsize(self, min_itemsize):
2138+
""" validate the min_itemisze doesn't contain items that are not in the axes
2139+
this needs data_columns to be defined """
2140+
if min_itemsize is None: return
2141+
if not isinstance(min_itemsize, dict): return
2142+
2143+
q = self.queryables()
2144+
for k, v in min_itemsize.items():
2145+
2146+
# ok, apply generally
2147+
if k == 'values':
2148+
continue
2149+
if k not in q:
2150+
raise ValueError("min_itemsize has [%s] which is not an axis or data_column" % k)
2151+
21352152
@property
21362153
def indexables(self):
21372154
""" create/cache the indexables if they don't exist """
@@ -2262,8 +2279,8 @@ def create_axes(self, axes, obj, validate=True, nan_rep=None, data_columns=None,
22622279
try:
22632280
axes = _AXES_MAP[type(obj)]
22642281
except:
2265-
raise NotImplementedError("cannot properly create the storer for: [group->%s,value->%s]" %
2266-
(self.group._v_name,type(obj)))
2282+
raise TypeError("cannot properly create the storer for: [group->%s,value->%s]" %
2283+
(self.group._v_name,type(obj)))
22672284

22682285
# map axes to numbers
22692286
axes = [obj._get_axis_number(a) for a in axes]
@@ -2280,7 +2297,7 @@ def create_axes(self, axes, obj, validate=True, nan_rep=None, data_columns=None,
22802297

22812298
# currently support on ndim-1 axes
22822299
if len(axes) != self.ndim - 1:
2283-
raise Exception("currently only support ndim-1 indexers in an AppendableTable")
2300+
raise ValueError("currently only support ndim-1 indexers in an AppendableTable")
22842301

22852302
# create according to the new data
22862303
self.non_index_axes = []
@@ -2370,7 +2387,7 @@ def create_axes(self, axes, obj, validate=True, nan_rep=None, data_columns=None,
23702387
try:
23712388
existing_col = existing_table.values_axes[i]
23722389
except:
2373-
raise Exception("Incompatible appended table [%s] with existing table [%s]" %
2390+
raise ValueError("Incompatible appended table [%s] with existing table [%s]" %
23742391
(blocks,existing_table.values_axes))
23752392
else:
23762393
existing_col = None
@@ -2386,12 +2403,15 @@ def create_axes(self, axes, obj, validate=True, nan_rep=None, data_columns=None,
23862403
col.set_pos(j)
23872404

23882405
self.values_axes.append(col)
2389-
except (NotImplementedError):
2390-
raise
2406+
except (NotImplementedError, ValueError, TypeError), e:
2407+
raise e
23912408
except (Exception), detail:
23922409
raise Exception("cannot find the correct atom type -> [dtype->%s,items->%s] %s" % (b.dtype.name, b.items, str(detail)))
23932410
j += 1
23942411

2412+
# validate our min_itemsize
2413+
self.validate_min_itemsize(min_itemsize)
2414+
23952415
# validate the axes if we have an existing table
23962416
if validate:
23972417
self.validate(existing_table)
@@ -2433,7 +2453,7 @@ def process_filter(field, filt):
24332453
takers = op(values,filt)
24342454
return obj.ix._getitem_axis(takers,axis=axis_number)
24352455

2436-
raise Exception("cannot find the field [%s] for filtering!" % field)
2456+
raise ValueError("cannot find the field [%s] for filtering!" % field)
24372457

24382458
obj = process_filter(field, filt)
24392459

@@ -3111,12 +3131,12 @@ def __init__(self, field, op=None, value=None, queryables=None):
31113131
self.value = op
31123132

31133133
else:
3114-
raise Exception(
3134+
raise ValueError(
31153135
"Term does not understand the supplied field [%s]" % field)
31163136

31173137
# we have valid fields
31183138
if self.field is None or self.op is None or self.value is None:
3119-
raise Exception("Could not create this term [%s]" % str(self))
3139+
raise ValueError("Could not create this term [%s]" % str(self))
31203140

31213141
# = vs ==
31223142
if self.op == '=':
@@ -3125,7 +3145,7 @@ def __init__(self, field, op=None, value=None, queryables=None):
31253145
# we have valid conditions
31263146
if self.op in ['>', '>=', '<', '<=']:
31273147
if hasattr(self.value, '__iter__') and len(self.value) > 1:
3128-
raise Exception("an inequality condition cannot have multiple values [%s]" % str(self))
3148+
raise ValueError("an inequality condition cannot have multiple values [%s]" % str(self))
31293149

31303150
if not hasattr(self.value, '__iter__'):
31313151
self.value = [self.value]
@@ -3157,7 +3177,7 @@ def eval(self):
31573177
""" set the numexpr expression for this term """
31583178

31593179
if not self.is_valid:
3160-
raise Exception("query term is not valid [%s]" % str(self))
3180+
raise ValueError("query term is not valid [%s]" % str(self))
31613181

31623182
# convert values if we are in the table
31633183
if self.is_in_table:
@@ -3199,7 +3219,7 @@ def eval(self):
31993219

32003220
else:
32013221

3202-
raise Exception("passing a filterable condition to a non-table indexer [%s]" % str(self))
3222+
raise TypeError("passing a filterable condition to a non-table indexer [%s]" % str(self))
32033223

32043224
def convert_value(self, v):
32053225
""" convert the expression that is in the term to something that is accepted by pytables """

0 commit comments

Comments
 (0)