[GRASS-SVN] r58249 - grass/trunk/lib/python/temporal

svn_grass at osgeo.org svn_grass at osgeo.org
Sun Nov 17 16:26:00 PST 2013


Author: huhabla
Date: 2013-11-17 16:26:00 -0800 (Sun, 17 Nov 2013)
New Revision: 58249

Added:
   grass/trunk/lib/python/temporal/c_libraries_interface.py
Modified:
   grass/trunk/lib/python/temporal/Makefile
   grass/trunk/lib/python/temporal/__init__.py
   grass/trunk/lib/python/temporal/abstract_map_dataset.py
   grass/trunk/lib/python/temporal/aggregation.py
   grass/trunk/lib/python/temporal/core.py
   grass/trunk/lib/python/temporal/space_time_datasets.py
Log:
New G_fatal_error() safe C-libraries interface to access C-functions via ctypes implemented
to reduce the use of ctype functions in the temporal framework. 


Modified: grass/trunk/lib/python/temporal/Makefile
===================================================================
--- grass/trunk/lib/python/temporal/Makefile	2013-11-17 18:22:12 UTC (rev 58248)
+++ grass/trunk/lib/python/temporal/Makefile	2013-11-18 00:26:00 UTC (rev 58249)
@@ -8,7 +8,7 @@
 GDIR = $(PYDIR)/grass
 DSTDIR = $(GDIR)/temporal
 
-MODULES = base core abstract_dataset abstract_map_dataset abstract_space_time_dataset space_time_datasets open factory gui_support list register sampling metadata spatial_extent temporal_extent datetime_math temporal_granularity spatio_temporal_relationships unit_tests aggregation stds_export stds_import extract mapcalc univar_statistics temporal_topology_dataset_connector spatial_topology_dataset_connector
+MODULES = base core abstract_dataset abstract_map_dataset abstract_space_time_dataset space_time_datasets open factory gui_support list register sampling metadata spatial_extent temporal_extent datetime_math temporal_granularity spatio_temporal_relationships unit_tests aggregation stds_export stds_import extract mapcalc univar_statistics temporal_topology_dataset_connector spatial_topology_dataset_connector c_libraries_interface
 
 PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
 PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)

Modified: grass/trunk/lib/python/temporal/__init__.py
===================================================================
--- grass/trunk/lib/python/temporal/__init__.py	2013-11-17 18:22:12 UTC (rev 58248)
+++ grass/trunk/lib/python/temporal/__init__.py	2013-11-18 00:26:00 UTC (rev 58249)
@@ -24,3 +24,4 @@
 from stds_import import *
 from mapcalc import *
 from univar_statistics import *
+from c_libraries_interface import *

Modified: grass/trunk/lib/python/temporal/abstract_map_dataset.py
===================================================================
--- grass/trunk/lib/python/temporal/abstract_map_dataset.py	2013-11-17 18:22:12 UTC (rev 58248)
+++ grass/trunk/lib/python/temporal/abstract_map_dataset.py	2013-11-18 00:26:00 UTC (rev 58249)
@@ -14,9 +14,6 @@
 """
 from abstract_dataset import *
 from datetime_math import *
-import grass.lib.date as libdate
-import grass.lib.gis as libgis
-import ctypes
 
 
 class AbstractMapDataset(AbstractDataset):
@@ -44,6 +41,7 @@
 
     def __init__(self):
         AbstractDataset.__init__(self)
+        self.ciface = get_tgis_c_library_interface()
 
     @abstractmethod
     def get_new_stds_instance(self, ident):
@@ -114,83 +112,6 @@
            in the temporal database.
         """
 
-    def _set_timestamp_from_grass(self, ts):
-        """!Set the timestamp of this map from the map metadata
-           in the grass file system based spatial database and
-           set the internal time stamp that should be insert/updated
-           in the temporal database.
-
-           @param ts The timetsamp to be set, is of type libgis.TimeStamp()
-        """
-
-        if not self.has_grass_timestamp():
-            return False
-
-        dt1 = libgis.DateTime()
-        dt2 = libgis.DateTime()
-        count = ctypes.c_int()
-
-        libgis.G_get_timestamps(ctypes.byref(ts),
-                                ctypes.byref(dt1),
-                                ctypes.byref(dt2),
-                                ctypes.byref(count))
-
-
-        if dt1.mode == libdate.DATETIME_ABSOLUTE:
-            pdt1 = None
-            pdt2 = None
-            if count.value >= 1:
-                pdt1 = datetime(int(dt1.year), int(dt1.month), int(dt1.day),
-                                int(dt1.hour), int(dt1.minute),
-                                int(dt1.second))
-            if count.value == 2:
-                pdt2 = datetime(int(dt2.year), int(dt2.month), int(dt2.day),
-                                int(dt2.hour), int(dt2.minute),
-                                int(dt2.second))
-
-            # ATTENTION: We ignore the time zone
-            # TODO: Write time zone support
-            self.set_absolute_time(pdt1, pdt2, None)
-        else:
-            unit = None
-            start = None
-            end = None
-            if count >= 1:
-                if dt1.year > 0:
-                    unit = "years"
-                    start = dt1.year
-                elif dt1.month > 0:
-                    unit = "months"
-                    start = dt1.month
-                elif dt1.day > 0:
-                    unit = "days"
-                    start = dt1.day
-                elif dt1.hour > 0:
-                    unit = "hours"
-                    start = dt1.hour
-                elif dt1.minute > 0:
-                    unit = "minutess"
-                    start = dt1.minutes
-                elif dt1.seconds > 0:
-                    unit = "seconds"
-                    start = dt1.seconds
-            if count == 2:
-                if dt2.year > 0:
-                    end = dt2.year
-                elif dt2.month > 0:
-                    end = dt2.month
-                elif dt2.day > 0:
-                    end = dt2.day
-                elif dt2.hour > 0:
-                    end = dt2.hour
-                elif dt2.minute > 0:
-                    end = dt2.minutes
-                elif dt2.seconds > 0:
-                    end = dt2.seconds
-            self.set_relative_time(start, end, unit)
-
-        return True
-
     @abstractmethod
     def remove_timestamp_from_grass(self):
         """!Remove the timestamp from the grass file
@@ -205,12 +126,6 @@
         """
 
     @abstractmethod
-    def read_info(self):
-        """!Read the map info from the grass file system based database and
-           store the content into a dictionary
-        """
-
-    @abstractmethod
     def load(self):
         """!Load the content of this object from the grass
            file system based database"""

