| 278 | self.decode_timedelta = decode_timedelta |
| 279 | |
| 280 | def encode(self, variable: Variable, name: T_Name = None): |
| 281 | dims, data, attrs, encoding = unpack_for_encoding(variable) |
| 282 | |
| 283 | dtype = np.dtype(encoding.get("dtype", data.dtype)) |
| 284 | # from netCDF best practices |
| 285 | # https://docs.unidata.ucar.edu/nug/current/best_practices.html#bp_Unsigned-Data |
| 286 | # "_Unsigned = "true" to indicate that |
| 287 | # integer data should be treated as unsigned" |
| 288 | has_unsigned = encoding.get("_Unsigned") is not None |
| 289 | fv = encoding.get("_FillValue") |
| 290 | mv = encoding.get("missing_value") |
| 291 | fill_value = None |
| 292 | |
| 293 | fv_exists = fv is not None |
| 294 | mv_exists = mv is not None |
| 295 | |
| 296 | if not fv_exists and not mv_exists: |
| 297 | return variable |
| 298 | |
| 299 | if fv_exists and mv_exists and not duck_array_ops.allclose_or_equiv(fv, mv): |
| 300 | raise ValueError( |
| 301 | f"Variable {name!r} has conflicting _FillValue ({fv}) and missing_value ({mv}). Cannot encode data." |
| 302 | ) |
| 303 | |
| 304 | if fv_exists: |
| 305 | # Ensure _FillValue is cast to same dtype as data's |
| 306 | # but not for packed data |
| 307 | if has_unsigned: |
| 308 | encoding["_FillValue"] = _encode_unsigned_fill_value(name, fv, dtype) |
| 309 | elif "add_offset" not in encoding and "scale_factor" not in encoding: |
| 310 | encoding["_FillValue"] = dtype.type(fv) |
| 311 | else: |
| 312 | encoding["_FillValue"] = fv |
| 313 | fill_value = pop_to(encoding, attrs, "_FillValue", name=name) |
| 314 | |
| 315 | if mv_exists: |
| 316 | # try to use _FillValue, if it exists to align both values |
| 317 | # or use missing_value and ensure it's cast to same dtype as data's |
| 318 | # but not for packed data |
| 319 | encoding["missing_value"] = attrs.get( |
| 320 | "_FillValue", |
| 321 | ( |
| 322 | _encode_unsigned_fill_value(name, mv, dtype) |
| 323 | if has_unsigned |
| 324 | else ( |
| 325 | dtype.type(mv) |
| 326 | if "add_offset" not in encoding |
| 327 | and "scale_factor" not in encoding |
| 328 | else mv |
| 329 | ) |
| 330 | ), |
| 331 | ) |
| 332 | fill_value = pop_to(encoding, attrs, "missing_value", name=name) |
| 333 | |
| 334 | # apply fillna |
| 335 | if fill_value is not None and not pd.isnull(fill_value): |
| 336 | # special case DateTime to properly handle NaT |
| 337 | if _is_time_like(attrs.get("units")): |