Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4f58676
Version: Bump to 1.1.0
simmsa Jun 29, 2026
3cca334
Examples: Update NLR/NatLabRockies links
simmsa Jun 29, 2026
e33f4c7
Dev: Lint
simmsa Jun 29, 2026
7479ddd
HSDS: Add note about HSDS domain and endpoint changes
simmsa Jun 29, 2026
321a767
HSDS: Set endpoint to developer.nlr.gov
simmsa Jun 29, 2026
e7c1e4e
Fix: Add alternative way to access meta for rex/hsds hindcast calls
simmsa Jun 29, 2026
cd8b377
Merge remote-tracking branch 'upstream/develop' into feat_prep_v1.1_r…
simmsa Jun 29, 2026
9c06a39
Fix: hindcast, Use s3 fallback for any HSDS read
simmsa Jun 29, 2026
cec82ef
Deps: Update rex to NLR-rex with hsds feature
simmsa Jun 29, 2026
84fcd86
HSDS: Store and use HSDS api key as Github Secret
simmsa Jun 29, 2026
8464197
Revert "HSDS: Store and use HSDS api key as Github Secret"
simmsa Jun 30, 2026
973ba90
Hindcast: Add fallback to read wave hindcast h5 data directly from S3
simmsa Jun 30, 2026
b048bb8
Hindcast: Revert out of scope hindcast fixes
simmsa Jun 30, 2026
bf926a4
Actions: Disable hindcast tests due to non functional api
simmsa Jun 30, 2026
d2d4e33
Hindcast: Add generic hindcast exception decorator
simmsa Jun 30, 2026
686851a
Hindcast: Wire up hindcast exception guard decorator
simmsa Jun 30, 2026
a566516
Tests: Temporarily disable hindcast tests
simmsa Jun 30, 2026
a0e4caf
NOAA: Add retries to api calls that can intermittently fail
simmsa Jun 30, 2026
888682e
NOAA: fix lints issues in _make_request
simmsa Jun 30, 2026
f71a2bb
Tests: Disable NOAA tidal api calls because endpoint is returning 504
simmsa Jun 30, 2026
a5ea293
Dev: Lint
simmsa Jun 30, 2026
02b1bad
Revert: NOAA request changes:
simmsa Jun 30, 2026
8f0afc4
Actions: Run tests in this PR on all operating systems as a sanity check
simmsa Jun 30, 2026
7bcbf37
Actions: Only upload to coveralls on pr's into main and pushes to main
simmsa Jun 30, 2026
b866a55
Actions: Add single action for coveralls uploads
simmsa Jun 30, 2026
c230467
Actions: Verify that coveralls still works on all operating systems
simmsa Jun 30, 2026
afc771f
Actions: Migrate macos-latest to macos-26:
simmsa Jun 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/actions/upload-coverage/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Upload coverage to Coveralls
description: Install the macOS reporter if needed and upload lcov coverage to Coveralls.

inputs:
github-token:
description: Token used to authenticate with Coveralls.
required: true
flag-name:
description: Unique flag identifying this coverage job.
required: true
fail-on-error:
description: Whether an upload failure should fail the job.
required: false
default: "true"

runs:
using: composite
steps:
# Fix for coveralls on homebrew 6+: https://github.com/coverallsapp/github-action/pull/265
- name: Install coveralls reporter (macOS)
if: runner.os == 'macOS'
shell: bash
run: brew install coverallsapp/coveralls/coveralls --quiet

- name: Upload coverage data to coveralls.io
uses: coverallsapp/github-action@v2
with:
github-token: ${{ inputs.github-token }}
flag-name: ${{ inputs.flag-name }}
parallel: true
path-to-lcov: ./coverage.lcov
fail-on-error: ${{ inputs.fail-on-error }}
80 changes: 58 additions & 22 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ env:
CONDA_ENVIRONMENT_NAME: mhkit-dev-env
# Coveralls: Set to false to ignore upload failures during outages.
# Check status: https://status.coveralls.io/
# Note this only affects the code coverage percentage badge in the README, nothing else
COVERALLS_FAIL_ON_ERROR: true

