diff --git a/.github/workflows/build_latest.yml b/.github/workflows/build_latest.yml index 0f3bb7d3e..cca163d45 100644 --- a/.github/workflows/build_latest.yml +++ b/.github/workflows/build_latest.yml @@ -35,7 +35,7 @@ jobs: pushd pnetcdf-${PNETCDF_VERSION} ./configure --prefix $NETCDF_DIR --enable-shared --disable-fortran --disable-cxx make -j 2 - make install + sudo make install popd echo "Download and build netCDF version ${NETCDF_VERSION}" wget https://downloads.unidata.ucar.edu/netcdf-c/${NETCDF_VERSION}/netcdf-c-${NETCDF_VERSION}.tar.gz @@ -46,7 +46,7 @@ jobs: export LIBS="-lhdf5_mpich_hl -lhdf5_mpich -lm -lz" ./configure --prefix $NETCDF_DIR --enable-netcdf-4 --enable-shared --enable-dap --enable-parallel4 $NETCDF_EXTRA_CONFIG make -j 2 - make install + sudo make install popd # - name: The job has failed diff --git a/.github/workflows/build_master.yml b/.github/workflows/build_master.yml index 9e0cf70f3..4e0e34fe5 100644 --- a/.github/workflows/build_master.yml +++ b/.github/workflows/build_master.yml @@ -35,7 +35,7 @@ jobs: autoreconf -i ./configure --prefix $NETCDF_DIR --enable-netcdf-4 --enable-shared --enable-dap --enable-parallel4 make -j 2 - make install + sudo make install popd # - name: The job has failed diff --git a/.github/workflows/build_old.yml b/.github/workflows/build_old.yml index 7f958f17a..047c892de 100644 --- a/.github/workflows/build_old.yml +++ b/.github/workflows/build_old.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-latest env: PNETCDF_VERSION: 1.12.1 - NETCDF_VERSION: 4.8.1 + NETCDF_VERSION: 4.7.4 NETCDF_DIR: ${{ github.workspace }}/.. NETCDF_EXTRA_CONFIG: --enable-pnetcdf CC: mpicc.mpich @@ -35,10 +35,11 @@ jobs: pushd pnetcdf-${PNETCDF_VERSION} ./configure --prefix $NETCDF_DIR --enable-shared --disable-fortran --disable-cxx make -j 2 - make install + sudo make install popd echo "Download and build netCDF version ${NETCDF_VERSION}" - wget https://downloads.unidata.ucar.edu/netcdf-c/${NETCDF_VERSION}/netcdf-c-${NETCDF_VERSION}.tar.gz + #wget https://downloads.unidata.ucar.edu/netcdf-c/${NETCDF_VERSION}/netcdf-c-${NETCDF_VERSION}.tar.gz + wget https://www.gfd-dennou.org/arch/netcdf/unidata-mirror/netcdf-c-${NETCDF_VERSION}.tar.gz tar -xzf netcdf-c-${NETCDF_VERSION}.tar.gz pushd netcdf-c-${NETCDF_VERSION} export CPPFLAGS="-I/usr/include/hdf5/mpich -I${NETCDF_DIR}/include" @@ -46,7 +47,7 @@ jobs: export LIBS="-lhdf5_mpich_hl -lhdf5_mpich -lm -lz" ./configure --prefix $NETCDF_DIR --enable-netcdf-4 --enable-shared --enable-dap --enable-parallel4 $NETCDF_EXTRA_CONFIG make -j 2 - make install + sudo make install popd # - name: The job has failed diff --git a/.github/workflows/cibuildwheel.yml b/.github/workflows/cibuildwheel.yml index cfbc6823d..831c120b2 100644 --- a/.github/workflows/cibuildwheel.yml +++ b/.github/workflows/cibuildwheel.yml @@ -92,7 +92,7 @@ jobs: echo "Setting CIBW_SKIP=$CIBW_SKIP" - name: "Building ${{ matrix.os }} (${{ matrix.arch }}) wheels" - uses: pypa/cibuildwheel@v2.19.2 + uses: pypa/cibuildwheel@v2.21.3 env: CIBW_SKIP: ${{ env.CIBW_SKIP }} CIBW_ARCHS: ${{ matrix.arch }} @@ -107,8 +107,6 @@ jobs: CIBW_TEST_COMMAND: > python -c "import netCDF4; print(f'netCDF4 v{netCDF4.__version__}')" && pytest -s -rxs -v {project}/test - && URL="https://icdc.cen.uni-hamburg.de/thredds/dodsC/ftpthredds/hamtide/m2.hamtide11a.nc" - && python -c "from netCDF4 import Dataset; nc=Dataset(\"${URL}\"); print(nc)" - uses: actions/upload-artifact@v4 with: @@ -135,7 +133,7 @@ jobs: python-version: 3.x - name: Setup Micromamba Python ${{ matrix.python-version }} - uses: mamba-org/setup-micromamba@v1 + uses: mamba-org/setup-micromamba@v2 with: environment-name: build init-shell: bash diff --git a/.github/workflows/miniconda.yml b/.github/workflows/miniconda.yml index ba790d589..6619db072 100644 --- a/.github/workflows/miniconda.yml +++ b/.github/workflows/miniconda.yml @@ -16,7 +16,7 @@ jobs: os: [windows-latest, ubuntu-latest, macos-latest] platform: [x64, x32] exclude: - - os: macos-latest + - os: macos-latest platform: x32 fail-fast: false defaults: @@ -29,7 +29,7 @@ jobs: submodules: true - name: Setup Micromamba - uses: mamba-org/setup-micromamba@v1 + uses: mamba-org/setup-micromamba@v2 with: environment-name: TEST init-shell: bash @@ -63,13 +63,13 @@ jobs: submodules: true - name: Setup Micromamba - uses: mamba-org/setup-micromamba@v1 + uses: mamba-org/setup-micromamba@v2 with: environment-name: TEST init-shell: bash create-args: >- python=${{ matrix.python-version }} - numpy cython pip pytest mpi4py hdf5=*=mpi* libnetcdf=*=mpi* cftime zlib certifi typing-extensions + numpy cython pip pytest openmpi mpi4py hdf5=*=mpi* libnetcdf=*=mpi* cftime zlib certifi typing-extensions --channel conda-forge - name: Install netcdf4-python with mpi @@ -82,7 +82,7 @@ jobs: run: | cd test && python run_all.py cd ../examples - export PATH="${CONDA_PREFIX}/bin:${CONDA_PREFIX}/Library/bin:$PATH" + export PATH="${CONDA_PREFIX}/bin:${CONDA_PREFIX}/Library/bin:$PATH" which mpirun mpirun --version mpirun -np 4 --oversubscribe python mpi_example.py # for openmpi diff --git a/Changelog b/Changelog index f1e82e2b3..bc46e06ce 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,9 @@ =============================== * add static type hints (PR #1302) * Expose nc_rc_set, nc_rc_get (via rc_set, rc_get module functions). (PR #1348) + * Add Variable.get_fill_value and allow `fill_value='default'` to + set `_FillValue` using default fill values. (issue #1374, PR #1375). + * Fix NETCDF3 endian error (issue #1373, PR #1355). version 1.7.1 (tag v1.7.1rel) =============================== @@ -22,7 +25,7 @@ version 1.6.5 (tag v1.6.5rel) =============================== - * fix for issue #1271 (mask ignored if bool MA assinged to uint8 var) + * fix for issue #1271 (mask ignored if bool MA assigned to uint8 var) * include information on specific object when reporting errors from netcdf-c * python 3.12 wheels added, support for python 3.7 removed. @@ -341,7 +344,7 @@ * Fix for auto scaling and masking when _Unsigned attribute set (create view as unsigned type after scaling and masking). Issue #671. * Always mask values outside valid_min, valid_max (not just when - missing_value attribue present). Issue #672. + missing_value attribute present). Issue #672. * Fix setup.py so pip install doesn't fail if cython not installed. setuptools >= 18.0 now required for installation (Issue #666). @@ -415,7 +418,7 @@ reading, a vlen string array attribute is returned as a list of strings. To write, use var.setncattr_string("name", ["two", "strings"]).) * Fix for issue #596 - julian day calculations wrong for negative years, - caused incorrect rountrip num2date(date2num(date)) roundtrip for dates with year + caused incorrect roundtrip num2date(date2num(date)) roundtrip for dates with year < 0. * Make sure negative years work in utime.num2date (issue #596). * raise NotImplementedError when trying to pickle Dataset, Variable, @@ -958,7 +961,7 @@ lib after the 4.2 release). Controlled by kwarg 'diskless' to netCDF4.Dataset (default False). diskless=True when creating a file results in a file that exists only in memory, closing the file - makes the data disapper, except if persist=True keyword given in + makes the data disappear, except if persist=True keyword given in which case it is persisted to a disk file on close. diskless=True when opening a file creates an in-memory copy of the file for faster access. @@ -1196,7 +1199,7 @@ version 0.8.1 (svn revision 744) * Experimental variable-length (vlen) data type support added. - * changes to accomodate compound types in netcdf-4.1-beta snapshots. + * changes to accommodate compound types in netcdf-4.1-beta snapshots. Compound types now work correctly for snapshots >= 20090603. * Added __len__ method and 'size' property to Variable class. @@ -1207,7 +1210,7 @@ version 0.8.1 (svn revision 744) * Fixed bug occurring when indexing with a numpy array of length 1. - * Fixed bug that occured when -1 was used as a variable index. + * Fixed bug that occurred when -1 was used as a variable index. * enabled 'shared access' mode for NETCDF3 formatted files (mode='ws', 'r+s' or 'as'). Writes in shared mode are unbuffered, which can @@ -1376,7 +1379,7 @@ version 0.7.3 (svn revision 501) to work as slice indices. * (netCDF4_classic only) try to make sure file is not left in 'define mode' - when execption is raised. + when exception is raised. * if slicing a variable results in a array with shape (1,), just return a scalar (except for compound types). diff --git a/README.md b/README.md index 59cf74311..8fa99985b 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ For details on the latest updates, see the [Changelog](https://github.com/Unidat 06/13/2024: Version [1.7.0](https://pypi.python.org/pypi/netCDF4/1.7.0) released. Add support for complex numbers via `auto_complex` keyword to `Dataset` ([PR #1295](https://github.com/Unidata/netcdf4-python/pull/1295)) 10/20/2023: Version [1.6.5](https://pypi.python.org/pypi/netCDF4/1.6.5) released. -Fix for issue #1271 (mask ignored if bool MA assinged to uint8 var), +Fix for issue #1271 (mask ignored if bool MA assigned to uint8 var), support for python 3.12 (removal of python 3.7 support), more informative error messages. diff --git a/README.wheels.md b/README.wheels.md deleted file mode 100644 index 83626b78f..000000000 --- a/README.wheels.md +++ /dev/null @@ -1,100 +0,0 @@ -# Building and uploading wheels - -## For OSX - -We automate OSX wheel building using a custom github repository that builds on -the travis-ci OSX machines. - -The travis-ci interface for the builds is : -https://travis-ci.org/MacPython/netcdf4-python-wheels - -The driving github repository is : -https://github.com/MacPython/netcdf4-python-wheels - -### How it works - -The wheel-building repository: - -* does a fresh build of the required C / C++ libraries; -* builds a netcdf4-python wheel, linking against these fresh builds; -* processes the wheel using [delocate](https://pypi.python.org/pypi/delocate). - `delocate` copies the required dynamic libraries into the wheel and relinks - the extension modules against the copied libraries; -* uploads the built wheel to http://wheels.scipy.org (a Rackspace container - kindly donated by Rackspace to scikit-learn). - -The resulting wheel is therefore self-contained and does not need any external -dynamic libraries apart from those provided as standard by OSX. - -### Triggering a build - -You will need write permission to the github repository to trigger new builds -on the travis-ci interface. Contact us on the mailing list if you need this. - -You can trigger a build by: - -* making a commit to the `netcdf4-python-wheels` repository (e.g. with `git - commit --allow-empty`); or -* clicking on the circular arrow icon towards the top right of the travis-ci - page, to rerun the previous build. - -In general, it is better to trigger a build with a commit, because this makes -a new set of build products and logs, keeping the old ones for reference. -Keeping the old build logs helps us keep track of previous problems and -successful builds. - -### Which netcdf4-python commit does the repository build? - -By default, the `netcd4-python-wheels` repository is usually set up to build -the latest git tag. To check whether this is so have a look around line 5 of -`.travis.yml` in the `netcdf4-python-wheels` repository. You should see -something like: - -``` -- BUILD_COMMIT='latest-tag' -``` - -If this is commented out, then the repository is set up to build the current -commit in the `netcdf4-python` submodule of the repository. If it is set to -another value then it will be specifying a commit to build. - -You can therefore build any arbitrary commit by specificying the commit hash -or branch name or tag name in this line of the `.travis.yml` file. - -### Uploading the built wheels to pypi - -Be careful, http://wheels.scipy.org points to a container on a distributed -content delivery network. It can take up to 15 minutes for the new wheel file -to get updated into the container at http://wheels.scipy.org. - -When the wheels are updated, you can of course just download them to your -machine manually, and then upload them manually to pypi, or by using -[twine][twine]. You can also use a script for doing this, housed at : -https://github.com/MacPython/terryfy/blob/master/wheel-uploader - -You'll need [twine][twine] and [beautiful soup 4][bs4]. - -You will typically have a directory on your machine where you store wheels, -called a `wheelhouse`. The typical call for `wheel-uploader` would then -be something like: - -``` -wheel-uploader -v -w ~/wheelhouse netCDF4 1.1.8 -``` - -where: - -* `-v` means give verbose messages; -* `-w ~/wheelhouse` means download the wheels from https://wheels.scipy.org to - the directory `~/wheelhouse`; -* `netCDF4` is the root name of the wheel(s) to download / upload; -* `1.1.8` is the version to download / upload. - -So, in this case, `wheel-uploader` will download all wheels starting with -`netCDF4-1.1.8-` from http://wheels.scipy.org to `~/wheelhouse`, then upload -them to pypi. - -Of course, you will need permissions to upload to pypi, for this to work. - -[twine]: https://pypi.python.org/pypi/twine -[bs4]: https://pypi.python.org/pypi/beautifulsoup4 diff --git a/docs/index.html b/docs/index.html index 730c955d7..8484e66d6 100644 --- a/docs/index.html +++ b/docs/index.html @@ -289,7 +289,7 @@

