Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

grass.pygrass: Reset back mapset search path after GridModule class instance finish #2567

Merged
merged 2 commits into from
Oct 26, 2022

Conversation

tmszi
Copy link
Member

@tmszi tmszi commented Sep 1, 2022

Describe the bug
Python pygrass GridModule class instance change LOCATION MAPSET search path.

To Reproduce
Steps to reproduce the behavior:

  1. Launch GRASS GIS with nc_spm_08_grass7 LOCATION and landsat MAPSET
  2. Launch g.mapsets operation=set mapset=landsat
GRASS nc_spm_08_grass7/landsat:~ > g.mapsets -p
Accessible mapsets:
landsat
  1. Launch this Python script
#!/usr/bin/env python3

from grass.pygrass.modules.grid.grid import GridModule

def main():
    grd = GridModule("r.slope.aspect",
                    width=100, height=100, overlap=2,
                    processes=None, split=False, elevation="elevation", 
                    slope="slope", aspect="aspect", overwrite=True)
    grd.run()

if __name__ == '__main__':
    main()
  1. Check output of g.mapsets -p
GRASS nc_spm_08_grass7/landsat:~ > g.mapsets -p
Accessible mapsets:
landsat PERMANENT climate_2000_2012

Expected behavior
Python pygrass GridModule class instance should not change LOCATION MAPSET search path.

System description (please complete the following information):

  • Operating System: all
  • GRASS GIS version: all

Additional context

GRASS GIS Addons issue OSGeo/grass-addons#787.

@tmszi tmszi added bug Something isn't working backport_needed labels Sep 1, 2022
@tmszi tmszi added this to the 8.2.1 milestone Sep 1, 2022
@tmszi
Copy link
Member Author

tmszi commented Sep 2, 2022

Commit 55dfaf4 and f28483a handle situation (reset back MAPSET search path and clean temp data) if input map doesn't exists (example bellow basin raster map doesn't exists in the current MAPSET) and OpenError exception is raised.

Example:

GRASS nc_spm_08_grass7/landsat:~ > g.mapsets operation=set mapset=landsat
GRASS nc_spm_08_grass7/landsat:~ > g.mapsets -p
Accessible mapsets:
landsat

GRASS nc_spm_08_grass7/landsat:~ > g.extension r.mapcalc.tiled

