Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/natcap/invest into task/152…
Browse files Browse the repository at this point in the history
…3-try-gh-actions-artifact-attestations
  • Loading branch information
phargogh committed May 7, 2024
2 parents 81f391b + 8a98ac9 commit 848e33f
Show file tree
Hide file tree
Showing 12 changed files with 98 additions and 21 deletions.
18 changes: 11 additions & 7 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ env:
# nomkl: make sure numpy w/out mkl
# setuptools_scm: needed for versioning to work
CONDA_DEFAULT_DEPENDENCIES: python-build nomkl setuptools_scm
LATEST_SUPPORTED_PYTHON_VERSION: "3.11"
LATEST_SUPPORTED_PYTHON_VERSION: "3.12"

permissions:
attestations: write
Expand Down Expand Up @@ -76,7 +76,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [3.8, 3.9, "3.10", "3.11"]
python-version: [3.8, 3.9, "3.10", "3.11", "3.12"]
os: [windows-latest, macos-latest]
steps:
- uses: actions/checkout@v3
Expand Down Expand Up @@ -168,7 +168,7 @@ jobs:
needs: check-syntax-errors
strategy:
matrix:
python-version: [3.8, 3.9, "3.10", "3.11"]
python-version: [3.8, 3.9, "3.10", "3.11", "3.12"]
os: [windows-latest, macos-latest]
steps:
- uses: actions/checkout@v3
Expand All @@ -190,7 +190,7 @@ jobs:
- name: Install from source distribution
run : |
# Install natcap.invest from the sdist in dist/
pip install $(find dist -name "natcap.invest*")
pip install $(find dist -name "natcap[._-]invest*")
# Model tests should cover model functionality, we just want
# to be sure that we can import `natcap.invest` here.
Expand Down Expand Up @@ -286,7 +286,7 @@ jobs:
uses: actions/cache@v3
with:
path: workbench/node_modules
key: ${{ runner.os }}-${{ hashFiles('workbench/yarn.lock') }}
key: ${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('workbench/yarn.lock') }}

- name: Install workbench dependencies
if: steps.nodemodules-cache.outputs.cache-hit != 'true'
Expand Down Expand Up @@ -327,7 +327,11 @@ jobs:
uses: ./.github/actions/setup_env
with:
python-version: ${{ env.LATEST_SUPPORTED_PYTHON_VERSION }}
requirements-files: requirements.txt requirements-dev.txt requirements-docs.txt
requirements-files: |
requirements.txt
requirements-dev.txt
requirements-docs.txt
constraints_tests.txt
requirements: ${{ env.CONDA_DEFAULT_DEPENDENCIES }} pandoc

- name: Make install
Expand Down Expand Up @@ -361,7 +365,7 @@ jobs:
uses: actions/cache@v3
with:
path: workbench/node_modules
key: ${{ runner.os }}-${{ hashFiles('workbench/yarn.lock') }}
key: ${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('workbench/yarn.lock') }}

- name: Install Workbench Dependencies
if: steps.nodemodules-cache.outputs.cache-hit != 'true'
Expand Down
12 changes: 12 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ Unreleased Changes
* Annual Water Yield
* Added the results_suffix to a few intermediate files where it was
missing. https://github.com/natcap/invest/issues/1517
* Coastal Blue Carbon
* Updated model validation to prevent the case where a user provides only
one snapshot year and no analysis year
(`#1534 <https://github.com/natcap/invest/issues/1534>`_).
Also enforces that the analysis year, if provided, is greater than the
latest snapshot year. An analysis year equal to the latest snapshot year
is no longer allowed.
* Coastal Vulnerability
* Fixed a bug in handling ``nan`` as the nodata value of the bathymetry
raster. ``nan`` pixels will now be propertly ignored before calculating
Expand All @@ -76,6 +83,11 @@ Unreleased Changes
* HRA
* Fixed a bug where habitat and stressor vectors were not being rasterized
with the `ALL_TOUCHED=TRUE` setting.
* Scenic Quality
* Fixed an issue with viewshed calculations where some slight numerical
error was introduced on M1 Macs, but not on x86-based computers. This
numerical error was leading to slightly different visibility results.
https://github.com/natcap/invest/issues/1562
* SDR
* Fixed an issue encountered in the sediment deposition function where
rasters with more than 2^32 pixels would raise a cryptic error relating
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
DATA_DIR := data
GIT_SAMPLE_DATA_REPO := https://bitbucket.org/natcap/invest-sample-data.git
GIT_SAMPLE_DATA_REPO_PATH := $(DATA_DIR)/invest-sample-data
GIT_SAMPLE_DATA_REPO_REV := 2e7cd618c661ec3f3b2a3bddfd2ce7d4704abc05
GIT_SAMPLE_DATA_REPO_REV := 8f78a4873f1fa4253d3ab9a01d6e23f11499b975

