Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion vector/v.info/local_proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#define STR_LEN 1024
#define BUFSZ 256

enum OutputFormat { PLAIN, SHELL, JSON };
enum OutputFormat { PLAIN, SHELL, JSON, CSV, NONE };

/* level1.c */
int level_one_info(struct Map_info *);
Expand Down
16 changes: 14 additions & 2 deletions vector/v.info/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ 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->options = "plain,shell,json,csv";
format_opt->descriptions = _("plain;Human readable text output;"
"shell;shell script style text output;"
"json;JSON (JavaScript Object Notation);");
"json;JSON (JavaScript Object Notation);"
"csv;CSV (Comma Separated Values);");
format_opt->answer = NULL;
format_opt->required = NO;
format_opt->guisection = _("Print");
Expand Down Expand Up @@ -78,11 +79,22 @@ void parse_args(int argc, char **argv, char **input, char **field, int *history,
*print_content |= PRINT_CONTENT_TOPO;
}
}
else if (format_opt->answer && strcmp(format_opt->answer, "csv") == 0) {
if (!*columns) {
G_fatal_error(_("format=csv is only valid with -c flag."));
}
*format_ptr = CSV;
}
else if (!format_opt->answer && *print_content == PRINT_CONTENT_UNSET &&
!*columns && !*history) {
// No flags and no format specified, default to plain.
*format_ptr = PLAIN;
}
else if (!format_opt->answer && *columns) { // -c without `format=`
// Backward compatibilty: sep should be pipe + header skipped
// sep and header is handled during printing
*format_ptr = NONE;
}
else {
*format_ptr = SHELL;
// If flags are specified with format=shell, obey them just as for JSON.
Expand Down
42 changes: 42 additions & 0 deletions vector/v.info/print.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ void print_region(struct Map_info *Map, enum OutputFormat format,
G_json_object_set_number(root_object, "top", box.T);
G_json_object_set_number(root_object, "bottom", box.B);
break;
default: // case CSV, NONE
break;
}
}

Expand Down Expand Up @@ -172,6 +174,8 @@ void print_topo(struct Map_info *Map, enum OutputFormat format,
}
G_json_object_set_number(root_object, "primitives", nprimitives);
G_json_object_set_boolean(root_object, "map3d", Vect_is_3d(Map));
default: // case NONE, CSV
break;
}
}

Expand Down Expand Up @@ -201,6 +205,9 @@ void print_columns(struct Map_info *Map, const char *input_opt,
"layer <%s>:\n"),
field_opt);
}
if (format == CSV) {
fprintf(stdout, "%s,%s\n", "name", "sql_type");
}

