Repository: MHKiT-Software/MHKiT-Python (language: python)

Issue:
Testing Consultation Summary
I had a meeting with the testing group at Sandia this week and wanted to record some of the discussion.

I met with Reed and Miranda from the group [1424](https://cfwebprod.sandia.gov/cfdocs/CompResearch/templates/insert/dept.cfm?org=01424). MIranda works on Pyomo ([Website](http://www.pyomo.org/) | [Github](http://www.pyomo.org/)).

Suggestions for MHKiT from the initial consultation:
1. The most immediate thing MHKiT needs to tackle is to move from nose tests to pytests bc nose tests are at their end of life and will not work with py 3.10.
2. Tests local to module. Meaning that wave tests are in the wave folder. This structural change is not needed at our current stage but as the structure of MHKiT grows it is expected that the package and thereby the test organization tends to become more abstract. Having tests in the module which the tests.
3. conda install. The team found it strange that we installed miniconda but used pip install. They were okay with the tests working that way if that is how our documentation suggests to do it, but recommended we add conda install support. If we do add conda install support they further recommended we test our package with both pip install and conda install because the packages in conda tend to diffeer from pip (pip is most up to date).
4. Separate out the API calls into separate serial tests. Currently, I have hacked together a solution to avoid calling the AWS hindcast data server too many times during testing. The team suggested I break out those specific test to run in serial on their own "build" (to use GitHub actions terminology).
5. There were further recommendations around using mocks and cashing data that is calculated/  read into memory to optimize our tests.
6. Add workflow dispatch to tests

My plan is to begin working on the ones that need attention in comming weeks in parallel with our other activities.







Discussion / hints:

Fix patch:
diff --git a/.github/workflows/.coveragehindcastrc b/.github/workflows/.coveragehindcastrc
new file mode 100644
index 000000000..a6399d5ca
--- /dev/null
+++ b/.github/workflows/.coveragehindcastrc
@@ -0,0 +1,7 @@
+[run]
+include =
+    ./mhkit/wave/io/hindcast.py
+
+[report]
+include =
+    ./mhkit/wave/io/hindcast.py
diff --git a/.github/workflows/.coveragerc b/.github/workflows/.coveragerc
new file mode 100644
index 000000000..8239a4e47
--- /dev/null
+++ b/.github/workflows/.coveragerc
@@ -0,0 +1,11 @@
+[run]
+omit =
+    # omit everything in tests and /wave
+    ./mhkit/tests/*
+    ./mhkit/wave/io/hindcast.py
+
+[report]
+omit =
+    # omit everything in tests and /wave
+    ./mhkit/tests/*    
+    ./mhkit/wave/io/hindcast.py
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 00f4e04b8..5798bd8b1 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -2,10 +2,10 @@ name: Py 3.7 3.8, 3.9 | Windows Mac Linux
 
 on:
   push:
-    branches: [ master ]
+    branches: [master]
   pull_request:
-    branches: 
-      - master 
+    branches:
+      - master
       - Develop
 
 jobs:
@@ -19,67 +19,47 @@ jobs:
         python-version: [3.7, 3.8, 3.9]
 
     steps:
-      
-    - uses: actions/checkout@v2
-
-    - name: Setup Conda
-      uses: s-weigand/setup-conda@v1
-      with:
-        activate-conda: false
-        conda-channels: conda-forge
-
-    - name: Python ${{ matrix.python-version }}
-      shell: bash -l {0}
-      run: |
-        conda create --name TEST python=${{ matrix.python-version }} numpy cython pip pytest hdf5 libnetcdf cftime netcdf4 --strict-channel-priority
-        source activate TEST
-        export PATH="${CONDA_PREFIX}/bin:${CONDA_PREFIX}/Library/bin:$PATH" # so setup.py finds nc-config
-        pip install -e . --no-deps --force-reinstall
-        conda info --all
-        conda list
-
-    - name: Tests
-      shell: bash -l {0}
-      run: |
-        source activate TEST
-        python -m pip install --upgrade pip wheel
-        pip install cython
-        pip install h5py --upgrade --no-dependencies --force
-        pip install h5pyd --upgrade
-        echo "THE PATH: $PATH"        
-        pip install nose
-        pip install pytest
-        pip install coveralls
-        pip install .
-        
-    - name: Run nose
-      shell: bash -l {0}
-      run: |          
-        source activate TEST
-        nosetests -v --traverse-namespace --with-coverage --cover-package=mhkit mhkit
-
-    - name: Upload coverage data to coveralls.io
-      shell: bash -l {0}
-      run: |
-        source activate TEST
-        coveralls --service=github
-      env:
-        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-        COVERALLS_FLAG_NAME: ${{ matrix.python-version }}
-        COVERALLS_PARALLEL: true
-  coveralls:
-    name: Indicate completion to coveralls.io
-    needs: conda-build
-    runs-on: ubuntu-latest
-    container: python:3-slim
-    steps:
-    - name: Finished
-      run: |
-        pip3 install --upgrade coveralls
-        coveralls --finish
-      env:
-        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      - uses: actions/checkout@v2
+
+      - name: Setup Conda
+        uses: s-weigand/setup-conda@v1
+        with:
+          activate-conda: false
+          conda-channels: conda-forge
+
+      - name: Python ${{ matrix.python-version }}
+        shell: bash -l {0}
+        run: |
+          conda create --name TEST python=${{ matrix.python-version }} numpy cython pip pytest hdf5 libnetcdf cftime netcdf4 --strict-channel-priority
+          source activate TEST
+          export PATH="${CONDA_PREFIX}/bin:${CONDA_PREFIX}/Library/bin:$PATH" # so setup.py finds nc-config
+          pip install -e . --no-deps --force-reinstall
+
+      - name: Tests
+        shell: bash -l {0}
+        run: |
+          source activate TEST
+          python -m pip install --upgrade pip wheel
+          pip install coverage
+          pip install pytest
+          pip install coveralls
+          pip install .
+
+      - name: Run pytest
+        shell: bash -l {0}
+        run: |
+          source activate TEST
+          coverage run --rcfile=.github/workflows/.coveragerc --source=./mhkit/ -m pytest -c .github/workflows/pytest.ini
 
+      - name: Upload coverage data to coveralls.io
+        shell: bash -l {0}
+        run: |
+          source activate TEST
+          coveralls --service=github
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          COVERALLS_FLAG_NAME: ${{ matrix.python-version }}
+          COVERALLS_PARALLEL: true
 
   pip-build:
     name: pip-${{ matrix.os }}/${{ matrix.python-version }}
@@ -91,31 +71,44 @@ jobs:
         python-version: [3.8, 3.9]
 
     steps:
+      - uses: conda-incubator/setup-miniconda@v2
 
-    - uses: conda-incubator/setup-miniconda@v2
-    
-    - name: Set up Python ${{ matrix.python-version }}
-      uses: actions/setup-python@v2
-      with:
-        python-version: ${{ matrix.python-version }}
-    - name: Set up Git repository
-      uses: actions/checkout@v2
-      
-
-    - name: Update and install packages
-      run: |
-        python -m pip install --upgrade pip wheel
-        pip install cython
-        pip install h5py --upgrade --no-dependencies --force
-        pip install h5pyd --upgrade
-        echo "THE PATH: $PATH"        
-        pip install nose
-        pip install pytest
-        pip install coveralls
-        pip install .
-        
-    - name: Run nose
-      shell: bash -l {0}
-      run: |          
-        nosetests -v --traverse-namespace --with-coverage --cover-package=mhkit mhkit
+      - name: Set up Python ${{ matrix.python-version }}
+        uses: actions/setup-python@v2
+        with:
+          python-version: ${{ matrix.python-version }}
 
+      - name: Set up Git repository
+        uses: actions/checkout@v2
+
+      - name: Update and install packages
+        run: |
+          python -m pip install --upgrade pip wheel
+          pip install coverage
+          pip install pytest
+          pip install coveralls
+          pip install .
+
+      - name: Run pytest
+        run: |
+          coverage run --rcfile=.github/workflows/.coveragerc --source=./mhkit/  -m pytest -c .github/workflows/pytest.ini
+
+      - name: Upload coverage data to coveralls.io
+        run: coveralls --service=github
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          COVERALLS_FLAG_NAME: ${{ matrix.python-version }}
+          COVERALLS_PARALLEL: true
+
+  coveralls:
+    name: Indicate completion to coveralls.io
+    needs: [conda-build, pip-build]
+    runs-on: ubuntu-latest
+    container: python:3-slim
+    steps:
+      - name: Finished
+        run: |
+          pip3 install --upgrade coveralls
+          coveralls --finish
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.pypirc b/.pypirc
new file mode 100644
index 000000000..be070c7e6
--- /dev/null
+++ b/.pypirc
@@ -0,0 +1,7 @@
+[distutils]
+index-servers=pypi
+ 
+[pypi]
+repository = https://upload.pypi.org/legacy/
+username = <username>
+password = <password>
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index b5b2c4f0e..852720ac9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
-pandas>=1.0.0
+pandas>=1.0.0, <=1.5.0
 numpy>=1.21.0
 scipy
 matplotlib
@@ -9,7 +9,8 @@ lxml
 scikit-learn
 NREL-rex>=0.2.63
 six>=1.13.0
-h5py
-netCDF4
-xarray
+h5py>=3.6.0
+h5pyd>=0.7.0, <=0.10.3
+netCDF4>=1.5.8
+xarray<=2022.9.0
 statsmodels
diff --git a/setup.py b/setup.py
index 7a6f4f173..4caed3791 100644
--- a/setup.py
+++ b/setup.py
@@ -17,8 +17,8 @@
                'Intended Audience :: Science/Research',
                'Operating System :: OS Independent',
                ]
-DEPENDENCIES = ['pandas',
-                'numpy',
+DEPENDENCIES = ['pandas>=1.0.0, <=1.5.0',
+                'numpy>=1.21.0',
                 'scipy',
                 'matplotlib',
                 'requests',
@@ -28,9 +28,10 @@
                 'scikit-learn',
                 'NREL-rex>=0.2.63',
                 'six>=1.13.0',
-                'h5py',                
-                'netCDF4',
-                'xarray',
+                'h5py>=3.6.0',
+                'h5pyd >=0.7.0, <=0.10.3',
+                'netCDF4<=1.5.8',
+                'xarray<=2022.9.0',
                 'statsmodels',
                 'pytz',
                 'dolfyn>=1.0.0']


Test patch:
diff --git a/.github/workflows/pytest-hindcast.ini b/.github/workflows/pytest-hindcast.ini
new file mode 100644
index 000000000..a9d6709ff
--- /dev/null
+++ b/.github/workflows/pytest-hindcast.ini
@@ -0,0 +1,2 @@
+[pytest]
+addopts = ./mhkit/tests/wave/io/test_hindcast.py
\ No newline at end of file
diff --git a/.github/workflows/pytest.ini b/.github/workflows/pytest.ini
new file mode 100644
index 000000000..56b7445e9
--- /dev/null
+++ b/.github/workflows/pytest.ini
@@ -0,0 +1,2 @@
+[pytest]
+addopts = --ignore=./mhkit/tests/wave/io/test_hindcast.py
\ No newline at end of file
diff --git a/mhkit/tests/wave/io/test_hindcast.py b/mhkit/tests/wave/io/test_hindcast.py
index 21ca0e85a..d65e2c109 100644
--- a/mhkit/tests/wave/io/test_hindcast.py
+++ b/mhkit/tests/wave/io/test_hindcast.py
@@ -22,7 +22,6 @@
 
 
 testdir = dirname(abspath(__file__))
-# datadir = normpath(join(testdir,relpath('../../../../examples/data/wave')))
 datadir = normpath(join(testdir,'..','..','..','..','examples','data','wave'))
 
 
@@ -78,58 +77,49 @@ def setUpClass(self):
     def tearDownClass(self):
         pass
 
-    ## WPTO hindcast data
-    #   only run test for one version of python per to not spam the server
-    #   yet keep coverage high on each test
-    if float(sys.version[0:3]) == 3.7:
-        def test_multi_year(self):
-            data_type = '3-hour'
-            years = [1990,1992]
-            lat_lon = (44.624076,-124.280097)
-            parameters = 'significant_wave_height'
-            (wave_multiyear,
-            meta) = (wave.io.hindcast
-                    .request_wpto_point_data(data_type,parameters,
-                                            lat_lon,years))
-            assert_frame_equal(self.my_swh,wave_multiyear)
-            assert_frame_equal(self.my_meta,meta)
-
-    elif float(sys.version[0:3]) == 3.8:
-        # wait five minute to ensure python 3.7 call is complete
-        time.sleep(300)
-        def test_multi_loc(self):
-            data_type = '3-hour'
-            years = [1995]
-            lat_lon = ((44.624076,-124.280097),(43.489171,-125.152137))
-            parameters = 'mean_absolute_period'
-            wave_multiloc, meta=(wave.io.hindcast
-                                .request_wpto_point_data(data_type,
-                                              parameters,lat_lon,years))
-            (dir_multiyear,
-            meta_dir)=(wave.io.hindcast
-                       .request_wpto_directional_spectrum(lat_lon,year='1995'))
-            dir_multiyear = dir_multiyear.sel(time_index=slice(dir_multiyear.time_index[0],dir_multiyear.time_index[99]))
-            dir_multiyear = dir_multiyear.rename_vars({87:'87',58:'58'})
-
-            assert_frame_equal(self.ml,wave_multiloc)
-            assert_frame_equal(self.ml_meta,meta)
-            xrt.assert_allclose(self.my_dir,dir_multiyear)
-            assert_frame_equal(self.my_dir_meta,meta_dir)
-
-    elif float(sys.version[0:3]) == 3.9:
-        # wait ten minutes to ensure python 3.7 and 3.8 call is complete
-        time.sleep(500)
-
-        def test_multi_parm(self):
-            data_type = '1-hour'
-            years = [1996]
-            lat_lon = (44.624076,-124.280097)
-            parameters = ['energy_period','mean_zero-crossing_period']
-            wave_multiparm, meta= wave.io.hindcast.request_wpto_point_data(data_type,
-            parameters,lat_lon,years)
-
-            assert_frame_equal(self.mp,wave_multiparm)
-            assert_frame_equal(self.mp_meta,meta)
+
+    def test_multi_year(self):
+        data_type = '3-hour'
+        years = [1990,1992]
+        lat_lon = (44.624076,-124.280097)
+        parameters = 'significant_wave_height'
+        (wave_multiyear,
+        meta) = (wave.io.hindcast
+                .request_wpto_point_data(data_type,parameters,
+                                        lat_lon,years))
+        assert_frame_equal(self.my_swh,wave_multiyear)
+        assert_frame_equal(self.my_meta,meta)
+
+    def test_multi_loc(self):
+        data_type = '3-hour'
+        years = [1995]
+        lat_lon = ((44.624076,-124.280097),(43.489171,-125.152137))
+        parameters = 'mean_absolute_period'
+        wave_multiloc, meta=(wave.io.hindcast
+                            .request_wpto_point_data(data_type,
+                                            parameters,lat_lon,years))
+        (dir_multiyear,
+        meta_dir)=(wave.io.hindcast
+                    .request_wpto_directional_spectrum(lat_lon,year='1995'))
+        dir_multiyear = dir_multiyear.sel(time_index=slice(dir_multiyear.time_index[0],dir_multiyear.time_index[99]))
+        dir_multiyear = dir_multiyear.rename_vars({87:'87',58:'58'})
+
+        assert_frame_equal(self.ml,wave_multiloc)
+        assert_frame_equal(self.ml_meta,meta)
+        xrt.assert_allclose(self.my_dir,dir_multiyear)
+        assert_frame_equal(self.my_dir_meta,meta_dir)
+
+
+    def test_multi_parm(self):
+        data_type = '1-hour'
+        years = [1996]
+        lat_lon = (44.624076,-124.280097)
+        parameters = ['energy_period','mean_zero-crossing_period']
+        wave_multiparm, meta= wave.io.hindcast.request_wpto_point_data(data_type,
+        parameters,lat_lon,years)
+
+        assert_frame_equal(self.mp,wave_multiparm)
+        assert_frame_equal(self.mp_meta,meta)
 
 
 if __name__ == '__main__':