|
@@ -26,6 +26,8 @@ import grass.lib.date as libdate
|
|
|
import grass.lib.raster3d as libraster3d
|
|
|
import grass.lib.temporal as libtgis
|
|
|
from grass.pygrass.rpc.base import RPCServerBase
|
|
|
+from grass.pygrass.raster import RasterRow
|
|
|
+from grass.pygrass.vector import VectorTopo
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
@@ -46,7 +48,8 @@ class RPCDefs(object):
|
|
|
G_MAPSET = 11
|
|
|
G_LOCATION = 12
|
|
|
G_GISDBASE = 13
|
|
|
- G_FATAL_ERROR = 14
|
|
|
+ READ_MAP_FULL_INFO = 14
|
|
|
+ G_FATAL_ERROR = 49
|
|
|
|
|
|
TYPE_RASTER = 0
|
|
|
TYPE_RASTER3D = 1
|
|
@@ -54,6 +57,94 @@ class RPCDefs(object):
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
+def _read_map_full_info(lock, conn, data):
|
|
|
+ """Read full map specific metadata from the spatial database using
|
|
|
+ PyGRASS functions.
|
|
|
+
|
|
|
+ :param lock: A multiprocessing.Lock instance
|
|
|
+ :param conn: A multiprocessing.Pipe instance used to send True or False
|
|
|
+ :param data: The list of data entries [function_id, maptype, name, mapset]
|
|
|
+ """
|
|
|
+ info = None
|
|
|
+ try:
|
|
|
+ maptype = data[1]
|
|
|
+ name = data[2]
|
|
|
+ mapset = data[3]
|
|
|
+ if maptype == RPCDefs.TYPE_RASTER:
|
|
|
+ info = _read_raster_full_info(name, mapset)
|
|
|
+ elif maptype == RPCDefs.TYPE_VECTOR:
|
|
|
+ info = _read_vector_full_info(name, mapset)
|
|
|
+ except:
|
|
|
+ raise
|
|
|
+ finally:
|
|
|
+ conn.send(info)
|
|
|
+
|
|
|
+def _read_raster_full_info(name, mapset):
|
|
|
+ """Read raster info, history and cats using PyGRASS RasterRow
|
|
|
+ and return a dictionary. Colors should be supported in the
|
|
|
+ future.
|
|
|
+ """
|
|
|
+
|
|
|
+ info = {}
|
|
|
+ r = RasterRow(name=name, mapset=mapset)
|
|
|
+ if r.exist() is True:
|
|
|
+ r.open("r")
|
|
|
+
|
|
|
+ for item in r.info:
|
|
|
+ info[item[0]] = item[1]
|
|
|
+
|
|
|
+ for item in r.hist:
|
|
|
+ info[item[0]] = item[1]
|
|
|
+
|
|
|
+ info["full_name"] = r.name_mapset()
|
|
|
+ info["mtype"] = r.mtype
|
|
|
+ if r.cats:
|
|
|
+ info["cats_title"] = r.cats_title
|
|
|
+ info["cats"] = list(r.cats)
|
|
|
+ r.close()
|
|
|
+
|
|
|
+ return(info)
|
|
|
+
|
|
|
+def _read_vector_full_info(name, mapset):
|
|
|
+ """Read vector info using PyGRASS VectorTopo
|
|
|
+ and return a dictionary. C
|
|
|
+ """
|
|
|
+
|
|
|
+ info = {}
|
|
|
+
|
|
|
+ v = VectorTopo(name=name, mapset=mapset)
|
|
|
+ if v.exist() is True:
|
|
|
+ v.open("r")
|
|
|
+ # Bounding box
|
|
|
+ for item in v.bbox().items():
|
|
|
+ info[item[0]] = item[1]
|
|
|
+
|
|
|
+ info["name"] = v.name
|
|
|
+ info["mapset"] = v.mapset
|
|
|
+ info["comment"] = v.comment
|
|
|
+ info["full_name"] = v.full_name
|
|
|
+ info["is_3d"] = v.is_3D()
|
|
|
+ info["map_date"] = v.map_date
|
|
|
+ info["maptype"] = v.maptype
|
|
|
+ info["organization"] = v.organization
|
|
|
+ info["person"] = v.person
|
|
|
+ info["proj"] = v.proj
|
|
|
+ info["proj_name"] = v.proj_name
|
|
|
+ info["title"] = v.title
|
|
|
+ info["thresh"] = v.thresh
|
|
|
+ info["zone"] = v.zone
|
|
|
+ vtypes = ['areas', 'dblinks', 'faces', 'holes', 'islands',
|
|
|
+ 'kernels', 'lines', 'nodes', 'points', 'updated_lines',
|
|
|
+ 'updated_nodes', 'volumes']
|
|
|
+ for vtype in vtypes:
|
|
|
+ info[vtype] = v.number_of(vtype)
|
|
|
+
|
|
|
+ info.update(v.num_primitives())
|
|
|
+
|
|
|
+ if v.table is not None:
|
|
|
+ info["columns"] = v.table.columns
|
|
|
+
|
|
|
+ return(info)
|
|
|
|
|
|
def _fatal_error(lock, conn, data):
|
|
|
"""Calls G_fatal_error()"""
|
|
@@ -127,18 +218,23 @@ def _get_database_name(lock, conn, data):
|
|
|
|
|
|
:returns: Name of the database or None if no temporal database present
|
|
|
"""
|
|
|
- mapset = data[1]
|
|
|
- if not mapset:
|
|
|
- mapset = libgis.G_mapset()
|
|
|
- dbstring = libtgis.tgis_get_mapset_database_name(mapset)
|
|
|
-
|
|
|
- if dbstring:
|
|
|
- # We substitute GRASS variables if they are located in the database string
|
|
|
- # This behavior is in conjunction with db.connect
|
|
|
- dbstring = dbstring.replace("$GISDBASE", libgis.G_gisdbase())
|
|
|
- dbstring = dbstring.replace("$LOCATION_NAME", libgis.G_location())
|
|
|
- dbstring = dbstring.replace("$MAPSET", mapset)
|
|
|
- conn.send(dbstring)
|
|
|
+ dbstring = None
|
|
|
+ try:
|
|
|
+ mapset = data[1]
|
|
|
+ if not mapset:
|
|
|
+ mapset = libgis.G_mapset()
|
|
|
+ dbstring = libtgis.tgis_get_mapset_database_name(mapset)
|
|
|
+
|
|
|
+ if dbstring:
|
|
|
+ # We substitute GRASS variables if they are located in the database string
|
|
|
+ # This behavior is in conjunction with db.connect
|
|
|
+ dbstring = dbstring.replace("$GISDBASE", libgis.G_gisdbase())
|
|
|
+ dbstring = dbstring.replace("$LOCATION_NAME", libgis.G_location())
|
|
|
+ dbstring = dbstring.replace("$MAPSET", mapset)
|
|
|
+ except:
|
|
|
+ raise
|
|
|
+ finally:
|
|
|
+ conn.send(dbstring)
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
@@ -195,21 +291,25 @@ def _has_timestamp(lock, conn, data):
|
|
|
mapset, layer]
|
|
|
|
|
|
"""
|
|
|
- maptype = data[1]
|
|
|
- name = data[2]
|
|
|
- mapset = data[3]
|
|
|
- layer = data[4]
|
|
|
check = False
|
|
|
- if maptype == RPCDefs.TYPE_RASTER:
|
|
|
- if libgis.G_has_raster_timestamp(name, mapset) == 1:
|
|
|
- check = True
|
|
|
- elif maptype == RPCDefs.TYPE_VECTOR:
|
|
|
- if libgis.G_has_vector_timestamp(name, layer, mapset) == 1:
|
|
|
- check = True
|
|
|
- elif maptype == RPCDefs.TYPE_RASTER3D:
|
|
|
- if libgis.G_has_raster3d_timestamp(name, mapset) == 1:
|
|
|
- check = True
|
|
|
- conn.send(check)
|
|
|
+ try:
|
|
|
+ maptype = data[1]
|
|
|
+ name = data[2]
|
|
|
+ mapset = data[3]
|
|
|
+ layer = data[4]
|
|
|
+ if maptype == RPCDefs.TYPE_RASTER:
|
|
|
+ if libgis.G_has_raster_timestamp(name, mapset) == 1:
|
|
|
+ check = True
|
|
|
+ elif maptype == RPCDefs.TYPE_VECTOR:
|
|
|
+ if libgis.G_has_vector_timestamp(name, layer, mapset) == 1:
|
|
|
+ check = True
|
|
|
+ elif maptype == RPCDefs.TYPE_RASTER3D:
|
|
|
+ if libgis.G_has_raster3d_timestamp(name, mapset) == 1:
|
|
|
+ check = True
|
|
|
+ except:
|
|
|
+ raise
|
|
|
+ finally:
|
|
|
+ conn.send(check)
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
@@ -239,21 +339,26 @@ def _read_timestamp(lock, conn, data):
|
|
|
mapset, layer]
|
|
|
|
|
|
"""
|
|
|
- maptype = data[1]
|
|
|
- name = data[2]
|
|
|
- mapset = data[3]
|
|
|
- layer = data[4]
|
|
|
check = False
|
|
|
- ts = libgis.TimeStamp()
|
|
|
- if maptype == RPCDefs.TYPE_RASTER:
|
|
|
- check = libgis.G_read_raster_timestamp(name, mapset, byref(ts))
|
|
|
- elif maptype == RPCDefs.TYPE_VECTOR:
|
|
|
- check = libgis.G_read_vector_timestamp(name, layer, mapset, byref(ts))
|
|
|
- elif maptype == RPCDefs.TYPE_RASTER3D:
|
|
|
- check = libgis.G_read_raster3d_timestamp(name, mapset, byref(ts))
|
|
|
-
|
|
|
- dates = _convert_timestamp_from_grass(ts)
|
|
|
- conn.send((check, dates))
|
|
|
+ dates = None
|
|
|
+ try:
|
|
|
+ maptype = data[1]
|
|
|
+ name = data[2]
|
|
|
+ mapset = data[3]
|
|
|
+ layer = data[4]
|
|
|
+ ts = libgis.TimeStamp()
|
|
|
+ if maptype == RPCDefs.TYPE_RASTER:
|
|
|
+ check = libgis.G_read_raster_timestamp(name, mapset, byref(ts))
|
|
|
+ elif maptype == RPCDefs.TYPE_VECTOR:
|
|
|
+ check = libgis.G_read_vector_timestamp(name, layer, mapset, byref(ts))
|
|
|
+ elif maptype == RPCDefs.TYPE_RASTER3D:
|
|
|
+ check = libgis.G_read_raster3d_timestamp(name, mapset, byref(ts))
|
|
|
+
|
|
|
+ dates = _convert_timestamp_from_grass(ts)
|
|
|
+ except:
|
|
|
+ raise
|
|
|
+ finally:
|
|
|
+ conn.send((check, dates))
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
@@ -273,27 +378,30 @@ def _write_timestamp(lock, conn, data):
|
|
|
:param data: The list of data entries [function_id, maptype, name,
|
|
|
mapset, layer, timestring]
|
|
|
"""
|
|
|
- maptype = data[1]
|
|
|
- name = data[2]
|
|
|
- mapset = data[3]
|
|
|
- layer = data[4]
|
|
|
- timestring = data[5]
|
|
|
check = -3
|
|
|
- ts = libgis.TimeStamp()
|
|
|
- check = libgis.G_scan_timestamp(byref(ts), timestring)
|
|
|
-
|
|
|
- if check != 1:
|
|
|
- logging.error("Unable to convert the timestamp: " + timestring)
|
|
|
- return -2
|
|
|
-
|
|
|
- if maptype == RPCDefs.TYPE_RASTER:
|
|
|
- check = libgis.G_write_raster_timestamp(name, byref(ts))
|
|
|
- elif maptype == RPCDefs.TYPE_VECTOR:
|
|
|
- check = libgis.G_write_vector_timestamp(name, layer, byref(ts))
|
|
|
- elif maptype == RPCDefs.TYPE_RASTER3D:
|
|
|
- check = libgis.G_write_raster3d_timestamp(name, byref(ts))
|
|
|
-
|
|
|
- conn.send(check)
|
|
|
+ try:
|
|
|
+ maptype = data[1]
|
|
|
+ name = data[2]
|
|
|
+ mapset = data[3]
|
|
|
+ layer = data[4]
|
|
|
+ timestring = data[5]
|
|
|
+ ts = libgis.TimeStamp()
|
|
|
+ check = libgis.G_scan_timestamp(byref(ts), timestring)
|
|
|
+
|
|
|
+ if check != 1:
|
|
|
+ logging.error("Unable to convert the timestamp: " + timestring)
|
|
|
+ return -2
|
|
|
+
|
|
|
+ if maptype == RPCDefs.TYPE_RASTER:
|
|
|
+ check = libgis.G_write_raster_timestamp(name, byref(ts))
|
|
|
+ elif maptype == RPCDefs.TYPE_VECTOR:
|
|
|
+ check = libgis.G_write_vector_timestamp(name, layer, byref(ts))
|
|
|
+ elif maptype == RPCDefs.TYPE_RASTER3D:
|
|
|
+ check = libgis.G_write_raster3d_timestamp(name, byref(ts))
|
|
|
+ except:
|
|
|
+ raise
|
|
|
+ finally:
|
|
|
+ conn.send(check)
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
@@ -314,19 +422,22 @@ def _remove_timestamp(lock, conn, data):
|
|
|
mapset, layer]
|
|
|
|
|
|
"""
|
|
|
- maptype = data[1]
|
|
|
- name = data[2]
|
|
|
- mapset = data[3]
|
|
|
- layer = data[4]
|
|
|
check = False
|
|
|
- if maptype == RPCDefs.TYPE_RASTER:
|
|
|
- check = libgis.G_remove_raster_timestamp(name, mapset)
|
|
|
- elif maptype == RPCDefs.TYPE_VECTOR:
|
|
|
- check = libgis.G_remove_vector_timestamp(name, layer, mapset)
|
|
|
- elif maptype == RPCDefs.TYPE_RASTER3D:
|
|
|
- check = libgis.G_remove_raster3d_timestamp(name, mapset)
|
|
|
-
|
|
|
- conn.send(check)
|
|
|
+ try:
|
|
|
+ maptype = data[1]
|
|
|
+ name = data[2]
|
|
|
+ mapset = data[3]
|
|
|
+ layer = data[4]
|
|
|
+ if maptype == RPCDefs.TYPE_RASTER:
|
|
|
+ check = libgis.G_remove_raster_timestamp(name, mapset)
|
|
|
+ elif maptype == RPCDefs.TYPE_VECTOR:
|
|
|
+ check = libgis.G_remove_vector_timestamp(name, layer, mapset)
|
|
|
+ elif maptype == RPCDefs.TYPE_RASTER3D:
|
|
|
+ check = libgis.G_remove_raster3d_timestamp(name, mapset)
|
|
|
+ except:
|
|
|
+ raise
|
|
|
+ finally:
|
|
|
+ conn.send(check)
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
@@ -342,21 +453,24 @@ def _map_exists(lock, conn, data):
|
|
|
:param data: The list of data entries [function_id, maptype, name, mapset]
|
|
|
|
|
|
"""
|
|
|
- maptype = data[1]
|
|
|
- name = data[2]
|
|
|
- mapset = data[3]
|
|
|
check = False
|
|
|
- if maptype == RPCDefs.TYPE_RASTER:
|
|
|
- mapset = libgis.G_find_raster(name, mapset)
|
|
|
- elif maptype == RPCDefs.TYPE_VECTOR:
|
|
|
- mapset = libgis.G_find_vector(name, mapset)
|
|
|
- elif maptype == RPCDefs.TYPE_RASTER3D:
|
|
|
- mapset = libgis.G_find_raster3d(name, mapset)
|
|
|
-
|
|
|
- if mapset:
|
|
|
- check = True
|
|
|
-
|
|
|
- conn.send(check)
|
|
|
+ try:
|
|
|
+ maptype = data[1]
|
|
|
+ name = data[2]
|
|
|
+ mapset = data[3]
|
|
|
+ if maptype == RPCDefs.TYPE_RASTER:
|
|
|
+ mapset = libgis.G_find_raster(name, mapset)
|
|
|
+ elif maptype == RPCDefs.TYPE_VECTOR:
|
|
|
+ mapset = libgis.G_find_vector(name, mapset)
|
|
|
+ elif maptype == RPCDefs.TYPE_RASTER3D:
|
|
|
+ mapset = libgis.G_find_raster3d(name, mapset)
|
|
|
+
|
|
|
+ if mapset:
|
|
|
+ check = True
|
|
|
+ except:
|
|
|
+ raise
|
|
|
+ finally:
|
|
|
+ conn.send(check)
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
@@ -369,17 +483,21 @@ def _read_map_info(lock, conn, data):
|
|
|
:param conn: A multiprocessing.Pipe instance used to send True or False
|
|
|
:param data: The list of data entries [function_id, maptype, name, mapset]
|
|
|
"""
|
|
|
- maptype = data[1]
|
|
|
- name = data[2]
|
|
|
- mapset = data[3]
|
|
|
- if maptype == RPCDefs.TYPE_RASTER:
|
|
|
- kvp = _read_raster_info(name, mapset)
|
|
|
- elif maptype == RPCDefs.TYPE_VECTOR:
|
|
|
- kvp = _read_vector_info(name, mapset)
|
|
|
- elif maptype == RPCDefs.TYPE_RASTER3D:
|
|
|
- kvp = _read_raster3d_info(name, mapset)
|
|
|
-
|
|
|
- conn.send(kvp)
|
|
|
+ kvp = None
|
|
|
+ try:
|
|
|
+ maptype = data[1]
|
|
|
+ name = data[2]
|
|
|
+ mapset = data[3]
|
|
|
+ if maptype == RPCDefs.TYPE_RASTER:
|
|
|
+ kvp = _read_raster_info(name, mapset)
|
|
|
+ elif maptype == RPCDefs.TYPE_VECTOR:
|
|
|
+ kvp = _read_vector_info(name, mapset)
|
|
|
+ elif maptype == RPCDefs.TYPE_RASTER3D:
|
|
|
+ kvp = _read_raster3d_info(name, mapset)
|
|
|
+ except:
|
|
|
+ raise
|
|
|
+ finally:
|
|
|
+ conn.send(kvp)
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
@@ -765,7 +883,7 @@ def c_library_server(lock, conn):
|
|
|
libgis.G_add_error_handler(cerror_handler, None)
|
|
|
|
|
|
# Crerate the function array
|
|
|
- functions = [0]*15
|
|
|
+ functions = [0]*50
|
|
|
functions[RPCDefs.STOP] = _stop
|
|
|
functions[RPCDefs.HAS_TIMESTAMP] = _has_timestamp
|
|
|
functions[RPCDefs.WRITE_TIMESTAMP] = _write_timestamp
|
|
@@ -779,6 +897,7 @@ def c_library_server(lock, conn):
|
|
|
functions[RPCDefs.G_MAPSET] = _get_mapset
|
|
|
functions[RPCDefs.G_LOCATION] = _get_location
|
|
|
functions[RPCDefs.G_GISDBASE] = _get_gisdbase
|
|
|
+ functions[RPCDefs.READ_MAP_FULL_INFO] = _read_map_full_info
|
|
|
functions[RPCDefs.G_FATAL_ERROR] = _fatal_error
|
|
|
|
|
|
libgis.G_gisinit("c_library_server")
|
|
@@ -843,6 +962,10 @@ class CLibrariesInterface(RPCServerBase):
|
|
|
True
|
|
|
>>> ciface.read_raster_info("test", tgis.get_current_mapset())
|
|
|
{'rows': 12, 'north': 80.0, 'min': 1, 'datatype': 'CELL', 'max': 1, 'ewres': 10.0, 'cols': 8, 'west': 0.0, 'east': 120.0, 'nsres': 10.0, 'south': 0.0}
|
|
|
+
|
|
|
+ >>> ciface.read_raster_full_info("test", tgis.get_current_mapset()) # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
|
|
|
+ {u'tbres': 1.0, ... 'title': 'test', u'south': 0.0}
|
|
|
+
|
|
|
>>> check = ciface.has_raster_timestamp("test", tgis.get_current_mapset())
|
|
|
>>> print check
|
|
|
True
|
|
@@ -890,8 +1013,23 @@ class CLibrariesInterface(RPCServerBase):
|
|
|
>>> print check
|
|
|
True
|
|
|
>>> kvp = ciface.read_vector_info("test", tgis.get_current_mapset())
|
|
|
+ >>> kvp['points']
|
|
|
+ 10
|
|
|
+
|
|
|
+ >>> kvp = ciface.read_vector_full_info("test", tgis.get_current_mapset())
|
|
|
>>> print kvp['points']
|
|
|
10
|
|
|
+ >>> kvp['point']
|
|
|
+ 10
|
|
|
+ >>> kvp['area']
|
|
|
+ 0
|
|
|
+ >>> kvp['lines']
|
|
|
+ 10
|
|
|
+ >>> kvp['line']
|
|
|
+ 0
|
|
|
+ >>> 'columns' in kvp
|
|
|
+ False
|
|
|
+
|
|
|
>>> check = ciface.has_vector_timestamp("test", tgis.get_current_mapset(), None)
|
|
|
>>> print check
|
|
|
True
|
|
@@ -979,6 +1117,22 @@ class CLibrariesInterface(RPCServerBase):
|
|
|
self.client_conn.send([RPCDefs.READ_MAP_INFO, RPCDefs.TYPE_RASTER,
|
|
|
name, mapset, None])
|
|
|
return self.safe_receive("read_raster_info")
|
|
|
+
|
|
|
+ def read_raster_full_info(self, name, mapset):
|
|
|
+ """Read raster info, history and cats using PyGRASS RasterRow
|
|
|
+ and return a dictionary. Colors should be supported in the
|
|
|
+ future.
|
|
|
+
|
|
|
+ :param name: The name of the map
|
|
|
+ :param mapset: The mapset of the map
|
|
|
+ :returns: The key value pairs of the map specific metadata,
|
|
|
+ or None in case of an error
|
|
|
+ """
|
|
|
+ self.check_server()
|
|
|
+ self.client_conn.send([RPCDefs.READ_MAP_FULL_INFO,
|
|
|
+ RPCDefs.TYPE_RASTER,
|
|
|
+ name, mapset, None])
|
|
|
+ return self.safe_receive("read_raster_full_info")
|
|
|
|
|
|
def has_raster_timestamp(self, name, mapset):
|
|
|
"""Check if a file based raster timetamp exists
|
|
@@ -1168,6 +1322,21 @@ class CLibrariesInterface(RPCServerBase):
|
|
|
name, mapset, None])
|
|
|
return self.safe_receive("read_vector_info")
|
|
|
|
|
|
+ def read_vector_full_info(self, name, mapset):
|
|
|
+ """Read vector info using PyGRASS VectorTopo
|
|
|
+ and return a dictionary.
|
|
|
+
|
|
|
+ :param name: The name of the map
|
|
|
+ :param mapset: The mapset of the map
|
|
|
+ :returns: The key value pairs of the map specific metadata,
|
|
|
+ or None in case of an error
|
|
|
+ """
|
|
|
+ self.check_server()
|
|
|
+ self.client_conn.send([RPCDefs.READ_MAP_FULL_INFO,
|
|
|
+ RPCDefs.TYPE_VECTOR,
|
|
|
+ name, mapset, None])
|
|
|
+ return self.safe_receive("read_vector_full_info")
|
|
|
+
|
|
|
def has_vector_timestamp(self, name, mapset, layer=None):
|
|
|
"""Check if a file based vector timetamp exists
|
|
|
|