Skip to content

Conversation

@wenzeslaus
Copy link
Member

@wenzeslaus wenzeslaus commented Oct 3, 2025

This enables access to the subcommands from the main grass command.

It keeps the commands not documented at the top level, so they remain hidden and experimental.

Backwards compatibility with the classic CLI parameters should be smooth. The decision is based on the first command line argument. This will yield unexpected results (only) when path to mapset matches one of the subcommands, e.g., when naming mapset simply mapset and running the grass command in the project directory which contains this mapset (same for project). It may become a bigger issue with more subcommands, but a simple workaround is prefixing the path ./.

This includes subcommands which are in other PRs, but the subcommand parser will deal with that by reporting an error. This could be an approach we take in general: reserving subcommand names even when we don't have them implemented yet (and triggering some of the directory (project, mapset, filename) issues sooner (even before a specific subcommand is fully introduced).

Before

python -m grass.app run --crs EPSG:3358 g.proj -p
python -m grass.app mapset lock /path/to/mapset  # mapset subcommand is in different PR

After

grass run --crs EPSG:3358 g.proj -p
grass mapset unlock /path/to/mapset  # mapset subcommand is in different PR

Commit message

This enables access to the subcommands from the main grass command.

It keeps the commands not documented at the top level, so they remain hidden and experimental.

Backwards compatibility with the classic CLI parameters should be smooth. The decision is based on the first command line argument. This will yield unexpected results (only) when path to mapset matches one of the subcommands, e.g., when naming mapset simply mapset and running the grass command in the project directory which contains this mapset (same for project). It may become a bigger issue with more subcommands, but a simple workaround is prefixing the path ./.

This includes subcommands which are in other PRs, but the subcommand parser will deal with that by reporting an error. This could be an approach we take in general: reserving subcommand names even when we don't have them implemented yet (and triggering some of the directory (project, mapset, filename) issues sooner (even before a specific subcommand is fully introduced).

This will is useful together with project create subcommand (#6441) and raster pack IO (#5877).

Before (assuming PYTHONPATH or FHS): python -m grass.app run --crs EPSG:3358 g.proj -p

After (assuming PATH): grass run --crs EPSG:3358 g.proj -p

This enables access to the subcommands from the main command. It keeps the commands not documeneted at the top level, so they remain hidden and experimental.

The lock and unlock, now under 'grass mapset lock' and 'grass mapset unlock', are accessible from outside of GRASS through CLI (no Python API or GRASS tools), providing a way of other applications (such as QGIS) to use GRASS locking when accessing GRASS mapsets.

Given that lock and unlock are under mapset (they are too low level to be at subcommand top level), it is clear there should be also project. The create_project function is readily available for CLI use (espetially after OSGeo#6415), so it is now under 'grass project create' and the subcommand is utilized in tests.

For symmetry, this adds also 'grass mapset create' which uses the semi-internal function grass.grassdb.create.create_mapset. The function parameters were adjusted to allow for a single path being provided (which was already supported through path resolution function).

The create_project function was also improved by adding description parameter as full word replacing (but keeping) desc parameter. The behavior was sligtly changes so that MYNAME is only created when description is provided which is what the documenetation suggests ('desc...creates MYNAME file'), but it was implemented that MYNAME was always created even if empty. Finally, missing documentation for the CRS parameter was added.

The new structure in the cli file is that project and mapset subcommand parser definitions have their own functions. This minimizes name conflicts and keeps the main function short.

Finally, 'grass run' subcommad now has --project to use an existing project (defaulting to PERMANENT mapset) or a mapset within that project. This is needed now for testing the created project using the subcommand interface.
@wenzeslaus wenzeslaus changed the title enable subcommands init: Enable subcommands for the main grass command Oct 3, 2025
@github-actions github-actions bot added Python Related code is in Python libraries labels Oct 3, 2025
Co-authored-by: Anna Petrasova <kratochanna@gmail.com>
Copy link
Contributor

@petrasovaa petrasovaa left a comment

Choose a reason for hiding this comment

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

This is a great step especially given GDAL has recently added subcommands.

@wenzeslaus wenzeslaus merged commit fb6729a into OSGeo:main Oct 6, 2025
27 of 28 checks passed
@wenzeslaus wenzeslaus deleted the enable-subcommands branch October 6, 2025 14:21
@github-actions github-actions bot added this to the 8.5.0 milestone Oct 6, 2025
wenzeslaus added a commit that referenced this pull request Oct 6, 2025
The lock and unlock subcommands are operating on a mapset and are low-level (they specifically just lock and unlock and don't do anything with any session). So, this is moving them under a new top-level subcommand mapset (from #6462).

With the lock subcommands being accessible outside of GRASS through CLI without a Python API or a GRASS tools (with or without #6442), other applications which can call subprocesses (such as QGIS) can use GRASS locking when accessing GRASS mapsets.

This is using the new structure in the cli.py file with parser definitions having their own functions (minimizing name conflicts between parses and keeping the main function short). Additionally, the interface and execution code are placed together because they would be changed at the same time.

Tests now test locking the the default mapset and a separate mapset in a smoke test fashion (more in-depth tests exist in the Python API).

Example: grass mapset lock /tmp/project_1/work_2
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants