diff --git a/HISTORY.rst b/HISTORY.rst index 2fc61c9f..d9f4fba2 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -16,6 +16,10 @@ Unreleased Changes * Updating pyproject.toml to use the standard ``license-files`` key and replacing the license-related Trove classifier with the approved SPDX string. https://github.com/natcap/pygeoprocessing/issues/466 +* Fixing a side effect in ``pygeoprocessing.align_and_resize_raster_stack`` + where aligning a raster stack using the bounding box mode would result in the + input bounding box being modified in-place. + https://github.com/natcap/pygeoprocessing/issues/471 2.4.10 (2026-01-13) ------------------- diff --git a/src/pygeoprocessing/geoprocessing.py b/src/pygeoprocessing/geoprocessing.py index 13d35edc..70847b3a 100644 --- a/src/pygeoprocessing/geoprocessing.py +++ b/src/pygeoprocessing/geoprocessing.py @@ -1084,6 +1084,9 @@ def align_and_resize_raster_stack( [target_bounding_box, mask_vector_bb], 'intersection') if raster_align_index is not None and raster_align_index >= 0: + # ensure we are working with a copy of the bounding box so that the + # original is unmodified. + target_bounding_box = target_bounding_box[:] # bounding box needs alignment align_bounding_box = ( raster_info_list[raster_align_index]['bounding_box']) diff --git a/tests/test_geoprocessing.py b/tests/test_geoprocessing.py index 0567ef12..a2ef4d38 100644 --- a/tests/test_geoprocessing.py +++ b/tests/test_geoprocessing.py @@ -2551,17 +2551,39 @@ def test_align_and_resize_raster_stack_bb(self): # goes first in the following bounding box construction base_a_raster_info = pygeoprocessing.get_raster_info(base_a_path) + # Make a new bounding box that's in between the two and not perfectly + # aligned to the pixels in base_a_raster. + xmin, ymin, xmax, ymax = base_a_raster_info['bounding_box'] + target_bbox = [ + xmin+23, + ymin+23, + xmax-46, + ymax-46, + ] + + # REGRESSION TEST: make sure this input variable is unmodified after + # execution + # https://github.com/natcap/pygeoprocessing/issues/471 + target_bbox_copy = target_bbox[:] + pygeoprocessing.align_and_resize_raster_stack( base_raster_path_list, target_raster_path_list, resample_method_list, - base_a_raster_info['pixel_size'], 'intersection', + base_a_raster_info['pixel_size'], + target_bbox, base_vector_path_list=None, raster_align_index=0) + # REGRESSION TEST: make sure this input variable is unmodified after + # execution. + # https://github.com/natcap/pygeoprocessing/issues/471 + self.assertEqual(target_bbox, target_bbox_copy) + # we expect this to be twice as big since second base raster has a # pixel size twice that of the first. target_array = pygeoprocessing.raster_to_numpy_array( target_raster_path_list[0]) - numpy.testing.assert_array_equal(pixel_a_matrix, target_array) + numpy.testing.assert_array_equal( + numpy.ones((4, 4), pixel_a_matrix.dtype), target_array) def test_raster_calculator(self): """PGP.geoprocessing: raster_calculator identity test."""