From db56e2577d58562bd1e702f3c1b839f6bf5d9480 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Wed, 24 Jun 2026 12:27:21 +0200 Subject: [PATCH 1/8] new region_name parameter to RegionManager allowing users to work with saved regions --- python/grass/script/raster.py | 47 +++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/python/grass/script/raster.py b/python/grass/script/raster.py index 47f9d7f2542..1c79136c159 100644 --- a/python/grass/script/raster.py +++ b/python/grass/script/raster.py @@ -509,23 +509,54 @@ class RegionManager: >>> with gs.RegionManager(raster="elevation", env=os.environ.copy()) as manager: ... gs.run_command("r.univar", map="elevation", env=manager.env) + The *region_name* parameter allows working with named saved regions (created with + ``g.region save=...``). If *region_name* refers to an existing saved region and no + additional *g.region* parameters are given, the saved region is used directly without + overwriting it. If *region_name* is not provided, a unique name is generated and the + temporary region is removed at the end of the context. + + Example using an existing saved region: + + >>> with gs.RegionManager(region_name="study_area"): + ... gs.parse_command("r.univar", map="elevation", format="json") + + Example saving to a named region that persists after the context: + + >>> with gs.RegionManager(region_name="my_region", raster="elevation"): + ... gs.run_command("r.slope.aspect", elevation="elevation", slope="slope") + In the background, this class manages the `WIND_OVERRIDE` environment variable that holds the unique name of the saved region to use. """ - def __init__(self, env: dict[str, str] | None = None, **kwargs): + def __init__( + self, + region_name: str | None = None, + env: dict[str, str] | None = None, + **kwargs, + ): """ Initializes the RegionManager. + :param region_name: Name of the saved region. Generated if not provided. + If it refers to an existing saved region and no kwargs are given, + the region is used as-is and never removed at the end. :param env: Environment to use. Defaults to modifying :external:py:data:`os.environ`. - :param kwargs: Keyword arguments passed to `g.region` + :param kwargs: Keyword arguments passed to `g.region` when saving the region. """ self.env = env if env is not None else os.environ self._original_value = None - self.region_name = append_uuid(append_node_pid("region")) self._region_inputs = kwargs or {} self._active = False + if region_name is None: + self.region_name = append_uuid(append_node_pid("region")) + self._remove = True + self._save_on_activate = True + else: + self.region_name = region_name + self._remove = False + self._save_on_activate = bool(kwargs) def set_region(self, **kwargs): """Sets region. @@ -535,16 +566,17 @@ def set_region(self, **kwargs): run_command("g.region", **kwargs, env=self.env) def activate(self): - """Sets the `WIND_OVERRIDE` environment variable to the generated region name. + """Sets the `WIND_OVERRIDE` environment variable to this manager's region name. :return: Returns the :class:`RegionManager` instance. """ if self._active: return None self._original_value = self.env.get("WIND_OVERRIDE") - run_command( - "g.region", save=self.region_name, env=self.env, **self._region_inputs - ) + if self._save_on_activate: + run_command( + "g.region", save=self.region_name, env=self.env, **self._region_inputs + ) self.env["WIND_OVERRIDE"] = self.region_name self._active = True return self @@ -564,6 +596,7 @@ def deactivate(self): self.env["WIND_OVERRIDE"] = self._original_value else: self.env.pop("WIND_OVERRIDE", None) + if self._remove: run_command( "g.remove", flags="f", From b5037647713a72d0ce8f60b2e92711b618196c01 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Thu, 9 Jul 2026 12:47:00 +0200 Subject: [PATCH 2/8] docstring expanded and save method added --- python/grass/script/raster.py | 73 ++++++++----------- .../tests/grass_script_raster_region_test.py | 22 ++++++ 2 files changed, 52 insertions(+), 43 deletions(-) diff --git a/python/grass/script/raster.py b/python/grass/script/raster.py index 1c79136c159..c2d114325f0 100644 --- a/python/grass/script/raster.py +++ b/python/grass/script/raster.py @@ -465,8 +465,9 @@ class RegionManager: settings are automatically restored. This is useful in scripts or functions that need to work with a specific region without permanently altering the user's working environment. - The new region can be defined by passing *g.region* parameters when initializing the context, - or by calling *g.region* directly within the context. + The new region can be defined either by passing *g.region* parameters as keyword + arguments when initializing the context or by calling *g.region* directly within + the context. The original region is saved at the beginning of the context and restored at the end. @@ -480,18 +481,29 @@ class RegionManager: >>> with gs.RegionManager(raster="elevation"): ... gs.run_command("r.slope.aspect", elevation="elevation", slope="slope") + Example using a saved region: + + >>> with gs.RegionManager(region="study_area"): + ... gs.parse_command("r.univar", map="elevation", format="json") + Example using g.region: >>> with gs.RegionManager(): ... gs.run_command("g.region", n=226000, s=222000, w=634000, e=638000) ... gs.parse_command("r.univar", map="elevation", format="json") - Example using :py:func:`~grass.script.raster.RegionManager.set_region`: + Example using :py:meth:`~grass.script.raster.RegionManager.set_region`: >>> with gs.RegionManager() as manager: ... manager.set_region(n=226000, s=222000, w=634000, e=638000) ... gs.parse_command("r.univar", map="elevation", format="json") + Example using :py:meth:`~grass.script.raster.RegionManager.save` to store the current + region under a persistent name so it can be reused after the context exits: + + >>> with gs.RegionManager(raster="elevation") as manager: + ... manager.save("elevation_region", overwrite=True) + Example using explicit activate and deactivate: >>> manager = gs.RegionManager(raster="elevation") @@ -509,54 +521,23 @@ class RegionManager: >>> with gs.RegionManager(raster="elevation", env=os.environ.copy()) as manager: ... gs.run_command("r.univar", map="elevation", env=manager.env) - The *region_name* parameter allows working with named saved regions (created with - ``g.region save=...``). If *region_name* refers to an existing saved region and no - additional *g.region* parameters are given, the saved region is used directly without - overwriting it. If *region_name* is not provided, a unique name is generated and the - temporary region is removed at the end of the context. - - Example using an existing saved region: - - >>> with gs.RegionManager(region_name="study_area"): - ... gs.parse_command("r.univar", map="elevation", format="json") - - Example saving to a named region that persists after the context: - - >>> with gs.RegionManager(region_name="my_region", raster="elevation"): - ... gs.run_command("r.slope.aspect", elevation="elevation", slope="slope") - In the background, this class manages the `WIND_OVERRIDE` environment variable that holds the unique name of the saved region to use. """ - def __init__( - self, - region_name: str | None = None, - env: dict[str, str] | None = None, - **kwargs, - ): + def __init__(self, env: dict[str, str] | None = None, **kwargs): """ Initializes the RegionManager. - :param region_name: Name of the saved region. Generated if not provided. - If it refers to an existing saved region and no kwargs are given, - the region is used as-is and never removed at the end. :param env: Environment to use. Defaults to modifying :external:py:data:`os.environ`. - :param kwargs: Keyword arguments passed to `g.region` when saving the region. + :param kwargs: Keyword arguments passed to `g.region` """ self.env = env if env is not None else os.environ self._original_value = None + self.region_name = append_uuid(append_node_pid("region")) self._region_inputs = kwargs or {} self._active = False - if region_name is None: - self.region_name = append_uuid(append_node_pid("region")) - self._remove = True - self._save_on_activate = True - else: - self.region_name = region_name - self._remove = False - self._save_on_activate = bool(kwargs) def set_region(self, **kwargs): """Sets region. @@ -565,18 +546,25 @@ def set_region(self, **kwargs): """ run_command("g.region", **kwargs, env=self.env) + def save(self, name, overwrite=False): + """Save the current region under a persistent name. + + :param name: Name of the region to save. + :param overwrite: Whether to overwrite an existing saved region. + """ + run_command("g.region", save=name, overwrite=overwrite, env=self.env) + def activate(self): - """Sets the `WIND_OVERRIDE` environment variable to this manager's region name. + """Sets the `WIND_OVERRIDE` environment variable to the generated region name. :return: Returns the :class:`RegionManager` instance. """ if self._active: return None self._original_value = self.env.get("WIND_OVERRIDE") - if self._save_on_activate: - run_command( - "g.region", save=self.region_name, env=self.env, **self._region_inputs - ) + run_command( + "g.region", save=self.region_name, env=self.env, **self._region_inputs + ) self.env["WIND_OVERRIDE"] = self.region_name self._active = True return self @@ -596,7 +584,6 @@ def deactivate(self): self.env["WIND_OVERRIDE"] = self._original_value else: self.env.pop("WIND_OVERRIDE", None) - if self._remove: run_command( "g.remove", flags="f", 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 6428842d24e..c2b63ffb593 100644 --- a/python/grass/script/tests/grass_script_raster_region_test.py +++ b/python/grass/script/tests/grass_script_raster_region_test.py @@ -163,3 +163,25 @@ def test_region_manager_env_activate_deactivate(session_2x2): # Deactivate twice is harmless manager.deactivate() assert "GRASS_REGION" not in session_2x2.env + + +def test_region_manager_save(session_2x2): + """Test RegionManager can persist the current region explicitly.""" + + with gs.RegionManager(n=6, s=0, e=6, w=0, res=1, env=session_2x2.env) as manager: + manager.save("saved_region", overwrite=True) + + try: + with gs.RegionManager(region="saved_region", env=session_2x2.env): + region = gs.region(env=session_2x2.env) + assert region["rows"] == 6 + assert region["cols"] == 6 + finally: + gs.run_command( + "g.remove", + flags="f", + type="region", + name="saved_region", + env=session_2x2.env, + quiet=True, + ) From 70e440fb6e9bbeff9ad2bb11e083551bc09d6ab7 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Sun, 12 Jul 2026 16:38:58 +0200 Subject: [PATCH 3/8] applying Anna's suggestions --- python/grass/script/raster.py | 43 +++++++++++++------ .../tests/grass_script_raster_region_test.py | 26 ++++++++++- 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/python/grass/script/raster.py b/python/grass/script/raster.py index c2d114325f0..76bbc994298 100644 --- a/python/grass/script/raster.py +++ b/python/grass/script/raster.py @@ -481,29 +481,25 @@ class RegionManager: >>> with gs.RegionManager(raster="elevation"): ... gs.run_command("r.slope.aspect", elevation="elevation", slope="slope") - Example using a saved region: - - >>> with gs.RegionManager(region="study_area"): - ... gs.parse_command("r.univar", map="elevation", format="json") - Example using g.region: >>> with gs.RegionManager(): ... gs.run_command("g.region", n=226000, s=222000, w=634000, e=638000) ... gs.parse_command("r.univar", map="elevation", format="json") + Example saving a region and reusing it later through *region=*: + + >>> with gs.RegionManager(raster="elevation") as manager: + ... manager.save("study_area") + >>> with gs.RegionManager(region="study_area"): + ... gs.parse_command("r.univar", map="elevation", format="json") + Example using :py:meth:`~grass.script.raster.RegionManager.set_region`: >>> with gs.RegionManager() as manager: ... manager.set_region(n=226000, s=222000, w=634000, e=638000) ... gs.parse_command("r.univar", map="elevation", format="json") - Example using :py:meth:`~grass.script.raster.RegionManager.save` to store the current - region under a persistent name so it can be reused after the context exits: - - >>> with gs.RegionManager(raster="elevation") as manager: - ... manager.save("elevation_region", overwrite=True) - Example using explicit activate and deactivate: >>> manager = gs.RegionManager(raster="elevation") @@ -546,7 +542,7 @@ def set_region(self, **kwargs): """ run_command("g.region", **kwargs, env=self.env) - def save(self, name, overwrite=False): + def save(self, name, overwrite=None): """Save the current region under a persistent name. :param name: Name of the region to save. @@ -605,7 +601,9 @@ class RegionManagerEnv: """Context manager for temporarily setting the computational region. See :class:`RegionManager`. Unlike :class:`RegionManager`, this class uses - `GRASS_REGION` instead of `WIND_OVERRIDE`. The advantage is no files are written to disk. + `GRASS_REGION` instead of `WIND_OVERRIDE`. The advantage is that, during normal + context usage, no region files are written to disk. If you call + :py:meth:`.save`, a named region is intentionally written to disk. The disadvantage is that simply calling *g.region* within the context will not affect the temporary region, but the global one, which can be confusing. @@ -626,6 +624,13 @@ class RegionManagerEnv: ... manager.env["GRASS_REGION"] = gs.region_env() ... gs.parse_command("r.univar", map="elevation", format="json") + Example saving the temporary region and reusing it later through *region=*: + + >>> with gs.RegionManagerEnv(raster="elevation") as manager: + ... manager.save("study_area") + >>> with gs.RegionManager(region="study_area"): + ... gs.parse_command("r.univar", map="elevation", format="json") + Example using explicit activate and deactivate: @@ -640,7 +645,9 @@ class RegionManagerEnv: .. caution:: To set region within the context, do not call *g.region*, - use :py:meth:`.set_region` instead. + use :py:meth:`.set_region` instead. The :py:meth:`.save` method + is an exception and uses *g.region save=* intentionally to store + the current region persistently. """ def __init__(self, env: dict[str, str] | None = None, **kwargs): @@ -663,6 +670,14 @@ def set_region(self, **kwargs): """ self.env["GRASS_REGION"] = region_env(**kwargs, env=self.env) + def save(self, name, overwrite=None): + """Save the current region under a persistent name. + + :param name: Name of the region to save. + :param overwrite: Whether to overwrite an existing saved region. + """ + run_command("g.region", save=name, overwrite=overwrite, env=self.env) + def activate(self): """Sets the `GRASS_REGION` environment variable to the generated region name. 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 c2b63ffb593..b0af0988ed4 100644 --- a/python/grass/script/tests/grass_script_raster_region_test.py +++ b/python/grass/script/tests/grass_script_raster_region_test.py @@ -76,6 +76,30 @@ def test_region_manager_env(session_2x2): assert region["cols"] == 2 +def test_region_manager_env_save(session_2x2): + """Test RegionManagerEnv can persist the current region explicitly.""" + saved_region_name = "saved_region_env" + + try: + with gs.RegionManagerEnv(env=session_2x2.env) as manager: + manager.set_region(n=5, s=0, e=5, w=0, res=1) + manager.save(saved_region_name) + + with gs.RegionManager(region=saved_region_name, env=session_2x2.env): + region = gs.region(env=session_2x2.env) + assert region["rows"] == 5 + assert region["cols"] == 5 + finally: + gs.run_command( + "g.remove", + flags="f", + type="region", + name=saved_region_name, + env=session_2x2.env, + quiet=True, + ) + + def test_region_manager_env_problem_with_g_region(session_2x2): """Test RegionManagerEnv with region parameters and g.region call.""" assert "GRASS_REGION" not in session_2x2.env @@ -169,7 +193,7 @@ def test_region_manager_save(session_2x2): """Test RegionManager can persist the current region explicitly.""" with gs.RegionManager(n=6, s=0, e=6, w=0, res=1, env=session_2x2.env) as manager: - manager.save("saved_region", overwrite=True) + manager.save("saved_region") try: with gs.RegionManager(region="saved_region", env=session_2x2.env): From 24c0539325c2c5aa804210fd77135a04dee67467 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Tue, 14 Jul 2026 13:19:46 +0200 Subject: [PATCH 4/8] notes from reviews --- python/grass/script/raster.py | 34 ++++++++------ .../tests/grass_script_raster_region_test.py | 44 +++++-------------- 2 files changed, 33 insertions(+), 45 deletions(-) diff --git a/python/grass/script/raster.py b/python/grass/script/raster.py index 76bbc994298..7ac81db281d 100644 --- a/python/grass/script/raster.py +++ b/python/grass/script/raster.py @@ -487,10 +487,9 @@ class RegionManager: ... gs.run_command("g.region", n=226000, s=222000, w=634000, e=638000) ... gs.parse_command("r.univar", map="elevation", format="json") - Example saving a region and reusing it later through *region=*: + Example using a saved region: - >>> with gs.RegionManager(raster="elevation") as manager: - ... manager.save("study_area") + >>> gs.run_command("g.region", save="study_area", s=1000, n=1100, w=1000, e=1100) >>> with gs.RegionManager(region="study_area"): ... gs.parse_command("r.univar", map="elevation", format="json") @@ -500,6 +499,12 @@ class RegionManager: ... manager.set_region(n=226000, s=222000, w=634000, e=638000) ... gs.parse_command("r.univar", map="elevation", format="json") + Example using :py:meth:`~grass.script.raster.RegionManager.save` to store the current + region under a persistent name so it can be reused after the context exits: + + >>> with gs.RegionManager(raster="elevation") as manager: + ... manager.save("elevation_region", overwrite=True) + Example using explicit activate and deactivate: >>> manager = gs.RegionManager(raster="elevation") @@ -602,16 +607,23 @@ class RegionManagerEnv: See :class:`RegionManager`. Unlike :class:`RegionManager`, this class uses `GRASS_REGION` instead of `WIND_OVERRIDE`. The advantage is that, during normal - context usage, no region files are written to disk. If you call - :py:meth:`.save`, a named region is intentionally written to disk. + context usage, no region files are written to disk. The disadvantage is that simply calling *g.region* within the context will not affect the temporary region, but the global one, which can be confusing. + The :py:meth:`.save` method intentionally writes the current region to a saved region file. + Example with explicit region parameters: >>> with gs.RegionManagerEnv(n=226000, s=222000, w=634000, e=638000): ... gs.parse_command("r.univar", map="elevation", format="json") + Example using a saved region: + + >>> gs.run_command("g.region", save="study_area", s=1000, n=1100, w=1000, e=1100) + >>> with gs.RegionManagerEnv(region="study_area"): + ... gs.parse_command("r.univar", map="elevation", format="json") + Example with :py:meth:`.set_region`: >>> with gs.RegionManagerEnv() as manager: @@ -624,13 +636,11 @@ class RegionManagerEnv: ... manager.env["GRASS_REGION"] = gs.region_env() ... gs.parse_command("r.univar", map="elevation", format="json") - Example saving the temporary region and reusing it later through *region=*: + Example using :py:meth:`.save`: to store the current region under + a persistent name so it can be reused after the context exits: >>> with gs.RegionManagerEnv(raster="elevation") as manager: - ... manager.save("study_area") - >>> with gs.RegionManager(region="study_area"): - ... gs.parse_command("r.univar", map="elevation", format="json") - + ... manager.save("elevation_region", overwrite=True) Example using explicit activate and deactivate: @@ -645,9 +655,7 @@ class RegionManagerEnv: .. caution:: To set region within the context, do not call *g.region*, - use :py:meth:`.set_region` instead. The :py:meth:`.save` method - is an exception and uses *g.region save=* intentionally to store - the current region persistently. + use :py:meth:`.set_region` instead. """ def __init__(self, env: dict[str, str] | None = None, **kwargs): 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 b0af0988ed4..8228f302630 100644 --- a/python/grass/script/tests/grass_script_raster_region_test.py +++ b/python/grass/script/tests/grass_script_raster_region_test.py @@ -80,24 +80,14 @@ def test_region_manager_env_save(session_2x2): """Test RegionManagerEnv can persist the current region explicitly.""" saved_region_name = "saved_region_env" - try: - with gs.RegionManagerEnv(env=session_2x2.env) as manager: - manager.set_region(n=5, s=0, e=5, w=0, res=1) - manager.save(saved_region_name) - - with gs.RegionManager(region=saved_region_name, env=session_2x2.env): - region = gs.region(env=session_2x2.env) - assert region["rows"] == 5 - assert region["cols"] == 5 - finally: - gs.run_command( - "g.remove", - flags="f", - type="region", - name=saved_region_name, - env=session_2x2.env, - quiet=True, - ) + with gs.RegionManagerEnv(env=session_2x2.env) as manager: + manager.set_region(n=5, s=0, e=5, w=0, res=1) + manager.save(saved_region_name) + + with gs.RegionManager(region=saved_region_name, env=session_2x2.env): + region = gs.region(env=session_2x2.env) + assert region["rows"] == 5 + assert region["cols"] == 5 def test_region_manager_env_problem_with_g_region(session_2x2): @@ -195,17 +185,7 @@ def test_region_manager_save(session_2x2): with gs.RegionManager(n=6, s=0, e=6, w=0, res=1, env=session_2x2.env) as manager: manager.save("saved_region") - try: - with gs.RegionManager(region="saved_region", env=session_2x2.env): - region = gs.region(env=session_2x2.env) - assert region["rows"] == 6 - assert region["cols"] == 6 - finally: - gs.run_command( - "g.remove", - flags="f", - type="region", - name="saved_region", - env=session_2x2.env, - quiet=True, - ) + with gs.RegionManager(region="saved_region", env=session_2x2.env): + region = gs.region(env=session_2x2.env) + assert region["rows"] == 6 + assert region["cols"] == 6 From 2a17cee3784d25145050c9c025f6f8530d7398f6 Mon Sep 17 00:00:00 2001 From: Linda Karlovska <49241681+lindakarlovska@users.noreply.github.com> Date: Tue, 14 Jul 2026 17:25:38 +0200 Subject: [PATCH 5/8] Update python/grass/script/raster.py Co-authored-by: Anna Petrasova --- python/grass/script/raster.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/grass/script/raster.py b/python/grass/script/raster.py index 7ac81db281d..e1528e2447b 100644 --- a/python/grass/script/raster.py +++ b/python/grass/script/raster.py @@ -499,8 +499,8 @@ class RegionManager: ... manager.set_region(n=226000, s=222000, w=634000, e=638000) ... gs.parse_command("r.univar", map="elevation", format="json") - Example using :py:meth:`~grass.script.raster.RegionManager.save` to store the current - region under a persistent name so it can be reused after the context exits: + Example using :py:meth:`~grass.script.raster.RegionManager.save` to store the temporarily + modified region under a persistent name so it can be reused after the context exits: >>> with gs.RegionManager(raster="elevation") as manager: ... manager.save("elevation_region", overwrite=True) From ad3824b16b287679b39aca99e5cc8afd9c494dbd Mon Sep 17 00:00:00 2001 From: Linda Karlovska <49241681+lindakarlovska@users.noreply.github.com> Date: Tue, 14 Jul 2026 17:25:53 +0200 Subject: [PATCH 6/8] Update python/grass/script/raster.py Co-authored-by: Anna Petrasova --- python/grass/script/raster.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/grass/script/raster.py b/python/grass/script/raster.py index e1528e2447b..4d55847dc7a 100644 --- a/python/grass/script/raster.py +++ b/python/grass/script/raster.py @@ -503,7 +503,7 @@ class RegionManager: modified region under a persistent name so it can be reused after the context exits: >>> with gs.RegionManager(raster="elevation") as manager: - ... manager.save("elevation_region", overwrite=True) + ... manager.save("elevation_region") Example using explicit activate and deactivate: From 76813a0eebca9fcc41c456f5a66fd205b9a09d3a Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Thu, 16 Jul 2026 12:08:05 +0200 Subject: [PATCH 7/8] change in wording --- python/grass/script/raster.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/python/grass/script/raster.py b/python/grass/script/raster.py index 4d55847dc7a..6e9afefe4bc 100644 --- a/python/grass/script/raster.py +++ b/python/grass/script/raster.py @@ -548,7 +548,7 @@ def set_region(self, **kwargs): run_command("g.region", **kwargs, env=self.env) def save(self, name, overwrite=None): - """Save the current region under a persistent name. + """Save the temporarily modified region under a persistent name. :param name: Name of the region to save. :param overwrite: Whether to overwrite an existing saved region. @@ -611,7 +611,8 @@ class RegionManagerEnv: The disadvantage is that simply calling *g.region* within the context will not affect the temporary region, but the global one, which can be confusing. - The :py:meth:`.save` method intentionally writes the current region to a saved region file. + The :py:meth:`.save` method intentionally writes the temporarily modified region to + a saved region file. Example with explicit region parameters: @@ -636,7 +637,7 @@ class RegionManagerEnv: ... manager.env["GRASS_REGION"] = gs.region_env() ... gs.parse_command("r.univar", map="elevation", format="json") - Example using :py:meth:`.save`: to store the current region under + Example using :py:meth:`.save`: to store the temporarily modified region under a persistent name so it can be reused after the context exits: >>> with gs.RegionManagerEnv(raster="elevation") as manager: @@ -679,7 +680,7 @@ def set_region(self, **kwargs): self.env["GRASS_REGION"] = region_env(**kwargs, env=self.env) def save(self, name, overwrite=None): - """Save the current region under a persistent name. + """Save the temporarily modified region under a persistent name. :param name: Name of the region to save. :param overwrite: Whether to overwrite an existing saved region. From 89398d76a9aa008731d9b17f8ea09e3b92dc16b6 Mon Sep 17 00:00:00 2001 From: lindakladivova Date: Thu, 16 Jul 2026 12:30:09 +0200 Subject: [PATCH 8/8] standardize design of test methods --- .../tests/grass_script_raster_region_test.py | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 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 8228f302630..ca75bc375af 100644 --- a/python/grass/script/tests/grass_script_raster_region_test.py +++ b/python/grass/script/tests/grass_script_raster_region_test.py @@ -76,20 +76,6 @@ def test_region_manager_env(session_2x2): assert region["cols"] == 2 -def test_region_manager_env_save(session_2x2): - """Test RegionManagerEnv can persist the current region explicitly.""" - saved_region_name = "saved_region_env" - - with gs.RegionManagerEnv(env=session_2x2.env) as manager: - manager.set_region(n=5, s=0, e=5, w=0, res=1) - manager.save(saved_region_name) - - with gs.RegionManager(region=saved_region_name, env=session_2x2.env): - region = gs.region(env=session_2x2.env) - assert region["rows"] == 5 - assert region["cols"] == 5 - - def test_region_manager_env_problem_with_g_region(session_2x2): """Test RegionManagerEnv with region parameters and g.region call.""" assert "GRASS_REGION" not in session_2x2.env @@ -180,7 +166,7 @@ def test_region_manager_env_activate_deactivate(session_2x2): def test_region_manager_save(session_2x2): - """Test RegionManager can persist the current region explicitly.""" + """Test RegionManager can persist the temporarily modified region explicitly.""" with gs.RegionManager(n=6, s=0, e=6, w=0, res=1, env=session_2x2.env) as manager: manager.save("saved_region") @@ -189,3 +175,15 @@ def test_region_manager_save(session_2x2): region = gs.region(env=session_2x2.env) assert region["rows"] == 6 assert region["cols"] == 6 + + +def test_region_manager_env_save(session_2x2): + """Test RegionManagerEnv can persist the temporarily modified region explicitly.""" + + with gs.RegionManagerEnv(n=6, s=0, e=6, w=0, res=1, env=session_2x2.env) as manager: + manager.save("saved_region_env") + + with gs.RegionManagerEnv(region="saved_region_env", env=session_2x2.env): + region = gs.region(env=session_2x2.env) + assert region["rows"] == 6 + assert region["cols"] == 6