~ubuntu-branches/ubuntu/vivid/grass/vivid-proposed

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Bas Couwenberg
  • Date: 2015-02-20 23:12:08 UTC
  • mfrom: (8.2.6 experimental)
  • Revision ID: package-import@ubuntu.com-20150220231208-1u6qvqm84v430b10
Tags: 7.0.0-1~exp1
* New upstream release.
* Update python-ctypes-ternary.patch to use if/else instead of and/or.
* Drop check4dev patch, rely on upstream check.
* Add build dependency on libpq-dev to grass-dev for libpq-fe.h.
* Drop patches applied upstream, refresh remaining patches.
* Update symlinks for images switched from jpg to png.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
"""
 
3
Fast and exit-safe interface to GRASS C-library functions
 
4
using ctypes and multiprocessing
 
5
 
 
6
(C) 2013 by the GRASS Development Team
 
7
This program is free software under the GNU General Public
 
8
License (>=v2). Read the file COPYING that comes with GRASS
 
9
for details.
 
10
 
 
11
:authors: Soeren Gebbert
 
12
"""
 
13
 
 
14
import sys
 
15
from multiprocessing import Process, Lock, Pipe
 
16
import logging
 
17
from ctypes import *
 
18
from core import *
 
19
import grass.lib.gis as libgis
 
20
import grass.lib.raster as libraster
 
21
import grass.lib.vector as libvector
 
22
import grass.lib.date as libdate
 
23
import grass.lib.raster3d as libraster3d
 
24
import grass.lib.temporal as libtgis
 
25
 
 
26
###############################################################################
 
27
 
 
28
 
 
29
class RPCDefs(object):
 
30
    # Function identifier and index
 
31
    STOP = 0
 
32
    HAS_TIMESTAMP = 1
 
33
    WRITE_TIMESTAMP = 2
 
34
    READ_TIMESTAMP = 3
 
35
    REMOVE_TIMESTAMP = 4
 
36
    READ_MAP_INFO = 5
 
37
    MAP_EXISTS = 6
 
38
    READ_MAP_INFO = 7
 
39
    AVAILABLE_MAPSETS = 8
 
40
    GET_DRIVER_NAME = 9
 
41
    GET_DATABASE_NAME = 10
 
42
    G_MAPSET = 11
 
43
    G_LOCATION = 12
 
44
    G_GISDBASE = 13
 
45
    G_FATAL_ERROR = 14
 
46
 
 
47
    TYPE_RASTER = 0
 
48
    TYPE_RASTER3D = 1
 
49
    TYPE_VECTOR = 2
 
50
 
 
51
###############################################################################
 
52
 
 
53
 
 
54
def _fatal_error(lock, conn, data):
 
55
    """Calls G_fatal_error()"""
 
56
    libgis.G_fatal_error("Fatal Error in C library server")
 
57
 
 
58
 
 
59
def _get_mapset(lock, conn, data):
 
60
    """Return the current mapset
 
61
 
 
62
       :param lock: A multiprocessing.Lock instance
 
63
       :param conn: A multiprocessing.Pipe instance used to send True or False
 
64
       :param data: The mapset as list entry 1 [function_id]
 
65
 
 
66
       :returns: Name of the current mapset
 
67
    """
 
68
    mapset = libgis.G_mapset()
 
69
    conn.send(mapset)
 
70
 
 
71
 
 
72
def _get_location(lock, conn, data):
 
73
    """Return the current location
 
74
 
 
75
       :param lock: A multiprocessing.Lock instance
 
76
       :param conn: A multiprocessing.Pipe instance used to send True or False
 
77
       :param data: The mapset as list entry 1 [function_id]
 
78
 
 
79
       :returns: Name of the location
 
80
    """
 
81
    location = libgis.G_location()
 
82
    conn.send(location)
 
83
 
 
84
 
 
85
def _get_gisdbase(lock, conn, data):
 
86
    """Return the current gisdatabase
 
87
 
 
88
       :param lock: A multiprocessing.Lock instance
 
89
       :param conn: A multiprocessing.Pipe instance used to send True or False
 
90
       :param data: The mapset as list entry 1 [function_id]
 
91
 
 
92
       :returns: Name of the gisdatabase
 
93
    """
 
94
    gisdbase = libgis.G_gisdbase()
 
95
    conn.send(gisdbase)
 
96
 
 
97
 
 
98
def _get_driver_name(lock, conn, data):
 
99
    """Return the temporal database driver of a specific mapset
 
100
 
 
101
       :param lock: A multiprocessing.Lock instance
 
102
       :param conn: A multiprocessing.Pipe instance used to send True or False
 
103
       :param data: The mapset as list entry 1 [function_id, mapset]
 
104
 
 
105
       :returns: Name of the driver or None if no temporal database present
 
106
    """
 
107
    mapset = data[1]
 
108
    if not mapset:
 
109
        mapset = libgis.G_mapset()
 
110
 
 
111
    drstring = libtgis.tgis_get_mapset_driver_name(mapset)
 
112
    conn.send(drstring)
 
113
 
 
114
###############################################################################
 
115
 
 
116
 
 
117
def _get_database_name(lock, conn, data):
 
118
    """Return the temporal database name of a specific mapset
 
119
 
 
120
       :param lock: A multiprocessing.Lock instance
 
121
       :param conn: A multiprocessing.Pipe instance used to send True or False
 
122
       :param data: The mapset as list entry 1 [function_id, mapset]
 
123
 
 
124
       :returns: Name of the database or None if no temporal database present
 
125
    """
 
126
    mapset = data[1]
 
127
    if not mapset:
 
128
        mapset = libgis.G_mapset()
 
129
    dbstring = libtgis.tgis_get_mapset_database_name(mapset)
 
130
 
 
131
    if dbstring:
 
132
        # We substitute GRASS variables if they are located in the database string
 
133
        # This behavior is in conjunction with db.connect
 
134
        dbstring = dbstring.replace("$GISDBASE", libgis.G_gisdbase())
 
135
        dbstring = dbstring.replace("$LOCATION_NAME", libgis.G_location())
 
136
        dbstring = dbstring.replace("$MAPSET", libgis.G_mapset())
 
137
    conn.send(dbstring)
 
138
 
 
139
###############################################################################
 
140
 
 
141
 
 
142
def _available_mapsets(lock, conn, data):
 
143
    """Return all available mapsets the user can access as a list of strings
 
144
 
 
145
       :param lock: A multiprocessing.Lock instance
 
146
       :param conn: A multiprocessing.Pipe instance used to send True or False
 
147
       :param data: The list of data entries [function_id]
 
148
 
 
149
       :returns: Names of available mapsets as list of strings
 
150
    """
 
151
 
 
152
    mapsets = libgis.G_get_available_mapsets()
 
153
 
 
154
    count = 0
 
155
    mapset_list = []
 
156
    while mapsets[count]:
 
157
        char_list = ""
 
158
        mapset = mapsets[count]
 
159
        if libgis.G_mapset_permissions(mapset) > 0:
 
160
            count += 1
 
161
            c = 0
 
162
            while mapset[c] != "\x00":
 
163
                char_list += mapset[c]
 
164
                c += 1
 
165
 
 
166
        mapset_list.append(char_list)
 
167
 
 
168
    # We need to sort the mapset list, but the first one should be
 
