@@ -244,6 +244,13 @@ def encode_datetime(d):
244
244
return np .vectorize (encode_datetime )(dates )
245
245
246
246
247
+ def cast_to_int_if_safe (num ):
248
+ int_num = np .array (num , dtype = np .int64 )
249
+ if (num == int_num ).all ():
250
+ num = int_num
251
+ return num
252
+
253
+
247
254
def encode_cf_datetime (dates , units = None , calendar = None ):
248
255
"""Given an array of datetime objects, returns the tuple `(num, units,
249
256
calendar)` suitable for a CF complient time variable.
@@ -279,6 +286,7 @@ def encode_cf_datetime(dates, units=None, calendar=None):
279
286
except (OutOfBoundsDatetime , ValueError , OverflowError ):
280
287
num = _encode_datetime_with_netcdf4 (dates , units , calendar )
281
288
289
+ num = cast_to_int_if_safe (num )
282
290
return (num , units , calendar )
283
291
284
292
@@ -289,11 +297,7 @@ def encode_cf_timedelta(timedeltas, units=None):
289
297
np_unit = _netcdf_to_numpy_timeunit (units )
290
298
num = 1.0 * timedeltas / np .timedelta64 (1 , np_unit )
291
299
num = np .where (pd .isnull (timedeltas ), np .nan , num )
292
-
293
- int_num = np .asarray (num , dtype = np .int64 )
294
- if (num == int_num ).all ():
295
- num = int_num
296
-
300
+ num = cast_to_int_if_safe (num )
297
301
return (num , units )
298
302
299
303
@@ -575,12 +579,18 @@ def maybe_encode_fill_value(var, needs_copy=True):
575
579
return var , needs_copy
576
580
577
581
578
- def maybe_encode_dtype (var ):
582
+ def maybe_encode_dtype (var , name = None ):
579
583
if 'dtype' in var .encoding :
580
584
dims , data , attrs , encoding = _var_as_tuple (var )
581
585
dtype = np .dtype (encoding .pop ('dtype' ))
582
586
if dtype != var .dtype and dtype .kind != 'O' :
583
- if np .issubdtype (dtype , int ):
587
+ if np .issubdtype (dtype , np .integer ):
588
+ if (np .issubdtype (var .dtype , np .floating )
589
+ and '_FillValue' not in var .attrs ):
590
+ warnings .warn ('saving variable %s with floating '
591
+ 'point data as an integer dtype without '
592
+ 'any _FillValue to use for NaNs' % name ,
593
+ RuntimeWarning , stacklevel = 3 )
584
594
data = ops .around (data )[...]
585
595
if dtype == 'S1' and data .dtype != 'S1' :
586
596
data = string_to_char (np .asarray (data , 'S' ))
@@ -638,7 +648,7 @@ def ensure_dtype_not_object(var):
638
648
return var
639
649
640
650
641
- def encode_cf_variable (var , needs_copy = True ):
651
+ def encode_cf_variable (var , needs_copy = True , name = None ):
642
652
"""
643
653
Converts an Variable into an Variable which follows some
644
654
of the CF conventions:
@@ -662,7 +672,7 @@ def encode_cf_variable(var, needs_copy=True):
662
672
var = maybe_encode_timedelta (var )
663
673
var , needs_copy = maybe_encode_offset_and_scale (var , needs_copy )
664
674
var , needs_copy = maybe_encode_fill_value (var , needs_copy )
665
- var = maybe_encode_dtype (var )
675
+ var = maybe_encode_dtype (var , name )
666
676
var = ensure_dtype_not_object (var )
667
677
return var
668
678
@@ -989,6 +999,6 @@ def cf_encoder(variables, attributes):
989
999
990
1000
See also: encode_cf_variable
991
1001
"""
992
- new_vars = OrderedDict ((k , encode_cf_variable (v ))
1002
+ new_vars = OrderedDict ((k , encode_cf_variable (v , name = k ))
993
1003
for k , v in iteritems (variables ))
994
1004
return new_vars , attributes
0 commit comments