diff --git a/python/grass/app/cli.py b/python/grass/app/cli.py index 0cf05afbb47..24f0e2356ed 100644 --- a/python/grass/app/cli.py +++ b/python/grass/app/cli.py @@ -68,6 +68,49 @@ def subcommand_run_tool(args, tool_args: list, print_help: bool) -> int: # other special flags, so later use of --json in tools will fail # with the other flags active. return tools.call_cmd(command).returncode + if args.link_raster: + for raster in args.link_raster: + gs.run_command( + "r.external", + input=raster, + output=Path(raster).stem, + flags="o", + env=session.env, + errors="status", + ) + gs.run_command("g.list", type="raster", env=session.env) + if args.link_vector: + for vector in args.link_vector: + gs.run_command( + "v.external", + input=vector, + output=Path(vector).stem, + flags="o", + env=session.env, + errors="status", + ) + if args.out_raster: + for out_r in args.out_raster: + abs_out_path = os.path.abspath(out_r) + Path(abs_out_path).mkdir(exist_ok=True, parents=True) + gs.run_command( + "r.external.out", + directory=abs_out_path, + env=session.env, + errors="status", + format="GTiff", + ) + if args.out_vector: + for out_v in args.out_vector: + abs_out_path = os.path.abspath(out_v) + Path(abs_out_path).mkdir(exist_ok=True, parents=True) + gs.run_command( + "v.external.out", + output=out_v, + env=session.env, + errors="status", + format="GPKG", + ) return tools.run_cmd(command).returncode except subprocess.CalledProcessError as error: return error.returncode @@ -224,6 +267,26 @@ def add_project_subparser(subparsers): action="store_true", help="overwrite existing project", ) + create_parser.add_argument( + "--link-raster", + action="append", + help="link a raster map to the project (can be used multiple times)", + ) + create_parser.add_argument( + "--link-vector", + action="append", + help="link a vector map to the project (can be used multiple times)", + ) + create_parser.add_argument( + "--out-raster", + action="append", + help="define external format for raster output (can be used multiple times)", + ) + create_parser.add_argument( + "--out-vector", + action="append", + help="define external format for vector output (can be used multiple times)", + ) create_parser.set_defaults(func=subcommand_create_project) @@ -240,7 +303,6 @@ def main(args=None, program=None): subparsers = parser.add_subparsers( title="subcommands", dest="subcommand", required=True ) - # Subcommand parsers run_subparser = subparsers.add_parser( @@ -255,6 +317,30 @@ def main(args=None, program=None): run_subparser.add_argument( "--project", type=str, help="project to use for computations" ) + run_subparser.add_argument( + "--link-raster", + type=str, + action="append", + help="Link a raster file (r.external) before execution", + ) + run_subparser.add_argument( + "--link-vector", + type=str, + action="append", + help="Link a vector file (v.external) before execution", + ) + run_subparser.add_argument( + "--out-raster", + type=str, + action="append", + help="Define external format for raster output (r.external.out)", + ) + run_subparser.add_argument( + "--out-vector", + type=str, + action="append", + help="Define external format for vector output (v.external.out)", + ) run_subparser.set_defaults(func=subcommand_run_tool) add_project_subparser(subparsers) diff --git a/raster/r.external/testsuite/test_r_external.py b/raster/r.external/testsuite/test_r_external.py index a22498eb773..81db192db38 100644 --- a/raster/r.external/testsuite/test_r_external.py +++ b/raster/r.external/testsuite/test_r_external.py @@ -134,6 +134,83 @@ def test_4(self): raster="test_external_map", reference=univar_string, precision=3 ) + def test_link_raster_simple(self): + self.assertModule( + "r.external", + input="data/elevation.asc", + output="test_external_map", + flags="e", + ) + + self.runModule("g.region", raster="test_external_map") + + def test_link_raster_with_title(self): + self.assertModule( + "r.external", + input="data/elevation.asc", + output="test_external_map", + title="Test Elevation Map", + flags="e", + ) + + def test_link_raster_overwrite(self): + self.runModule( + "r.external", + input="data/elevation.asc", + output="test_external_map", + flags="e", + ) + + self.assertModule( + "r.external", + input="data/elevation.asc", + output="test_external_map", + flags="e", + overwrite=True, + ) + + def test_invalid_input_fails(self): + self.assertModuleFail( + "r.external", + input="non_existent_file.tif", + output="should_not_exist", + flags="e", + ) + + def test_link_multiple_rasters(self): + self.runModule("g.remove", type="raster", name="map_1", flags="f") + self.runModule("g.remove", type="raster", name="map_2", flags="f") + + self.assertModule( + "r.external", input="data/elevation.asc", output="map_1", flags="e" + ) + + self.assertModule( + "r.external", input="data/elevation.asc", output="map_2", flags="e" + ) + + def test_link_sequential_calls(self): + self.runModule("g.remove", type="raster", name="first_map", flags="f") + self.runModule("g.remove", type="raster", name="second_map", flags="f") + + self.runModule( + "r.external", input="data/elevation.asc", output="first_map", flags="e" + ) + + self.assertModule( + "r.external", input="data/elevation.asc", output="second_map", flags="e" + ) + + def test_link_with_project_context(self): + self.assertModule( + "r.external", + input="data/elevation.asc", + output="test_external_map", + flags="e", + ) + + self.runModule("g.list", type="raster", pattern="test_external_map") + def test_netCDF_3d_1(self): self.assertModule( "r.external",