Modified: grass/trunk/lib/python/temporal/aggregation.py
===================================================================
--- grass/trunk/lib/python/temporal/aggregation.py	2013-11-17 18:22:12 UTC (rev 58248)
+++ grass/trunk/lib/python/temporal/aggregation.py	2013-11-18 00:26:00 UTC (rev 58249)
@@ -24,7 +24,6 @@
 """
 
 from space_time_datasets import *
-import grass.lib.gis as libgis
 
 ###############################################################################
 
@@ -125,7 +124,7 @@
     msgr.verbose(_("Aggregate %s raster maps") % (len(inputs)))
     output = "%s_%i" % (base, count)
 
-    mapset = libgis.G_mapset()
+    mapset = get_current_mapset()
     map_id = output + "@" + mapset
     new_map = RasterDataset(map_id)
 

Added: grass/trunk/lib/python/temporal/c_libraries_interface.py
===================================================================
--- grass/trunk/lib/python/temporal/c_libraries_interface.py	                        (rev 0)
+++ grass/trunk/lib/python/temporal/c_libraries_interface.py	2013-11-18 00:26:00 UTC (rev 58249)
@@ -0,0 +1,1045 @@
+# -*- coding: utf-8 -*-
+"""!@package grass.pygrass.massages
+
+ at brief Temporal Framework GRASS C-library interface
+
+Fast and exit-safe interface to GRASS C-library functions
+using ctypes and multiprocessing
+
+
+(C) 2013 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Soeren Gebbert
+"""
+
+import sys
+from multiprocessing import Process, Lock, Pipe
+import logging
+from ctypes import *
+from core import *
+import grass.lib.gis as libgis
+import grass.lib.raster as libraster
+import grass.lib.vector as libvector
+import grass.lib.date as libdate
+import grass.lib.raster3d as libraster3d
+
+###############################################################################
+
+class RPCDefs(object):
+    # Function identifier and index
+    STOP=0
+    HAS_TIMESTAMP=1
+    WRITE_TIMESTAMP=2
+    READ_TIMESTAMP=3
+    REMOVE_TIMESTAMP=4
+    READ_MAP_INFO=5
+    MAP_EXISTS=6
+    READ_MAP_INFO=7
+
+    TYPE_RASTER=0
+    TYPE_RASTER3D=1
+    TYPE_VECTOR=2
+
+###############################################################################
+
+def _has_timestamp(lock, conn, data):
+    """!Check if the file based GRASS timestamp is present and send
+       True or False using the provided pipe.
+
+       @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, 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)
+
+###############################################################################
+
+def _read_timestamp(lock, conn, data):
+    """!Read the file based GRASS timestamp and send
+       the result using the provided pipe.
+
+       The tuple to be send via pipe: (return value of G_read_*_timestamp, timestamps).
+
+       Please have a look at the documentation of G_read_raster_timestamp,
+       G_read_vector_timestamp and G_read_raster3d_timestamp for the return
+       values description.
+
+       The timestamps to be send are tuples of values:
+           - relative time (start, end, unit), start and end are of type
+             integer, unit is of type string.
+           - absolute time (start, end), start and end are of type datetime
+
+       The end time may be None in case of a time instance.
+
+       @param lock A multiprocessing.Lock instance
+       @param conn A multiprocessing.Pipe instance used to send the result
+       @param data The list of data entries [function_id, maptype, name, 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))
+
+###############################################################################
+
+def _write_timestamp(lock, conn, data):
+    """!Write the file based GRASS timestamp
+       the return values of the called C-functions using the provided pipe.
+
+       The value to be send via pipe is the return value of G_write_*_timestamp.
+
+       Please have a look at the documentation of G_write_raster_timestamp,
+       G_write_vector_timestamp and G_write_raster3d_timestamp for the return
+       values description.
+
+       @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, 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)
+
+###############################################################################
+
+def _remove_timestamp(lock, conn, data):
+    """!Remove the file based GRASS timestamp
+       the return values of the called C-functions using the provided pipe.
+
+       The value to be send via pipe is the return value of G_remove_*_timestamp.
+
+       Please have a look at the documentation of G_remove_raster_timestamp,
+       G_remove_vector_timestamp and G_remove_raster3d_timestamp for the return
+       values description.
+
+       @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, 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)
+
+###############################################################################
+
+def _map_exists(lock, conn, data):
+    """!Check if a map exists in the spatial database
+
+       The value to be send via pipe is True in case the map exists and False
+       if not.
+
+       @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]
+
+    """
+    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)
+
+###############################################################################
+
+def _read_map_info(lock, conn, data):
+    """!Read map specific metadata from the spatial database using C-library
+       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]
+    """
+    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)
+
+###############################################################################
+
+def _read_raster_info(name, mapset):
+    """!Read the raster map info from the file system and store the content
+       into a dictionary
+
+       This method uses the ctypes interface to the gis and raster libraries
+       to read the map metadata information
+
+       @param name The name of the map
+       @param mapset The mapset of the map
+       @return The key value pairs of the map specific metadata, or None in case of an error
+    """
+
+    kvp = {}
+
+    if not libgis.G_find_raster(name, mapset):
+        return None
+
+    # Read the region information
+    region = libgis.Cell_head()
+    libraster.Rast_get_cellhd(name, mapset, byref(region))
+
+    kvp["north"] = region.north
+    kvp["south"] = region.south
+    kvp["east"] = region.east
+    kvp["west"] = region.west
+    kvp["nsres"] = region.ns_res
+    kvp["ewres"] = region.ew_res
+    kvp["rows"] = region.cols
+    kvp["cols"] = region.rows
+
+    maptype = libraster.Rast_map_type(name, mapset)
+
+    if maptype == libraster.DCELL_TYPE:
+        kvp["datatype"] = "DCELL"
+    elif maptype == libraster.FCELL_TYPE:
+        kvp["datatype"] = "FCELL"
+    elif maptype == libraster.CELL_TYPE:
+        kvp["datatype"] = "CELL"
+
+    # Read range
+    if libraster.Rast_map_is_fp(name, mapset):
+        range = libraster.FPRange()
+        libraster.Rast_init_fp_range(byref(range))
+        ret = libraster.Rast_read_fp_range(name, mapset, byref(range))
+        if ret < 0:
+            logging.error(_("Unable to read range file"))
+            return None
+        if ret == 2:
+            kvp["min"] = None
+            kvp["max"] = None
+        else:
+            min = libgis.DCELL()
+            max = libgis.DCELL()
+            libraster.Rast_get_fp_range_min_max(
+                byref(range), byref(min), byref(max))
+            kvp["min"] = min.value
+            kvp["max"] = max.value
+    else:
+        range = libraster.Range()
+        libraster.Rast_init_range(byref(range))
+        ret = libraster.Rast_read_range(name, mapset, byref(range))
+        if ret < 0:
+            logging.error(_("Unable to read range file"))
+            return None
+        if ret == 2:
+            kvp["min"] = None
+            kvp["max"] = None
+        else:
+            min = libgis.CELL()
+            max = libgis.CELL()
+            libraster.Rast_get_range_min_max(
+                byref(range), byref(min), byref(max))
+            kvp["min"] = min.value
+            kvp["max"] = max.value
+
+    return kvp
+
+###############################################################################
+
+def _read_raster3d_info(name, mapset):
+    """!Read the 3D raster map info from the file system and store the content
+       into a dictionary
+
+       This method uses the ctypes interface to the gis and raster3d libraries
+       to read the map metadata information
+
+       @param name The name of the map
+       @param mapset The mapset of the map
+       @return The key value pairs of the map specific metadata, or None in case of an error
+    """
+
+    kvp = {}
+
+    if not libgis.G_find_raster3d(name, mapset):
+        return None
+
+    # Read the region information
+    region = libraster3d.RASTER3D_Region()
+    libraster3d.Rast3d_read_region_map(name, mapset, byref(region))
+
+    kvp["north"] = region.north
+    kvp["south"] = region.south
+    kvp["east"] = region.east
+    kvp["west"] = region.west
+    kvp["nsres"] = region.ns_res
+    kvp["ewres"] = region.ew_res
+    kvp["tbres"] = region.tb_res
+    kvp["rows"] = region.cols
+    kvp["cols"] = region.rows
+    kvp["depths"] = region.depths
+    kvp["top"] = region.top
+    kvp["bottom"] = region.bottom
+
+    # We need to open the map, this function returns a void pointer
+    # but we may need the correct type which is RASTER3D_Map, hence
+    # the casting
+    g3map = cast(libraster3d.Rast3d_open_cell_old(name, mapset,
+                 libraster3d.RASTER3D_DEFAULT_WINDOW,
+                 libraster3d.RASTER3D_TILE_SAME_AS_FILE,
+                 libraster3d.RASTER3D_NO_CACHE),
+                 POINTER(libraster3d.RASTER3D_Map))
+
+    if not g3map:
+        logging.error(_("Unable to open 3D raster map <%s>" % (name)))
+        return None
+
+    maptype = libraster3d.Rast3d_file_type_map(g3map)
+
+    if maptype == libraster.DCELL_TYPE:
+        kvp["datatype"] = "DCELL"
+    elif maptype == libraster.FCELL_TYPE:
+        kvp["datatype"] = "FCELL"
+
+    # Read range
+    min = libgis.DCELL()
+    max = libgis.DCELL()
+    ret = libraster3d.Rast3d_range_load(g3map)
+    if not ret:
+        logging.error(_("Unable to load range of 3D raster map <%s>" %
+                     (name)))
+        return None
+    libraster3d.Rast3d_range_min_max(g3map, byref(min), byref(max))
+
+    if min.value != min.value:
+        kvp["min"] = None
+    else:
+        kvp["min"] = float(min.value)
+    if max.value != max.value:
+        kvp["max"] = None
+    else:
+        kvp["max"] = float(max.value)
+
+    if not libraster3d.Rast3d_close(g3map):
+        logging.error(_("Unable to close 3D raster map <%s>" % (name)))
+        return None
+
+    return kvp
+
+###############################################################################
+
+def _read_vector_info(name, mapset):
+    """!Read the vector map info from the file system and store the content
+       into a dictionary
+
+       This method uses the ctypes interface to the vector libraries
+       to read the map metadata information
+
+       @param name The name of the map
+       @param mapset The mapset of the map
+       @return The key value pairs of the map specific metadata, or None in case of an error
+    """
+
+    kvp = {}
+
+    if not libgis.G_find_vector(name, mapset):
+        return None
+
+    # The vector map structure
+    Map = libvector.Map_info()
+
+    # We open the maps always in topology mode first
+    libvector.Vect_set_open_level(2)
+    with_topo = True
+
+    # Code lend from v.info main.c
+    if libvector.Vect_open_old_head2(byref(Map), name, mapset, "1") < 2:
+        # force level 1, open fully
+        # NOTE: number of points, lines, boundaries, centroids,
+        # faces, kernels is still available
+        libvector.Vect_set_open_level(1)  # no topology
+        with_topo = False
+        if libvector.Vect_open_old2(byref(Map), name, mapset, "1") < 1:
+            logging.error(_("Unable to open vector map <%s>" %
+                         (libvector.Vect_get_full_name(byref(Map)))))
+            return None
+
+    # Release the vector spatial index memory when closed
+    libvector.Vect_set_release_support(byref(Map))
+
+    # Read the extent information
+    bbox = libvector.bound_box()
+    libvector.Vect_get_map_box(byref(Map), byref(bbox))
+
+    kvp["north"] = bbox.N
+    kvp["south"] = bbox.S
+    kvp["east"] = bbox.E
+    kvp["west"] = bbox.W
+    kvp["top"] = bbox.T
+    kvp["bottom"] = bbox.B
+
+    kvp["map3d"] = bool(libvector.Vect_is_3d(byref(Map)))
+
+    # Read number of features
+    if with_topo:
+        kvp["points"] = libvector.Vect_get_num_primitives(
+            byref(Map), libvector.GV_POINT)
+        kvp["lines"] = libvector.Vect_get_num_primitives(
+            byref(Map), libvector.GV_LINE)
+        kvp["boundaries"] = libvector.Vect_get_num_primitives(
+            byref(Map), libvector.GV_BOUNDARY)
+        kvp["centroids"] = libvector.Vect_get_num_primitives(
+            byref(Map), libvector.GV_CENTROID)
+        kvp["faces"] = libvector.Vect_get_num_primitives(
+            byref(Map), libvector.GV_FACE)
+        kvp["kernels"] = libvector.Vect_get_num_primitives(
+            byref(Map), libvector.GV_KERNEL)
+
+        # Summarize the primitives
+        kvp["primitives"] = kvp["points"] + kvp["lines"] + \
+            kvp["boundaries"] + kvp["centroids"]
+        if kvp["map3d"]:
+            kvp["primitives"] += kvp["faces"] + kvp["kernels"]
+
+        # Read topology information
+        kvp["nodes"] = libvector.Vect_get_num_nodes(byref(Map))
+        kvp["areas"] = libvector.Vect_get_num_areas(byref(Map))
+        kvp["islands"] = libvector.Vect_get_num_islands(byref(Map))
+        kvp["holes"] = libvector.Vect_get_num_holes(byref(Map))
+        kvp["volumes"] = libvector.Vect_get_num_primitives(
+            byref(Map), libvector.GV_VOLUME)
+    else:
+        kvp["points"] = None
+        kvp["lines"] = None
+        kvp["boundaries"] = None
+        kvp["centroids"] = None
+        kvp["faces"] = None
+        kvp["kernels"] = None
+        kvp["primitives"] = None
+        kvp["nodes"] = None
+        kvp["areas"] = None
+        kvp["islands"] = None
+        kvp["holes"] = None
+        kvp["volumes"] = None
+
+    libvector.Vect_close(byref(Map))
+
+    return kvp
+
+###############################################################################
+
+def _convert_timestamp_from_grass(ts):
+    """!Convert a GRASS file based timestamp into the temporal framework
+       format datetime or integer.
+
+       A tuple of two datetime objects (start, end) is returned in case of absolute time.
+       In case of relative time a tuple with start time, end time and the
+       relative unit (start, end, unit) will be returned.
+
+       Note:
+       The end time will be set to None in case of a time instance.
+
+       @param ts grass.lib.gis.TimeStamp object created by G_read_*_timestamp
+    """
+
+    dt1 = libgis.DateTime()
+    dt2 = libgis.DateTime()
+    count = c_int()
+
+    libgis.G_get_timestamps(byref(ts),
+                            byref(dt1),
+                            byref(dt2),
+                            byref(count))
+
+
+    if dt1.mode == libdate.DATETIME_ABSOLUTE:
+        pdt1 = None
+        pdt2 = None
+        if count.value >= 1:
+            pdt1 = datetime(int(dt1.year), int(dt1.month), int(dt1.day),
+                            int(dt1.hour), int(dt1.minute),
+                            int(dt1.second))
+        if count.value == 2:
+            pdt2 = datetime(int(dt2.year), int(dt2.month), int(dt2.day),
+                            int(dt2.hour), int(dt2.minute),
+                            int(dt2.second))
+
+        # ATTENTION: We ignore the time zone
+        # TODO: Write time zone support
+        return (pdt1, pdt2)
+    else:
+        unit = None
+        start = None
+        end = None
+        if count >= 1:
+            if dt1.year > 0:
+                unit = "years"
+                start = dt1.year
+            elif dt1.month > 0:
+                unit = "months"
+                start = dt1.month
+            elif dt1.day > 0:
+                unit = "days"
+                start = dt1.day
+            elif dt1.hour > 0:
+                unit = "hours"
+                start = dt1.hour
+            elif dt1.minute > 0:
+                unit = "minutess"
+                start = dt1.minutes
+            elif dt1.seconds > 0:
+                unit = "seconds"
+                start = dt1.seconds
+        if count == 2:
+            if dt2.year > 0:
+                end = dt2.year
+            elif dt2.month > 0:
+                end = dt2.month
+            elif dt2.day > 0:
+                end = dt2.day
+            elif dt2.hour > 0:
+                end = dt2.hour
+            elif dt2.minute > 0:
+                end = dt2.minutes
+            elif dt2.seconds > 0:
+                end = dt2.seconds
+        return (start, end, unit)
+
+###############################################################################
+
+def _stop(lock, conn, data):
+	conn.close()
+	lock.release()
+	sys.exit()
+
+###############################################################################
+
+def c_library_server(lock, conn):
+    """!The GRASS C-libraries server function designed to be a target for
+       multiprocessing.Process
+
+       @param lock A multiprocessing.Lock
+       @param conn A multiprocessing.Pipe
+    """
+    # Crerate the function array
+    functions = [0]*8
+    functions[RPCDefs.STOP] = _stop
+    functions[RPCDefs.HAS_TIMESTAMP] = _has_timestamp
+    functions[RPCDefs.WRITE_TIMESTAMP] = _write_timestamp
+    functions[RPCDefs.READ_TIMESTAMP] = _read_timestamp
+    functions[RPCDefs.REMOVE_TIMESTAMP] = _remove_timestamp
+    functions[RPCDefs.READ_MAP_INFO] = _read_map_info
+    functions[RPCDefs.MAP_EXISTS] = _map_exists
+
+    libgis.G_gisinit("c_library_server")
+
+    while True:
+        # Avoid busy waiting
+        conn.poll(4)
+        data = conn.recv()
+        lock.acquire()
+        functions[data[0]](lock, conn, data)
+        lock.release()
+
+class CLibrariesInterface(object):
+    """!Fast and exit-safe interface to GRASS C-libraries functions
+
+       This class implements a fast and exit-safe interface to the GRASS
+       gis, raster, 3D raster and vector  C-libraries functions.
+
+       The C-libraries functions are called via ctypes in a subprocess
+       using a pipe (multiprocessing.Pipe) to transfer the text messages.
+       Hence, the process that uses the CLibrariesInterface will not be
+       exited, if a G_fatal_error() was invoked in the subprocess.
+       In this case the CLibrariesInterface object will simply start a
+       new subprocess and restarts the pipeline.
+
+
+       Usage:
+
+       @code
+       >>> import grass.script as grass
+       >>> import grass.temporal as tgis
+       >>> grass.use_temp_region()
+       >>> grass.run_command("g.region", n=80.0, s=0.0, e=120.0, w=0.0,
+       ... t=1.0, b=0.0, res=10.0, res3=10.0)
+       0
+       >>> tgis.init()
+       >>> grass.run_command("r.mapcalc", expression="test = 1", overwrite=True, quiet=True)
+       0
+       >>> grass.run_command("r3.mapcalc", expression="test = 1", overwrite=True, quiet=True)
+       0
+       >>> grass.run_command("v.random", output="test", n=10, overwrite=True, quiet=True)
+       0
+       >>> grass.run_command("r.timestamp", map="test", date='12 Mar 1995', overwrite=True, quiet=True)
+       0
+       >>> grass.run_command("r3.timestamp", map="test", date='12 Mar 1995', overwrite=True, quiet=True)
+       0
+       >>> grass.run_command("v.timestamp", map="test", date='12 Mar 1995', overwrite=True, quiet=True)
+       0
+
+
+       # Raster map
+       >>> ciface = tgis.CLibrariesInterface()
+       >>> check = ciface.raster_map_exists("test", tgis.get_current_mapset())
+       >>> print check
+       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}
+       >>> check = ciface.has_raster_timestamp("test", tgis.get_current_mapset())
+       >>> print check
+       True
+       >>> if check:
+       ...     res = ciface.read_raster_timestamp("test", tgis.get_current_mapset())
+       ...     if res[0]:
+       ...         print str(res[1][0]), str(res[1][0])
+       ...         ciface.remove_raster_timestamp("test", tgis.get_current_mapset())
+       1995-03-12 00:00:00 1995-03-12 00:00:00
+       1
+       >>> ciface.has_raster_timestamp("test", tgis.get_current_mapset())
+       False
+       >>> ciface.write_raster_timestamp("test", tgis.get_current_mapset(), "13 Jan 1999")
+       1
+       >>> ciface.has_raster_timestamp("test", tgis.get_current_mapset())
+       True
+
+
+       # 3D raster map
+       >>> check = ciface.raster3d_map_exists("test", tgis.get_current_mapset())
+       >>> print check
+       True
+       >>> ciface.read_raster3d_info("test", tgis.get_current_mapset())
+       {'tbres': 1.0, 'rows': 12, 'north': 80.0, 'bottom': 0.0, 'datatype': 'DCELL', 'max': 1.0, 'top': 1.0, 'min': 1.0, 'cols': 8, 'depths': 1, 'west': 0.0, 'ewres': 10.0, 'east': 120.0, 'nsres': 10.0, 'south': 0.0}
+       >>> check = ciface.has_raster3d_timestamp("test", tgis.get_current_mapset())
+       >>> print check
+       True
+       >>> if check:
+       ...     res = ciface.read_raster3d_timestamp("test", tgis.get_current_mapset())
+       ...     if res[0]:
+       ...         print str(res[1][0]), str(res[1][0])
+       ...         ciface.remove_raster3d_timestamp("test", tgis.get_current_mapset())
+       1995-03-12 00:00:00 1995-03-12 00:00:00
+       1
+       >>> ciface.has_raster3d_timestamp("test", tgis.get_current_mapset())
+       False
+       >>> ciface.write_raster3d_timestamp("test", tgis.get_current_mapset(), "13 Jan 1999")
+       1
+       >>> ciface.has_raster3d_timestamp("test", tgis.get_current_mapset())
+       True
+
+
+       # Vector map
+       >>> check = ciface.vector_map_exists("test", tgis.get_current_mapset())
+       >>> print check
+       True
+       >>> kvp = ciface.read_vector_info("test", tgis.get_current_mapset())
+       >>> print kvp['points']
+       10
+       >>> check = ciface.has_vector_timestamp("test", tgis.get_current_mapset(), None)
+       >>> print check
+       True
+       >>> if check:
+       ...     res = ciface.read_vector_timestamp("test", tgis.get_current_mapset())
+       ...     if res[0]:
+       ...         print str(res[1][0]), str(res[1][0])
+       ...         ciface.remove_vector_timestamp("test", tgis.get_current_mapset())
+       1995-03-12 00:00:00 1995-03-12 00:00:00
+       1
+       >>> ciface.has_vector_timestamp("test", tgis.get_current_mapset())
+       False
+       >>> ciface.write_vector_timestamp("test", tgis.get_current_mapset(), "13 Jan 1999")
+       1
+       >>> ciface.has_vector_timestamp("test", tgis.get_current_mapset())
+       True
+
+       >>> grass.del_temp_region()
+
+       @endcode
+    """
+    def __init__(self):
+        self.client_conn = None
+        self.server_conn = None
+        self.server = None
+        self.start_server()
+
+    def __del__(self):
+        self.stop()
+
+    def start_server(self):
+        self.client_conn, self.server_conn = Pipe()
+        self.lock = Lock()
+        self.server = Process(target=c_library_server, args=(self.lock,
+                                                          self.server_conn))
+        self.server.daemon = True
+        self.server.start()
+
+    def _check_restart_server(self):
+        """!Restart the server if it was terminated
+        """
+        if self.server.is_alive() is True:
+            return
+        self.client_conn.close()
+        self.server_conn.close()
+        self.start_server()
+        logging.warning("Needed to restart the libgis server")
+
+    def raster_map_exists(self, name, mapset):
+        """!Check if a raster map exists in the spatial database
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @return True if exists, False if not
+       """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.MAP_EXISTS, RPCDefs.TYPE_RASTER,
+                               name, mapset, None])
+        return self.client_conn.recv()
+
+    def read_raster_info(self, name, mapset):
+        """!Read the raster map info from the file system and store the content
+           into a dictionary
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @return The key value pairs of the map specific metadata, or None in case of an error
+        """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.READ_MAP_INFO, RPCDefs.TYPE_RASTER,
+                               name, mapset, None])
+        return self.client_conn.recv()
+
+    def has_raster_timestamp(self, name, mapset):
+        """!Check if a file based raster timetamp exists
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @return True if exists, False if not
+       """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.HAS_TIMESTAMP, RPCDefs.TYPE_RASTER,
+                               name, mapset, None])
+        return self.client_conn.recv()
+
+    def remove_raster_timestamp(self, name, mapset):
+        """!Remove a file based raster timetamp
+
+           Please have a look at the documentation G_remove_raster_timestamp
+           for the return values description.
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @return The return value of G_remove_raster_timestamp
+       """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.REMOVE_TIMESTAMP, RPCDefs.TYPE_RASTER,
+                               name, mapset, None])
+        return self.client_conn.recv()
+
+    def read_raster_timestamp(self, name, mapset):
+        """!Read a file based raster timetamp
+
+           Please have a look at the documentation G_read_raster_timestamp
+           for the return values description.
+
+           The timestamps to be send are tuples of values:
+               - relative time (start, end, unit), start and end are of type
+                 integer, unit is of type string.
+               - absolute time (start, end), start and end are of type datetime
+
+           The end time may be None in case of a time instance.
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @return The return value of G_read_raster_timestamp
+       """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.READ_TIMESTAMP, RPCDefs.TYPE_RASTER,
+                               name, mapset, None])
+        return self.client_conn.recv()
+
+    def write_raster_timestamp(self, name, mapset, timestring):
+        """!Write a file based raster timetamp
+
+           Please have a look at the documentation G_write_raster_timestamp
+           for the return values description.
+
+           Note:
+               Only timestamps of maps from the current mapset can written.
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @param timestring A GRASS datetime C-library compatible string
+           @return The return value of G_write_raster_timestamp
+        """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.WRITE_TIMESTAMP, RPCDefs.TYPE_RASTER,
+                               name, mapset, None, timestring])
+        return self.client_conn.recv()
+
+    def raster3d_map_exists(self, name, mapset):
+        """!Check if a 3D raster map exists in the spatial database
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @return True if exists, False if not
+       """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.MAP_EXISTS, RPCDefs.TYPE_RASTER3D,
+                               name, mapset, None])
+        return self.client_conn.recv()
+
+    def read_raster3d_info(self, name, mapset):
+        """!Read the 3D raster map info from the file system and store the content
+           into a dictionary
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @return The key value pairs of the map specific metadata, or None in case of an error
+        """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.READ_MAP_INFO, RPCDefs.TYPE_RASTER3D,
+                               name, mapset, None])
+        return self.client_conn.recv()
+
+    def has_raster3d_timestamp(self, name, mapset):
+        """!Check if a file based 3D raster timetamp exists
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @return True if exists, False if not
+       """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.HAS_TIMESTAMP, RPCDefs.TYPE_RASTER3D,
+                               name, mapset, None])
+        return self.client_conn.recv()
+
+    def remove_raster3d_timestamp(self, name, mapset):
+        """!Remove a file based 3D raster timetamp
+
+           Please have a look at the documentation G_remove_raster3d_timestamp
+           for the return values description.
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @return The return value of G_remove_raster3d_timestamp
+       """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.REMOVE_TIMESTAMP, RPCDefs.TYPE_RASTER3D,
+                               name, mapset, None])
+        return self.client_conn.recv()
+
+    def read_raster3d_timestamp(self, name, mapset):
+        """!Read a file based 3D raster timetamp
+
+           Please have a look at the documentation G_read_raster3d_timestamp
+           for the return values description.
+
+           The timestamps to be send are tuples of values:
+               - relative time (start, end, unit), start and end are of type
+                 integer, unit is of type string.
+               - absolute time (start, end), start and end are of type datetime
+
+           The end time may be None in case of a time instance.
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @return The return value of G_read_raster3d_timestamp
+       """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.READ_TIMESTAMP, RPCDefs.TYPE_RASTER3D,
+                               name, mapset, None])
+        return self.client_conn.recv()
+
+    def write_raster3d_timestamp(self, name, mapset, timestring):
+        """!Write a file based 3D raster timetamp
+
+           Please have a look at the documentation G_write_raster3d_timestamp
+           for the return values description.
+
+           Note:
+               Only timestamps of maps from the current mapset can written.
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @param timestring A GRASS datetime C-library compatible string
+           @return The return value of G_write_raster3d_timestamp
+        """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.WRITE_TIMESTAMP, RPCDefs.TYPE_RASTER3D,
+                               name, mapset, None, timestring])
+        return self.client_conn.recv()
+
+    def vector_map_exists(self, name, mapset):
+        """!Check if a vector map exists in the spatial database
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @return True if exists, False if not
+       """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.MAP_EXISTS, RPCDefs.TYPE_VECTOR,
+                               name, mapset, None])
+        return self.client_conn.recv()
+
+    def read_vector_info(self, name, mapset):
+        """!Read the vector map info from the file system and store the content
+           into a dictionary
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @return The key value pairs of the map specific metadata, or None in case of an error
+        """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.READ_MAP_INFO, RPCDefs.TYPE_VECTOR,
+                               name, mapset, None])
+        return self.client_conn.recv()
+
+    def has_vector_timestamp(self, name, mapset, layer=None):
+        """!Check if a file based vector timetamp exists
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @param layer The layer of the vector map
+           @return True if exists, False if not
+       """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.HAS_TIMESTAMP, RPCDefs.TYPE_VECTOR,
+                               name, mapset, layer])
+        return self.client_conn.recv()
+
+    def remove_vector_timestamp(self, name, mapset, layer=None):
+        """!Remove a file based vector timetamp
+
+           Please have a look at the documentation G_remove_vector_timestamp
+           for the return values description.
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @param layer The layer of the vector map
+           @return The return value of G_remove_vector_timestamp
+       """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.REMOVE_TIMESTAMP, RPCDefs.TYPE_VECTOR,
+                               name, mapset, layer])
+        return self.client_conn.recv()
+
+    def read_vector_timestamp(self, name, mapset, layer=None):
+        """!Read a file based vector timetamp
+
+           Please have a look at the documentation G_read_vector_timestamp
+           for the return values description.
+
+           The timestamps to be send are tuples of values:
+               - relative time (start, end, unit), start and end are of type
+                 integer, unit is of type string.
+               - absolute time (start, end), start and end are of type datetime
+
+           The end time may be None in case of a time instance.
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @param layer The layer of the vector map
+           @return The return value ofG_read_vector_timestamp and the timestamps
+       """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.READ_TIMESTAMP, RPCDefs.TYPE_VECTOR,
+                               name, mapset, layer])
+        return self.client_conn.recv()
+
+    def write_vector_timestamp(self, name, mapset, timestring, layer=None):
+        """!Write a file based vector timetamp
+
+           Please have a look at the documentation G_write_vector_timestamp
+           for the return values description.
+
+           Note:
+               Only timestamps pf maps from the current mapset can written.
+
+           @param name The name of the map
+           @param mapset The mapset of the map
+           @param timestring A GRASS datetime C-library compatible string
+           @param layer The layer of the vector map
+           @return The return value of G_write_vector_timestamp
+        """
+        self._check_restart_server()
+        self.client_conn.send([RPCDefs.WRITE_TIMESTAMP, RPCDefs.TYPE_VECTOR,
+                               name, mapset, layer, timestring])
+        return self.client_conn.recv()
+
+    def stop(self):
+        """!Stop the messenger server and close the pipe
+        """
+        if self.server is not None and self.server.is_alive():
+            self.client_conn.send([0,])
+            self.server.join(5)
+            self.server.terminate()
+        if self.client_conn is not None:
+            self.client_conn.close()
+
+if __name__ == "__main__":
+    import doctest
+    doctest.testmod()

Modified: grass/trunk/lib/python/temporal/core.py
===================================================================
--- grass/trunk/lib/python/temporal/core.py	2013-11-17 18:22:12 UTC (rev 58248)
+++ grass/trunk/lib/python/temporal/core.py	2013-11-18 00:26:00 UTC (rev 58249)
@@ -37,6 +37,7 @@
 import os
 import grass.script.core as core
 from datetime import datetime
+from c_libraries_interface import *
 # Import all supported database backends
 # Ignore import errors since they are checked later
 try:
@@ -104,10 +105,8 @@
 # provides a fast and exit safe interface to the C-library message functions
 message_interface=None
 
-def _set_tgis_message_interface():
-    """!Set the global mesage interface variable
-
-       @param messenger The grass.pyhrass.message.Messenger() object
+def _init_tgis_message_interface():
+    """!Initiate the global mesage interface
     """
     global message_interface
     from grass.pygrass import messages
