c_libraries_interface.py 53 KB

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