From 7901d86fd7862210e38744e088b56790527f1c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Wed, 28 Oct 2026 19:56:56 +0000 Subject: [PATCH 1/2] grass.script: Remove the saved region of a nested RegionManager RegionManager.deactivate() removed the region it saved only when no WIND_OVERRIDE was set before activation. In a nested RegionManager the inner one found the region of the outer one, restored it, and left its own region in the mapset. Remove the saved region in both cases, like MaskManager does with its mask. Add tests that the region saved by a RegionManager is removed, also when RegionManagers are nested. Found by checking whether the tests detect the removal of the g.remove call, using mutation testing and AI assistance. --- python/grass/script/raster.py | 17 ++++++------ .../tests/grass_script_raster_region_test.py | 27 +++++++++++++++++++ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/python/grass/script/raster.py b/python/grass/script/raster.py index 01092ce9029..ed4033cbaf7 100644 --- a/python/grass/script/raster.py +++ b/python/grass/script/raster.py @@ -583,14 +583,15 @@ def deactivate(self): self.env["WIND_OVERRIDE"] = self._original_value else: self.env.pop("WIND_OVERRIDE", None) - run_command( - "g.remove", - flags="f", - quiet=True, - type="region", - name=self.region_name, - env=self.env, - ) + + run_command( + "g.remove", + flags="f", + quiet=True, + type="region", + name=self.region_name, + env=self.env, + ) self._active = False def __enter__(self): diff --git a/python/grass/script/tests/grass_script_raster_region_test.py b/python/grass/script/tests/grass_script_raster_region_test.py index ca75bc375af..54eba62e769 100644 --- a/python/grass/script/tests/grass_script_raster_region_test.py +++ b/python/grass/script/tests/grass_script_raster_region_test.py @@ -187,3 +187,30 @@ def test_region_manager_env_save(session_2x2): region = gs.region(env=session_2x2.env) assert region["rows"] == 6 assert region["cols"] == 6 + + +def test_region_manager_removes_temporary_region(session_2x2): + """Test RegionManager does not leave the region it saved in the mapset.""" + env = session_2x2.env + with gs.RegionManager(env=env) as manager: + assert any( + name.startswith(manager.region_name) + for name in gs.list_strings("region", env=env) + ) + assert not any( + name.startswith(manager.region_name) + for name in gs.list_strings("region", env=env) + ) + + +def test_region_manager_nested_removes_temporary_regions(session_2x2): + """Test a nested RegionManager does not leave its saved region in the mapset.""" + env = session_2x2.env + with ( + gs.RegionManager(env=env) as outer, + gs.RegionManager(env=env) as inner, + ): + pass + saved = gs.list_strings("region", env=env) + assert not any(name.startswith(outer.region_name) for name in saved) + assert not any(name.startswith(inner.region_name) for name in saved) From 2087cbb20723673e5c4f71d03279d3a0ac24b574 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 30 Oct 2026 12:09:54 +0000 Subject: [PATCH 2/2] tests: Check saved regions with g.findfile in RegionManager tests Check whether a region exists with g.findfile instead of searching the list of regions for a name prefix. Also check that both nested regions exist before they are removed. --- .../tests/grass_script_raster_region_test.py | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/python/grass/script/tests/grass_script_raster_region_test.py b/python/grass/script/tests/grass_script_raster_region_test.py index 54eba62e769..47e8a306bd0 100644 --- a/python/grass/script/tests/grass_script_raster_region_test.py +++ b/python/grass/script/tests/grass_script_raster_region_test.py @@ -1,4 +1,11 @@ import grass.script as gs +from grass.tools import Tools + + +def region_exists(name, env): + """Return True if a saved region with the name is found""" + found = Tools(env=env).g_findfile(element="windows", file=name, format="json") + return found["name"] is not None def test_region_manager_with_g_region(session_2x2): @@ -193,14 +200,8 @@ def test_region_manager_removes_temporary_region(session_2x2): """Test RegionManager does not leave the region it saved in the mapset.""" env = session_2x2.env with gs.RegionManager(env=env) as manager: - assert any( - name.startswith(manager.region_name) - for name in gs.list_strings("region", env=env) - ) - assert not any( - name.startswith(manager.region_name) - for name in gs.list_strings("region", env=env) - ) + assert region_exists(manager.region_name, env=env) + assert not region_exists(manager.region_name, env=env) def test_region_manager_nested_removes_temporary_regions(session_2x2): @@ -210,7 +211,7 @@ def test_region_manager_nested_removes_temporary_regions(session_2x2): gs.RegionManager(env=env) as outer, gs.RegionManager(env=env) as inner, ): - pass - saved = gs.list_strings("region", env=env) - assert not any(name.startswith(outer.region_name) for name in saved) - assert not any(name.startswith(inner.region_name) for name in saved) + assert region_exists(outer.region_name, env=env) + assert region_exists(inner.region_name, env=env) + assert not region_exists(outer.region_name, env=env) + assert not region_exists(inner.region_name, env=env)