jobs:
Expand All @@ -36,12 +37,43 @@ jobs:
steps:
- id: set-matrix
run: |
if [[ "${{ github.event_name }}" == "pull_request" && "${{ github.base_ref }}" == "develop" ]]; then
echo "matrix_os=[ \"ubuntu-latest\"]" >> $GITHUB_OUTPUT
else
echo "matrix_os=[\"windows-latest\", \"ubuntu-latest\", \"macos-latest\"]" >> $GITHUB_OUTPUT
fi

# TEMP(all-os): Force all operating systems for this PR. Restore the
# block below to go back to the develop-only ubuntu shortcut.
echo "matrix_os=[\"windows-latest\", \"ubuntu-latest\", \"macos-26\"]" >> $GITHUB_OUTPUT
# if [[ "${{ github.event_name }}" == "pull_request" && "${{ github.base_ref }}" == "develop" ]]; then
# echo "matrix_os=[ \"ubuntu-latest\"]" >> $GITHUB_OUTPUT
# else
# echo "matrix_os=[\"windows-latest\", \"ubuntu-latest\", \"macos-26\"]" >> $GITHUB_OUTPUT
# fi


# `coveralls-gate` controls whether code coverage data is uploaded to coveralls.
# The README code coverage badge is main-only. Because this is a simple metric we don't need to
# calculate this for every code push, just the ones that can change the badge coverage percentage
#
# Specific code changes that require coveralls are:
# * a PR targeting main
# * a push to main
# Coveralls badge:
# <img src="https://github.com/MHKiT-Software/MHKiT-Python/actions/workflows/main.yml/badge.svg">
coveralls-gate:
runs-on: ubuntu-latest
outputs:
should-upload: ${{ steps.gate.outputs.should-upload }}
steps:
- id: gate
run: |
# TEMP(test-coveralls): Force coveralls upload on every run to test the
# macOS reporter fix. Restore the gate logic below when done.
echo "should-upload=true" >> "$GITHUB_OUTPUT"
# should_upload=false
# if [[ "${{ github.event_name }}" == "pull_request" && "${{ github.base_ref }}" == "main" ]]; then
# should_upload=true
# fi
# if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/heads/main" ]]; then
# should_upload=true
# fi
# echo "should-upload=$should_upload" >> "$GITHUB_OUTPUT"

# This job decides if the hindcast test suite should run.
check-changes:
Expand All @@ -64,11 +96,15 @@ jobs:

- id: hindcast-logic
run: |
if [[ "${{ github.event.pull_request.base.ref }}" == "main" || "${{ steps.changes.outputs.wave_io_hindcast }}" == "true" ]]; then
echo "should-run-hindcast=true" >> "$GITHUB_OUTPUT"
else
echo "should-run-hindcast=false" >> "$GITHUB_OUTPUT"
fi
# TODO(restore-hindcast): NLR HSDS endpoint is down for v1.1, so hindcast
# jobs are disabled. Restore the logic below when the service is back online.
# See https://github.com/MHKiT-Software/MHKiT-Python/issues/450
echo "should-run-hindcast=false" >> "$GITHUB_OUTPUT"
# if [[ "${{ github.event.pull_request.base.ref }}" == "main" || "${{ steps.changes.outputs.wave_io_hindcast }}" == "true" ]]; then
# echo "should-run-hindcast=true" >> "$GITHUB_OUTPUT"
# else
# echo "should-run-hindcast=false" >> "$GITHUB_OUTPUT"
# fi

prepare-nonhindcast-cache:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -201,7 +237,7 @@ jobs:

conda-forge-build:
name: conda-forge-${{ matrix.os }}/${{ matrix.python-version }}
needs: [set-os, prepare-nonhindcast-cache]
needs: [set-os, prepare-nonhindcast-cache, coveralls-gate]
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
Expand Down Expand Up @@ -249,17 +285,16 @@ jobs:
coverage lcov

- name: Upload coverage data to coveralls.io
uses: coverallsapp/github-action@v2
if: needs.coveralls-gate.outputs.should-upload == 'true'
uses: ./.github/actions/upload-coverage
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
flag-name: conda-forge-${{ runner.os }}-py${{ matrix.python-version }}
parallel: true
path-to-lcov: ./coverage.lcov
fail-on-error: ${{ env.COVERALLS_FAIL_ON_ERROR }}

