__init__.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. # -*- coding: utf-8 -*-
  2. #!/usr/bin/env python2.7
  3. from __future__ import (nested_scopes, generators, division, absolute_import,
  4. with_statement, print_function, unicode_literals)
  5. from os import listdir
  6. from os.path import join, isdir
  7. import shutil
  8. import ctypes as ct
  9. import fnmatch
  10. import grass.lib.gis as libgis
  11. libgis.G_gisinit('')
  12. from grass.pygrass.errors import GrassError
  13. test_vector_name="Gis_test_vector"
  14. test_raster_name="Gis_test_raster"
  15. ETYPE = {'raster': libgis.G_ELEMENT_RASTER,
  16. 'raster_3d': libgis.G_ELEMENT_RASTER3D,
  17. 'vector': libgis.G_ELEMENT_VECTOR,
  18. 'label': libgis.G_ELEMENT_LABEL,
  19. 'region': libgis.G_ELEMENT_REGION,
  20. 'group': libgis.G_ELEMENT_GROUP}
  21. CHECK_IS = {"GISBASE": libgis.G_is_gisbase,
  22. "GISDBASE": lambda x: True,
  23. "LOCATION_NAME": libgis.G_is_location,
  24. "MAPSET": libgis.G_is_mapset}
  25. def _check(value, path, type):
  26. """Private function to check the correctness of a value.
  27. :param value: Name of the directory
  28. :type value: str
  29. :param path: Path where the directory is located
  30. :type path: path
  31. :param type: it is a string defining the type that will e checked,
  32. valid types are: GISBASE, GISDBASE, LOCATION_NAME, MAPSET
  33. :type type: str
  34. :return: the value if verify else None and
  35. if value is empty return environmental variable
  36. :rtype: str
  37. """
  38. if value and CHECK_IS[type](join(path, value)):
  39. return value
  40. elif value is '':
  41. from grass.pygrass.utils import getenv
  42. return getenv(type)
  43. else:
  44. raise GrassError("%s <%s> not found" % (type.title(),
  45. join(path, value)))
  46. def set_current_mapset(mapset, location=None, gisdbase=None):
  47. """Set the current mapset as working area
  48. :param mapset: Name of the mapset
  49. :type value: str
  50. :param location: Name of the location
  51. :type location: str
  52. :param gisdbase: Name of the gisdbase
  53. :type gisdbase: str
  54. """
  55. libgis.G_setenv('MAPSET', mapset)
  56. if location:
  57. libgis.G_setenv('LOCATION_NAME', location)
  58. if gisdbase:
  59. libgis.G_setenv('GISDBASE', gisdbase)
  60. def make_mapset(mapset, location=None, gisdbase=None):
  61. """Create a new mapset
  62. :param mapset: Name of the mapset
  63. :type value: str
  64. :param location: Name of the location
  65. :type location: str
  66. :param gisdbase: Name of the gisdbase
  67. :type gisdbase: str"""
  68. res = libgis.G_make_mapset(gisdbase, location, mapset)
  69. if res == -1:
  70. raise GrassError("Cannot create new mapset")
  71. elif res == -2:
  72. raise GrassError("Illegal name")
  73. class Gisdbase(object):
  74. """Return Gisdbase object. ::
  75. >>> from grass.script.core import gisenv
  76. >>> gisdbase = Gisdbase()
  77. >>> gisdbase.name == gisenv()['GISDBASE']
  78. True
  79. ..
  80. """
  81. def __init__(self, gisdbase=''):
  82. self.name = gisdbase
  83. def _get_name(self):
  84. return self._name
  85. def _set_name(self, name):
  86. self._name = _check(name, '', "GISDBASE")
  87. name = property(fget=_get_name, fset=_set_name,
  88. doc="Set or obtain the name of GISDBASE")
  89. def __str__(self):
  90. return self.name
  91. def __repr__(self):
  92. return 'Gisdbase(%s)' % self.name
  93. def __getitem__(self, location):
  94. """Return a Location object. ::
  95. >>> from grass.script.core import gisenv
  96. >>> loc_env = gisenv()['LOCATION_NAME']
  97. >>> gisdbase = Gisdbase()
  98. >>> loc_py = gisdbase[loc_env]
  99. >>> loc_env == loc_py.name
  100. True
  101. ..
  102. """
  103. if location in self.locations():
  104. return Location(location, self.name)
  105. else:
  106. raise KeyError('Location: %s does not exist' % location)
  107. def __iter__(self):
  108. for loc in self.locations():
  109. yield Location(loc, self.name)
  110. # TODO remove or complete this function
  111. def new_location(self):
  112. if libgis.G_make_location() != 0:
  113. raise GrassError("Cannot create new location")
  114. def locations(self):
  115. """Return a list of locations that are available in the gisdbase: ::
  116. >>> gisdbase = Gisdbase()
  117. >>> gisdbase.locations() # doctest: +ELLIPSIS
  118. [...]
  119. ..
  120. """
  121. return sorted([loc for loc in listdir(self.name)
  122. if libgis.G_is_location(join(self.name, loc))])
  123. class Location(object):
  124. """Location object ::
  125. >>> from grass.script.core import gisenv
  126. >>> location = Location()
  127. >>> location # doctest: +ELLIPSIS
  128. Location(...)
  129. >>> location.gisdbase == gisenv()['GISDBASE']
  130. True
  131. >>> location.name == gisenv()['LOCATION_NAME']
  132. True
  133. ..
  134. """
  135. def __init__(self, location='', gisdbase=''):
  136. self.gisdbase = gisdbase
  137. self.name = location
  138. def _get_gisdb(self):
  139. return self._gisdb
  140. def _set_gisdb(self, gisdb):
  141. self._gisdb = _check(gisdb, '', "GISDBASE")
  142. gisdbase = property(fget=_get_gisdb, fset=_set_gisdb,
  143. doc="Set or obtain the name of GISDBASE")
  144. def _get_name(self):
  145. return self._name
  146. def _set_name(self, name):
  147. self._name = _check(name, self._gisdb, "LOCATION_NAME")
  148. name = property(fget=_get_name, fset=_set_name,
  149. doc="Set or obtain the name of LOCATION")
  150. def __getitem__(self, mapset):
  151. if mapset in self.mapsets():
  152. return Mapset(mapset)
  153. else:
  154. raise KeyError('Mapset: %s does not exist' % mapset)
  155. def __iter__(self):
  156. lpath = self.path()
  157. return (m for m in listdir(lpath)
  158. if (isdir(join(lpath, m)) and _check(m, lpath, "MAPSET")))
  159. def __len__(self):
  160. return len(self.mapsets())
  161. def __str__(self):
  162. return self.name
  163. def __repr__(self):
  164. return 'Location(%r)' % self.name
  165. def mapsets(self, pattern=None, permissions=True):
  166. """Return a list of the available mapsets.
  167. :param pattern: the pattern to filter the result
  168. :type pattern: str
  169. :param permissions: check the permission of mapset
  170. :type permissions: bool
  171. :return: a list of mapset's names
  172. :rtype: list of strings
  173. ::
  174. >>> location = Location()
  175. >>> sorted(location.mapsets()) # doctest: +ELLIPSIS
  176. [...]
  177. """
  178. mapsets = [mapset for mapset in self]
  179. if permissions:
  180. mapsets = [mapset for mapset in mapsets
  181. if libgis.G_mapset_permissions(mapset)]
  182. if pattern:
  183. return fnmatch.filter(mapsets, pattern)
  184. return mapsets
  185. def path(self):
  186. """Return the complete path of the location"""
  187. return join(self.gisdbase, self.name)
  188. class Mapset(object):
  189. """Mapset ::
  190. >>> from grass.script.core import gisenv
  191. >>> genv = gisenv()
  192. >>> mapset = Mapset()
  193. >>> mapset # doctest: +ELLIPSIS
  194. Mapset(...)
  195. >>> mapset.gisdbase == genv['GISDBASE']
  196. True
  197. >>> mapset.location == genv['LOCATION_NAME']
  198. True
  199. >>> mapset.name == genv['MAPSET']
  200. True
  201. ..
  202. """
  203. def __init__(self, mapset='', location='', gisdbase=''):
  204. self.gisdbase = gisdbase
  205. self.location = location
  206. self.name = mapset
  207. self.visible = VisibleMapset(self.name, self.location, self.gisdbase)
  208. def _get_gisdb(self):
  209. return self._gisdb
  210. def _set_gisdb(self, gisdb):
  211. self._gisdb = _check(gisdb, '', "GISDBASE")
  212. gisdbase = property(fget=_get_gisdb, fset=_set_gisdb,
  213. doc="Set or obtain the name of GISDBASE")
  214. def _get_loc(self):
  215. return self._loc
  216. def _set_loc(self, loc):
  217. self._loc = _check(loc, self._gisdb, "LOCATION_NAME")
  218. location = property(fget=_get_loc, fset=_set_loc,
  219. doc="Set or obtain the name of LOCATION")
  220. def _get_name(self):
  221. return self._name
  222. def _set_name(self, name):
  223. self._name = _check(name, join(self._gisdb, self._loc), "MAPSET")
  224. name = property(fget=_get_name, fset=_set_name,
  225. doc="Set or obtain the name of MAPSET")
  226. def __str__(self):
  227. return self.name
  228. def __repr__(self):
  229. return 'Mapset(%r)' % self.name
  230. def glist(self, type, pattern=None):
  231. """Return a list of grass types like:
  232. * 'group',
  233. * 'label',
  234. * 'raster',
  235. * 'raster_3d',
  236. * 'region',
  237. * 'vector',
  238. :param type: the type of element to query
  239. :type type: str
  240. :param pattern: the pattern to filter the result
  241. :type pattern: str
  242. ::
  243. >>> mapset = Mapset()
  244. >>> mapset.current()
  245. >>> rast = mapset.glist('raster')
  246. >>> test_raster_name in rast
  247. True
  248. >>> vect = mapset.glist('vector')
  249. >>> test_vector_name in vect
  250. True
  251. ..
  252. """
  253. if type not in ETYPE:
  254. str_err = "Type %s is not valid, valid types are: %s."
  255. raise TypeError(str_err % (type, ', '.join(ETYPE.keys())))
  256. clist = libgis.G_list(ETYPE[type], self.gisdbase,
  257. self.location, self.name)
  258. elist = []
  259. for el in clist:
  260. el_name = ct.cast(el, ct.c_char_p).value
  261. if el_name:
  262. elist.append(el_name)
  263. else:
  264. if pattern:
  265. return fnmatch.filter(elist, pattern)
  266. return elist
  267. def is_current(self):
  268. """Check if the MAPSET is the working MAPSET"""
  269. return (self.name == libgis.G_getenv('MAPSET') and
  270. self.location == libgis.G_getenv('LOCATION_NAME') and
  271. self.gisdbase == libgis.G_getenv('GISDBASE'))
  272. def current(self):
  273. """Set the mapset as current"""
  274. set_current_mapset(self.name, self.location, self.gisdbase)
  275. def delete(self):
  276. """Delete the mapset"""
  277. if self.is_current():
  278. raise GrassError('The mapset is in use.')
  279. shutil.rmtree(self.path())
  280. def path(self):
  281. """Return the complete path of the mapset"""
  282. return join(self.gisdbase, self.location, self.name)
  283. class VisibleMapset(object):
  284. """VisibleMapset object
  285. """
  286. def __init__(self, mapset, location='', gisdbase=''):
  287. self.mapset = mapset
  288. self.location = Location(location, gisdbase)
  289. self._list = []
  290. self.spath = join(self.location.path(), self.mapset, 'SEARCH_PATH')
  291. def __repr__(self):
  292. return repr(self.read())
  293. def __iter__(self):
  294. for mapset in self.read():
  295. yield mapset
  296. def read(self):
  297. """Return the mapsets in the search path"""
  298. with open(self.spath, "a+") as f:
  299. lines = f.readlines()
  300. if lines:
  301. return [l.strip() for l in lines]
  302. lns = ['PERMANENT', ]
  303. self.write(lns)
  304. return lns
  305. def _write(self, mapsets):
  306. """Write to SEARCH_PATH file the changes in the search path
  307. :param mapsets: a list of mapset's names
  308. :type mapsets: list
  309. """
  310. with open(self.spath, "w+") as f:
  311. ms = self.location.mapsets()
  312. f.write('%s' % '\n'.join([m for m in mapsets if m in ms]))
  313. def add(self, mapset):
  314. """Add a mapset to the search path
  315. :param mapset: a mapset's name
  316. :type mapset: str
  317. """
  318. if mapset not in self.read() and mapset in self.location:
  319. with open(self.spath, "a+") as f:
  320. f.write('\n%s' % mapset)
  321. else:
  322. raise TypeError('Mapset not found')
  323. def remove(self, mapset):
  324. """Remove mapset to the search path
  325. :param mapset: a mapset's name
  326. :type mapset: str
  327. """
  328. mapsets = self.read()
  329. mapsets.remove(mapset)
  330. self._write(mapsets)
  331. def extend(self, mapsets):
  332. """Add more mapsets to the search path
  333. :param mapsets: a list of mapset's names
  334. :type mapsets: list
  335. """
  336. ms = self.location.mapsets()
  337. final = self.read()
  338. final.extend([m for m in mapsets if m in ms and m not in final])
  339. self._write(final)
  340. def reset(self):
  341. """Reset to the original search path"""
  342. final = [self.mapset, 'PERMANENT']
  343. self._write(final)
  344. if __name__ == "__main__":
  345. import doctest
  346. from grass.pygrass import utils
  347. from grass.script.core import run_command
  348. utils.create_test_vector_map(test_vector_name)
  349. run_command("g.region", n=50, s=0, e=60, w=0, res=1)
  350. run_command("r.mapcalc", expression="%s = 1"%(test_raster_name),
  351. overwrite=True)
  352. run_command("g.region", n=40, s=0, e=40, w=0, res=2)
  353. doctest.testmod()
  354. """Remove the generated vector map, if exist"""
  355. mset = utils.get_mapset_vector(test_vector_name, mapset='')
  356. if mset:
  357. run_command("g.remove", flags='f', type='vector', name=test_vector_name)
  358. mset = utils.get_mapset_raster(test_raster_name, mapset='')
  359. if mset:
  360. run_command("g.remove", flags='f', type='raster', name=test_raster_name)