From b86f4b63926f9fbd166bf696c9c9f0aed4c762f2 Mon Sep 17 00:00:00 2001 From: verduijn Date: Wed, 25 Sep 2024 10:18:57 +0200 Subject: [PATCH 1/5] Fix wrong return type in 'check_satpy' comment --- satpy/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/satpy/utils.py b/satpy/utils.py index 77645a476a..b7a5c28376 100644 --- a/satpy/utils.py +++ b/satpy/utils.py @@ -498,8 +498,8 @@ def check_satpy(readers=None, writers=None, extras=None): writers (list or None): Limit writers checked to those specified extras (list or None): Limit extras checked to those specified - Returns: bool - True if all specified features were successfully loaded. + Returns: + None """ from satpy.readers import configs_for_reader From fd5749d8992e0f1c25f50436189f3128bec2f08a Mon Sep 17 00:00:00 2001 From: verduijn Date: Fri, 27 Sep 2024 21:07:46 +0200 Subject: [PATCH 2/5] Add show_versions to utils and use in check_satpy --- satpy/tests/test_utils.py | 18 +++++---- satpy/utils.py | 80 +++++++++++++++++++++++++++++---------- 2 files changed, 72 insertions(+), 26 deletions(-) diff --git a/satpy/tests/test_utils.py b/satpy/tests/test_utils.py index 61255c8006..455971babd 100644 --- a/satpy/tests/test_utils.py +++ b/satpy/tests/test_utils.py @@ -278,13 +278,17 @@ def test_specific_check_satpy(self): """Test 'check_satpy' with specific features provided.""" from satpy.utils import check_satpy with mock.patch("satpy.utils.print") as print_mock: - check_satpy(readers=["viirs_sdr"], extras=("cartopy", "__fake")) - checked_fake = False - for call in print_mock.mock_calls: - if len(call[1]) > 0 and "__fake" in call[1][0]: - assert "ok" not in call[1][1] - checked_fake = True - assert checked_fake, "Did not find __fake module mentioned in checks" + check_satpy(readers=["viirs_sdr"], packages=("cartopy", "__fake")) + checked_fake = any("__fake: not installed" in c[1] for c in print_mock.mock_calls if len(c[1])) + assert checked_fake, "Did not find __fake package mentioned in checks" + +class TestShowVersions: + """Test the 'show_versions' function.""" + + def test_basic_show_versions(self): + """Test 'check_satpy' basic functionality.""" + from satpy.utils import show_versions + show_versions() def test_debug_on(caplog): diff --git a/satpy/utils.py b/satpy/utils.py index b7a5c28376..64c3be54b8 100644 --- a/satpy/utils.py +++ b/satpy/utils.py @@ -20,9 +20,11 @@ import contextlib import datetime +import importlib.metadata import logging import os import pathlib +import platform import warnings from contextlib import contextmanager from copy import deepcopy @@ -476,27 +478,72 @@ def _check_yaml_configs(configs, key): pass return diagnostic +def _check_package_version(package_name: str) -> Optional[str]: + """Check the version of `package_name`. -def _check_import(module_names): - """Import the specified modules and provide status.""" - diagnostics = {} - for module_name in module_names: - try: - __import__(module_name) - res = "ok" - except ImportError as err: - res = str(err) - diagnostics[module_name] = res - return diagnostics + Args: + package_name (str): the distribution package name. + + Returns: + the version number if available else `None`. + """ + try: + return importlib.metadata.version(package_name) + except importlib.metadata.PackageNotFoundError: + return None +def show_versions(packages=None): + """Shows version for system, python and common packages (if installed). -def check_satpy(readers=None, writers=None, extras=None): + Args: + packages (list or None): Limit packages to those specified. + + Returns: + None. + + """ + packages = ( + ( + "cartopy", + "geoviews", + "numpy", + "dask", + "xarray", + "gdal", + "rasterio", + "pyproj", + "netcdf4", + "h5py", + "pyhdf", + "h5netcdf", + "fsspec", + ) + if packages is None + else packages + ) + + print("Versions") # noqa: T201 + print("======") # noqa: T201 + print(f"platform: {platform.platform()}") # noqa: T201 + print(f"python: {platform.python_version()}") # noqa: T201 + print() # noqa: T201 + + for package_name in sorted(packages): + package_version = _check_package_version(package_name) + print( # noqa: T201 + f"{package_name}: {package_version if package_version else 'not installed'}" + ) + + print() # noqa: T201 + + +def check_satpy(readers=None, writers=None, packages=None): """Check the satpy readers and writers for correct installation. Args: readers (list or None): Limit readers checked to those specified writers (list or None): Limit writers checked to those specified - extras (list or None): Limit extras checked to those specified + packages (list or None): Limit packages checked to those specified Returns: None @@ -517,12 +564,7 @@ def check_satpy(readers=None, writers=None, extras=None): print(writer + ": ", res) # noqa: T201 print() # noqa: T201 - print("Extras") # noqa: T201 - print("======") # noqa: T201 - module_names = extras if extras is not None else ("cartopy", "geoviews") - for module_name, res in sorted(_check_import(module_names).items()): - print(module_name + ": ", res) # noqa: T201 - print() # noqa: T201 + show_versions(packages=packages) def unify_chunks(*data_arrays: xr.DataArray) -> tuple[xr.DataArray, ...]: From 3a93ea97616846541d8211d35f7489157d08a52f Mon Sep 17 00:00:00 2001 From: verduijn Date: Tue, 8 Oct 2024 08:54:49 +0200 Subject: [PATCH 3/5] Apply code formatting suggestions from code review Co-authored-by: Panu Lahtinen --- satpy/tests/test_utils.py | 1 + satpy/utils.py | 1 + 2 files changed, 2 insertions(+) diff --git a/satpy/tests/test_utils.py b/satpy/tests/test_utils.py index 455971babd..74b5a3ecfd 100644 --- a/satpy/tests/test_utils.py +++ b/satpy/tests/test_utils.py @@ -282,6 +282,7 @@ def test_specific_check_satpy(self): checked_fake = any("__fake: not installed" in c[1] for c in print_mock.mock_calls if len(c[1])) assert checked_fake, "Did not find __fake package mentioned in checks" + class TestShowVersions: """Test the 'show_versions' function.""" diff --git a/satpy/utils.py b/satpy/utils.py index 64c3be54b8..f4d456d4f6 100644 --- a/satpy/utils.py +++ b/satpy/utils.py @@ -492,6 +492,7 @@ def _check_package_version(package_name: str) -> Optional[str]: except importlib.metadata.PackageNotFoundError: return None + def show_versions(packages=None): """Shows version for system, python and common packages (if installed). From f53c6f191443a904922646176f1e4f159455712c Mon Sep 17 00:00:00 2001 From: verduijn Date: Tue, 8 Oct 2024 11:10:08 +0200 Subject: [PATCH 4/5] Add tests for `show_versions` with installed and missing packages --- satpy/tests/test_utils.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/satpy/tests/test_utils.py b/satpy/tests/test_utils.py index 74b5a3ecfd..a10e285886 100644 --- a/satpy/tests/test_utils.py +++ b/satpy/tests/test_utils.py @@ -291,6 +291,37 @@ def test_basic_show_versions(self): from satpy.utils import show_versions show_versions() + def test_show_specific_version(self): + """Test 'show_version' works with installed package.""" + from satpy.utils import show_versions + with mock.patch("satpy.utils.print") as print_mock: + show_versions(packages=["pytest"]) + + # no regex or `.__version__` based checks to prevent edge case failures + pytest_mentioned = any( + "pytest:" in c[1][0] for c in print_mock.mock_calls if len(c[1]) + ) + pytest_installed = all( + "pytest: not installed" not in c[1][0] + for c in print_mock.mock_calls + if len(c[1]) + ) + check_pytest = pytest_mentioned and pytest_installed + assert check_pytest, "pytest with package version not in print output" + + def test_show_missing_specific_version(self): + """Test 'show_version' works with missing package.""" + from satpy.utils import show_versions + + with mock.patch("satpy.utils.print") as print_mock: + show_versions(packages=["__fake"]) + checked_fake = any( + "__fake: not installed" in c[1] + for c in print_mock.mock_calls + if len(c[1]) + ) + assert checked_fake, "Did not find '__fake: not installed' in print output" + def test_debug_on(caplog): """Test that debug_on is working as expected.""" From 692c9b1506bfc5d0e1f238067a12fbebf0d9d8c9 Mon Sep 17 00:00:00 2001 From: verduijn Date: Tue, 8 Oct 2024 15:49:36 +0200 Subject: [PATCH 5/5] Use capys fixture instead of patching print in tests --- satpy/tests/test_utils.py | 42 ++++++++++++--------------------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/satpy/tests/test_utils.py b/satpy/tests/test_utils.py index a10e285886..c52006f1be 100644 --- a/satpy/tests/test_utils.py +++ b/satpy/tests/test_utils.py @@ -291,36 +291,25 @@ def test_basic_show_versions(self): from satpy.utils import show_versions show_versions() - def test_show_specific_version(self): + def test_show_specific_version(self, capsys): """Test 'show_version' works with installed package.""" from satpy.utils import show_versions - with mock.patch("satpy.utils.print") as print_mock: - show_versions(packages=["pytest"]) + show_versions(packages=["pytest"]) + out, _ = capsys.readouterr() - # no regex or `.__version__` based checks to prevent edge case failures - pytest_mentioned = any( - "pytest:" in c[1][0] for c in print_mock.mock_calls if len(c[1]) - ) - pytest_installed = all( - "pytest: not installed" not in c[1][0] - for c in print_mock.mock_calls - if len(c[1]) - ) - check_pytest = pytest_mentioned and pytest_installed - assert check_pytest, "pytest with package version not in print output" + pytest_mentioned = "pytest:" in out + pytest_installed = "pytest: not installed" not in out + check_pytest = pytest_mentioned and pytest_installed + assert check_pytest, "pytest with package version not in print output" - def test_show_missing_specific_version(self): + def test_show_missing_specific_version(self, capsys): """Test 'show_version' works with missing package.""" from satpy.utils import show_versions + show_versions(packages=["__fake"]) + out, _ = capsys.readouterr() - with mock.patch("satpy.utils.print") as print_mock: - show_versions(packages=["__fake"]) - checked_fake = any( - "__fake: not installed" in c[1] - for c in print_mock.mock_calls - if len(c[1]) - ) - assert checked_fake, "Did not find '__fake: not installed' in print output" + check_fake = "__fake: not installed" in out + assert check_fake, "Did not find '__fake: not installed' in print output" def test_debug_on(caplog): @@ -330,12 +319,7 @@ def test_debug_on(caplog): def depwarn(): logger = logging.getLogger("satpy.silly") logger.debug("But now it's just got SILLY.") - warnings.warn( - "Stop that! It's SILLY.", - DeprecationWarning, - stacklevel=2 - ) - + warnings.warn("Stop that! It's SILLY.", DeprecationWarning, stacklevel=2) warnings.filterwarnings("ignore", category=DeprecationWarning) debug_on(False) filts_before = warnings.filters.copy()