@@ -125,6 +124,29 @@
 
 ###############################################################################
 
+# The global variable that stores the C-library interface object that
+# provides a fast and exit safe interface to the C-library libgis,
+# libraster, libraster3d and libvector functions
+c_library_interface=None
+
+def _init_tgis_c_library_interface():
+    """!Set the global C-library interface variable that
+       provides a fast and exit safe interface to the C-library libgis,
+       libraster, libraster3d and libvector functions
+    """
+    global c_library_interface
+    c_library_interface = CLibrariesInterface()
+
+def get_tgis_c_library_interface():
+    """!Return the C-library interface that
+       provides a fast and exit safe interface to the C-library libgis,
+       libraster, libraster3d and libvector functions
+    """
+    global c_library_interface
+    return c_library_interface
+
+###############################################################################
+
 def get_tgis_version():
     """!Get the verion number of the temporal framework
        @return The version number of the temporal framework as string
@@ -197,38 +219,6 @@
 
 ###############################################################################
 
-# This variable specifies if the ctypes interface to the grass
-# libraries should be used to read map specific data. If set to False
-# the grass scripting library will be used to get map informations.
-# The advantage of the ctypes inteface is speed, the disadvantage is that
-# the GRASS C functions may call G_fatal_error() which exits the process.
-# That is not catchable in Python.
-use_ctypes_map_access = True
-
-def set_use_ctypes_map_access(use_ctype = True):
-    """!Define the map access method for the temporal GIS library
-
-       Using ctypes to read map metadata is much faster
-       then using the grass.script interface that calls grass modules.
-       The disadvantage is that GRASS C-library function will call
-       G_fatal_error() that will exit the calling process.
-
-       GUI developer should set this flag to False.
-
-       @param use_ctype True use ctypes interface, False use grass.script interface
-    """
-    global use_ctypes_map_access
-    use_ctypes_map_access = use_ctype
-
-###############################################################################
-
-def get_use_ctypes_map_access():
-    """!Return true if ctypes is used for map access """
-    global use_ctypes_map_access
-    return use_ctypes_map_access
-
-###############################################################################
-
 def get_sql_template_path():
     base = os.getenv("GISBASE")
     base_etc = os.path.join(base, "etc")
@@ -255,7 +245,9 @@
     # Set the global variable current_mapset for fast mapset access
     _set_current_mapset(grassenv["MAPSET"])
     # Start the GRASS message interface server
-    _set_tgis_message_interface()
+    _init_tgis_message_interface()
+    # Start the C-library interface server
+    _init_tgis_c_library_interface()
 
     msgr = get_tgis_message_interface()
 

Modified: grass/trunk/lib/python/temporal/space_time_datasets.py
===================================================================
--- grass/trunk/lib/python/temporal/space_time_datasets.py	2013-11-17 18:22:12 UTC (rev 58248)
+++ grass/trunk/lib/python/temporal/space_time_datasets.py	2013-11-18 00:26:00 UTC (rev 58249)
@@ -12,13 +12,7 @@
 @author Soeren Gebbert
 """
 import getpass
