[GRASS-SVN] r62469 - in grass/trunk: gui/wxpython/mapdisp lib/python/script vector/v.what vector/v.what/testsuite vector/v.what/testsuite/data
svn_grass at osgeo.org
svn_grass at osgeo.org
Tue Oct 28 20:36:05 PDT 2014
Author: annakrat
Date: 2014-10-28 20:36:05 -0700 (Tue, 28 Oct 2014)
New Revision: 62469
Modified:
grass/trunk/gui/wxpython/mapdisp/frame.py
grass/trunk/lib/python/script/vector.py
grass/trunk/vector/v.what/main.c
grass/trunk/vector/v.what/testsuite/data/table1.csv
grass/trunk/vector/v.what/testsuite/test_vwhat_layers.py
grass/trunk/vector/v.what/testsuite/test_vwhat_ncspm.py
grass/trunk/vector/v.what/what.c
grass/trunk/vector/v.what/what.h
Log:
v.what: add json format to simplify parsing output and thus to fix #2431
Modified: grass/trunk/gui/wxpython/mapdisp/frame.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/frame.py 2014-10-29 02:24:30 UTC (rev 62468)
+++ grass/trunk/gui/wxpython/mapdisp/frame.py 2014-10-29 03:36:05 UTC (rev 62469)
@@ -867,7 +867,9 @@
if rast:
rastQuery = grass.raster_what(map=rast, coord=(east, north))
if vect:
- vectQuery = grass.vector_what(map=vect, coord=(east, north), distance=qdist)
+ encoding = UserSettings.Get(group='atm', key='encoding', subkey='value')
+ vectQuery = grass.vector_what(map=vect, coord=(east, north), distance=qdist,
+ encoding=encoding)
self._QueryMapDone()
if 'Id' in vectQuery:
self._queryHighlight(vectQuery)
Modified: grass/trunk/lib/python/script/vector.py
===================================================================
--- grass/trunk/lib/python/script/vector.py 2014-10-29 02:24:30 UTC (rev 62468)
+++ grass/trunk/lib/python/script/vector.py 2014-10-29 03:36:05 UTC (rev 62469)
@@ -258,7 +258,11 @@
return {'columns': columns, 'values': values}
-def vector_what(map, coord, distance=0.0, ttype=None):
+json = None
+orderedDict = None
+
+
+def vector_what(map, coord, distance=0.0, ttype=None, encoding=None):
"""Query vector map at given locations
To query one vector map at one location
@@ -336,7 +340,7 @@
coord_list.append('%f,%f' % (e, n))
cmdParams = dict(quiet = True,
- flags = 'ag',
+ flags = 'aj',
map = ','.join(map_list),
layer = ','.join(layer_list),
coordinates = ','.join(coord_list),
@@ -345,7 +349,7 @@
cmdParams['type'] = ','.join(ttype)
ret = read_command('v.what',
- **cmdParams)
+ **cmdParams).strip()
if "LC_ALL" in os.environ:
os.environ["LC_ALL"] = locale
@@ -354,62 +358,31 @@
if not ret:
return data
- # parse `v.what -g` output is a nightmare
- # TODO: change `v.what -g` format or add parsable format (e.g. XML)
- dict_attrb = None
- dict_map = None
- dict_layer = None
- attr_pseudo_key = 'Attributes'
- for item in ret.splitlines():
+ # lazy import
+ global json
+ global orderedDict
+ if json is None:
+ import json
+ if orderedDict is None:
try:
- key, value = __builtin__.map(lambda x: x.strip(), item.split('=', 1))
- except ValueError:
- continue
- if key in ('East', 'North'):
- continue
+ from collections import OrderedDict
+ orderedDict = OrderedDict
+ except ImportError:
+ orderedDict = dict
- if key == 'Map':
- # attach the last one from the previous map
- if dict_map is not None:
- dict_main = copy.copy(dict_map)
- if dict_layer is not None:
- dict_main.update(dict_layer)
- data.append(dict_main)
- dict_map = {key : value}
- dict_layer = None
- dict_attrb = None
- elif key == 'Layer':
- if not dict_attrb:
- # attach the last the previous Layer
- if dict_layer is not None:
- dict_main = copy.copy(dict_map)
- dict_main.update(dict_layer)
- data.append(dict_main)
- dict_layer = {key: int(value)}
- dict_attrb = None
- else:
- dict_attrb[key] = value
- elif key == 'Key_column':
- dict_layer[key] = value
- dict_attrb = dict()
- dict_layer[attr_pseudo_key] = dict_attrb
- elif dict_attrb is not None:
- dict_attrb[key] = value
- elif dict_layer is not None:
- if key == 'Category':
- dict_layer[key] = int(value)
- else:
- dict_layer[key] = value
+ if encoding:
+ result = json.loads(ret, object_pairs_hook=orderedDict, encoding=encoding)
+ else:
+ result = json.loads(ret, object_pairs_hook=orderedDict)
+
+ for vmap in result['Maps']:
+ cats = vmap.pop('Categories', None)
+ if cats:
+ for cat in cats:
+ tmp = vmap.copy()
+ tmp.update(cat)
+ data.append(tmp)
else:
- dict_map[key] = value
- # TODO: there are some keys which has non-string values
- # examples: Sq_Meters, Hectares, Acres, Sq_Miles
+ data.append(vmap)
- # attach the last one
- if dict_map is not None:
- dict_main = copy.copy(dict_map)
- if dict_layer:
- dict_main.update(dict_layer)
- data.append(dict_main)
-
return data
Modified: grass/trunk/vector/v.what/main.c
===================================================================
--- grass/trunk/vector/v.what/main.c 2014-10-29 02:24:30 UTC (rev 62468)
+++ grass/trunk/vector/v.what/main.c 2014-10-29 03:36:05 UTC (rev 62469)
@@ -33,7 +33,7 @@
int main(int argc, char **argv)
{
struct {
- struct Flag *print, *topo, *shell;
+ struct Flag *print, *topo, *shell, *json;
} flag;
struct {
struct Option *map, *field, *coords, *maxdist, *type;
@@ -97,6 +97,11 @@
flag.shell->key = 'g';
flag.shell->description = _("Print the stats in shell script style");
flag.shell->guisection = _("Print");
+
+ flag.json = G_define_flag();
+ flag.json->key = 'j';
+ flag.json->description = _("Print the stats in JSON");
+ flag.json->guisection = _("Print");
if (G_parser(argc, argv))
exit(EXIT_FAILURE);
@@ -112,6 +117,9 @@
else
G_fatal_error(_("No input vector maps!"));
+ if (flag.shell->answer && flag.json->answer)
+ G_fatal_error(_("Flags g and j are mutually exclusive"));
+
maxd = atof(opt.maxdist->answer);
type = Vect_option_to_types(opt.type);
@@ -178,7 +186,7 @@
ret = sscanf(buf, "%lf%c%lf", &xval, &ch, &yval);
if (ret == 3 && (ch == ',' || ch == ' ' || ch == '\t')) {
what(Map, nvects, vect, xval, yval, maxd, type, flag.topo->answer,
- flag.print->answer, flag.shell->answer, field);
+ flag.print->answer, flag.shell->answer, flag.json->answer, field);
}
else {
G_warning(_("Unknown input format, skipping: '%s'"), buf);
@@ -192,7 +200,7 @@
xval = atof(opt.coords->answers[i]);
yval = atof(opt.coords->answers[i + 1]);
what(Map, nvects, vect, xval, yval, maxd, type, flag.topo->answer,
- flag.print->answer, flag.shell->answer, field);
+ flag.print->answer, flag.shell->answer, flag.json->answer, field);
}
}
Modified: grass/trunk/vector/v.what/testsuite/data/table1.csv
===================================================================
--- grass/trunk/vector/v.what/testsuite/data/table1.csv 2014-10-29 02:24:30 UTC (rev 62468)
+++ grass/trunk/vector/v.what/testsuite/data/table1.csv 2014-10-29 03:36:05 UTC (rev 62469)
@@ -1,2 +1,2 @@
cat,text,number
-1,"xxx",6
+1,"Petrášová",6
Modified: grass/trunk/vector/v.what/testsuite/test_vwhat_layers.py
===================================================================
--- grass/trunk/vector/v.what/testsuite/test_vwhat_layers.py 2014-10-29 02:24:30 UTC (rev 62468)
+++ grass/trunk/vector/v.what/testsuite/test_vwhat_layers.py 2014-10-29 03:36:05 UTC (rev 62469)
@@ -48,7 +48,7 @@
Table: t1
Key column: cat_
cat_ : 1
-text : xxx
+text : Petrášová
number : 6
Layer: 2
Category: 3
@@ -92,7 +92,7 @@
Table=t1
Key_column=cat_
cat_=1
-text=xxx
+text=Petrášová
number=6
Layer=2
Category=3
@@ -144,6 +144,16 @@
self.assertModule(self.vwhat)
self.assertLooksLike(reference=out3, actual=self.vwhat.outputs.stdout)
+ def test_print_options_json(self):
+ import json
+ self.vwhat.flags['j'].value = True
+ self.vwhat.flags['a'].value = True
+ self.assertModule(self.vwhat)
+ try:
+ json.loads(self.vwhat.outputs.stdout, encoding='utf-8')
+ except ValueError:
+ self.fail(msg="No JSON object could be decoded:\n" + self.vwhat.outputs.stdout)
+
if __name__ == '__main__':
test()
Modified: grass/trunk/vector/v.what/testsuite/test_vwhat_ncspm.py
===================================================================
--- grass/trunk/vector/v.what/testsuite/test_vwhat_ncspm.py 2014-10-29 02:24:30 UTC (rev 62468)
+++ grass/trunk/vector/v.what/testsuite/test_vwhat_ncspm.py 2014-10-29 03:36:05 UTC (rev 62469)
@@ -6,6 +6,10 @@
out1 = """East: 636661
North: 226489
------------------------------------------------------------------
+Map: bridges
+Mapset: PERMANENT
+Nothing found.
+------------------------------------------------------------------
Map: roadsmajor
Mapset: PERMANENT
Type: Line
@@ -36,6 +40,10 @@
out2 = """East: 636661
North: 226489
------------------------------------------------------------------
+Map: bridges
+Mapset: PERMANENT
+Nothing found.
+------------------------------------------------------------------
Map: roadsmajor
Mapset: PERMANENT
Type: Line
@@ -114,6 +122,9 @@
out3 = """East=636661
North=226489
+Map=bridges
+Mapset=PERMANENT
+
Map=roadsmajor
Mapset=PERMANENT
Type=Line
@@ -189,13 +200,17 @@
out4 = """East: 636661
North: 226489
------------------------------------------------------------------
+Map: bridges
+Mapset: PERMANENT
+Nothing found.
+------------------------------------------------------------------
Map: roadsmajor
Mapset: PERMANENT
-Nothing Found.
+Nothing found.
------------------------------------------------------------------
Map: precip_30ynormals_3d
Mapset: PERMANENT
-Nothing Found.
+Nothing found.
------------------------------------------------------------------
Map: lakes
Mapset: PERMANENT
@@ -212,8 +227,8 @@
class TestNCMaps(TestCase):
def setUp(self):
- self.vwhat = SimpleModule('v.what', map=['roadsmajor', 'precip_30ynormals_3d', 'lakes'],
- layer=['-1', '-1', '-1'], coordinates=[636661, 226489],
+ self.vwhat = SimpleModule('v.what', map=['bridges', 'roadsmajor', 'precip_30ynormals_3d', 'lakes'],
+ layer=['-1', '-1', '-1', '-1'], coordinates=[636661, 226489],
distance=1000)
def test_multiple_maps(self):
@@ -234,6 +249,14 @@
self.assertModule(self.vwhat)
self.assertLooksLike(reference=out4, actual=self.vwhat.outputs.stdout)
+ def test_print_options_json(self):
+ import json
+ self.vwhat.flags['j'].value = True
+ self.assertModule(self.vwhat)
+ try:
+ json.loads(self.vwhat.outputs.stdout)
+ except ValueError:
+ self.fail(msg="No JSON object could be decoded:\n" + self.vwhat.outputs.stdout)
if __name__ == '__main__':
- test()
\ No newline at end of file
+ test()
Modified: grass/trunk/vector/v.what/what.c
===================================================================
--- grass/trunk/vector/v.what/what.c 2014-10-29 02:24:30 UTC (rev 62468)
+++ grass/trunk/vector/v.what/what.c 2014-10-29 03:36:05 UTC (rev 62469)
@@ -17,7 +17,7 @@
static void F_generate(const char *drvname, const char *dbname,
const char *tblname, const char *key, int keyval,
- char **form)
+ int script, int json, char **form)
{
int col, ncols, sqltype, more;
char buf[5000];
@@ -87,8 +87,14 @@
colname = db_get_column_name(column);
G_debug(2, "%s: %s", colname, db_get_string(&str));
-
- sprintf(buf, "%s : %s\n", colname, db_get_string(&str));
+ if (json) {
+ sprintf(buf, "%s\"%s\": \"%s\"", col == 0 ? "" : ",\n",
+ colname, db_get_string(&str));
+ }
+ else if (script)
+ sprintf(buf, "%s=%s\n", colname, db_get_string(&str));
+ else
+ sprintf(buf, "%s : %s\n", colname, db_get_string(&str));
db_append_string(&html, buf);
}
}
@@ -106,7 +112,7 @@
}
void what(struct Map_info *Map, int nvects, char **vect, double east, double north,
- double maxdist, int qtype, int topo, int showextra, int script, int *field)
+ double maxdist, int qtype, int topo, int showextra, int script, int json, int *field)
{
int type;
char east_buf[40], north_buf[40];
@@ -173,6 +179,9 @@
fprintf(stdout, "East=%s\nNorth=%s\n", east_buf,
north_buf);
}
+ else if (json){
+ fprintf(stdout, "{\"Coordinates\": {\"East\": %s, \"North\": %s}", east_buf,
+ north_buf);}
else {
fprintf(stdout, "East: %s\nNorth: %s\n", east_buf,
north_buf);
@@ -189,6 +198,19 @@
fprintf(stdout, "\nMap=%s\nMapset=%s\n", Map[i].name,
Map[i].mapset);
}
+ else if (json) {
+ if (!i) {
+ if (line + area > 0 || G_verbose() >= G_verbose_std())
+ fprintf(stdout, ",\n\"Maps\":\n[{\"Map\": \"%s\",\n\"Mapset\": \"%s\"",
+ Map[i].name, Map[i].mapset);
+ else
+ fprintf(stdout, "{\"Maps\":\n[{\"Map\": \"%s\",\n\"Mapset\": \"%s\"",
+ Map[i].name, Map[i].mapset);
+ }
+ else
+ fprintf(stdout, ",\n{\"Map\": \"%s\",\n\"Mapset\": \"%s\"",
+ Map[i].name, Map[i].mapset);
+ }
else {
fprintf(stdout, "%s", SEP);
fprintf(stdout, "\nMap: %s \nMapset: %s\n", Map[i].name,
@@ -198,9 +220,10 @@
nlines++;
if (line + area == 0) {
- if (!script) {
- fprintf(stdout, _("Nothing Found.\n"));
- }
+ if (json)
+ fprintf(stdout, "}\n");
+ else if (!script)
+ fprintf(stdout, _("Nothing found.\n"));
nlines++;
continue;
}
@@ -208,8 +231,12 @@
if (line > 0) {
type = Vect_read_line(&Map[i], Points, Cats, line);
- if (field[i] != -1 && !Vect_cat_get(Cats, field[i], NULL))
- continue;
+ if (field[i] != -1 && !Vect_cat_get(Cats, field[i], NULL)) {
+ if (json) {
+ fprintf(stdout, "}\n");
+ }
+ continue;
+ }
switch (type) {
case GV_POINT:
@@ -252,6 +279,12 @@
"Id=%d\nType=%s\nLeft=%d\nRight=%d\n",
line, buf, left, right);
}
+ else if (json) {
+ fprintf(stdout, ",\n\"Feature_max_distance\": %f", maxdist);
+ fprintf(stdout,
+ ",\n\"Id\": %d,\n\"Type\": \"%s\",\n\"Left\": %d,\n\"Right\": %d",
+ line, buf, left, right);
+ }
else {
fprintf(stdout, "Looking for features within: %f\n",
maxdist);
@@ -283,6 +316,11 @@
_("Node[%d]=%d\nNumber_lines=%d\nCoordinates=%.6f,%.6f,%.6f\n"),
n, node[n], nnlines, nx, ny, nz);
}
+ else if (json) {
+ fprintf(stdout,
+ _(",\n\"Node[%d]\": %d,\n\"Number_lines\": %d,\n\"Coordinates\": %.6f,%.6f,%.6f"),
+ n, node[n], nnlines, nx, ny, nz);
+ }
else {
fprintf(stdout,
_("Node[%d]: %d\nNumber of lines: %d\nCoordinates: %.6f, %.6f, %.6f\n"),
@@ -298,6 +336,10 @@
fprintf(stdout, "Id=%5d\nAngle=%.8f\n",
nodeline, angle);
}
+ else if (json) {
+ fprintf(stdout, ",\n\"Id\": %5d,\n\"Angle\": %.8f",
+ nodeline, angle);
+ }
else {
fprintf(stdout, _("Id: %5d\nAngle: %.8f\n"),
nodeline, angle);
@@ -313,6 +355,12 @@
if (type & GV_LINES)
fprintf(stdout, "Length=%f\n", l);
}
+ else if (json) {
+ fprintf(stdout, ",\n\"Type\": \"%s\"", buf);
+ fprintf(stdout, ",\n\"Id\": %d", line);
+ if (type & GV_LINES)
+ fprintf(stdout, ",\n\"Length\": %f", l);
+ }
else {
fprintf(stdout, _("Type: %s\n"), buf);
fprintf(stdout, _("Id: %d\n"), line);
@@ -330,6 +378,9 @@
if (script) {
fprintf(stdout, "Point_height=%f\n", Points->z[0]);
}
+ else if (json) {
+ fprintf(stdout, ",\n\"Point_height\": %f", Points->z[0]);
+ }
else {
fprintf(stdout, _("Point height: %f\n"),
Points->z[0]);
@@ -347,6 +398,9 @@
if (script) {
fprintf(stdout, "Line_height=%f\n", min);
}
+ else if (json) {
+ fprintf(stdout, ",\n\"Line_height\": %f", min);
+ }
else {
fprintf(stdout, _("Line height: %f\n"), min);
}
@@ -357,6 +411,11 @@
"Line_height_min=%f\nLine_height_max=%f\n",
min, max);
}
+ else if (json) {
+ fprintf(stdout,
+ ",\n\"Line_height_min\": %f,\n\"Line_height_max\": %f",
+ min, max);
+ }
else {
fprintf(stdout,
_("Line height min: %f\nLine height max: %f\n"),
@@ -372,6 +431,9 @@
if (script) {
fprintf(stdout, "Type=Area\nArea_height=%f\n", z);
}
+ else if (json) {
+ fprintf(stdout, ",\n\"Type\": \"Area\",\n\"Area_height\": %f", z);
+ }
else {
fprintf(stdout, _("Type: Area\nArea height: %f\n"), z);
}
@@ -380,6 +442,9 @@
if (script) {
fprintf(stdout, "Type=Area\n");
}
+ else if (json) {
+ fprintf(stdout, ",\n\"Type\": \"Area\"");
+ }
else {
fprintf(stdout, _("Type: Area\n"));
}
@@ -402,6 +467,10 @@
fprintf(stdout, "Area=%d\nNumber_isles=%d\n", area,
nisles);
}
+ else if (json) {
+ fprintf(stdout, ",\n\"Area\": %d,\n\"Number_isles\": %d", area,
+ nisles);
+ }
else {
fprintf(stdout, _("Area: %d\nNumber of isles: %d\n"),
area, nisles);
@@ -412,6 +481,9 @@
if (script) {
fprintf(stdout, "Isle[%d]=%d\n", isleidx, isle);
}
+ else if (json) {
+ fprintf(stdout, ",\n\"Isle[%d]\": %d", isleidx, isle);
+ }
else {
fprintf(stdout, _("Isle[%d]: %d\n"), isleidx, isle);
}
@@ -425,6 +497,10 @@
fprintf(stdout, "Island=%d\nIsland_area=%d\n", isle,
isle_area);
}
+ else if (json) {
+ fprintf(stdout, ",\n\"Island\": %d,\n\"Island_area\": %d", isle,
+ isle_area);
+ }
else {
fprintf(stdout, _("Island: %d In area: %d\n"), isle,
isle_area);
@@ -438,6 +514,12 @@
fprintf(stdout, "Acres=%.3f\nSq_Miles=%.4f\n",
acres, sq_miles);
}
+ else if (json) {
+ fprintf(stdout, ",\n\"Sq_Meters\": %.3f,\n\"Hectares\": %.3f",
+ sq_meters, hectares);
+ fprintf(stdout, ",\n\"Acres\": %.3f,\n\"Sq_Miles\": %.4f",
+ acres, sq_miles);
+ }
else {
fprintf(stdout, _("Sq Meters: %.3f\nHectares: %.3f\n"),
sq_meters, hectares);
@@ -454,8 +536,10 @@
if (Cats->n_cats > 0) {
int j;
- char *formbuf1, *formbuf2;
-
+ char *formbuf1;
+ if (json) {
+ fprintf(stdout, ",\n\"Categories\": [");
+ }
for (j = 0; j < Cats->n_cats; j++) {
G_debug(2, "field = %d category = %d\n", Cats->field[j],
Cats->cat[j]);
@@ -463,6 +547,10 @@
fprintf(stdout, "Layer=%d\nCategory=%d\n", Cats->field[j],
Cats->cat[j]);
}
+ else if (json) {
+ fprintf(stdout, "%s\n{\"Layer\": %d, \"Category\": %d", j == 0 ? "": ",",
+ Cats->field[j], Cats->cat[j]);
+ }
else {
fprintf(stdout, _("Layer: %d\nCategory: %d\n"),
Cats->field[j], Cats->cat[j]);
@@ -474,29 +562,46 @@
"Driver=%s\nDatabase=%s\nTable=%s\nKey_column=%s\n",
Fi->driver, Fi->database, Fi->table, Fi->key);
}
+ else if (json) {
+ fprintf(stdout,
+ ",\n\"Driver\": \"%s\",\n\"Database\": \"%s\",\n\"Table\": \"%s\",\n\"Key_column\": \"%s\"",
+ Fi->driver, Fi->database, Fi->table, Fi->key);
+ }
else {
fprintf(stdout,
_("\nDriver: %s\nDatabase: %s\nTable: %s\nKey column: %s\n"),
Fi->driver, Fi->database, Fi->table, Fi->key);
}
F_generate(Fi->driver, Fi->database, Fi->table,
- Fi->key, Cats->cat[j], &form);
+ Fi->key, Cats->cat[j], script, json, &form);
if (script) {
- formbuf1 = G_str_replace(form, " : ", "=");
- formbuf2 = G_str_replace(formbuf1, " ", "_");
- fprintf(stdout, "%s", formbuf2);
+ formbuf1 = G_str_replace(form, " ", "_");
+ fprintf(stdout, "%s", formbuf1);
G_free(formbuf1);
- G_free(formbuf2);
}
+ else if (json)
+ fprintf(stdout, ",\n\"Attributes\": {%s}", form);
else
fprintf(stdout, "%s", form);
G_free(form);
G_free(Fi);
}
+ if (json) {
+ fprintf(stdout, "}"); /* for cat */
+ }
}
+ if (json) {
+ fprintf(stdout, "]"); /* for list of cats */
+ }
}
- } /* for nvects */
+ if (json) {
+ fprintf(stdout, "}"); /* for map */
+ }
+ }
+ if (json) {
+ fprintf(stdout, "]}\n"); /* for nvects */
+ }
fflush(stdout);
}
Modified: grass/trunk/vector/v.what/what.h
===================================================================
--- grass/trunk/vector/v.what/what.h 2014-10-29 02:24:30 UTC (rev 62468)
+++ grass/trunk/vector/v.what/what.h 2014-10-29 03:36:05 UTC (rev 62469)
@@ -1,3 +1,3 @@
/* what.c */
void what(struct Map_info *, int, char **,
- double, double, double, int, int, int, int, int *);
+ double, double, double, int, int, int, int, int, int *);
More information about the grass-commit
mailing list