Browse Source

Major code review and application of pep8 coding standard.
Several doctests added to temporal base classes.


git-svn-id: https://svn.osgeo.org/grass/grass/trunk@52621 15284696-431f-4ddb-bdfa-cd5b030d7da7

Soeren Gebbert 12 years ago
parent
commit
fe088b6dcc

+ 123 - 182
lib/python/temporal/abstract_dataset.py

@@ -7,11 +7,17 @@ Temporal GIS related functions to be used in temporal GIS Python library package
 
 Usage:
 
-@code
-import grass.temporal as tgis
-
-...
-@endcode
+>>> import grass.temporal as tgis
+>>> ad = abstract_dataset()
+>>> ad.reset(ident="soil@PERMANENT")
+Traceback (most recent call last):
+  File "/usr/lib/python2.7/doctest.py", line 1289, in __run
+    compileflags, 1) in test.globs
+  File "<doctest __main__[2]>", line 1, in <module>
+    ad.reset(ident="soil@PERMANENT")
+  File "abstract_dataset.py", line 53, in reset
+    raise ImplementationError("This method must be implemented in the subclasses")
+ImplementationError: 'This method must be implemented in the subclasses'
 
 (C) 2008-2011 by the GRASS Development Team
 This program is free software under the GNU General Public
@@ -26,74 +32,84 @@ from temporal_extent import *
 from spatial_extent import *
 from metadata import *
 
+
+class ImplementationError(Exception):
+    """!Exception raised for the calling of methods that should be implemented in
+       sub classes.
+    """
+    def __init__(self, msg):
+        self.msg = msg
+    def __str__(self):
+        return repr(self.msg)
+    
 class abstract_dataset(object):
     """!This is the base class for all datasets (raster, vector, raster3d, strds, stvds, str3ds)"""
 
     def reset(self, ident):
-	"""!Reset the internal structure and set the identifier
+        """!Reset the internal structure and set the identifier
 
            @param ident: The identifier of the dataset
         """
-	raise IOError("This method must be implemented in the subclasses")
+        raise ImplementationError("This method must be implemented in the subclasses")
 
     def get_type(self):
         """!Return the type of this class"""
-        raise IOError("This method must be implemented in the subclasses")
-    
+        raise ImplementationError("This method must be implemented in the subclasses")
+
     def get_new_instance(self, ident):
         """!Return a new instance with the type of this class
 
            @param ident: The identifier of the dataset
         """
-        raise IOError("This method must be implemented in the subclasses")
+        raise ImplementationError("This method must be implemented in the subclasses")
 
     def spatial_overlapping(self, dataset):
         """!Return True if the spatial extents are overlapping"""
 
-        raise IOError("This method must be implemented in the subclasses")
+        raise ImplementationError("This method must be implemented in the subclasses")
 
     def spatial_relation(self, dataset):
         """Return the spatial relationship between self and dataset"""
 
-        raise IOError("This method must be implemented in the subclasses")
-    
+        raise ImplementationError("This method must be implemented in the subclasses")
+
     def print_info(self):
         """!Print information about this class in human readable style"""
-	raise IOError("This method must be implemented in the subclasses")
-        
+        raise ImplementationError("This method must be implemented in the subclasses")
+
     def print_shell_info(self):
         """!Print information about this class in shell style"""
-	raise IOError("This method must be implemented in the subclasses")
- 
+        raise ImplementationError("This method must be implemented in the subclasses")
+
     def print_self(self):
-	"""!Print the content of the internal structure to stdout"""
-	self.base.print_self()
-	if self.is_time_absolute():
-	    self.absolute_time.print_self()
+        """!Print the content of the internal structure to stdout"""
+        self.base.print_self()
+        if self.is_time_absolute():
+            self.absolute_time.print_self()
         if self.is_time_relative():
-	    self.relative_time.print_self()
-	self.spatial_extent.print_self()
-	self.metadata.print_self()
-	
+            self.relative_time.print_self()
+        self.spatial_extent.print_self()
+        self.metadata.print_self()
+
     def set_id(self, ident):
-	self.base.set_id(ident)
-	if self.is_time_absolute():
-	    self.absolute_time.set_id(ident)
+        self.base.set_id(ident)
+        if self.is_time_absolute():
+            self.absolute_time.set_id(ident)
         if self.is_time_relative():
-	    self.relative_time.set_id(ident)
-	self.spatial_extent.set_id(ident)
-	self.metadata.set_id(ident)
+            self.relative_time.set_id(ident)
+        self.spatial_extent.set_id(ident)
+        self.metadata.set_id(ident)
 
     def get_id(self):
-	"""!Return the unique identifier of the dataset"""
+        """!Return the unique identifier of the dataset"""
         return self.base.get_id()
 
     def get_name(self):
-	"""!Return the name"""
+        """!Return the name"""
         return self.base.get_name()
 
     def get_mapset(self):
-	"""!Return the mapset"""
+        """!Return the mapset"""
         return self.base.get_mapset()
 
     def get_valid_time(self):
@@ -103,27 +119,27 @@ class abstract_dataset(object):
 
         start = None
         end = None
-               
-	if self.is_time_absolute():
+
+        if self.is_time_absolute():
             start = self.absolute_time.get_start_time()
             end = self.absolute_time.get_end_time()
         if self.is_time_relative():
             start = self.relative_time.get_start_time()
             end = self.relative_time.get_end_time()
-        
+
         return (start, end)
- 
+
     def get_absolute_time(self):
         """!Returns a tuple of the start, the end valid time and the timezone of the map
            @return A tuple of (start_time, end_time, timezone)
         """
-               
+
         start = self.absolute_time.get_start_time()
         end = self.absolute_time.get_end_time()
         tz = self.absolute_time.get_timezone()
-        
+
         return (start, end, tz)
-    
+
     def get_relative_time(self):
         """!Returns the relative time interval (start_time, end_time, unit) or None if not present"""
 
@@ -132,7 +148,7 @@ class abstract_dataset(object):
         unit = self.relative_time.get_unit()
 
         return (start, end, unit)
- 
+
     def get_relative_time_unit(self):
         """!Returns the relative time unit or None if not present"""
 
@@ -142,57 +158,49 @@ class abstract_dataset(object):
 
     def check_relative_time_unit(self, unit):
         """!Check if unit is of type  years, months, days, hours, minutes or seconds
-        
-           Return True if success or False otherwise 
+
+           Return True if success or False otherwise
         """
         # Check unit
-        units = ["years","months","days","hours","minutes","seconds"]
+        units = ["years", "months", "days", "hours", "minutes", "seconds"]
         if unit not in units:
             return False
         return True
- 
+
     def get_temporal_type(self):
         """!Return the temporal type of this dataset"""
         return self.base.get_ttype()
-    
+
     def get_spatial_extent(self):
         """!Return a tuple of spatial extent (north, south, east, west, top, bottom) """
-        
-        north = self.spatial_extent.get_north()
-        south = self.spatial_extent.get_south()
-        east = self.spatial_extent.get_east()
-        west = self.spatial_extent.get_west()
-        top = self.spatial_extent.get_top()
-        bottom = self.spatial_extent.get_bottom()
-        
-        return (north, south, east, west, top, bottom)
-    
+        return self.spatial_extent.get_spatial_extent()
+
     def select(self, dbif=None):
-	"""!Select temporal dataset entry from database and fill up the internal structure"""
+        """!Select temporal dataset entry from database and fill up the internal structure"""
 
         dbif, connect = init_dbif(dbif)
 
-	self.base.select(dbif)
-	if self.is_time_absolute():
-	    self.absolute_time.select(dbif)
+        self.base.select(dbif)
+        if self.is_time_absolute():
+            self.absolute_time.select(dbif)
         if self.is_time_relative():
-	    self.relative_time.select(dbif)
-	self.spatial_extent.select(dbif)
-	self.metadata.select(dbif)
+            self.relative_time.select(dbif)
+        self.spatial_extent.select(dbif)
+        self.metadata.select(dbif)
 
         if connect:
             dbif.close()
 
     def is_in_db(self, dbif=None):
         """!Check if the temporal dataset entry is in the database
-        
+
            @param dbif: The database interface to be used
         """
         return self.base.is_in_db(dbif)
 
     def delete(self):
-	"""!Delete temporal dataset entry from database if it exists"""
-        raise IOError("This method must be implemented in the subclasses")
+        """!Delete temporal dataset entry from database if it exists"""
+        raise ImplementationError("This method must be implemented in the subclasses")
 
     def insert(self, dbif=None, execute=True):
         """!Insert temporal dataset entry into database from the internal structure
@@ -204,20 +212,22 @@ class abstract_dataset(object):
         """
 
         dbif, connect = init_dbif(dbif)
-        
+
         # Build the INSERT SQL statement
         statement = self.base.get_insert_statement_mogrified(dbif)
         if self.is_time_absolute():
-            statement += self.absolute_time.get_insert_statement_mogrified(dbif)
+            statement += self.absolute_time.get_insert_statement_mogrified(
+                dbif)
         if self.is_time_relative():
-            statement += self.relative_time.get_insert_statement_mogrified(dbif)
+            statement += self.relative_time.get_insert_statement_mogrified(
+                dbif)
         statement += self.spatial_extent.get_insert_statement_mogrified(dbif)
         statement += self.metadata.get_insert_statement_mogrified(dbif)
 
         if execute == True:
             dbif.execute_transaction(statement)
-	    if connect:
-		dbif.close()
+            if connect:
+                dbif.close()
             return ""
 
         if connect:
@@ -225,59 +235,64 @@ class abstract_dataset(object):
         return statement
 
     def update(self, dbif=None, execute=True):
-	"""!Update temporal dataset entry of database from the internal structure
-	   excluding None variables
+        """!Update temporal dataset entry of database from the internal structure
+           excluding None variables
 
            @param dbif: The database interface to be used
            @param execute: If True the SQL statements will be executed.
                            If False the prepared SQL statements are returned and must be executed by the caller.
-	"""
+        """
 
         dbif, connect = init_dbif(dbif)
-        
+
         # Build the UPDATE SQL statement
         statement = self.base.get_update_statement_mogrified(dbif)
-	if self.is_time_absolute():
-            statement += self.absolute_time.get_update_statement_mogrified(dbif)
+        if self.is_time_absolute():
+            statement += self.absolute_time.get_update_statement_mogrified(
+                dbif)
         if self.is_time_relative():
-            statement += self.relative_time.get_update_statement_mogrified(dbif)
+            statement += self.relative_time.get_update_statement_mogrified(
+                dbif)
         statement += self.spatial_extent.get_update_statement_mogrified(dbif)
         statement += self.metadata.get_update_statement_mogrified(dbif)
 
         if execute == True:
             dbif.execute_transaction(statement)
-	    if connect:
-		dbif.close()
+            if connect:
+                dbif.close()
             return ""
 
         if connect:
             dbif.close()
         return statement
- 
+
     def update_all(self, dbif=None, execute=True):
-	"""!Update temporal dataset entry of database from the internal structure
-	   and include None varuables.
+        """!Update temporal dataset entry of database from the internal structure
+           and include None variables.
 
            @param dbif: The database interface to be used
            @param execute: If True the SQL statements will be executed.
                            If False the prepared SQL statements are returned and must be executed by the caller.
-	"""
+        """
 
         dbif, connect = init_dbif(dbif)
-        
+
         # Build the UPDATE SQL statement
         statement = self.base.get_update_all_statement_mogrified(dbif)
-	if self.is_time_absolute():
-            statement += self.absolute_time.get_update_all_statement_mogrified(dbif)
+        if self.is_time_absolute():
+            statement += self.absolute_time.get_update_all_statement_mogrified(
+                dbif)
         if self.is_time_relative():
-            statement += self.relative_time.get_update_all_statement_mogrified(dbif)
-        statement += self.spatial_extent.get_update_all_statement_mogrified(dbif)
+            statement += self.relative_time.get_update_all_statement_mogrified(
+                dbif)
+        statement += self.spatial_extent.get_update_all_statement_mogrified(
+            dbif)
         statement += self.metadata.get_update_all_statement_mogrified(dbif)
 
         if execute == True:
             dbif.execute_transaction(statement)
-	    if connect:
-		dbif.close()
+            if connect:
+                dbif.close()
             return ""
 
         if connect:
@@ -285,107 +300,33 @@ class abstract_dataset(object):
         return statement
 
     def set_time_to_absolute(self):
-	self.base.set_ttype("absolute")
+        self.base.set_ttype("absolute")
 
     def set_time_to_relative(self):
         self.base.set_ttype("relative")
 
     def is_time_absolute(self):
-	if self.base.D.has_key("temporal_type"):
-	    return self.base.get_ttype() == "absolute"
+        if "temporal_type" in self.base.D:
+            return self.base.get_ttype() == "absolute"
         else:
-	    return None
+            return None
 
     def is_time_relative(self):
-	if self.base.D.has_key("temporal_type"):
-	    return self.base.get_ttype() == "relative"
+        if "temporal_type" in self.base.D:
+            return self.base.get_ttype() == "relative"
         else:
-	    return None
+            return None
 
     def temporal_relation(self, map):
-	"""!Return the temporal relation of this and the provided temporal map"""
-	if self.is_time_absolute() and map.is_time_absolute():
-	    return self.absolute_time.temporal_relation(map.absolute_time)
+        """!Return the temporal relation of this and the provided temporal map"""
+        if self.is_time_absolute() and map.is_time_absolute():
+            return self.absolute_time.temporal_relation(map.absolute_time)
         if self.is_time_relative() and map.is_time_relative():
-	    return self.relative_time.temporal_relation(map.relative_time)
-    	return None
+            return self.relative_time.temporal_relation(map.relative_time)
+        return None
 
 ###############################################################################
-	
-class abstract_dataset_comparison_key_start_time(object):
-    """!This comparison key can be used to sort lists of abstract datasets by start time
-    
-        Example:
-        
-        # Return all maps in a space time raster dataset as map objects
-	map_list = strds.get_registered_maps_as_objects()
-	
-	# Sort the maps in the list by start time
-	sorted_map_list = sorted(map_list, key=abstract_dataset_comparison_key_start_time)
-    """
-    def __init__(self, obj, *args):
-	self.obj = obj
-    def __lt__(self, other):
-	startA, endA = self.obj.get_valid_time()
-	startB, endB = other.obj.get_valid_time()
-	return startA < startB
-    def __gt__(self, other):
-	startA, endA = self.obj.get_valid_time()
-	startB, endB = other.obj.get_valid_time()
-	return startA > startB
-    def __eq__(self, other):
-	startA, endA = self.obj.get_valid_time()
-	startB, endB = other.obj.get_valid_time()
-	return startA == startB
-    def __le__(self, other):
-	startA, endA = self.obj.get_valid_time()
-	startB, endB = other.obj.get_valid_time()
-	return startA <= startB
-    def __ge__(self, other):
-	startA, endA = self.obj.get_valid_time()
-	startB, endB = other.obj.get_valid_time()
-	return startA >= startB
-    def __ne__(self, other):
-	startA, endA = self.obj.get_valid_time()
-	startB, endB = other.obj.get_valid_time()
-	return startA != startB
-	
-###############################################################################
-	
-class abstract_dataset_comparison_key_end_time(object):
-    """!This comparison key can be used to sort lists of abstract datasets by end time
-    
-        Example:
-        
-        # Return all maps in a space time raster dataset as map objects
-	map_list = strds.get_registered_maps_as_objects()
-	
-	# Sort the maps in the list by end time
-	sorted_map_list = sorted(map_list, key=abstract_dataset_comparison_key_end_time)
-    """
-    def __init__(self, obj, *args):
-	self.obj = obj
-    def __lt__(self, other):
-	startA, endA = self.obj.get_valid_time()
-	startB, endB = other.obj.get_valid_time()
-	return endA < endB
-    def __gt__(self, other):
-	startA, endA = self.obj.get_valid_time()
-	startB, endB = other.obj.get_valid_time()
-	return endA > endB
-    def __eq__(self, other):
-	startA, endA = self.obj.get_valid_time()
-	startB, endB = other.obj.get_valid_time()
-	return endA == endB
-    def __le__(self, other):
-	startA, endA = self.obj.get_valid_time()
-	startB, endB = other.obj.get_valid_time()
-	return endA <= endB
-    def __ge__(self, other):
-	startA, endA = self.obj.get_valid_time()
-	startB, endB = other.obj.get_valid_time()
-	return endA >= endB
-    def __ne__(self, other):
-	startA, endA = self.obj.get_valid_time()
-	startB, endB = other.obj.get_valid_time()
-	return endA != endB
+
+if __name__ == "__main__":
+    import doctest
+    doctest.testmod()

File diff suppressed because it is too large
+ 434 - 390
lib/python/temporal/abstract_map_dataset.py


+ 3 - 3
lib/python/temporal/abstract_space_time_dataset.py

@@ -47,11 +47,11 @@ class abstract_space_time_dataset(abstract_dataset):
 
            @param ident: The unique identifier of the new object
         """
-        raise IOError("This method must be implemented in the subclasses")
+        raise ImplementationError("This method must be implemented in the subclasses")
 
     def get_map_register(self):
         """!Return the name of the map register table"""
-        raise IOError("This method must be implemented in the subclasses")
+        raise ImplementationError("This method must be implemented in the subclasses")
 
     def set_map_register(self, name):
         """!Set the name of the map register table
@@ -60,7 +60,7 @@ class abstract_space_time_dataset(abstract_dataset):
 
            @param name: The name of the register table
         """
-        raise IOError("This method must be implemented in the subclasses")
+        raise ImplementationError("This method must be implemented in the subclasses")
  
     def print_self(self):
 	"""!Print the content of the internal structure to stdout"""

File diff suppressed because it is too large
+ 546 - 384
lib/python/temporal/base.py


+ 162 - 129
lib/python/temporal/core.py

@@ -2,16 +2,25 @@
 
 @brief GRASS Python scripting module (temporal GIS functions)
 
-Temporal GIS core functions to be used in Python scripts.
+Temporal GIS core functions to be used in library modules and scripts.
 
-Usage:
+This module provides the functionality to create the temporal
+SQL database and to establish a connection to the database.
 
-@code
-import grass.temporal as tgis
+Usage:
 
