c_libraries_interface.py 59 KB

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