c_libraries_interface.py 60 KB

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