GRASS nc_spm_08_grass7/landsat:~ > r.mapcalc.tiled expression="test = if(basin==12, 1, null())" overlap=2 width=200 height=200
DEST grid_r_mapcalc_gentoo_gnu_linux_9399_000_000
Invalid map <basin>
Parse error
ERROR: parse error
DEST grid_r_mapcalc_gentoo_gnu_linux_9399_000_001
Invalid map <basin>
Parse error
ERROR: parse error
DEST grid_r_mapcalc_gentoo_gnu_linux_9399_000_002
Invalid map <basin>
Parse error
ERROR: parse error
DEST grid_r_mapcalc_gentoo_gnu_linux_9399_001_000
Invalid map <basin>
Parse error
ERROR: parse error
DEST grid_r_mapcalc_gentoo_gnu_linux_9399_001_001
Invalid map <basin>
Parse error
ERROR: parse error
DEST grid_r_mapcalc_gentoo_gnu_linux_9399_001_002
Invalid map <basin>
Parse error
ERROR: parse error
DEST grid_r_mapcalc_gentoo_gnu_linux_9399_002_000
Invalid map <basin>
Parse error
ERROR: parse error
DEST grid_r_mapcalc_gentoo_gnu_linux_9399_002_001
Invalid map <basin>
Parse error
ERROR: parse error
DEST grid_r_mapcalc_gentoo_gnu_linux_9399_002_002
Invalid map <basin>
Parse error
ERROR: parse error
Traceback (most recent call last):
  File "/usr/lib64/grass83/etc/python/grass/pygrass/modules/grid/grid.py", line 686, in run
    self.patch()
  File "/home/tomas/.grass8/addons/scripts/r.mapcalc.tiled", line 124, in patch
    rpatch_map(
  File "/usr/lib64/grass83/etc/python/grass/pygrass/modules/grid/patch.py", line 95, in rpatch_map
    rtype.open("r")
  File "/usr/lib64/grass83/etc/python/grass/pygrass/raster/__init__.py", line 218, in open
    raise OpenError(str_err)
grass.exceptions.OpenError: The map does not exist, I can't open in 'r' mode

GRASS nc_spm_08_grass7/landsat:~ > g.mapsets -p
Accessible mapsets:
landsat

@tmszi
Copy link
Member Author

tmszi commented Sep 2, 2022

With this PR GridModule class instance internally extend current MAPSET search path by all accesible LOCATION MAPSETs.

Example:

When input map name e.g. elevation has unique name across all LOCATION MAPSETs you could use simple map name as input param e.g. elevation="elevation" in r.slope.aspect module (Python code example in the comment above). However if elevation map isn't unique across all LOCATION MAPSETs you have to use fully qualified map name elevation="elevation@climate_2000_2012" in r.slope.aspect module, because you get warning message. And in the case that you want use different input elevation map than the one is in current MAPSET.

Using <elevation@PERMANENT>...
Data element 'cellhd/elevation' was found in more mapsets (also found in <landsat>)
Data element 'cellhd/elevation' was found in more mapsets (also found in <climate_2000_2012>)

On the end of GridModule class instance run processing it reset back current MAPSET search path to the state before running this process.

Copy link
Member

@wenzeslaus wenzeslaus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think GridModule should not modify the search path of the current mapset at all. It should simply use fully qualified names if needed.

Sprinkling _reset_mapset_search_path in the code seems tricky to get right.

try-except with explicit traceback handling seems wrong. Why not finally or using context manager and with? But again, no reset would be needed if no modification is done which seems to be the most robust solution.

@tmszi
Copy link
Member Author

tmszi commented Sep 14, 2022

I think GridModule should not modify the search path of the current mapset at all. It should simply use fully qualified names if needed.

Yes, I agree with you.

try-except with explicit traceback handling seems wrong. Why not finally or using context manager and with? But again, no reset would be needed if no modification is done which seems to be the most robust solution.

Yes, you're right, thanks.

@wenzeslaus
Copy link
Member

Can you please extend the description to comment on what actually changed and what is just indentation?

@@ -154,8 +154,6 @@ def get_mapset(gisrc_src, gisrc_dst):
copy_special_mapset_files(path_src, path_dst)
src = Mapset(msrc, lsrc, gsrc)
dst = Mapset(mdst, ldst, gdst)
loc = Location()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove extend current MAPSET search path.

Comment on lines 157 to 160
visible = [m for m in src.visible]
if src.name not in visible:
visible.append(src.name)
dst.visible.extend(visible)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we should keep this. If I interpret this correctly, this is trying to replicate search path of the current mapset in the temporary mapset. So if user doesn't specify input with full name@mapset, this would be needed. At least it doesn't harm, since it's a temp mapset anyway.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I originally made it so that the user didn't have to specify the exact MAPSET name (full name@MAPSET) when entering the input map name, but then the search path of the current MAPSET needs to be reseted after the run() method completes.

#2567 (review)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we should keep this. If I interpret this correctly, this is trying to replicate search path of the current mapset in the temporary mapset. So if user doesn't specify input with full name@mapset, this would be needed. At least it doesn't harm, since it's a temp mapset anyway.

Example (if these lines are preserved):

  1. Launch GG with with nc_spm_08_grass7 LOCATION and landsat MAPSET
  2. g.mapsets operation=set mapset=landsat
GRASS nc_spm_08_grass7/landsat:~ > g.mapsets -p
Accessible mapsets:
landsat
  1. Launch Python script mentioned here
  2. Check current MAPSET search path again
GRASS nc_spm_08_grass7/landsat:~ > g.mapsets -p
Accessible mapsets:
landsat PERMANENT

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the problem is elsewhere, see #2584.

Copy link
Member Author

@tmszi tmszi Sep 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested with #2584 and these code lines are preserved (which you mentioned above):

  1. Check current MAPSET search path again
GRASS nc_spm_08_grass7/landsat:~ > g.mapsets -p
Accessible mapsets:
landsat

Current MAPSET search path is the same as before running GridModule class instance run() method.

With these preserved code lines (which you mentioned above) for input map name is still required full name map@MAPSET.

@petrasovaa
Copy link
Contributor

This is mixing a bugfix and enhancement, so it seems to me the CleanManager should be separated into another PR. There have been changes (#2584) and I didn't test recently but it seems only the change in patch() is needed to address the original bug (modifying search path), or?

@tmszi tmszi force-pushed the fix-pygrass-grid_module-mapset-search-path branch from 8aedae2 to e88236f Compare October 24, 2022 19:05
@tmszi
Copy link
Member Author

tmszi commented Oct 24, 2022

This is mixing a bugfix and enhancement, so it seems to me the CleanManager should be separated into another PR. There have been changes (#2584) and I didn't test recently but it seems only the change in patch() is needed to address the original bug (modifying search path), or?

Yes, you are right.

There are two bugs:

  1. patch() method expose all LOCATION MAPSETs, fixed with e88236f.
  2. If input map doesn't exists, temporary MAPSETs are not cleaned automatically (solved with CleanManager class). I will open new PR.

@petrasovaa
Copy link
Contributor

It looks like the grid.py tests are broken, but I don't see why this change would trigger that. Anyway, the doctest probably needs to be fixed, it shouldn't require SEARCH_PATH.

@tmszi
Copy link
Member Author

tmszi commented Oct 25, 2022

It looks like the grid.py tests are broken, but I don't see why this change would trigger that.

I think this is because the SEARCH_PATH file does not exist by default because we removed this line mset.visible.extend(loc.mapsets()) which creates this file.

@petrasovaa petrasovaa removed the request for review from wenzeslaus October 25, 2022 19:12
@tmszi tmszi merged commit d276b95 into OSGeo:main Oct 26, 2022
tmszi added a commit to tmszi/grass that referenced this pull request Oct 26, 2022
…class instance finish (OSGeo#2567)

* Fix copy_mapset() func doc test
tmszi added a commit to tmszi/grass that referenced this pull request Oct 26, 2022
…class instance finish (OSGeo#2567)

* Fix copy_mapset() func doc test
tmszi added a commit to tmszi/grass that referenced this pull request Oct 26, 2022
…class instance finish (OSGeo#2567)

* Fix copy_mapset() func doc test
@tmszi tmszi deleted the fix-pygrass-grid_module-mapset-search-path branch October 26, 2022 03:40
ninsbl pushed a commit to ninsbl/grass that referenced this pull request Feb 17, 2023
…class instance finish (OSGeo#2567)

* Fix copy_mapset() func doc test
marisn pushed a commit to marisn/grass that referenced this pull request Jun 2, 2023
…class instance finish (OSGeo#2567)

* Fix copy_mapset() func doc test
@wenzeslaus wenzeslaus changed the title python/grass/pygrass: reset back MAPSET search path after GridModule class instance finish grass.pygrass: Reset back mapset search path after GridModule class instance finish Jun 6, 2023
neteler pushed a commit to nilason/grass that referenced this pull request Nov 7, 2023
…class instance finish (OSGeo#2567)

* Fix copy_mapset() func doc test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants