2
2
from .. import Variable
3
3
from ..conventions import cf_encoder
4
4
from ..core import indexing
5
- from ..core .utils import FrozenOrderedDict , close_on_error
6
- from ..core .pycompat import iteritems , basestring , unicode_type , OrderedDict
5
+ from ..core .utils import FrozenOrderedDict , close_on_error , Frozen
6
+ from ..core .pycompat import iteritems , bytes_type , unicode_type , OrderedDict
7
7
8
8
from .common import AbstractWritableDataStore
9
9
from .netCDF4_ import _nc4_group , _nc4_values_and_dtype
10
10
11
11
12
+ def maybe_decode_bytes (txt ):
13
+ if isinstance (txt , bytes_type ):
14
+ return txt .decode ('utf-8' )
15
+ else :
16
+ return txt
17
+
18
+
19
+ def _read_attributes (h5netcdf_var ):
20
+ # GH451
21
+ # to ensure conventions decoding works properly on Python 3, decode all
22
+ # bytes attributes to strings
23
+ attrs = OrderedDict ()
24
+ for k in h5netcdf_var .ncattrs ():
25
+ v = h5netcdf_var .getncattr (k )
26
+ if k not in ['_FillValue' , 'missing_value' ]:
27
+ v = maybe_decode_bytes (v )
28
+ attrs [k ] = v
29
+ return attrs
30
+
31
+
12
32
class H5NetCDFStore (AbstractWritableDataStore ):
13
33
"""Store for reading and writing data via h5netcdf
14
34
"""
@@ -33,8 +53,7 @@ def store(self, variables, attributes):
33
53
def open_store_variable (self , var ):
34
54
dimensions = var .dimensions
35
55
data = indexing .LazilyIndexedArray (var )
36
- attributes = OrderedDict ((k , var .getncattr (k ))
37
- for k in var .ncattrs ())
56
+ attrs = _read_attributes (var )
38
57
39
58
# netCDF4 specific encoding
40
59
encoding = dict (var .filters ())
@@ -44,15 +63,14 @@ def open_store_variable(self, var):
44
63
# save source so __repr__ can detect if it's local or not
45
64
encoding ['source' ] = self ._filename
46
65
47
- return Variable (dimensions , data , attributes , encoding )
66
+ return Variable (dimensions , data , attrs , encoding )
48
67
49
68
def get_variables (self ):
50
69
return FrozenOrderedDict ((k , self .open_store_variable (v ))
51
70
for k , v in iteritems (self .ds .variables ))
52
71
53
72
def get_attrs (self ):
54
- return FrozenOrderedDict ((k , self .ds .getncattr (k ))
55
- for k in self .ds .ncattrs ())
73
+ return Frozen (_read_attributes (self .ds ))
56
74
57
75
def get_dimensions (self ):
58
76
return self .ds .dimensions
0 commit comments