GIT_TEST_DATA_REPO := https://bitbucket.org/natcap/invest-test-data.git
GIT_TEST_DATA_REPO_PATH := $(DATA_DIR)/invest-test-data
GIT_TEST_DATA_REPO_REV := 324abde73e1d770ad75921466ecafd1ec6297752

GIT_UG_REPO := https://github.com/natcap/invest.users-guide
GIT_UG_REPO_PATH := doc/users-guide
GIT_UG_REPO_REV := fa6b181d49136089dce56d4ff8f3dcaf12eb4ced
GIT_UG_REPO_REV := 0404bc5d4d43085cdc58f50f8fc29944b10cefb1

ENV = "./env"
ifeq ($(OS),Windows_NT)
Expand Down
6 changes: 5 additions & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ RUN cd / && \

# Create the container for distribution that has runtime dependencies.
FROM mambaorg/micromamba:1.5.0-bookworm-slim
# Python version should match the version used in stage 1.
# If we update the stage 1 debian version, also update this python version
ARG PYTHON_VERSION="3.11"
COPY --from=build /invest/dist/*.whl /tmp/

# The environment.yml file will be built during github actions.
COPY --chown=$MAMBA_USER:$MAMBA_USER environment.yml /tmp/environment.yml
RUN micromamba install -y -n base -c conda-forge -f /tmp/environment.yml && \
RUN micromamba install -y -n base -c conda-forge python==${PYTHON_VERSION} && \
micromamba install -y -n base -c conda-forge -f /tmp/environment.yml && \
micromamba clean --all --yes && \
/opt/conda/bin/python -m pip install /tmp/*.whl && \
/opt/conda/bin/python -m pip cache purge && \
Expand Down
12 changes: 10 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "natcap.invest"
description = "InVEST Ecosystem Service models"
readme = "README_PYTHON.rst"
requires-python = ">=3.8,<3.12"
requires-python = ">=3.8"
license = {file = "LICENSE.txt"}
maintainers = [
{name = "Natural Capital Project Software Team"}
Expand All @@ -21,6 +21,7 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Cython",
"License :: OSI Approved :: BSD License",
"Topic :: Scientific/Engineering :: GIS"
Expand Down Expand Up @@ -78,4 +79,11 @@ where = ["src"]

[tool.pytest.ini_options]
# raise warnings to errors, except for deprecation warnings
filterwarnings = ["error", "default::DeprecationWarning", "default::FutureWarning"]
filterwarnings = [
"error",
"default::DeprecationWarning",
"default::FutureWarning",
# don't error on a specific runtime warning coming from a shapely
# issue on M1: https://github.com/natcap/invest/issues/1562
"default:invalid value encountered in intersection:RuntimeWarning",
]
4 changes: 3 additions & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ pytest
pytest-subtests
wheel>=0.27.0
pypiwin32; sys_platform == 'win32' # pip-only
setuptools>=8.0,<60.7.0 # https://github.com/pyinstaller/pyinstaller/issues/6564

# 60.7.0 exception because of https://github.com/pyinstaller/pyinstaller/issues/6564
setuptools>=8.0,!=60.7.0
PyInstaller>=4.10
setuptools_scm>=6.4.0
requests
Expand Down
11 changes: 9 additions & 2 deletions src/natcap/invest/coastal_blue_carbon/coastal_blue_carbon.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,10 @@
LOGGER = logging.getLogger(__name__)

INVALID_ANALYSIS_YEAR_MSG = gettext(
"Analysis year {analysis_year} must be >= the latest snapshot year "
"Analysis year ({analysis_year}) must be greater than the latest snapshot year "
"({latest_year})")
MISSING_ANALYSIS_YEAR_MSG = gettext(
"Analysis year is required if only one snapshot year is provided.")
INVALID_TRANSITION_VALUES_MSG = gettext(
"The transition table expects values of {model_transitions} but found "
"values of {transition_values}.")
Expand Down Expand Up @@ -2174,9 +2176,14 @@ def validate(args, limit_to=None):
**MODEL_SPEC['args']['landcover_snapshot_csv']
)['raster_path'].to_dict()

snapshot_years = set(snapshots.keys())
if len(snapshot_years) == 1 and "analysis_year" not in sufficient_keys:
validation_warnings.append(
(['analysis_year'], MISSING_ANALYSIS_YEAR_MSG))

if ("analysis_year" not in invalid_keys
and "analysis_year" in sufficient_keys):
if max(set(snapshots.keys())) > int(args['analysis_year']):
if max(snapshot_years) >= int(args['analysis_year']):
validation_warnings.append((
['analysis_year'],
INVALID_ANALYSIS_YEAR_MSG.format(
Expand Down
19 changes: 17 additions & 2 deletions src/natcap/invest/scenic_quality/viewshed.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -815,8 +815,23 @@ def viewshed(dem_raster_path_band,
if target_distance > max_visible_radius:
break

z = (((previous_height-r_v)/slope_distance) *
target_distance + r_v)
# This is a weird platform-specific workaround addressing
# https://github.com/natcap/invest/issues/1562
# On M1 macs, the all-in-one-line addition of _product and r_v
# would create small but noticeable numerical error. Breaking the
# calculation onto two lines eliminates the numerical error. This
# behavior is reproducible in C, outside of Cython on an M1 mac.
# So, this calculation would introduce error:
# z = (((previous_height-r_v)/slope_distance) * target_distance) + r_v
# while the formlation below does not.
# For the script used for testing, see
# https://gist.github.com/phargogh/c4264b37e7f0beed31661eacce53d14a
#
# Some of this may be related to the fact that x86 chips have
# extended precision for FPU-based calculations while M1 ARM chips
# do not. Still, that doesn't explain why the error is introduced.
_product = (((previous_height-r_v)/slope_distance) * target_distance)
z = _product + r_v

# add on refractivity/curvature-of-earth calculations.
adjustment = 0.0 # increase in required height due to curvature
Expand Down
25 changes: 25 additions & 0 deletions tests/test_coastal_blue_carbon.py
Original file line number Diff line number Diff line change
Expand Up @@ -1034,3 +1034,28 @@ def test_track_later_disturbance(self):
expected_year_of_disturbance)
finally:
raster = None

def test_validate_required_analysis_year(self):
"""CBC: analysis year validation (regression test for #1534)."""
from natcap.invest.coastal_blue_carbon import coastal_blue_carbon

args = TestCBC2._create_model_args(self.workspace_dir)
args['workspace_dir'] = self.workspace_dir
args['analysis_year'] = None
# truncate the CSV so that it has only one snapshot year
with open(args['landcover_snapshot_csv'], 'r') as file:
lines = file.readlines()
with open(args['landcover_snapshot_csv'], 'w') as file:
file.writelines(lines[:2])
validation_warnings = coastal_blue_carbon.validate(args)
self.assertEqual(
validation_warnings,
[(['analysis_year'], coastal_blue_carbon.MISSING_ANALYSIS_YEAR_MSG)])

args['analysis_year'] = 2000 # set analysis year equal to snapshot year
validation_warnings = coastal_blue_carbon.validate(args)
self.assertEqual(
validation_warnings,
[(['analysis_year'],
coastal_blue_carbon.INVALID_ANALYSIS_YEAR_MSG.format(
analysis_year=2000, latest_year=2000))])
2 changes: 1 addition & 1 deletion tests/test_ndr.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ def test_masking_invalid_geometry(self):
# bowtie geometry is invalid; verify we can still create a mask.
coordinates = []
for pixel_x_offset, pixel_y_offset in [
(0, 0), (0, 1), (1, 0), (1, 1), (0, 0)]:
(0, 0), (0, 1), (1, 0.25), (1, 0.75), (0, 0)]:
coordinates.append((
default_origin[0] + default_pixel_size[0] * pixel_x_offset,
default_origin[1] + default_pixel_size[1] * pixel_y_offset
Expand Down
4 changes: 2 additions & 2 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1199,7 +1199,7 @@ def test_os_path_normalization_linux(self):
relative_to = os.path.join(self.workspace_dir, 'test.csv')
expected_path = os.path.join(self.workspace_dir, "foo/bar.shp")
path = utils.expand_path(rel_path, relative_to)
self.assertEquals(path, expected_path)
self.assertEqual(path, expected_path)

@unittest.skipIf(platform.system() != 'Windows',
"Function behavior differs across systems.")
Expand All @@ -1213,7 +1213,7 @@ def test_os_path_normalization_windows(self):
relative_to = os.path.join(self.workspace_dir, 'test.csv')
expected_path = os.path.join(self.workspace_dir, "foo\\bar.shp")
path = utils.expand_path(rel_path, relative_to)
self.assertEquals(path, expected_path)
self.assertEqual(path, expected_path)

def test_falsey(self):
"""Utils: test return None when falsey."""
Expand Down
2 changes: 1 addition & 1 deletion workbench/tests/binary_tests/puppet.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const TMP_AOI_PATH = path.join(TMP_DIR, 'aoi.geojson');

if (process.platform === 'darwin') {
// https://github.com/electron-userland/electron-builder/issues/2724#issuecomment-375850150
[BINARY_PATH] = glob.sync('./dist/mac/*.app/Contents/MacOS/InVEST*');
[BINARY_PATH] = glob.sync('./dist/mac*/*.app/Contents/MacOS/InVEST*');
SCREENSHOT_PREFIX = path.join(
os.homedir(), 'Library/Logs', pkg.name, 'invest-workbench-'
);
Expand Down

0 comments on commit 848e33f

Please sign in to comment.