diff --git a/CHANGELOG.md b/CHANGELOG.md index eb7e430f..479dfd15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). * Added manual test for pysatModels RC pip install * Updated tests to new pysat and pytest standards * Updated model Instruments to include the new `_clean_warn` attribute + * Removed backwards-support for pysat pre-3.0.4 functions * Documentation * Added badges and instructions for PyPi and Zenodo diff --git a/README.md b/README.md index 724eed14..560cfc77 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ pysatModels handles model-centric data loading through pysat and contains a variety of tools to perform model-data analysis, including model validation. -Come join us on Slack! An invitation to the pysat workspace is available +Come join us on Slack! An invitation to the pysat workspace is available in the 'About' section of the [pysat GitHub Repository.](https://github.com/pysat/pysat) @@ -31,7 +31,7 @@ the Space Physics community. This module officially supports Python 3.6+. | ------------------ | ------------------ | | numpy | pyForecastTools | | pandas >= 1.4.0 | pysat >= 3.0.4 | -| requests | pysatNASA >= 0.0.5 | +| requests | pysatNASA | | scipy | | | xarray | | diff --git a/docs/installation.rst b/docs/installation.rst index 7a881357..35bffcb3 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -24,8 +24,8 @@ the Space Physics community. This module officially supports Python 3.6+. Common modules Community modules ============== ================= numpy pysat - pandas pyForecastTools - requests + pandas pysatNASA + requests pyForecastTools scipy xarray ============== ================= @@ -85,7 +85,7 @@ is set up, you may choose to register the the :py:mod:`pysatModel` model .. code:: python - + import pysat import pysatModels as pymod diff --git a/pysatModels/models/sami2py_sami2.py b/pysatModels/models/sami2py_sami2.py index ad0e6222..d7a02392 100644 --- a/pysatModels/models/sami2py_sami2.py +++ b/pysatModels/models/sami2py_sami2.py @@ -23,7 +23,6 @@ import datetime as dt import functools -from packaging import version as pack_version import warnings import xarray as xr @@ -147,26 +146,14 @@ def load(fnames, tag='', inst_id='', **kwargs): file_info['day']): epochs.append(dt.datetime(year, month, day)) - vstr = '3.0.2' # TODO(#112) Remove support for backwards compatibility loaded_data = [] loaded_meta = [] for epoch, fname in zip(epochs, fnames): # Load data - # TODO(#112) Remove backwards compatibility - if pack_version.Version(pysat.__version__) < pack_version.Version(vstr): - data, meta = pysat.utils.load_netcdf4([fname], pandas_format=False, - epoch_name='ut') - data = data.rename({"ut": "time"}) - - # Create datetimes from 'ut' variable - data['time'] = [epoch - + dt.timedelta(seconds=int(val * 3600.0)) - for val in data['time'].values] - else: - data, meta = pysat.utils.load_netcdf4([fname], pandas_format=False, - epoch_name='ut', - epoch_origin=epoch, - epoch_unit='h') + data, meta = pysat.utils.io.load_netcdf([fname], pandas_format=False, + epoch_name='ut', + epoch_origin=epoch, + epoch_unit='h') # Store data/meta for each loop loaded_data.append(data) diff --git a/pysatModels/models/ucar_tiegcm.py b/pysatModels/models/ucar_tiegcm.py index d4186336..1bb827eb 100644 --- a/pysatModels/models/ucar_tiegcm.py +++ b/pysatModels/models/ucar_tiegcm.py @@ -186,13 +186,9 @@ def load(fnames, tag='', inst_id='', **kwargs): """ - # TODO(#114): eventually remove support for multiple pysat versions - if hasattr(pysat.utils, 'io'): - data, meta = pysat.utils.io.load_netcdf(fnames, pandas_format=False, - epoch_name='time', - decode_times=True) - else: - data, meta = pysat.utils.load_netcdf4(fnames, pandas_format=False) + data, meta = pysat.utils.io.load_netcdf(fnames, pandas_format=False, + epoch_name='time', + decode_times=True) # Move misc parameters from xarray to the Instrument object via Meta. # Doing this after `meta` created ensures all metadata is still kept diff --git a/pysatModels/tests/test_methods_general.py b/pysatModels/tests/test_methods_general.py index 0acef864..fdf8d5d2 100644 --- a/pysatModels/tests/test_methods_general.py +++ b/pysatModels/tests/test_methods_general.py @@ -14,7 +14,7 @@ class TestMethodsGeneralLogging(object): """Unit tests for log messages raised by general methods.""" - def setup(self): + def setup_method(self): """Set up the unit test environment.""" self.ch = logging.StreamHandler() self.ch.setLevel(logging.INFO) @@ -22,7 +22,7 @@ def setup(self): return - def teardown(self): + def teardown_method(self): """Clean up the unit test environment.""" del self.ch, self.model @@ -50,7 +50,7 @@ def test_general_clean(self, caplog): class TestMethodsGeneralDownload(object): """Unit tests for general methods handling downloads.""" - def setup(self): + def setup_method(self): """Set up the unit test environment.""" # TODO(#100): remove if-statement when it is always triggered tkwargs = {} @@ -65,7 +65,7 @@ def setup(self): return - def teardown(self): + def teardown_method(self): """Clean up the unit test environment.""" if os.path.isfile(self.out_file): diff --git a/pysatModels/tests/test_models.py b/pysatModels/tests/test_models.py index 72411d63..b6a22736 100644 --- a/pysatModels/tests/test_models.py +++ b/pysatModels/tests/test_models.py @@ -8,159 +8,31 @@ import datetime as dt import os -from packaging import version as pack_version -import pytest import shutil import sys import tempfile +# Import the test classes from pysat import pysat -from pysat.tests.instrument_test_class import InstTestClass +from pysat.tests.classes import cls_instrument_library as clslib import pysatModels # Retrieve the lists of Model instruments and testing methods -instruments = pysat.utils.generate_instrument_list(inst_loc=pysatModels.models) -method_list = [func for func in dir(InstTestClass) - if callable(getattr(InstTestClass, func))] - -# Search tests for iteration via pytestmark, update instrument list -for method in method_list: - if hasattr(getattr(InstTestClass, method), 'pytestmark'): - # Get list of names of pytestmarks - mark_name = [mod_mark.name for mod_mark - in getattr(InstTestClass, method).pytestmark] - - # Add instruments from your library - if 'all_inst' in mark_name: - mark = pytest.mark.parametrize("inst_name", instruments['names']) - getattr(InstTestClass, method).pytestmark.append(mark) - elif 'download' in mark_name: - mark = pytest.mark.parametrize("inst_dict", - instruments['download']) - getattr(InstTestClass, method).pytestmark.append(mark) - elif 'no_download' in mark_name: - mark = pytest.mark.parametrize("inst_dict", - instruments['no_download']) - getattr(InstTestClass, method).pytestmark.append(mark) - - -class TestModels(InstTestClass): +instruments = clslib.InstLibTests.initialize_test_package( + clslib.InstLibTests, inst_loc=pysatModels.models) + + +class TestModels(clslib.InstLibTests): """Main class for instrument tests. Note ---- - Uses class level setup and teardown so that all tests use the same - temporary directory. We do not want to geneate a new tempdir for each test, - as the load tests need to be the same as the download tests. + All standard tests, setup, and teardown inherited from the core pysat + instrument test class. """ - def setup_class(self): - """Initialize the testing setup once before all tests are run.""" - # Make sure to use a temporary directory so that the user setup is not - # altered - # TODO(#100): remove if-statement when it is always triggered - tkwargs = {} - if sys.version_info.major >= 3 and sys.version_info.minor >= 10: - tkwargs = {"ignore_cleanup_errors": True} - self.tempdir = tempfile.TemporaryDirectory(**tkwargs) - self.saved_path = pysat.params['data_dirs'] - pysat.params.data['data_dirs'] = [self.tempdir.name] - - # Assign the location of the model Instrument sub-modules - self.inst_loc = pysatModels.models - return - - def teardown_class(self): - """Clean up downloaded files and parameters from tests.""" - - pysat.params.data['data_dirs'] = self.saved_path - - # TODO(#100): Remove try/except when Python 3.10 is the lowest version - try: - self.tempdir.cleanup() - except Exception: - pass - - del self.inst_loc, self.saved_path, self.tempdir - return - - -class TestSAMIPysatVersion(object): - """Test SAMI load code for pysat version differences across v3.0.2.""" - - def setup_class(self): - """Initialize the testing setup once before all tests are run.""" - # Make sure to use a temporary directory so that the user setup is not - # altered - - # TODO(#100): remove if-statement when it is always triggered - tkwargs = {} - if sys.version_info.major >= 3 and sys.version_info.minor >= 10: - tkwargs = {"ignore_cleanup_errors": True} - self.tempdir = tempfile.TemporaryDirectory(**tkwargs) - self.saved_path = pysat.params['data_dirs'] - self.saved_ver = pysat.__version__ - pysat.params.data['data_dirs'] = [self.tempdir.name] - - # Assign the location of the model Instrument sub-modules - self.inst_loc = pysatModels.models - return - - def teardown_class(self): - """Clean up downloaded files and parameters from tests.""" - - pysat.params.data['data_dirs'] = self.saved_path - pysat.__version__ = self.saved_ver - - # Remove the temporary directory - # TODO(#100): Remove try/except when Python 3.10 is the lowest version - try: - self.tempdir.cleanup() - except Exception: - pass - - del self.inst_loc, self.saved_path, self.tempdir, self.saved_ver - return - - def test_load_failure(self): - """Test for SAMI load failure when faking a different pysat version.""" - - if (pack_version.Version(pysat.__version__) - >= pack_version.Version('3.0.2')): - # Define target error variable label - label = 'ut' - - # Replace reported version with one before 3.0.2 - vlabel = '3.0.1' - - # Expected error - error = ValueError - else: - # Define target error variable label - label = 'epoch_origin' - - # Expected error - error = TypeError - - # Replace reported version with one including 3.0.2 - vlabel = '3.0.2' - - # Update reported pysat version - pysat.__version__ = vlabel - - with pytest.raises(error) as verr: - inst = pysat.Instrument(inst_module=self.inst_loc.sami2py_sami2, - tag='test') - inst.download(self.inst_loc.sami2py_sami2._test_dates['']['test'], - self.inst_loc.sami2py_sami2._test_dates['']['test']) - inst.load(date=self.inst_loc.sami2py_sami2._test_dates['']['test']) - - assert str(verr).find(label) >= 0 - - return - class TestSAMILoadMultipleDays(object): """Test SAMI load code for multiple days.""" diff --git a/pysatModels/tests/test_utils_convert.py b/pysatModels/tests/test_utils_convert.py index bea06b00..ce4ddf3e 100644 --- a/pysatModels/tests/test_utils_convert.py +++ b/pysatModels/tests/test_utils_convert.py @@ -64,7 +64,7 @@ def eval_xarray_output(inst, xdata): class TestUtilsConvertLoadModelXarray(object): """Unit tests for `utils.convert.load_model_xarray`.""" - def setup(self): + def setup_method(self): """Create a clean testing setup before each method.""" self.ftime = pysat.instruments.pysat_testing_xarray._test_dates[''][''] self.filename = "%Y-%m-%d.nofile" @@ -76,7 +76,7 @@ def setup(self): self.xout = None self.temp_file = 'None' - def teardown(self): + def teardown_method(self): """Clean up test environment after each method.""" if os.path.isfile(self.temp_file): os.remove(self.temp_file) @@ -130,11 +130,11 @@ def test_load_inst(self, mkey, mval): class TestUtilsConvertPysatXarray(object): """Unit tests for utils.convert.convert_pysat_to_xarray.""" - def setup(self): + def setup_method(self): """Create a clean testing setup before each method.""" self.ref_time = pysat.instruments.pysat_testing._test_dates[''][''] - def teardown(self): + def teardown_method(self): """Clean up test environment after each method.""" del self.ref_time diff --git a/pysatModels/tests/test_utils_extract.py b/pysatModels/tests/test_utils_extract.py index 19bd6326..5cf9a9aa 100644 --- a/pysatModels/tests/test_utils_extract.py +++ b/pysatModels/tests/test_utils_extract.py @@ -7,7 +7,6 @@ import logging import numpy as np -from packaging import version as pack_version import platform import pytest @@ -20,7 +19,7 @@ class TestUtilsExtractInstThroughMod(object): """Unit tests for `instrument_view_through_model`.""" - def setup(self): + def setup_method(self): """Set up the unit test environment for each method.""" self.inst = pysat.Instrument(platform='pysat', name='testing') @@ -28,9 +27,7 @@ def setup(self): # Load the data in the instruments load_kwargs = {'date': pysat_testmodel._test_dates['']['']} - if(pack_version.Version(pysat.__version__) - > pack_version.Version('3.0.1')): - load_kwargs['use_header'] = True + load_kwargs['use_header'] = True self.inst.load(**load_kwargs) self.model.load(**load_kwargs) @@ -51,7 +48,7 @@ def setup(self): self.out = [] return - def teardown(self): + def teardown_method(self): """Clean up the unit test environment after each method.""" del self.inst, self.model, self.input_args, self.out, self.input_kwargs @@ -198,14 +195,10 @@ def test_success_for_some_already_ran_data(self, caplog): return -@pytest.mark.skipif(pack_version.Version(pysat.__version__) - <= pack_version.Version('3.0.1'), - reason=''.join(('Requires test model in pysat ', - ' v3.0.2 or later.'))) class TestUtilsExtractModObs(TestUtilsExtractInstThroughMod): """Unit tests for `utils.extract.extract_modelled_observations`.""" - def setup(self): + def setup_method(self): """Set up the unit test environment for each method.""" self.inst = pysat.Instrument(platform='pysat', name='testing') @@ -213,9 +206,7 @@ def setup(self): # Load the data in the instruments load_kwargs = {'date': pysat_testmodel._test_dates['']['']} - if(pack_version.Version(pysat.__version__) - > pack_version.Version('3.0.1')): - load_kwargs['use_header'] = True + load_kwargs['use_header'] = True self.inst.load(**load_kwargs) self.model.load(**load_kwargs) @@ -233,7 +224,7 @@ def setup(self): self.out = [] return - def teardown(self): + def teardown_method(self): """Clean up the unit test environment after each method.""" del self.inst, self.model, self.input_args, self.out, self.input_kwargs @@ -344,14 +335,10 @@ def test_success_for_some_already_ran_data(self, caplog): return -@pytest.mark.skipif(pack_version.Version(pysat.__version__) - <= pack_version.Version('3.0.1'), - reason=''.join(('Requires test model in pysat ', - ' v3.0.2 or later.'))) class TestUtilsExtractModObsXarray(TestUtilsExtractModObs): """Xarray unit tests for `utils.extract.extract_modelled_observations`.""" - def setup(self): + def setup_method(self): """Set up the unit test environment for each method.""" self.inst = pysat.Instrument(platform='pysat', name='testing_xarray') @@ -359,9 +346,7 @@ def setup(self): # Load the data in the instruments load_kwargs = {'date': pysat_testmodel._test_dates['']['']} - if(pack_version.Version(pysat.__version__) - > pack_version.Version('3.0.1')): - load_kwargs['use_header'] = True + load_kwargs['use_header'] = True self.inst.load(**load_kwargs) self.model.load(**load_kwargs) @@ -379,21 +364,17 @@ def setup(self): self.out = [] return - def teardown(self): + def teardown_method(self): """Clean up the unit test environment after each method.""" del self.inst, self.model, self.input_args, self.out, self.input_kwargs return -@pytest.mark.skipif(pack_version.Version(pysat.__version__) - <= pack_version.Version('3.0.1'), - reason=''.join(('Requires test model in pysat ', - ' v3.0.2 or later.'))) class TestUtilsExtractModObsXarray2D(TestUtilsExtractModObs): """Xarray unit tests for `utils.extract.extract_modelled_observations`.""" - def setup(self): + def setup_method(self): """Set up the unit test environment for each method.""" self.inst = pysat.Instrument(platform='pysat', name='testing2d_xarray') @@ -401,9 +382,7 @@ def setup(self): # Load the data in the instruments load_kwargs = {'date': pysat_testmodel._test_dates['']['']} - if(pack_version.Version(pysat.__version__) - > pack_version.Version('3.0.1')): - load_kwargs['use_header'] = True + load_kwargs['use_header'] = True self.inst.load(**load_kwargs) self.model.load(**load_kwargs) @@ -421,7 +400,7 @@ def setup(self): self.out = [] return - def teardown(self): + def teardown_method(self): """Clean up the unit test environment after each method.""" del self.inst, self.model, self.input_args, self.out, self.input_kwargs @@ -431,7 +410,7 @@ def teardown(self): class TestUtilsExtractInstModViewXarray(TestUtilsExtractInstThroughMod): """Xarray unit tests for `instrument_view_through_model`.""" - def setup(self): + def setup_method(self): """Run before every method to create a clean testing setup.""" self.inst = pysat.Instrument(platform='pysat', name='testing2d_xarray') @@ -439,9 +418,7 @@ def setup(self): # Load the data in the instruments load_kwargs = {'date': pysat_testmodel._test_dates['']['']} - if(pack_version.Version(pysat.__version__) - > pack_version.Version('3.0.1')): - load_kwargs['use_header'] = True + load_kwargs['use_header'] = True self.inst.load(**load_kwargs) self.model.load(**load_kwargs) @@ -464,7 +441,7 @@ def setup(self): return - def teardown(self): + def teardown_method(self): """Run after every method to clean up previous testing.""" del self.inst, self.model, self.input_args, self.out, self.input_kwargs @@ -475,14 +452,10 @@ def teardown(self): # TODO(#118): fix `instrument_altitude_to_model_pressure` for Windows env @pytest.mark.skipif(platform.system() == "Windows", reason="Broken on windows, see #118") -@pytest.mark.skipif(pack_version.Version(pysat.__version__) - <= pack_version.Version('3.0.1'), - reason=''.join(('Requires test model in pysat ', - ' v3.0.2 or later.'))) class TestUtilsAltitudePressure(object): """Unit tests for `utils.extract.instrument_altitude_to_model_pressure`.""" - def setup(self): + def setup_method(self): """Set up the unit test environment for each method.""" self.inst = pysat.Instrument(platform='pysat', name='testing') @@ -491,9 +464,7 @@ def setup(self): # Load the data in the instruments load_kwargs = {'date': pysat_testmodel._test_dates['']['']} - if(pack_version.Version(pysat.__version__) - > pack_version.Version('3.0.1')): - load_kwargs['use_header'] = True + load_kwargs['use_header'] = True self.inst.load(**load_kwargs) self.model.load(**load_kwargs) @@ -509,7 +480,7 @@ def setup(self): self.out = [] return - def teardown(self): + def teardown_method(self): """Clean up the unit test environment after each method.""" del self.inst, self.model, self.input_args, self.out @@ -611,14 +582,10 @@ def test_alternate_output_names(self): # TODO(#118): fix `instrument_altitude_to_model_pressure` for Windows env @pytest.mark.skipif(platform.system() == "Windows", reason="Broken on windows, see #118") -@pytest.mark.skipif(pack_version.Version(pysat.__version__) - <= pack_version.Version('3.0.1'), - reason=''.join(('Requires test model in pysat ', - ' v3.0.2 or later.'))) class TestUtilsAltitudePressureXarray(TestUtilsAltitudePressure): """Xarray unit tests for `instrument_altitude_to_model_pressure`.""" - def setup(self): + def setup_method(self): """Set up the unit test environment for each method.""" self.inst = pysat.Instrument(platform='pysat', name='testing2d_xarray') @@ -627,9 +594,7 @@ def setup(self): # Load the data in the instruments load_kwargs = {'date': pysat_testmodel._test_dates['']['']} - if(pack_version.Version(pysat.__version__) - > pack_version.Version('3.0.1')): - load_kwargs['use_header'] = True + load_kwargs['use_header'] = True self.inst.load(**load_kwargs) self.model.load(**load_kwargs) @@ -645,7 +610,7 @@ def setup(self): self.out = [] return - def teardown(self): + def teardown_method(self): """Clean up the unit test environment after each method.""" del self.inst, self.model, self.input_args, self.out @@ -653,14 +618,10 @@ def teardown(self): return -@pytest.mark.skipif(pack_version.Version(pysat.__version__) - <= pack_version.Version('3.0.1'), - reason=''.join(('Requires `max_latitude` test Instrument ', - 'support in pysat v3.0.2 or later.'))) class TestUtilsExtractInstModIrregView(object): """Unit tests for `utils.extract.instrument_view_irregular_model`.""" - def setup(self): + def setup_method(self): """Run before every method to create a clean testing setup.""" self.inst = pysat.Instrument(platform='pysat', name='testing', @@ -671,9 +632,7 @@ def setup(self): # Load the data in the instruments load_kwargs = {'date': pysat_testmodel._test_dates['']['']} - if(pack_version.Version(pysat.__version__) - > pack_version.Version('3.0.1')): - load_kwargs['use_header'] = True + load_kwargs['use_header'] = True self.inst.load(**load_kwargs) self.model.load(**load_kwargs) @@ -689,7 +648,7 @@ def setup(self): return - def teardown(self): + def teardown_method(self): """Run after every method to clean up previous testing.""" del self.inst, self.model, self.input_args, self.out, self.in_kwargs @@ -766,14 +725,10 @@ def test_bad_kwarg_input(self, bad_key, bad_val, err_msg): return -@pytest.mark.skipif(pack_version.Version(pysat.__version__) - <= pack_version.Version('3.0.1'), - reason=''.join(('Requires `max_latitude` test Instrument ', - 'support in pysat v3.0.2 or later.'))) class TestUtilsExtractInstModIrregViewXarray(TestUtilsExtractInstModIrregView): """Xarray unit tests for `instrument_view_irregular_model`.""" - def setup(self): + def setup_method(self): """Run before every method to create a clean testing setup.""" self.inst = pysat.Instrument(platform='pysat', name='testing2d_xarray', @@ -784,9 +739,7 @@ def setup(self): # Load the data in the instruments load_kwargs = {'date': pysat_testmodel._test_dates['']['']} - if(pack_version.Version(pysat.__version__) - > pack_version.Version('3.0.1')): - load_kwargs['use_header'] = True + load_kwargs['use_header'] = True self.inst.load(**load_kwargs) self.model.load(**load_kwargs) @@ -802,7 +755,7 @@ def setup(self): return - def teardown(self): + def teardown_method(self): """Run after every method to clean up previous testing.""" del self.inst, self.model, self.input_args, self.out, self.in_kwargs diff --git a/pysatModels/tests/test_utils_testing.py b/pysatModels/tests/test_utils_testing.py index e96177c2..67121924 100644 --- a/pysatModels/tests/test_utils_testing.py +++ b/pysatModels/tests/test_utils_testing.py @@ -18,7 +18,7 @@ class TestUtilsCompareModName(object): """Unit tests for `compare_mod_name_coordinates`.""" - def setup(self): + def setup_method(self): """Set up the unit test environment for each method.""" self.model = pysat.Instrument(inst_module=pysat_testmodel, tag='') @@ -33,7 +33,7 @@ def setup(self): return - def teardown(self): + def teardown_method(self): """Clean up the unit test environment after each method.""" del self.model @@ -99,7 +99,7 @@ def test_compare_model_name_coordinates_failure(self, var, coords, msg, class TestUtilsCompareModNamePressure(TestUtilsCompareModName): """Unit tests for `compare_mod_name_coordinates`.""" - def setup(self): + def setup_method(self): """Set up the unit test environment for each method.""" self.model = pysat.Instrument(inst_module=pysat_testmodel, diff --git a/requirements.txt b/requirements.txt index f180b4ca..540b4e62 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ packaging pandas pyForecastTools pysat >= 3.0.4 -pysatNASA >= 0.0.5 +pysatNASA requests scipy xarray