__init__.py 13 KB

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