c_libraries_interface.py 51 KB

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