169
    # the current mapset
 
170
    current_mapset = libgis.G_mapset()
 
171
    mapset_list.remove(current_mapset)
 
172
    mapset_list.sort()
 
173
    mapset_list.reverse()
 
174
    mapset_list.append(current_mapset)
 
175
    mapset_list.reverse()
 
176
 
 
177
    conn.send(mapset_list)
 
178
 
 
179
 
 
180
def _has_timestamp(lock, conn, data):
 
181
    """Check if the file based GRASS timestamp is present and send
 
182
       True or False using the provided pipe.
 
183
 
 
184
       :param lock: A multiprocessing.Lock instance
 
185
       :param conn: A multiprocessing.Pipe instance used to send True or False
 
186
       :param data: The list of data entries [function_id, maptype, name,
 
187
                    mapset, layer]
 
188
 
 
189
    """
 
190
    maptype = data[1]
 
191
    name = data[2]
 
192
    mapset = data[3]
 
193
    layer = data[4]
 
194
    check = False
 
195
    if maptype == RPCDefs.TYPE_RASTER:
 
196
        if libgis.G_has_raster_timestamp(name, mapset) == 1:
 
197
            check = True
 
198
    elif maptype == RPCDefs.TYPE_VECTOR:
 
199
        if libgis.G_has_vector_timestamp(name, layer, mapset) == 1:
 
200
            check = True
 
201
    elif maptype == RPCDefs.TYPE_RASTER3D:
 
202
        if libgis.G_has_raster3d_timestamp(name, mapset) == 1:
 
203
            check = True
 
204
    conn.send(check)
 
205
 
 
206
###############################################################################
 
207
 
 
208
 
 
209
def _read_timestamp(lock, conn, data):
 
210
    """Read the file based GRASS timestamp and send
 
211
       the result using the provided pipe.
 
212
 
 
213
       The tuple to be send via pipe: (return value of G_read_*_timestamp,
 
214
       timestamps).
 
215
 
 
216
       Please have a look at the documentation of G_read_raster_timestamp,
 
217
       G_read_vector_timestamp and G_read_raster3d_timestamp for the return
 
218
       values description.
 
219
 
 
220
       The timestamps to be send are tuples of values:
 
221
 
 
222
           - relative time (start, end, unit), start and end are of type
 
223
             integer, unit is of type string.
 
224
           - absolute time (start, end), start and end are of type datetime
 
225
 
 
226
       The end time may be None in case of a time instance.
 
227
 
 
228
       :param lock: A multiprocessing.Lock instance
 
229
       :param conn: A multiprocessing.Pipe instance used to send the result
 
230
       :param data: The list of data entries [function_id, maptype, name,
 
231
                    mapset, layer]
 
232
 
 
233
    """
 
234
    maptype = data[1]
 
235
    name = data[2]
 
236
    mapset = data[3]
 
237
    layer = data[4]
 
238
    check = False
 
239
    ts = libgis.TimeStamp()
 
240
    if maptype == RPCDefs.TYPE_RASTER:
 
241
        check = libgis.G_read_raster_timestamp(name, mapset, byref(ts))
 
242
    elif maptype == RPCDefs.TYPE_VECTOR:
 
243
        check = libgis.G_read_vector_timestamp(name, layer, mapset, byref(ts))
 
244
    elif maptype == RPCDefs.TYPE_RASTER3D:
 
245
        check = libgis.G_read_raster3d_timestamp(name, mapset, byref(ts))
 
246
 
 
247
    dates = _convert_timestamp_from_grass(ts)
 
248
    conn.send((check, dates))
 
249
 
 
250
###############################################################################
 
251
 
 
252
 
 
253
def _write_timestamp(lock, conn, data):
 
254
    """Write the file based GRASS timestamp
 
255
       the return values of the called C-functions using the provided pipe.
 
256
 
 
257
       The value to be send via pipe is the return value of G_write_*_timestamp.
 
258
 
 
259
       Please have a look at the documentation of G_write_raster_timestamp,
 
260
       G_write_vector_timestamp and G_write_raster3d_timestamp for the return
 
261
       values description.
 
262
 
 
263
       :param lock: A multiprocessing.Lock instance
 
264
       :param conn: A multiprocessing.Pipe instance used to send True or False
 
265
       :param data: The list of data entries [function_id, maptype, name,
 
266
                    mapset, layer, timestring]
 
267
    """
 
268
    maptype = data[1]
 
269
    name = data[2]
 
270
    mapset = data[3]
 
271
    layer = data[4]
 
272
    timestring = data[5]
 
273
    check = -3
 
274
    ts = libgis.TimeStamp()
 
275
    check = libgis.G_scan_timestamp(byref(ts), timestring)
 
276
 
 
277
    if check != 1:
 
278
        logging.error("Unable to convert the timestamp: " + timestring)
 
279
        return -2
 
280
 
 
281
    if maptype == RPCDefs.TYPE_RASTER:
 
282
        check = libgis.G_write_raster_timestamp(name, byref(ts))
 
283
    elif maptype == RPCDefs.TYPE_VECTOR:
 
284
        check = libgis.G_write_vector_timestamp(name, layer, byref(ts))
 
285
    elif maptype == RPCDefs.TYPE_RASTER3D:
 
286
        check = libgis.G_write_raster3d_timestamp(name, byref(ts))
 
287
 
 
288
    conn.send(check)
 
289
 
 
290
###############################################################################
 
291
 
 
292
 
 
293
def _remove_timestamp(lock, conn, data):
 
294
    """Remove the file based GRASS timestamp
 
295
       the return values of the called C-functions using the provided pipe.
 
296
 
 
297
       The value to be send via pipe is the return value of G_remove_*_timestamp.
 
298
 
 
299
       Please have a look at the documentation of G_remove_raster_timestamp,
 
300
       G_remove_vector_timestamp and G_remove_raster3d_timestamp for the return
 
301
       values description.
 
302
 
 
303
       :param lock: A multiprocessing.Lock instance
 
304
       :param conn: A multiprocessing.Pipe instance used to send True or False
 
305
       :param data: The list of data entries [function_id, maptype, name,
 
306
                    mapset, layer]
 
307
 
 
308
    """
 
309
    maptype = data[1]
 
310
    name = data[2]
 
311
    mapset = data[3]
 
312
    layer = data[4]
 
313
    check = False
 
314
    if maptype == RPCDefs.TYPE_RASTER:
 
315
        check = libgis.G_remove_raster_timestamp(name, mapset)
 
316
    elif maptype == RPCDefs.TYPE_VECTOR:
 
317
        check = libgis.G_remove_vector_timestamp(name, layer, mapset)
 
318
    elif maptype == RPCDefs.TYPE_RASTER3D:
 
319
        check = libgis.G_remove_raster3d_timestamp(name, mapset)
 
320
 
 
321
    conn.send(check)
 
322
 
 
323
###############################################################################
 
324
 
 
325
 
 
326
def _map_exists(lock, conn, data):
 
327
    """Check if a map exists in the spatial database
 
328
 
 
329
       The value to be send via pipe is True in case the map exists and False
 
330
       if not.
 
331
 
 
332
       :param lock: A multiprocessing.Lock instance
 
333
       :param conn: A multiprocessing.Pipe instance used to send True or False
 
334
       :param data: The list of data entries [function_id, maptype, name, mapset]
 
335
 
 
336
    """
 