-tgis.create_temporal_database()
-...
-@endcode
+>>> import grass.temporal as tgis
+>>> # Create the temporal database
+>>> tgis.create_temporal_database()
+>>> # Establish a database connection
+>>> dbif, connected = tgis.init_dbif(None)
+>>> dbif.connect()
+>>> # Execute a SQL statement
+>>> dbif.execute_transaction("SELECT datetime(0, 'unixepoch', 'localtime');")
+>>> # Mogrify an SQL statement
+>>> dbif.mogrify_sql_statement(["SELECT name from raster_base where name = ?", ("precipitation",)])
+"SELECT name from raster_base where name = 'precipitation'"
+>>> dbif.close()
 
 (C) 2008-2011 by the GRASS Development Team
 This program is free software under the GNU General Public
@@ -22,7 +31,6 @@ for details.
 """
 import os
 import copy
-from datetime import datetime, date, time, timedelta
 import grass.script.core as core
 
 ###############################################################################
@@ -31,7 +39,7 @@ import grass.script.core as core
 # Check the grass environment before import
 core.run_command("t.connect", flags="c")
 kv = core.parse_command("t.connect", flags="pg")
-if kv.has_key("driver"):
+if "driver" in kv:
     if kv["driver"] == "sqlite":
         import sqlite3 as dbmi
     elif kv["driver"] == "pg":
@@ -47,50 +55,54 @@ else:
 
 ###############################################################################
 
+
 def get_temporal_dbmi_init_string():
     kv = core.parse_command("t.connect", flags="pg")
     grassenv = core.gisenv()
     if dbmi.__name__ == "sqlite3":
-        if kv.has_key("database"):
-            string =  kv["database"]
+        if "database" in kv:
+            string = kv["database"]
             string = string.replace("$GISDBASE", grassenv["GISDBASE"])
-            string = string.replace("$LOCATION_NAME", grassenv["LOCATION_NAME"])
+            string = string.replace(
+                "$LOCATION_NAME", grassenv["LOCATION_NAME"])
             return string
         else:
             core.fatal(_("Unable to initialize the temporal GIS DBMI interface. Use t.connect to specify the driver and the database string"))
     elif dbmi.__name__ == "psycopg2":
-        if kv.has_key("database"):
-            string =  kv["database"]
+        if "database" in kv:
+            string = kv["database"]
             return string
         else:
             core.fatal(_("Unable to initialize the temporal GIS DBMI interface. Use t.connect to specify the driver and the database string"))
-	    return "dbname=grass_test user=soeren password=abcdefgh"
+            return "dbname=grass_test user=soeren password=abcdefgh"
 
 ###############################################################################
 
+
 def get_sql_template_path():
     base = os.getenv("GISBASE")
-    base_etc  = os.path.join(base, "etc")
+    base_etc = os.path.join(base, "etc")
     return os.path.join(base_etc, "sql")
 
 ###############################################################################
 
+
 def create_temporal_database():
     """!This function creates the grass location database structure for raster, vector and raster3d maps
        as well as for the space-time datasets strds, str3ds and stvds
 
