Skip to content

grass.script: add create_mapset function - #7298

Merged
petrasovaa merged 3 commits into
OSGeo:mainfrom
petrasovaa:create_mapset
Jul 15, 2026
Merged

petrasovaa merged 3 commits into
OSGeo:mainfrom
petrasovaa:create_mapset

Conversation

@petrasovaa

Copy link
Copy Markdown
Contributor

Add gs.create_mapset() to grass.script for creating mapsets programmatically in Python (e.g. in jupyter notebooks).
This has been a missing piece with Python jupyter workflows - you create new project, import data, then you want to do the analysis in a different mapset, but calling g.mapset does not match the API style and immediately switches to the new mapset which might not be desired.

The new gs.create_mapset() provides a user-facing API consistent with gs.create_project() — it can run outside of GRASS session, handles validation, overwrite, DB initialization, and supports multiple calling conventions.

There is an existing create_mapset in grass.grassdb.create, but it is a low-level function that only creates the directory and WIND file. The GUI (gui/wxpython/startup/guiutils.py) wraps it with initialize_mapset to also set up the database connection. The CLI (grass mapset create) doesn't initialize the DB at all.

import grass.script as gs                                                                  
                
# Full path
gs.create_mapset("/home/user/grassdata/project/new_mapset")
                                                                                           
# Project path + name
gs.create_mapset("/home/user/grassdata/project", name="new_mapset")                        
                                                                                           
# Name only (within an active session)
gs.create_mapset(name="new_mapset")                                                        
gs.create_mapset(name="new_mapset", env=session.env)                                       
                                                                                           
# Overwrite existing                                                                       
gs.create_mapset(project, name="analysis", overwrite=True)                                 
                
# Skip DB initialization
gs.create_mapset(project, name="tmp", initialize_db=False)
 

Features

  • Validates project exists and has PERMANENT mapset
  • Validates mapset name using legal_name()
  • Rejects creating PERMANENT
  • overwrite=True to replace existing mapset
  • initialize_db=True (default) runs db.connect -c via Tools API
  • env parameter for use with specific sessions, falls back to os.environ
  • Raises ScriptError with clear messages for all error cases

@petrasovaa
petrasovaa requested a review from wenzeslaus April 7, 2026 18:40
@petrasovaa petrasovaa added this to the 8.5.0 milestone Apr 7, 2026
@github-actions github-actions Bot added Python Related code is in Python libraries tests Related to Test Suite labels Apr 7, 2026

@wenzeslaus wenzeslaus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Design:

  1. path + triplet vs path + name: I think it is good not to both with the complexities of supporting triplet in a new function.
  2. First parameter as always path (current) versus sometimes being a name (create in current project, not in a current directory): Current directory case could still be supported by explicit ./. What is more/less confusing?
  3. What parameters are positional only and which are keyword only? (See the comment)
  4. Should there be also ensure mapset? I kind of thought it makes the notebook workflows easier, but that's also before we added proper create_project. There is a dedicated function for that if needed. pathlib.Path has some exists_ok for dirs.

Feature parity should be improved: grass mapset create should behave the same as the new create_mapset (e.g. use it).

Parameter alignment: Compare the parameters against create_project, grass.jupter's session switch_mapset, and grass mapset create.

Comment thread python/grass/script/core.py Resolved
Comment thread python/grass/script/core.py Resolved
Comment thread python/grass/script/core.py Resolved
Comment thread python/grass/script/core.py Resolved
Comment thread python/grass/script/core.py Resolved
Comment thread python/grass/script/core.py Resolved
Comment thread python/grass/script/core.py Resolved
Comment thread python/grass/script/core.py Resolved
Comment thread python/grass/script/core.py Resolved
@petrasovaa

Copy link
Copy Markdown
Contributor Author

Design:

  1. Should there be also ensure mapset? I kind of thought it makes the notebook workflows easier, but that's also before we added proper create_project. There is a dedicated function for that if needed. pathlib.Path has some exists_ok for dirs.

