c_libraries_interface.py 49 KB

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