Skip to content

Commit

Permalink
r.mask.status: Always output name of the mask (#4531)
Browse files Browse the repository at this point in the history
For both active and inactive raster mask, show the name of the raster which is used (or would be used) for the mask. This will allow tools like r.mask or GUI to do lower-level operations with or around mask without a need to know about defaults or user mechanism to change the name.

I'm repurposing the existing 'name' (full_name) key which is now always set (as opposed to being null when no mask is present) as the 'present' boolean key already has the information on the mask presence. I'm renaming full_name to name because that creates a simpler interface (which is whole point of outputting full name as opposed to two keys to get name and mapset).
  • Loading branch information
wenzeslaus authored Oct 31, 2024
1 parent 00f51c9 commit ba0a495
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 36 deletions.
1 change: 1 addition & 0 deletions include/grass/defs/raster.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ int Rast_option_to_interp_type(const struct Option *);

/* mask_info.c */
char *Rast_mask_info(void);
char *Rast_mask_name(void);
bool Rast_mask_status(char *, char *, bool *, char *, char *);
int Rast__mask_info(char *, char *);
bool Rast_mask_is_present(void);
Expand Down
21 changes: 21 additions & 0 deletions lib/raster/mask_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,27 @@ char *Rast_mask_info(void)
return G_store(text);
}

/**
* @brief Retrieves the name of the raster mask to use.
*
* The returned raster map name is fully qualified, i.e., in the form
% "name@mapset".
*
* The mask name is "MASK@<mapset>", where <mapset> is the current
* mapset.
*
* The memory for the returned mask name is dynamically allocated using
* G_store(). It is the caller's responsibility to free the memory with
* G_free() when it is no longer needed.
*
* @returns A dynamically allocated string containing the mask name.
*/
char *Rast_mask_name(void)
{
// Mask name is always "MASK@<current mapset>".
return G_fully_qualified_name("MASK", G_mapset());
}