if ((fi = Vect_get_field2(Map, field_opt)) == NULL) {
Vect_close(Map);
Expand Down Expand Up @@ -242,6 +249,17 @@ void print_columns(struct Map_info *Map, const char *input_opt,
for (col = 0; col < ncols; col++) {
switch (format) {
case SHELL:
G_fatal_error(_("format=shell is not valid with -c flag."));
break;

case CSV:
fprintf(stdout, "%s,%s\n",
db_get_column_name(db_get_table_column(table, col)),
db_sqltype_name(db_get_column_sqltype(
db_get_table_column(table, col))));
break;

case NONE: // Backward Compatibility
fprintf(stdout, "%s|%s\n",
db_sqltype_name(
db_get_column_sqltype(db_get_table_column(table, col))),
Expand Down Expand Up @@ -354,6 +372,8 @@ void print_shell(struct Map_info *Map, const char *field_opt,
G_json_object_set_string(root_object, "source_date",
Vect_get_map_date(Map));
break;
default: // case CSV, NONE
break;
}

/* This shows the TimeStamp (if present) */
Expand All @@ -368,6 +388,8 @@ void print_shell(struct Map_info *Map, const char *field_opt,
case JSON:
G_json_object_set_string(root_object, "timestamp", timebuff);
break;
default: // case CSV, NONE
break;
}
}
else {
Expand All @@ -380,6 +402,8 @@ void print_shell(struct Map_info *Map, const char *field_opt,
case JSON:
G_json_object_set_null(root_object, "timestamp");
break;
default: // case CSV, NONE
break;
}
}

Expand All @@ -403,6 +427,8 @@ void print_shell(struct Map_info *Map, const char *field_opt,
Vect_get_finfo_dsn_name(Map));
G_json_object_set_string(root_object, "feature_type", geom_type);
break;
default: // case CSV, NONE
break;
}
}
else if (map_type == GV_FORMAT_POSTGIS) {
Expand Down Expand Up @@ -434,6 +460,8 @@ void print_shell(struct Map_info *Map, const char *field_opt,
finfo->pg.geom_column);
G_json_object_set_string(root_object, "feature_type", geom_type);
break;
default: // case CSV, NONE
break;
}

topo_format = Vect_get_finfo_topology_info(Map, &toposchema_name,
Expand All @@ -452,6 +480,8 @@ void print_shell(struct Map_info *Map, const char *field_opt,
G_json_object_set_string(root_object, "pg_topo_column",
topogeom_column);
break;
default: // case CSV, NONE
break;
}
}
G_free(topogeom_column);
Expand All @@ -467,6 +497,8 @@ void print_shell(struct Map_info *Map, const char *field_opt,
case JSON:
G_json_object_set_string(root_object, "format", maptype_str);
break;
default:
break;
}
}

Expand All @@ -479,6 +511,8 @@ void print_shell(struct Map_info *Map, const char *field_opt,
case JSON:
G_json_object_set_number(root_object, "level", Vect_level(Map));
break;
default: // case CSV, NONE
break;
}
if (Vect_level(Map) > 0) {
switch (format) {
Expand All @@ -491,6 +525,8 @@ void print_shell(struct Map_info *Map, const char *field_opt,
G_json_object_set_number(root_object, "num_dblinks",
Vect_get_num_dblinks(Map));
break;
default: // case CSV, NONE
break;
}

if (Vect_get_num_dblinks(Map) > 0) {
Expand Down Expand Up @@ -522,6 +558,8 @@ void print_shell(struct Map_info *Map, const char *field_opt,
G_json_object_set_string(root_object,
"attribute_primary_key", fi->key);
break;
default: // case CSV, NONE
break;
}
}
Vect_destroy_field_info(fi);
Expand Down Expand Up @@ -549,6 +587,8 @@ void print_shell(struct Map_info *Map, const char *field_opt,
Vect_get_thresh(Map));
G_json_object_set_string(root_object, "comment", Vect_get_comment(Map));
break;
default: // case CSV, NONE
break;
}
G_free(finfo_lname);
G_free((void *)maptype_str);
Expand Down Expand Up @@ -892,6 +932,8 @@ void print_history(struct Map_info *Map, enum OutputFormat format)
mapset_path[0] = '\0';
}
break;
default: // case CSV, NONE
break;
}
}

Expand Down
29 changes: 29 additions & 0 deletions vector/v.info/testsuite/test_vinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from grass.gunittest.main import test

from grass.gunittest.gmodules import SimpleModule
from grass.exceptions import CalledModuleError


class TestVInfo(TestCase):
Expand Down Expand Up @@ -472,6 +473,34 @@ def test_database_table(self):
reference={"INTEGER": "cat", "DOUBLE PRECISION": "elevation"},
)

def test_column_csv_format(self):
"""Test v.info -c format=csv output"""
expected = "name,sql_type\ncat,INTEGER\nelevation,DOUBLE PRECISION\n"

module = SimpleModule(
"v.info", map=self.test_vinfo_with_db, flags="c", format="csv"
)
self.runModule(module)
self.assertEqual(module.outputs.stdout, expected)

def test_column_default_format(self):
"""Test backward compatibility -c"""
expected = "INTEGER|cat\nDOUBLE PRECISION|elevation\n"

module = SimpleModule("v.info", map=self.test_vinfo_with_db, flags="c")
self.runModule(module)
self.assertEqual(module.outputs.stdout, expected)

def test_error_invalid_flag(self):
"""Test for error: `format=shell -c` and `format=csv` without -c"""
with self.assertRaises(CalledModuleError):
self.runModule(
"v.info", map=self.test_vinfo_with_db, flags="c", format="shell"
)

with self.assertRaises(CalledModuleError):
self.runModule("v.info", map=self.test_vinfo_with_db, format="csv")


if __name__ == "__main__":
test()
Loading