-from ctypes import *
-import grass.lib.gis as libgis
-import grass.lib.raster as libraster
-import grass.lib.vector as libvector
-import grass.lib.raster3d as libraster3d
-import grass.script as grass
-
+import logging
 from abstract_map_dataset import *
 from abstract_space_time_dataset import *
 
@@ -40,11 +34,11 @@
         >>> grass.run_command("g.region", n=80.0, s=0.0, e=120.0, w=0.0,
         ... t=1.0, b=0.0, res=10.0)
         0
-        >>> grass.run_command("r.mapcalc", overwrite=True,
+        >>> grass.run_command("r.mapcalc", overwrite=True, quiet=True,
         ... expression="strds_map_test_case = 1")
         0
         >>> grass.run_command("r.timestamp", map="strds_map_test_case",
-        ...                   date="15 jan 1999")
+        ...                   date="15 jan 1999", quiet=True)
         0
         >>> mapset = get_current_mapset()
         >>> name = "strds_map_test_case"
@@ -110,7 +104,7 @@
         >>> rmap.is_time_relative()
         False
 
-        >>> grass.run_command("g.remove", rast=name)
+        >>> grass.run_command("g.remove", rast=name, quiet=True)
         0
         >>> grass.del_temp_region()
 
@@ -208,151 +202,93 @@
 
     def has_grass_timestamp(self):
         """!Check if a grass file bsased time stamp exists for this map.
+
+           @return True if success, False on error
         """
