diff --git a/doc/source/_static/main.js b/doc/source/_static/main.js index 6fcd3ce79a..188a335e71 100644 --- a/doc/source/_static/main.js +++ b/doc/source/_static/main.js @@ -1,5 +1,6 @@ $(document).ready( function () { $('table.datatable').DataTable( { - "paging": false + "paging": false, + "dom": 'lfitp' } ); } ); diff --git a/doc/source/reader_table.py b/doc/source/reader_table.py index 3982728f47..1c6760a390 100644 --- a/doc/source/reader_table.py +++ b/doc/source/reader_table.py @@ -18,6 +18,8 @@ # along with satpy. If not, see . """Module for autogenerating reader table from config files.""" +from yaml import BaseLoader + from satpy.readers import available_readers @@ -72,7 +74,7 @@ def generate_reader_table(): table = [rst_table_header("Satpy Readers", header=["Description", "Reader name", "Status", "fsspec support"], widths=[45, 25, 30, 30])] - reader_configs = available_readers(as_dict=True) + reader_configs = available_readers(as_dict=True, yaml_loader=BaseLoader) for rc in reader_configs: table.append(rst_table_row([rc.get("long_name", "").rstrip("\n"), rc.get("name", ""), rc.get("status", ""), rc.get("supports_fsspec", "false")])) diff --git a/satpy/composites/config_loader.py b/satpy/composites/config_loader.py index 58f6b2a2bb..4550ca58b9 100644 --- a/satpy/composites/config_loader.py +++ b/satpy/composites/config_loader.py @@ -25,11 +25,7 @@ from typing import Callable, Iterable import yaml - -try: - from yaml import UnsafeLoader -except ImportError: - from yaml import Loader as UnsafeLoader # type: ignore +from yaml import UnsafeLoader import satpy from satpy import DataID, DataQuery diff --git a/satpy/plugin_base.py b/satpy/plugin_base.py index 65660ba1f0..ee19341796 100644 --- a/satpy/plugin_base.py +++ b/satpy/plugin_base.py @@ -20,11 +20,7 @@ import logging import yaml - -try: - from yaml import UnsafeLoader -except ImportError: - from yaml import Loader as UnsafeLoader # type: ignore +from yaml import UnsafeLoader from satpy._config import config_search_paths from satpy.utils import recursive_dict_update diff --git a/satpy/readers/__init__.py b/satpy/readers/__init__.py index a789623f62..de9efd26e4 100644 --- a/satpy/readers/__init__.py +++ b/satpy/readers/__init__.py @@ -26,11 +26,7 @@ from functools import total_ordering import yaml - -try: - from yaml import UnsafeLoader -except ImportError: - from yaml import Loader as UnsafeLoader # type: ignore +from yaml import UnsafeLoader from satpy._config import config_search_paths, get_entry_points_config_dirs, glob_config @@ -370,22 +366,24 @@ def get_valid_reader_names(reader): return new_readers -def available_readers(as_dict=False): +def available_readers(as_dict=False, yaml_loader=UnsafeLoader): """Available readers based on current configuration. Args: as_dict (bool): Optionally return reader information as a dictionary. - Default: False + Default: False. + yaml_loader (Optional[Union[yaml.BaseLoader, yaml.FullLoader, yaml.UnsafeLoader]]): + The yaml loader type. Default: ``yaml.UnsafeLoader``. - Returns: List of available reader names. If `as_dict` is `True` then - a list of dictionaries including additionally reader information - is returned. + Returns: + Union[list[str], list[dict]]: List of available reader names. If `as_dict` is `True` then + a list of dictionaries including additionally reader information is returned. """ readers = [] for reader_configs in configs_for_reader(): try: - reader_info = read_reader_config(reader_configs) + reader_info = read_reader_config(reader_configs, loader=yaml_loader) except (KeyError, IOError, yaml.YAMLError): LOG.debug("Could not import reader config from: %s", reader_configs) LOG.debug("Error loading YAML", exc_info=True) @@ -454,12 +452,12 @@ def find_files_and_readers(start_time=None, end_time=None, base_dir=None, missing_ok (bool): If False (default), raise ValueError if no files are found. If True, return empty dictionary if no files are found. - fs (FileSystem): Optional, instance of implementation of - fsspec.spec.AbstractFileSystem (strictly speaking, - any object of a class implementing ``.glob`` is - enough). Defaults to searching the local filesystem. + fs (:class:`fsspec.spec.AbstractFileSystem`): Optional, instance of implementation of + :class:`fsspec.spec.AbstractFileSystem` (strictly speaking, any object of a class implementing + ``.glob`` is enough). Defaults to searching the local filesystem. - Returns: Dictionary mapping reader name string to list of filenames + Returns: + dict: Dictionary mapping reader name string to list of filenames """ reader_files = {} diff --git a/satpy/readers/yaml_reader.py b/satpy/readers/yaml_reader.py index 2e3203e5a8..97eb7510bd 100644 --- a/satpy/readers/yaml_reader.py +++ b/satpy/readers/yaml_reader.py @@ -26,22 +26,16 @@ from collections import OrderedDict, deque from contextlib import suppress from fnmatch import fnmatch +from functools import cached_property from weakref import WeakValueDictionary import numpy as np import xarray as xr import yaml - -try: - from yaml import UnsafeLoader -except ImportError: - from yaml import Loader as UnsafeLoader # type: ignore - -from functools import cached_property - from pyresample.boundary import AreaDefBoundary, Boundary from pyresample.geometry import AreaDefinition, StackedAreaDefinition, SwathDefinition from trollsift.parser import globify, parse +from yaml import UnsafeLoader from satpy import DatasetDict from satpy.aux_download import DataDownloadMixin diff --git a/satpy/tests/test_readers.py b/satpy/tests/test_readers.py index 6a30ba09fa..3f76e63596 100644 --- a/satpy/tests/test_readers.py +++ b/satpy/tests/test_readers.py @@ -17,7 +17,9 @@ # satpy. If not, see . """Test classes and functions in the readers/__init__.py module.""" +import builtins import os +import sys import unittest from contextlib import suppress from unittest import mock @@ -55,6 +57,8 @@ }, } +real_import = builtins.__import__ + def make_dataid(**items): """Make a data id.""" @@ -625,6 +629,11 @@ def test_old_reader_name_mapping(self): class TestYAMLFiles(unittest.TestCase): """Test and analyze the reader configuration files.""" + def setUp(self): + """Set up monkeypatch.""" + from _pytest.monkeypatch import MonkeyPatch + self.monkeypatch = MonkeyPatch() + def test_filename_matches_reader_name(self): """Test that every reader filename matches the name in the YAML.""" import yaml @@ -662,6 +671,29 @@ def test_available_readers(self): self.assertIn('name', reader_info) self.assertEqual(reader_infos, sorted(reader_infos, key=lambda reader_info: reader_info['name'])) + def test_available_readers_base_loader(self): + """Test the 'available_readers' function for yaml loader type BaseLoader.""" + import yaml + + from satpy import available_readers + from satpy._config import glob_config + + def patched_import_error(name, globals=None, locals=None, fromlist=(), level=0): + if name in ('netcdf4', ): + raise ImportError(f"Mocked import error {name}") + return real_import(name, globals=globals, locals=locals, fromlist=fromlist, level=level) + + self.monkeypatch.delitem(sys.modules, 'netcdf4', raising=False) + self.monkeypatch.setattr(builtins, '__import__', patched_import_error) + + with pytest.raises(ImportError): + import netcdf4 # noqa: F401 + + reader_names = available_readers(yaml_loader=yaml.BaseLoader) + self.assertIn('abi_l1b', reader_names) # needs netcdf4 + self.assertIn('viirs_l1b', reader_names) + self.assertEqual(len(reader_names), len(list(glob_config('readers/*.yaml')))) + class TestGroupFiles(unittest.TestCase): """Test the 'group_files' utility function.""" diff --git a/satpy/utils.py b/satpy/utils.py index e1489a9c19..26efc90bf5 100644 --- a/satpy/utils.py +++ b/satpy/utils.py @@ -31,15 +31,10 @@ import numpy as np import xarray as xr import yaml -from yaml import BaseLoader +from yaml import BaseLoader, UnsafeLoader from satpy import CHUNK_SIZE -try: - from yaml import UnsafeLoader -except ImportError: - from yaml import Loader as UnsafeLoader # type: ignore - _is_logging_on = False TRACE_LEVEL = 5 diff --git a/satpy/writers/__init__.py b/satpy/writers/__init__.py index f31a6008f6..655b42571c 100644 --- a/satpy/writers/__init__.py +++ b/satpy/writers/__init__.py @@ -29,14 +29,9 @@ import numpy as np import xarray as xr import yaml - -try: - from yaml import UnsafeLoader -except ImportError: - from yaml import Loader as UnsafeLoader # type: ignore - from trollimage.xrimage import XRImage from trollsift import parser +from yaml import UnsafeLoader from satpy import CHUNK_SIZE from satpy._config import config_search_paths, get_entry_points_config_dirs, glob_config diff --git a/setup.py b/setup.py index 0e700c37ae..cdddac0058 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,7 @@ pass requires = ['numpy >=1.13', 'pillow', 'pyresample >=1.24.0', 'trollsift', - 'trollimage >1.10.1', 'pykdtree', 'pyyaml', 'xarray >=0.10.1, !=0.13.0', + 'trollimage >1.10.1', 'pykdtree', 'pyyaml >=5.1', 'xarray >=0.10.1, !=0.13.0', 'dask[array] >=0.17.1', 'pyproj>=2.2', 'zarr', 'donfig', 'appdirs', 'pooch', 'pyorbital'] diff --git a/utils/convert_to_ninjotiff.py b/utils/convert_to_ninjotiff.py index 1c3eef595e..e457ee35e3 100644 --- a/utils/convert_to_ninjotiff.py +++ b/utils/convert_to_ninjotiff.py @@ -30,17 +30,12 @@ import os import yaml +from yaml import UnsafeLoader from satpy import Scene from satpy.pyresample import get_area_def from satpy.utils import debug_on -try: - from yaml import UnsafeLoader -except ImportError: - from yaml import Loader as UnsafeLoader # type: ignore - - debug_on() parser = argparse.ArgumentParser(description='Turn an image into a NinjoTiff.')