-       This functions must be called before any spatio-temporal processing is started
+       This functions must be called before any spatio-temporal processing can be started
     """
-    
+
     database = get_temporal_dbmi_init_string()
-    
+
     db_exists = False
 
     # Check if the database already exists
     if dbmi.__name__ == "sqlite3":
-	# Check path of the sqlite database
-	if os.path.exists(database):
-	    db_exists = True
+        # Check path of the sqlite database
+        if os.path.exists(database):
+            db_exists = True
     elif dbmi.__name__ == "psycopg2":
         # Connect to database
         connection = dbmi.connect(database)
@@ -102,25 +114,34 @@ def create_temporal_database():
         cursor.close()
 
     if db_exists == True:
-	return
-    
-    core.message(_("Create temporal database: %s"%(database)))
-    
+        return
+
+    core.message(_("Create temporal database: %s" % (database)))
+
     # Read all SQL scripts and templates
-    map_tables_template_sql = open(os.path.join(get_sql_template_path(), "map_tables_template.sql"), 'r').read()
-    raster_metadata_sql = open(os.path.join(get_sql_template_path(), "raster_metadata_table.sql"), 'r').read()
-    raster3d_metadata_sql = open(os.path.join(get_sql_template_path(), "raster3d_metadata_table.sql"), 'r').read()
-    vector_metadata_sql = open(os.path.join(get_sql_template_path(), "vector_metadata_table.sql"), 'r').read()
-    stds_tables_template_sql = open(os.path.join(get_sql_template_path(), "stds_tables_template.sql"), 'r').read()
-    strds_metadata_sql = open(os.path.join(get_sql_template_path(), "strds_metadata_table.sql"), 'r').read()
-    str3ds_metadata_sql = open(os.path.join(get_sql_template_path(), "str3ds_metadata_table.sql"), 'r').read()
-    stvds_metadata_sql = open(os.path.join(get_sql_template_path(), "stvds_metadata_table.sql"), 'r').read()
-    
+    map_tables_template_sql = open(os.path.join(
+        get_sql_template_path(), "map_tables_template.sql"), 'r').read()
+    raster_metadata_sql = open(os.path.join(
+        get_sql_template_path(), "raster_metadata_table.sql"), 'r').read()
+    raster3d_metadata_sql = open(os.path.join(get_sql_template_path(
+        ), "raster3d_metadata_table.sql"), 'r').read()
+    vector_metadata_sql = open(os.path.join(
+        get_sql_template_path(), "vector_metadata_table.sql"), 'r').read()
+    stds_tables_template_sql = open(os.path.join(
+        get_sql_template_path(), "stds_tables_template.sql"), 'r').read()
+    strds_metadata_sql = open(os.path.join(
+        get_sql_template_path(), "strds_metadata_table.sql"), 'r').read()
+    str3ds_metadata_sql = open(os.path.join(
+        get_sql_template_path(), "str3ds_metadata_table.sql"), 'r').read()
+    stvds_metadata_sql = open(os.path.join(
+        get_sql_template_path(), "stvds_metadata_table.sql"), 'r').read()
+
     # Create the raster, raster3d and vector tables
     raster_tables_sql = map_tables_template_sql.replace("GRASS_MAP", "raster")
     vector_tables_sql = map_tables_template_sql.replace("GRASS_MAP", "vector")
-    raster3d_tables_sql = map_tables_template_sql.replace("GRASS_MAP", "raster3d")
-  
+    raster3d_tables_sql = map_tables_template_sql.replace(
+        "GRASS_MAP", "raster3d")
+
     # Create the space-time raster, raster3d and vector dataset tables
     strds_tables_sql = stds_tables_template_sql.replace("STDS", "strds")
     stvds_tables_sql = stds_tables_template_sql.replace("STDS", "stvds")
@@ -131,58 +152,60 @@ def create_temporal_database():
     cursor = connection.cursor()
 
     if dbmi.__name__ == "sqlite3":
-	
-	sqlite3_delete_trigger_sql = open(os.path.join(get_sql_template_path(), "sqlite3_delete_trigger.sql"), 'r').read()
-	
-	# Execute the SQL statements for sqlite
-	# Create the global tables for the native grass datatypes
-	cursor.executescript(raster_tables_sql)
-	cursor.executescript(raster_metadata_sql)
-	cursor.executescript(vector_tables_sql)
-	cursor.executescript(vector_metadata_sql)
-	cursor.executescript(raster3d_tables_sql)
-	cursor.executescript(raster3d_metadata_sql)
-	# Create the tables for the new space-time datatypes
-	cursor.executescript(strds_tables_sql)
-	cursor.executescript(strds_metadata_sql)
-	cursor.executescript(stvds_tables_sql)
-	cursor.executescript(stvds_metadata_sql)
-	cursor.executescript(str3ds_tables_sql)
-	cursor.executescript(str3ds_metadata_sql)
-	cursor.executescript(sqlite3_delete_trigger_sql)
+
+        sqlite3_delete_trigger_sql = open(os.path.join(get_sql_template_path(
+        ), "sqlite3_delete_trigger.sql"), 'r').read()
+
+        # Execute the SQL statements for sqlite
+        # Create the global tables for the native grass datatypes
+        cursor.executescript(raster_tables_sql)
+        cursor.executescript(raster_metadata_sql)
+        cursor.executescript(vector_tables_sql)
+        cursor.executescript(vector_metadata_sql)
+        cursor.executescript(raster3d_tables_sql)
+        cursor.executescript(raster3d_metadata_sql)
+        # Create the tables for the new space-time datatypes
+        cursor.executescript(strds_tables_sql)
+        cursor.executescript(strds_metadata_sql)
+        cursor.executescript(stvds_tables_sql)
+        cursor.executescript(stvds_metadata_sql)
+        cursor.executescript(str3ds_tables_sql)
+        cursor.executescript(str3ds_metadata_sql)
+        cursor.executescript(sqlite3_delete_trigger_sql)
     elif dbmi.__name__ == "psycopg2":
-	# Execute the SQL statements for postgresql
-	# Create the global tables for the native grass datatypes
-	cursor.execute(raster_tables_sql)
-	cursor.execute(raster_metadata_sql)
-	cursor.execute(vector_tables_sql)
-	cursor.execute(vector_metadata_sql)
-	cursor.execute(raster3d_tables_sql)
-	cursor.execute(raster3d_metadata_sql)
-	# Create the tables for the new space-time datatypes
-	cursor.execute(strds_tables_sql)
-	cursor.execute(strds_metadata_sql)
-	cursor.execute(stvds_tables_sql)
-	cursor.execute(stvds_metadata_sql)
-	cursor.execute(str3ds_tables_sql)
-	cursor.execute(str3ds_metadata_sql)
+        # Execute the SQL statements for postgresql
+        # Create the global tables for the native grass datatypes
+        cursor.execute(raster_tables_sql)
+        cursor.execute(raster_metadata_sql)
+        cursor.execute(vector_tables_sql)
+        cursor.execute(vector_metadata_sql)
+        cursor.execute(raster3d_tables_sql)
+        cursor.execute(raster3d_metadata_sql)
+        # Create the tables for the new space-time datatypes
+        cursor.execute(strds_tables_sql)
+        cursor.execute(strds_metadata_sql)
+        cursor.execute(stvds_tables_sql)
+        cursor.execute(stvds_metadata_sql)
+        cursor.execute(str3ds_tables_sql)
+        cursor.execute(str3ds_metadata_sql)
 
     connection.commit()
     cursor.close()
 
 ###############################################################################
 
-class sql_database_interface_connection():
+
+class SQLDatabaseInterfaceConnection():
     """!This class represents the database interface connection
-    
+
        The following DBMS are supported:
        * sqlite via the sqlite3 standard library
        * postgresql via psycopg2
 
     """
     def __init__(self):
-	self.connected = False
-	
+        self.connected = False
+
     def connect(self):
         """!Connect to the DBMI to execute SQL statements
 
@@ -191,24 +214,25 @@ class sql_database_interface_connection():
         init = get_temporal_dbmi_init_string()
         #print "Connect to",  self.database
         if dbmi.__name__ == "sqlite3":
-	    self.connection = dbmi.connect(init, detect_types=dbmi.PARSE_DECLTYPES|dbmi.PARSE_COLNAMES)
-	    self.connection.row_factory = dbmi.Row
+            self.connection = dbmi.connect(init, detect_types=dbmi.PARSE_DECLTYPES | dbmi.PARSE_COLNAMES)
+            self.connection.row_factory = dbmi.Row
             self.connection.isolation_level = None
-	    self.cursor = self.connection.cursor()
+            self.cursor = self.connection.cursor()
             self.cursor.execute("PRAGMA synchronous = OFF")
             self.cursor.execute("PRAGMA journal_mode = MEMORY")
         elif dbmi.__name__ == "psycopg2":
-	    self.connection = dbmi.connect(init)
-	    #self.connection.set_isolation_level(dbmi.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
-	    self.cursor = self.connection.cursor(cursor_factory=dbmi.extras.DictCursor)
-	self.connected = True
-	
+            self.connection = dbmi.connect(init)
+            #self.connection.set_isolation_level(dbmi.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
+            self.cursor = self.connection.cursor(
+                cursor_factory=dbmi.extras.DictCursor)
+        self.connected = True
+
     def close(self):
         """!Close the DBMI connection"""
         #print "Close connection to",  self.database