-        if libgis.G_has_raster_timestamp(self.get_name(), self.get_mapset()):
-            return True
-        else:
-            return False
+        return self.ciface.has_raster_timestamp(self.get_name(),
+                                                self.get_mapset())
 
     def read_timestamp_from_grass(self):
         """!Read the timestamp of this map from the map metadata
            in the grass file system based spatial database and
            set the internal time stamp that should be insert/updated
            in the temporal database.
+
+           @return True if success, False on error
         """
 
         if not self.has_grass_timestamp():
             return False
 
-        ts = libgis.TimeStamp()
-        check = libgis.G_read_raster_timestamp(self.get_name(), self.get_mapset(),
-                                               byref(ts))
+        check, dates = self.ciface.read_raster_timestamp(self.get_name(),
+                                                      self.get_mapset(),)
 
         if check < 1:
             self.msgr.error(_("Unable to read timestamp file "
                          "for raster map <%s>" % (self.get_map_id())))
             return False
 
-        return self._set_timestamp_from_grass(ts)
+        if len(dates) == 2:
+            self.set_absolute_time(dates[0], dates[1], None)
+        else:
+            self.set_relative_time(dates[0], dates[1], dates[2])
 
+        return True
+
     def write_timestamp_to_grass(self):
         """!Write the timestamp of this map into the map metadata in
            the grass file system based spatial database.
 
            Internally the libgis API functions are used for writing
+
+           @return True if success, False on error
         """
