@@ -294,6 +294,18 @@ class MaskManager:
294294 >>> with gs.MaskManager(mask_name="state_boundary"):
295295 ... gs.parse_command("r.univar", map="elevation", format="json")
296296
297+ Example using explicit activate and deactivate:
298+
299+ >>> manager = gs.MaskManager()
300+ >>> manager.activate()
301+ >>> try:
302+ ... # Create mask with r.mask
303+ ... gs.run_command("r.mask", raster="state_boundary")
304+ ... gs.parse_command("r.univar", map="elevation", format="json")
305+ ... finally:
306+ ... manager.deactivate()
307+
308+
297309 Note the difference between using the name of an existing raster map directly
298310 and using *r.mask* to create a new mask. Both zeros and NULL values are used
299311 to represent mask resulting in NULL cells, while *r.mask*
@@ -368,20 +380,24 @@ def __init__(
368380 else :
369381 self .mask_name = mask_name
370382 self ._remove = False if remove is None else remove
383+ self ._active = False
371384
372- def __enter__ (self ):
385+ def activate (self ):
373386 """Set mask in the given environment.
374387
375388 Sets the `GRASS_MASK` environment variable to the provided or
376389 generated mask name.
377390
378391 :return: Returns the MaskManager instance.
379392 """
393+ if self ._active :
394+ return None
380395 self ._original_value = self .env .get ("GRASS_MASK" )
381396 self .env ["GRASS_MASK" ] = self .mask_name
397+ self ._active = True
382398 return self
383399
384- def __exit__ (self , exc_type , exc_val , exc_tb ):
400+ def deactivate (self ):
385401 """Restore the previous mask state.
386402
387403 Restores the original value of `GRASS_MASK` and optionally removes
@@ -391,6 +407,8 @@ def __exit__(self, exc_type, exc_val, exc_tb):
391407 :param exc_val: Exception value, if any.
392408 :param exc_tb: Traceback, if any.
393409 """
410+ if not self ._active :
411+ return
394412 if self ._original_value is not None :
395413 self .env ["GRASS_MASK" ] = self ._original_value
396414 else :
@@ -405,6 +423,13 @@ def __exit__(self, exc_type, exc_val, exc_tb):
405423 env = self .env ,
406424 quiet = True ,
407425 )
426+ self ._active = False
427+
428+ def __enter__ (self ):
429+ return self .activate ()
430+
431+ def __exit__ (self , exc_type , exc_val , exc_tb ):
432+ self .deactivate ()
408433
409434
410435class RegionManager :
@@ -442,6 +467,15 @@ class RegionManager:
442467 ... manager.set_region(n=226000, s=222000, w=634000, e=638000)
443468 ... gs.parse_command("r.univar", map="elevation", format="json")
444469
470+ Example using explicit activate and deactivate:
471+
472+ >>> manager = gs.RegionManager(raster="elevation")
473+ >>> manager.activate()
474+ >>> try:
475+ ... gs.run_command("r.slope.aspect", elevation="elevation", slope="slope")
476+ ... finally:
477+ ... manager.deactivate()
478+
445479 If no environment is provided, the global environment is used. When running parallel
446480 processes in the same mapset that modify region settings, it is useful to use a copy
447481 of the global environment. The following code creates the copy of the global environment
@@ -466,6 +500,7 @@ def __init__(self, env: dict[str, str] | None = None, **kwargs):
466500 self ._original_value = None
467501 self .region_name = append_uuid (append_node_pid ("region" ))
468502 self ._region_inputs = kwargs or {}
503+ self ._active = False
469504
470505 def set_region (self , ** kwargs ):
471506 """Sets region.
@@ -474,19 +509,22 @@ def set_region(self, **kwargs):
474509 """
475510 run_command ("g.region" , ** kwargs , env = self .env )
476511
477- def __enter__ (self ):
512+ def activate (self ):
478513 """Sets the `WIND_OVERRIDE` environment variable to the generated region name.
479514
480515 :return: Returns the :class:`RegionManager` instance.
481516 """
517+ if self ._active :
518+ return None
482519 self ._original_value = self .env .get ("WIND_OVERRIDE" )
483520 run_command (
484521 "g.region" , save = self .region_name , env = self .env , ** self ._region_inputs
485522 )
486523 self .env ["WIND_OVERRIDE" ] = self .region_name
524+ self ._active = True
487525 return self
488526
489- def __exit__ (self , exc_type , exc_val , exc_tb ):
527+ def deactivate (self ):
490528 """Restore the previous region state.
491529
492530 Restores the original value of `WIND_OVERRIDE`.
@@ -495,6 +533,8 @@ def __exit__(self, exc_type, exc_val, exc_tb):
495533 :param exc_val: Exception value, if any.
496534 :param exc_tb: Traceback, if any.
497535 """
536+ if not self ._active :
537+ return
498538 if self ._original_value is not None :
499539 self .env ["WIND_OVERRIDE" ] = self ._original_value
500540 else :
@@ -507,6 +547,13 @@ def __exit__(self, exc_type, exc_val, exc_tb):
507547 name = self .region_name ,
508548 env = self .env ,
509549 )
550+ self ._active = False
551+
552+ def __enter__ (self ):
553+ return self .activate ()
554+
555+ def __exit__ (self , exc_type , exc_val , exc_tb ):
556+ self .deactivate ()
510557
511558
512559class RegionManagerEnv :
@@ -534,6 +581,17 @@ class RegionManagerEnv:
534581 manager.env["GRASS_REGION"] = gs.region_env()
535582 ... gs.parse_command("r.univar", map="elevation", format="json")
536583
584+
585+ Example using explicit activate and deactivate:
586+
587+ >>> manager = gs.RegionManagerEnv(raster="elevation")
588+ >>> manager.activate()
589+ >>> try:
590+ ... manager.set_region(n=226000, s=222000, w=634000, e=638000)
591+ ... gs.parse_command("r.univar", map="elevation", format="json")
592+ ... finally:
593+ ... manager.deactivate()
594+
537595 .. caution::
538596
539597 To set region within the context, do not call `g.region`,
@@ -551,6 +609,7 @@ def __init__(self, env: dict[str, str] | None = None, **kwargs):
551609 self .env = env if env is not None else os .environ
552610 self ._original_value = None
553611 self ._region_inputs = kwargs or {}
612+ self ._active = False
554613
555614 def set_region (self , ** kwargs ):
556615 """Sets region.
@@ -559,16 +618,19 @@ def set_region(self, **kwargs):
559618 """
560619 self .env ["GRASS_REGION" ] = region_env (** kwargs , env = self .env )
561620
562- def __enter__ (self ):
621+ def activate (self ):
563622 """Sets the `GRASS_REGION` environment variable to the generated region name.
564623
565624 :return: Returns the :class:`RegionManagerEnv` instance.
566625 """
626+ if self ._active :
627+ return None
567628 self ._original_value = self .env .get ("GRASS_REGION" )
568629 self .env ["GRASS_REGION" ] = region_env (** self ._region_inputs , env = self .env )
630+ self ._active = True
569631 return self
570632
571- def __exit__ (self , exc_type , exc_val , exc_tb ):
633+ def deactivate (self ):
572634 """Restore the previous region state.
573635
574636 Restores the original value of `WIND_OVERRIDE`.
@@ -577,7 +639,16 @@ def __exit__(self, exc_type, exc_val, exc_tb):
577639 :param exc_val: Exception value, if any.
578640 :param exc_tb: Traceback, if any.
579641 """
642+ if not self ._active :
643+ return
580644 if self ._original_value is not None :
581645 self .env ["GRASS_REGION" ] = self ._original_value
582646 else :
583647 self .env .pop ("GRASS_REGION" , None )
648+ self ._active = False
649+
650+ def __enter__ (self ):
651+ return self .activate ()
652+
653+ def __exit__ (self , exc_type , exc_val , exc_tb ):
654+ self .deactivate ()
0 commit comments