c_libraries_interface.py 54 KB

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