337
    maptype = data[1]
 
338
    name = data[2]
 
339
    mapset = data[3]
 
340
    check = False
 
341
    if maptype == RPCDefs.TYPE_RASTER:
 
342
        mapset = libgis.G_find_raster(name, mapset)
 
343
    elif maptype == RPCDefs.TYPE_VECTOR:
 
344
        mapset = libgis.G_find_vector(name, mapset)
 
345
    elif maptype == RPCDefs.TYPE_RASTER3D:
 
346
        mapset = libgis.G_find_raster3d(name, mapset)
 
347
 
 
348
    if mapset:
 
349
        check = True
 
350
 
 
351
    conn.send(check)
 
352
 
 
353
###############################################################################
 
354
 
 
355
 
 
356
def _read_map_info(lock, conn, data):
 
357
    """Read map specific metadata from the spatial database using C-library
 
358
       functions
 
359
 
 
360
       :param lock: A multiprocessing.Lock instance
 
361
       :param conn: A multiprocessing.Pipe instance used to send True or False
 
362
       :param data: The list of data entries [function_id, maptype, name, mapset]
 
363
    """
 
364
    maptype = data[1]
 
365
    name = data[2]
 
366
    mapset = data[3]
 
367
    if maptype == RPCDefs.TYPE_RASTER:
 
368
        kvp = _read_raster_info(name, mapset)
 
369
    elif maptype == RPCDefs.TYPE_VECTOR:
 
370
        kvp = _read_vector_info(name, mapset)
 
371
    elif maptype == RPCDefs.TYPE_RASTER3D:
 
372
        kvp = _read_raster3d_info(name, mapset)
 
373
 
 
374
    conn.send(kvp)
 
375
 
 
376
###############################################################################
 
377
 
 
378
 
 
379
def _read_raster_info(name, mapset):
 
380
    """Read the raster map info from the file system and store the content
 
381
       into a dictionary
 
382
 
 
383
       This method uses the ctypes interface to the gis and raster libraries
 
384
       to read the map metadata information
 
385
 
 
386
       :param name: The name of the map
 
387
       :param mapset: The mapset of the map
 
388
       :returns: The key value pairs of the map specific metadata, or None in
 
389
                 case of an error
 
390
    """
 
391
 
 
392
    kvp = {}
 
393
 
 
394
    if not libgis.G_find_raster(name, mapset):
 
395
        return None
 
396
 
 
397
    # Read the region information
 
398
    region = libgis.Cell_head()
 
399
    libraster.Rast_get_cellhd(name, mapset, byref(region))
 
400
 
 
401
    kvp["north"] = region.north
 
402
    kvp["south"] = region.south
 
403
    kvp["east"] = region.east
 
404
    kvp["west"] = region.west
 
405
    kvp["nsres"] = region.ns_res
 
406
    kvp["ewres"] = region.ew_res
 
407
    kvp["rows"] = region.cols
 
408
    kvp["cols"] = region.rows
 
409
 
 
410
    maptype = libraster.Rast_map_type(name, mapset)
 
411
 
 
412
    if maptype == libraster.DCELL_TYPE:
 
413
        kvp["datatype"] = "DCELL"
 
414
    elif maptype == libraster.FCELL_TYPE:
 
415
        kvp["datatype"] = "FCELL"
 
416
    elif maptype == libraster.CELL_TYPE:
 
417
        kvp["datatype"] = "CELL"
 
418
 
 
419
    # Read range
 
420
    if libraster.Rast_map_is_fp(name, mapset):
 
421
        range = libraster.FPRange()
 
422
        libraster.Rast_init_fp_range(byref(range))
 
423
        ret = libraster.Rast_read_fp_range(name, mapset, byref(range))
 
424
        if ret < 0:
 
425
            logging.error(_("Unable to read range file"))
 
426
            return None
 
427
        if ret == 2:
 
428
            kvp["min"] = None
 
429
            kvp["max"] = None
 
430
        else:
 
431
            min = libgis.DCELL()
 
432
            max = libgis.DCELL()
 
433
            libraster.Rast_get_fp_range_min_max(
 
434
                byref(range), byref(min), byref(max))
 
435
            kvp["min"] = min.value
 
436
            kvp["max"] = max.value
 
437
    else:
 
438
        range = libraster.Range()
 
439
        libraster.Rast_init_range(byref(range))
 
440
        ret = libraster.Rast_read_range(name, mapset, byref(range))
 
441
        if ret < 0:
 
442
            logging.error(_("Unable to read range file"))
 
443
            return None
 
444
        if ret == 2:
 
445
            kvp["min"] = None
 
446
            kvp["max"] = None
 
447
        else:
 
448
            min = libgis.CELL()
 
449
            max = libgis.CELL()
 
450
            libraster.Rast_get_range_min_max(
 
451
                byref(range), byref(min), byref(max))
 
452
            kvp["min"] = min.value
 
453
            kvp["max"] = max.value
 
454
 
 
455
    return kvp
 
456
 
 
457
###############################################################################
 
458
 
 
459
 
 
460
def _read_raster3d_info(name, mapset):
 
461
    """Read the 3D raster map info from the file system and store the content
 
462
       into a dictionary
 
463
 
 
464
       This method uses the ctypes interface to the gis and raster3d libraries
 
465
       to read the map metadata information
 
466
 
 
467
       :param name: The name of the map
 
468
       :param mapset: The mapset of the map
 
469
       :returns: The key value pairs of the map specific metadata, or None in
 
470
                 case of an error
 
471
    """
 
472
 
 
473
    kvp = {}
 
474
 
 
475
    if not libgis.G_find_raster3d(name, mapset):
 
476
        return None
 
477
 
 
478
    # Read the region information
 
479
    region = libraster3d.RASTER3D_Region()
 
480
    libraster3d.Rast3d_read_region_map(name, mapset, byref(region))
 
481
 
 
482
    kvp["north"] = region.north
 
483
    kvp["south"] = region.south
 
484
    kvp["east"] = region.east
 
485
    kvp["west"] = region.west
 
486
    kvp["nsres"] = region.ns_res
 
487
    kvp["ewres"] = region.ew_res
 
488
    kvp["tbres"] = region.tb_res
 
489
    kvp["rows"] = region.cols
 
490
    kvp["cols"] = region.rows
 
491
    kvp["depths"] = region.depths
 
492
    kvp["top"] = region.top
 
493
    kvp["bottom"] = region.bottom
 
494
 
 
495
    # We need to open the map, this function returns a void pointer
 
496
    # but we may need the correct type which is RASTER3D_Map, hence
 
497
    # the casting
 
498
    g3map = cast(libraster3d.Rast3d_open_cell_old(name, mapset,
 
499
                 libraster3d.RASTER3D_DEFAULT_WINDOW,
 
500
                 libraster3d.RASTER3D_TILE_SAME_AS_FILE,
 
501
                 libraster3d.RASTER3D_NO_CACHE),
 
502
                 POINTER(libraster3d.RASTER3D_Map))
 
503
 
 
504
    if not g3map:
 
505
        logging.error(_("Unable to open 3D raster map <%s>" % (name)))
 
506
        return None
 
507
 
 
508
    maptype = libraster3d.Rast3d_file_type_map(g3map)
 
