From f7595b5c07dcb0f9971c53caf1782549e1ec665d Mon Sep 17 00:00:00 2001 From: "Sadie L. Bartholomew" Date: Wed, 25 Mar 2026 14:56:44 +0000 Subject: [PATCH 1/2] Update cf.environment function to include cf-plot dependencies --- cf/functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cf/functions.py b/cf/functions.py index 3760a9154d..9487124502 100644 --- a/cf/functions.py +++ b/cf/functions.py @@ -3183,8 +3183,7 @@ def _section(x, axes=None, stop=None, chunks=False, min_step=1): def environment(display=True, paths=True): - """Return the names and versions of the cf package and its - dependencies. + """Return the names and versions of cf, cf-plot and their dependencies. :Parameters: @@ -3216,6 +3215,7 @@ def environment(display=True, paths=True): "psutil": _get_module_info("psutil"), "matplotlib": _get_module_info("matplotlib", try_except=True), "activestorage": _get_module_info("activestorage", try_except=True), + "cartopy": _get_module_info("cartopy", try_except=True), "cfplot": _get_module_info("cfplot", try_except=True), "cf": (__version__, _os_path_abspath(__file__)), } From 04b226b892a395f680491f915ce057eeb8c669a0 Mon Sep 17 00:00:00 2001 From: "Sadie L. Bartholomew" Date: Wed, 25 Mar 2026 23:15:30 +0000 Subject: [PATCH 2/2] Update cf.environment unit test to cover all keys and kwargs --- cf/test/test_functions.py | 85 ++++++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 15 deletions(-) diff --git a/cf/test/test_functions.py b/cf/test/test_functions.py index 5da228db9b..98d186d02a 100644 --- a/cf/test/test_functions.py +++ b/cf/test/test_functions.py @@ -288,24 +288,79 @@ def test_environment(self): e = cf.environment(display=False) ep = cf.environment(display=False, paths=False) + # Basic structure self.assertIsInstance(e, list) self.assertIsInstance(ep, list) + self.assertEqual(len(e), len(ep)) + self.assertTrue(all(isinstance(s, str) for s in e)) + self.assertTrue(all(isinstance(s, str) for s in ep)) + + # Extract component names + names_e = [s.split(":")[0] for s in e] + names_ep = [s.split(":")[0] for s in ep] + + # Expected full set of components + expected = [ + "Platform", + "Python", + "packaging", + "numpy", + "cfdm.core", + "udunits2 library", + "HDF5 library", + "netcdf library", + "netCDF4", + "h5netcdf", + "h5py", + "pyfive", + "zarr", + "fsspec", + "scipy", + "dask", + "distributed", + "cftime", + "cfunits", + "cfdm", + "esmpy/ESMF", + "psutil", + "matplotlib", + "activestorage", + "cartopy", + "cfplot", + "cf", + ] + + # Ensure all expected components are present + self.assertEqual(sorted(names_e), sorted(expected)) + self.assertEqual(sorted(names_ep), sorted(expected)) + + # Specific known entries (sanity checks) + self.assertIn( + f"Python: {platform.python_version()} {sys.executable}", e + ) + self.assertTrue( + any( + s.startswith(f"Python: {platform.python_version()}") + for s in ep + ) + ) - components = ["Platform: ", "netCDF4: ", "numpy: ", "cftime: "] - for component in components: - self.assertTrue(any(s.startswith(component) for s in e)) - self.assertTrue(any(s.startswith(component) for s in ep)) - for component in [ - f"cf: {cf.__version__} {os.path.abspath(cf.__file__)}", - f"Python: {platform.python_version()} {sys.executable}", - ]: - self.assertIn(component, e) - self.assertNotIn(component, ep) # paths shouldn't be present here - for component in [ - f"cf: {cf.__version__}", - f"Python: {platform.python_version()}", - ]: - self.assertIn(component, ep) + self.assertIn( + f"cf: {cf.__version__} {os.path.abspath(cf.__file__)}", e + ) + self.assertIn(f"cf: {cf.__version__}", ep) + + # Each entry without paths should match the start of the + # corresponding entry with paths + for full, short in zip(e, ep): + name_full, val_full = full.split(": ", 1) + name_short, val_short = short.split(": ", 1) + + self.assertEqual(name_full, name_short) + self.assertTrue( + val_full.startswith(val_short), + msg=f"Mismatch for {name_full}: '{val_full}' vs '{val_short}'", + ) def test_indices_shape(self): import dask.array as da