pip-build:
name: pip-${{ matrix.os }}/${{ matrix.python-version }}
needs: [set-os, prepare-nonhindcast-cache]
needs: [set-os, prepare-nonhindcast-cache, coveralls-gate]
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
Expand Down Expand Up @@ -310,12 +345,11 @@ jobs:
coverage lcov

- name: Upload coverage data to coveralls.io
uses: coverallsapp/github-action@v2
if: needs.coveralls-gate.outputs.should-upload == 'true'
uses: ./.github/actions/upload-coverage
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
flag-name: pip-${{ runner.os }}-py${{ matrix.python-version }}
parallel: true
path-to-lcov: ./coverage.lcov
fail-on-error: ${{ env.COVERALLS_FAIL_ON_ERROR }}

hindcast-calls:
Expand All @@ -326,6 +360,7 @@ jobs:
prepare-wave-hindcast-cache,
prepare-wind-hindcast-cache,
set-os,
coveralls-gate,
]
if: (needs.check-changes.outputs.should-run-hindcast == 'true')

Expand Down Expand Up @@ -388,12 +423,11 @@ jobs:
coverage lcov

- name: Upload coverage data to coveralls.io
uses: coverallsapp/github-action@v2
if: needs.coveralls-gate.outputs.should-upload == 'true'
uses: ./.github/actions/upload-coverage
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
flag-name: hindcast-${{ runner.os }}-py${{ matrix.python-version }}
parallel: true
path-to-lcov: ./coverage.lcov
fail-on-error: ${{ env.COVERALLS_FAIL_ON_ERROR }}

