1
# -*- coding: utf-8 -*-
3
Fast and exit-safe interface to GRASS C-library functions
4
using ctypes and multiprocessing
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
11
:authors: Soeren Gebbert
15
from multiprocessing import Process, Lock, Pipe
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
26
###############################################################################
29
class RPCDefs(object):
30
# Function identifier and index
41
GET_DATABASE_NAME = 10
51
###############################################################################
54
def _fatal_error(lock, conn, data):
55
"""Calls G_fatal_error()"""
56
libgis.G_fatal_error("Fatal Error in C library server")
59
def _get_mapset(lock, conn, data):
60
"""Return the current mapset
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]
66
:returns: Name of the current mapset
68
mapset = libgis.G_mapset()
72
def _get_location(lock, conn, data):
73
"""Return the current location
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]
79
:returns: Name of the location
81
location = libgis.G_location()
85
def _get_gisdbase(lock, conn, data):
86
"""Return the current gisdatabase
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]
92
:returns: Name of the gisdatabase
94
gisdbase = libgis.G_gisdbase()
98
def _get_driver_name(lock, conn, data):
99
"""Return the temporal database driver of a specific mapset
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]
105
:returns: Name of the driver or None if no temporal database present
109
mapset = libgis.G_mapset()
111
drstring = libtgis.tgis_get_mapset_driver_name(mapset)
114
###############################################################################
117
def _get_database_name(lock, conn, data):
118
"""Return the temporal database name of a specific mapset
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]
124
:returns: Name of the database or None if no temporal database present
128
mapset = libgis.G_mapset()
129
dbstring = libtgis.tgis_get_mapset_database_name(mapset)
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())
139
###############################################################################
142
def _available_mapsets(lock, conn, data):
143
"""Return all available mapsets the user can access as a list of strings
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]
149
:returns: Names of available mapsets as list of strings
152
mapsets = libgis.G_get_available_mapsets()
156
while mapsets[count]:
158
mapset = mapsets[count]
159
if libgis.G_mapset_permissions(mapset) > 0:
162
while mapset[c] != "\x00":
163
char_list += mapset[c]
166
mapset_list.append(char_list)
168
# We need to sort the mapset list, but the first one should be
170
current_mapset = libgis.G_mapset()
171
mapset_list.remove(current_mapset)
173
mapset_list.reverse()
174
mapset_list.append(current_mapset)
175
mapset_list.reverse()
177
conn.send(mapset_list)
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.
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,
195
if maptype == RPCDefs.TYPE_RASTER:
196
if libgis.G_has_raster_timestamp(name, mapset) == 1:
198
elif maptype == RPCDefs.TYPE_VECTOR:
199
if libgis.G_has_vector_timestamp(name, layer, mapset) == 1:
201
elif maptype == RPCDefs.TYPE_RASTER3D:
202
if libgis.G_has_raster3d_timestamp(name, mapset) == 1:
206
###############################################################################
209
def _read_timestamp(lock, conn, data):
210
"""Read the file based GRASS timestamp and send
211
the result using the provided pipe.
213
The tuple to be send via pipe: (return value of G_read_*_timestamp,
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
220
The timestamps to be send are tuples of values:
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
226
The end time may be None in case of a time instance.
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,
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))
247
dates = _convert_timestamp_from_grass(ts)
248
conn.send((check, dates))
250
###############################################################################
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.
257
The value to be send via pipe is the return value of G_write_*_timestamp.
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
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]
274
ts = libgis.TimeStamp()
275
check = libgis.G_scan_timestamp(byref(ts), timestring)
278
logging.error("Unable to convert the timestamp: " + timestring)
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))
290
###############################################################################
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.
297
The value to be send via pipe is the return value of G_remove_*_timestamp.
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
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,
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)
323
###############################################################################
326
def _map_exists(lock, conn, data):
327
"""Check if a map exists in the spatial database
329
The value to be send via pipe is True in case the map exists and False
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]
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)
353
###############################################################################
356
def _read_map_info(lock, conn, data):
357
"""Read map specific metadata from the spatial database using C-library
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]
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)
376
###############################################################################
379
def _read_raster_info(name, mapset):
380
"""Read the raster map info from the file system and store the content
383
This method uses the ctypes interface to the gis and raster libraries
384
to read the map metadata information
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
394
if not libgis.G_find_raster(name, mapset):
397
# Read the region information
398
region = libgis.Cell_head()
399
libraster.Rast_get_cellhd(name, mapset, byref(region))
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
410
maptype = libraster.Rast_map_type(name, mapset)
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"
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))
425
logging.error(_("Unable to read range file"))
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
438
range = libraster.Range()
439
libraster.Rast_init_range(byref(range))
440
ret = libraster.Rast_read_range(name, mapset, byref(range))
442
logging.error(_("Unable to read range file"))
450
libraster.Rast_get_range_min_max(
451
byref(range), byref(min), byref(max))
452
kvp["min"] = min.value
453
kvp["max"] = max.value
457
###############################################################################
460
def _read_raster3d_info(name, mapset):
461
"""Read the 3D raster map info from the file system and store the content
464
This method uses the ctypes interface to the gis and raster3d libraries
465
to read the map metadata information
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
475
if not libgis.G_find_raster3d(name, mapset):
478
# Read the region information
479
region = libraster3d.RASTER3D_Region()
480
libraster3d.Rast3d_read_region_map(name, mapset, byref(region))
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
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
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))
505
logging.error(_("Unable to open 3D raster map <%s>" % (name)))
508
maptype = libraster3d.Rast3d_file_type_map(g3map)
510
if maptype == libraster.DCELL_TYPE:
511
kvp["datatype"] = "DCELL"
512
elif maptype == libraster.FCELL_TYPE:
513
kvp["datatype"] = "FCELL"
518
ret = libraster3d.Rast3d_range_load(g3map)
520
logging.error(_("Unable to load range of 3D raster map <%s>" %
523
libraster3d.Rast3d_range_min_max(g3map, byref(min), byref(max))
525
if min.value != min.value:
528
kvp["min"] = float(min.value)
529
if max.value != max.value:
532
kvp["max"] = float(max.value)
534
if not libraster3d.Rast3d_close(g3map):
535
logging.error(_("Unable to close 3D raster map <%s>" % (name)))
540
###############################################################################
543
def _read_vector_info(name, mapset):
544
"""Read the vector map info from the file system and store the content
547
This method uses the ctypes interface to the vector libraries
548
to read the map metadata information
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
558
if not libgis.G_find_vector(name, mapset):
561
# The vector map structure
562
Map = libvector.Map_info()
564
# We open the maps always in topology mode first
565
libvector.Vect_set_open_level(2)
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
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)))))
580
# Release the vector spatial index memory when closed
581
libvector.Vect_set_release_support(byref(Map))
583
# Read the extent information
584
bbox = libvector.bound_box()
585
libvector.Vect_get_map_box(byref(Map), byref(bbox))
587
kvp["north"] = bbox.N
588
kvp["south"] = bbox.S
592
kvp["bottom"] = bbox.B
594
kvp["map3d"] = bool(libvector.Vect_is_3d(byref(Map)))
596
# Read number of features
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)
611
# Summarize the primitives
612
kvp["primitives"] = kvp["points"] + kvp["lines"] + \
613
kvp["boundaries"] + kvp["centroids"]
615
kvp["primitives"] += kvp["faces"] + kvp["kernels"]
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)
627
kvp["boundaries"] = None
628
kvp["centroids"] = None
630
kvp["kernels"] = None
631
kvp["primitives"] = None
634
kvp["islands"] = None
636
kvp["volumes"] = None
638
libvector.Vect_close(byref(Map))
642
###############################################################################
645
def _convert_timestamp_from_grass(ts):
646
"""Convert a GRASS file based timestamp into the temporal framework
647
format datetime or integer.
649
A tuple of two datetime objects (start, end) is returned in case of
651
In case of relative time a tuple with start time, end time and the
652
relative unit (start, end, unit) will be returned.
655
The end time will be set to None in case of a time instance.
657
:param ts grass.lib.gis.TimeStamp object created by G_read_*_timestamp
660
dt1 = libgis.DateTime()
661
dt2 = libgis.DateTime()
664
libgis.G_get_timestamps(byref(ts),
669
if dt1.mode == libdate.DATETIME_ABSOLUTE:
673
pdt1 = datetime(int(dt1.year), int(dt1.month), int(dt1.day),
674
int(dt1.hour), int(dt1.minute),
677
pdt2 = datetime(int(dt2.year), int(dt2.month), int(dt2.day),
678
int(dt2.hour), int(dt2.minute),
681
# ATTENTION: We ignore the time zone
682
# TODO: Write time zone support
720
return (start, end, unit)
722
###############################################################################
725
def _stop(lock, conn, data):
726
libgis.G_debug(1, "Stop C-interface server")
731
###############################################################################
732
# Global server connection
733
server_connection = None
737
def c_library_server(lock, conn):
738
"""The GRASS C-libraries server function designed to be a target for
739
multiprocessing.Process
741
:param lock: A multiprocessing.Lock
742
:param conn: A multiprocessing.Pipe
744
# Crerate the function array
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
761
libgis.G_gisinit("c_library_server")
762
libgis.G_debug(1, "Start C-interface server")
769
functions[data[0]](lock, conn, data)
773
class CLibrariesInterface(object):
774
"""Fast and exit-safe interface to GRASS C-libraries functions
776
This class implements a fast and exit-safe interface to the GRASS
777
gis, raster, 3D raster and vector C-libraries functions.
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.
789
.. code-block:: python
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)
798
>>> gscript.run_command("r.mapcalc", expression="test = 1", overwrite=True, quiet=True)
800
>>> gscript.run_command("r3.mapcalc", expression="test = 1", overwrite=True, quiet=True)
802
>>> gscript.run_command("v.random", output="test", n=10, overwrite=True, quiet=True)
804
>>> gscript.run_command("r.timestamp", map="test", date='12 Mar 1995 10:34:40', overwrite=True, quiet=True)
806
>>> gscript.run_command("r3.timestamp", map="test", date='12 Mar 1995 10:34:40', overwrite=True, quiet=True)
808
>>> gscript.run_command("v.timestamp", map="test", date='12 Mar 1995 10:34:40', overwrite=True, quiet=True)
812
>>> ciface = tgis.CLibrariesInterface()
813
>>> mapsets = ciface.available_mapsets()
814
>>> mapsets[0] == tgis.get_current_mapset()
818
>>> ciface = tgis.CLibrariesInterface()
819
>>> check = ciface.raster_map_exists("test", tgis.get_current_mapset())
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())
828
... res = ciface.read_raster_timestamp("test", tgis.get_current_mapset())
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
834
>>> ciface.has_raster_timestamp("test", tgis.get_current_mapset())
836
>>> ciface.write_raster_timestamp("test", tgis.get_current_mapset(), "13 Jan 1999 14:30:05")
838
>>> ciface.has_raster_timestamp("test", tgis.get_current_mapset())
843
>>> check = ciface.raster3d_map_exists("test", tgis.get_current_mapset())
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())
852
... res = ciface.read_raster3d_timestamp("test", tgis.get_current_mapset())
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
858
>>> ciface.has_raster3d_timestamp("test", tgis.get_current_mapset())
860
>>> ciface.write_raster3d_timestamp("test", tgis.get_current_mapset(), "13 Jan 1999 14:30:05")
862
>>> ciface.has_raster3d_timestamp("test", tgis.get_current_mapset())
867
>>> check = ciface.vector_map_exists("test", tgis.get_current_mapset())
870
>>> kvp = ciface.read_vector_info("test", tgis.get_current_mapset())
871
>>> print kvp['points']
873
>>> check = ciface.has_vector_timestamp("test", tgis.get_current_mapset(), None)
877
... res = ciface.read_vector_timestamp("test", tgis.get_current_mapset())
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
883
>>> ciface.has_vector_timestamp("test", tgis.get_current_mapset())
885
>>> ciface.write_vector_timestamp("test", tgis.get_current_mapset(), "13 Jan 1999 14:30:05")
887
>>> ciface.has_vector_timestamp("test", tgis.get_current_mapset())
890
>>> ciface.get_driver_name()
892
>>> ciface.get_database_name().split("/")[-1]
895
>>> mapset = ciface.get_mapset()
896
>>> location = ciface.get_location()
897
>>> gisdbase = ciface.get_gisdbase()
899
>>> gscript.del_temp_region()
903
self.client_conn = None
904
self.server_conn = None
909
def start_server(self):
910
self.client_conn, self.server_conn = Pipe(True)
912
self.server = Process(target=c_library_server, args=(self.lock,
914
self.server.daemon = True
917
def _check_restart_server(self):
918
"""Restart the server if it was terminated
920
if self.server.is_alive() is True:
922
self.client_conn.close()
923
self.server_conn.close()
925
logging.warning("Needed to restart the libgis server")
927
def raster_map_exists(self, name, mapset):
928
"""Check if a raster map exists in the spatial database
930
:param name: The name of the map
931
:param mapset: The mapset of the map
932
:returns: True if exists, False if not
934
self._check_restart_server()
935
self.client_conn.send([RPCDefs.MAP_EXISTS, RPCDefs.TYPE_RASTER,
937
return self.client_conn.recv()
939
def read_raster_info(self, name, mapset):
940
"""Read the raster map info from the file system and store the content
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
948
self._check_restart_server()
949
self.client_conn.send([RPCDefs.READ_MAP_INFO, RPCDefs.TYPE_RASTER,
951
return self.client_conn.recv()
953
def has_raster_timestamp(self, name, mapset):
954
"""Check if a file based raster timetamp exists
956
:param name: The name of the map
957
:param mapset: The mapset of the map
958
:returns: True if exists, False if not
960
self._check_restart_server()
961
self.client_conn.send([RPCDefs.HAS_TIMESTAMP, RPCDefs.TYPE_RASTER,
963
return self.client_conn.recv()
965
def remove_raster_timestamp(self, name, mapset):
966
"""Remove a file based raster timetamp
968
Please have a look at the documentation G_remove_raster_timestamp
969
for the return values description.
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
975
self._check_restart_server()
976
self.client_conn.send([RPCDefs.REMOVE_TIMESTAMP, RPCDefs.TYPE_RASTER,
978
return self.client_conn.recv()
980
def read_raster_timestamp(self, name, mapset):
981
"""Read a file based raster timetamp
983
Please have a look at the documentation G_read_raster_timestamp
984
for the return values description.
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
991
The end time may be None in case of a time instance.
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
997
self._check_restart_server()
998
self.client_conn.send([RPCDefs.READ_TIMESTAMP, RPCDefs.TYPE_RASTER,
1000
return self.client_conn.recv()
1002
def write_raster_timestamp(self, name, mapset, timestring):
1003
"""Write a file based raster timetamp
1005
Please have a look at the documentation G_write_raster_timestamp
1006
for the return values description.
1009
Only timestamps of maps from the current mapset can written.
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
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()
1021
def raster3d_map_exists(self, name, mapset):
1022
"""Check if a 3D raster map exists in the spatial database
1024
:param name: The name of the map
1025
:param mapset: The mapset of the map
1026
:returns: True if exists, False if not
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()
1033
def read_raster3d_info(self, name, mapset):
1034
"""Read the 3D raster map info from the file system and store the content
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
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()
1047
def has_raster3d_timestamp(self, name, mapset):
1048
"""Check if a file based 3D raster timetamp exists
1050
:param name: The name of the map
1051
:param mapset: The mapset of the map
1052
:returns: True if exists, False if not
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()
1059
def remove_raster3d_timestamp(self, name, mapset):
1060
"""Remove a file based 3D raster timetamp
1062
Please have a look at the documentation G_remove_raster3d_timestamp
1063
for the return values description.
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
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()
1074
def read_raster3d_timestamp(self, name, mapset):
1075
"""Read a file based 3D raster timetamp
1077
Please have a look at the documentation G_read_raster3d_timestamp
1078
for the return values description.
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
1085
The end time may be None in case of a time instance.
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
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()
1096
def write_raster3d_timestamp(self, name, mapset, timestring):
1097
"""Write a file based 3D raster timetamp
1099
Please have a look at the documentation G_write_raster3d_timestamp
1100
for the return values description.
1103
Only timestamps of maps from the current mapset can written.
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
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()
1115
def vector_map_exists(self, name, mapset):
1116
"""Check if a vector map exists in the spatial database
1118
:param name: The name of the map
1119
:param mapset: The mapset of the map
1120
:returns: True if exists, False if not
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()
1127
def read_vector_info(self, name, mapset):
1128
"""Read the vector map info from the file system and store the content
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
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()
1141
def has_vector_timestamp(self, name, mapset, layer=None):
1142
"""Check if a file based vector timetamp exists
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
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()
1154
def remove_vector_timestamp(self, name, mapset, layer=None):
1155
"""Remove a file based vector timetamp
1157
Please have a look at the documentation G_remove_vector_timestamp
1158
for the return values description.
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
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()
1170
def read_vector_timestamp(self, name, mapset, layer=None):
1171
"""Read a file based vector timetamp
1173
Please have a look at the documentation G_read_vector_timestamp
1174
for the return values description.
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
1181
The end time may be None in case of a time instance.
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
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()
1193
def write_vector_timestamp(self, name, mapset, timestring, layer=None):
1194
"""Write a file based vector timestamp
1196
Please have a look at the documentation G_write_vector_timestamp
1197
for the return values description.
1200
Only timestamps pf maps from the current mapset can written.
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
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()
1213
def available_mapsets(self):
1214
"""Return all available mapsets the user can access as a list of strings
1216
:returns: Names of available mapsets as list of strings
1218
self._check_restart_server()
1219
self.client_conn.send([RPCDefs.AVAILABLE_MAPSETS, ])
1220
return self.client_conn.recv()
1222
def get_driver_name(self, mapset=None):
1223
"""Return the temporal database driver of a specific mapset
1225
:param mapset: Name of the mapset
1227
:returns: Name of the driver or None if no temporal database present
1229
self._check_restart_server()
1230
self.client_conn.send([RPCDefs.GET_DRIVER_NAME, mapset])
1231
return self.client_conn.recv()
1233
def get_database_name(self, mapset=None):
1234
"""Return the temporal database name of a specific mapset
1236
:param mapset: Name of the mapset
1238
:returns: Name of the database or None if no temporal database present
1240
self._check_restart_server()
1241
self.client_conn.send([RPCDefs.GET_DATABASE_NAME, mapset])
1242
return self.client_conn.recv()
1244
def get_mapset(self):
1245
"""Return the current mapset
1247
:returns: Name of the current mapset
1249
self._check_restart_server()
1250
self.client_conn.send([RPCDefs.G_MAPSET, ])
1251
return self.client_conn.recv()
1253
def get_location(self):
1254
"""Return the location
1256
:returns: Name of the location
1258
self._check_restart_server()
1259
self.client_conn.send([RPCDefs.G_LOCATION, ])
1260
return self.client_conn.recv()
1262
def get_gisdbase(self):
1263
"""Return the gisdatabase
1265
:returns: Name of the gisdatabase
1267
self._check_restart_server()
1268
self.client_conn.send([RPCDefs.G_GISDBASE, ])
1269
return self.client_conn.recv()
1271
def fatal_error(self, mapset=None):
1272
"""Return the temporal database name of a specific mapset
1274
:param mapset: Name of the mapset
1276
:returns: Name of the database or None if no temporal database present
1278
self._check_restart_server()
1279
self.client_conn.send([RPCDefs.G_FATAL_ERROR])
1282
"""Stop the messenger server and close the pipe
1284
This method should be called at exit using the package atexit
1286
if self.server is not None and self.server.is_alive():
1287
self.client_conn.send([0, ])
1289
self.server.terminate()
1290
if self.client_conn is not None:
1291
self.client_conn.close()
1293
if __name__ == "__main__":