From e11ed76599dc0864125d208fe63db8071789d710 Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Tue, 15 Oct 2024 13:26:48 -0400 Subject: [PATCH 1/3] r.mask.status: Always output name of the mask 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). --- include/grass/defs/raster.h | 1 + lib/raster/mask_info.c | 21 ++++++++++++ raster/r.mask.status/main.c | 34 +++++++------------ raster/r.mask.status/r.mask.status.html | 20 ++++++++--- .../r.mask.status/tests/r_mask_status_test.py | 23 +++++++------ 5 files changed, 63 insertions(+), 36 deletions(-) diff --git a/include/grass/defs/raster.h b/include/grass/defs/raster.h index 7f358562c72..bbdc8bfeaa1 100644 --- a/include/grass/defs/raster.h +++ b/include/grass/defs/raster.h @@ -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); diff --git a/lib/raster/mask_info.c b/lib/raster/mask_info.c index 317bab75b63..bfc1c9f8d5a 100644 --- a/lib/raster/mask_info.c +++ b/lib/raster/mask_info.c @@ -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 uses the mask name "MASK@", where 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@". + return G_fully_qualified_name("MASK", G_mapset()); +} + /** * @brief Get raster mask status information * diff --git a/raster/r.mask.status/main.c b/raster/r.mask.status/main.c index 16790adf35c..b0a7b9185c0 100644 --- a/raster/r.mask.status/main.c +++ b/raster/r.mask.status/main.c @@ -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) @@ -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); @@ -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); @@ -135,19 +130,16 @@ 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 @@ -155,14 +147,14 @@ int report_status(struct Parameters *params) 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"), diff --git a/raster/r.mask.status/r.mask.status.html b/raster/r.mask.status/r.mask.status.html index 248ee3ea317..fb1ee248773 100644 --- a/raster/r.mask.status/r.mask.status.html +++ b/raster/r.mask.status/r.mask.status.html @@ -1,11 +1,21 @@

DESCRIPTION

The r.mask.status 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. - -

+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 +(present boolean in JSON), what is raster name used to represent +the mask (name string in JSON), and whether the raster is +reclassifed from another (name 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. + +

With the -t flag, no output is printed, instead a return code is used to indicate presence or absence. The convention is the same same the POSIX test utility, so r.mask.status returns 0 when the mask is diff --git a/raster/r.mask.status/tests/r_mask_status_test.py b/raster/r.mask.status/tests/r_mask_status_test.py index deafdfb145b..a5d406ad581 100644 --- a/raster/r.mask.status/tests/r_mask_status_test.py +++ b/raster/r.mask.status/tests/r_mask_status_test.py @@ -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"] @@ -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"] @@ -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"] @@ -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"] @@ -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"] @@ -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): From c9744ab33338475367ee2df0bf81c75b0b5f51b1 Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Thu, 31 Oct 2024 10:54:56 -0400 Subject: [PATCH 2/3] Fix wording --- lib/raster/mask_info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/raster/mask_info.c b/lib/raster/mask_info.c index bfc1c9f8d5a..25d61341ebe 100644 --- a/lib/raster/mask_info.c +++ b/lib/raster/mask_info.c @@ -55,7 +55,7 @@ char *Rast_mask_info(void) * The returned raster map name is fully qualified, i.e., in the form % "name@mapset". * - * The uses the mask name "MASK@", where is the current + * The mask name is "MASK@", where is the current * mapset. * * The memory for the returned mask name is dynamically allocated using From 70d14edfe9ce17ce4407ee2fdf9fb12c07962d7b Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Thu, 31 Oct 2024 10:57:44 -0400 Subject: [PATCH 3/3] Fix key name --- raster/r.mask.status/r.mask.status.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raster/r.mask.status/r.mask.status.html b/raster/r.mask.status/r.mask.status.html index fb1ee248773..cb3897820f5 100644 --- a/raster/r.mask.status/r.mask.status.html +++ b/raster/r.mask.status/r.mask.status.html @@ -10,7 +10,7 @@

DESCRIPTION

The tool can be used to check if the mask is currently set (present boolean in JSON), what is raster name used to represent the mask (name string in JSON), and whether the raster is -reclassifed from another (name string or null in JSON). +reclassifed from another (is_reclass_of 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.