Dimensions in a netCDF file

<class 'netCDF4._netCDF4.Dimension'>: name = 'lon', size = 144

Dimension names can be changed using the -Datatset.renameDimension method of a Dataset or +Dataset.renameDimension() method of a Dataset or Group instance.

Variables in a netCDF file

netCDF variables behave much like python multidimensional array objects @@ -901,7 +901,7 @@

Parallel IO

The optional comm keyword may be used to specify a particular MPI communicator (MPI_COMM_WORLD is used by default). Each process (or rank) -can now write to the file indepedently. +can now write to the file independently. In this example the process rank is written to a different variable index on each task

>>> d = nc.createDimension('dim',4)
@@ -1164,7 +1164,7 @@ 

Functions

Will be converted to a array of strings, where each string has a fixed length of b.shape[-1] characters.

optional kwarg encoding can be used to specify character encoding (default -utf-8). If encoding is 'none' or 'bytes', a numpy.string_ btye array is +utf-8). If encoding is 'none' or 'bytes', a numpy.string_ byte array is returned.

returns a numpy string array with datatype 'UN' (or 'SN') and shape b.shape[:-1] where where N=b.shape[-1].

@@ -1173,7 +1173,8 @@

Functions

def date2index(dates, nctime, calendar=None, select='exact', has_year_zero=None)
-