509
 
 
510
    if maptype == libraster.DCELL_TYPE:
 
511
        kvp["datatype"] = "DCELL"
 
512
    elif maptype == libraster.FCELL_TYPE:
 
513
        kvp["datatype"] = "FCELL"
 
514
 
 
515
    # Read range
 
516
    min = libgis.DCELL()
 
517
    max = libgis.DCELL()
 
518
    ret = libraster3d.Rast3d_range_load(g3map)
 
519
    if not ret:
 
520
        logging.error(_("Unable to load range of 3D raster map <%s>" %
 
521
                      (name)))
 
522
        return None
 
523
    libraster3d.Rast3d_range_min_max(g3map, byref(min), byref(max))
 
524
 
 
525
    if min.value != min.value:
 
526
        kvp["min"] = None
 
527
    else:
 
528
        kvp["min"] = float(min.value)
 
529
    if max.value != max.value:
 
530
        kvp["max"] = None
 
531
    else:
 
532
        kvp["max"] = float(max.value)
 
533
 
 
534
    if not libraster3d.Rast3d_close(g3map):
 
535
        logging.error(_("Unable to close 3D raster map <%s>" % (name)))
 
536
        return None
 
537
 
 
538
    return kvp
 
539
 
 
540
###############################################################################
 
541
 
 
542
 
 
543
def _read_vector_info(name, mapset):
 
544
    """Read the vector map info from the file system and store the content
 
545
       into a dictionary
 
546
 
 
547
       This method uses the ctypes interface to the vector libraries
 
548
       to read the map metadata information
 
549
 
 
550
       :param name: The name of the map
 
551
       :param mapset: The mapset of the map
 
552
       :returns: The key value pairs of the map specific metadata, or None in
 
553
                 case of an error
 
554
    """
 
555
 
 
556
    kvp = {}
 
557
 
 
558
    if not libgis.G_find_vector(name, mapset):
 
559
        return None
 
560
 
 
561
    # The vector map structure
 
562
    Map = libvector.Map_info()
 
563
 
 
564
    # We open the maps always in topology mode first
 
565
    libvector.Vect_set_open_level(2)
 
566
    with_topo = True
 
567
 
 
568
    # Code lend from v.info main.c
 
569
    if libvector.Vect_open_old_head2(byref(Map), name, mapset, "1") < 2:
 
570
        # force level 1, open fully
 
571
        # NOTE: number of points, lines, boundaries, centroids,
 
572
        # faces, kernels is still available
 
573
        libvector.Vect_set_open_level(1)  # no topology
 
574
        with_topo = False
 
575
        if libvector.Vect_open_old2(byref(Map), name, mapset, "1") < 1:
 
576
            logging.error(_("Unable to open vector map <%s>" %
 
577
                          (libvector.Vect_get_full_name(byref(Map)))))
 
578
            return None
 
579
 
 
580
    # Release the vector spatial index memory when closed
 
581
    libvector.Vect_set_release_support(byref(Map))
 
582
 
 
583
    # Read the extent information
 
584
    bbox = libvector.bound_box()
 
585
    libvector.Vect_get_map_box(byref(Map), byref(bbox))
 
586
 
 
587
    kvp["north"] = bbox.N
 
588
    kvp["south"] = bbox.S
 
589
    kvp["east"] = bbox.E
 
590
    kvp["west"] = bbox.W
 
591
    kvp["top"] = bbox.T
 
592
    kvp["bottom"] = bbox.B
 
593
 
 
594
    kvp["map3d"] = bool(libvector.Vect_is_3d(byref(Map)))
 
595
 
 
596
    # Read number of features
 
597
    if with_topo:
 
598
        kvp["points"] = libvector.Vect_get_num_primitives(
 
599
            byref(Map), libvector.GV_POINT)
 
600
        kvp["lines"] = libvector.Vect_get_num_primitives(
 
601
            byref(Map), libvector.GV_LINE)
 
602
        kvp["boundaries"] = libvector.Vect_get_num_primitives(
 
603
            byref(Map), libvector.GV_BOUNDARY)
 
604
        kvp["centroids"] = libvector.Vect_get_num_primitives(
 
605
            byref(Map), libvector.GV_CENTROID)
 
606
        kvp["faces"] = libvector.Vect_get_num_primitives(
 
607
            byref(Map), libvector.GV_FACE)
 
608
        kvp["kernels"] = libvector.Vect_get_num_primitives(
 
609
            byref(Map), libvector.GV_KERNEL)
 
610
 
 
611
        # Summarize the primitives
 
612
        kvp["primitives"] = kvp["points"] + kvp["lines"] + \
 
613
            kvp["boundaries"] + kvp["centroids"]
 
614
        if kvp["map3d"]:
 
615
            kvp["primitives"] += kvp["faces"] + kvp["kernels"]
 
616
 
 
617
        # Read topology information
 
618
        kvp["nodes"] = libvector.Vect_get_num_nodes(byref(Map))
 
619
        kvp["areas"] = libvector.Vect_get_num_areas(byref(Map))
 
620
        kvp["islands"] = libvector.Vect_get_num_islands(byref(Map))
 
621
        kvp["holes"] = libvector.Vect_get_num_holes(byref(Map))
 
622
        kvp["volumes"] = libvector.Vect_get_num_primitives(
 
623
            byref(Map), libvector.GV_VOLUME)
 
624
    else:
 
625
        kvp["points"] = None
 
626
        kvp["lines"] = None
 
627
        kvp["boundaries"] = None
 
628
        kvp["centroids"] = None
 
629
        kvp["faces"] = None
 
630
        kvp["kernels"] = None
 
631
        kvp["primitives"] = None
 
632
        kvp["nodes"] = None
 
633
        kvp["areas"] = None
 
634
        kvp["islands"] = None
 
635
        kvp["holes"] = None
 
636
        kvp["volumes"] = None
 
637
 
 
638
    libvector.Vect_close(byref(Map))
 
639
 
 
640
    return kvp
 
641
 
 
642
###############################################################################
 
643
 
 
644
 
 
645
def _convert_timestamp_from_grass(ts):
 
646
    """Convert a GRASS file based timestamp into the temporal framework
 
647
       format datetime or integer.
 
648
 
 
649
       A tuple of two datetime objects (start, end) is returned in case of
 
650
       absolute time.
 
651
       In case of relative time a tuple with start time, end time and the
 
652
       relative unit (start, end, unit) will be returned.
 
653
 
 
654
       Note:
 
655
       The end time will be set to None in case of a time instance.
 
656
 
 
657
       :param ts grass.lib.gis.TimeStamp object created by G_read_*_timestamp
 
658
    """
 
659
 
 
660
    dt1 = libgis.DateTime()
 
661
    dt2 = libgis.DateTime()
 
662
    count = c_int()
 
663
 
 
664
    libgis.G_get_timestamps(byref(ts),
 
665
                            byref(dt1),
 
666
                            byref(dt2),
 
667
                            byref(count))
 
668
 
 
669
    if dt1.mode == libdate.DATETIME_ABSOLUTE:
 
670
        pdt1 = None
 
671
        pdt2 = None
 
672
        if count.value >= 1:
 
673
            pdt1 = datetime(int(dt1.year), int(dt1.month), int(dt1.day),
 
674
                            int(dt1.hour), int(dt1.minute),
 
675
                            int(dt1.second))
 
