utils.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. # -*- coding: utf-8 -*-
  2. import itertools
  3. import fnmatch
  4. import os
  5. from sqlite3 import OperationalError
  6. import grass.lib.gis as libgis
  7. libgis.G_gisinit('')
  8. import grass.lib.raster as libraster
  9. from grass.script import core as grasscore
  10. from grass.pygrass.errors import GrassError
  11. def looking(obj, filter_string):
  12. """
  13. >>> import grass.lib.vector as libvect
  14. >>> sorted(looking(libvect, '*by_box*')) # doctest: +NORMALIZE_WHITESPACE
  15. ['Vect_select_areas_by_box', 'Vect_select_isles_by_box',
  16. 'Vect_select_lines_by_box', 'Vect_select_nodes_by_box']
  17. """
  18. word_list = dir(obj)
  19. word_list.sort()
  20. return fnmatch.filter(word_list, filter_string)
  21. def findfiles(dirpath, match=None):
  22. """Return a list of the files"""
  23. res = []
  24. for f in sorted(os.listdir(dirpath)):
  25. abspath = os.path.join(dirpath, f)
  26. if os.path.isdir(abspath):
  27. res.extend(findfiles(abspath, match))
  28. if match:
  29. if fnmatch.fnmatch(abspath, match):
  30. res.append(abspath)
  31. else:
  32. res.append(abspath)
  33. return res
  34. def findmaps(type, pattern=None, mapset='', location='', gisdbase=''):
  35. """Return a list of tuple contining the names of the:
  36. * map
  37. * mapset,
  38. * location,
  39. * gisdbase
  40. """
  41. from grass.pygrass.gis import Gisdbase, Location, Mapset
  42. def find_in_location(type, pattern, location):
  43. res = []
  44. for msetname in location.mapsets():
  45. mset = Mapset(msetname, location.name, location.gisdbase)
  46. res.extend([(m, mset.name, mset.location, mset.gisdbase)
  47. for m in mset.glist(type, pattern)])
  48. return res
  49. def find_in_gisdbase(type, pattern, gisdbase):
  50. res = []
  51. for loc in gisdbase.locations():
  52. res.extend(find_in_location(type, pattern,
  53. Location(loc, gisdbase.name)))
  54. return res
  55. if gisdbase and location and mapset:
  56. mset = Mapset(mapset, location, gisdbase)
  57. return [(m, mset.name, mset.location, mset.gisdbase)
  58. for m in mset.glist(type, pattern)]
  59. elif gisdbase and location:
  60. loc = Location(location, gisdbase)
  61. return find_in_location(type, pattern, loc)
  62. elif gisdbase:
  63. gis = Gisdbase(gisdbase)
  64. return find_in_gisdbase(type, pattern, gis)
  65. elif location:
  66. loc = Location(location)
  67. return find_in_location(type, pattern, loc)
  68. elif mapset:
  69. mset = Mapset(mapset)
  70. return [(m, mset.name, mset.location, mset.gisdbase)
  71. for m in mset.glist(type, pattern)]
  72. else:
  73. gis = Gisdbase()
  74. return find_in_gisdbase(type, pattern, gis)
  75. def remove(oldname, maptype):
  76. """Remove a map"""
  77. grasscore.run_command('g.remove', quiet=True, flags='f',
  78. type=maptype, name=oldname)
  79. def rename(oldname, newname, maptype, **kwargs):
  80. """Rename a map"""
  81. kwargs.update({maptype: '{old},{new}'.format(old=oldname, new=newname), })
  82. grasscore.run_command('g.rename', quiet=True, **kwargs)
  83. def copy(existingmap, newmap, maptype, **kwargs):
  84. """Copy a map
  85. >>> copy('census', 'mycensus', 'vect')
  86. >>> rename('mycensus', 'mynewcensus', 'vect')
  87. >>> remove('mynewcensus', 'vect')
  88. """
  89. kwargs.update({maptype: '{old},{new}'.format(old=existingmap, new=newmap)})
  90. grasscore.run_command('g.copy', quiet=True, **kwargs)
  91. def getenv(env):
  92. """Return the current grass environment variables
  93. >>> getenv("MAPSET")
  94. 'user1'
  95. """
  96. return libgis.G_getenv_nofatal(env)
  97. def get_mapset_raster(mapname, mapset=''):
  98. """Return the mapset of the raster map
  99. >>> get_mapset_raster('elevation')
  100. 'PERMANENT'
  101. """
  102. return libgis.G_find_raster2(mapname, mapset)
  103. def get_mapset_vector(mapname, mapset=''):
  104. """Return the mapset of the vector map
  105. >>> get_mapset_vector('census')
  106. 'PERMANENT'
  107. """
  108. return libgis.G_find_vector2(mapname, mapset)
  109. def is_clean_name(name):
  110. """Return if the name is valid
  111. >>> is_clean_name('census')
  112. True
  113. >>> is_clean_name('0census')
  114. True
  115. >>> is_clean_name('census?')
  116. False
  117. >>> is_clean_name('cénsus')
  118. False
  119. """
  120. if libgis.G_legal_filename(name) < 0:
  121. return False
  122. return True
  123. def coor2pixel(coord, region):
  124. """Convert coordinates into a pixel row and col
  125. >>> reg = Region()
  126. >>> coor2pixel((reg.west, reg.north), reg)
  127. (0.0, 0.0)
  128. >>> coor2pixel((reg.east, reg.south), reg) == (reg.rows, reg.cols)
  129. True
  130. """
  131. (east, north) = coord
  132. return (libraster.Rast_northing_to_row(north, region.c_region),
  133. libraster.Rast_easting_to_col(east, region.c_region))
  134. def pixel2coor(pixel, region):
  135. """Convert row and col of a pixel into a coordinates
  136. >>> reg = Region()
  137. >>> pixel2coor((0, 0), reg) == (reg.north, reg.west)
  138. True
  139. >>> pixel2coor((reg.cols, reg.rows), reg) == (reg.south, reg.east)
  140. True
  141. """
  142. (col, row) = pixel
  143. return (libraster.Rast_row_to_northing(row, region.c_region),
  144. libraster.Rast_col_to_easting(col, region.c_region))
  145. def get_raster_for_points(poi_vector, raster, column=None, region=None):
  146. """Query a raster map for each point feature of a vector
  147. Example
  148. >>> from grass.pygrass.vector import VectorTopo
  149. >>> from grass.pygrass.raster import RasterRow
  150. >>> ele = RasterRow('elevation')
  151. >>> copy('schools','myschools','vect')
  152. >>> sch = VectorTopo('myschools')
  153. >>> sch.open(mode='r')
  154. >>> get_raster_for_points(sch, ele) # doctest: +ELLIPSIS
  155. [(1, 633649.2856743174, 221412.94434781274, 145.06602)...
  156. >>> sch.table.columns.add('elevation','double precision')
  157. >>> 'elevation' in sch.table.columns
  158. True
  159. >>> get_raster_for_points(sch, ele, 'elevation')
  160. True
  161. >>> sch.table.filters.select('NAMESHORT','elevation')
  162. Filters(u'SELECT NAMESHORT, elevation FROM myschools;')
  163. >>> cur = sch.table.execute()
  164. >>> cur.fetchall() # doctest: +ELLIPSIS
  165. [(u'SWIFT CREEK', 145.06602), ... (u'9TH GRADE CTR', None)]
  166. >>> remove('myschools','vect')
  167. :param point: point vector object
  168. :param raster: raster object
  169. :param str column: column name to update
  170. """
  171. from math import isnan
  172. if not column:
  173. result = []
  174. if region is None:
  175. from grass.pygrass.gis.region import Region
  176. region = Region()
  177. if not poi_vector.is_open():
  178. poi_vector.open()
  179. if not raster.is_open():
  180. raster.open()
  181. if poi_vector.num_primitive_of('point') == 0:
  182. raise GrassError(_("Vector doesn't contain points"))
  183. for poi in poi_vector.viter('points'):
  184. val = raster.get_value(poi, region)
  185. if column:
  186. if val is not None and not isnan(val):
  187. poi.attrs[column] = val
  188. else:
  189. if val is not None and not isnan(val):
  190. result.append((poi.id, poi.x, poi.y, val))
  191. else:
  192. result.append((poi.id, poi.x, poi.y, None))
  193. if not column:
  194. return result
  195. else:
  196. poi.attrs.commit()
  197. return True
  198. def r_export(rast, output='', fmt='png', **kargs):
  199. from grass.pygrass.modules import Module
  200. if rast.exist():
  201. output = output if output else "%s_%s.%s" % (rast.name, rast.mapset,
  202. fmt)
  203. Module('r.out.%s' % fmt, input=rast.fullname(), output=output,
  204. overwrite=True, **kargs)
  205. return output
  206. else:
  207. raise ValueError('Raster map does not exist.')
  208. def get_lib_path(modname, libname=None):
  209. """Return the path of the libname contained in the module.
  210. """
  211. from os.path import isdir, join, sep
  212. from os import getenv
  213. if isdir(join(getenv('GISBASE'), 'etc', modname)):
  214. path = join(os.getenv('GISBASE'), 'etc', modname)
  215. elif getenv('GRASS_ADDON_BASE') and libname and \
  216. isdir(join(getenv('GRASS_ADDON_BASE'), 'etc', modname, libname)):
  217. path = join(getenv('GRASS_ADDON_BASE'), 'etc', modname)
  218. elif getenv('GRASS_ADDON_BASE') and \
  219. isdir(join(getenv('GRASS_ADDON_BASE'), 'etc', modname)):
  220. path = join(getenv('GRASS_ADDON_BASE'), 'etc', modname)
  221. elif getenv('GRASS_ADDON_BASE') and \
  222. isdir(join(getenv('GRASS_ADDON_BASE'), modname, modname)):
  223. path = join(os.getenv('GRASS_ADDON_BASE'), modname, modname)
  224. else:
  225. # used by g.extension compilation process
  226. cwd = os.getcwd()
  227. idx = cwd.find(modname)
  228. if idx < 0:
  229. return None
  230. path = '{cwd}{sep}etc{sep}{modname}'.format(cwd=cwd[:idx+len(modname)],
  231. sep=sep,
  232. modname=modname)
  233. return path
  234. def set_path(modulename, dirname=None, path='.'):
  235. """Set sys.path looking in the the local directory GRASS directories.
  236. :param modulename: string with the name of the GRASS module
  237. :param dirname: string with the directory name containing the python
  238. libraries, default None
  239. :param path: string with the path to reach the dirname locally.
  240. Example
  241. --------
  242. "set_path" example working locally with the source code of a module
  243. (r.green) calling the function with all the parameters. Below it is
  244. reported the directory structure on the r.green module.
  245. ::
  246. grass_prompt> pwd
  247. ~/Download/r.green/r.green.hydro/r.green.hydro.financial
  248. grass_prompt> tree ../../../r.green
  249. ../../../r.green
  250. |-- ...
  251. |-- libgreen
  252. | |-- pyfile1.py
  253. | +-- pyfile2.py
  254. +-- r.green.hydro
  255. |-- Makefile
  256. |-- libhydro
  257. | |-- pyfile1.py
  258. | +-- pyfile2.py
  259. |-- r.green.hydro.*
  260. +-- r.green.hydro.financial
  261. |-- Makefile
  262. |-- ...
  263. +-- r.green.hydro.financial.py
  264. 21 directories, 125 files
  265. in the source code the function is called with the following parameters: ::
  266. set_path('r.green', 'libhydro', '..')
  267. set_path('r.green', 'libgreen', os.path.join('..', '..'))
  268. when we are executing the module: r.green.hydro.financial locally from
  269. the command line: ::
  270. grass_prompt> python r.green.hydro.financial.py --ui
  271. In this way we are executing the local code even if the module was already
  272. installed as grass-addons and it is available in GRASS standards path.
  273. The function is cheching if the dirname is provided and if the
  274. directory exists and it is available using the path
  275. provided as third parameter, if yes add the path to sys.path to be
  276. importable, otherwise it will check on GRASS GIS standard paths.
  277. """
  278. import sys
  279. # TODO: why dirname is checked first - the logic should be revised
  280. pathlib = None
  281. if dirname:
  282. pathlib = os.path.join(path, dirname)
  283. if pathlib and os.path.exists(pathlib):
  284. # we are running the script from the script directory, therefore
  285. # we add the path to sys.path to reach the directory (dirname)
  286. sys.path.append(os.path.abspath(path))
  287. else:
  288. # running from GRASS GIS session
  289. path = get_lib_path(modulename, dirname)
  290. if path is None:
  291. pathname = os.path.join(modulename, dirname) if dirname else modulename
  292. raise ImportError("Not able to find the path '%s' directory "
  293. "(current dir '%s')." % (pathname, os.getcwd()))
  294. sys.path.insert(0, path)
  295. def split_in_chunk(iterable, length=10):
  296. """Split a list in chunk.
  297. >>> for chunk in split_in_chunk(range(25)): print chunk
  298. (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
  299. (10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
  300. (20, 21, 22, 23, 24)
  301. >>> for chunk in split_in_chunk(range(25), 3): print chunk
  302. (0, 1, 2)
  303. (3, 4, 5)
  304. (6, 7, 8)
  305. (9, 10, 11)
  306. (12, 13, 14)
  307. (15, 16, 17)
  308. (18, 19, 20)
  309. (21, 22, 23)
  310. (24,)
  311. """
  312. it = iter(iterable)
  313. while True:
  314. chunk = tuple(itertools.islice(it, length))
  315. if not chunk:
  316. return
  317. yield chunk
  318. def table_exist(cursor, table_name):
  319. """Return True if the table exist False otherwise"""
  320. try:
  321. # sqlite
  322. cursor.execute("SELECT name FROM sqlite_master"
  323. " WHERE type='table' AND name='%s';" % table_name)
  324. except OperationalError:
  325. try:
  326. # pg
  327. cursor.execute("SELECT EXISTS(SELECT * FROM "
  328. "information_schema.tables "
  329. "WHERE table_name=%s)" % table_name)
  330. except OperationalError:
  331. return False
  332. one = cursor.fetchone() if cursor else None
  333. return True if one and one[0] else False