-	self.connection.commit()
+        self.connection.commit()
         self.cursor.close()
-	self.connected = False
+        self.connected = False
 
     def mogrify_sql_statement(self, content):
         """!Return the SQL statement and arguments as executable SQL string
@@ -231,16 +255,16 @@ class sql_database_interface_connection():
                     statement = self.cursor.mogrify(sql, args)
                     self.close()
                     return statement
-                    
+
         elif dbmi.__name__ == "sqlite3":
             if len(args) == 0:
                 return sql
             else:
-                # Unfortunately as sqlite does not support 
+                # Unfortunately as sqlite does not support
                 # the transformation of sql strings and qmarked or
                 # named arguments we must make our hands dirty
                 # and do it by ourself. :(
-                # Doors are open for SQL injection because of the 
+                # Doors are open for SQL injection because of the
                 # limited python sqlite3 implementation!!!
                 pos = 0
                 count = 0
@@ -251,56 +275,59 @@ class sql_database_interface_connection():
                     pos = statement.find("?", pos + 1)
                     if pos == -1:
                         break
-                    
-                    if args[count] == None:
-                        statement = "%sNULL%s"%(statement[0:pos], statement[pos+1:])
+
+                    if args[count] is None:
+                        statement = "%sNULL%s" % (statement[0:
+                                                            pos], statement[pos + 1:])
                     elif isinstance(args[count], (int, long)):
-                        statement = "%s%d%s"%(statement[0:pos], args[count],statement[pos+1:])
+                        statement = "%s%d%s" % (statement[0:pos], args[count],
+                                                statement[pos + 1:])
                     elif isinstance(args[count], float):
-                        statement = "%s%f%s"%(statement[0:pos], args[count],statement[pos+1:])
+                        statement = "%s%f%s" % (statement[0:pos], args[count],
+                                                statement[pos + 1:])
                     else:
                         # Default is a string, this works for datetime objects too
-                        statement = "%s\'%s\'%s"%(statement[0:pos], str(args[count]),statement[pos+1:])
+                        statement = "%s\'%s\'%s" % (statement[0:pos], str(args[count]), statement[pos + 1:])
                     count += 1
 
                 return statement
-                
+
     def execute_transaction(self, statement):
-	"""!Execute a transactional SQL statement
-
-	    The BEGIN and END TRANSACTION statements will be added automatically
-	    to the sql statement
-
-	    @param statement The executable SQL statement or SQL script
-	"""
-	connect = False
-	if self.connected == False:
-	    self.connect()
-	    connect = True
-
-	sql_script = ""
-	sql_script += "BEGIN TRANSACTION;\n"
-	sql_script += statement
-	sql_script += "END TRANSACTION;"
-	try:
-	    if dbmi.__name__ == "sqlite3":
-		self.cursor.executescript(statement)
-	    else:
-		self.cursor.execute(statement)
-	    self.connection.commit()
-	except:
-	    if connect == True:
-		self.close()
-	    core.error(_("Unable to execute transaction:\n %s") % (statement))
-	    raise
-
-	if connect:
-	    self.close()
-	    
+        """!Execute a transactional SQL statement
+
+            The BEGIN and END TRANSACTION statements will be added automatically
+            to the sql statement
+
+            @param statement The executable SQL statement or SQL script
+        """
+        connect = False
+        if self.connected == False:
+            self.connect()
+            connect = True
+
+        sql_script = ""
+        sql_script += "BEGIN TRANSACTION;\n"
+        sql_script += statement
+        sql_script += "END TRANSACTION;"
+        try:
+            if dbmi.__name__ == "sqlite3":
+                self.cursor.executescript(statement)
+            else:
+                self.cursor.execute(statement)
+            self.connection.commit()
+        except:
+            if connect == True:
+                self.close()
+            core.error(_("Unable to execute transaction:\n %s") % (statement))
+            raise
+
+        if connect:
+            self.close()
+
 ###############################################################################
 
 def init_dbif(dbif):
-    """!This method checks if the database interface connection exists, if not a new one 
+    """!This method checks if the database interface connection exists, if not a new one
         will be created, connected and True will be returned
 
         Usage code sample:
@@ -308,9 +335,15 @@ def init_dbif(dbif):
         if connect:
             dbif.close()
     """
-    if dbif == None:
-        dbif = sql_database_interface_connection()
+    if dbif is None:
+        dbif = SQLDatabaseInterfaceConnection()
         dbif.connect()
         return dbif, True
 
     return dbif, False
+
+###############################################################################
+
+if __name__ == "__main__":
+    import doctest
+    doctest.testmod()

+ 1 - 1
lib/python/temporal/extract.py