676
        if count.value == 2:
 
677
            pdt2 = datetime(int(dt2.year), int(dt2.month), int(dt2.day),
 
678
                            int(dt2.hour), int(dt2.minute),
 
679
                            int(dt2.second))
 
680
 
 
681
        # ATTENTION: We ignore the time zone
 
682
        # TODO: Write time zone support
 
683
        return (pdt1, pdt2)
 
684
    else:
 
685
        unit = None
 
686
        start = None
 
687
        end = None
 
688
        if count.value >= 1:
 
689
            if dt1.year > 0:
 
690
                unit = "years"
 
691
                start = dt1.year
 
692
            elif dt1.month > 0:
 
693
                unit = "months"
 
694
                start = dt1.month
 
695
            elif dt1.day > 0:
 
696
                unit = "days"
 
697
                start = dt1.day
 
698
            elif dt1.hour > 0:
 
699
                unit = "hours"
 
700
                start = dt1.hour
 
701
            elif dt1.minute > 0:
 
702
                unit = "minutes"
 
703
                start = dt1.minute
 
704
            elif dt1.second > 0:
 
705
                unit = "seconds"
 
706
                start = dt1.second
 
707
        if count.value == 2:
 
708
            if dt2.year > 0:
 
709
                end = dt2.year
 
710
            elif dt2.month > 0:
 
711
                end = dt2.month
 
712
            elif dt2.day > 0:
 
713
                end = dt2.day
 
714
            elif dt2.hour > 0:
 
715
                end = dt2.hour
 
716
            elif dt2.minute > 0:
 
717
                end = dt2.minute
 
718
            elif dt2.second > 0:
 
719
                end = dt2.second
 
720
        return (start, end, unit)
 
721
 
 
722
###############################################################################
 
723
 
 
724
 
 
725
def _stop(lock, conn, data):
 
726
    libgis.G_debug(1, "Stop C-interface server")
 
727
    conn.close()
 
728
    lock.release()
 
729
    sys.exit()
 
730
 
 
731
###############################################################################
 
732
# Global server connection
 
733
server_connection = None
 
734
server_lock = None
 
735
 
 
736
 
 
737
def c_library_server(lock, conn):
 
738
    """The GRASS C-libraries server function designed to be a target for
 
739
       multiprocessing.Process
 
740
 
 
741
       :param lock: A multiprocessing.Lock
 
742
       :param conn: A multiprocessing.Pipe
 
743
    """
 
744
    # Crerate the function array
 
745
    functions = [0]*15
 
746
    functions[RPCDefs.STOP] = _stop
 
747
    functions[RPCDefs.HAS_TIMESTAMP] = _has_timestamp
 
748
    functions[RPCDefs.WRITE_TIMESTAMP] = _write_timestamp
 
749
    functions[RPCDefs.READ_TIMESTAMP] = _read_timestamp
 
750
    functions[RPCDefs.REMOVE_TIMESTAMP] = _remove_timestamp
 
751
    functions[RPCDefs.READ_MAP_INFO] = _read_map_info
 
752
    functions[RPCDefs.MAP_EXISTS] = _map_exists
 
753
    functions[RPCDefs.AVAILABLE_MAPSETS] = _available_mapsets
 
754
    functions[RPCDefs.GET_DRIVER_NAME] = _get_driver_name
 
755
    functions[RPCDefs.GET_DATABASE_NAME] = _get_database_name
 
756
    functions[RPCDefs.G_MAPSET] = _get_mapset
 
757
    functions[RPCDefs.G_LOCATION] = _get_location
 
758
    functions[RPCDefs.G_GISDBASE] = _get_gisdbase
 
759
    functions[RPCDefs.G_FATAL_ERROR] = _fatal_error
 
760
 
 
761
    libgis.G_gisinit("c_library_server")
 
762
    libgis.G_debug(1, "Start C-interface server")
 
763
 
 
764
    while True:
 
765
        # Avoid busy waiting
 
766
        conn.poll(4)
 
767
        data = conn.recv()
 
768
        lock.acquire()
 
769
        functions[data[0]](lock, conn, data)
 
770
        lock.release()
 
771
 
 
772
 
 
773
class CLibrariesInterface(object):
 
