From ed35c6ad341b1f4ea2aadb30da3dc82bd2215b07 Mon Sep 17 00:00:00 2001 From: Kriti Birda Date: Fri, 31 May 2024 15:39:56 +0530 Subject: [PATCH 1/8] Add JSON support to v.info module Use parson to add json output format support to the v.info module. The module has various flags to control the fields being output in case of plain format. The current prototype ignores the flags and always outputs all data for the JSON output. --- vector/v.info/Makefile | 2 +- vector/v.info/local_proto.h | 11 +- vector/v.info/main.c | 38 +++- vector/v.info/parse.c | 12 +- vector/v.info/print.c | 313 +++++++++++++++++++------- vector/v.info/testsuite/test_vinfo.py | 51 +++++ 6 files changed, 328 insertions(+), 99 deletions(-) diff --git a/vector/v.info/Makefile b/vector/v.info/Makefile index e7bb7e6eff6..6791e2513c7 100644 --- a/vector/v.info/Makefile +++ b/vector/v.info/Makefile @@ -3,7 +3,7 @@ MODULE_TOPDIR = ../.. PGM = v.info -LIBES = $(VECTORLIB) $(DIG2LIB) $(DBMILIB) $(GISLIB) +LIBES = $(VECTORLIB) $(DIG2LIB) $(DBMILIB) $(GISLIB) $(PARSONLIB) DEPENDENCIES = $(VECTORDEP) $(DIG2DEP) $(DBMIDEP) $(GISDEP) EXTRA_INC = $(VECT_INC) EXTRA_CFLAGS = $(VECT_CFLAGS) diff --git a/vector/v.info/local_proto.h b/vector/v.info/local_proto.h index 8d16b41bbe1..031dda7e6ce 100644 --- a/vector/v.info/local_proto.h +++ b/vector/v.info/local_proto.h @@ -1,20 +1,23 @@ #include +#include #define SHELL_NO 0x00 #define SHELL_BASIC 0x02 #define SHELL_REGION 0x04 #define SHELL_TOPO 0x08 +enum OutputFormat { PLAIN, JSON }; + /* level1.c */ int level_one_info(struct Map_info *); /* parse.c */ -void parse_args(int, char **, char **, char **, int *, int *, int *); +void parse_args(int, char **, char **, char **, int *, int *, int *, enum OutputFormat *); /* print.c */ void format_double(double, char *); -void print_region(struct Map_info *); -void print_topo(struct Map_info *); +void print_region(struct Map_info *, enum OutputFormat, JSON_Object *); +void print_topo(struct Map_info *, enum OutputFormat, JSON_Object *); void print_columns(struct Map_info *, const char *, const char *); void print_info(struct Map_info *); -void print_shell(struct Map_info *, const char *); +void print_shell(struct Map_info *, const char *, enum OutputFormat, JSON_Object *); diff --git a/vector/v.info/main.c b/vector/v.info/main.c index 4506b2b7bf6..6066680fcbd 100644 --- a/vector/v.info/main.c +++ b/vector/v.info/main.c @@ -29,6 +29,11 @@ int main(int argc, char *argv[]) char *input_opt, *field_opt; int hist_flag, col_flag, shell_flag; + enum OutputFormat format; + + JSON_Value *root_value; + JSON_Object *root_object; + struct Map_info Map; G_gisinit(argv[0]); @@ -47,7 +52,13 @@ int main(int argc, char *argv[]) G_debug(1, "LFS is %s", sizeof(off_t) == 8 ? "available" : "not available"); parse_args(argc, argv, &input_opt, &field_opt, &hist_flag, &col_flag, - &shell_flag); + &shell_flag, &format); + + if (format == JSON) { + root_value = json_value_init_object(); + root_object = json_value_get_object(root_value); + json_set_float_serialization_format("%lf"); + } /* try to open head-only on level 2 */ if (Vect_open_old_head2(&Map, input_opt, "", field_opt) < 2) { @@ -82,19 +93,30 @@ int main(int argc, char *argv[]) return (EXIT_SUCCESS); } - if (shell_flag & SHELL_BASIC) { - print_shell(&Map, field_opt); + if ((shell_flag & SHELL_BASIC) || format == JSON) { + print_shell(&Map, field_opt, format, root_object); } - if (shell_flag & SHELL_REGION) { - print_region(&Map); + if ((shell_flag & SHELL_REGION) || format == JSON) { + print_region(&Map, format, root_object); } - if (shell_flag & SHELL_TOPO) { - print_topo(&Map); + if ((shell_flag & SHELL_TOPO) || format == JSON) { + print_topo(&Map, format, root_object); } - if (shell_flag == 0) { + if (shell_flag == 0 && format == PLAIN) { print_info(&Map); } + if (format == JSON) { + char *serialized_string = NULL; + serialized_string = json_serialize_to_string_pretty(root_value); + if (serialized_string == NULL) { + G_fatal_error(_("Failed to initialize pretty JSON string.")); + } + puts(serialized_string); + json_free_serialized_string(serialized_string); + json_value_free(root_value); + } + Vect_close(&Map); return (EXIT_SUCCESS); diff --git a/vector/v.info/parse.c b/vector/v.info/parse.c index 8d439535443..7d59ed922eb 100644 --- a/vector/v.info/parse.c +++ b/vector/v.info/parse.c @@ -6,9 +6,9 @@ #include "local_proto.h" void parse_args(int argc, char **argv, char **input, char **field, int *history, - int *columns, int *shell) + int *columns, int *shell, enum OutputFormat *format_ptr) { - struct Option *input_opt, *field_opt; + struct Option *input_opt, *field_opt, *format_opt; struct Flag *hist_flag, *col_flag, *shell_flag, *region_flag, *topo_flag; input_opt = G_define_standard_option(G_OPT_V_MAP); @@ -42,6 +42,9 @@ void parse_args(int argc, char **argv, char **input, char **field, int *history, topo_flag->description = _("Print topology info in shell script style"); topo_flag->guisection = _("Print"); + format_opt = G_define_standard_option(G_OPT_F_FORMAT); + format_opt->guisection = _("Print"); + if (G_parser(argc, argv)) exit(EXIT_FAILURE); @@ -56,4 +59,9 @@ void parse_args(int argc, char **argv, char **input, char **field, int *history, *shell |= SHELL_REGION; if (topo_flag->answer) *shell |= SHELL_TOPO; + + if (strcmp(format_opt->answer, "json") == 0) + *format_ptr = JSON; + else + *format_ptr = PLAIN; } diff --git a/vector/v.info/print.c b/vector/v.info/print.c index 0830006a777..459024aa14e 100644 --- a/vector/v.info/print.c +++ b/vector/v.info/print.c @@ -5,6 +5,8 @@ #include #include +#include + #include "local_proto.h" #define printline(x) G_faprintf(stdout, " | %-74.74s |\n", x) @@ -38,7 +40,7 @@ static char *format_zone(int zone_num) return zone_str; } -void print_region(struct Map_info *Map) +void print_region(struct Map_info *Map, enum OutputFormat format, JSON_Object* root_object) { char tmp1[1024], tmp2[1024]; @@ -46,20 +48,33 @@ void print_region(struct Map_info *Map) /* print the spatial extent as double values */ Vect_get_map_box(Map, &box); - G_format_northing(box.N, tmp1, -1); - G_format_northing(box.S, tmp2, -1); - fprintf(stdout, "north=%s\n", tmp1); - fprintf(stdout, "south=%s\n", tmp2); - - G_format_easting(box.E, tmp1, -1); - G_format_easting(box.W, tmp2, -1); - fprintf(stdout, "east=%s\n", tmp1); - fprintf(stdout, "west=%s\n", tmp2); - fprintf(stdout, "top=%f\n", box.T); - fprintf(stdout, "bottom=%f\n", box.B); + + switch (format) { + case PLAIN: + G_format_northing(box.N, tmp1, -1); + G_format_northing(box.S, tmp2, -1); + fprintf(stdout, "north=%s\n", tmp1); + fprintf(stdout, "south=%s\n", tmp2); + + G_format_easting(box.E, tmp1, -1); + G_format_easting(box.W, tmp2, -1); + fprintf(stdout, "east=%s\n", tmp1); + fprintf(stdout, "west=%s\n", tmp2); + fprintf(stdout, "top=%f\n", box.T); + fprintf(stdout, "bottom=%f\n", box.B); + break; + case JSON: + json_object_set_number(root_object, "north", box.N); + json_object_set_number(root_object, "south", box.S); + json_object_set_number(root_object, "east", box.E); + json_object_set_number(root_object, "west", box.W); + json_object_set_number(root_object, "top", box.T); + json_object_set_number(root_object, "bottom", box.B); + break; + } } -void print_topo(struct Map_info *Map) +void print_topo(struct Map_info *Map, enum OutputFormat format, JSON_Object* root_object) { int with_z; long nprimitives; @@ -77,50 +92,72 @@ void print_topo(struct Map_info *Map) nprimitives += Vect_get_num_primitives(Map, GV_KERNEL); } - fprintf(stdout, "nodes=%d\n", Vect_get_num_nodes(Map)); - fflush(stdout); - - fprintf(stdout, "points=%d\n", Vect_get_num_primitives(Map, GV_POINT)); - fflush(stdout); - - fprintf(stdout, "lines=%d\n", Vect_get_num_primitives(Map, GV_LINE)); - fflush(stdout); + switch (format) { + case PLAIN: + fprintf(stdout, "nodes=%d\n", Vect_get_num_nodes(Map)); + fflush(stdout); - fprintf(stdout, "boundaries=%d\n", - Vect_get_num_primitives(Map, GV_BOUNDARY)); - fflush(stdout); + fprintf(stdout, "points=%d\n", Vect_get_num_primitives(Map, GV_POINT)); + fflush(stdout); - fprintf(stdout, "centroids=%d\n", - Vect_get_num_primitives(Map, GV_CENTROID)); - fflush(stdout); + fprintf(stdout, "lines=%d\n", Vect_get_num_primitives(Map, GV_LINE)); + fflush(stdout); - fprintf(stdout, "areas=%d\n", Vect_get_num_areas(Map)); - fflush(stdout); + fprintf(stdout, "boundaries=%d\n", + Vect_get_num_primitives(Map, GV_BOUNDARY)); + fflush(stdout); - fprintf(stdout, "islands=%d\n", Vect_get_num_islands(Map)); - fflush(stdout); + fprintf(stdout, "centroids=%d\n", + Vect_get_num_primitives(Map, GV_CENTROID)); + fflush(stdout); - if (with_z) { - fprintf(stdout, "faces=%d\n", Vect_get_num_primitives(Map, GV_FACE)); + fprintf(stdout, "areas=%d\n", Vect_get_num_areas(Map)); fflush(stdout); - fprintf(stdout, "kernels=%d\n", - Vect_get_num_primitives(Map, GV_KERNEL)); + fprintf(stdout, "islands=%d\n", Vect_get_num_islands(Map)); fflush(stdout); - fprintf(stdout, "volumes=%d\n", - Vect_get_num_primitives(Map, GV_VOLUME)); + if (with_z) { + fprintf(stdout, "faces=%d\n", Vect_get_num_primitives(Map, GV_FACE)); + fflush(stdout); + + fprintf(stdout, "kernels=%d\n", + Vect_get_num_primitives(Map, GV_KERNEL)); + fflush(stdout); + + fprintf(stdout, "volumes=%d\n", + Vect_get_num_primitives(Map, GV_VOLUME)); + fflush(stdout); + + fprintf(stdout, "holes=%d\n", Vect_get_num_holes(Map)); + fflush(stdout); + } + + fprintf(stdout, "primitives=%ld\n", nprimitives); fflush(stdout); - fprintf(stdout, "holes=%d\n", Vect_get_num_holes(Map)); + fprintf(stdout, "map3d=%d\n", Vect_is_3d(Map) ? 1 : 0); fflush(stdout); - } - fprintf(stdout, "primitives=%ld\n", nprimitives); - fflush(stdout); + break; + case JSON: + json_object_set_number(root_object, "nodes", Vect_get_num_nodes(Map)); + json_object_set_number(root_object, "points",Vect_get_num_primitives(Map, GV_POINT)); + json_object_set_number(root_object, "lines", Vect_get_num_primitives(Map, GV_LINE)); + json_object_set_number(root_object, "boundaries", Vect_get_num_primitives(Map, GV_BOUNDARY)); + json_object_set_number(root_object, "centroids", Vect_get_num_primitives(Map, GV_CENTROID)); + json_object_set_number(root_object, "areas", Vect_get_num_areas(Map)); + json_object_set_number(root_object, "islands", Vect_get_num_islands(Map)); + if (with_z) { + json_object_set_number(root_object, "faces", Vect_get_num_primitives(Map, GV_FACE)); + json_object_set_number(root_object, "kernels", Vect_get_num_primitives(Map, GV_KERNEL)); + json_object_set_number(root_object, "volumes", Vect_get_num_primitives(Map, GV_VOLUME)); + json_object_set_number(root_object, "holes", Vect_get_num_holes(Map)); + } + json_object_set_number(root_object, "primitives", nprimitives); + json_object_set_number(root_object, "map3d", Vect_is_3d(Map) ? 1 : 0); + } - fprintf(stdout, "map3d=%d\n", Vect_is_3d(Map) ? 1 : 0); - fflush(stdout); } void print_columns(struct Map_info *Map, const char *input_opt, @@ -174,7 +211,7 @@ void print_columns(struct Map_info *Map, const char *input_opt, db_shutdown_driver(driver); } -void print_shell(struct Map_info *Map, const char *field_opt) +void print_shell(struct Map_info *Map, const char *field_opt, enum OutputFormat format, JSON_Object* root_object) { int map_type; int time_ok, first_time_ok, second_time_ok; @@ -197,31 +234,73 @@ void print_shell(struct Map_info *Map, const char *field_opt) map_type = Vect_maptype(Map); - fprintf(stdout, "name=%s\n", Vect_get_name(Map)); - fprintf(stdout, "mapset=%s\n", Vect_get_mapset(Map)); - fprintf(stdout, "location=%s\n", G_location()); - fprintf(stdout, "project=%s\n", G_location()); - fprintf(stdout, "database=%s\n", G_gisdbase()); - fprintf(stdout, "title=%s\n", Vect_get_map_name(Map)); - fprintf(stdout, "scale=1:%d\n", Vect_get_scale(Map)); - fprintf(stdout, "creator=%s\n", Vect_get_person(Map)); - fprintf(stdout, "organization=%s\n", Vect_get_organization(Map)); - fprintf(stdout, "source_date=%s\n", Vect_get_map_date(Map)); + switch (format) { + case PLAIN: + fprintf(stdout, "name=%s\n", Vect_get_name(Map)); + fprintf(stdout, "mapset=%s\n", Vect_get_mapset(Map)); + fprintf(stdout, "location=%s\n", G_location()); + fprintf(stdout, "project=%s\n", G_location()); + fprintf(stdout, "database=%s\n", G_gisdbase()); + fprintf(stdout, "title=%s\n", Vect_get_map_name(Map)); + fprintf(stdout, "scale=1:%d\n", Vect_get_scale(Map)); + fprintf(stdout, "creator=%s\n", Vect_get_person(Map)); + fprintf(stdout, "organization=%s\n", Vect_get_organization(Map)); + fprintf(stdout, "source_date=%s\n", Vect_get_map_date(Map)); + break; + case JSON: + json_object_set_string(root_object, "name", Vect_get_name(Map)); + json_object_set_string(root_object, "mapset", Vect_get_mapset(Map)); + json_object_set_string(root_object, "location", G_location()); + json_object_set_string(root_object, "project", G_location()); + json_object_set_string(root_object, "database", G_gisdbase()); + json_object_set_string(root_object, "title", Vect_get_map_name(Map)); + json_object_set_number(root_object, "scale", Vect_get_scale(Map)); // fixme: 1:scale + json_object_set_string(root_object, "creator", Vect_get_person(Map)); + json_object_set_string(root_object, "organization", Vect_get_organization(Map)); + json_object_set_string(root_object, "source_date", Vect_get_map_date(Map)); + break; + } + /* This shows the TimeStamp (if present) */ if (time_ok == TRUE && (first_time_ok || second_time_ok)) { G_format_timestamp(&ts, timebuff); - fprintf(stdout, "timestamp=%s\n", timebuff); + switch (format) { + case PLAIN: + fprintf(stdout, "timestamp=%s\n", timebuff); + break; + case JSON: + json_object_set_string(root_object, "timestamp", timebuff); + break; + } } else { - fprintf(stdout, "timestamp=none\n"); + switch (format) { + case PLAIN: + fprintf(stdout, "timestamp=none\n"); + break; + case JSON: + json_object_set_null(root_object, "timestamp"); + break; + } } if (map_type == GV_FORMAT_OGR || map_type == GV_FORMAT_OGR_DIRECT) { - fprintf(stdout, "format=%s,%s\n", Vect_maptype_info(Map), - Vect_get_finfo_format_info(Map)); - fprintf(stdout, "ogr_layer=%s\n", Vect_get_finfo_layer_name(Map)); - fprintf(stdout, "ogr_dsn=%s\n", Vect_get_finfo_dsn_name(Map)); - fprintf(stdout, "feature_type=%s\n", Vect_get_finfo_geometry_type(Map)); + switch (format) { + case PLAIN: + fprintf(stdout, "format=%s,%s\n", Vect_maptype_info(Map), + Vect_get_finfo_format_info(Map)); + fprintf(stdout, "ogr_layer=%s\n", Vect_get_finfo_layer_name(Map)); + fprintf(stdout, "ogr_dsn=%s\n", Vect_get_finfo_dsn_name(Map)); + fprintf(stdout, "feature_type=%s\n", Vect_get_finfo_geometry_type(Map)); + break; + case JSON: + // fixme: add format=%,%s + json_object_set_string(root_object, "ogr_layer", Vect_get_finfo_layer_name(Map)); + json_object_set_string(root_object, "ogr_dsn", Vect_get_finfo_dsn_name(Map)); + json_object_set_string(root_object, "feature_type", Vect_get_finfo_geometry_type(Map)); + break; + } + } else if (map_type == GV_FORMAT_POSTGIS) { int topo_format; @@ -230,47 +309,113 @@ void print_shell(struct Map_info *Map, const char *field_opt) finfo = Vect_get_finfo(Map); - fprintf(stdout, "format=%s,%s\n", Vect_maptype_info(Map), - Vect_get_finfo_format_info(Map)); - fprintf(stdout, "pg_table=%s\n", Vect_get_finfo_layer_name(Map)); - fprintf(stdout, "pg_dbname=%s\n", Vect_get_finfo_dsn_name(Map)); - fprintf(stdout, "geometry_column=%s\n", finfo->pg.geom_column); - fprintf(stdout, "feature_type=%s\n", Vect_get_finfo_geometry_type(Map)); + switch (format) { + case PLAIN: + fprintf(stdout, "format=%s,%s\n", Vect_maptype_info(Map), + Vect_get_finfo_format_info(Map)); + fprintf(stdout, "pg_table=%s\n", Vect_get_finfo_layer_name(Map)); + fprintf(stdout, "pg_dbname=%s\n", Vect_get_finfo_dsn_name(Map)); + fprintf(stdout, "geometry_column=%s\n", finfo->pg.geom_column); + fprintf(stdout, "feature_type=%s\n", Vect_get_finfo_geometry_type(Map)); + break; + case JSON: + // fixme: add format=%,%s + json_object_set_string(root_object, "pg_table", Vect_get_finfo_layer_name(Map)); + json_object_set_string(root_object, "pg_dbname", Vect_get_finfo_dsn_name(Map)); + json_object_set_string(root_object, "geometry_column", finfo->pg.geom_column); + json_object_set_string(root_object, "feature_type", Vect_get_finfo_geometry_type(Map)); + break; + } + topo_format = Vect_get_finfo_topology_info(Map, &toposchema_name, &topogeom_column, NULL); if (topo_format == GV_TOPO_POSTGIS) { - fprintf(stdout, "pg_topo_schema=%s\n", toposchema_name); - fprintf(stdout, "pg_topo_column=%s\n", topogeom_column); + switch (format) { + case PLAIN: + fprintf(stdout, "pg_topo_schema=%s\n", toposchema_name); + fprintf(stdout, "pg_topo_column=%s\n", topogeom_column); + break; + case JSON: + json_object_set_string(root_object, "pg_topo_schema", toposchema_name); + json_object_set_string(root_object, "pg_topo_column", topogeom_column); + break; + } } } else { - fprintf(stdout, "format=%s\n", Vect_maptype_info(Map)); + switch (format) { + case PLAIN: + fprintf(stdout, "format=%s\n", Vect_maptype_info(Map)); + break; + case JSON: + json_object_set_string(root_object, "format", Vect_maptype_info(Map)); + break; + } } - fprintf(stdout, "level=%d\n", Vect_level(Map)); - + switch (format) { + case PLAIN: + fprintf(stdout, "level=%d\n", Vect_level(Map)); + break; + case JSON: + json_object_set_number(root_object, "level", Vect_level(Map)); + break; + } if (Vect_level(Map) > 0) { - fprintf(stdout, "num_dblinks=%d\n", Vect_get_num_dblinks(Map)); + switch (format) { + case PLAIN: + fprintf(stdout, "num_dblinks=%d\n", Vect_get_num_dblinks(Map)); + break; + case JSON: + json_object_set_number(root_object, "num_dblinks", Vect_get_num_dblinks(Map)); + break; + } if (Vect_get_num_dblinks(Map) > 0) { fi = Vect_get_field2(Map, field_opt); if (fi != NULL) { - fprintf(stdout, "attribute_layer_number=%i\n", fi->number); - fprintf(stdout, "attribute_layer_name=%s\n", fi->name); - fprintf(stdout, "attribute_database=%s\n", fi->database); - fprintf(stdout, "attribute_database_driver=%s\n", fi->driver); - fprintf(stdout, "attribute_table=%s\n", fi->table); - fprintf(stdout, "attribute_primary_key=%s\n", fi->key); + switch (format) { + case PLAIN: + fprintf(stdout, "attribute_layer_number=%i\n", fi->number); + fprintf(stdout, "attribute_layer_name=%s\n", fi->name); + fprintf(stdout, "attribute_database=%s\n", fi->database); + fprintf(stdout, "attribute_database_driver=%s\n", fi->driver); + fprintf(stdout, "attribute_table=%s\n", fi->table); + fprintf(stdout, "attribute_primary_key=%s\n", fi->key); + break; + case JSON: + json_object_set_number(root_object, "attribute_layer_number", fi->number); + json_object_set_string(root_object, "attribute_layer_name", fi->name); + json_object_set_string(root_object, "attribute_database", fi->database); + json_object_set_string(root_object, "attribute_database_driver", fi->driver); + json_object_set_string(root_object, "attribute_table", fi->table); + json_object_set_string(root_object, "attribute_primary_key", fi->key); + break; + } + } } } - fprintf(stdout, "projection=%s\n", Vect_get_proj_name(Map)); - if (G_projection() == PROJECTION_UTM) { - fprintf(stdout, "zone=%d\n", Vect_get_zone(Map)); + switch (format) { + case PLAIN: + fprintf(stdout, "projection=%s\n", Vect_get_proj_name(Map)); + if (G_projection() == PROJECTION_UTM) { + fprintf(stdout, "zone=%d\n", Vect_get_zone(Map)); + } + fprintf(stdout, "digitization_threshold=%f\n", Vect_get_thresh(Map)); + fprintf(stdout, "comment=%s\n", Vect_get_comment(Map)); + break; + case JSON: + json_object_set_string(root_object, "projection", Vect_get_proj_name(Map)); + if (G_projection() == PROJECTION_UTM) { + json_object_set_number(root_object, "zone", Vect_get_zone(Map)); + } + json_object_set_number(root_object, "digitization_threshold", Vect_get_thresh(Map)); + json_object_set_string(root_object, "comment", Vect_get_comment(Map)); + break; } - fprintf(stdout, "digitization_threshold=%f\n", Vect_get_thresh(Map)); - fprintf(stdout, "comment=%s\n", Vect_get_comment(Map)); + } void print_info(struct Map_info *Map) diff --git a/vector/v.info/testsuite/test_vinfo.py b/vector/v.info/testsuite/test_vinfo.py index b163df02327..aa2e80583a3 100644 --- a/vector/v.info/testsuite/test_vinfo.py +++ b/vector/v.info/testsuite/test_vinfo.py @@ -1,6 +1,10 @@ +import json + from grass.gunittest.case import TestCase from grass.gunittest.main import test +from grass.gunittest.gmodules import SimpleModule + class TestVInfo(TestCase): """Test the shell output of v.info that is not location/mapset or user dependent""" @@ -183,6 +187,53 @@ def test_info_with_db_3d(self): ), ) + def test_json(self): + module = SimpleModule("v.info", map=self.test_vinfo_with_db_3d, format="json") + self.runModule(module) + + expected = { + "name": "test_vinfo_with_db_3d", + "title": "", + "scale": 1.000000, + "organization": "", + "timestamp": "15 Jan 1994", + "format": "native", + "level": 2.000000, + "num_dblinks": 1.000000, + "attribute_layer_number": 1.000000, + "attribute_layer_name": "test_vinfo_with_db_3d", + "attribute_database_driver": "sqlite", + "attribute_table": "test_vinfo_with_db_3d", + "attribute_primary_key": "cat", + "projection": "Lambert Conformal Conic", + "digitization_threshold": 0.000000, + "comment": "", + "nodes": 0.000000, + "points": 5.000000, + "lines": 0.000000, + "boundaries": 0.000000, + "centroids": 0.000000, + "areas": 0.000000, + "islands": 0.000000, + "faces": 0.000000, + "kernels": 0.000000, + "volumes": 0.000000, + "holes": 0.000000, + "primitives": 5.000000, + "map3d": 1.000000 + } + result = json.loads(module.outputs.stdout) + + # the following fields vary with the Grass sample data's path + # therefore only check for their presence in the JSON output + # and not exact values + remove_fields = ["location", "project", "database", "source_date", "attribute_database", + "top", "bottom", "east", "west", "north", "south", "creator", "mapset"] + for field in remove_fields: + self.assertIn(field, result) + result.pop(field) + self.assertDictEqual(expected, result) + def test_database_table(self): """Test the database table column and type of the two vector maps with attribute data""" self.assertModuleKeyValue( From eaccea5b5a09ff7057f8881248ec4ec9f1e80c36 Mon Sep 17 00:00:00 2001 From: Kriti Birda Date: Fri, 31 May 2024 17:57:52 +0530 Subject: [PATCH 2/8] fix lint --- vector/v.info/local_proto.h | 6 +- vector/v.info/print.c | 118 +++++++++++++++++--------- vector/v.info/testsuite/test_vinfo.py | 19 ++++- 3 files changed, 96 insertions(+), 47 deletions(-) diff --git a/vector/v.info/local_proto.h b/vector/v.info/local_proto.h index 031dda7e6ce..243a6ca7668 100644 --- a/vector/v.info/local_proto.h +++ b/vector/v.info/local_proto.h @@ -12,7 +12,8 @@ enum OutputFormat { PLAIN, JSON }; int level_one_info(struct Map_info *); /* parse.c */ -void parse_args(int, char **, char **, char **, int *, int *, int *, enum OutputFormat *); +void parse_args(int, char **, char **, char **, int *, int *, int *, + enum OutputFormat *); /* print.c */ void format_double(double, char *); @@ -20,4 +21,5 @@ void print_region(struct Map_info *, enum OutputFormat, JSON_Object *); void print_topo(struct Map_info *, enum OutputFormat, JSON_Object *); void print_columns(struct Map_info *, const char *, const char *); void print_info(struct Map_info *); -void print_shell(struct Map_info *, const char *, enum OutputFormat, JSON_Object *); +void print_shell(struct Map_info *, const char *, enum OutputFormat, + JSON_Object *); diff --git a/vector/v.info/print.c b/vector/v.info/print.c index 459024aa14e..e5d60878c76 100644 --- a/vector/v.info/print.c +++ b/vector/v.info/print.c @@ -40,7 +40,8 @@ static char *format_zone(int zone_num) return zone_str; } -void print_region(struct Map_info *Map, enum OutputFormat format, JSON_Object* root_object) +void print_region(struct Map_info *Map, enum OutputFormat format, + JSON_Object *root_object) { char tmp1[1024], tmp2[1024]; @@ -74,7 +75,8 @@ void print_region(struct Map_info *Map, enum OutputFormat format, JSON_Object* r } } -void print_topo(struct Map_info *Map, enum OutputFormat format, JSON_Object* root_object) +void print_topo(struct Map_info *Map, enum OutputFormat format, + JSON_Object *root_object) { int with_z; long nprimitives; @@ -118,7 +120,8 @@ void print_topo(struct Map_info *Map, enum OutputFormat format, JSON_Object* roo fflush(stdout); if (with_z) { - fprintf(stdout, "faces=%d\n", Vect_get_num_primitives(Map, GV_FACE)); + fprintf(stdout, "faces=%d\n", + Vect_get_num_primitives(Map, GV_FACE)); fflush(stdout); fprintf(stdout, "kernels=%d\n", @@ -142,22 +145,30 @@ void print_topo(struct Map_info *Map, enum OutputFormat format, JSON_Object* roo break; case JSON: json_object_set_number(root_object, "nodes", Vect_get_num_nodes(Map)); - json_object_set_number(root_object, "points",Vect_get_num_primitives(Map, GV_POINT)); - json_object_set_number(root_object, "lines", Vect_get_num_primitives(Map, GV_LINE)); - json_object_set_number(root_object, "boundaries", Vect_get_num_primitives(Map, GV_BOUNDARY)); - json_object_set_number(root_object, "centroids", Vect_get_num_primitives(Map, GV_CENTROID)); + json_object_set_number(root_object, "points", + Vect_get_num_primitives(Map, GV_POINT)); + json_object_set_number(root_object, "lines", + Vect_get_num_primitives(Map, GV_LINE)); + json_object_set_number(root_object, "boundaries", + Vect_get_num_primitives(Map, GV_BOUNDARY)); + json_object_set_number(root_object, "centroids", + Vect_get_num_primitives(Map, GV_CENTROID)); json_object_set_number(root_object, "areas", Vect_get_num_areas(Map)); - json_object_set_number(root_object, "islands", Vect_get_num_islands(Map)); + json_object_set_number(root_object, "islands", + Vect_get_num_islands(Map)); if (with_z) { - json_object_set_number(root_object, "faces", Vect_get_num_primitives(Map, GV_FACE)); - json_object_set_number(root_object, "kernels", Vect_get_num_primitives(Map, GV_KERNEL)); - json_object_set_number(root_object, "volumes", Vect_get_num_primitives(Map, GV_VOLUME)); - json_object_set_number(root_object, "holes", Vect_get_num_holes(Map)); + json_object_set_number(root_object, "faces", + Vect_get_num_primitives(Map, GV_FACE)); + json_object_set_number(root_object, "kernels", + Vect_get_num_primitives(Map, GV_KERNEL)); + json_object_set_number(root_object, "volumes", + Vect_get_num_primitives(Map, GV_VOLUME)); + json_object_set_number(root_object, "holes", + Vect_get_num_holes(Map)); } json_object_set_number(root_object, "primitives", nprimitives); json_object_set_number(root_object, "map3d", Vect_is_3d(Map) ? 1 : 0); } - } void print_columns(struct Map_info *Map, const char *input_opt, @@ -211,7 +222,8 @@ void print_columns(struct Map_info *Map, const char *input_opt, db_shutdown_driver(driver); } -void print_shell(struct Map_info *Map, const char *field_opt, enum OutputFormat format, JSON_Object* root_object) +void print_shell(struct Map_info *Map, const char *field_opt, + enum OutputFormat format, JSON_Object *root_object) { int map_type; int time_ok, first_time_ok, second_time_ok; @@ -254,10 +266,13 @@ void print_shell(struct Map_info *Map, const char *field_opt, enum OutputFormat json_object_set_string(root_object, "project", G_location()); json_object_set_string(root_object, "database", G_gisdbase()); json_object_set_string(root_object, "title", Vect_get_map_name(Map)); - json_object_set_number(root_object, "scale", Vect_get_scale(Map)); // fixme: 1:scale + json_object_set_number(root_object, "scale", + Vect_get_scale(Map)); // fixme: 1:scale json_object_set_string(root_object, "creator", Vect_get_person(Map)); - json_object_set_string(root_object, "organization", Vect_get_organization(Map)); - json_object_set_string(root_object, "source_date", Vect_get_map_date(Map)); + json_object_set_string(root_object, "organization", + Vect_get_organization(Map)); + json_object_set_string(root_object, "source_date", + Vect_get_map_date(Map)); break; } @@ -291,16 +306,19 @@ void print_shell(struct Map_info *Map, const char *field_opt, enum OutputFormat Vect_get_finfo_format_info(Map)); fprintf(stdout, "ogr_layer=%s\n", Vect_get_finfo_layer_name(Map)); fprintf(stdout, "ogr_dsn=%s\n", Vect_get_finfo_dsn_name(Map)); - fprintf(stdout, "feature_type=%s\n", Vect_get_finfo_geometry_type(Map)); + fprintf(stdout, "feature_type=%s\n", + Vect_get_finfo_geometry_type(Map)); break; case JSON: // fixme: add format=%,%s - json_object_set_string(root_object, "ogr_layer", Vect_get_finfo_layer_name(Map)); - json_object_set_string(root_object, "ogr_dsn", Vect_get_finfo_dsn_name(Map)); - json_object_set_string(root_object, "feature_type", Vect_get_finfo_geometry_type(Map)); + json_object_set_string(root_object, "ogr_layer", + Vect_get_finfo_layer_name(Map)); + json_object_set_string(root_object, "ogr_dsn", + Vect_get_finfo_dsn_name(Map)); + json_object_set_string(root_object, "feature_type", + Vect_get_finfo_geometry_type(Map)); break; } - } else if (map_type == GV_FORMAT_POSTGIS) { int topo_format; @@ -316,14 +334,19 @@ void print_shell(struct Map_info *Map, const char *field_opt, enum OutputFormat fprintf(stdout, "pg_table=%s\n", Vect_get_finfo_layer_name(Map)); fprintf(stdout, "pg_dbname=%s\n", Vect_get_finfo_dsn_name(Map)); fprintf(stdout, "geometry_column=%s\n", finfo->pg.geom_column); - fprintf(stdout, "feature_type=%s\n", Vect_get_finfo_geometry_type(Map)); + fprintf(stdout, "feature_type=%s\n", + Vect_get_finfo_geometry_type(Map)); break; case JSON: // fixme: add format=%,%s - json_object_set_string(root_object, "pg_table", Vect_get_finfo_layer_name(Map)); - json_object_set_string(root_object, "pg_dbname", Vect_get_finfo_dsn_name(Map)); - json_object_set_string(root_object, "geometry_column", finfo->pg.geom_column); - json_object_set_string(root_object, "feature_type", Vect_get_finfo_geometry_type(Map)); + json_object_set_string(root_object, "pg_table", + Vect_get_finfo_layer_name(Map)); + json_object_set_string(root_object, "pg_dbname", + Vect_get_finfo_dsn_name(Map)); + json_object_set_string(root_object, "geometry_column", + finfo->pg.geom_column); + json_object_set_string(root_object, "feature_type", + Vect_get_finfo_geometry_type(Map)); break; } @@ -336,8 +359,10 @@ void print_shell(struct Map_info *Map, const char *field_opt, enum OutputFormat fprintf(stdout, "pg_topo_column=%s\n", topogeom_column); break; case JSON: - json_object_set_string(root_object, "pg_topo_schema", toposchema_name); - json_object_set_string(root_object, "pg_topo_column", topogeom_column); + json_object_set_string(root_object, "pg_topo_schema", + toposchema_name); + json_object_set_string(root_object, "pg_topo_column", + topogeom_column); break; } } @@ -348,7 +373,8 @@ void print_shell(struct Map_info *Map, const char *field_opt, enum OutputFormat fprintf(stdout, "format=%s\n", Vect_maptype_info(Map)); break; case JSON: - json_object_set_string(root_object, "format", Vect_maptype_info(Map)); + json_object_set_string(root_object, "format", + Vect_maptype_info(Map)); break; } } @@ -367,7 +393,8 @@ void print_shell(struct Map_info *Map, const char *field_opt, enum OutputFormat fprintf(stdout, "num_dblinks=%d\n", Vect_get_num_dblinks(Map)); break; case JSON: - json_object_set_number(root_object, "num_dblinks", Vect_get_num_dblinks(Map)); + json_object_set_number(root_object, "num_dblinks", + Vect_get_num_dblinks(Map)); break; } @@ -379,20 +406,26 @@ void print_shell(struct Map_info *Map, const char *field_opt, enum OutputFormat fprintf(stdout, "attribute_layer_number=%i\n", fi->number); fprintf(stdout, "attribute_layer_name=%s\n", fi->name); fprintf(stdout, "attribute_database=%s\n", fi->database); - fprintf(stdout, "attribute_database_driver=%s\n", fi->driver); + fprintf(stdout, "attribute_database_driver=%s\n", + fi->driver); fprintf(stdout, "attribute_table=%s\n", fi->table); fprintf(stdout, "attribute_primary_key=%s\n", fi->key); break; case JSON: - json_object_set_number(root_object, "attribute_layer_number", fi->number); - json_object_set_string(root_object, "attribute_layer_name", fi->name); - json_object_set_string(root_object, "attribute_database", fi->database); - json_object_set_string(root_object, "attribute_database_driver", fi->driver); - json_object_set_string(root_object, "attribute_table", fi->table); - json_object_set_string(root_object, "attribute_primary_key", fi->key); + json_object_set_number( + root_object, "attribute_layer_number", fi->number); + json_object_set_string(root_object, "attribute_layer_name", + fi->name); + json_object_set_string(root_object, "attribute_database", + fi->database); + json_object_set_string( + root_object, "attribute_database_driver", fi->driver); + json_object_set_string(root_object, "attribute_table", + fi->table); + json_object_set_string(root_object, "attribute_primary_key", + fi->key); break; } - } } } @@ -407,15 +440,16 @@ void print_shell(struct Map_info *Map, const char *field_opt, enum OutputFormat fprintf(stdout, "comment=%s\n", Vect_get_comment(Map)); break; case JSON: - json_object_set_string(root_object, "projection", Vect_get_proj_name(Map)); + json_object_set_string(root_object, "projection", + Vect_get_proj_name(Map)); if (G_projection() == PROJECTION_UTM) { json_object_set_number(root_object, "zone", Vect_get_zone(Map)); } - json_object_set_number(root_object, "digitization_threshold", Vect_get_thresh(Map)); + json_object_set_number(root_object, "digitization_threshold", + Vect_get_thresh(Map)); json_object_set_string(root_object, "comment", Vect_get_comment(Map)); break; } - } void print_info(struct Map_info *Map) diff --git a/vector/v.info/testsuite/test_vinfo.py b/vector/v.info/testsuite/test_vinfo.py index aa2e80583a3..3a4a066123f 100644 --- a/vector/v.info/testsuite/test_vinfo.py +++ b/vector/v.info/testsuite/test_vinfo.py @@ -220,15 +220,28 @@ def test_json(self): "volumes": 0.000000, "holes": 0.000000, "primitives": 5.000000, - "map3d": 1.000000 + "map3d": 1.000000, } result = json.loads(module.outputs.stdout) # the following fields vary with the Grass sample data's path # therefore only check for their presence in the JSON output # and not exact values - remove_fields = ["location", "project", "database", "source_date", "attribute_database", - "top", "bottom", "east", "west", "north", "south", "creator", "mapset"] + remove_fields = [ + "location", + "project", + "database", + "source_date", + "attribute_database", + "top", + "bottom", + "east", + "west", + "north", + "south", + "creator", + "mapset", + ] for field in remove_fields: self.assertIn(field, result) result.pop(field) From db587156de772e8dfe444c88b89351edd19cfd3c Mon Sep 17 00:00:00 2001 From: Kriti Birda <164247895+kritibirda26@users.noreply.github.com> Date: Fri, 7 Jun 2024 14:09:59 +0530 Subject: [PATCH 3/8] Apply suggestions from code review Co-authored-by: Vaclav Petras --- vector/v.info/main.c | 3 +-- vector/v.info/print.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/vector/v.info/main.c b/vector/v.info/main.c index 6066680fcbd..fcb15ec9428 100644 --- a/vector/v.info/main.c +++ b/vector/v.info/main.c @@ -107,8 +107,7 @@ int main(int argc, char *argv[]) } if (format == JSON) { - char *serialized_string = NULL; - serialized_string = json_serialize_to_string_pretty(root_value); + char *serialized_string = json_serialize_to_string_pretty(root_value); if (serialized_string == NULL) { G_fatal_error(_("Failed to initialize pretty JSON string.")); } diff --git a/vector/v.info/print.c b/vector/v.info/print.c index e5d60878c76..dc35488efe5 100644 --- a/vector/v.info/print.c +++ b/vector/v.info/print.c @@ -167,7 +167,7 @@ void print_topo(struct Map_info *Map, enum OutputFormat format, Vect_get_num_holes(Map)); } json_object_set_number(root_object, "primitives", nprimitives); - json_object_set_number(root_object, "map3d", Vect_is_3d(Map) ? 1 : 0); + json_object_set_boolean(root_object, "map3d", Vect_is_3d(Map)); } } @@ -262,7 +262,6 @@ void print_shell(struct Map_info *Map, const char *field_opt, case JSON: json_object_set_string(root_object, "name", Vect_get_name(Map)); json_object_set_string(root_object, "mapset", Vect_get_mapset(Map)); - json_object_set_string(root_object, "location", G_location()); json_object_set_string(root_object, "project", G_location()); json_object_set_string(root_object, "database", G_gisdbase()); json_object_set_string(root_object, "title", Vect_get_map_name(Map)); From 159dbf61fe47c533855ccd98bddebfdb4698db2d Mon Sep 17 00:00:00 2001 From: Kriti Birda Date: Fri, 7 Jun 2024 16:08:12 +0530 Subject: [PATCH 4/8] document json format for v.info and add changes from code review --- vector/v.info/main.c | 1 - vector/v.info/print.c | 10 +++++-- vector/v.info/testsuite/test_vinfo.py | 1 - vector/v.info/v.info.html | 43 +++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/vector/v.info/main.c b/vector/v.info/main.c index fcb15ec9428..6f4aa9a8fcf 100644 --- a/vector/v.info/main.c +++ b/vector/v.info/main.c @@ -57,7 +57,6 @@ int main(int argc, char *argv[]) if (format == JSON) { root_value = json_value_init_object(); root_object = json_value_get_object(root_value); - json_set_float_serialization_format("%lf"); } /* try to open head-only on level 2 */ diff --git a/vector/v.info/print.c b/vector/v.info/print.c index dc35488efe5..1cd5a31b75a 100644 --- a/vector/v.info/print.c +++ b/vector/v.info/print.c @@ -309,7 +309,10 @@ void print_shell(struct Map_info *Map, const char *field_opt, Vect_get_finfo_geometry_type(Map)); break; case JSON: - // fixme: add format=%,%s + json_object_set_string(root_object, "format", + Vect_maptype_info(Map)); + json_object_set_string(root_object, "format-detail", + Vect_get_finfo_format_info(Map)); json_object_set_string(root_object, "ogr_layer", Vect_get_finfo_layer_name(Map)); json_object_set_string(root_object, "ogr_dsn", @@ -337,7 +340,10 @@ void print_shell(struct Map_info *Map, const char *field_opt, Vect_get_finfo_geometry_type(Map)); break; case JSON: - // fixme: add format=%,%s + json_object_set_string(root_object, "format", + Vect_maptype_info(Map)); + json_object_set_string(root_object, "format-detail", + Vect_get_finfo_format_info(Map)); json_object_set_string(root_object, "pg_table", Vect_get_finfo_layer_name(Map)); json_object_set_string(root_object, "pg_dbname", diff --git a/vector/v.info/testsuite/test_vinfo.py b/vector/v.info/testsuite/test_vinfo.py index 3a4a066123f..1e1d0f3043d 100644 --- a/vector/v.info/testsuite/test_vinfo.py +++ b/vector/v.info/testsuite/test_vinfo.py @@ -228,7 +228,6 @@ def test_json(self): # therefore only check for their presence in the JSON output # and not exact values remove_fields = [ - "location", "project", "database", "source_date", diff --git a/vector/v.info/v.info.html b/vector/v.info/v.info.html index 1facf172dc9..90404397889 100644 --- a/vector/v.info/v.info.html +++ b/vector/v.info/v.info.html @@ -136,6 +136,49 @@