Return indices of a netCDF time variable corresponding to the given dates.

+

date2index(dates, nctime, calendar=None, select=u'exact', has_year_zero=None)

+

Return indices of a netCDF time variable corresponding to the given dates.

dates: A datetime object or a sequence of datetime objects. The datetime objects should not include a time-zone offset.

nctime: A netCDF time variable object. The nctime object must have a @@ -1212,7 +1213,8 @@

Functions

def date2num(dates, units, calendar=None, has_year_zero=None, longdouble=False)
-

Return numeric time values given datetime objects. The units +

date2num(dates, units, calendar=None, has_year_zero=None, longdouble=False)

+

Return numeric time values given datetime objects. The units of the numeric time values are described by the units argument and the calendar keyword. The datetime objects must be in UTC with no time-zone offset. @@ -1292,7 +1294,8 @@

Functions

def num2date(times, units, calendar='standard', only_use_cftime_datetimes=True, only_use_python_datetimes=False, has_year_zero=None)
-

Return datetime objects given numeric time values. The units +

num2date(times, units, calendar=u'standard', only_use_cftime_datetimes=True, only_use_python_datetimes=False, has_year_zero=None)

+

Return datetime objects given numeric time values. The units of the numeric time values are described by the units argument and the calendar keyword. The returned datetime objects represent UTC with no time-zone offset, even if the specified @@ -1348,14 +1351,18 @@

