c_libraries_interface.py 54 KB

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