-
Notifications
You must be signed in to change notification settings - Fork 264
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add get_fill_value Variable method and fill_value='default' option #1375
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
459dd04
add method to return variable _FillValue (get_fill_value)
jswhit 61121e5
add comments
jswhit 821c740
update
jswhit 1668b99
update
jswhit 365fbab
update
jswhit 33da47b
use C API to get default fill values
jswhit2 d2099dc
update
jswhit2 0deeb12
update
jswhit2 3d9b9d9
add test case
jswhit2 b4b6eee
update
jswhit2 d16a91f
update docstring
jswhit2 d740b0a
update
jswhit2 f50a70d
close file
jswhit2 5d922e4
add get_fill_value to stub
jswhit2 1f67c94
update
jswhit2 aa9452a
add fill_value='default' option
jswhit2 f3eba10
update
jswhit2 801e7b6
add warning if fill_value='default' used for non primitive data type
jswhit2 bff03a4
fix typos in docstrings
jswhit2 6e30d7b
update docs
jswhit2 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4035,11 +4035,16 @@ behavior is similar to Fortran or Matlab, but different than numpy. | |
Ignored if `significant_digts` not specified. If 'BitRound' is used, then | ||
`significant_digits` is interpreted as binary (not decimal) digits. | ||
|
||
**`fill_value`**: If specified, the default netCDF `_FillValue` (the | ||
**`fill_value`**: If specified, the default netCDF fill value (the | ||
value that the variable gets filled with before any data is written to it) | ||
is replaced with this value. If fill_value is set to `False`, then | ||
the variable is not pre-filled. The default netCDF fill values can be found | ||
in the dictionary `netCDF4.default_fillvals`. | ||
is replaced with this value, and the `_FillValue` attribute is set. | ||
If fill_value is set to `False`, then the variable is not pre-filled. | ||
The default netCDF fill values can be found in the dictionary `netCDF4.default_fillvals`. | ||
If not set, the default fill value will be used but no `_FillValue` attribute will be created | ||
(this is the default behavior of the netcdf-c library). If you want to use the | ||
default fill value, but have the `_FillValue` attribute set, use | ||
`fill_value='default'` (note - this only works for primitive data types). `Variable.get_fill_value` | ||
can be used to retrieve the fill value, even if the `_FillValue` attribute is not set. | ||
|
||
**`chunk_cache`**: If specified, sets the chunk cache size for this variable. | ||
Persists as long as Dataset is open. Use `set_var_chunk_cache` to | ||
|
@@ -4403,6 +4408,17 @@ behavior is similar to Fortran or Matlab, but different than numpy. | |
if ierr != NC_NOERR: | ||
if grp.data_model != 'NETCDF4': grp._enddef() | ||
_ensure_nc_success(ierr, extra_msg=error_info) | ||
elif fill_value == 'default': | ||
if self._isprimitive: | ||
fillval = numpy.array(default_fillvals[self.dtype.str[1:]]) | ||
if not fillval.dtype.isnative: fillval.byteswap(True) | ||
_set_att(self._grp, self._varid, '_FillValue',\ | ||
fillval, xtype=xtype) | ||
else: | ||
msg = """ | ||
WARNING: there is no default fill value for this data type, so fill_value='default' | ||
does not do anything.""" | ||
warnings.warn(msg) | ||
else: | ||
if self._isprimitive or self._isenum or \ | ||
(self._isvlen and self.dtype == str): | ||
|
@@ -4638,6 +4654,36 @@ behavior is similar to Fortran or Matlab, but different than numpy. | |
return the group that this `Variable` is a member of.""" | ||
return self._grp | ||
|
||
def get_fill_value(self): | ||
""" | ||
**`get_fill_value(self)`** | ||
|
||
return the fill value associated with this `Variable` (returns `None` if data is not | ||
pre-filled). Works even if default fill value was used, and `_FillValue` attribute | ||
does not exist.""" | ||
cdef int ierr, no_fill | ||
with nogil: | ||
ierr = nc_inq_var_fill(self._grpid,self._varid,&no_fill,NULL) | ||
_ensure_nc_success(ierr) | ||
if no_fill == 1: # no filling for this variable | ||
return None | ||
else: | ||
try: | ||
fillval = self._FillValue | ||
return fillval | ||
except AttributeError: | ||
# _FillValue attribute not set, see if we can retrieve _FillValue. | ||
# for primitive data types. | ||
if self._isprimitive: | ||
#return numpy.array(default_fillvals[self.dtype.str[1:]],self.dtype) | ||
fillval = numpy.empty((),self.dtype) | ||
ierr=nc_inq_var_fill(self._grpid,self._varid,&no_fill,PyArray_DATA(fillval)) | ||
_ensure_nc_success(ierr) | ||
return fillval | ||
else: | ||
# no default filling for non-primitive data types. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe this is where no_fill would be 1 -- so I'd think we would want to return the _FillValue attribute if it exists. |
||
return None | ||
|
||
def ncattrs(self): | ||
""" | ||
**`ncattrs(self)`** | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import unittest, os, tempfile | ||
import netCDF4 | ||
from numpy.testing import assert_array_equal | ||
import numpy as np | ||
|
||
fill_val = np.array(9.9e31) | ||
|
||
# test Variable.get_fill_value | ||
|
||
class TestGetFillValue(unittest.TestCase): | ||
def setUp(self): | ||
self.testfile = tempfile.NamedTemporaryFile(suffix='.nc', delete=False).name | ||
f = netCDF4.Dataset(self.testfile, 'w') | ||
dim = f.createDimension('x',10) | ||
for dt in netCDF4.default_fillvals.keys(): | ||
if not dt.startswith('c'): | ||
v = f.createVariable(dt+'_var',dt,dim) | ||
v = f.createVariable('float_var',np.float64,dim,fill_value=fill_val) | ||
# test fill_value='default' option (issue #1374) | ||
v2 = f.createVariable('float_var2',np.float64,dim,fill_value='default') | ||
f.close() | ||
|
||
def tearDown(self): | ||
os.remove(self.testfile) | ||
|
||
def runTest(self): | ||
f = netCDF4.Dataset(self.testfile, "r") | ||
# no _FillValue set, test that default fill value returned | ||
for dt in netCDF4.default_fillvals.keys(): | ||
if not dt.startswith('c'): | ||
fillval = np.array(netCDF4.default_fillvals[dt]) | ||
if dt == 'S1': fillval = fillval.astype(dt) | ||
v = f[dt+'_var'] | ||
assert_array_equal(fillval, v.get_fill_value()) | ||
# _FillValue attribute is set. | ||
v = f['float_var'] | ||
assert_array_equal(fill_val, v.get_fill_value()) | ||
v = f['float_var2'] | ||
assert_array_equal(np.array(netCDF4.default_fillvals['f8']), v._FillValue) | ||
f.close() | ||
|
||
if __name__ == '__main__': | ||
unittest.main() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure when no_fill would be one -- but if there is a
_FillValue
attribute, maybe it should be returned anyway? e.g. look for that first?The other question is what to do if the
_FillValue
attribute doesn't match what nc_inq_var_fill returns?That would be a malformed file, but maybe helpful to warn the user somehow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if no_fill=1, there is no pre-filling of data in the variable (so
_FillValue
is not used). Not sure what happens if pre-filling is turned off and_FillValue
is set - but in this case, I think the user would expect to get information on what is actually happening when you create a variable and don't write data to it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah -- that's the challenge -- the fill value has a well defined meaning and purpose, but it's commonly used (abused?) to means missing value, or invalid value. So someone could, in theory, write a file without the fill value set, and then use the attribute to mean missing data. so ????
But I suppose the pathological cases are not our problem :-) -- the point of this new method to get the actual, under the hood, fill_value.
in which case, looking for the FillValue attribute is unnecessary -- unless we want to check that it matches, which might be a good idea!