774
    """Fast and exit-safe interface to GRASS C-libraries functions
 
775
 
 
776
       This class implements a fast and exit-safe interface to the GRASS
 
777
       gis, raster, 3D raster and vector  C-libraries functions.
 
778
 
 
779
       The C-libraries functions are called via ctypes in a subprocess
 
780
       using a pipe (multiprocessing.Pipe) to transfer the text messages.
 
781
       Hence, the process that uses the CLibrariesInterface will not be
 
782
       exited, if a G_fatal_error() was invoked in the subprocess.
 
783
       In this case the CLibrariesInterface object will simply start a
 
784
       new subprocess and restarts the pipeline.
 
785
 
 
786
 
 
787
       Usage:
 
788
 
 
789
       .. code-block:: python
 
790
 
 
791
           >>> import grass.script as gscript
 
792
           >>> import grass.temporal as tgis
 
793
           >>> gscript.use_temp_region()
 
794
           >>> gscript.run_command("g.region", n=80.0, s=0.0, e=120.0, w=0.0,
 
795
           ... t=1.0, b=0.0, res=10.0, res3=10.0)
 
796
           0
 
797
           >>> tgis.init()
 
798
           >>> gscript.run_command("r.mapcalc", expression="test = 1", overwrite=True, quiet=True)
 
799
           0
 
800
           >>> gscript.run_command("r3.mapcalc", expression="test = 1", overwrite=True, quiet=True)
 
801
           0
 
802
           >>> gscript.run_command("v.random", output="test", n=10, overwrite=True, quiet=True)
 
803
           0
 
804
           >>> gscript.run_command("r.timestamp", map="test", date='12 Mar 1995 10:34:40', overwrite=True, quiet=True)
 
805
           0
 
806
           >>> gscript.run_command("r3.timestamp", map="test", date='12 Mar 1995 10:34:40', overwrite=True, quiet=True)
 
807
           0
 
808
           >>> gscript.run_command("v.timestamp", map="test", date='12 Mar 1995 10:34:40', overwrite=True, quiet=True)
 
809
           0
 
810
 
 
811
           # Check mapsets
 
812
           >>> ciface = tgis.CLibrariesInterface()
 
813
           >>> mapsets = ciface.available_mapsets()
 
814
           >>> mapsets[0] == tgis.get_current_mapset()
 
815
           True
 
816
 
 
817
           # Raster map
 
818
           >>> ciface = tgis.CLibrariesInterface()
 
819
           >>> check = ciface.raster_map_exists("test", tgis.get_current_mapset())
 
820
           >>> print check
 
821
           True
 
822
           >>> ciface.read_raster_info("test", tgis.get_current_mapset())
 
823
           {'rows': 12, 'north': 80.0, 'min': 1, 'datatype': 'CELL', 'max': 1, 'ewres': 10.0, 'cols': 8, 'west': 0.0, 'east': 120.0, 'nsres': 10.0, 'south': 0.0}
 
824
           >>> check = ciface.has_raster_timestamp("test", tgis.get_current_mapset())
 
825
           >>> print check
 
826
           True
 
827
           >>> if check:
 
828
           ...     res = ciface.read_raster_timestamp("test", tgis.get_current_mapset())
 
829
           ...     if res[0]:
 
830
           ...         print str(res[1][0]), str(res[1][0])
 
831
           ...         ciface.remove_raster_timestamp("test", tgis.get_current_mapset())
 
832
           1995-03-12 10:34:40 1995-03-12 10:34:40
 
833
           1
 
834
           >>> ciface.has_raster_timestamp("test", tgis.get_current_mapset())
 
835
           False
 
836
           >>> ciface.write_raster_timestamp("test", tgis.get_current_mapset(), "13 Jan 1999 14:30:05")
 
837
           1
 
838
           >>> ciface.has_raster_timestamp("test", tgis.get_current_mapset())
 
839
           True
 
840
 
 
841
 
 
842
           # 3D raster map
 
843
           >>> check = ciface.raster3d_map_exists("test", tgis.get_current_mapset())
 
844
           >>> print check
 
845
           True
 
846
           >>> ciface.read_raster3d_info("test", tgis.get_current_mapset())
 
847
           {'tbres': 1.0, 'rows': 12, 'north': 80.0, 'bottom': 0.0, 'datatype': 'DCELL', 'max': 1.0, 'top': 1.0, 'min': 1.0, 'cols': 8, 'depths': 1, 'west': 0.0, 'ewres': 10.0, 'east': 120.0, 'nsres': 10.0, 'south': 0.0}
 
848
           >>> check = ciface.has_raster3d_timestamp("test", tgis.get_current_mapset())
 
849
           >>> print check
 
850
           True
 
851
           >>> if check:
 
852
           ...     res = ciface.read_raster3d_timestamp("test", tgis.get_current_mapset())
 
853
           ...     if res[0]:
 
854
           ...         print str(res[1][0]), str(res[1][0])
 
855
           ...         ciface.remove_raster3d_timestamp("test", tgis.get_current_mapset())
 
856
           1995-03-12 10:34:40 1995-03-12 10:34:40
 
857
           1
 
858
           >>> ciface.has_raster3d_timestamp("test", tgis.get_current_mapset())
 
859
           False
 
860
           >>> ciface.write_raster3d_timestamp("test", tgis.get_current_mapset(), "13 Jan 1999 14:30:05")
 
861
           1
 
862
           >>> ciface.has_raster3d_timestamp("test", tgis.get_current_mapset())
 
863
           True
 
864
 
 
865
 
 
866
           # Vector map
 
867
           >>> check = ciface.vector_map_exists("test", tgis.get_current_mapset())
 
868
           >>> print check
 
869
           True
 
870
           >>> kvp = ciface.read_vector_info("test", tgis.get_current_mapset())
 
871
           >>> print kvp['points']
 
872
           10
 
873
           >>> check = ciface.has_vector_timestamp("test", tgis.get_current_mapset(), None)
 
874
           >>> print check
 
875
           True
 
876
           >>> if check:
 
877
           ...     res = ciface.read_vector_timestamp("test", tgis.get_current_mapset())
 
878
           ...     if res[0]:
 
879
           ...         print str(res[1][0]), str(res[1][0])
 
880
           ...         ciface.remove_vector_timestamp("test", tgis.get_current_mapset())
 
881
           1995-03-12 10:34:40 1995-03-12 10:34:40
 
882
           1
 
883
           >>> ciface.has_vector_timestamp("test", tgis.get_current_mapset())
 
884
           False
 
885
           >>> ciface.write_vector_timestamp("test", tgis.get_current_mapset(), "13 Jan 1999 14:30:05")
 
886
           1
 
887
           >>> ciface.has_vector_timestamp("test", tgis.get_current_mapset())
 
888
           True
 
889
 
 
890
           >>> ciface.get_driver_name()
 
891
           'sqlite'
 
892
           >>> ciface.get_database_name().split("/")[-1]
 
893
           'sqlite.db'
 
894
 
 
895
           >>> mapset = ciface.get_mapset()
 
896
           >>> location = ciface.get_location()
 
897
           >>> gisdbase = ciface.get_gisdbase()
 
898
 
 
899
           >>> gscript.del_temp_region()
 
900
 
 
901
    """
 
902
    def __init__(self):
 
903
        self.client_conn = None
 
904
        self.server_conn = None
 
905
        self.queue = None
 
906
        self.server = None
 
907
        self.start_server()
 
908
 
 
909
    def start_server(self):
 
910
        self.client_conn, self.server_conn = Pipe(True)
 
911
        self.lock = Lock()
 
912
        self.server = Process(target=c_library_server, args=(self.lock,
 
913
                                                             self.server_conn))
 
914
        self.server.daemon = True
 
915
        self.server.start()
 
916
 
 
917
    def _check_restart_server(self):
 
918
        """Restart the server if it was terminated
 
919
        """
 
920
        if self.server.is_alive() is True:
 
921
            return
 
922
        self.client_conn.close()
 
923
        self.server_conn.close()
 
924
        self.start_server()
 
925
        logging.warning("Needed to restart the libgis server")
 
926
 
 
927
    def raster_map_exists(self, name, mapset):
 
928
        """Check if a raster map exists in the spatial database
 
929
 
 
930
           :param name: The name of the map
 
931
           :param mapset: The mapset of the map
 
932
           :returns: True if exists, False if not
 
933
       """
 
934
        self._check_restart_server()
 
935
        self.client_conn.send([RPCDefs.MAP_EXISTS, RPCDefs.TYPE_RASTER,
 
936
                               name, mapset, None])
 
937
        return self.client_conn.recv()
 
938
 
 
939
    def read_raster_info(self, name, mapset):
 
940
        """Read the raster map info from the file system and store the content
 
941
           into a dictionary
 
942
 
 
943
           :param name: The name of the map
 
944
           :param mapset: The mapset of the map
 
945
           :returns: The key value pairs of the map specific metadata,
 
946
                     or None in case of an error
 
947
        """
 
948
        self._check_restart_server()
 
949
        self.client_conn.send([RPCDefs.READ_MAP_INFO, RPCDefs.TYPE_RASTER,
 
950
                               name, mapset, None])
 
951
        return self.client_conn.recv()
 
952
 
 
953
    def has_raster_timestamp(self, name, mapset):
 
954
        """Check if a file based raster timetamp exists
 
955
 
 
956
           :param name: The name of the map
 
957
           :param mapset: The mapset of the map
 
958
           :returns: True if exists, False if not
 
959
       """
 
960
        self._check_restart_server()
 
961
        self.client_conn.send([RPCDefs.HAS_TIMESTAMP, RPCDefs.TYPE_RASTER,
 
962
                               name, mapset, None])
 
963
        return self.client_conn.recv()
 
964
 
 
965
    def remove_raster_timestamp(self, name, mapset):
 
966
        """Remove a file based raster timetamp
 
967
 
 
968
           Please have a look at the documentation G_remove_raster_timestamp
 
969
           for the return values description.
 
970
 
 
971
           :param name: The name of the map
 
972
           :param mapset: The mapset of the map
 
973
           :returns: The return value of G_remove_raster_timestamp
 
974
       """
 
975
        self._check_restart_server()
 
976
        self.client_conn.send([RPCDefs.REMOVE_TIMESTAMP, RPCDefs.TYPE_RASTER,
 
977
                               name, mapset, None])
 