Functions

rc_get(key)

-

Returns the internal netcdf-c rc table value corresponding to key.

+

Returns the internal netcdf-c rc table value corresponding to key. +See https://docs.unidata.ucar.edu/netcdf-c/current/md_auth.html +for more information on rc files and values.

def rc_set(key, value)

rc_set(key, value)

-

Sets the internal netcdf-c rc table value corresponding to key.

+

Sets the internal netcdf-c rc table value corresponding to key. +See https://docs.unidata.ucar.edu/netcdf-c/current/md_auth.html +for more information on rc files and values.

def set_alignment(threshold, alignment) @@ -2669,12 +2676,16 @@

Instance variables

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 +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 change it when Dataset is re-opened.

@@ -2799,6 +2810,15 @@

Methods

return a tuple of Dimension instances associated with this Variable.

+
+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.

+
def get_var_chunk_cache(self)
@@ -2877,7 +2897,7 @@

Methods

The value of _Encoding is the unicode encoding that is used to decode the bytes into strings.

When numpy string data is written to a variable it is converted back to -indiviual bytes, with the number of bytes in each string equalling the +individual bytes, with the number of bytes in each string equalling the rightmost dimension of the variable.

The default value of chartostring() is True (automatic conversions are performed).

@@ -3234,6 +3254,7 @@