test-wheel-packaging:
Expand Down Expand Up @@ -636,9 +670,11 @@ jobs:
conda-forge-build,
pip-build,
hindcast-calls,
coveralls-gate,
]
if: |
always() &&
needs.coveralls-gate.outputs.should-upload == 'true' &&
(
(
needs.conda-forge-build.result == 'success' &&
Expand Down
2 changes: 1 addition & 1 deletion .hscfg
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
hs_endpoint = https://developer.nrel.gov/api/hsds
hs_endpoint = https://developer.nlr.gov/api/hsds
hs_username =
hs_password =
hs_api_key = jODGciIBnejrYd9GXxgXjbbAjMDLBMWQer05P98N
7 changes: 6 additions & 1 deletion environment-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,10 @@ dependencies:
- notebook
- matplotlib>=3.9.1
- fatpack
- nrel-rex
- cartopy
# rex is installed from PyPI (NLR-rex), not conda-forge. The conda-forge
# `nrel-rex` is frozen at 0.2.84, which predates the s3:// fsspec support
# needed to read the wave hindcast .h5 files directly from S3. The [hsds] extra
# pulls the HSDS client dependencies the hindcast reads use.
- pip:
- NLR-rex[hsds]>=0.5.0
4 changes: 2 additions & 2 deletions examples/WPTO_hindcast_example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@
"\n",
"### Setting up Access to WPTO Hindcast Data\n",
"To access the WPTO hindcast data, you will need to configure h5pyd for data access on HSDS. \n",
" To get your own API key, visit https://developer.nrel.gov/signup/. \n",
" To get your own API key, visit https://developer.nlr.gov/signup/. \n",
"\n",
"To configure h5phd type:\n",
"\n",
" hsconfigure\n",
" \n",
"and enter at the prompt:\n",
"\n",
" hs_endpoint = https://developer.nrel.gov/api/hsds\n",
" hs_endpoint = https://developer.nlr.gov/api/hsds\n",
" hs_username = None\n",
" hs_password = None\n",
" hs_api_key = {your key}\n",
Expand Down
8 changes: 4 additions & 4 deletions examples/metocean_example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@
"source": [
"## 2. Request Surface Wind Data from WIND Toolkit\n",
"\n",
"MHKiT can be used to request historical data from [WIND Toolkit](https://www.nrel.gov/grid/wind-toolkit.html). The WIND Toolkit is a high-spatial-resolution dataset of meteorological parameters covering several offshore regions including California, Hawaii, the Northwest Pacific, and the Mid-Atlantic. The offshore datasets span 2000-2019 (or to 2020 for the Mid-Atlantic region). \n",
"MHKiT can be used to request historical data from [WIND Toolkit](https://www.nlr.gov/grid/wind-toolkit). The WIND Toolkit is a high-spatial-resolution dataset of meteorological parameters covering several offshore regions including California, Hawaii, the Northwest Pacific, and the Mid-Atlantic. The offshore datasets span 2000-2019 (or to 2020 for the Mid-Atlantic region). \n",
"\n",
"\n",
"### Included Variables: \n",
Expand All @@ -588,7 +588,7 @@
"\n",
"### Setting up Access to WIND Toolkit\n",
"To access the WIND Toolkit, you will need to configure h5pyd for data access on HSDS. \n",
"To get your own API key, visit https://developer.nrel.gov/signup/. \n",
"To get your own API key, visit https://developer.nlr.gov/signup/. \n",
"If you have already accessed WPTO Hindcast data, you may skip this step.\n",
"\n",
"To configure h5pyd type:\n",
Expand All @@ -597,7 +597,7 @@
" \n",
"and enter at the prompt:\n",
"\n",
" hs_endpoint = https://developer.nrel.gov/api/hsds\n",
" hs_endpoint = https://developer.nlr.gov/api/hsds\n",
" hs_username = None\n",
" hs_password = None\n",
" hs_api_key = {your key}\n",
Expand All @@ -615,7 +615,7 @@
"* location\n",
"* year\n",
"\n",
"A full list of available historical parameters can be found [here](https://github.com/NREL/hsds-examples/blob/master/datasets/WINDToolkit.md#model). Here we are interested in historical surface wind data (`'windspeed_10m'`, `'winddirection_10m'`) and a vertical temperature profile. For demonstration purposes, not all temperature elevations will be used. Additionally, we will use the latitude and longitude of NDBC buoy `'46022'` to later compare to the NDBC dataset. The buoy location can be found [here](https://www.ndbc.noaa.gov/data/stations/station_table.txt). The `elevation_to_string` can be used to easily combine an array of elevations with a parameter name to create the correctly formatted parameter string. This is demonstrated for the array of temperature parameters."
"A full list of available historical parameters can be found [here](https://github.com/NatLabRockies/hsds-examples/blob/master/datasets/WINDToolkit.md#model). Here we are interested in historical surface wind data (`'windspeed_10m'`, `'winddirection_10m'`) and a vertical temperature profile. For demonstration purposes, not all temperature elevations will be used. Additionally, we will use the latitude and longitude of NDBC buoy `'46022'` to later compare to the NDBC dataset. The buoy location can be found [here](https://www.ndbc.noaa.gov/data/stations/station_table.txt). The `elevation_to_string` can be used to easily combine an array of elevations with a parameter name to create the correctly formatted parameter string. This is demonstrated for the array of temperature parameters."
]
},
{
Expand Down
2 changes: 1 addition & 1 deletion mhkit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

configure_warnings()

__version__ = "v1.0.1"
__version__ = "v1.1.0"

__copyright__ = """
Copyright 2019, Alliance for Energy Innovation, LLC under the terms of
Expand Down
16 changes: 15 additions & 1 deletion mhkit/tests/tidal/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import numpy as np
import mhkit.tidal as tidal


testdir = dirname(abspath(__file__))
plotdir = join(testdir, "plots")
isdir = os.path.isdir(plotdir)
Expand Down Expand Up @@ -68,6 +67,11 @@ def test_load_noaa_data_xarray(self):
self.assertEqual(len(data["index"]), 18890)
self.assertEqual(data.attrs["id"], "s08010")

# TODO(noaa_api_failures): NOAA Tides and Currents API intermittently
# returns 504 Gateway Timeout, causing this test to fail in CI. Re-enable
# once the upstream API is reliable. See
# https://github.com/MHKiT-Software/MHKiT-Python/issues/451
@unittest.skip("NOAA API intermittently unavailable; see issue #451")
def test_request_noaa_data_basic(self):
"""
Test the request_noaa_data function with basic input parameters
Expand All @@ -89,6 +93,11 @@ def test_request_noaa_data_basic(self):
self.assertEqual(data.shape, (183, 3))
self.assertEqual(metadata["id"], "s08010")

# TODO(noaa_api_failures): NOAA Tides and Currents API intermittently
# returns 504 Gateway Timeout, causing this test to fail in CI. Re-enable
# once the upstream API is reliable. See
# https://github.com/MHKiT-Software/MHKiT-Python/issues/451
@unittest.skip("NOAA API intermittently unavailable; see issue #451")
def test_request_noaa_data_basic_xarray(self):
"""
Test the request_noaa_data function with basic input parameters
Expand Down Expand Up @@ -116,6 +125,11 @@ def test_request_noaa_data_basic_xarray(self):
self.assertEqual(len(data["index"]), 183)
self.assertEqual(data.attrs["id"], "s08010")

# TODO(noaa_api_failures): NOAA Tides and Currents API intermittently
# returns 504 Gateway Timeout, causing this test to fail in CI. Re-enable
# once the upstream API is reliable. See
# https://github.com/MHKiT-Software/MHKiT-Python/issues/451
@unittest.skip("NOAA API intermittently unavailable; see issue #451")
def test_request_noaa_data_write_json(self):
"""
Test the request_noaa_data function with the write_json parameter
Expand Down
7 changes: 6 additions & 1 deletion mhkit/tests/wave/io/hindcast/test_hindcast.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import unittest
from os.path import abspath, dirname, join, normpath
from pandas.testing import assert_frame_equal
import xarray.testing as xrt
import pandas as pd
import mhkit.wave as wave
import xarray as xr
Expand All @@ -37,6 +36,12 @@
)


# TODO(restore-hindcast): 6/30/2026, NLR HSDS endpoint is non functional
# https://github.com/MHKiT-Software/MHKiT-Python/issues/450
@unittest.skip(
"TODO(restore-hindcast): NLR HSDS endpoint unavailable. See "
"https://github.com/MHKiT-Software/MHKiT-Python/issues/450"
)
class TestWPTOhindcast(unittest.TestCase):
"""
A test call designed to check the WPTO hindcast retrival
Expand Down
9 changes: 7 additions & 2 deletions mhkit/tests/wave/io/hindcast/test_wind_toolkit.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from os.path import abspath, dirname, join, isfile, normpath, relpath
from os.path import abspath, dirname, join, normpath
from pandas.testing import assert_frame_equal
import matplotlib.pylab as plt
import mhkit.wave.io.hindcast.wind_toolkit as wtk
import pandas as pd
import unittest
import pytest


testdir = dirname(abspath(__file__))
datadir = normpath(
join(
Expand All @@ -24,6 +23,12 @@
)


# TODO(restore-hindcast): 6/30/2026, NLR HSDS endpoint is non functional
# https://github.com/MHKiT-Software/MHKiT-Python/issues/450
@unittest.skip(
"TODO(restore-hindcast): NLR HSDS endpoint unavailable. See "
"https://github.com/MHKiT-Software/MHKiT-Python/issues/450"
)
class TestWINDToolkit(unittest.TestCase):
@classmethod
def setUpClass(self):
Expand Down
4 changes: 4 additions & 0 deletions mhkit/wave/io/hindcast/hindcast.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
from mhkit.utils.cache import handle_caching
from mhkit.utils.type_handling import convert_to_dataset

from mhkit.wave.io.hindcast.hindcast_exceptions import hindcast_guard


def region_selection(lat_lon: Union[List[float], Tuple[float, float]]) -> str:
"""
Expand Down Expand Up @@ -74,6 +76,7 @@ def region_search(
# pylint: disable=too-many-locals
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements
@hindcast_guard
def request_wpto_point_data(
data_type: str,
parameter: Union[str, List[str]],
Expand Down Expand Up @@ -283,6 +286,7 @@ def request_wpto_point_data(

# pylint: disable=too-many-branches
# pylint: disable=too-many-statements
@hindcast_guard
def request_wpto_directional_spectrum(
lat_lon: Union[Tuple[float, float], List[Tuple[float, float]]],
year: str,
Expand Down
Loading
Loading