978
        return self.client_conn.recv()
 
979
 
 
980
    def read_raster_timestamp(self, name, mapset):
 
981
        """Read a file based raster timetamp
 
982
 
 
983
           Please have a look at the documentation G_read_raster_timestamp
 
984
           for the return values description.
 
985
 
 
986
           The timestamps to be send are tuples of values:
 
987
               - relative time (start, end, unit), start and end are of type
 
988
                 integer, unit is of type string.
 
989
               - absolute time (start, end), start and end are of type datetime
 
990
 
 
991
           The end time may be None in case of a time instance.
 
992
 
 
993
           :param name: The name of the map
 
994
           :param mapset: The mapset of the map
 
995
           :returns: The return value of G_read_raster_timestamp
 
996
       """
 
997
        self._check_restart_server()
 
998
        self.client_conn.send([RPCDefs.READ_TIMESTAMP, RPCDefs.TYPE_RASTER,
 
999
                               name, mapset, None])
 
1000
        return self.client_conn.recv()
 
1001
 
 
1002
    def write_raster_timestamp(self, name, mapset, timestring):
 
1003
        """Write a file based raster timetamp
 
1004
 
 
1005
           Please have a look at the documentation G_write_raster_timestamp
 
1006
           for the return values description.
 
1007
 
 
1008
           Note:
 
1009
               Only timestamps of maps from the current mapset can written.
 
1010
 
 
1011
           :param name: The name of the map
 
1012
           :param mapset: The mapset of the map
 
1013
           :param timestring: A GRASS datetime C-library compatible string
 
1014
           :returns: The return value of G_write_raster_timestamp
 
1015
        """
 
1016
        self._check_restart_server()
 
1017
        self.client_conn.send([RPCDefs.WRITE_TIMESTAMP, RPCDefs.TYPE_RASTER,
 
1018
                               name, mapset, None, timestring])
 
1019
        return self.client_conn.recv()
 
1020
 
 
1021
    def raster3d_map_exists(self, name, mapset):
 
1022
        """Check if a 3D raster map exists in the spatial database
 
1023
 
 
1024
           :param name: The name of the map
 
1025
           :param mapset: The mapset of the map
 
1026
           :returns: True if exists, False if not
 
1027
       """
 
1028
        self._check_restart_server()
 
1029
        self.client_conn.send([RPCDefs.MAP_EXISTS, RPCDefs.TYPE_RASTER3D,
 
1030
                               name, mapset, None])
 
1031
        return self.client_conn.recv()
 
1032
 
 
1033
    def read_raster3d_info(self, name, mapset):
 
1034
        """Read the 3D raster map info from the file system and store the content
 
1035
           into a dictionary
 
1036
 
 
1037
           :param name: The name of the map
 
1038
           :param mapset: The mapset of the map
 
1039
           :returns: The key value pairs of the map specific metadata,
 
1040
                     or None in case of an error
 
1041
        """
 
1042
        self._check_restart_server()
 
1043
        self.client_conn.send([RPCDefs.READ_MAP_INFO, RPCDefs.TYPE_RASTER3D,
 
1044
                               name, mapset, None])
 
1045
        return self.client_conn.recv()
 
1046
 
 
1047
    def has_raster3d_timestamp(self, name, mapset):
 
1048
        """Check if a file based 3D raster timetamp exists
 
1049
 
 
1050
           :param name: The name of the map
 
1051
           :param mapset: The mapset of the map
 
1052
           :returns: True if exists, False if not
 
1053
       """
 
1054
        self._check_restart_server()
 
1055
        self.client_conn.send([RPCDefs.HAS_TIMESTAMP, RPCDefs.TYPE_RASTER3D,
 
1056
                               name, mapset, None])
 
1057
        return self.client_conn.recv()
 
1058
 
 
1059
    def remove_raster3d_timestamp(self, name, mapset):
 
1060
        """Remove a file based 3D raster timetamp
 
1061
 
 
1062
           Please have a look at the documentation G_remove_raster3d_timestamp
 
1063
           for the return values description.
 
1064
 
 
1065
           :param name: The name of the map
 
1066
           :param mapset: The mapset of the map
 
1067
           :returns: The return value of G_remove_raster3d_timestamp
 
1068
       """
 
1069
        self._check_restart_server()
 
1070
        self.client_conn.send([RPCDefs.REMOVE_TIMESTAMP, RPCDefs.TYPE_RASTER3D,
 
1071
                               name, mapset, None])
 
1072
        return self.client_conn.recv()
 
1073
 
 
1074
    def read_raster3d_timestamp(self, name, mapset):
 
1075
        """Read a file based 3D raster timetamp
 
1076
 
 
1077
           Please have a look at the documentation G_read_raster3d_timestamp
 
1078
           for the return values description.
 
1079
 
 
1080
           The timestamps to be send are tuples of values:
 
1081
               - relative time (start, end, unit), start and end are of type
 
1082
                 integer, unit is of type string.
 
1083
               - absolute time (start, end), start and end are of type datetime
 
1084
 
 
1085
           The end time may be None in case of a time instance.
 
1086
 
 
1087
           :param name: The name of the map
 
1088
           :param mapset: The mapset of the map
 
1089
           :returns: The return value of G_read_raster3d_timestamp
 
1090
       """
 
1091
        self._check_restart_server()
 
1092
        self.client_conn.send([RPCDefs.READ_TIMESTAMP, RPCDefs.TYPE_RASTER3D,
 
1093
                               name, mapset, None])
 
1094
        return self.client_conn.recv()
 
1095
 
 
1096
    def write_raster3d_timestamp(self, name, mapset, timestring):
 
1097
        """Write a file based 3D raster timetamp
 
1098
 
 
1099
           Please have a look at the documentation G_write_raster3d_timestamp
 
1100
           for the return values description.
 
1101
 
 
1102
           Note:
 
1103
               Only timestamps of maps from the current mapset can written.
 
1104
 
 
1105
           :param name: The name of the map
 
1106
           :param mapset: The mapset of the map
 
1107
           :param timestring: A GRASS datetime C-library compatible string
 
1108
           :returns: The return value of G_write_raster3d_timestamp
 
1109
        """
 
1110
        self._check_restart_server()
 
1111
        self.client_conn.send([RPCDefs.WRITE_TIMESTAMP, RPCDefs.TYPE_RASTER3D,
 
1112
                               name, mapset, None, timestring])
 
1113
        return self.client_conn.recv()
 
1114
 
 
1115
    def vector_map_exists(self, name, mapset):
 
1116
        """Check if a vector map exists in the spatial database
 
1117
 
 
1118
           :param name: The name of the map
 
1119
           :param mapset: The mapset of the map
 
1120
           :returns: True if exists, False if not
 
1121
       """
 
1122
        self._check_restart_server()
 
1123
        self.client_conn.send([RPCDefs.MAP_EXISTS, RPCDefs.TYPE_VECTOR,
 
1124
                               name, mapset, None])
 
1125
        return self.client_conn.recv()
 
1126
 
 
1127
    def read_vector_info(self, name, mapset):
 
1128
        """Read the vector map info from the file system and store the content
 
1129
           into a dictionary
 
1130
 
 
1131
           :param name: The name of the map
 
1132
           :param mapset: The mapset of the map
 
1133
           :returns: The key value pairs of the map specific metadata,
 
1134
                     or None in case of an error
 
1135
        """
 
