~ubuntu-branches/ubuntu/wily/grass/wily

« back to all changes in this revision

Viewing changes to lib/python/temporal/base.py

Tags: 7.0.0~rc1+ds1-1~exp1
* New upstream release candidate.
* Repack upstream tarball, remove precompiled Python objects.
* Add upstream metadata.
* Update gbp.conf and Vcs-Git URL to use the experimental branch.
* Update watch file for GRASS 7.0.
* Drop build dependencies for Tcl/Tk, add build dependencies:
  python-numpy, libnetcdf-dev, netcdf-bin, libblas-dev, liblapack-dev
* Update Vcs-Browser URL to use cgit instead of gitweb.
* Update paths to use grass70.
* Add configure options: --with-netcdf, --with-blas, --with-lapack,
  remove --with-tcltk-includes.
* Update patches for GRASS 7.
* Update copyright file, changes:
  - Update copyright years
  - Group files by license
  - Remove unused license sections
* Add patches for various typos.
* Fix desktop file with patch instead of d/rules.
* Use minimal dh rules.
* Bump Standards-Version to 3.9.6, no changes.
* Use dpkg-maintscript-helper to replace directories with symlinks.
  (closes: #776349)
* Update my email to use @debian.org address.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
This packages includes all base classes to store basic information
 
3
like id, name, mapset creation and modification time as well as sql
 
4
serialization and de-serialization and the sql database interface.
 
5
 
 
6
Usage:
 
7
 
 
8
.. code-block:: python
 
9
 
 
10
    >>> import grass.temporal as tgis
 
11
    >>> tgis.init()
 
12
    >>> rbase = tgis.RasterBase(ident="soil@PERMANENT")
 
13
    >>> vbase = tgis.VectorBase(ident="soil:1@PERMANENT")
 
14
    >>> r3base = tgis.Raster3DBase(ident="soil@PERMANENT")
 
15
    >>> strdsbase = tgis.STRDSBase(ident="soil@PERMANENT")
 
16
    >>> stvdsbase = tgis.STVDSBase(ident="soil@PERMANENT")
 
17
    >>> str3dsbase = tgis.STR3DSBase(ident="soil@PERMANENT")
 
18
 
 
19
 
 
20
(C) 2011-2013 by the GRASS Development Team
 
21
This program is free software under the GNU General Public
 
22
License (>=v2). Read the file COPYING that comes with GRASS
 
23
for details.
 
24
 
 
25
:author: Soeren Gebbert
 
26
"""
 
27
 
 
28
from datetime import datetime
 
29
from core import *
 
30
 
 
31
###############################################################################
 
32
 
 
33
 
 
34
class DictSQLSerializer(object):
 
35
    def __init__(self):
 
36
        self.D = {}
 
37
        self.dbmi_paramstyle = get_tgis_dbmi_paramstyle()
 
38
 
 
39
    def serialize(self, type, table, where=None):
 
40
        """Convert the internal dictionary into a string of semicolon
 
41
            separated SQL statements The keys are the column names and
 
42
            the values are the row entries
 
43
 
 
44
            Usage:
 
45
 
 
46
            .. code-block:: python
 
47
 
 
48
                >>> init()
 
49
                >>> t = DictSQLSerializer()
 
50
                >>> t.D["id"] = "soil@PERMANENT"
 
51
                >>> t.D["name"] = "soil"
 
52
                >>> t.D["mapset"] = "PERMANENT"
 
53
                >>> t.D["creator"] = "soeren"
 
54
                >>> t.D["creation_time"] = datetime(2001,1,1)
 
55
                >>> t.D["modification_time"] = datetime(2001,1,1)
 
56
                >>> t.serialize(type="SELECT", table="raster_base")
 
57
                ('SELECT  name  , creator  , creation_time  , modification_time  , mapset  , id  FROM raster_base ;\\n', ())
 
58
                >>> t.serialize(type="INSERT", table="raster_base")
 
59
                ('INSERT INTO raster_base ( name  ,creator  ,creation_time  ,modification_time  ,mapset  ,id ) VALUES (? ,? ,? ,? ,? ,?) ;\\n', ('soil', 'soeren', datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil@PERMANENT'))
 
60
                >>> t.serialize(type="UPDATE", table="raster_base")
 
61
                ('UPDATE raster_base SET  name = ?  ,creator = ?  ,creation_time = ?  ,modification_time = ?  ,mapset = ?  ,id = ? ;\\n', ('soil', 'soeren', datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil@PERMANENT'))
 
62
                >>> t.serialize(type="UPDATE ALL", table="raster_base")
 
63
                ('UPDATE raster_base SET  name = ?  ,creator = ?  ,creation_time = ?  ,modification_time = ?  ,mapset = ?  ,id = ? ;\\n', ('soil', 'soeren', datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil@PERMANENT'))
 
64
 
 
65
                :param type: must be SELECT. INSERT, UPDATE
 
66
                :param table: The name of the table to select, insert or update
 
67
                :param where: The optional where statement
 
68
                :return: a tuple containing the SQL string and the arguments
 
69
 
 
70
        """
 
71
 
 
72
        sql = ""
 
73
        args = []
 
74
 
 
75
        # Create ordered select statement
 
76
        if type == "SELECT":
 
77
            sql += 'SELECT '
 
78
            count = 0
 
79
            for key in self.D.keys():
 
80
                if count == 0:
 
81
                    sql += ' %s ' % key
 
82
                else:
 
83
                    sql += ' , %s ' % key
 
84
                count += 1
 
85
            sql += ' FROM ' + table + ' '
 
86
            if where:
 
87
                sql += where
 
88
            sql += ";\n"
 
89
 
 
90
        # Create insert statement
 
91
        if type == "INSERT":
 
92
            count = 0
 
93
            sql += 'INSERT INTO ' + table + ' ('
 
94
            for key in self.D.keys():
 
95
                if count == 0:
 
96
                    sql += ' %s ' % key
 
97
                else:
 
98
                    sql += ' ,%s ' % key
 
99
                count += 1
 
100
 
 
101
            count = 0
 
102
            sql += ') VALUES ('
 
103
            for key in self.D.keys():
 
104
                if count == 0:
 
105
                    if self.dbmi_paramstyle == "qmark":
 
106
                        sql += '?'
 
107
                    else:
 
108
                        sql += '%s'
 
109
                else:
 
110
                    if self.dbmi_paramstyle == "qmark":
 
111
                        sql += ' ,?'
 
112
                    else:
 
113
                        sql += ' ,%s'
 
114
                count += 1
 
115
                args.append(self.D[key])
 
116
            sql += ') '
 
117
 
 
118
            if where:
 
119
                sql += where
 
120
            sql += ";\n"
 
121
 
 
122
        # Create update statement for existing entries
 
123
        if type == "UPDATE":
 
124
            count = 0
 
125
            sql += 'UPDATE ' + table + ' SET '
 
126
            for key in self.D.keys():
 
127
                # Update only entries which are not None
 
128
                if self.D[key] is not None:
 
129
                    if count == 0:
 
130
                        if self.dbmi_paramstyle == "qmark":
 
131
                            sql += ' %s = ? ' % key
 
132
                        else:
 
133
                            sql += ' %s ' % key
 
134
                            sql += '= %s '
 
135
                    else:
 
136
                        if self.dbmi_paramstyle == "qmark":
 
137
                            sql += ' ,%s = ? ' % key
 
138
                        else:
 
139
                            sql += ' ,%s ' % key
 
140
                            sql += '= %s '
 
141
                    count += 1
 
142
                    args.append(self.D[key])
 
143
            if where:
 
144
                sql += where
 
145
            sql += ";\n"
 
146
 
 
147
        # Create update statement for all entries
 
148
        if type == "UPDATE ALL":
 
149
            count = 0
 
150
            sql += 'UPDATE ' + table + ' SET '
 
151
            for key in self.D.keys():
 
152
                if count == 0:
 
153
                    if self.dbmi_paramstyle == "qmark":
 
154
                        sql += ' %s = ? ' % key
 
155
                    else:
 
156
                        sql += ' %s ' % key
 
157
                        sql += '= %s '
 
158
                else:
 
159
                    if self.dbmi_paramstyle == "qmark":
 
160
                        sql += ' ,%s = ? ' % key
 
161
                    else:
 
162
                        sql += ' ,%s ' % key
 
163
                        sql += '= %s '
 
164
                count += 1
 
165
                args.append(self.D[key])
 
166
            if where:
 
167
                sql += where
 
168
            sql += ";\n"
 
169
 
 
170
        return sql, tuple(args)
 
171
 
 
172
    def deserialize(self, row):
 
173
        """Convert the content of the dbmi dictionary like row into the
 
174
           internal dictionary
 
175
 
 
176
           :param row: The dictionary like row to store in the internal dict
 
177
        """
 
178
        self.D = {}
 
179
        for key in row.keys():
 
180
            self.D[key] = row[key]
 
181
 
 
182
    def clear(self):
 
183
        """Initialize the internal storage"""
 
184
        self.D = {}
 
185
 
 
186
    def print_self(self):
 
187
        """Print the content of the internal dictionary to stdout
 
188
        """
 
189
        print self.D
 
190
 
 
191
###############################################################################
 
192
 
 
193
 
 
194
class SQLDatabaseInterface(DictSQLSerializer):
 
195
    """This class represents the SQL database interface
 
196
 
 
197
       Functions to insert, select and update the internal
 
198
       structure of this class in the temporal database are implemented.
 
199
       This is the base class for raster, raster3d, vector and
 
200
       space time datasets data management classes:
 
201
 
 
202
       - Identification information (base)
 
203
       - Spatial extent
 
204
       - Temporal extent
 
205
       - Metadata
 
206
 
 
207
       Usage:
 
208
 
 
209
       .. code-block:: python
 
210
 
 
211
            >>> init()
 
212
            >>> t = SQLDatabaseInterface("raster", "soil@PERMANENT")
 
213
            >>> t.mapset = get_current_mapset()
 
214
            >>> t.D["name"] = "soil"
 
215
            >>> t.D["mapset"] = "PERMANENT"
 
216
            >>> t.D["creator"] = "soeren"
 
217
            >>> t.D["creation_time"] = datetime(2001,1,1)
 
218
            >>> t.get_delete_statement()
 
219
            "DELETE FROM raster WHERE id = 'soil@PERMANENT';\\n"
 
220
            >>> t.get_is_in_db_statement()
 
221
            "SELECT id FROM raster WHERE id = 'soil@PERMANENT';\\n"
 
222
            >>> t.get_select_statement()
 
223
            ("SELECT  creation_time  , mapset  , name  , creator  FROM raster WHERE id = 'soil@PERMANENT';\\n", ())
 
224
            >>> t.get_select_statement_mogrified()
 
225
            "SELECT  creation_time  , mapset  , name  , creator  FROM raster WHERE id = 'soil@PERMANENT';\\n"
 
226
            >>> t.get_insert_statement()
 
227
            ('INSERT INTO raster ( creation_time  ,mapset  ,name  ,creator ) VALUES (? ,? ,? ,?) ;\\n', (datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil', 'soeren'))
 
228
            >>> t.get_insert_statement_mogrified()
 
229
            "INSERT INTO raster ( creation_time  ,mapset  ,name  ,creator ) VALUES ('2001-01-01 00:00:00' ,'PERMANENT' ,'soil' ,'soeren') ;\\n"
 
230
            >>> t.get_update_statement()
 
231
            ("UPDATE raster SET  creation_time = ?  ,mapset = ?  ,name = ?  ,creator = ? WHERE id = 'soil@PERMANENT';\\n", (datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil', 'soeren'))
 
232
            >>> t.get_update_statement_mogrified()
 
233
            "UPDATE raster SET  creation_time = '2001-01-01 00:00:00'  ,mapset = 'PERMANENT'  ,name = 'soil'  ,creator = 'soeren' WHERE id = 'soil@PERMANENT';\\n"
 
234
            >>> t.get_update_all_statement()
 
235
            ("UPDATE raster SET  creation_time = ?  ,mapset = ?  ,name = ?  ,creator = ? WHERE id = 'soil@PERMANENT';\\n", (datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil', 'soeren'))
 
236
            >>> t.get_update_all_statement_mogrified()
 
237
            "UPDATE raster SET  creation_time = '2001-01-01 00:00:00'  ,mapset = 'PERMANENT'  ,name = 'soil'  ,creator = 'soeren' WHERE id = 'soil@PERMANENT';\\n"
 
238
 
 
239
    """
 
240
    def __init__(self, table=None, ident=None):
 
241
        """Constructor of this class
 
242
 
 
243
           :param table: The name of the table
 
244
           :param ident: The identifier (primary key) of this
 
245
                         object in the database table
 
246
        """
 
247
        DictSQLSerializer.__init__(self)
 
248
 
 
249
        self.table = table  # Name of the table, set in the subclass
 
250
        self.ident = ident
 
251
        self.msgr = get_tgis_message_interface()
 
252
 
 
253
        if self.ident and self.ident.find("@") >= 0:
 
254
            self.mapset = self.ident.split("@""")[1]
 
255
        else:
 
256
            self.mapset = None
 
257
 
 
258
    def get_table_name(self):
 
259
        """Return the name of the table in which the internal
 
260
           data are inserted, updated or selected
 
261
           :return: The name of the table
 
262
           """
 
263
        return self.table
 
264
 
 
265
    def get_delete_statement(self):
 
266
        """Return the delete string
 
267
           :return: The DELETE string
 
268
        """
 
269
        return "DELETE FROM " + self.get_table_name() + \
 
270
               " WHERE id = \'" + str(self.ident) + "\';\n"
 
271
 
 
272
    def delete(self, dbif=None):
 
273
        """Delete the entry of this object from the temporal database
 
274
 
 
275
           :param dbif: The database interface to be used,
 
276
                        if None a temporary connection will be established
 
277
        """
 
278
        sql = self.get_delete_statement()
 
279
        #print sql
 
280
 
 
281
        if dbif:
 
282
            dbif.execute(sql,   mapset=self.mapset)
 
283
        else:
 
284
            dbif = SQLDatabaseInterfaceConnection()
 
285
            dbif.connect()
 
286
            dbif.execute(sql,   mapset=self.mapset)
 
287
            dbif.close()
 
288
 
 
289
    def get_is_in_db_statement(self):
 
290
        """Return the selection string that checks if this object is registered in the
 
291
           temporal database
 
292
           :return: The SELECT string
 
293
        """
 
294
        return "SELECT id FROM " + self.get_table_name() + \
 
295
               " WHERE id = \'" + str(self.ident) + "\';\n"
 
296
 
 
297
    def is_in_db(self, dbif=None):
 
298
        """Check if this object is present in the temporal database
 
299
 
 
300
           :param dbif: The database interface to be used,
 
301
                        if None a temporary connection will be established
 
302
           :return: True if this object is present in the temporal database,
 
303
                    False otherwise
 
304
        """
 
305
 
 
306
        sql = self.get_is_in_db_statement()
 
307
 
 
308
        if dbif:
 
309
            dbif.execute(sql, mapset=self.mapset)
 
310
            row = dbif.fetchone(mapset=self.mapset)
 
311
        else:
 
312
            dbif = SQLDatabaseInterfaceConnection()
 
313
            dbif.connect()
 
314
            dbif.execute(sql, mapset=self.mapset)
 
315
            row = dbif.fetchone(mapset=self.mapset)
 
316
            dbif.close()
 
317
 
 
318
        # Nothing found
 
319
        if row is None:
 
320
            return False
 
321
 
 
322
        return True
 
323
 
 
324
    def get_select_statement(self):
 
325
        """Return the sql statement and the argument list in
 
326
           database specific style
 
327
           :return: The SELECT string
 
328
        """
 
329
        return self.serialize("SELECT", self.get_table_name(),
 
330
                              "WHERE id = \'" + str(self.ident) + "\'")
 
331
 
 
332
    def get_select_statement_mogrified(self, dbif=None):
 
333
        """Return the select statement as mogrified string
 
334
 
 
335
           :param dbif: The database interface to be used,
 
336
                        if None a temporary connection will be established
 
337
           :return: The SELECT string
 
338
        """
 
339
        if not dbif:
 
340
            dbif = SQLDatabaseInterfaceConnection()
 
341
 
 
342
        return dbif.mogrify_sql_statement(self.get_select_statement(),
 
343
                                          mapset=self.mapset)
 
344
 
 
345
    def select(self, dbif=None):
 
346
        """Select the content from the temporal database and store it
 
347
           in the internal dictionary structure
 
348
 
 
349
           :param dbif: The database interface to be used,
 
350
                        if None a temporary connection will be established
 
351
        """
 
352
        sql, args = self.get_select_statement()
 
353
        #print sql
 
354
        #print args
 
355
 
 
356
        if dbif:
 
357
            if len(args) == 0:
 
358
                dbif.execute(sql,  mapset=self.mapset)
 
359
            else:
 
360
                dbif.execute(sql, args,  mapset=self.mapset)
 
361
            row = dbif.fetchone(mapset=self.mapset)
 
362
        else:
 
363
            dbif = SQLDatabaseInterfaceConnection()
 
364
            dbif.connect()
 
365
            if len(args) == 0:
 
366
                dbif.execute(sql, mapset=self.mapset)
 
367
            else:
 
368
                dbif.execute(sql, args, mapset=self.mapset)
 
369
            row = dbif.fetchone(mapset=self.mapset)
 
370
            dbif.close()
 
371
 
 
372
        # Nothing found
 
373
        if row is None:
 
374
            return False
 
375
 
 
376
        if len(row) > 0:
 
377
            self.deserialize(row)
 
378
        else:
 
379
            self.msgr.fatal(_("Object <%s> not found in the temporal database")
 
380
                            % self.get_id())
 
381
 
 
382
        return True
 
383
 
 
384
    def get_insert_statement(self):
 
385
        """Return the sql statement and the argument
 
386
           list in database specific style
 
387
           :return: The INSERT string"""
 
388
        return self.serialize("INSERT", self.get_table_name())
 
389
 
 
390
    def get_insert_statement_mogrified(self, dbif=None):
 
391
        """Return the insert statement as mogrified string
 
392
 
 
393
           :param dbif: The database interface to be used,
 
394
                        if None a temporary connection will be established
 
395
           :return: The INSERT string
 
396
        """
 
397
        if not dbif:
 
398
            dbif = SQLDatabaseInterfaceConnection()
 
399
 
 
400
        return dbif.mogrify_sql_statement(self.get_insert_statement(),
 
401
                                          mapset=self.mapset)
 
402
 
 
403
    def insert(self, dbif=None):
 
404
        """Serialize the content of this object and store it in the temporal
 
405
           database using the internal identifier
 
406
 
 
407
           :param dbif: The database interface to be used,
 
408
                        if None a temporary connection will be established
 
409
        """
 
410
        sql, args = self.get_insert_statement()
 
411
        #print sql
 
412
        #print args
 
413
 
 
414
        if dbif:
 
415
            dbif.execute(sql, args, mapset=self.mapset)
 
416
        else:
 
417
            dbif = SQLDatabaseInterfaceConnection()
 
418
            dbif.connect()
 
419
            dbif.execute(sql, args, mapset=self.mapset)
 
420
            dbif.close()
 
421
 
 
422
    def get_update_statement(self, ident=None):
 
423
        """Return the sql statement and the argument list
 
424
           in database specific style
 
425
 
 
426
           :param ident: The identifier to be updated, useful for renaming
 
427
           :return: The UPDATE string
 
428
 
 
429
           """
 
430
        if ident:
 
431
            return self.serialize("UPDATE", self.get_table_name(),
 
432
                                  "WHERE id = \'" + str(ident) + "\'")
 
433
        else:
 
434
            return self.serialize("UPDATE", self.get_table_name(),
 
435
                                  "WHERE id = \'" + str(self.ident) + "\'")
 
436
 
 
437
    def get_update_statement_mogrified(self, dbif=None, ident=None):
 
438
        """Return the update statement as mogrified string
 
439
 
 
440
           :param dbif: The database interface to be used,
 
441
                        if None a temporary connection will be established
 
442
           :param ident: The identifier to be updated, useful for renaming
 
443
           :return: The UPDATE string
 
444
        """
 
445
        if not dbif:
 
446
            dbif = SQLDatabaseInterfaceConnection()
 
447
 
 
448
        return dbif.mogrify_sql_statement(self.get_update_statement(ident),
 
449
                                          mapset=self.mapset)
 
450
 
 
451
    def update(self, dbif=None, ident=None):
 
452
        """Serialize the content of this object and update it in the temporal
 
453
           database using the internal identifier
 
454
 
 
455
           Only object entries which are exists (not None) are updated
 
456
 
 
457
           :param dbif: The database interface to be used,
 
458
                        if None a temporary connection will be established
 
459
           :param ident: The identifier to be updated, useful for renaming
 
460
        """
 
461
        if self.ident is None:
 
462
            self.msgr.fatal(_("Missing identifer"))
 
463
 
 
464
        sql, args = self.get_update_statement(ident)
 
465
        #print sql
 
466
        #print args
 
467
 
 
468
        if dbif:
 
469
            dbif.execute(sql, args, mapset=self.mapset)
 
470
        else:
 
471
            dbif = SQLDatabaseInterfaceConnection()
 
472
            dbif.connect()
 
473
            dbif.execute(sql, args, mapset=self.mapset)
 
474
            dbif.close()
 
475
 
 
476
    def get_update_all_statement(self, ident=None):
 
477
        """Return the sql statement and the argument
 
478
           list in database specific style
 
479
 
 
480
           :param ident: The identifier to be updated, useful for renaming
 
481
           :return: The UPDATE string
 
482
           """
 
483
        if ident:
 
484
            return self.serialize("UPDATE ALL", self.get_table_name(),
 
485
                                  "WHERE id = \'" + str(ident) + "\'")
 
486
        else:
 
487
            return self.serialize("UPDATE ALL", self.get_table_name(),
 
488
                                  "WHERE id = \'" + str(self.ident) + "\'")
 
489
 
 
490
    def get_update_all_statement_mogrified(self, dbif=None, ident=None):
 
491
        """Return the update all statement as mogrified string
 
492
 
 
493
           :param dbif: The database interface to be used,
 
494
                        if None a temporary connection will be established
 
495
           :param ident: The identifier to be updated, useful for renaming
 
496
           :return: The UPDATE string
 
497
        """
 
498
        if not dbif:
 
499
            dbif = SQLDatabaseInterfaceConnection()
 
500
 
 
501
        return dbif.mogrify_sql_statement(self.get_update_all_statement(ident),
 
502
                                          mapset=self.mapset)
 
503
 
 
504
    def update_all(self, dbif=None, ident=None):
 
505
        """Serialize the content of this object, including None objects,
 
506
        and update it in the temporal database using the internal identifier
 
507
 
 
508
           :param dbif: The database interface to be used,
 
509
                        if None a temporary connection will be established
 
510
           :param ident: The identifier to be updated, useful for renaming
 
511
        """
 
512
        if self.ident is None:
 
513
            self.msgr.fatal(_("Missing identifer"))
 
514
 
 
515
        sql, args = self.get_update_all_statement(ident)
 
516
        #print sql
 
517
        #print args
 
518
 
 
519
        if dbif:
 
520
            dbif.execute(sql, args, mapset=self.mapset)
 
521
        else:
 
522
            dbif = SQLDatabaseInterfaceConnection()
 
523
            dbif.connect()
 
524
            dbif.execute(sql, args, mapset=self.mapset)
 
525
            dbif.close()
 
526
 
 
527
###############################################################################
 
528
 
 
529
 
 
530
class DatasetBase(SQLDatabaseInterface):
 
531
    """This is the base class for all maps and spacetime datasets storing
 
532
        basic identification information
 
533
 
 
534
        Usage:
 
535
 
 
536
        .. code-block:: python
 
537
 
 
538
            >>> init()
 
539
            >>> t = DatasetBase("raster", "soil@PERMANENT", creator="soeren", ctime=datetime(2001,1,1), ttype="absolute")
 
540
            >>> t.id
 
541
            'soil@PERMANENT'
 
542
            >>> t.name
 
543
            'soil'
 
544
            >>> t.mapset
 
545
            'PERMANENT'
 
546
            >>> t.creator
 
547
            'soeren'
 
548
            >>> t.ctime
 
549
            datetime.datetime(2001, 1, 1, 0, 0)
 
550
            >>> t.ttype
 
551
            'absolute'
 
552
            >>> t.print_info()
 
553
             +-------------------- Basic information -------------------------------------+
 
554
             | Id: ........................ soil@PERMANENT
 
555
             | Name: ...................... soil
 
556
             | Mapset: .................... PERMANENT
 
557
             | Creator: ................... soeren
 
558
             | Temporal type: ............. absolute
 
559
             | Creation time: ............. 2001-01-01 00:00:00
 
560
            >>> t.print_shell_info()
 
561
            id=soil@PERMANENT
 
562
            name=soil
 
563
            mapset=PERMANENT
 
564
            creator=soeren
 
565
            temporal_type=absolute
 
566
            creation_time=2001-01-01 00:00:00
 
567
 
 
568
    """
 
569
 
 
570
    def __init__(self, table=None, ident=None, name=None, mapset=None,
 
571
                 creator=None, ctime=None, ttype=None):
 
572
        """Constructor
 
573
 
 
574
            :param table: The name of the temporal database table
 
575
                          that should be used to store the values
 
576
            :param ident: The unique identifier must be a combination of
 
577
                          the dataset name, layer name and the mapset
 
578
                          "name@mapset" or "name:layer@mapset"
 
579
                          used as as primary key in the temporal database
 
580
            :param name: The name of the map or dataset
 
581
            :param mapset: The name of the mapset
 
582
            :param creator: The name of the creator
 
583
            :param ctime: The creation datetime object
 
584
            :param ttype: The temporal type
 
585
 
 
586
                              - "absolute" Identifier for absolute time
 
587
                              - "relative" Identifier for relative time
 
588
        """
 
589
 
 
590
        SQLDatabaseInterface.__init__(self, table, ident)
 
591
 
 
592
        self.set_id(ident)
 
593
        if ident is not None and name is None and mapset is None:
 
594
            if ident.find("@") >= 0:
 
595
                name, mapset = ident.split("@")
 
596
            if name.find(":") >= 0:
 
597
                name, layer = ident.split(":")
 
598
        self.set_name(name)
 
599
        self.set_mapset(mapset)
 
600
        self.set_creator(creator)
 
601
        self.set_ctime(ctime)
 
602
        self.set_ttype(ttype)
 
603
 
 
604
    def set_id(self, ident):
 
605
        """Convenient method to set the unique identifier (primary key)
 
606
 
 
607
           :param ident: The unique identifier must be a combination
 
608
                         of the dataset name, layer name and the mapset
 
609
                         "name@mapset" or "name:layer@mapset"
 
610
        """
 
611
        self.ident = ident
 
612
        self.D["id"] = ident
 
613
 
 
614
        if ident is not None:
 
615
            if ident.find("@") >= 0:
 
616
                name, mapset = ident.split("@")
 
617
                self.set_mapset(mapset)
 
618
                self.set_name(name)
 
619
            else:
 
620
                self.msgr.fatal(_("Wrong identifier, the mapset is missing"))
 
621
            if name.find(":") >= 0:
 
622
                name, layer = ident.split(":")
 
623
                self.set_layer(layer)
 
624
            self.set_name(name)
 
625
 
 
626
    def set_name(self, name):
 
627
        """Set the name of the dataset
 
628
 
 
629
           :param name: The name of the dataset
 
630
        """
 
631
        self.D["name"] = name
 
632
 
 
633
    def set_mapset(self, mapset):
 
634
        """Set the mapset of the dataset
 
635
 
 
636
           :param mapset: The name of the mapset in which this dataset is stored
 
637
        """
 
638
        self.D["mapset"] = mapset
 
639
 
 
640
    def set_layer(self, layer):
 
641
        """Convenient method to set the layer of the map (part of primary key)
 
642
 
 
643
           Layer are supported for vector maps
 
644
 
 
645
           :param layer: The layer of the map
 
646
        """
 
647
        self.D["layer"] = layer
 
648
 
 
649
    def set_creator(self, creator):
 
650
        """Set the creator of the dataset
 
651
 
 
652
           :param creator: The name of the creator
 
653
        """
 
654
        self.D["creator"] = creator
 
655
 
 
656
    def set_ctime(self, ctime=None):
 
657
        """Set the creation time of the dataset,
 
658
           if nothing set the current time is used
 
659
 
 
660
           :param ctime: The current time of type datetime
 
661
        """
 
662
        if ctime is None:
 
663
            self.D["creation_time"] = datetime.today()
 
664
        else:
 
665
            self.D["creation_time"] = ctime
 
666
 
 
667
    def set_ttype(self, ttype):
 
668
        """Set the temporal type of the dataset: absolute or relative,
 
669
           if nothing set absolute time will assumed
 
670
 
 
671
           :param ttype: The temporal type of the dataset "absolute or relative"
 
672
        """
 
673
        if ttype is None or (ttype != "absolute" and ttype != "relative"):
 
674
            self.D["temporal_type"] = "absolute"
 
675
        else:
 
676
            self.D["temporal_type"] = ttype
 
677
 
 
678
    def get_id(self):
 
679
        """Convenient method to get the unique identifier (primary key)
 
680
 
 
681
           :return: None if not found
 
682
        """
 
683
        if "id" in self.D:
 
684
            return self.D["id"]
 
685
        else:
 
686
            return None
 
687
 
 
688
    def get_map_id(self):
 
689
        """Convenient method to get the unique map identifier
 
690
           without layer information
 
691
 
 
692
           :return: the name of the vector map as "name@mapset"
 
693
                  or None in case the id was not set
 
694
        """
 
695
        if self.id:
 
696
            if self.id.find(":") >= 0:
 
697
                # Remove the layer identifier from the id
 
698
                return self.id.split("@")[0].split(":")[0] + "@" + \
 
699
                       self.id.split("@")[1]
 
700
            else:
 
701
                return self.id
 
702
        else:
 
703
            return None
 
704
 
 
705
    def get_layer(self):
 
706
        """Convenient method to get the layer of the map (part of primary key)
 
707
 
 
708
           Layer are currently supported for vector maps
 
709
 
 
710
           :return: None if not found
 
711
        """
 
712
        if "layer" in self.D:
 
713
            return self.D["layer"]
 
714
        else:
 
715
            return None
 
716
 
 
717
    def get_name(self):
 
718
        """Get the name of the dataset
 
719
           :return: None if not found"""
 
720
        if "name" in self.D:
 
721
            return self.D["name"]
 
722
        else:
 
723
            return None
 
724
 
 
725
    def get_mapset(self):
 
726
        """Get the name of mapset of this dataset
 
727
           :return: None if not found"""
 
728
        if "mapset" in self.D:
 
729
            return self.D["mapset"]
 
730
        else:
 
731
            return None
 
732
 
 
733
    def get_creator(self):
 
734
        """Get the creator of the dataset
 
735
           :return: None if not found"""
 
736
        if "creator" in self.D:
 
737
            return self.D["creator"]
 
738
        else:
 
739
            return None
 
740
 
 
741
    def get_ctime(self):
 
742
        """Get the creation time of the dataset, datatype is datetime
 
743
           :return: None if not found"""
 
744
        if "creation_time" in self.D:
 
745
            return self.D["creation_time"]
 
746
        else:
 
747
            return None
 
748
 
 
749
    def get_ttype(self):
 
750
        """Get the temporal type of the map
 
751
           :return: None if not found"""
 
752
        if "temporal_type" in self.D:
 
753
            return self.D["temporal_type"]
 
754
        else:
 
755
            return None
 
756
 
 
757
    # Properties of this class
 
758
    id = property(fget=get_id, fset=set_id)
 
759
    map_id = property(fget=get_map_id, fset=None)
 
760
    name = property(fget=get_name, fset=set_name)
 
761
    mapset = property(fget=get_mapset, fset=set_mapset)
 
762
    ctime = property(fget=get_ctime, fset=set_ctime)
 
763
    ttype = property(fget=get_ttype, fset=set_ttype)
 
764
    creator = property(fget=get_creator, fset=set_creator)
 
765
 
 
766
    def print_info(self):
 
767
        """Print information about this class in human readable style"""
 
768
        #      0123456789012345678901234567890
 
769
        print " +-------------------- Basic information -------------------------------------+"
 
770
        print " | Id: ........................ " + str(self.get_id())
 
771
        print " | Name: ...................... " + str(self.get_name())
 
772
        print " | Mapset: .................... " + str(self.get_mapset())
 
773
        if self.get_layer():
 
774
            print " | Layer:...................... " + str(self.get_layer())
 
775
        print " | Creator: ................... " + str(self.get_creator())
 
776
        print " | Temporal type: ............. " + str(self.get_ttype())
 
777
        print " | Creation time: ............. " + str(self.get_ctime())
 
778
 
 
779
    def print_shell_info(self):
 
780
        """Print information about this class in shell style"""
 
781
        print "id=" + str(self.get_id())
 
782
        print "name=" + str(self.get_name())
 
783
        print "mapset=" + str(self.get_mapset())
 
784
        if self.get_layer():
 
785
            print "layer=" + str(self.get_layer())
 
786
        print "creator=" + str(self.get_creator())
 
787
        print "temporal_type=" + str(self.get_ttype())
 
788
        print "creation_time=" + str(self.get_ctime())
 
789
 
 
790
###############################################################################
 
791
 
 
792
 
 
793
class RasterBase(DatasetBase):
 
794
    """Time stamped raster map base information class"""
 
795
    def __init__(self, ident=None, name=None, mapset=None, creator=None,
 
796
                 creation_time=None, temporal_type=None):
 
797
        DatasetBase.__init__(self, "raster_base", ident, name, mapset,
 
798
                             creator, creation_time, temporal_type)
 
799
 
 
800
 
 
801
class Raster3DBase(DatasetBase):
 
802
    """Time stamped 3D raster map base information class"""
 
803
    def __init__(self, ident=None, name=None, mapset=None, creator=None,
 
804
                 creation_time=None, temporal_type=None,):
 
805
        DatasetBase.__init__(self, "raster3d_base", ident, name,
 
806
                             mapset, creator, creation_time,
 
807
                             temporal_type)
 
808
 
 
809
 
 
810
class VectorBase(DatasetBase):
 
811
    """Time stamped vector map base information class"""
 
812
    def __init__(self, ident=None, name=None, mapset=None, layer=None,
 
813
                 creator=None, creation_time=None, temporal_type=None):
 
814
        DatasetBase.__init__(self, "vector_base", ident, name, mapset,
 
815
                             creator, creation_time, temporal_type)
 
816
 
 
817
        self.set_id(ident)
 
818
        if ident is not None and name is None and mapset is None:
 
819
            if ident.find("@") >= 0:
 
820
                name, mapset = ident.split("@")
 
821
            if layer is None:
 
822
                if name.find(":") >= 0:
 
823
                    name, layer = name.split(":")
 
824
        self.set_name(name)
 
825
        self.set_mapset(mapset)
 
826
        # Layer currently only in use by vector maps
 
827
        self.set_layer(layer)
 
828
 
 
829
###############################################################################
 
830
 
 
831
 
 
832
class STDSBase(DatasetBase):
 
833
    """Base class for space time datasets
 
834
 
 
835
       This class adds the semantic type member variable to the dataset
 
836
       base class.
 
837
 
 
838
    Usage:
 
839
 
 
840
    .. code-block:: python
 
841
 
 
842
        >>> init()
 
843
        >>> t = STDSBase("stds", "soil@PERMANENT", semantic_type="average", creator="soeren", ctime=datetime(2001,1,1), ttype="absolute", mtime=datetime(2001,1,1))
 
844
        >>> t.semantic_type
 
845
        'average'
 
846
        >>> t.print_info()
 
847
         +-------------------- Basic information -------------------------------------+
 
848
         | Id: ........................ soil@PERMANENT
 
849
         | Name: ...................... soil
 
850
         | Mapset: .................... PERMANENT
 
851
         | Creator: ................... soeren
 
852
         | Temporal type: ............. absolute
 
853
         | Creation time: ............. 2001-01-01 00:00:00
 
854
         | Modification time:.......... 2001-01-01 00:00:00
 
855
         | Semantic type:.............. average
 
856
        >>> t.print_shell_info()
 
857
        id=soil@PERMANENT
 
858
        name=soil
 
859
        mapset=PERMANENT
 
860
        creator=soeren
 
861
        temporal_type=absolute
 
862
        creation_time=2001-01-01 00:00:00
 
863
        modification_time=2001-01-01 00:00:00
 
864
        semantic_type=average
 
865
 
 
866
    """
 
867
    def __init__(self, table=None, ident=None, name=None, mapset=None,
 
868
                 semantic_type=None, creator=None, ctime=None,
 
869
                 ttype=None, mtime=None):
 
870
        DatasetBase.__init__(self, table, ident, name, mapset, creator,
 
871
                             ctime, ttype)
 
872
 
 
873
        self.set_semantic_type(semantic_type)
 
874
        self.set_mtime(mtime)
 
875
 
 
876
    def set_semantic_type(self, semantic_type):
 
877
        """Set the semantic type of the space time dataset"""
 
878
        self.D["semantic_type"] = semantic_type
 
879
 
 
880
    def set_mtime(self, mtime=None):
 
881
        """Set the modification time of the space time dataset, if nothing set
 
882
           the current time is used
 
883
        """
 
884
        if mtime is None:
 
885
            self.D["modification_time"] = datetime.now()
 
886
        else:
 
887
            self.D["modification_time"] = mtime
 
888
 
 
889
    def get_semantic_type(self):
 
890
        """Get the semantic type of the space time dataset
 
891
           :return: None if not found
 
892
        """
 
893
        if "semantic_type" in self.D:
 
894
            return self.D["semantic_type"]
 
895
        else:
 
896
            return None
 
897
 
 
898
    def get_mtime(self):
 
899
        """Get the modification time of the space time dataset, datatype is
 
900
           datetime
 
901
 
 
902
           :return: None if not found
 
903
        """
 
904
        if self.D.has_key("modification_time"):
 
905
            return self.D["modification_time"]
 
906
        else:
 
907
            return None
 
908
 
 
909
    semantic_type = property(fget=get_semantic_type, fset=set_semantic_type)
 
910
 
 
911
    def print_info(self):
 
912
        """Print information about this class in human readable style"""
 
913
        DatasetBase.print_info(self)
 
914
        #      0123456789012345678901234567890
 
915
        print " | Modification time:.......... " + str(self.get_mtime())
 
916
        print " | Semantic type:.............. " + str(
 
917
            self.get_semantic_type())
 
918
 
 
919
    def print_shell_info(self):
 
920
        """Print information about this class in shell style"""
 
921
        DatasetBase.print_shell_info(self)
 
922
        print "modification_time=" + str(self.get_mtime())
 
923
        print "semantic_type=" + str(self.get_semantic_type())
 
924
 
 
925
###############################################################################
 
926
 
 
927
 
 
928
class STRDSBase(STDSBase):
 
929
    """Space time raster dataset base information class"""
 
930
    def __init__(self, ident=None, name=None, mapset=None,
 
931
                 semantic_type=None, creator=None, ctime=None,
 
932
                 ttype=None):
 
933
        STDSBase.__init__(self, "strds_base", ident, name, mapset,
 
934
                          semantic_type, creator, ctime,
 
935
                          ttype)
 
936
 
 
937
 
 
938
class STR3DSBase(STDSBase):
 
939
    """Space time 3D raster dataset base information class"""
 
940
    def __init__(self, ident=None, name=None, mapset=None,
 
941
                 semantic_type=None, creator=None, ctime=None,
 
942
                 ttype=None):
 
943
        STDSBase.__init__(self, "str3ds_base", ident, name, mapset,
 
944
                          semantic_type, creator, ctime,
 
945
                          ttype)
 
946
 
 
947
 
 
948
class STVDSBase(STDSBase):
 
949
    """Space time vector dataset base information class"""
 
950
    def __init__(self, ident=None, name=None, mapset=None,
 
951
                 semantic_type=None, creator=None, ctime=None,
 
952
                 ttype=None):
 
953
        STDSBase.__init__(self, "stvds_base", ident, name, mapset,
 
954
                          semantic_type, creator, ctime,
 
955
                          ttype)
 
956
 
 
957
###############################################################################
 
958
 
 
959
 
 
960
class AbstractSTDSRegister(SQLDatabaseInterface):
 
961
    """This is the base class for all maps to store the space time datasets
 
962
       as comma separated string in which they are registered
 
963
 
 
964
        Usage:
 
965
 
 
966
        .. code-block:: python
 
967
 
 
968
            >>> init()
 
969
            >>> t = AbstractSTDSRegister("raster", "soil@PERMANENT", "A@P,B@P,C@P")
 
970
            >>> t.id
 
971
            'soil@PERMANENT'
 
972
            >>> t.registered_stds
 
973
            'A@P,B@P,C@P'
 
974
 
 
975
    """
 
976
 
 
977
    def __init__(self, table=None, ident=None, registered_stds=None):
 
978
        """Constructor
 
979
 
 
980
            :param table: The name of the temporal database table
 
981
                          that should be used to store the values
 
982
            :param ident: The unique identifier must be a combination of
 
983
                          the dataset name, layer name and the mapset
 
984
                          "name@mapset" or "name:layer@mapset"
 
985
                          used as as primary key in the temporal database
 
986
            :param stds: A comma separted list of space time dataset ids
 
987
        """
 
988
 
 
989
        SQLDatabaseInterface.__init__(self, table, ident)
 
990
 
 
991
        self.set_id(ident)
 
992
        self.set_registered_stds(registered_stds)
 
993
 
 
994
    def set_id(self, ident):
 
995
        """Convenient method to set the unique identifier (primary key)
 
996
 
 
997
           :param ident: The unique identifier must be a combination
 
998
                         of the dataset name, layer name and the mapset
 
999
                         "name@mapset" or "name:layer@mapset"
 
1000
        """
 
1001
        self.ident = ident
 
1002
        self.D["id"] = ident
 
1003
 
 
1004
    def set_registered_stds(self, registered_stds):
 
1005
        """Get the comma separated list of space time datasets ids
 
1006
           in which this map is registered
 
1007
 
 
1008
           :param registered_stds: A comma separated list of space time
 
1009
                                   dataset ids in which this map is registered
 
1010
        """
 
1011
        self.D["registered_stds"] = registered_stds
 
1012
 
 
1013
    def get_id(self):
 
1014
        """Convenient method to get the unique identifier (primary key)
 
1015
 
 
1016
           :return: None if not found
 
1017
        """
 
1018
        if "id" in self.D:
 
1019
            return self.D["id"]
 
1020
        else:
 
1021
            return None
 
1022
 
 
1023
    def get_registered_stds(self):
 
1024
        """Get the comma separated list of space time datasets ids
 
1025
           in which this map is registered
 
1026
 
 
1027
           :return: None if not found
 
1028
        """
 
1029
        if "registered_stds" in self.D:
 
1030
            return self.D["registered_stds"]
 
1031
        else:
 
1032
            return None
 
1033
 
 
1034
    # Properties of this class
 
1035
    id = property(fget=get_id, fset=set_id)
 
1036
    registered_stds = property(fget=get_registered_stds,
 
1037
                               fset=set_registered_stds)
 
1038
 
 
1039
###############################################################################
 
1040
 
 
1041
 
 
1042
class RasterSTDSRegister(AbstractSTDSRegister):
 
1043
    """Time stamped raster map base information class"""
 
1044
    def __init__(self, ident=None, registered_stds=None):
 
1045
        AbstractSTDSRegister.__init__(self, "raster_stds_register", ident,
 
1046
                                      registered_stds)
 
1047
 
 
1048
 
 
1049
class Raster3DSTDSRegister(AbstractSTDSRegister):
 
1050
    """Time stamped 3D raster map base information class"""
 
1051
    def __init__(self, ident=None, registered_stds=None):
 
1052
        AbstractSTDSRegister.__init__(self, "raster3d_stds_register", ident,
 
1053
                                      registered_stds)
 
1054
 
 
1055
 
 
1056
class VectorSTDSRegister(AbstractSTDSRegister):
 
1057
    """Time stamped vector map base information class"""
 
1058
    def __init__(self, ident=None, registered_stds=None):
 
1059
        AbstractSTDSRegister.__init__(self, "vector_stds_register", ident,
 
1060
                                      registered_stds)
 
1061
 
 
1062
###############################################################################
 
1063
 
 
1064
if __name__ == "__main__":
 
1065
    import doctest
 
1066
    doctest.testmod()