c_libraries_interface.py 54 KB

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