Basic metadata information in shell script style

bottom=0.000000 +

Output in JSON format

+
+{
+    "name": "geology",
+    "mapset": "PERMANENT",
+    "project": "nc_spm_08_grass7",
+    "database": "\/grassdata",
+    "title": "North Carolina geology map (polygon map)",
+    "scale": 1,
+    "creator": "helena",
+    "organization": "NC OneMap",
+    "source_date": "Mon Nov  6 15:48:53 2006",
+    "timestamp": null,
+    "format": "native",
+    "level": 2,
+    "num_dblinks": 1,
+    "attribute_layer_number": 1,
+    "attribute_layer_name": "geology",
+    "attribute_database": "\/grassdata\/nc_spm_08_grass7\/PERMANENT\/sqlite\/sqlite.db",
+    "attribute_database_driver": "sqlite",
+    "attribute_table": "geology",
+    "attribute_primary_key": "cat",
+    "projection": "Lambert Conformal Conic",
+    "digitization_threshold": 0,
+    "comment": "",
+    "north": 318117.43741634465,
+    "south": 10875.827232091688,
+    "east": 930172.31282271142,
+    "west": 123971.19498978264,
+    "top": 0,
+    "bottom": 0,
+    "nodes": 2724,
+    "points": 0,
+    "lines": 0,
+    "boundaries": 3649,
+    "centroids": 1832,
+    "areas": 1832,
+    "islands": 907,
+    "primitives": 5481,
+    "map3d": false
+}
+
+