@@ -62,7 +62,7 @@ def extract_dataset(input, output, type, where, expression, base, nprocs=1, regi
 	
     dummy = sp.get_new_map_instance(None)
 	
-    dbif = sql_database_interface_connection()
+    dbif = ()
     dbif.connect()
     
     if sp.is_in_db(dbif) == False:

+ 1 - 1
lib/python/temporal/mapcalc.py

@@ -42,7 +42,7 @@ def dataset_mapcalculator(inputs, output, type, expression, base, method, nprocs
     """
     
     # We need a database interface for fast computation
-    dbif = sql_database_interface_connection()
+    dbif = ()
     dbif.connect()
 
     mapset =  core.gisenv()["MAPSET"]

File diff suppressed because it is too large
+ 1302 - 690
lib/python/temporal/metadata.py


+ 124 - 30
lib/python/temporal/space_time_datasets.py

@@ -98,11 +98,11 @@ class raster_dataset(abstract_map_dataset):
 	
     def reset(self, ident):
 	"""!Reset the internal structure and set the identifier"""
-	self.base = raster_base(ident=ident)
-	self.absolute_time = raster_absolute_time(ident=ident)
-	self.relative_time = raster_relative_time(ident=ident)
-	self.spatial_extent = raster_spatial_extent(ident=ident)
-	self.metadata = raster_metadata(ident=ident)
+	self.base = RasterBase(ident=ident)
+	self.absolute_time = RasterAbslouteTime(ident=ident)
+	self.relative_time = RasterRelativeTime(ident=ident)
+	self.spatial_extent = RasterSpatialExtent(ident=ident)
+	self.metadata = RasterMetadata(ident=ident)
 		
     def has_grass_timestamp(self):
         """!Check if a grass file bsased time stamp exists for this map. 
@@ -306,11 +306,11 @@ class raster3d_dataset(abstract_map_dataset):
         
     def reset(self, ident):
 	"""!Reset the internal structure and set the identifier"""
-	self.base = raster3d_base(ident=ident)
-	self.absolute_time = raster3d_absolute_time(ident=ident)
-	self.relative_time = raster3d_relative_time(ident=ident)
-	self.spatial_extent = raster3d_spatial_extent(ident=ident)
-	self.metadata = raster3d_metadata(ident=ident)
+	self.base = Raster3DBase(ident=ident)
+	self.absolute_time = Raster3DAbslouteTime(ident=ident)
+	self.relative_time = Raster3DRelativeTime(ident=ident)
+	self.spatial_extent = Raster3DSpatialExtent(ident=ident)
+	self.metadata = Raster3DMetadata(ident=ident)
 
     def has_grass_timestamp(self):
         """!Check if a grass file bsased time stamp exists for this map. 
@@ -515,11 +515,11 @@ class vector_dataset(abstract_map_dataset):
 	
     def reset(self, ident):
 	"""!Reset the internal structure and set the identifier"""
-	self.base = vector_base(ident=ident)
-	self.absolute_time = vector_absolute_time(ident=ident)
-	self.relative_time = vector_relative_time(ident=ident)
-	self.spatial_extent = vector_spatial_extent(ident=ident)
-	self.metadata = vector_metadata(ident=ident)
+	self.base = VectorBase(ident=ident)
+	self.absolute_time = VectorAbslouteTime(ident=ident)
+	self.relative_time = VectorRelativeTime(ident=ident)
+	self.spatial_extent = VectorSpatialExtent(ident=ident)
+	self.metadata = VectorMetadata(ident=ident)
 
     def has_grass_timestamp(self):
         """!Check if a grass file bsased time stamp exists for this map. 
@@ -724,12 +724,12 @@ class space_time_raster_dataset(abstract_space_time_dataset):
     def reset(self, ident):
 
 	"""!Reset the internal structure and set the identifier"""
-	self.base = strds_base(ident=ident)
+	self.base = STRDSBase(ident=ident)
         self.base.set_creator(str(getpass.getuser()))
-        self.absolute_time = strds_absolute_time(ident=ident)
-        self.relative_time = strds_relative_time(ident=ident)
-	self.spatial_extent = strds_spatial_extent(ident=ident)
-	self.metadata = strds_metadata(ident=ident)
+        self.absolute_time = STRDSAbslouteTime(ident=ident)
+        self.relative_time = STRDSRelativeTime(ident=ident)
+	self.spatial_extent = STRDSSpatialExtent(ident=ident)
+	self.metadata = STRDSMetadata(ident=ident)
 
 ###############################################################################
 
@@ -778,12 +778,12 @@ class space_time_raster3d_dataset(abstract_space_time_dataset):
     def reset(self, ident):
 
 	"""!Reset the internal structure and set the identifier"""
-	self.base = str3ds_base(ident=ident)
+	self.base = STR3DSBase(ident=ident)
         self.base.set_creator(str(getpass.getuser()))
-        self.absolute_time = str3ds_absolute_time(ident=ident)
-        self.relative_time = str3ds_relative_time(ident=ident)
-	self.spatial_extent = str3ds_spatial_extent(ident=ident)
-	self.metadata = str3ds_metadata(ident=ident)
+        self.absolute_time = STR3DSAbslouteTime(ident=ident)
+        self.relative_time = STR3DSRelativeTime(ident=ident)
+	self.spatial_extent = STR3DSSpatialExtent(ident=ident)
+	self.metadata = STR3DSMetadata(ident=ident)
 
 ###############################################################################
 
@@ -826,10 +826,104 @@ class space_time_vector_dataset(abstract_space_time_dataset):
     def reset(self, ident):
 
 	"""!Reset the internal structure and set the identifier"""
-	self.base = stvds_base(ident=ident)
+	self.base = STVDSBase(ident=ident)
         self.base.set_creator(str(getpass.getuser()))
-        self.absolute_time = stvds_absolute_time(ident=ident)
-        self.relative_time = stvds_relative_time(ident=ident)
-	self.spatial_extent = stvds_spatial_extent(ident=ident)
-	self.metadata = stvds_metadata(ident=ident)
+        self.absolute_time = STVDSAbslouteTime(ident=ident)
+        self.relative_time = STVDSRelativeTime(ident=ident)
+	self.spatial_extent = STVDSSpatialExtent(ident=ident)
+	self.metadata = STVDSMetadata(ident=ident)
+
+###############################################################################
+
+class AbstractDatasetComparisonKeyStartTime(object):
+    """!This comparison key can be used to sort lists of abstract datasets by start time
+
+        Example:
+
+        # Return all maps in a space time raster dataset as map objects
+        map_list = strds.get_registered_maps_as_objects()
+
+        # Sort the maps in the list by start time
+        sorted_map_list = sorted(
+            map_list, key=AbstractDatasetComparisonKeyStartTime)
+    """
+    def __init__(self, obj, *args):
+        self.obj = obj
+
+    def __lt__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return startA < startB
+
+    def __gt__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return startA > startB
+
+    def __eq__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return startA == startB
+
+    def __le__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return startA <= startB
+
+    def __ge__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return startA >= startB
+
+    def __ne__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return startA != startB
+
+###############################################################################
+
+class AbstractDatasetComparisonKeyEndTime(object):
+    """!This comparison key can be used to sort lists of abstract datasets by end time
+
+        Example:
+
+        # Return all maps in a space time raster dataset as map objects
+        map_list = strds.get_registered_maps_as_objects()
+
+        # Sort the maps in the list by end time
+        sorted_map_list = sorted(
+            map_list, key=AbstractDatasetComparisonKeyEndTime)
+    """
+    def __init__(self, obj, *args):
+        self.obj = obj
+
+    def __lt__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return endA < endB
+
+    def __gt__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return endA > endB
+
+    def __eq__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return endA == endB
+
+    def __le__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return endA <= endB
+
+    def __ge__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return endA >= endB
+
+    def __ne__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return endA != endB
 

+ 1 - 1
lib/python/temporal/space_time_datasets_tools.py

@@ -541,7 +541,7 @@ def sample_stds_by_stds_topology(intype, sampletype, inputs, sampler, header, se
 
     sst = dataset_factory(sampletype, sid)
 
-    dbif = sql_database_interface_connection()
+    dbif = ()
     dbif.connect()
 
     for st in sts:

File diff suppressed because it is too large
+ 935 - 610
lib/python/temporal/spatial_extent.py


File diff suppressed because it is too large
+ 724 - 306
lib/python/temporal/temporal_extent.py


+ 2 - 2
lib/python/temporal/temporal_relationships.py

@@ -29,7 +29,7 @@ class temporal_topology_builder(object):
     """!This class is designed to build the temporal topology based on a lists of maps
     
 	Example:
-	
+	@code
 	# We have a space time raster dataset and build a map list
 	# from all registered maps ordered by start time
 	maps = strds.get_registered_maps_as_objects()
@@ -56,7 +56,7 @@ class temporal_topology_builder(object):
 	
 	# Dictionary like accessed
 	_map = tb["name@mapset"]
-	       
+	@endcode
     
     """
     def __init__(self):

+ 2 - 2
lib/python/temporal/univar_statistics.py

@@ -38,7 +38,7 @@ def print_gridded_dataset_univar_statistics(type, input, where, extended, header
     """
     
     # We need a database interface
-    dbif = sql_database_interface_connection()
+    dbif = SQLDatabaseInterfaceConnection()
     dbif.connect()
    
     mapset =  core.gisenv()["MAPSET"]
@@ -115,7 +115,7 @@ def print_vector_dataset_univar_statistics(input, twhere, layer, type, column, w
     """
 
     # We need a database interface
-    dbif = sql_database_interface_connection()
+    dbif = SQLDatabaseInterfaceConnection()
     dbif.connect()
    
     mapset =  core.gisenv()["MAPSET"]

+ 1 - 1
temporal/t.create/t.create.py

@@ -80,7 +80,7 @@ def main():
 
     sp = tgis.dataset_factory(type, id)
 
-    dbif = tgis.sql_database_interface_connection()
+    dbif = tgis.SQLDatabaseInterfaceConnection()
     dbif.connect()
 
     if sp.is_in_db(dbif) and grass.overwrite() == False:

+ 1 - 1
temporal/t.list/t.list.py

@@ -89,7 +89,7 @@ def main():
     id = None
     sp = tgis.dataset_factory(type, id)
 
-    dbif = tgis.sql_database_interface_connection()
+    dbif = tgis.SQLDatabaseInterfaceConnection()
     dbif.connect()
 
     # Create the sql selection statement

+ 1 - 1
temporal/t.rast.aggregate.ds/t.rast.aggregate.ds.py

@@ -82,7 +82,7 @@ def main():
     # Make sure the temporal database exists
     tgis.create_temporal_database()
     # We need a database interface
-    dbif = tgis.sql_database_interface_connection()
+    dbif = tgis.SQLDatabaseInterfaceConnection()
     dbif.connect()
    
     mapset =  grass.gisenv()["MAPSET"]

+ 1 - 1
temporal/t.rast.aggregate/t.rast.aggregate.py

@@ -85,7 +85,7 @@ def main():
     # Make sure the temporal database exists
     tgis.create_temporal_database()
     # We need a database interface
-    dbif = tgis.sql_database_interface_connection()
+    dbif = tgis.SQLDatabaseInterfaceConnection()
     dbif.connect()
    
     mapset =  grass.gisenv()["MAPSET"]

+ 1 - 1
temporal/t.rast.gapfill/t.rast.gapfill.py

@@ -73,7 +73,7 @@ def main():
         id = input + "@" + mapset
 
     # We need a database interface
-    dbif = tgis.sql_database_interface_connection()
+    dbif = tgis.SQLDatabaseInterfaceConnection()
     dbif.connect()
     
     sp = tgis.space_time_raster_dataset(id)

+ 1 - 1
temporal/t.remove/t.remove.py

@@ -59,7 +59,7 @@ def main():
     # Make sure the temporal database exists
     tgis.create_temporal_database()
 
-    dbif = tgis.sql_database_interface_connection()
+    dbif = tgis.SQLDatabaseInterfaceConnection()
     dbif.connect()
 
     dataset_list = []

+ 1 - 1
temporal/t.support/t.support.py

@@ -89,7 +89,7 @@ def main():
     else:
         id = name + "@" + mapset
         
-    dbif = tgis.sql_database_interface_connection()
+    dbif = tgis.SQLDatabaseInterfaceConnection()
     dbif.connect()
 
     stds = tgis.dataset_factory(type, id)

+ 1 - 1
temporal/t.unregister/t.unregister.py

@@ -63,7 +63,7 @@ def main():
 
     mapset =  grass.gisenv()["MAPSET"]
 
-    dbif = tgis.sql_database_interface_connection()
+    dbif = tgis.SQLDatabaseInterfaceConnection()
     dbif.connect()
 
     # In case a space time dataset is specified

+ 1 - 1
temporal/t.vect.observe.strds/t.vect.observe.strds.py

@@ -74,7 +74,7 @@ def main():
     # Make sure the temporal database exists
     tgis.create_temporal_database()
     # We need a database interface
-    dbif = tgis.sql_database_interface_connection()
+    dbif = tgis.SQLDatabaseInterfaceConnection()
     dbif.connect()
    
     mapset =  grass.gisenv()["MAPSET"]

+ 1 - 1
temporal/t.vect.what.strds/t.vect.what.strds.py

@@ -80,7 +80,7 @@ def main():
     # Make sure the temporal database exists
     tgis.create_temporal_database()
     # We need a database interface
-    dbif = tgis.sql_database_interface_connection()
+    dbif = tgis.SQLDatabaseInterfaceConnection()
     dbif.connect()
    
     mapset =  grass.gisenv()["MAPSET"]