From 598ab4deeaace02ab206a0ba68f2a2747f8eab03 Mon Sep 17 00:00:00 2001 From: Michael Niklas Date: Thu, 14 Nov 2024 17:23:37 +0100 Subject: [PATCH 1/6] support PathLikes in fromcdl --- src/netCDF4/__init__.pyi | 2 +- src/netCDF4/_netCDF4.pyx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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..d00124efb 100644 --- a/src/netCDF4/_netCDF4.pyx +++ b/src/netCDF4/_netCDF4.pyx @@ -3502,8 +3502,8 @@ 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') formatcodes = {'NETCDF4': 4, 'NETCDF4_CLASSIC': 7, @@ -3514,7 +3514,7 @@ Dataset instance for `ncfilename` is returned. if format not in formatcodes: raise ValueError('illegal format requested') ncgenargs="-knc%s" % formatcodes[format] - subprocess.run(["ncgen", ncgenargs, "-o", ncfilename, cdlfilename], check=True) + subprocess.run(["ncgen", ncgenargs, "-o", str(ncfilename), str(cdlfilename)], check=True) return Dataset(ncfilename, mode=mode) def tocdl(self,coordvars=False,data=False,outfile=None): From 000466cf8981d564e958ed54689495c823e70154 Mon Sep 17 00:00:00 2001 From: Michael Niklas Date: Thu, 14 Nov 2024 17:24:02 +0100 Subject: [PATCH 2/6] ignore .vscode folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) 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/ From 43ba78addd9253495f371f919f324617b91fa403 Mon Sep 17 00:00:00 2001 From: Michael Niklas Date: Thu, 14 Nov 2024 17:25:39 +0100 Subject: [PATCH 3/6] use filepath --- src/netCDF4/_netCDF4.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/netCDF4/_netCDF4.pyx b/src/netCDF4/_netCDF4.pyx index d00124efb..861fa076d 100644 --- a/src/netCDF4/_netCDF4.pyx +++ b/src/netCDF4/_netCDF4.pyx @@ -3514,7 +3514,7 @@ Dataset instance for `ncfilename` is returned. if format not in formatcodes: raise ValueError('illegal format requested') ncgenargs="-knc%s" % formatcodes[format] - subprocess.run(["ncgen", ncgenargs, "-o", str(ncfilename), str(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): From 0affb732496ce273bcd248b3091b8ab25e299c5b Mon Sep 17 00:00:00 2001 From: Michael Niklas Date: Thu, 14 Nov 2024 17:38:58 +0100 Subject: [PATCH 4/6] raise better errors if file exist/do not exist --- src/netCDF4/_netCDF4.pyx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/netCDF4/_netCDF4.pyx b/src/netCDF4/_netCDF4.pyx index 861fa076d..3b8851aac 100644 --- a/src/netCDF4/_netCDF4.pyx +++ b/src/netCDF4/_netCDF4.pyx @@ -3505,14 +3505,22 @@ Dataset instance for `ncfilename` is returned. filepath = pathlib.Path(cdlfilename) if ncfilename is None: 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", str(ncfilename), str(filepath)], check=True) return Dataset(ncfilename, mode=mode) From 66007af89cef8568aacb64b224e600279de1897f Mon Sep 17 00:00:00 2001 From: Michael Niklas Date: Thu, 14 Nov 2024 21:04:01 +0100 Subject: [PATCH 5/6] add tests --- test/test_cdl.py | 10 ++++++++++ 1 file changed, 10 insertions(+) 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 From d419ea83f7430543847def7f8286d68f70906736 Mon Sep 17 00:00:00 2001 From: Michael Niklas Date: Thu, 14 Nov 2024 21:11:34 +0100 Subject: [PATCH 6/6] add changelog --- Changelog | 2 ++ 1 file changed, 2 insertions(+) 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)