c_libraries_interface.py 54 KB

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