@@ -61,26 +61,35 @@ def _ensure_encoding(encoding):
61
61
return encoding
62
62
63
63
64
- class IncompatibilityWarning (Warning ):
64
+ class PossibleDataLossError (Exception ):
65
+ pass
66
+
67
+ class ClosedFileError (Exception ):
65
68
pass
66
69
70
+ class IncompatibilityWarning (Warning ):
71
+ pass
67
72
68
73
incompatibility_doc = """
69
74
where criteria is being ignored as this version [%s] is too old (or
70
75
not-defined), read the file in and write it out to a new file to upgrade (with
71
76
the copy_to method)
72
77
"""
73
78
74
-
75
79
class AttributeConflictWarning (Warning ):
76
80
pass
77
81
78
-
79
82
attribute_conflict_doc = """
80
83
the [%s] attribute of the existing index is [%s] which conflicts with the new
81
84
[%s], resetting the attribute to None
82
85
"""
83
86
87
+ class DuplicateWarning (Warning ):
88
+ pass
89
+
90
+ duplicate_doc = """
91
+ duplicate entries in table, taking most recently appended
92
+ """
84
93
85
94
performance_doc = """
86
95
your performance may suffer as PyTables will pickle object types that it cannot
@@ -263,7 +272,6 @@ class HDFStore(StringMixin):
263
272
>>> bar = store['foo'] # retrieve
264
273
>>> store.close()
265
274
"""
266
- _quiet = False
267
275
268
276
def __init__ (self , path , mode = None , complevel = None , complib = None ,
269
277
fletcher32 = False ):
@@ -281,11 +289,12 @@ def __init__(self, path, mode=None, complevel=None, complib=None,
281
289
self ._complib = complib
282
290
self ._fletcher32 = fletcher32
283
291
self ._filters = None
284
- self .open (mode = mode , warn = False )
292
+ self .open (mode = mode )
285
293
286
294
@property
287
295
def root (self ):
288
296
""" return the root node """
297
+ self ._check_if_open ()
289
298
return self ._handle .root
290
299
291
300
def __getitem__ (self , key ):
@@ -299,6 +308,7 @@ def __delitem__(self, key):
299
308
300
309
def __getattr__ (self , name ):
301
310
""" allow attribute access to get stores """
311
+ self ._check_if_open ()
302
312
try :
303
313
return self .get (name )
304
314
except :
@@ -321,24 +331,26 @@ def __len__(self):
321
331
322
332
def __unicode__ (self ):
323
333
output = '%s\n File path: %s\n ' % (type (self ), pprint_thing (self ._path ))
324
-
325
- if len (list (self .keys ())):
326
- keys = []
327
- values = []
328
-
329
- for k in self .keys ():
330
- try :
331
- s = self .get_storer (k )
332
- if s is not None :
333
- keys .append (pprint_thing (s .pathname or k ))
334
- values .append (pprint_thing (s or 'invalid_HDFStore node' ))
335
- except Exception as detail :
336
- keys .append (k )
337
- values .append ("[invalid_HDFStore node: %s]" % pprint_thing (detail ))
338
-
339
- output += adjoin (12 , keys , values )
334
+ if self .is_open :
335
+ if len (list (self .keys ())):
336
+ keys = []
337
+ values = []
338
+
339
+ for k in self .keys ():
340
+ try :
341
+ s = self .get_storer (k )
342
+ if s is not None :
343
+ keys .append (pprint_thing (s .pathname or k ))
344
+ values .append (pprint_thing (s or 'invalid_HDFStore node' ))
345
+ except Exception as detail :
346
+ keys .append (k )
347
+ values .append ("[invalid_HDFStore node: %s]" % pprint_thing (detail ))
348
+
349
+ output += adjoin (12 , keys , values )
350
+ else :
351
+ output += 'Empty'
340
352
else :
341
- output += 'Empty'
353
+ output += "File is CLOSED"
342
354
343
355
return output
344
356
@@ -358,7 +370,7 @@ def items(self):
358
370
359
371
iteritems = items
360
372
361
- def open (self , mode = 'a' , warn = True ):
373
+ def open (self , mode = 'a' ):
362
374
"""
363
375
Open the file in the specified mode
364
376
@@ -367,19 +379,23 @@ def open(self, mode='a', warn=True):
367
379
mode : {'a', 'w', 'r', 'r+'}, default 'a'
368
380
See HDFStore docstring or tables.openFile for info about modes
369
381
"""
370
- self ._mode = mode
371
- if warn and mode == 'w' : # pragma: no cover
372
- while True :
373
- if compat .PY3 :
374
- raw_input = input
375
- response = raw_input ("Re-opening as mode='w' will delete the "
376
- "current file. Continue (y/n)?" )
377
- if response == 'y' :
378
- break
379
- elif response == 'n' :
380
- return
381
- if self ._handle is not None and self ._handle .isopen :
382
- self ._handle .close ()
382
+ if self ._mode != mode :
383
+
384
+ # if we are chaning a write mode to read, ok
385
+ if self ._mode in ['a' ,'w' ] and mode in ['r' ,'r+' ]:
386
+ pass
387
+ elif mode in ['w' ]:
388
+
389
+ # this would truncate, raise here
390
+ if self .is_open :
391
+ raise PossibleDataLossError ("Re-opening the file [{0}] with mode [{1}] "
392
+ "will delete the current file!" .format (self ._path ,self ._mode ))
393
+
394
+ self ._mode = mode
395
+
396
+ # close and reopen the handle
397
+ if self .is_open :
398
+ self .close ()
383
399
384
400
if self ._complib is not None :
385
401
if self ._complevel is None :
@@ -401,13 +417,24 @@ def close(self):
401
417
"""
402
418
Close the PyTables file handle
403
419
"""
404
- self ._handle .close ()
420
+ if self ._handle is not None :
421
+ self ._handle .close ()
422
+ self ._handle = None
423
+
424
+ @property
425
+ def is_open (self ):
426
+ """
427
+ return a boolean indicating whether the file is open
428
+ """
429
+ if self ._handle is None : return False
430
+ return bool (self ._handle .isopen )
405
431
406
432
def flush (self ):
407
433
"""
408
434
Force all buffered modifications to be written to disk
409
435
"""
410
- self ._handle .flush ()
436
+ if self ._handle is not None :
437
+ self ._handle .flush ()
411
438
412
439
def get (self , key ):
413
440
"""
@@ -748,11 +775,13 @@ def create_table_index(self, key, **kwargs):
748
775
def groups (self ):
749
776
""" return a list of all the top-level nodes (that are not themselves a pandas storage object) """
750
777
_tables ()
778
+ self ._check_if_open ()
751
779
return [ g for g in self ._handle .walkNodes () if getattr (g ._v_attrs ,'pandas_type' ,None ) or getattr (
752
780
g ,'table' ,None ) or (isinstance (g ,_table_mod .table .Table ) and g ._v_name != u ('table' )) ]
753
781
754
782
def get_node (self , key ):
755
783
""" return the node with the key or None if it does not exist """
784
+ self ._check_if_open ()
756
785
try :
757
786
if not key .startswith ('/' ):
758
787
key = '/' + key
@@ -811,6 +840,9 @@ def copy(self, file, mode = 'w', propindexes = True, keys = None, complib = None
811
840
return new_store
812
841
813
842
###### private methods ######
843
+ def _check_if_open (self ):
844
+ if not self .is_open :
845
+ raise ClosedFileError ("{0} file is not open!" .format (self ._path ))
814
846
815
847
def _create_storer (self , group , value = None , table = False , append = False , ** kwargs ):
816
848
""" return a suitable Storer class to operate """
@@ -1647,10 +1679,6 @@ def pathname(self):
1647
1679
def _handle (self ):
1648
1680
return self .parent ._handle
1649
1681
1650
- @property
1651
- def _quiet (self ):
1652
- return self .parent ._quiet
1653
-
1654
1682
@property
1655
1683
def _filters (self ):
1656
1684
return self .parent ._filters
@@ -2918,9 +2946,7 @@ def read(self, where=None, columns=None, **kwargs):
2918
2946
objs .append (obj )
2919
2947
2920
2948
else :
2921
- if not self ._quiet : # pragma: no cover
2922
- print ('Duplicate entries in table, taking most recently '
2923
- 'appended' )
2949
+ warnings .warn (duplicate_doc , DuplicateWarning )
2924
2950
2925
2951
# reconstruct
2926
2952
long_index = MultiIndex .from_arrays (
0 commit comments