/**
* @brief Get raster mask status information
*
Expand Down
34 changes: 13 additions & 21 deletions raster/r.mask.status/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ int report_status(struct Parameters *params)
}

// Mask raster
char *full_mask = G_fully_qualified_name(name, mapset);
char *full_mask = Rast_mask_name();
// Underlying raster if applicable
char *full_underlying = NULL;
if (is_mask_reclass)
Expand All @@ -99,10 +99,7 @@ int report_status(struct Parameters *params)
JSON_Value *root_value = json_value_init_object();
JSON_Object *root_object = json_object(root_value);
json_object_set_boolean(root_object, "present", present);
if (present)
json_object_set_string(root_object, "full_name", full_mask);
else
json_object_set_null(root_object, "full_name");
json_object_set_string(root_object, "name", full_mask);
if (is_mask_reclass)
json_object_set_string(root_object, "is_reclass_of",
full_underlying);
Expand All @@ -121,9 +118,7 @@ int report_status(struct Parameters *params)
printf("1");
else
printf("0");
printf("\nfull_name=");
if (present)
printf("%s", full_mask);
printf("\nname=%s", full_mask);
printf("\nis_reclass_of=");
if (is_mask_reclass)
printf("%s", full_underlying);
Expand All @@ -135,34 +130,31 @@ int report_status(struct Parameters *params)
printf("true");
else
printf("false");
printf("\nfull_name: ");
if (present)
printf("|-\n %s", full_mask);
else
printf("null");
// Null values in YAML can be an empty (no) value (rather than null),
// so we could use that, but using the explicit null as a reasonable
// starting point.
printf("\nname: ");
printf("|-\n %s", full_mask);
printf("\nis_reclass_of: ");
// Using block scalar with |- to avoid need for escaping.
// Alternatively, we could check mapset naming limits against YAML
// escaping needs for different types of strings and do the necessary
// escaping here.
// Null values in YAML can be an empty (no) value (rather than null),
// so we could use that, but using the explicit null as a reasonable
// starting point.
if (is_mask_reclass)
printf("|-\n %s", full_underlying);
else
printf("null");
printf("\n");
}
else {
if (present)
printf(_("Mask is active"));
else
printf(_("Mask is not present"));
if (present) {
printf("\n");
printf(_("Mask is active"));
printf(_("Mask name: %s"), full_mask);
}
else {
printf(_("Mask is not present"));
printf(_("If activated, mask name will be: %s"), full_mask);
}
if (is_mask_reclass) {
printf("\n");
printf(_("Mask is a raster reclassified from: %s"),
Expand Down
20 changes: 15 additions & 5 deletions raster/r.mask.status/r.mask.status.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
<h2>DESCRIPTION</h2>

The <em>r.mask.status</em> reports information about the 2D raster mask and its
status. If the mask is present, the tool reports a full name of the raster (name
including the mapset) which represents the mask. It can also report full name of
the underlying raster if the mask is reclassified from another raster.

<p></p>
status. The tool reports whether the mask is present or not. For both active
and inactive mask, the tool reports a full name of the raster (name including
the mapset) which represents or would represent the mask.
It can also report full name of the underlying raster if the mask is
reclassified from another raster.

The tool can be used to check if the mask is currently set
(<code>present</code> boolean in JSON), what is raster name used to represent
the mask (<code>name</code> string in JSON), and whether the raster is
reclassifed from another (<code>is_reclass_of</code> string or null in JSON).
YAML and shell script style outputs are following the JSON output if possible.
The plain text format outputs multi-line human-readable information in natural
language.

<p>
With the <b>-t</b> flag, no output is printed, instead a return code is used to
indicate presence or absence. The convention is the same same the POSIX
<em>test</em> utility, so <em>r.mask.status</em> returns 0 when the mask is
Expand Down
23 changes: 13 additions & 10 deletions raster/r.mask.status/tests/r_mask_status_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ def test_json_no_mask(session_no_data):
session = session_no_data
data = gs.parse_command("r.mask.status", format="json", env=session.env)
assert "present" in data
assert "full_name" in data
assert "name" in data
assert data["name"], "Mask name needs to be always set"
assert data["name"] == "MASK@PERMANENT", "Default mask name and current mapset"
assert "is_reclass_of" in data
assert data["present"] is False
assert not data["full_name"]
assert not data["is_reclass_of"]


Expand All @@ -28,13 +29,13 @@ def test_json_with_r_mask(session_with_data):
gs.run_command("r.mask", raster="a", env=session.env)
data = gs.parse_command("r.mask.status", format="json", env=session.env)
assert data["present"] is True
assert data["full_name"] == "MASK@PERMANENT"
assert data["name"] == "MASK@PERMANENT"
assert data["is_reclass_of"] == "a@PERMANENT"
# Now remove the mask.
gs.run_command("r.mask", flags="r", env=session.env)
data = gs.parse_command("r.mask.status", format="json", env=session.env)
assert data["present"] is False
assert not data["full_name"]
assert data["name"] == "MASK@PERMANENT"
assert not data["is_reclass_of"]


Expand All @@ -44,13 +45,13 @@ def test_json_with_g_copy(session_with_data):
gs.run_command("g.copy", raster="a,MASK", env=session.env)
data = gs.parse_command("r.mask.status", format="json", env=session.env)
assert data["present"] is True
assert data["full_name"] == "MASK@PERMANENT"
assert data["name"] == "MASK@PERMANENT"
assert not data["is_reclass_of"]
# Now remove the mask.
gs.run_command("g.remove", type="raster", name="MASK", flags="f", env=session.env)
data = gs.parse_command("r.mask.status", format="json", env=session.env)
assert data["present"] is False
assert not data["full_name"]
assert data["name"] == "MASK@PERMANENT"
assert not data["is_reclass_of"]


Expand All @@ -60,13 +61,13 @@ def test_shell(session_with_data):
gs.run_command("r.mask", raster="a", env=session.env)
data = gs.parse_command("r.mask.status", format="shell", env=session.env)
assert int(data["present"])
assert data["full_name"] == "MASK@PERMANENT"
assert data["name"] == "MASK@PERMANENT"
assert data["is_reclass_of"] == "a@PERMANENT"
# Now remove the mask.
gs.run_command("r.mask", flags="r", env=session.env)
data = gs.parse_command("r.mask.status", format="shell", env=session.env)
assert not int(data["present"])
assert not data["full_name"]
assert data["name"] == "MASK@PERMANENT"
assert not data["is_reclass_of"]


Expand All @@ -78,14 +79,14 @@ def test_yaml(session_with_data):
text = gs.read_command("r.mask.status", format="yaml", env=session.env)
data = yaml.safe_load(text)
assert data["present"] is True
assert data["full_name"] == "MASK@PERMANENT"
assert data["name"] == "MASK@PERMANENT"
assert data["is_reclass_of"] == "a@PERMANENT"
# Now remove the mask.
gs.run_command("r.mask", flags="r", env=session.env)
text = gs.read_command("r.mask.status", format="yaml", env=session.env)
data = yaml.safe_load(text)
assert data["present"] is False
assert not data["full_name"]
assert data["name"] == "MASK@PERMANENT"
assert not data["is_reclass_of"]


Expand All @@ -101,6 +102,8 @@ def test_plain(session_with_data):
gs.run_command("r.mask", flags="r", env=session.env)
text = gs.read_command("r.mask.status", format="plain", env=session.env)
assert text
assert "MASK@PERMANENT" in text
assert "a@PERMANENT" not in text


def test_without_parameters(session_no_data):
Expand Down

0 comments on commit ba0a495

Please sign in to comment.