+        check = self.ciface.write_raster_timestamp(self.get_name(),
+                                                   self.get_mapset(),
+                                                   self._convert_timestamp())
 
-        ts = libgis.TimeStamp()
-
-        libgis.G_scan_timestamp(byref(ts), self._convert_timestamp())
-        check = libgis.G_write_raster_timestamp(self.get_name(), byref(ts))
-
         if check == -1:
             self.msgr.error(_("Unable to create timestamp file "
                          "for raster map <%s>" % (self.get_map_id())))
+            return False
 
         if check == -2:
             self.msgr.error(_("Invalid datetime in timestamp for raster map <%s>" %
                          (self.get_map_id())))
+            return False
 
+        if check == -3:
+            self.msgr.error(_("Internal error"))
+            return False
+
+        return True
+
     def remove_timestamp_from_grass(self):
         """!Remove the timestamp from the grass file system based
            spatial database
 
            Internally the libgis API functions are used for removal
+
+           @return True if success, False on error
         """
-        check = libgis.G_remove_raster_timestamp(self.get_name())
+        check = self.ciface.remove_raster_timestamp(self.get_name(),
+                                                    self.get_mapset())
 
         if check == -1:
-            core.error(_("Unable to remove timestamp for raster map <%s>" %
+            self.msgr.error(_("Unable to remove timestamp for raster map <%s>" %
                          (self.get_name())))
+            return False
 
+        return True
+
     def map_exists(self):
         """!Return True in case the map exists in the grass spatial database
 
            @return True if map exists, False otherwise
         """
-        mapset = libgis.G_find_raster(self.get_name(), self.get_mapset())
+        return self.ciface.raster_map_exists(self.get_name(),
+                                             self.get_mapset())
 
-        if not mapset:
-            return False
-
-        return True
-
-    def read_info(self):
-        """!Read the raster map info from the file system and store the content
-           into a dictionary
-
-           This method uses the ctypes interface to the gis and raster libraries
-           to read the map metadata information
-        """
-
-        kvp = {}
-
-        name = self.get_name()
-        mapset = self.get_mapset()
-
-        if not self.map_exists():
-            core.fatal(_("Raster map <%s> not found" % name))
-
-        # Read the region information
-        region = libgis.Cell_head()
-        libraster.Rast_get_cellhd(name, mapset, byref(region))
-
-        kvp["north"] = region.north
-        kvp["south"] = region.south
-        kvp["east"] = region.east
-        kvp["west"] = region.west
-        kvp["nsres"] = region.ns_res
-        kvp["ewres"] = region.ew_res
-        kvp["rows"] = region.cols
-        kvp["cols"] = region.rows
-
-        maptype = libraster.Rast_map_type(name, mapset)
-
-        if maptype == libraster.DCELL_TYPE:
-            kvp["datatype"] = "DCELL"
-        elif maptype == libraster.FCELL_TYPE:
-            kvp["datatype"] = "FCELL"
-        elif maptype == libraster.CELL_TYPE:
-            kvp["datatype"] = "CELL"
-
-        # Read range
-        if libraster.Rast_map_is_fp(name, mapset):
-            range = libraster.FPRange()
-            libraster.Rast_init_fp_range(byref(range))
-            ret = libraster.Rast_read_fp_range(name, mapset, byref(range))
-            if ret < 0:
-                core.fatal(_("Unable to read range file"))
-            if ret == 2:
-                kvp["min"] = None
-                kvp["max"] = None
-            else:
-                min = libgis.DCELL()
-                max = libgis.DCELL()
-                libraster.Rast_get_fp_range_min_max(
-                    byref(range), byref(min), byref(max))
-                kvp["min"] = min.value
-                kvp["max"] = max.value
-        else:
-            range = libraster.Range()
-            libraster.Rast_init_range(byref(range))
-            ret = libraster.Rast_read_range(name, mapset, byref(range))
-            if ret < 0:
-                core.fatal(_("Unable to read range file"))
-            if ret == 2:
-                kvp["min"] = None
-                kvp["max"] = None
-            else:
-                min = libgis.CELL()
-                max = libgis.CELL()
-                libraster.Rast_get_range_min_max(
-                    byref(range), byref(min), byref(max))
-                kvp["min"] = min.value
-                kvp["max"] = max.value
-
-        return kvp
-
     def load(self):
         """!Load all info from an existing raster map into the internal s
            tructure"""
@@ -360,20 +296,16 @@
         # Fill base information
         self.base.set_creator(str(getpass.getuser()))
 
-        # Get the data from an existing raster map
+        kvp = self.ciface.read_raster_info(self.get_name(),
+                                           self.get_mapset())
 
-        if get_use_ctypes_map_access() == True:
-            kvp = self.read_info()
-        else:
-            kvp = grass.raster_info(self.get_id())
-
         # Fill spatial extent
+        self.set_spatial_extent_from_values(north=kvp["north"],
+                                            south=kvp["south"],
+                                            east=kvp["east"],
+                                            west=kvp["west"])
 
-        self.set_spatial_extent_from_values(north=kvp["north"], south=kvp["south"],
-                                east=kvp["east"], west=kvp["west"])
-
         # Fill metadata
-
         self.metadata.set_nsres(kvp["nsres"])
         self.metadata.set_ewres(kvp["ewres"])
         self.metadata.set_datatype(kvp["datatype"])
@@ -405,13 +337,13 @@
         >>> init()
         >>> grass.use_temp_region()
         >>> grass.run_command("g.region", n=80.0, s=0.0, e=120.0, w=0.0,
-        ... t=100.0, b=0.0, res=10.0)
+        ... t=100.0, b=0.0, res=10.0, res3=10.0)
         0
-        >>> grass.run_command("r3.mapcalc", overwrite=True,
+        >>> grass.run_command("r3.mapcalc", overwrite=True, quiet=True,
         ...                   expression="str3ds_map_test_case = 1")
         0
         >>> grass.run_command("r3.timestamp", map="str3ds_map_test_case",
-        ...                   date="15 jan 1999")
+        ...                   date="15 jan 1999", quiet=True)
         0
         >>> mapset = get_current_mapset()
         >>> name = "str3ds_map_test_case"
@@ -478,7 +410,7 @@
         True
         >>> r3map.is_time_relative()
         False
-        >>> grass.run_command("g.remove", rast3d=name)
+        >>> grass.run_command("g.remove", rast3d=name, quiet=True)
         0
         >>> grass.del_temp_region()
     """
@@ -589,152 +521,90 @@
 
     def has_grass_timestamp(self):
         """!Check if a grass file bsased time stamp exists for this map.
+
+           @return True if success, False on error
         """
-        if libgis.G_has_raster3d_timestamp(self.get_name(), self.get_mapset()):
-            return True
-        else:
-            return False
+        return self.ciface.has_raster3d_timestamp(self.get_name(),
+                                                self.get_mapset())
 
-
     def read_timestamp_from_grass(self):
         """!Read the timestamp of this map from the map metadata
            in the grass file system based spatial database and
            set the internal time stamp that should be insert/updated
            in the temporal database.
+
+           @return True if success, False on error
         """
 
         if not self.has_grass_timestamp():
             return False
 
-        ts = libgis.TimeStamp()
-        check = libgis.G_read_raster3d_timestamp(self.get_name(), self.get_mapset(),
-                                               byref(ts))
+        check, dates = self.ciface.read_raster3d_timestamp(self.get_name(),
+                                                      self.get_mapset(),)
 
         if check < 1:
             self.msgr.error(_("Unable to read timestamp file "
                          "for 3D raster map <%s>" % (self.get_map_id())))
             return False
 
-        return self._set_timestamp_from_grass(ts)
+        if len(dates) == 2:
+            self.set_absolute_time(dates[0], dates[1], None)
+        else:
+            self.set_relative_time(dates[0], dates[1], dates[2])
 
+        return True
+
     def write_timestamp_to_grass(self):
         """!Write the timestamp of this map into the map metadata
         in the grass file system based spatial database.
 
            Internally the libgis API functions are used for writing
+
+           @return True if success, False on error
         """
+        check = self.ciface.write_raster3d_timestamp(self.get_name(),
+                                                     self.get_mapset(),
+                                                     self._convert_timestamp())
 
-        ts = libgis.TimeStamp()
-
-        libgis.G_scan_timestamp(byref(ts), self._convert_timestamp())
-        check = libgis.G_write_raster3d_timestamp(self.get_name(), byref(ts))
-
         if check == -1:
             self.msgr.error(_("Unable to create timestamp file "
-                         "for raster3d map <%s>" % (self.get_map_id())))
+                         "for 3D raster map <%s>" % (self.get_map_id())))
+            return False
 
         if check == -2:
-            self.msgr.error(_("Invalid datetime in timestamp "
-                         "for raster3d map <%s>" % (self.get_map_id())))
+            self.msgr.error(_("Invalid datetime in timestamp for 3D raster map <%s>" %
+                         (self.get_map_id())))
+            return False
 
+        if check == -3:
+            self.msgr.error(_("Internal error"))
+            return False
+
+        return True
+
     def remove_timestamp_from_grass(self):
         """!Remove the timestamp from the grass file system based spatial database
 
-           Internally the libgis API functions are used for removal
+           @return True if success, False on error
         """
-        check = libgis.G_remove_raster3d_timestamp(self.get_name())
+        check = self.ciface.remove_raster3d_timestamp(self.get_name(),
+                                                      self.get_mapset())
 
         if check == -1:
-            self.msgr.error(_("Unable to remove timestamp for raster3d map <%s>" %
+            self.msgr.error(_("Unable to remove timestamp for raster map <%s>" %
                          (self.get_name())))
+            return False
 
+        return True
+
     def map_exists(self):
         """!Return True in case the map exists in the grass spatial database
 
            @return True if map exists, False otherwise
         """
-        mapset = libgis.G_find_raster3d(self.get_name(), self.get_mapset())
+        return self.ciface.raster3d_map_exists(self.get_name(),
+                                               self.get_mapset())
 
-        if not mapset:
-            return False
-
-        return True
-
-    def read_info(self):
-        """!Read the raster3d map info from the file system and store the content
-           into a dictionary
-
-           This method uses the ctypes interface to the gis and raster3d libraries
-           to read the map metadata information
-        """
-
-        kvp = {}
-
-        name = self.get_name()
-        mapset = self.get_mapset()
-
-        if not self.map_exists():
-            core.fatal(_("Raster3d map <%s> not found" % name))
-
-        # Read the region information
-        region = libraster3d.RASTER3D_Region()
-        libraster3d.Rast3d_read_region_map(name, mapset, byref(region))
-
-        kvp["north"] = region.north
-        kvp["south"] = region.south
-        kvp["east"] = region.east
-        kvp["west"] = region.west
-        kvp["nsres"] = region.ns_res
-        kvp["ewres"] = region.ew_res
-        kvp["tbres"] = region.tb_res
-        kvp["rows"] = region.cols
-        kvp["cols"] = region.rows
-        kvp["depths"] = region.depths
-        kvp["top"] = region.top
-        kvp["bottom"] = region.bottom
-
-        # We need to open the map, this function returns a void pointer
-        # but we may need the correct type which is RASTER3D_Map, hence
-        # the casting
-        g3map = cast(libraster3d.Rast3d_open_cell_old(name, mapset,
-                     libraster3d.RASTER3D_DEFAULT_WINDOW,
-                     libraster3d.RASTER3D_TILE_SAME_AS_FILE,
-                     libraster3d.RASTER3D_NO_CACHE),
-                     POINTER(libraster3d.RASTER3D_Map))
-
-        if not g3map:
-            core.fatal(_("Unable to open 3D raster map <%s>" % (name)))
-
-        maptype = libraster3d.Rast3d_file_type_map(g3map)
-
-        if maptype == libraster.DCELL_TYPE:
-            kvp["datatype"] = "DCELL"
-        elif maptype == libraster.FCELL_TYPE:
-            kvp["datatype"] = "FCELL"
-
-        # Read range
-        min = libgis.DCELL()
-        max = libgis.DCELL()
-        ret = libraster3d.Rast3d_range_load(g3map)
-        if not ret:
-            core.fatal(_("Unable to load range of 3D raster map <%s>" %
-                         (name)))
-        libraster3d.Rast3d_range_min_max(g3map, byref(min), byref(max))
-
-        if min.value != min.value:
-            kvp["min"] = None
-        else:
-            kvp["min"] = float(min.value)
-        if max.value != max.value:
-            kvp["max"] = None
-        else:
-            kvp["max"] = float(max.value)
-
-        if not libraster3d.Rast3d_close(g3map):
-            G_fatal_error(_("Unable to close 3D raster map <%s>" % (name)))
-
-        return kvp
-
     def load(self):
         """!Load all info from an existing raster3d map into the internal structure"""
 
@@ -742,14 +612,9 @@
         self.base.set_creator(str(getpass.getuser()))
 
         # Fill spatial extent
+        kvp = self.ciface.read_raster3d_info(self.get_name(),
+                                           self.get_mapset())
 
-        # Get the data from an existing 3D raster map
-
-        if get_use_ctypes_map_access() == True:
-            kvp = self.read_info()
-        else:
-            kvp = grass.raster3d_info(self.get_id())
-
         self.set_spatial_extent_from_values(north=kvp["north"], south=kvp["south"],
                                 east=kvp["east"], west=kvp["west"],
                                 top=kvp["top"], bottom=kvp["bottom"])
@@ -792,10 +657,10 @@
         ... t=1.0, b=0.0, res=10.0)
         0
         >>> grass.run_command("v.random", overwrite=True, output="stvds_map_test_case",
-        ... n=100, zmin=0, zmax=100, flags="z", column="elevation")
+        ... n=100, zmin=0, zmax=100, flags="z", column="elevation", quiet=True)
         0
         >>> grass.run_command("v.timestamp", map="stvds_map_test_case",
-        ...                   date="15 jan 1999")
+        ...                   date="15 jan 1999", quiet=True)
         0
         >>> mapset = get_current_mapset()
         >>> name = "stvds_map_test_case"
@@ -854,7 +719,7 @@
         True
         >>> vmap.is_time_relative()
         False
-        >>> grass.run_command("g.remove", vect=name)
+        >>> grass.run_command("g.remove", vect=name, quiet=True)
         0
         >>> grass.del_temp_region()
 
@@ -937,11 +802,9 @@
     def has_grass_timestamp(self):
         """!Check if a grass file bsased time stamp exists for this map.
         """
-        if libgis.G_has_vector_timestamp(self.get_name(), self.get_layer(),
-                                  self.get_mapset()):
-            return True
-        else:
-            return False
+        return self.ciface.has_vector_timestamp(self.get_name(),
+                                                self.get_mapset(),
+                                                self.get_layer())
 
 
     def read_timestamp_from_grass(self):
@@ -954,162 +817,69 @@
         if not self.has_grass_timestamp():
             return False
 
-        ts = libgis.TimeStamp()
-        check = libgis.G_read_vector_timestamp(self.get_name(),
-                                               self.get_layer(),
-                                               self.get_mapset(),
-                                               byref(ts))
+        check, dates = self.ciface.read_vector_timestamp(self.get_name(),
+                                                      self.get_mapset(),)
 
         if check < 1:
             self.msgr.error(_("Unable to read timestamp file "
                          "for vector map <%s>" % (self.get_map_id())))
             return False
 
-        return self._set_timestamp_from_grass(ts)
+        if len(dates) == 2:
+            self.set_absolute_time(dates[0], dates[1], None)
+        else:
+            self.set_relative_time(dates[0], dates[1], dates[2])
 
+        return True
+
     def write_timestamp_to_grass(self):
         """!Write the timestamp of this map into the map metadata in
            the grass file system based spatial database.
 
            Internally the libgis API functions are used for writing
         """
+        check = self.ciface.write_vector_timestamp(self.get_name(),
+                                                   self.get_mapset(),
+                                                   self._convert_timestamp(),
+                                                   self.get_layer())
 
-        ts = libgis.TimeStamp()
-
-        libgis.G_scan_timestamp(byref(ts), self._convert_timestamp())
-        check = libgis.G_write_vector_timestamp(
-            self.get_name(), self.get_layer(), byref(ts))
-
         if check == -1:
             self.msgr.error(_("Unable to create timestamp file "
                          "for vector map <%s>" % (self.get_map_id())))
+            return False
 
         if check == -2:
             self.msgr.error(_("Invalid datetime in timestamp for vector map <%s>" %
                          (self.get_map_id())))
+            return False
 
+        return True
+
     def remove_timestamp_from_grass(self):
         """!Remove the timestamp from the grass file system based spatial
            database
 
            Internally the libgis API functions are used for removal
         """
-        check = libgis.G_remove_vector_timestamp(
-            self.get_name(), self.get_layer())
+        check = self.ciface.remove_vector_timestamp(self.get_name(),
+                                                    self.get_mapset())
 
         if check == -1:
             self.msgr.error(_("Unable to remove timestamp for vector map <%s>" %
                          (self.get_name())))
+            return False
 
+        return True
+
     def map_exists(self):
         """!Return True in case the map exists in the grass spatial database
 
            @return True if map exists, False otherwise
         """
-        mapset = libgis.G_find_vector(self.get_name(), self.get_mapset())
+        return self.ciface.vector_map_exists(self.get_name(),
+                                             self.get_mapset())
 
-        if not mapset:
-            return False
 
-        return True
-
-    def read_info(self):
-        """!Read the vector map info from the file system and store the content
-           into a dictionary
-
-           This method uses the ctypes interface to the vector libraries
-           to read the map metadata information
-        """
-
-        kvp = {}
-
-        name = self.get_name()
-        mapset = self.get_mapset()
-
-        if not self.map_exists():
-            core.fatal(_("Vector map <%s> not found" % name))
-
-        # The vector map structure
-        Map = libvector.Map_info()
-
-        # We open the maps always in topology mode first
-        libvector.Vect_set_open_level(2)
-        with_topo = True
-
-        # Code lend from v.info main.c
-        if libvector.Vect_open_old_head2(byref(Map), name, mapset, "1") < 2:
-            # force level 1, open fully
-            # NOTE: number of points, lines, boundaries, centroids,
-            # faces, kernels is still available
-            libvector.Vect_set_open_level(1)  # no topology
-            with_topo = False
-            self.msgr.message(_("Open map without topology support"))
-            if libvector.Vect_open_old2(byref(Map), name, mapset, "1") < 1:
-                core.fatal(_("Unable to open vector map <%s>" %
-                             (libvector.Vect_get_full_name(byref(Map)))))
-
-        # Release the vector spatial index memory when closed
-        libvector.Vect_set_release_support(byref(Map))
-
-        # Read the extent information
-        bbox = libvector.bound_box()
-        libvector.Vect_get_map_box(byref(Map), byref(bbox))
-
-        kvp["north"] = bbox.N
-        kvp["south"] = bbox.S
-        kvp["east"] = bbox.E
-        kvp["west"] = bbox.W
-        kvp["top"] = bbox.T
-        kvp["bottom"] = bbox.B
-
-        kvp["map3d"] = bool(libvector.Vect_is_3d(byref(Map)))
-
-        # Read number of features
-        if with_topo:
-            kvp["points"] = libvector.Vect_get_num_primitives(
-                byref(Map), libvector.GV_POINT)
-            kvp["lines"] = libvector.Vect_get_num_primitives(
-                byref(Map), libvector.GV_LINE)
-            kvp["boundaries"] = libvector.Vect_get_num_primitives(
-                byref(Map), libvector.GV_BOUNDARY)
-            kvp["centroids"] = libvector.Vect_get_num_primitives(
-                byref(Map), libvector.GV_CENTROID)
-            kvp["faces"] = libvector.Vect_get_num_primitives(
-                byref(Map), libvector.GV_FACE)
-            kvp["kernels"] = libvector.Vect_get_num_primitives(
-                byref(Map), libvector.GV_KERNEL)
-
-            # Summarize the primitives
-            kvp["primitives"] = kvp["points"] + kvp["lines"] + \
-                kvp["boundaries"] + kvp["centroids"]
-            if kvp["map3d"]:
-                kvp["primitives"] += kvp["faces"] + kvp["kernels"]
-
-            # Read topology information
-            kvp["nodes"] = libvector.Vect_get_num_nodes(byref(Map))
-            kvp["areas"] = libvector.Vect_get_num_areas(byref(Map))
-            kvp["islands"] = libvector.Vect_get_num_islands(byref(Map))
-            kvp["holes"] = libvector.Vect_get_num_holes(byref(Map))
-            kvp["volumes"] = libvector.Vect_get_num_primitives(
-                byref(Map), libvector.GV_VOLUME)
-        else:
-            kvp["points"] = None
-            kvp["lines"] = None
-            kvp["boundaries"] = None
-            kvp["centroids"] = None
-            kvp["faces"] = None
-            kvp["kernels"] = None
-            kvp["primitives"] = None
-            kvp["nodes"] = None
-            kvp["areas"] = None
-            kvp["islands"] = None
-            kvp["holes"] = None
-            kvp["volumes"] = None
-
-        libvector.Vect_close(byref(Map))
-
-        return kvp
-
     def load(self):
         """!Load all info from an existing vector map into the internal
         structure"""
@@ -1119,10 +889,8 @@
 
         # Get the data from an existing vector map
 
-        if get_use_ctypes_map_access() == True:
-            kvp = self.read_info()
-        else:
-            kvp = grass.vector_info(self.get_map_id())
+        kvp = self.ciface.read_vector_info(self.get_name(),
+                                           self.get_mapset())
 
         # Fill spatial extent
         self.set_spatial_extent_from_values(north=kvp["north"], south=kvp["south"],



More information about the grass-commit mailing list