diff --git a/Changelog b/Changelog index ac1271c90..8970167b9 100644 --- a/Changelog +++ b/Changelog @@ -1,6 +1,7 @@ version 1.6.5 (not yet released) =============================== * fix for issue #1271 (mask ignored if bool MA assinged to uint8 var) + * include information on specific object when reporting errors from netcdf-c version 1.6.4 (tag v1.6.4rel) =============================== diff --git a/src/netCDF4/_netCDF4.pyx b/src/netCDF4/_netCDF4.pyx index eeed0a9e9..3edbc6f34 100644 --- a/src/netCDF4/_netCDF4.pyx +++ b/src/netCDF4/_netCDF4.pyx @@ -2016,16 +2016,22 @@ cdef _get_vars(group): free(varids) # free pointer holding variable ids. return variables -cdef _ensure_nc_success(ierr, err_cls=RuntimeError, filename=None): +def _ensure_nc_success(ierr, err_cls=RuntimeError, filename=None, extra_msg=None): # print netcdf error message, raise error. - if ierr != NC_NOERR: - err_str = (nc_strerror(ierr)).decode('ascii') - if issubclass(err_cls, OSError): - if isinstance(filename, bytes): - filename = filename.decode() - raise err_cls(ierr, err_str, filename) - else: - raise err_cls(err_str) + if ierr == NC_NOERR: + return + + err_str = (nc_strerror(ierr)).decode('ascii') + if issubclass(err_cls, OSError): + if isinstance(filename, bytes): + filename = filename.decode() + raise err_cls(ierr, err_str, filename) + + if extra_msg: + if isinstance(extra_msg, bytes): + extra_msg = extra_msg.decode() + err_str = f"{err_str}: {extra_msg}" + raise err_cls(err_str) # these are class attributes that # only exist at the python level (not in the netCDF file). @@ -4016,6 +4022,10 @@ behavior is similar to Fortran or Matlab, but different than numpy. cdef size_t sizep, nelemsp cdef size_t *chunksizesp cdef float preemptionp + + # Extra information for more helpful error messages + error_info = f"(variable '{name}', group '{grp.name}')" + # flag to indicate that orthogonal indexing is supported self.__orthogonal_indexing__ = True # For backwards compatibility, deprecated zlib kwarg takes @@ -4059,7 +4069,7 @@ behavior is similar to Fortran or Matlab, but different than numpy. compression = None # if compression evaluates to False, set to None. pass else: - raise ValueError("Unsupported value for compression kwarg") + raise ValueError(f"Unsupported value for compression kwarg {error_info}") self._grpid = grp._grpid # make a weakref to group to avoid circular ref (issue 218) # keep strong reference the default behaviour (issue 251) @@ -4117,14 +4127,15 @@ behavior is similar to Fortran or Matlab, but different than numpy. 'Variable length strings are only supported for the ' 'NETCDF4 format. For other formats, consider using ' 'netCDF4.stringtochar to convert string arrays into ' - 'character arrays with an additional dimension.') + 'character arrays with an additional dimension.' + f' {error_info}') datatype = VLType(self._grp, str, None) self._vltype = datatype xtype = datatype._nc_type # make sure this a valid user defined datatype defined in this Group with nogil: ierr = nc_inq_type(self._grpid, xtype, namstring, NULL) - _ensure_nc_success(ierr) + _ensure_nc_success(ierr, extra_msg=error_info) # dtype variable attribute is a numpy datatype object. self.dtype = datatype.dtype elif datatype.str[1:] in _supportedtypes: @@ -4135,7 +4146,7 @@ behavior is similar to Fortran or Matlab, but different than numpy. # dtype variable attribute is a numpy datatype object. self.dtype = datatype else: - raise TypeError('illegal primitive data type, must be one of %s, got %s' % (_supportedtypes,datatype)) + raise TypeError(f'Illegal primitive data type, must be one of {_supportedtypes}, got {datatype} {error_info}') if 'id' in kwargs: self._varid = kwargs['id'] else: @@ -4161,6 +4172,12 @@ behavior is similar to Fortran or Matlab, but different than numpy. with nogil: ierr = nc_def_var(self._grpid, varname, xtype, ndims, NULL, &self._varid) + + if ierr != NC_NOERR: + if grp.data_model != 'NETCDF4': + grp._enddef() + _ensure_nc_success(ierr, extra_msg=error_info) + # set chunk cache size if desired # default is 1mb per var, can cause problems when many (1000's) # of vars are created. This change only lasts as long as file is @@ -4169,16 +4186,14 @@ behavior is similar to Fortran or Matlab, but different than numpy. with nogil: ierr = nc_get_var_chunk_cache(self._grpid, self._varid, &sizep, &nelemsp, &preemptionp) - _ensure_nc_success(ierr) + _ensure_nc_success(ierr, extra_msg=error_info) # reset chunk cache size, leave other parameters unchanged. sizep = chunk_cache with nogil: ierr = nc_set_var_chunk_cache(self._grpid, self._varid, sizep, nelemsp, preemptionp) - _ensure_nc_success(ierr) - if ierr != NC_NOERR: - if grp.data_model != 'NETCDF4': grp._enddef() - _ensure_nc_success(ierr) + _ensure_nc_success(ierr, extra_msg=error_info) + # set compression, shuffle, chunking, fletcher32 and endian # variable settings. # don't bother for NETCDF3* formats. @@ -4198,7 +4213,7 @@ behavior is similar to Fortran or Matlab, but different than numpy. ierr = nc_def_var_deflate(self._grpid, self._varid, 0, 1, icomplevel) if ierr != NC_NOERR: if grp.data_model != 'NETCDF4': grp._enddef() - _ensure_nc_success(ierr) + _ensure_nc_success(ierr, extra_msg=error_info) if szip: IF HAS_SZIP_SUPPORT: try: @@ -4211,7 +4226,7 @@ behavior is similar to Fortran or Matlab, but different than numpy. ierr = nc_def_var_szip(self._grpid, self._varid, iszip_coding, iszip_pixels_per_block) if ierr != NC_NOERR: if grp.data_model != 'NETCDF4': grp._enddef() - _ensure_nc_success(ierr) + _ensure_nc_success(ierr, extra_msg=error_info) ELSE: msg = """ compression='szip' only works if linked version of hdf5 has szip functionality enabled""" @@ -4223,7 +4238,7 @@ compression='szip' only works if linked version of hdf5 has szip functionality e ierr = nc_def_var_zstandard(self._grpid, self._varid, icomplevel) if ierr != NC_NOERR: if grp.data_model != 'NETCDF4': grp._enddef() - _ensure_nc_success(ierr) + _ensure_nc_success(ierr, extra_msg=error_info) ELSE: msg = """ compression='zstd' only works with netcdf-c >= 4.9.0. To enable, install Cython, make sure you have @@ -4236,7 +4251,7 @@ version 4.9.0 or higher netcdf-c with zstandard support, and rebuild netcdf4-pyt ierr = nc_def_var_bzip2(self._grpid, self._varid, icomplevel) if ierr != NC_NOERR: if grp.data_model != 'NETCDF4': grp._enddef() - _ensure_nc_success(ierr) + _ensure_nc_success(ierr, extra_msg=error_info) ELSE: msg = """ compression='bzip2' only works with netcdf-c >= 4.9.0. To enable, install Cython, make sure you have @@ -4255,7 +4270,7 @@ version 4.9.0 or higher netcdf-c with bzip2 support, and rebuild netcdf4-python. iblosc_shuffle) if ierr != NC_NOERR: if grp.data_model != 'NETCDF4': grp._enddef() - _ensure_nc_success(ierr) + _ensure_nc_success(ierr, extra_msg=error_info) ELSE: msg = """ compression='blosc_*' only works with netcdf-c >= 4.9.0. To enable, install Cython, make sure you have @@ -4267,7 +4282,7 @@ version 4.9.0 or higher netcdf-c with blosc support, and rebuild netcdf4-python. ierr = nc_def_var_fletcher32(self._grpid, self._varid, 1) if ierr != NC_NOERR: if grp.data_model != 'NETCDF4': grp._enddef() - _ensure_nc_success(ierr) + _ensure_nc_success(ierr, extra_msg=error_info) # set chunking stuff. if ndims: # don't bother for scalar variable. if contiguous: @@ -4295,7 +4310,7 @@ version 4.9.0 or higher netcdf-c with blosc support, and rebuild netcdf4-python. free(chunksizesp) if ierr != NC_NOERR: if grp.data_model != 'NETCDF4': grp._enddef() - _ensure_nc_success(ierr) + _ensure_nc_success(ierr, extra_msg=error_info) # set endian-ness of variable if endian == 'little': with nogil: @@ -4327,17 +4342,17 @@ version 4.9.0 or higher netcdf-c with blosc support, and rebuild netcdf4-python. ELSE: if significant_digits is not None: - msg = """ + msg = f""" significant_digits kwarg only works with netcdf-c >= 4.9.0. To enable, install Cython, make sure you have version 4.9.0 or higher netcdf-c, and rebuild netcdf4-python. Otherwise, use least_significant_digit -kwarg for quantization.""" +kwarg for quantization. {error_info}""" raise ValueError(msg) if ierr != NC_NOERR: if grp.data_model != 'NETCDF4': grp._enddef() - _ensure_nc_success(ierr) + _ensure_nc_success(ierr, extra_msg=error_info) else: if endian != 'native': - msg="only endian='native' allowed for NETCDF3 files" + msg=f"only endian='native' allowed for NETCDF3 files {error_info}" raise RuntimeError(msg) # set a fill value for this variable if fill_value keyword # given. This avoids the HDF5 overhead of deleting and @@ -4354,7 +4369,7 @@ kwarg for quantization.""" ierr = nc_def_var_fill(self._grpid, self._varid, 1, NULL) if ierr != NC_NOERR: if grp.data_model != 'NETCDF4': grp._enddef() - _ensure_nc_success(ierr) + _ensure_nc_success(ierr, extra_msg=error_info) else: if self._isprimitive or self._isenum or \ (self._isvlen and self.dtype == str): @@ -4379,7 +4394,7 @@ kwarg for quantization.""" # set ndim attribute (number of dimensions). with nogil: ierr = nc_inq_varndims(self._grpid, self._varid, &numdims) - _ensure_nc_success(ierr) + _ensure_nc_success(ierr, extra_msg=error_info) self.ndim = numdims self._name = name # default for automatically applying scale_factor and