PYTHON

See Python From b95ea0157f66005edc06ed57a44cac9ef47dc7b3 Mon Sep 17 00:00:00 2001 From: Kriti Birda Date: Sun, 16 Jun 2024 18:01:47 +0530 Subject: [PATCH 5/8] add shell output format --- lib/gis/testsuite/test_parser_json.py | 4 +++- vector/v.info/local_proto.h | 2 +- vector/v.info/parse.c | 18 +++++++++++++++--- vector/v.info/print.c | 26 ++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/lib/gis/testsuite/test_parser_json.py b/lib/gis/testsuite/test_parser_json.py index b325de2314c..918fb453d04 100644 --- a/lib/gis/testsuite/test_parser_json.py +++ b/lib/gis/testsuite/test_parser_json.py @@ -97,13 +97,15 @@ def test_v_info(self): inputs = [ {"param": "map", "value": "hospitals@PERMANENT"}, {"param": "layer", "value": "1"}, + {"param": "format", "value": "plain"}, ] stdout, stderr = subprocess.Popen(args, stdout=subprocess.PIPE).communicate() print(stdout) json_code = json.loads(decode(stdout)) + print(json_code) self.assertEqual(json_code["module"], "v.info") - self.assertEqual(len(json_code["inputs"]), 2) + self.assertEqual(len(json_code["inputs"]), 3) self.assertEqual(json_code["inputs"], inputs) diff --git a/vector/v.info/local_proto.h b/vector/v.info/local_proto.h index 243a6ca7668..1ed32468562 100644 --- a/vector/v.info/local_proto.h +++ b/vector/v.info/local_proto.h @@ -6,7 +6,7 @@ #define SHELL_REGION 0x04 #define SHELL_TOPO 0x08 -enum OutputFormat { PLAIN, JSON }; +enum OutputFormat { PLAIN, SHELL, JSON }; /* level1.c */ int level_one_info(struct Map_info *); diff --git a/vector/v.info/parse.c b/vector/v.info/parse.c index 7d59ed922eb..54820420e01 100644 --- a/vector/v.info/parse.c +++ b/vector/v.info/parse.c @@ -43,6 +43,10 @@ void parse_args(int argc, char **argv, char **input, char **field, int *history, topo_flag->guisection = _("Print"); format_opt = G_define_standard_option(G_OPT_F_FORMAT); + format_opt->options = "plain,shell,json"; + format_opt->descriptions = _("plain;Human readable text output;" + "shell;shell script style text output;" + "json;JSON (JavaScript Object Notation);"); format_opt->guisection = _("Print"); if (G_parser(argc, argv)) @@ -60,8 +64,16 @@ void parse_args(int argc, char **argv, char **input, char **field, int *history, if (topo_flag->answer) *shell |= SHELL_TOPO; - if (strcmp(format_opt->answer, "json") == 0) - *format_ptr = JSON; - else + if (strcmp(format_opt->answer, "plain") == 0) { *format_ptr = PLAIN; + } + else if (strcmp(format_opt->answer, "json") == 0) + *format_ptr = JSON; + else { + *format_ptr = SHELL; + } + + if (*shell != 0 && *format_ptr == PLAIN) { + *format_ptr = SHELL; + } } diff --git a/vector/v.info/print.c b/vector/v.info/print.c index 1cd5a31b75a..ab8fe61e987 100644 --- a/vector/v.info/print.c +++ b/vector/v.info/print.c @@ -52,6 +52,8 @@ void print_region(struct Map_info *Map, enum OutputFormat format, switch (format) { case PLAIN: + break; + case SHELL: G_format_northing(box.N, tmp1, -1); G_format_northing(box.S, tmp2, -1); fprintf(stdout, "north=%s\n", tmp1); @@ -96,6 +98,8 @@ void print_topo(struct Map_info *Map, enum OutputFormat format, switch (format) { case PLAIN: + break; + case SHELL: fprintf(stdout, "nodes=%d\n", Vect_get_num_nodes(Map)); fflush(stdout); @@ -248,6 +252,8 @@ void print_shell(struct Map_info *Map, const char *field_opt, switch (format) { case PLAIN: + break; + case SHELL: fprintf(stdout, "name=%s\n", Vect_get_name(Map)); fprintf(stdout, "mapset=%s\n", Vect_get_mapset(Map)); fprintf(stdout, "location=%s\n", G_location()); @@ -280,6 +286,8 @@ void print_shell(struct Map_info *Map, const char *field_opt, G_format_timestamp(&ts, timebuff); switch (format) { case PLAIN: + break; + case SHELL: fprintf(stdout, "timestamp=%s\n", timebuff); break; case JSON: @@ -290,6 +298,8 @@ void print_shell(struct Map_info *Map, const char *field_opt, else { switch (format) { case PLAIN: + break; + case SHELL: fprintf(stdout, "timestamp=none\n"); break; case JSON: @@ -301,6 +311,8 @@ void print_shell(struct Map_info *Map, const char *field_opt, if (map_type == GV_FORMAT_OGR || map_type == GV_FORMAT_OGR_DIRECT) { switch (format) { case PLAIN: + break; + case SHELL: fprintf(stdout, "format=%s,%s\n", Vect_maptype_info(Map), Vect_get_finfo_format_info(Map)); fprintf(stdout, "ogr_layer=%s\n", Vect_get_finfo_layer_name(Map)); @@ -331,6 +343,8 @@ void print_shell(struct Map_info *Map, const char *field_opt, switch (format) { case PLAIN: + break; + case SHELL: fprintf(stdout, "format=%s,%s\n", Vect_maptype_info(Map), Vect_get_finfo_format_info(Map)); fprintf(stdout, "pg_table=%s\n", Vect_get_finfo_layer_name(Map)); @@ -360,6 +374,8 @@ void print_shell(struct Map_info *Map, const char *field_opt, if (topo_format == GV_TOPO_POSTGIS) { switch (format) { case PLAIN: + break; + case SHELL: fprintf(stdout, "pg_topo_schema=%s\n", toposchema_name); fprintf(stdout, "pg_topo_column=%s\n", topogeom_column); break; @@ -375,6 +391,8 @@ void print_shell(struct Map_info *Map, const char *field_opt, else { switch (format) { case PLAIN: + break; + case SHELL: fprintf(stdout, "format=%s\n", Vect_maptype_info(Map)); break; case JSON: @@ -386,6 +404,8 @@ void print_shell(struct Map_info *Map, const char *field_opt, switch (format) { case PLAIN: + break; + case SHELL: fprintf(stdout, "level=%d\n", Vect_level(Map)); break; case JSON: @@ -395,6 +415,8 @@ void print_shell(struct Map_info *Map, const char *field_opt, if (Vect_level(Map) > 0) { switch (format) { case PLAIN: + break; + case SHELL: fprintf(stdout, "num_dblinks=%d\n", Vect_get_num_dblinks(Map)); break; case JSON: @@ -408,6 +430,8 @@ void print_shell(struct Map_info *Map, const char *field_opt, if (fi != NULL) { switch (format) { case PLAIN: + break; + case SHELL: fprintf(stdout, "attribute_layer_number=%i\n", fi->number); fprintf(stdout, "attribute_layer_name=%s\n", fi->name); fprintf(stdout, "attribute_database=%s\n", fi->database); @@ -437,6 +461,8 @@ void print_shell(struct Map_info *Map, const char *field_opt, switch (format) { case PLAIN: + break; + case SHELL: fprintf(stdout, "projection=%s\n", Vect_get_proj_name(Map)); if (G_projection() == PROJECTION_UTM) { fprintf(stdout, "zone=%d\n", Vect_get_zone(Map)); From 83fa6ed740deb4ecd91dbcd20d8f0948af51ec45 Mon Sep 17 00:00:00 2001 From: Kriti Birda Date: Sun, 16 Jun 2024 20:10:58 +0530 Subject: [PATCH 6/8] fix scale and precision --- vector/v.info/print.c | 8 +++--- vector/v.info/testsuite/test_vinfo.py | 36 +++++++++++++-------------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/vector/v.info/print.c b/vector/v.info/print.c index ab8fe61e987..6c36d6391f6 100644 --- a/vector/v.info/print.c +++ b/vector/v.info/print.c @@ -250,6 +250,9 @@ void print_shell(struct Map_info *Map, const char *field_opt, map_type = Vect_maptype(Map); + char scale_tmp[18]; + snprintf(scale_tmp, 18, "1:%d", Vect_get_scale(Map)); + switch (format) { case PLAIN: break; @@ -260,7 +263,7 @@ void print_shell(struct Map_info *Map, const char *field_opt, fprintf(stdout, "project=%s\n", G_location()); fprintf(stdout, "database=%s\n", G_gisdbase()); fprintf(stdout, "title=%s\n", Vect_get_map_name(Map)); - fprintf(stdout, "scale=1:%d\n", Vect_get_scale(Map)); + fprintf(stdout, "scale=%s\n", scale_tmp); fprintf(stdout, "creator=%s\n", Vect_get_person(Map)); fprintf(stdout, "organization=%s\n", Vect_get_organization(Map)); fprintf(stdout, "source_date=%s\n", Vect_get_map_date(Map)); @@ -271,8 +274,7 @@ void print_shell(struct Map_info *Map, const char *field_opt, json_object_set_string(root_object, "project", G_location()); json_object_set_string(root_object, "database", G_gisdbase()); json_object_set_string(root_object, "title", Vect_get_map_name(Map)); - json_object_set_number(root_object, "scale", - Vect_get_scale(Map)); // fixme: 1:scale + json_object_set_string(root_object, "scale", scale_tmp); json_object_set_string(root_object, "creator", Vect_get_person(Map)); json_object_set_string(root_object, "organization", Vect_get_organization(Map)); diff --git a/vector/v.info/testsuite/test_vinfo.py b/vector/v.info/testsuite/test_vinfo.py index 1e1d0f3043d..b5b3aa17b82 100644 --- a/vector/v.info/testsuite/test_vinfo.py +++ b/vector/v.info/testsuite/test_vinfo.py @@ -194,33 +194,33 @@ def test_json(self): expected = { "name": "test_vinfo_with_db_3d", "title": "", - "scale": 1.000000, + "scale": "1:1", "organization": "", "timestamp": "15 Jan 1994", "format": "native", - "level": 2.000000, - "num_dblinks": 1.000000, - "attribute_layer_number": 1.000000, + "level": 2, + "num_dblinks": 1, + "attribute_layer_number": 1, "attribute_layer_name": "test_vinfo_with_db_3d", "attribute_database_driver": "sqlite", "attribute_table": "test_vinfo_with_db_3d", "attribute_primary_key": "cat", "projection": "Lambert Conformal Conic", - "digitization_threshold": 0.000000, + "digitization_threshold": 0, "comment": "", - "nodes": 0.000000, - "points": 5.000000, - "lines": 0.000000, - "boundaries": 0.000000, - "centroids": 0.000000, - "areas": 0.000000, - "islands": 0.000000, - "faces": 0.000000, - "kernels": 0.000000, - "volumes": 0.000000, - "holes": 0.000000, - "primitives": 5.000000, - "map3d": 1.000000, + "nodes": 0, + "points": 5, + "lines": 0, + "boundaries": 0, + "centroids": 0, + "areas": 0, + "islands": 0, + "faces": 0, + "kernels": 0, + "volumes": 0, + "holes": 0, + "primitives": 5, + "map3d": 1, } result = json.loads(module.outputs.stdout) From 4f5e8fe86bca7a12232f69b7e3930a928895bbb3 Mon Sep 17 00:00:00 2001 From: Kriti Birda Date: Tue, 18 Jun 2024 00:55:05 +0530 Subject: [PATCH 7/8] document python example --- vector/v.info/v.info.html | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/vector/v.info/v.info.html b/vector/v.info/v.info.html index 90404397889..05e7903ac2d 100644 --- a/vector/v.info/v.info.html +++ b/vector/v.info/v.info.html @@ -194,6 +194,21 @@