Variablefilters
  • getValue
  • get_dims
  • +
  • get_fill_value
  • get_var_chunk_cache
  • getncattr
  • group
  • diff --git a/examples/reading_netCDF.ipynb b/examples/reading_netCDF.ipynb index 670b06340..95d33957d 100644 --- a/examples/reading_netCDF.ipynb +++ b/examples/reading_netCDF.ipynb @@ -479,7 +479,7 @@ "### Finding the latitude and longitude indices of 50N, 140W\n", "\n", "- The `X` and `Y` dimensions don't look like longitudes and latitudes\n", - "- Use the auxilary coordinate variables named in the `coordinates` variable attribute, `Latitude` and `Longitude`" + "- Use the auxiliary coordinate variables named in the `coordinates` variable attribute, `Latitude` and `Longitude`" ] }, { diff --git a/examples/writing_netCDF.ipynb b/examples/writing_netCDF.ipynb index 2e2fef5ef..61927929f 100644 --- a/examples/writing_netCDF.ipynb +++ b/examples/writing_netCDF.ipynb @@ -710,7 +710,7 @@ "\n", "netCDF version 4 added support for organizing data in hierarchical groups.\n", "\n", - "- analagous to directories in a filesystem. \n", + "- analogous to directories in a filesystem. \n", "- Groups serve as containers for variables, dimensions and attributes, as well as other groups. \n", "- A `netCDF4.Dataset` creates a special group, called the 'root group', which is similar to the root directory in a unix filesystem. \n", "\n", diff --git a/external/nc_complex/src/nc_complex.c b/external/nc_complex/src/nc_complex.c index 68decb02c..4063d4fdc 100644 --- a/external/nc_complex/src/nc_complex.c +++ b/external/nc_complex/src/nc_complex.c @@ -9,6 +9,11 @@ #include "nc_complex_version.h" +// to enable compilation with older versions of netcdf-c +#ifndef NC_FORMATX_NCZARR +#define NC_FORMATX_NCZARR (10) +#endif + // NOLINTBEGIN(bugprone-assignment-in-if-condition) #define CHECK(func) \ do { \ diff --git a/include/membuf.pyx b/include/membuf.pyx index b964453e9..21a916db4 100644 --- a/include/membuf.pyx +++ b/include/membuf.pyx @@ -12,7 +12,7 @@ cdef memview_fromptr(void *memory, size_t size): buf.size = size # size of pointer in bytes return memoryview(buf) -# private extension type that implements buffer protocal. +# private extension type that implements buffer protocol. cdef class _MemBuf: cdef const void *memory cdef size_t size diff --git a/include/netCDF4.pxi b/include/netCDF4.pxi index f748bf82c..62b9be609 100644 --- a/include/netCDF4.pxi +++ b/include/netCDF4.pxi @@ -55,7 +55,7 @@ cdef extern from "netcdf.h": NC_NETCDF4 # Use netCDF-4/HDF5 format NC_CLASSIC_MODEL # Enforce strict netcdf-3 rules. # Use these 'mode' flags for both nc_create and nc_open. - NC_SHARE # Share updates, limit cacheing + NC_SHARE # Share updates, limit caching # The following flag currently is ignored, but use in # nc_open() or nc_create() may someday support use of advisory # locking to prevent multiple writers from clobbering a file @@ -111,7 +111,7 @@ cdef extern from "netcdf.h": NC_FILL NC_NOFILL # Starting with version 3.6, there are different format netCDF - # files. 4.0 instroduces the third one. These defines are only for + # files. 4.0 introduces the third one. These defines are only for # the nc_set_default_format function. NC_FORMAT_CLASSIC NC_FORMAT_64BIT diff --git a/setup.cfg b/setup.cfg index 55736d8b9..c0afd570c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,7 +32,7 @@ use_ncconfig=True # use szip_libdir and szip_incdir. #szip_dir = /usr/local # if netcdf lib was build statically with HDF4 support, -# uncomment and set to hdf4 lib (libmfhdf and libdf) nstall location. +# uncomment and set to hdf4 lib (libmfhdf and libdf) install location. # If the libraries and include files are installed in separate locations, # use hdf4_libdir and hdf4_incdir. #hdf4_dir = /usr/local diff --git a/setup.py b/setup.py index c23eb0348..b17f09ef5 100644 --- a/setup.py +++ b/setup.py @@ -182,7 +182,7 @@ def extract_version(CYTHON_FNAME): HAS_NCCONFIG = False # make sure USE_NCCONFIG from environment takes -# precendence over use_ncconfig from setup.cfg (issue #341). +# precedence over use_ncconfig from setup.cfg (issue #341). if use_ncconfig and not USE_NCCONFIG: USE_NCCONFIG = use_ncconfig elif not USE_NCCONFIG: diff --git a/src/netCDF4/__init__.pyi b/src/netCDF4/__init__.pyi index 443762f25..5bdc58d00 100644 --- a/src/netCDF4/__init__.pyi +++ b/src/netCDF4/__init__.pyi @@ -568,6 +568,7 @@ class Variable(Generic[VarT]): def renameAttribute(self, oldname: str, newname: str) -> None: ... def assignValue(self, val: Any) -> None: ... def getValue(self) -> Any: ... + def get_fill_value(self) -> Any: ... def set_auto_chartostring(self, chartostring: bool) -> None: ... def use_nc_get_vars(self, use_nc_get_vars: bool) -> None: ... def set_auto_maskandscale(self, maskandscale: bool) -> None: ... diff --git a/src/netCDF4/_netCDF4.pyx b/src/netCDF4/_netCDF4.pyx index 9bbc3aaf6..7c92f09bd 100644 --- a/src/netCDF4/_netCDF4.pyx +++ b/src/netCDF4/_netCDF4.pyx @@ -285,7 +285,7 @@ and whether it is unlimited. ``` `Dimension` names can be changed using the -`Datatset.renameDimension` method of a `Dataset` or +`Dataset.renameDimension` method of a `Dataset` or `Group` instance. ## Variables in a netCDF file @@ -997,7 +997,7 @@ use the `parallel` keyword to enable parallel access. The optional `comm` keyword may be used to specify a particular MPI communicator (`MPI_COMM_WORLD` is used by default). Each process (or rank) -can now write to the file indepedently. In this example the process rank is +can now write to the file independently. In this example the process rank is written to a different variable index on each task ```python @@ -1323,6 +1323,8 @@ def rc_get(key): **```rc_get(key)```** Returns the internal netcdf-c rc table value corresponding to key. +See +for more information on rc files and values. """ cdef int ierr cdef char *keyc @@ -1345,6 +1347,8 @@ def rc_set(key, value): **```rc_set(key, value)```** Sets the internal netcdf-c rc table value corresponding to key. +See +for more information on rc files and values. """ cdef int ierr cdef char *keyc @@ -2058,10 +2062,11 @@ cdef _get_vars(group, bint auto_complex=False): endianness = None with nogil: ierr = nc_inq_var_endian(_grpid, varid, &iendian) - if ierr == NC_NOERR and iendian == NC_ENDIAN_LITTLE: - endianness = '<' - elif iendian == NC_ENDIAN_BIG: - endianness = '>' + if ierr == NC_NOERR: + if iendian == NC_ENDIAN_LITTLE: + endianness = '<' + elif iendian == NC_ENDIAN_BIG: + endianness = '>' # check to see if it is a supported user-defined type. try: datatype = _nctonptype[xtype] @@ -4030,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 @@ -4398,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): @@ -4633,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. + return None + def ncattrs(self): """ **`ncattrs(self)`** @@ -5621,7 +5672,7 @@ of the the rightmost dimension of the variable). The value of `_Encoding` is the unicode encoding that is used to decode the bytes into strings. When numpy string data is written to a variable it is converted back to -indiviual bytes, with the number of bytes in each string equalling the +individual bytes, with the number of bytes in each string equalling the rightmost dimension of the variable. The default value of `chartostring` is `True` @@ -6747,7 +6798,7 @@ Will be converted to a array of strings, where each string has a fixed length of `b.shape[-1]` characters. optional kwarg `encoding` can be used to specify character encoding (default -`utf-8`). If `encoding` is 'none' or 'bytes', a `numpy.string_` btye array is +`utf-8`). If `encoding` is 'none' or 'bytes', a `numpy.string_` byte array is returned. returns a numpy string array with datatype `'UN'` (or `'SN'`) and shape diff --git a/test/test_alignment.py b/test/test_alignment.py index 3f7333cd6..39c437535 100644 --- a/test/test_alignment.py +++ b/test/test_alignment.py @@ -134,7 +134,7 @@ def test_setting_alignment(self): for line in h5ls_results.split('\n'): if not line.startswith(' '): data_variable = line.split(' ')[0] - # only process the data variables we care to inpsect + # only process the data variables we care to inspect if data_variable not in addresses: continue line = line.strip() diff --git a/test/test_get_fill_value.py b/test/test_get_fill_value.py new file mode 100644 index 000000000..257a3121e --- /dev/null +++ b/test/test_get_fill_value.py @@ -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()