diff --git a/.gitignore b/.gitignore index f188f233a..219570adf 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ netcdftime/_netcdftime.c venv/ .eggs/ .idea/ +.vscode/ diff --git a/Changelog b/Changelog index e79959aff..bcf2550e7 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,7 @@ since version 1.7.2 release =========================== + * support os.PathLike arguments for `Dataset.fromcdl` and raise a `FileNotFoundError` + if the cdl is missing and a `FileExistsError` if the nc file already exists (PR #1387) * raise more informative error when trying to iterate or perform a membership operation on a Dataset (issue #1383) * fix type hint for createEnumType (issue #1378) diff --git a/src/netCDF4/__init__.pyi b/src/netCDF4/__init__.pyi index 4d88568a7..0949b4ed2 100644 --- a/src/netCDF4/__init__.pyi +++ b/src/netCDF4/__init__.pyi @@ -373,7 +373,7 @@ class Dataset: def get_variables_by_attributes(self, **kwargs: Callable[[Any], bool] | Any) -> list[Variable]: ... @staticmethod def fromcdl( - cdlfilename: str, ncfilename: str | None = None, mode: AccessMode = "a", format: Format = "NETCDF4" + cdlfilename: str | os.PathLike, ncfilename: str | os.PathLike | None = None, mode: AccessMode = "a", format: Format = "NETCDF4" ) -> Dataset: ... @overload def tocdl(self, coordvars: bool = False, data: bool = False, outfile: None = None) -> str: ... diff --git a/src/netCDF4/_netCDF4.pyx b/src/netCDF4/_netCDF4.pyx index 6d5ae3c4b..3b8851aac 100644 --- a/src/netCDF4/_netCDF4.pyx +++ b/src/netCDF4/_netCDF4.pyx @@ -3502,19 +3502,27 @@ Dataset instance for `ncfilename` is returned. [ncgen]: https://www.unidata.ucar.edu/software/netcdf/docs/netcdf_utilities_guide.html#ncgen_guide [cdl]: https://www.unidata.ucar.edu/software/netcdf/docs/netcdf_utilities_guide.html#cdl_guide """ + filepath = pathlib.Path(cdlfilename) if ncfilename is None: - filepath = pathlib.Path(cdlfilename) ncfilename = filepath.with_suffix('.nc') + else: + ncfilename = pathlib.Path(ncfilename) formatcodes = {'NETCDF4': 4, 'NETCDF4_CLASSIC': 7, 'NETCDF3_CLASSIC': 3, 'NETCDF3_64BIT': 6, # legacy 'NETCDF3_64BIT_OFFSET': 6, 'NETCDF3_64BIT_DATA': 5} + if format not in formatcodes: raise ValueError('illegal format requested') + if not filepath.exists(): + raise FileNotFoundError(filepath) + if ncfilename.exists(): + raise FileExistsError(ncfilename) + ncgenargs="-knc%s" % formatcodes[format] - subprocess.run(["ncgen", ncgenargs, "-o", ncfilename, cdlfilename], check=True) + subprocess.run(["ncgen", ncgenargs, "-o", str(ncfilename), str(filepath)], check=True) return Dataset(ncfilename, mode=mode) def tocdl(self,coordvars=False,data=False,outfile=None): diff --git a/test/test_cdl.py b/test/test_cdl.py index 4ee4da3c0..895f572fa 100644 --- a/test/test_cdl.py +++ b/test/test_cdl.py @@ -68,8 +68,18 @@ def test_fromcdl(self): assert len(f1.dimensions["d"]) == len(f2.dimensions["d"]) assert (f1["ub"][:] == f2["ub"][:]).all() assert (f1["sb"][:] == f2["sb"][:]).all() + + # test if os.PathLike works + with netCDF4.Dataset.fromcdl(pathlib.Path("ubyte.cdl"), ncfilename=pathlib.Path("ubyte3.nc")) as f3: + assert f1.variables.keys() == f3.variables.keys() + # check if correct errors are raised + self.assertRaises(FileNotFoundError, netCDF4.Dataset.fromcdl, "doesnotexist.cdl") + self.assertRaises(FileExistsError, netCDF4.Dataset.fromcdl, "ubyte.cdl", ncfilename="ubyte2.nc") + + # cleanup os.remove("ubyte2.nc") + os.remove("ubyte3.nc") def tearDown(self): # Remove the temporary files