PYTHON

gcore.vector_info_topo('geology') # for `v.info shell=topo` +Here is an example of how the JSON output format can be used to integrate Grass with other python libraries easily. +
+import grass.script as gs
+import pandas as pd
+
+# Run v.info command
+busstops = gs.run_command("v.info", map="busstopsall", format="json")
+
+# Load data into dataframe
+df = pd.DataFrame([busstops])
+
+# Display the DataFrame
+print(df)
+
+

SEE ALSO

From 071d259198d4b55e7eff55930a48b9f2f5c950f5 Mon Sep 17 00:00:00 2001 From: Kriti Birda Date: Tue, 18 Jun 2024 21:22:05 +0530 Subject: [PATCH 8/8] update handling for shell script output --- vector/v.info/parse.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/vector/v.info/parse.c b/vector/v.info/parse.c index 54820420e01..b63b7a64055 100644 --- a/vector/v.info/parse.c +++ b/vector/v.info/parse.c @@ -65,15 +65,25 @@ void parse_args(int argc, char **argv, char **input, char **field, int *history, *shell |= SHELL_TOPO; if (strcmp(format_opt->answer, "plain") == 0) { - *format_ptr = PLAIN; + // if shell flags are specified and format=PLAIN (default), + // print in shell script format + if (*shell != 0) { + *format_ptr = SHELL; + } + else { + *format_ptr = PLAIN; + } } else if (strcmp(format_opt->answer, "json") == 0) *format_ptr = JSON; else { *format_ptr = SHELL; - } - - if (*shell != 0 && *format_ptr == PLAIN) { - *format_ptr = SHELL; + // if shell flags are specified with format=shell, obey them + // if only format=shell is specified, print all info + if (*shell == 0) { + *shell |= SHELL_BASIC; + *shell |= SHELL_REGION; + *shell |= SHELL_TOPO; + } } }