Skip to content

Commit 03011c1

Browse files
committed
BUG: removed table check in select if where is provided (convience really)
allow types in Term that are datetime-like (e.g. can provide a timetuple method) added a warning if you try to select/remove with a where criteria on a legacy table (which isn't supported), you must convert to new format added versioning ability, 'pandas_version', can't detect future format changes (not a required attribute)
1 parent ae17462 commit 03011c1

File tree

2 files changed

+42
-14
lines changed

2 files changed

+42
-14
lines changed

pandas/io/pytables.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import re
1111
import copy
1212
import itertools
13+
import warnings
1314

1415
import numpy as np
1516
from pandas import (
@@ -34,6 +35,11 @@
3435

3536
from contextlib import contextmanager
3637

38+
# versioning attribute
39+
_version = '0.10'
40+
41+
class IncompatibilityWarning(Warning): pass
42+
3743
# reading and writing the full object in one go
3844
_TYPE_MAP = {
3945
Series: 'series',
@@ -341,8 +347,6 @@ def select(self, key, where=None):
341347
group = self.get_node(key)
342348
if group is None:
343349
raise KeyError('No object named %s in the file' % key)
344-
if where is not None and not _is_table_type(group):
345-
raise Exception('can only select with where on objects written as tables')
346350
return self._read_group(group, where)
347351

348352
def put(self, key, value, table=False, append=False,
@@ -498,6 +502,7 @@ def _write_to_group(self, key, value, table=False, append=False,
498502

499503
wrapper(value)
500504
group._v_attrs.pandas_type = kind
505+
group._v_attrs.pandas_version = _version
501506

502507
def _write_series(self, group, series):
503508
self._write_index(group, 'index', series.index)
@@ -1123,6 +1128,7 @@ class Table(object):
11231128
def __init__(self, parent, group):
11241129
self.parent = parent
11251130
self.group = group
1131+
self.version = getattr(group._v_attrs,'version',None)
11261132
self.index_axes = []
11271133
self.non_index_axes = []
11281134
self.values_axes = []
@@ -1475,6 +1481,11 @@ def write(self, **kwargs):
14751481
def read(self, where=None):
14761482
""" we have n indexable columns, with an arbitrary number of data axes """
14771483

1484+
# are we trying to operate on an old version?
1485+
if where is not None:
1486+
if self.version is None or self.version < 0.1:
1487+
warnings.warn("where criteria is being ignored as we this version is too old (or not-defined) [%s]" % self.version, IncompatibilityWarning)
1488+
14781489
if not self.read_axes(where): return None
14791490

14801491
indicies = [ i.values for i in self.index_axes ]
@@ -2114,7 +2125,7 @@ def convert_value(self, v):
21142125
if self.field == 'index' or self.field == 'major_axis':
21152126
if self.kind == 'datetime64' :
21162127
return [lib.Timestamp(v).value, None]
2117-
elif isinstance(v, datetime):
2128+
elif isinstance(v, datetime) or hasattr(v,'timetuple'):
21182129
return [time.mktime(v.timetuple()), None]
21192130
elif not isinstance(v, basestring):
21202131
return [str(v), None]

pandas/io/tests/test_pytables.py

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
import unittest
33
import os
44
import sys
5+
import warnings
56

67
from datetime import datetime
78
import numpy as np
89

910
from pandas import (Series, DataFrame, Panel, MultiIndex, bdate_range,
1011
date_range, Index)
11-
from pandas.io.pytables import HDFStore, get_store, Term
12+
from pandas.io.pytables import HDFStore, get_store, Term, IncompatibilityWarning
1213
import pandas.util.testing as tm
1314
from pandas.tests.test_series import assert_series_equal
1415
from pandas.tests.test_frame import assert_frame_equal
@@ -85,6 +86,17 @@ def test_contains(self):
8586
self.assert_('/foo/b' not in self.store)
8687
self.assert_('bar' not in self.store)
8788

89+
def test_versioning(self):
90+
self.store['a'] = tm.makeTimeSeries()
91+
self.store['b'] = tm.makeDataFrame()
92+
df = tm.makeTimeDataFrame()
93+
self.store.remove('df1')
94+
self.store.append('df1', df[:10])
95+
self.store.append('df1', df[10:])
96+
self.assert_(self.store.root.a._v_attrs.pandas_version == '0.10')
97+
self.assert_(self.store.root.b._v_attrs.pandas_version == '0.10')
98+
self.assert_(self.store.root.df1._v_attrs.pandas_version == '0.10')
99+
88100
def test_reopen_handle(self):
89101
self.store['a'] = tm.makeTimeSeries()
90102
self.store.open('w', warn=False)
@@ -176,8 +188,6 @@ def test_append(self):
176188
tm.assert_frame_equal(self.store['df3'], df)
177189

178190
# this is allowed by almost always don't want to do it
179-
import warnings
180-
import tables
181191
warnings.filterwarnings('ignore', category=tables.NaturalNameWarning)
182192
self.store.remove('/df3 foo')
183193
self.store.append('/df3 foo', df[:10])
@@ -451,9 +461,9 @@ def test_remove_where(self):
451461
'wp', ['foo'])
452462

453463
# selectin non-table with a where
454-
self.store.put('wp2', wp, table=False)
455-
self.assertRaises(Exception, self.store.remove,
456-
'wp2', [('column', ['A', 'D'])])
464+
#self.store.put('wp2', wp, table=False)
465+
#self.assertRaises(Exception, self.store.remove,
466+
# 'wp2', [('column', ['A', 'D'])])
457467

458468

459469
def test_remove_crit(self):
@@ -890,8 +900,8 @@ def test_select(self):
890900
self.store.select('wp2')
891901

892902
# selectin non-table with a where
893-
self.assertRaises(Exception, self.store.select,
894-
'wp2', ('column', ['A', 'D']))
903+
#self.assertRaises(Exception, self.store.select,
904+
# 'wp2', ('column', ['A', 'D']))
895905

896906
def test_panel_select(self):
897907
wp = tm.makePanel()
@@ -927,9 +937,9 @@ def test_frame_select(self):
927937
tm.assert_frame_equal(result, expected)
928938

929939
# can't select if not written as table
930-
self.store['frame'] = df
931-
self.assertRaises(Exception, self.store.select,
932-
'frame', [crit1, crit2])
940+
#self.store['frame'] = df
941+
#self.assertRaises(Exception, self.store.select,
942+
# 'frame', [crit1, crit2])
933943

934944
def test_select_filter_corner(self):
935945
df = DataFrame(np.random.randn(50, 100))
@@ -1004,6 +1014,13 @@ def test_legacy_table_read(self):
10041014
store.select('df1')
10051015
store.select('df2')
10061016
store.select('wp1')
1017+
1018+
# old version (this still throws an exception though)
1019+
import warnings
1020+
warnings.filterwarnings('ignore', category=IncompatibilityWarning)
1021+
self.assertRaises(Exception, store.select, 'wp1', Term('minor_axis','=','B'))
1022+
warnings.filterwarnings('always', category=IncompatibilityWarning)
1023+
10071024
store.close()
10081025

10091026
def test_legacy_table_write(self):

0 commit comments

Comments
 (0)