c_libraries_interface.py 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853
  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_char_p, 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_BAND_REFERENCE = 15
  46. READ_BAND_REFERENCE = 16
  47. REMOVE_BAND_REFERENCE = 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_band_reference(lock, conn, data):
  409. """Read the file based GRASS band identifier
  410. the result using the provided pipe.
  411. The tuple to be send via pipe: (return value of
  412. Rast_read_band_reference).
  413. Please have a look at the documentation of
  414. Rast_read_band_reference, for the return values description.
  415. :param lock: A multiprocessing.Lock instance
  416. :param conn: A multiprocessing.Pipe instance used to send True or False
  417. :param data: The list of data entries [function_id, maptype, name,
  418. mapset, layer, timestring]
  419. """
  420. check = False
  421. band_ref = None
  422. try:
  423. maptype = data[1]
  424. name = data[2]
  425. mapset = data[3]
  426. layer = data[4]
  427. if maptype == RPCDefs.TYPE_RASTER:
  428. p_filename = c_char_p()
  429. p_band_ref = c_char_p()
  430. check = libraster.Rast_read_band_reference(
  431. name, mapset, byref(p_filename), byref(p_band_ref)
  432. )
  433. if check:
  434. band_ref = decode(p_band_ref.value)
  435. libgis.G_free(p_filename)
  436. libgis.G_free(p_band_ref)
  437. else:
  438. logging.error(
  439. "Unable to read band reference. " "Unsupported map type %s" % maptype
  440. )
  441. return -1
  442. except:
  443. raise
  444. finally:
  445. conn.send((check, band_ref))
  446. ###############################################################################
  447. def _write_band_reference(lock, conn, data):
  448. """Write the file based GRASS band identifier
  449. the return values of the called C-functions using the provided pipe.
  450. The value to be send via pipe is the return value of Rast_write_band_reference.
  451. Please have a look at the documentation of
  452. Rast_write_band_reference, for the return values description.
  453. :param lock: A multiprocessing.Lock instance
  454. :param conn: A multiprocessing.Pipe instance used to send True or False
  455. :param data: The list of data entries [function_id, maptype, name,
  456. mapset, layer, timestring]
  457. """
  458. check = -3
  459. try:
  460. maptype = data[1]
  461. name = data[2]
  462. mapset = data[3]
  463. layer = data[4]
  464. band_reference = data[5]
  465. if maptype == RPCDefs.TYPE_RASTER:
  466. from grass.bandref import BandReferenceReader
  467. reader = BandReferenceReader()
  468. # determine filename (assuming that band_reference is unique!)
  469. filename = reader.find_file(band_reference)
  470. check = libraster.Rast_write_band_reference(name, filename, band_reference)
  471. else:
  472. logging.error(
  473. "Unable to write band reference. " "Unsupported map type %s" % maptype
  474. )
  475. return -2
  476. except:
  477. raise
  478. finally:
  479. conn.send(check)
  480. ###############################################################################
  481. def _remove_band_reference(lock, conn, data):
  482. """Remove the file based GRASS band identifier
  483. the return values of the called C-functions using the provided pipe.
  484. The value to be send via pipe is the return value of Rast_remove_band_reference.
  485. Please have a look at the documentation of
  486. Rast_remove_band_reference, for the return values description.
  487. :param lock: A multiprocessing.Lock instance
  488. :param conn: A multiprocessing.Pipe instance used to send True or False
  489. :param data: The list of data entries [function_id, maptype, name,
  490. mapset, layer, timestring]
  491. """
  492. check = False
  493. try:
  494. maptype = data[1]
  495. name = data[2]
  496. mapset = data[3]
  497. layer = data[4]
  498. if maptype == RPCDefs.TYPE_RASTER:
  499. check = libraster.Rast_remove_band_reference(name)
  500. else:
  501. logging.error(
  502. "Unable to remove band reference. " "Unsupported map type %s" % maptype
  503. )
  504. return -2
  505. except:
  506. raise
  507. finally:
  508. conn.send(check)
  509. ###############################################################################
  510. def _map_exists(lock, conn, data):
  511. """Check if a map exists in the spatial database
  512. The value to be send via pipe is True in case the map exists and False
  513. if not.
  514. :param lock: A multiprocessing.Lock instance
  515. :param conn: A multiprocessing.Pipe instance used to send True or False
  516. :param data: The list of data entries [function_id, maptype, name, mapset]
  517. """
  518. check = False
  519. try:
  520. maptype = data[1]
  521. name = data[2]
  522. mapset = data[3]
  523. if maptype == RPCDefs.TYPE_RASTER:
  524. mapset = libgis.G_find_raster(name, mapset)
  525. elif maptype == RPCDefs.TYPE_VECTOR:
  526. mapset = libgis.G_find_vector(name, mapset)
  527. elif maptype == RPCDefs.TYPE_RASTER3D:
  528. mapset = libgis.G_find_raster3d(name, mapset)
  529. if mapset:
  530. check = True
  531. except:
  532. raise
  533. finally:
  534. conn.send(check)
  535. ###############################################################################
  536. def _read_map_info(lock, conn, data):
  537. """Read map specific metadata from the spatial database using C-library
  538. functions
  539. :param lock: A multiprocessing.Lock instance
  540. :param conn: A multiprocessing.Pipe instance used to send True or False
  541. :param data: The list of data entries [function_id, maptype, name, mapset]
  542. """
  543. kvp = None
  544. try:
  545. maptype = data[1]
  546. name = data[2]
  547. mapset = data[3]
  548. if maptype == RPCDefs.TYPE_RASTER:
  549. kvp = _read_raster_info(name, mapset)
  550. elif maptype == RPCDefs.TYPE_VECTOR:
  551. kvp = _read_vector_info(name, mapset)
  552. elif maptype == RPCDefs.TYPE_RASTER3D:
  553. kvp = _read_raster3d_info(name, mapset)
  554. except:
  555. raise
  556. finally:
  557. conn.send(kvp)
  558. ###############################################################################
  559. def _read_raster_info(name, mapset):
  560. """Read the raster map info from the file system and store the content
  561. into a dictionary
  562. This method uses the ctypes interface to the gis and raster libraries
  563. to read the map metadata information
  564. :param name: The name of the map
  565. :param mapset: The mapset of the map
  566. :returns: The key value pairs of the map specific metadata, or None in
  567. case of an error
  568. """
  569. kvp = {}
  570. if not libgis.G_find_raster(name, mapset):
  571. return None
  572. # Read the region information
  573. region = libraster.struct_Cell_head()
  574. libraster.Rast_get_cellhd(name, mapset, byref(region))
  575. kvp["north"] = region.north
  576. kvp["south"] = region.south
  577. kvp["east"] = region.east
  578. kvp["west"] = region.west
  579. kvp["nsres"] = region.ns_res
  580. kvp["ewres"] = region.ew_res
  581. kvp["rows"] = region.cols
  582. kvp["cols"] = region.rows
  583. maptype = libraster.Rast_map_type(name, mapset)
  584. if maptype == libraster.DCELL_TYPE:
  585. kvp["datatype"] = "DCELL"
  586. elif maptype == libraster.FCELL_TYPE:
  587. kvp["datatype"] = "FCELL"
  588. elif maptype == libraster.CELL_TYPE:
  589. kvp["datatype"] = "CELL"
  590. # Read range
  591. if libraster.Rast_map_is_fp(name, mapset):
  592. range = libraster.FPRange()
  593. libraster.Rast_init_fp_range(byref(range))
  594. ret = libraster.Rast_read_fp_range(name, mapset, byref(range))
  595. if ret < 0:
  596. logging.error(_("Unable to read range file"))
  597. return None
  598. if ret == 2:
  599. kvp["min"] = None
  600. kvp["max"] = None
  601. else:
  602. min = libgis.DCELL()
  603. max = libgis.DCELL()
  604. libraster.Rast_get_fp_range_min_max(byref(range), byref(min), byref(max))
  605. kvp["min"] = min.value
  606. kvp["max"] = max.value
  607. else:
  608. range = libraster.Range()
  609. libraster.Rast_init_range(byref(range))
  610. ret = libraster.Rast_read_range(name, mapset, byref(range))
  611. if ret < 0:
  612. logging.error(_("Unable to read range file"))
  613. return None
  614. if ret == 2:
  615. kvp["min"] = None
  616. kvp["max"] = None
  617. else:
  618. min = libgis.CELL()
  619. max = libgis.CELL()
  620. libraster.Rast_get_range_min_max(byref(range), byref(min), byref(max))
  621. kvp["min"] = min.value
  622. kvp["max"] = max.value
  623. return kvp
  624. ###############################################################################
  625. def _read_raster3d_info(name, mapset):
  626. """Read the 3D raster map info from the file system and store the content
  627. into a dictionary
  628. This method uses the ctypes interface to the gis and raster3d libraries
  629. to read the map metadata information
  630. :param name: The name of the map
  631. :param mapset: The mapset of the map
  632. :returns: The key value pairs of the map specific metadata, or None in
  633. case of an error
  634. """
  635. kvp = {}
  636. if not libgis.G_find_raster3d(name, mapset):
  637. return None
  638. # Read the region information
  639. region = libraster3d.RASTER3D_Region()
  640. libraster3d.Rast3d_read_region_map(name, mapset, byref(region))
  641. kvp["north"] = region.north
  642. kvp["south"] = region.south
  643. kvp["east"] = region.east
  644. kvp["west"] = region.west
  645. kvp["nsres"] = region.ns_res
  646. kvp["ewres"] = region.ew_res
  647. kvp["tbres"] = region.tb_res
  648. kvp["rows"] = region.cols
  649. kvp["cols"] = region.rows
  650. kvp["depths"] = region.depths
  651. kvp["top"] = region.top
  652. kvp["bottom"] = region.bottom
  653. # We need to open the map, this function returns a void pointer
  654. # but we may need the correct type which is RASTER3D_Map, hence
  655. # the casting
  656. g3map = cast(
  657. libraster3d.Rast3d_open_cell_old(
  658. name,
  659. mapset,
  660. libraster3d.RASTER3D_DEFAULT_WINDOW,
  661. libraster3d.RASTER3D_TILE_SAME_AS_FILE,
  662. libraster3d.RASTER3D_NO_CACHE,
  663. ),
  664. POINTER(libraster3d.RASTER3D_Map),
  665. )
  666. if not g3map:
  667. logging.error(_("Unable to open 3D raster map <%s>" % (name)))
  668. return None
  669. maptype = libraster3d.Rast3d_file_type_map(g3map)
  670. if maptype == libraster.DCELL_TYPE:
  671. kvp["datatype"] = "DCELL"
  672. elif maptype == libraster.FCELL_TYPE:
  673. kvp["datatype"] = "FCELL"
  674. # Read range
  675. min = libgis.DCELL()
  676. max = libgis.DCELL()
  677. ret = libraster3d.Rast3d_range_load(g3map)
  678. if not ret:
  679. logging.error(_("Unable to load range of 3D raster map <%s>" % (name)))
  680. return None
  681. libraster3d.Rast3d_range_min_max(g3map, byref(min), byref(max))
  682. if min.value != min.value:
  683. kvp["min"] = None
  684. else:
  685. kvp["min"] = float(min.value)
  686. if max.value != max.value:
  687. kvp["max"] = None
  688. else:
  689. kvp["max"] = float(max.value)
  690. if not libraster3d.Rast3d_close(g3map):
  691. logging.error(_("Unable to close 3D raster map <%s>" % (name)))
  692. return None
  693. return kvp
  694. ###############################################################################
  695. def _read_vector_info(name, mapset):
  696. """Read the vector map info from the file system and store the content
  697. into a dictionary
  698. This method uses the ctypes interface to the vector libraries
  699. to read the map metadata information
  700. :param name: The name of the map
  701. :param mapset: The mapset of the map
  702. :returns: The key value pairs of the map specific metadata, or None in
  703. case of an error
  704. """
  705. kvp = {}
  706. if not libgis.G_find_vector(name, mapset):
  707. return None
  708. # The vector map structure
  709. Map = libvector.Map_info()
  710. # We open the maps always in topology mode first
  711. libvector.Vect_set_open_level(2)
  712. with_topo = True
  713. # Code lend from v.info main.c
  714. if libvector.Vect_open_old_head2(byref(Map), name, mapset, "1") < 2:
  715. # force level 1, open fully
  716. # NOTE: number of points, lines, boundaries, centroids,
  717. # faces, kernels is still available
  718. libvector.Vect_set_open_level(1) # no topology
  719. with_topo = False
  720. if libvector.Vect_open_old2(byref(Map), name, mapset, "1") < 1:
  721. logging.error(
  722. _(
  723. "Unable to open vector map <%s>"
  724. % (libvector.Vect_get_full_name(byref(Map)))
  725. )
  726. )
  727. return None
  728. # Release the vector spatial index memory when closed
  729. libvector.Vect_set_release_support(byref(Map))
  730. # Read the extent information
  731. bbox = libvector.bound_box()
  732. libvector.Vect_get_map_box(byref(Map), byref(bbox))
  733. kvp["north"] = bbox.N
  734. kvp["south"] = bbox.S
  735. kvp["east"] = bbox.E
  736. kvp["west"] = bbox.W
  737. kvp["top"] = bbox.T
  738. kvp["bottom"] = bbox.B
  739. kvp["map3d"] = bool(libvector.Vect_is_3d(byref(Map)))
  740. # Read number of features
  741. if with_topo:
  742. kvp["points"] = libvector.Vect_get_num_primitives(
  743. byref(Map), libvector.GV_POINT
  744. )
  745. kvp["lines"] = libvector.Vect_get_num_primitives(byref(Map), libvector.GV_LINE)
  746. kvp["boundaries"] = libvector.Vect_get_num_primitives(
  747. byref(Map), libvector.GV_BOUNDARY
  748. )
  749. kvp["centroids"] = libvector.Vect_get_num_primitives(
  750. byref(Map), libvector.GV_CENTROID
  751. )
  752. kvp["faces"] = libvector.Vect_get_num_primitives(byref(Map), libvector.GV_FACE)
  753. kvp["kernels"] = libvector.Vect_get_num_primitives(
  754. byref(Map), libvector.GV_KERNEL
  755. )
  756. # Summarize the primitives
  757. kvp["primitives"] = (
  758. kvp["points"] + kvp["lines"] + kvp["boundaries"] + kvp["centroids"]
  759. )
  760. if kvp["map3d"]:
  761. kvp["primitives"] += kvp["faces"] + kvp["kernels"]
  762. # Read topology information
  763. kvp["nodes"] = libvector.Vect_get_num_nodes(byref(Map))
  764. kvp["areas"] = libvector.Vect_get_num_areas(byref(Map))
  765. kvp["islands"] = libvector.Vect_get_num_islands(byref(Map))
  766. kvp["holes"] = libvector.Vect_get_num_holes(byref(Map))
  767. kvp["volumes"] = libvector.Vect_get_num_primitives(
  768. byref(Map), libvector.GV_VOLUME
  769. )
  770. else:
  771. kvp["points"] = None
  772. kvp["lines"] = None
  773. kvp["boundaries"] = None
  774. kvp["centroids"] = None
  775. kvp["faces"] = None
  776. kvp["kernels"] = None
  777. kvp["primitives"] = None
  778. kvp["nodes"] = None
  779. kvp["areas"] = None
  780. kvp["islands"] = None
  781. kvp["holes"] = None
  782. kvp["volumes"] = None
  783. libvector.Vect_close(byref(Map))
  784. return kvp
  785. ###############################################################################
  786. def _convert_timestamp_from_grass(ts):
  787. """Convert a GRASS file based timestamp into the temporal framework
  788. format datetime or integer.
  789. A tuple of two datetime objects (start, end) is returned in case of
  790. absolute time.
  791. In case of relative time a tuple with start time, end time and the
  792. relative unit (start, end, unit) will be returned.
  793. Note:
  794. The end time will be set to None in case of a time instance.
  795. :param ts grass.lib.gis.TimeStamp object created by G_read_*_timestamp
  796. """
  797. dt1 = libgis.DateTime()
  798. dt2 = libgis.DateTime()
  799. count = c_int()
  800. libgis.G_get_timestamps(byref(ts), byref(dt1), byref(dt2), byref(count))
  801. if dt1.mode == libdate.DATETIME_ABSOLUTE:
  802. pdt1 = None
  803. pdt2 = None
  804. if count.value >= 1:
  805. pdt1 = datetime(
  806. int(dt1.year),
  807. int(dt1.month),
  808. int(dt1.day),
  809. int(dt1.hour),
  810. int(dt1.minute),
  811. int(dt1.second),
  812. )
  813. if count.value == 2:
  814. pdt2 = datetime(
  815. int(dt2.year),
  816. int(dt2.month),
  817. int(dt2.day),
  818. int(dt2.hour),
  819. int(dt2.minute),
  820. int(dt2.second),
  821. )
  822. # ATTENTION: We ignore the time zone
  823. # TODO: Write time zone support
  824. return (pdt1, pdt2)
  825. else:
  826. unit = None
  827. start = None
  828. end = None
  829. if count.value >= 1:
  830. if dt1.year > 0:
  831. unit = "years"
  832. start = dt1.year
  833. elif dt1.month > 0:
  834. unit = "months"
  835. start = dt1.month
  836. elif dt1.day > 0:
  837. unit = "days"
  838. start = dt1.day
  839. elif dt1.hour > 0:
  840. unit = "hours"
  841. start = dt1.hour
  842. elif dt1.minute > 0:
  843. unit = "minutes"
  844. start = dt1.minute
  845. elif dt1.second > 0:
  846. unit = "seconds"
  847. start = dt1.second
  848. if count.value == 2:
  849. if dt2.year > 0:
  850. end = dt2.year
  851. elif dt2.month > 0:
  852. end = dt2.month
  853. elif dt2.day > 0:
  854. end = dt2.day
  855. elif dt2.hour > 0:
  856. end = dt2.hour
  857. elif dt2.minute > 0:
  858. end = dt2.minute
  859. elif dt2.second > 0:
  860. end = dt2.second
  861. return (start, end, unit)
  862. ###############################################################################
  863. def _stop(lock, conn, data):
  864. libgis.G_debug(1, "Stop C-interface server")
  865. conn.close()
  866. lock.release()
  867. sys.exit()
  868. ###############################################################################
  869. def c_library_server(lock, conn):
  870. """The GRASS C-libraries server function designed to be a target for
  871. multiprocessing.Process
  872. :param lock: A multiprocessing.Lock
  873. :param conn: A multiprocessing.Pipe
  874. """
  875. def error_handler(data):
  876. """This function will be called in case of a fatal error in libgis"""
  877. # sys.stderr.write("Error handler was called\n")
  878. # We send an exception that will be handled in
  879. # the parent process, then close the pipe
  880. # and release any possible lock
  881. conn.send(FatalError())
  882. conn.close()
  883. lock.release()
  884. CALLBACK = CFUNCTYPE(c_void_p, c_void_p)
  885. CALLBACK.restype = c_void_p
  886. CALLBACK.argtypes = c_void_p
  887. cerror_handler = CALLBACK(error_handler)
  888. libgis.G_add_error_handler(cerror_handler, None)
  889. # Crerate the function array
  890. functions = [0] * 50
  891. functions[RPCDefs.STOP] = _stop
  892. functions[RPCDefs.HAS_TIMESTAMP] = _has_timestamp
  893. functions[RPCDefs.WRITE_TIMESTAMP] = _write_timestamp
  894. functions[RPCDefs.READ_TIMESTAMP] = _read_timestamp
  895. functions[RPCDefs.REMOVE_TIMESTAMP] = _remove_timestamp
  896. functions[RPCDefs.READ_MAP_INFO] = _read_map_info
  897. functions[RPCDefs.MAP_EXISTS] = _map_exists
  898. functions[RPCDefs.AVAILABLE_MAPSETS] = _available_mapsets
  899. functions[RPCDefs.GET_DRIVER_NAME] = _get_driver_name
  900. functions[RPCDefs.GET_DATABASE_NAME] = _get_database_name
  901. functions[RPCDefs.G_MAPSET] = _get_mapset
  902. functions[RPCDefs.G_LOCATION] = _get_location
  903. functions[RPCDefs.G_GISDBASE] = _get_gisdbase
  904. functions[RPCDefs.READ_MAP_FULL_INFO] = _read_map_full_info
  905. functions[RPCDefs.WRITE_BAND_REFERENCE] = _write_band_reference
  906. functions[RPCDefs.READ_BAND_REFERENCE] = _read_band_reference
  907. functions[RPCDefs.REMOVE_BAND_REFERENCE] = _remove_band_reference
  908. functions[RPCDefs.G_FATAL_ERROR] = _fatal_error
  909. libgis.G_gisinit("c_library_server")
  910. libgis.G_debug(1, "Start C-interface server")
  911. while True:
  912. # Avoid busy waiting
  913. conn.poll(None)
  914. data = conn.recv()
  915. lock.acquire()
  916. functions[data[0]](lock, conn, data)
  917. lock.release()
  918. class CLibrariesInterface(RPCServerBase):
  919. """Fast and exit-safe interface to GRASS C-libraries functions
  920. This class implements a fast and exit-safe interface to the GRASS
  921. gis, raster, 3D raster and vector C-libraries functions.
  922. The C-libraries functions are called via ctypes in a subprocess
  923. using a pipe (multiprocessing.Pipe) to transfer the text messages.
  924. Hence, the process that uses the CLibrariesInterface will not be
  925. exited, if a G_fatal_error() was invoked in the subprocess.
  926. In this case the CLibrariesInterface object will simply start a
  927. new subprocess and restarts the pipeline.
  928. Usage:
  929. .. code-block:: python
  930. >>> import grass.script as gscript
  931. >>> import grass.temporal as tgis
  932. >>> gscript.use_temp_region()
  933. >>> gscript.run_command("g.region", n=80.0, s=0.0, e=120.0, w=0.0,
  934. ... t=1.0, b=0.0, res=10.0, res3=10.0)
  935. 0
  936. >>> tgis.init()
  937. >>> gscript.run_command("r.mapcalc", expression="test = 1", overwrite=True, quiet=True)
  938. 0
  939. >>> gscript.run_command("r3.mapcalc", expression="test = 1", overwrite=True, quiet=True)
  940. 0
  941. >>> gscript.run_command("v.random", output="test", n=10, overwrite=True, quiet=True)
  942. 0
  943. >>> gscript.run_command("r.timestamp", map="test", date='12 Mar 1995 10:34:40', overwrite=True, quiet=True)
  944. 0
  945. >>> gscript.run_command("r3.timestamp", map="test", date='12 Mar 1995 10:34:40', overwrite=True, quiet=True)
  946. 0
  947. >>> gscript.run_command("v.timestamp", map="test", date='12 Mar 1995 10:34:40', overwrite=True, quiet=True)
  948. 0
  949. # Check mapsets
  950. >>> ciface = tgis.CLibrariesInterface()
  951. >>> mapsets = ciface.available_mapsets()
  952. >>> mapsets[0] == tgis.get_current_mapset()
  953. True
  954. # Raster map
  955. >>> ciface = tgis.CLibrariesInterface()
  956. >>> check = ciface.raster_map_exists("test", tgis.get_current_mapset())
  957. >>> print check
  958. True
  959. >>> ciface.read_raster_info("test", tgis.get_current_mapset())
  960. {'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}
  961. >>> info = ciface.read_raster_full_info("test", tgis.get_current_mapset())
  962. >>> info # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
  963. {u'tbres': 1.0, ... 'keyword': 'generated by r.mapcalc',
  964. u'bottom': 0.0, 'end_time': None, 'title': 'test', u'south': 0.0}
  965. >>> info["start_time"]
  966. datetime.datetime(1995, 3, 12, 10, 34, 40)
  967. >>> info["end_time"]
  968. >>> check = ciface.has_raster_timestamp("test", tgis.get_current_mapset())
  969. >>> print check
  970. True
  971. >>> if check:
  972. ... res = ciface.read_raster_timestamp("test", tgis.get_current_mapset())
  973. ... if res[0]:
  974. ... print str(res[1][0]), str(res[1][0])
  975. ... ciface.remove_raster_timestamp("test", tgis.get_current_mapset())
  976. 1995-03-12 10:34:40 1995-03-12 10:34:40
  977. 1
  978. >>> ciface.has_raster_timestamp("test", tgis.get_current_mapset())
  979. False
  980. >>> ciface.write_raster_timestamp("test", tgis.get_current_mapset(), "13 Jan 1999 14:30:05")
  981. 1
  982. >>> ciface.has_raster_timestamp("test", tgis.get_current_mapset())
  983. True
  984. # 3D raster map
  985. >>> check = ciface.raster3d_map_exists("test", tgis.get_current_mapset())
  986. >>> print check
  987. True
  988. >>> ciface.read_raster3d_info("test", tgis.get_current_mapset())
  989. {'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}
  990. >>> check = ciface.has_raster3d_timestamp("test", tgis.get_current_mapset())
  991. >>> print check
  992. True
  993. >>> if check:
  994. ... res = ciface.read_raster3d_timestamp("test", tgis.get_current_mapset())
  995. ... if res[0]:
  996. ... print str(res[1][0]), str(res[1][0])
  997. ... ciface.remove_raster3d_timestamp("test", tgis.get_current_mapset())
  998. 1995-03-12 10:34:40 1995-03-12 10:34:40
  999. 1
  1000. >>> ciface.has_raster3d_timestamp("test", tgis.get_current_mapset())
  1001. False
  1002. >>> ciface.write_raster3d_timestamp("test", tgis.get_current_mapset(), "13 Jan 1999 14:30:05")
  1003. 1
  1004. >>> ciface.has_raster3d_timestamp("test", tgis.get_current_mapset())
  1005. True
  1006. # Vector map
  1007. >>> check = ciface.vector_map_exists("test", tgis.get_current_mapset())
  1008. >>> print check
  1009. True
  1010. >>> kvp = ciface.read_vector_info("test", tgis.get_current_mapset())
  1011. >>> kvp['points']
  1012. 10
  1013. >>> kvp = ciface.read_vector_full_info("test", tgis.get_current_mapset())
  1014. >>> print kvp['points']
  1015. 10
  1016. >>> kvp['point']
  1017. 10
  1018. >>> kvp['area']
  1019. 0
  1020. >>> kvp['lines']
  1021. 0
  1022. >>> kvp['line']
  1023. 0
  1024. >>> 'columns' in kvp
  1025. False
  1026. >>> kvp["start_time"]
  1027. datetime.datetime(1995, 3, 12, 10, 34, 40)
  1028. >>> kvp["end_time"]
  1029. >>> check = ciface.has_vector_timestamp("test", tgis.get_current_mapset(), None)
  1030. >>> print check
  1031. True
  1032. >>> if check:
  1033. ... res = ciface.read_vector_timestamp("test", tgis.get_current_mapset())
  1034. ... if res[0]:
  1035. ... print str(res[1][0]), str(res[1][0])
  1036. ... ciface.remove_vector_timestamp("test", tgis.get_current_mapset())
  1037. 1995-03-12 10:34:40 1995-03-12 10:34:40
  1038. 1
  1039. >>> ciface.has_vector_timestamp("test", tgis.get_current_mapset())
  1040. False
  1041. >>> ciface.write_vector_timestamp("test", tgis.get_current_mapset(), "13 Jan 1999 14:30:05")
  1042. 1
  1043. >>> ciface.has_vector_timestamp("test", tgis.get_current_mapset())
  1044. True
  1045. >>> ciface.get_driver_name()
  1046. 'sqlite'
  1047. >>> ciface.get_database_name().split("/")[-1]
  1048. 'sqlite.db'
  1049. >>> mapset = ciface.get_mapset()
  1050. >>> location = ciface.get_location()
  1051. >>> gisdbase = ciface.get_gisdbase()
  1052. >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
  1053. Traceback (most recent call last):
  1054. raise FatalError("Exception raised: " + str(e) + " Message: " + message)
  1055. FatalError: Exception raised: ...
  1056. >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
  1057. Traceback (most recent call last):
  1058. raise FatalError("Exception raised: " + str(e) + " Message: " + message)
  1059. FatalError: Exception raised: ...
  1060. >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
  1061. Traceback (most recent call last):
  1062. raise FatalError("Exception raised: " + str(e) + " Message: " + message)
  1063. FatalError: Exception raised: ...
  1064. >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
  1065. Traceback (most recent call last):
  1066. raise FatalError("Exception raised: " + str(e) + " Message: " + message)
  1067. FatalError: Exception raised: ...
  1068. >>> ciface.stop()
  1069. >>> gscript.del_temp_region()
  1070. """
  1071. def __init__(self):
  1072. RPCServerBase.__init__(self)
  1073. def start_server(self):
  1074. self.client_conn, self.server_conn = Pipe(True)
  1075. self.lock = Lock()
  1076. self.server = Process(
  1077. target=c_library_server, args=(self.lock, self.server_conn)
  1078. )
  1079. self.server.daemon = True
  1080. self.server.start()
  1081. def raster_map_exists(self, name, mapset):
  1082. """Check if a raster map exists in the spatial database
  1083. :param name: The name of the map
  1084. :param mapset: The mapset of the map
  1085. :returns: True if exists, False if not
  1086. """
  1087. self.check_server()
  1088. self.client_conn.send(
  1089. [RPCDefs.MAP_EXISTS, RPCDefs.TYPE_RASTER, name, mapset, None]
  1090. )
  1091. return self.safe_receive("raster_map_exists")
  1092. def read_raster_info(self, name, mapset):
  1093. """Read the raster map info from the file system and store the content
  1094. into a dictionary
  1095. :param name: The name of the map
  1096. :param mapset: The mapset of the map
  1097. :returns: The key value pairs of the map specific metadata,
  1098. or None in case of an error
  1099. """
  1100. self.check_server()
  1101. self.client_conn.send(
  1102. [RPCDefs.READ_MAP_INFO, RPCDefs.TYPE_RASTER, name, mapset, None]
  1103. )
  1104. return self.safe_receive("read_raster_info")
  1105. def read_raster_full_info(self, name, mapset):
  1106. """Read raster info, history and cats using PyGRASS RasterRow
  1107. and return a dictionary. Colors should be supported in the
  1108. future.
  1109. :param name: The name of the map
  1110. :param mapset: The mapset of the map
  1111. :returns: The key value pairs of the map specific metadata,
  1112. or None in case of an error
  1113. """
  1114. self.check_server()
  1115. self.client_conn.send(
  1116. [RPCDefs.READ_MAP_FULL_INFO, RPCDefs.TYPE_RASTER, name, mapset, None]
  1117. )
  1118. return self.safe_receive("read_raster_full_info")
  1119. def has_raster_timestamp(self, name, mapset):
  1120. """Check if a file based raster timestamp exists
  1121. :param name: The name of the map
  1122. :param mapset: The mapset of the map
  1123. :returns: True if exists, False if not
  1124. """
  1125. self.check_server()
  1126. self.client_conn.send(
  1127. [RPCDefs.HAS_TIMESTAMP, RPCDefs.TYPE_RASTER, name, mapset, None]
  1128. )
  1129. return self.safe_receive("has_raster_timestamp")
  1130. def remove_raster_timestamp(self, name, mapset):
  1131. """Remove a file based raster timestamp
  1132. Please have a look at the documentation G_remove_raster_timestamp
  1133. for the return values description.
  1134. :param name: The name of the map
  1135. :param mapset: The mapset of the map
  1136. :returns: The return value of G_remove_raster_timestamp
  1137. """
  1138. self.check_server()
  1139. self.client_conn.send(
  1140. [RPCDefs.REMOVE_TIMESTAMP, RPCDefs.TYPE_RASTER, name, mapset, None]
  1141. )
  1142. return self.safe_receive("remove_raster_timestamp")
  1143. def read_raster_timestamp(self, name, mapset):
  1144. """Read a file based raster timestamp
  1145. Please have a look at the documentation G_read_raster_timestamp
  1146. for the return values description.
  1147. The timestamps to be send are tuples of values:
  1148. - relative time (start, end, unit), start and end are of type
  1149. integer, unit is of type string.
  1150. - absolute time (start, end), start and end are of type datetime
  1151. The end time may be None in case of a time instance.
  1152. :param name: The name of the map
  1153. :param mapset: The mapset of the map
  1154. :returns: The return value of G_read_raster_timestamp
  1155. """
  1156. self.check_server()
  1157. self.client_conn.send(
  1158. [RPCDefs.READ_TIMESTAMP, RPCDefs.TYPE_RASTER, name, mapset, None]
  1159. )
  1160. return self.safe_receive("read_raster_timestamp")
  1161. def write_raster_timestamp(self, name, mapset, timestring):
  1162. """Write a file based raster timestamp
  1163. Please have a look at the documentation G_write_raster_timestamp
  1164. for the return values description.
  1165. Note:
  1166. Only timestamps of maps from the current mapset can written.
  1167. :param name: The name of the map
  1168. :param mapset: The mapset of the map
  1169. :param timestring: A GRASS datetime C-library compatible string
  1170. :returns: The return value of G_write_raster_timestamp
  1171. """
  1172. self.check_server()
  1173. self.client_conn.send(
  1174. [
  1175. RPCDefs.WRITE_TIMESTAMP,
  1176. RPCDefs.TYPE_RASTER,
  1177. name,
  1178. mapset,
  1179. None,
  1180. timestring,
  1181. ]
  1182. )
  1183. return self.safe_receive("write_raster_timestamp")
  1184. def remove_raster_band_reference(self, name, mapset):
  1185. """Remove a file based raster band reference
  1186. Please have a look at the documentation Rast_remove_band_reference
  1187. for the return values description.
  1188. :param name: The name of the map
  1189. :param mapset: The mapset of the map
  1190. :returns: The return value of Rast_remove_band_reference
  1191. """
  1192. self.check_server()
  1193. self.client_conn.send(
  1194. [RPCDefs.REMOVE_BAND_REFERENCE, RPCDefs.TYPE_RASTER, name, mapset, None]
  1195. )
  1196. return self.safe_receive("remove_raster_timestamp")
  1197. def read_raster_band_reference(self, name, mapset):
  1198. """Read a file based raster band reference
  1199. Please have a look at the documentation Rast_read_band_reference
  1200. for the return values description.
  1201. :param name: The name of the map
  1202. :param mapset: The mapset of the map
  1203. :returns: The return value of Rast_read_band_reference
  1204. """
  1205. self.check_server()
  1206. self.client_conn.send(
  1207. [RPCDefs.READ_BAND_REFERENCE, RPCDefs.TYPE_RASTER, name, mapset, None]
  1208. )
  1209. return self.safe_receive("read_raster_band_reference")
  1210. def write_raster_band_reference(self, name, mapset, band_reference):
  1211. """Write a file based raster band reference
  1212. Please have a look at the documentation Rast_write_band_reference
  1213. for the return values description.
  1214. Note:
  1215. Only band references of maps from the current mapset can written.
  1216. :param name: The name of the map
  1217. :param mapset: The mapset of the map
  1218. :param band_reference: band reference identifier
  1219. :returns: The return value of Rast_write_band_reference
  1220. """
  1221. self.check_server()
  1222. self.client_conn.send(
  1223. [
  1224. RPCDefs.WRITE_BAND_REFERENCE,
  1225. RPCDefs.TYPE_RASTER,
  1226. name,
  1227. mapset,
  1228. None,
  1229. band_reference,
  1230. ]
  1231. )
  1232. return self.safe_receive("write_raster_band_reference")
  1233. def raster3d_map_exists(self, name, mapset):
  1234. """Check if a 3D raster map exists in the spatial database
  1235. :param name: The name of the map
  1236. :param mapset: The mapset of the map
  1237. :returns: True if exists, False if not
  1238. """
  1239. self.check_server()
  1240. self.client_conn.send(
  1241. [RPCDefs.MAP_EXISTS, RPCDefs.TYPE_RASTER3D, name, mapset, None]
  1242. )
  1243. return self.safe_receive("raster3d_map_exists")
  1244. def read_raster3d_info(self, name, mapset):
  1245. """Read the 3D raster map info from the file system and store the content
  1246. into a dictionary
  1247. :param name: The name of the map
  1248. :param mapset: The mapset of the map
  1249. :returns: The key value pairs of the map specific metadata,
  1250. or None in case of an error
  1251. """
  1252. self.check_server()
  1253. self.client_conn.send(
  1254. [RPCDefs.READ_MAP_INFO, RPCDefs.TYPE_RASTER3D, name, mapset, None]
  1255. )
  1256. return self.safe_receive("read_raster3d_info")
  1257. def has_raster3d_timestamp(self, name, mapset):
  1258. """Check if a file based 3D raster timestamp exists
  1259. :param name: The name of the map
  1260. :param mapset: The mapset of the map
  1261. :returns: True if exists, False if not
  1262. """
  1263. self.check_server()
  1264. self.client_conn.send(
  1265. [RPCDefs.HAS_TIMESTAMP, RPCDefs.TYPE_RASTER3D, name, mapset, None]
  1266. )
  1267. return self.safe_receive("has_raster3d_timestamp")
  1268. def remove_raster3d_timestamp(self, name, mapset):
  1269. """Remove a file based 3D raster timestamp
  1270. Please have a look at the documentation G_remove_raster3d_timestamp
  1271. for the return values description.
  1272. :param name: The name of the map
  1273. :param mapset: The mapset of the map
  1274. :returns: The return value of G_remove_raster3d_timestamp
  1275. """
  1276. self.check_server()
  1277. self.client_conn.send(
  1278. [RPCDefs.REMOVE_TIMESTAMP, RPCDefs.TYPE_RASTER3D, name, mapset, None]
  1279. )
  1280. return self.safe_receive("remove_raster3d_timestamp")
  1281. def read_raster3d_timestamp(self, name, mapset):
  1282. """Read a file based 3D raster timestamp
  1283. Please have a look at the documentation G_read_raster3d_timestamp
  1284. for the return values description.
  1285. The timestamps to be send are tuples of values:
  1286. - relative time (start, end, unit), start and end are of type
  1287. integer, unit is of type string.
  1288. - absolute time (start, end), start and end are of type datetime
  1289. The end time may be None in case of a time instance.
  1290. :param name: The name of the map
  1291. :param mapset: The mapset of the map
  1292. :returns: The return value of G_read_raster3d_timestamp
  1293. """
  1294. self.check_server()
  1295. self.client_conn.send(
  1296. [RPCDefs.READ_TIMESTAMP, RPCDefs.TYPE_RASTER3D, name, mapset, None]
  1297. )
  1298. return self.safe_receive("read_raster3d_timestamp")
  1299. def write_raster3d_timestamp(self, name, mapset, timestring):
  1300. """Write a file based 3D raster timestamp
  1301. Please have a look at the documentation G_write_raster3d_timestamp
  1302. for the return values description.
  1303. Note:
  1304. Only timestamps of maps from the current mapset can written.
  1305. :param name: The name of the map
  1306. :param mapset: The mapset of the map
  1307. :param timestring: A GRASS datetime C-library compatible string
  1308. :returns: The return value of G_write_raster3d_timestamp
  1309. """
  1310. self.check_server()
  1311. self.client_conn.send(
  1312. [
  1313. RPCDefs.WRITE_TIMESTAMP,
  1314. RPCDefs.TYPE_RASTER3D,
  1315. name,
  1316. mapset,
  1317. None,
  1318. timestring,
  1319. ]
  1320. )
  1321. return self.safe_receive("write_raster3d_timestamp")
  1322. def vector_map_exists(self, name, mapset):
  1323. """Check if a vector map exists in the spatial database
  1324. :param name: The name of the map
  1325. :param mapset: The mapset of the map
  1326. :returns: True if exists, False if not
  1327. """
  1328. self.check_server()
  1329. self.client_conn.send(
  1330. [RPCDefs.MAP_EXISTS, RPCDefs.TYPE_VECTOR, name, mapset, None]
  1331. )
  1332. return self.safe_receive("vector_map_exists")
  1333. def read_vector_info(self, name, mapset):
  1334. """Read the vector map info from the file system and store the content
  1335. into a dictionary
  1336. :param name: The name of the map
  1337. :param mapset: The mapset of the map
  1338. :returns: The key value pairs of the map specific metadata,
  1339. or None in case of an error
  1340. """
  1341. self.check_server()
  1342. self.client_conn.send(
  1343. [RPCDefs.READ_MAP_INFO, RPCDefs.TYPE_VECTOR, name, mapset, None]
  1344. )
  1345. return self.safe_receive("read_vector_info")
  1346. def read_vector_full_info(self, name, mapset):
  1347. """Read vector info using PyGRASS VectorTopo
  1348. and return a dictionary.
  1349. :param name: The name of the map
  1350. :param mapset: The mapset of the map
  1351. :returns: The key value pairs of the map specific metadata,
  1352. or None in case of an error
  1353. """
  1354. self.check_server()
  1355. self.client_conn.send(
  1356. [RPCDefs.READ_MAP_FULL_INFO, RPCDefs.TYPE_VECTOR, name, mapset, None]
  1357. )
  1358. return self.safe_receive("read_vector_full_info")
  1359. def has_vector_timestamp(self, name, mapset, layer=None):
  1360. """Check if a file based vector timestamp exists
  1361. :param name: The name of the map
  1362. :param mapset: The mapset of the map
  1363. :param layer: The layer of the vector map
  1364. :returns: True if exists, False if not
  1365. """
  1366. self.check_server()
  1367. self.client_conn.send(
  1368. [RPCDefs.HAS_TIMESTAMP, RPCDefs.TYPE_VECTOR, name, mapset, layer]
  1369. )
  1370. return self.safe_receive("has_vector_timestamp")
  1371. def remove_vector_timestamp(self, name, mapset, layer=None):
  1372. """Remove a file based vector timestamp
  1373. Please have a look at the documentation G_remove_vector_timestamp
  1374. for the return values description.
  1375. :param name: The name of the map
  1376. :param mapset: The mapset of the map
  1377. :param layer: The layer of the vector map
  1378. :returns: The return value of G_remove_vector_timestamp
  1379. """
  1380. self.check_server()
  1381. self.client_conn.send(
  1382. [RPCDefs.REMOVE_TIMESTAMP, RPCDefs.TYPE_VECTOR, name, mapset, layer]
  1383. )
  1384. return self.safe_receive("remove_vector_timestamp")
  1385. def read_vector_timestamp(self, name, mapset, layer=None):
  1386. """Read a file based vector timestamp
  1387. Please have a look at the documentation G_read_vector_timestamp
  1388. for the return values description.
  1389. The timestamps to be send are tuples of values:
  1390. - relative time (start, end, unit), start and end are of type
  1391. integer, unit is of type string.
  1392. - absolute time (start, end), start and end are of type datetime
  1393. The end time may be None in case of a time instance.
  1394. :param name: The name of the map
  1395. :param mapset: The mapset of the map
  1396. :param layer: The layer of the vector map
  1397. :returns: The return value ofG_read_vector_timestamp and the timestamps
  1398. """
  1399. self.check_server()
  1400. self.client_conn.send(
  1401. [RPCDefs.READ_TIMESTAMP, RPCDefs.TYPE_VECTOR, name, mapset, layer]
  1402. )
  1403. return self.safe_receive("read_vector_timestamp")
  1404. def write_vector_timestamp(self, name, mapset, timestring, layer=None):
  1405. """Write a file based vector timestamp
  1406. Please have a look at the documentation G_write_vector_timestamp
  1407. for the return values description.
  1408. Note:
  1409. Only timestamps pf maps from the current mapset can written.
  1410. :param name: The name of the map
  1411. :param mapset: The mapset of the map
  1412. :param timestring: A GRASS datetime C-library compatible string
  1413. :param layer: The layer of the vector map
  1414. :returns: The return value of G_write_vector_timestamp
  1415. """
  1416. self.check_server()
  1417. self.client_conn.send(
  1418. [
  1419. RPCDefs.WRITE_TIMESTAMP,
  1420. RPCDefs.TYPE_VECTOR,
  1421. name,
  1422. mapset,
  1423. layer,
  1424. timestring,
  1425. ]
  1426. )
  1427. return self.safe_receive("write_vector_timestamp")
  1428. def available_mapsets(self):
  1429. """Return all available mapsets the user can access as a list of strings
  1430. :returns: Names of available mapsets as list of strings
  1431. """
  1432. self.check_server()
  1433. self.client_conn.send(
  1434. [
  1435. RPCDefs.AVAILABLE_MAPSETS,
  1436. ]
  1437. )
  1438. return self.safe_receive("available_mapsets")
  1439. def get_driver_name(self, mapset=None):
  1440. """Return the temporal database driver of a specific mapset
  1441. :param mapset: Name of the mapset
  1442. :returns: Name of the driver or None if no temporal database present
  1443. """
  1444. self.check_server()
  1445. self.client_conn.send([RPCDefs.GET_DRIVER_NAME, mapset])
  1446. return self.safe_receive("get_driver_name")
  1447. def get_database_name(self, mapset=None):
  1448. """Return the temporal database name of a specific mapset
  1449. :param mapset: Name of the mapset
  1450. :returns: Name of the database or None if no temporal database present
  1451. """
  1452. self.check_server()
  1453. self.client_conn.send([RPCDefs.GET_DATABASE_NAME, mapset])
  1454. return self.safe_receive("get_database_name")
  1455. def get_mapset(self):
  1456. """Return the current mapset
  1457. :returns: Name of the current mapset
  1458. """
  1459. self.check_server()
  1460. self.client_conn.send(
  1461. [
  1462. RPCDefs.G_MAPSET,
  1463. ]
  1464. )
  1465. return self.safe_receive("get_mapset")
  1466. def get_location(self):
  1467. """Return the location
  1468. :returns: Name of the location
  1469. """
  1470. self.check_server()
  1471. self.client_conn.send(
  1472. [
  1473. RPCDefs.G_LOCATION,
  1474. ]
  1475. )
  1476. return self.safe_receive("get_location")
  1477. def get_gisdbase(self):
  1478. """Return the gisdatabase
  1479. :returns: Name of the gisdatabase
  1480. """
  1481. self.check_server()
  1482. self.client_conn.send(
  1483. [
  1484. RPCDefs.G_GISDBASE,
  1485. ]
  1486. )
  1487. return self.safe_receive("get_gisdbase")
  1488. def fatal_error(self, mapset=None):
  1489. """Generate a fatal error in libgis.
  1490. This function is only for testing purpose.
  1491. """
  1492. self.check_server()
  1493. self.client_conn.send([RPCDefs.G_FATAL_ERROR])
  1494. # The pipe should be closed in the checker thread
  1495. return self.safe_receive("Fatal error")
  1496. if __name__ == "__main__":
  1497. import doctest
  1498. doctest.testmod()