1136
        self._check_restart_server()
 
1137
        self.client_conn.send([RPCDefs.READ_MAP_INFO, RPCDefs.TYPE_VECTOR,
 
1138
                               name, mapset, None])
 
1139
        return self.client_conn.recv()
 
1140
 
 
1141
    def has_vector_timestamp(self, name, mapset, layer=None):
 
1142
        """Check if a file based vector timetamp exists
 
1143
 
 
1144
           :param name: The name of the map
 
1145
           :param mapset: The mapset of the map
 
1146
           :param layer: The layer of the vector map
 
1147
           :returns: True if exists, False if not
 
1148
       """
 
1149
        self._check_restart_server()
 
1150
        self.client_conn.send([RPCDefs.HAS_TIMESTAMP, RPCDefs.TYPE_VECTOR,
 
1151
                               name, mapset, layer])
 
1152
        return self.client_conn.recv()
 
1153
 
 
1154
    def remove_vector_timestamp(self, name, mapset, layer=None):
 
1155
        """Remove a file based vector timetamp
 
1156
 
 
1157
           Please have a look at the documentation G_remove_vector_timestamp
 
1158
           for the return values description.
 
1159
 
 
1160
           :param name: The name of the map
 
1161
           :param mapset: The mapset of the map
 
1162
           :param layer: The layer of the vector map
 
1163
           :returns: The return value of G_remove_vector_timestamp
 
1164
       """
 
1165
        self._check_restart_server()
 
1166
        self.client_conn.send([RPCDefs.REMOVE_TIMESTAMP, RPCDefs.TYPE_VECTOR,
 
1167
                               name, mapset, layer])
 
1168
        return self.client_conn.recv()
 
1169
 
 
1170
    def read_vector_timestamp(self, name, mapset, layer=None):
 
1171
        """Read a file based vector timetamp
 
1172
 
 
1173
           Please have a look at the documentation G_read_vector_timestamp
 
1174
           for the return values description.
 
1175
 
 
1176
           The timestamps to be send are tuples of values:
 
1177
               - relative time (start, end, unit), start and end are of type
 
1178
                 integer, unit is of type string.
 
1179
               - absolute time (start, end), start and end are of type datetime
 
1180
 
 
1181
           The end time may be None in case of a time instance.
 
1182
 
 
1183
           :param name: The name of the map
 
1184
           :param mapset: The mapset of the map
 
1185
           :param layer: The layer of the vector map
 
1186
           :returns: The return value ofG_read_vector_timestamp and the timestamps
 
1187
       """
 
1188
        self._check_restart_server()
 
1189
        self.client_conn.send([RPCDefs.READ_TIMESTAMP, RPCDefs.TYPE_VECTOR,
 
1190
                               name, mapset, layer])
 
1191
        return self.client_conn.recv()
 
1192
 
 
1193
    def write_vector_timestamp(self, name, mapset, timestring, layer=None):
 
1194
        """Write a file based vector timestamp
 
1195
 
 
1196
           Please have a look at the documentation G_write_vector_timestamp
 
1197
           for the return values description.
 
1198
 
 
1199
           Note:
 
1200
               Only timestamps pf maps from the current mapset can written.
 
1201
 
 
1202
           :param name: The name of the map
 
1203
           :param mapset: The mapset of the map
 
1204
           :param timestring: A GRASS datetime C-library compatible string
 
1205
           :param layer: The layer of the vector map
 
1206
           :returns: The return value of G_write_vector_timestamp
 
1207
        """
 
1208
        self._check_restart_server()
 
1209
        self.client_conn.send([RPCDefs.WRITE_TIMESTAMP, RPCDefs.TYPE_VECTOR,
 
1210
                               name, mapset, layer, timestring])
 
1211
        return self.client_conn.recv()
 
1212
 
 
1213
    def available_mapsets(self):
 
1214
        """Return all available mapsets the user can access as a list of strings
 
1215
 
 
1216
           :returns: Names of available mapsets as list of strings
 
1217
        """
 
1218
        self._check_restart_server()
 
1219
        self.client_conn.send([RPCDefs.AVAILABLE_MAPSETS, ])
 
1220
        return self.client_conn.recv()
 
1221
 
 
1222
    def get_driver_name(self, mapset=None):
 
1223
        """Return the temporal database driver of a specific mapset
 
1224
 
 
1225
           :param mapset: Name of the mapset
 
1226
 
 
1227
           :returns: Name of the driver or None if no temporal database present
 
1228
        """
 
1229
        self._check_restart_server()
 
1230
        self.client_conn.send([RPCDefs.GET_DRIVER_NAME, mapset])
 
1231
        return self.client_conn.recv()
 
1232
 
 
1233
    def get_database_name(self, mapset=None):
 
1234
        """Return the temporal database name of a specific mapset
 
1235
 
 
1236
           :param mapset: Name of the mapset
 
1237
 
 
1238
           :returns: Name of the database or None if no temporal database present
 
1239
        """
 
1240
        self._check_restart_server()
 
1241
        self.client_conn.send([RPCDefs.GET_DATABASE_NAME, mapset])
 
1242
        return self.client_conn.recv()
 
1243
 
 
1244
    def get_mapset(self):
 
1245
        """Return the current mapset
 
1246
 
 
1247
           :returns: Name of the current mapset
 
1248
        """
 
1249
        self._check_restart_server()
 
1250
        self.client_conn.send([RPCDefs.G_MAPSET, ])
 
1251
        return self.client_conn.recv()
 
1252
 
 
1253
    def get_location(self):
 
1254
        """Return the location
 
1255
 
 
1256
           :returns: Name of the location
 
1257
        """
 
1258
        self._check_restart_server()
 
1259
        self.client_conn.send([RPCDefs.G_LOCATION, ])
 
1260
        return self.client_conn.recv()
 
1261
 
 
1262
    def get_gisdbase(self):
 
1263
        """Return the gisdatabase
 
1264
 
 
1265
           :returns: Name of the gisdatabase
 
1266
        """
 
1267
        self._check_restart_server()
 
1268
        self.client_conn.send([RPCDefs.G_GISDBASE, ])
 
1269
        return self.client_conn.recv()
 
1270
 
 
1271
    def fatal_error(self, mapset=None):
 
1272
        """Return the temporal database name of a specific mapset
 
1273
 
 
1274
           :param mapset: Name of the mapset
 
1275
 
 
1276
           :returns: Name of the database or None if no temporal database present
 
1277
        """
 
1278
        self._check_restart_server()
 
1279
        self.client_conn.send([RPCDefs.G_FATAL_ERROR])
 
1280
 
 
1281
    def stop(self):
 
1282
        """Stop the messenger server and close the pipe
 
1283
 
 
1284
           This method should be called at exit using the package atexit
 
1285
        """
 
1286
        if self.server is not None and self.server.is_alive():
 
1287
            self.client_conn.send([0, ])
 
1288
            self.server.join(5)
 
1289
            self.server.terminate()
 
1290
        if self.client_conn is not None:
 
1291
            self.client_conn.close()
 
1292
 
 
1293
if __name__ == "__main__":
 
1294
    import doctest
 
1295
    doctest.testmod()