Let's skip this now, create_project would need the same.

Feature parity should be improved: grass mapset create should behave the same as the new create_mapset (e.g. use it).

Done, also added overwrite flag.

Parameter alignment: Compare the parameters against create_project, grass.jupter's session switch_mapset, and grass mapset create.

Went stricter than create_project (positional-only path) since this is a new function with no existing callers; consciously diverging from the triplet style of switch_mapset since create doesn't need it.

create_project has the same all-caps warning in its overwrite docstring — leaving it for a follow-up since this PR is scoped to create_mapset.

@wenzeslaus wenzeslaus modified the milestones: 8.5.0, 8.6.0 May 8, 2026
@petrasovaa
petrasovaa requested a review from wenzeslaus June 9, 2026 03:37
@petrasovaa
petrasovaa requested a review from cwhite911 July 12, 2026 14:13
Comment thread python/grass/script/core.py Resolved
@cwhite911

Copy link
Copy Markdown
Contributor

Code review

Found 1 issue:

  1. create_mapset() accepts the reserved mapset name ogr: the new validation checks legal_name() and rejects PERMANENT, but not the case-insensitive reserved name ogr (bug due to lib/gis/find_file.c, which special-cases strcasecmp(pmapset, "ogr") as the virtual OGR mapset for vector access, so a real mapset named ogr would be shadowed for any map@ogr reference). The existing validator grass.grassdb.checks.get_mapset_name_invalid_reason(), used by the GUI mapset creation path, already rejects this name.

if not legal_name(mapset_path.mapset):
msg = f"Illegal mapset name <{mapset_path.mapset}>"
raise ValueError(msg)
if mapset_path.mapset == "PERMANENT":
msg = "Cannot create PERMANENT mapset (it is managed by the project)"
raise ValueError(msg)

For reference, the existing reserved-name check and the C-level special case:

# Check reserved mapset name
elif mapset_name.lower() == "ogr":
message = _(
"Name '{}' is reserved for direct "
"read access to OGR layers. Please use "
"another name for your mapset."
).format(mapset_name)
# Check whether mapset exists

if (strcmp(element, "vector") == 0 && pmapset &&
strcasecmp(pmapset, "ogr") == 0) {
/* don't check for virtual OGR mapset */
return G_store(pmapset);
}

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@petrasovaa
petrasovaa requested a review from cwhite911 July 14, 2026 17:15
@cwhite911

Copy link
Copy Markdown
Contributor
  1. Should there be also ensure mapset? I kind of thought it makes the notebook workflows easier, but that's also before we added proper create_project. There is a dedicated function for that if needed. pathlib.Path has some exists_ok for dirs.

So does ensure mapset mean

If no mapset:
create mapset
If mapset exists:
Continue with no error

Different from create_mapset which would fail if the mapset exists or overwrites the mapset if the overwrite flag is present.

@petrasovaa

Copy link
Copy Markdown
Contributor Author
  1. Should there be also ensure mapset? I kind of thought it makes the notebook workflows easier, but that's also before we added proper create_project. There is a dedicated function for that if needed. pathlib.Path has some exists_ok for dirs.

So does ensure mapset mean

If no mapset: create mapset If mapset exists: Continue with no error

Different from create_mapset which would fail if the mapset exists or overwrites the mapset if the overwrite flag is present.

yes, I think so. But it's unclear whether we want different function or parameter and create_project would have to have something similar. So this change is more straighforward at this point.

@cwhite911

Copy link
Copy Markdown
Contributor

yes, I think so. But it's unclear whether we want different function or parameter and create_project would have to have something similar. So this change is more straighforward at this point.

I think it should be a different function instead of a parameter, but we just need to make sure the difference is well documented with example use cases.

@petrasovaa
petrasovaa merged commit f0970ee into OSGeo:main Jul 15, 2026
26 checks passed
@petrasovaa
petrasovaa deleted the create_mapset branch July 15, 2026 13:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libraries Python Related code is in Python tests Related to Test Suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants