c_libraries_interface.py 53 KB

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