GRASS Programmer's Manual
6.4.2(2012)
|
00001 """!@package grass.script.core 00002 00003 @brief GRASS Python scripting module (core functions) 00004 00005 Core functions to be used in Python scripts. 00006 00007 Usage: 00008 00009 @code 00010 from grass.script import core as grass 00011 00012 grass.parser() 00013 ... 00014 @endcode 00015 00016 (C) 2008-2011 by the GRASS Development Team 00017 This program is free software under the GNU General Public 00018 License (>=v2). Read the file COPYING that comes with GRASS 00019 for details. 00020 00021 @author Glynn Clements 00022 @author Martin Landa <landa.martin gmail.com> 00023 @author Michael Barton <michael.barton asu.edu> 00024 """ 00025 00026 import os 00027 import sys 00028 import types 00029 import re 00030 import atexit 00031 import subprocess 00032 import shutil 00033 import locale 00034 import codecs 00035 00036 # i18N 00037 import gettext 00038 gettext.install('grasslibs', os.path.join(os.getenv("GISBASE"), 'locale'), unicode=True) 00039 00040 # subprocess wrapper that uses shell on Windows 00041 00042 class Popen(subprocess.Popen): 00043 def __init__(self, args, bufsize = 0, executable = None, 00044 stdin = None, stdout = None, stderr = None, 00045 preexec_fn = None, close_fds = False, shell = None, 00046 cwd = None, env = None, universal_newlines = False, 00047 startupinfo = None, creationflags = 0): 00048 00049 if shell == None: 00050 shell = (sys.platform == "win32") 00051 00052 subprocess.Popen.__init__(self, args, bufsize, executable, 00053 stdin, stdout, stderr, 00054 preexec_fn, close_fds, shell, 00055 cwd, env, universal_newlines, 00056 startupinfo, creationflags) 00057 00058 PIPE = subprocess.PIPE 00059 STDOUT = subprocess.STDOUT 00060 00061 class ScriptError(Exception): 00062 def __init__(self, msg): 00063 self.value = msg 00064 00065 def __str__(self): 00066 return repr(self.value) 00067 00068 raise_on_error = False # raise exception instead of calling fatal() 00069 debug_level = 0 # DEBUG level 00070 00071 def call(*args, **kwargs): 00072 return Popen(*args, **kwargs).wait() 00073 00074 # GRASS-oriented interface to subprocess module 00075 00076 _popen_args = ["bufsize", "executable", "stdin", "stdout", "stderr", 00077 "preexec_fn", "close_fds", "cwd", "env", 00078 "universal_newlines", "startupinfo", "creationflags"] 00079 00080 def decode(string): 00081 enc = locale.getdefaultlocale()[1] 00082 if enc: 00083 return string.decode(enc) 00084 00085 return string 00086 00087 def _make_val(val): 00088 if isinstance(val, types.StringType) or \ 00089 isinstance(val, types.UnicodeType): 00090 return val 00091 if isinstance(val, types.ListType): 00092 return ",".join(map(_make_val, val)) 00093 if isinstance(val, types.TupleType): 00094 return _make_val(list(val)) 00095 return str(val) 00096 00097 def make_command(prog, flags = "", overwrite = False, quiet = False, verbose = False, **options): 00098 """!Return a list of strings suitable for use as the args parameter to 00099 Popen() or call(). Example: 00100 00101 @code 00102 >>> grass.make_command("g.message", flags = 'w', message = 'this is a warning') 00103 ['g.message', '-w', 'message=this is a warning'] 00104 @endcode 00105 00106 @param prog GRASS module 00107 @param flags flags to be used (given as a string) 00108 @param overwrite True to enable overwriting the output (<tt>--o</tt>) 00109 @param quiet True to run quietly (<tt>--q</tt>) 00110 @param verbose True to run verbosely (<tt>--v</tt>) 00111 @param options module's parameters 00112 00113 @return list of arguments 00114 """ 00115 args = [prog] 00116 if overwrite: 00117 args.append("--o") 00118 if quiet: 00119 args.append("--q") 00120 if verbose: 00121 args.append("--v") 00122 if flags: 00123 if '-' in flags: 00124 raise ScriptError("'-' is not a valid flag") 00125 args.append("-%s" % flags) 00126 for opt, val in options.iteritems(): 00127 if val != None: 00128 if opt[0] == '_': 00129 opt = opt[1:] 00130 args.append("%s=%s" % (opt, _make_val(val))) 00131 return args 00132 00133 def start_command(prog, flags = "", overwrite = False, quiet = False, verbose = False, **kwargs): 00134 """!Returns a Popen object with the command created by make_command. 00135 Accepts any of the arguments which Popen() accepts apart from "args" 00136 and "shell". 00137 00138 \code 00139 >>> p = grass.start_command("g.gisenv", stdout = subprocess.PIPE) 00140 >>> print p 00141 <subprocess.Popen object at 0xb7c12f6c> 00142 >>> print p.communicate()[0] 00143 GISDBASE='/opt/grass-data'; 00144 LOCATION_NAME='spearfish60'; 00145 MAPSET='glynn'; 00146 GRASS_DB_ENCODING='ascii'; 00147 GRASS_GUI='text'; 00148 MONITOR='x0'; 00149 \endcode 00150 00151 @param prog GRASS module 00152 @param flags flags to be used (given as a string) 00153 @param overwrite True to enable overwriting the output (<tt>--o</tt>) 00154 @param quiet True to run quietly (<tt>--q</tt>) 00155 @param verbose True to run verbosely (<tt>--v</tt>) 00156 @param kwargs module's parameters 00157 00158 @return Popen object 00159 """ 00160 options = {} 00161 popts = {} 00162 for opt, val in kwargs.iteritems(): 00163 if opt in _popen_args: 00164 popts[opt] = val 00165 else: 00166 options[opt] = val 00167 args = make_command(prog, flags, overwrite, quiet, verbose, **options) 00168 if sys.platform == 'win32' and os.path.splitext(prog)[1] == '.py': 00169 os.chdir(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'scripts')) 00170 args.insert(0, sys.executable) 00171 00172 global debug_level 00173 if debug_level > 0: 00174 sys.stderr.write("D1/%d: %s.start_command(): %s\n" % (debug_level, __name__, ' '.join(args))) 00175 sys.stderr.flush() 00176 00177 return Popen(args, **popts) 00178 00179 def run_command(*args, **kwargs): 00180 """!Passes all arguments to start_command(), then waits for the process to 00181 complete, returning its exit code. Similar to subprocess.call(), but 00182 with the make_command() interface. 00183 00184 @param args list of unnamed arguments (see start_command() for details) 00185 @param kwargs list of named arguments (see start_command() for details) 00186 00187 @return exit code (0 for success) 00188 """ 00189 ps = start_command(*args, **kwargs) 00190 return ps.wait() 00191 00192 def pipe_command(*args, **kwargs): 00193 """!Passes all arguments to start_command(), but also adds 00194 "stdout = PIPE". Returns the Popen object. 00195 00196 \code 00197 >>> p = grass.pipe_command("g.gisenv") 00198 >>> print p 00199 <subprocess.Popen object at 0xb7c12f6c> 00200 >>> print p.communicate()[0] 00201 GISDBASE='/opt/grass-data'; 00202 LOCATION_NAME='spearfish60'; 00203 MAPSET='glynn'; 00204 GRASS_DB_ENCODING='ascii'; 00205 GRASS_GUI='text'; 00206 MONITOR='x0'; 00207 \endcode 00208 00209 @param args list of unnamed arguments (see start_command() for details) 00210 @param kwargs list of named arguments (see start_command() for details) 00211 00212 @return Popen object 00213 """ 00214 kwargs['stdout'] = PIPE 00215 return start_command(*args, **kwargs) 00216 00217 def feed_command(*args, **kwargs): 00218 """!Passes all arguments to start_command(), but also adds 00219 "stdin = PIPE". Returns the Popen object. 00220 00221 @param args list of unnamed arguments (see start_command() for details) 00222 @param kwargs list of named arguments (see start_command() for details) 00223 00224 @return Popen object 00225 """ 00226 kwargs['stdin'] = PIPE 00227 return start_command(*args, **kwargs) 00228 00229 def read_command(*args, **kwargs): 00230 """!Passes all arguments to pipe_command, then waits for the process to 00231 complete, returning its stdout (i.e. similar to shell `backticks`). 00232 00233 @param args list of unnamed arguments (see start_command() for details) 00234 @param kwargs list of named arguments (see start_command() for details) 00235 00236 @return stdout 00237 """ 00238 ps = pipe_command(*args, **kwargs) 00239 return ps.communicate()[0] 00240 00241 def parse_command(*args, **kwargs): 00242 """!Passes all arguments to read_command, then parses the output 00243 by parse_key_val(). 00244 00245 Parsing function can be optionally given by <em>parse</em> parameter 00246 including its arguments, e.g. 00247 00248 @code 00249 parse_command(..., parse = (grass.parse_key_val, { 'sep' : ':' })) 00250 @endcode 00251 00252 or you can simply define <em>delimiter</em> 00253 00254 @code 00255 parse_command(..., delimiter = ':') 00256 @endcode 00257 00258 @param args list of unnamed arguments (see start_command() for details) 00259 @param kwargs list of named arguments (see start_command() for details) 00260 00261 @return parsed module output 00262 """ 00263 parse = None 00264 parse_args = {} 00265 if 'parse' in kwargs: 00266 if type(kwargs['parse']) is types.TupleType: 00267 parse = kwargs['parse'][0] 00268 parse_args = kwargs['parse'][1] 00269 del kwargs['parse'] 00270 00271 if 'delimiter' in kwargs: 00272 parse_args = { 'sep' : kwargs['delimiter'] } 00273 del kwargs['delimiter'] 00274 00275 if not parse: 00276 parse = parse_key_val # use default fn 00277 00278 res = read_command(*args, **kwargs) 00279 00280 return parse(res, **parse_args) 00281 00282 def write_command(*args, **kwargs): 00283 """!Passes all arguments to feed_command, with the string specified 00284 by the 'stdin' argument fed to the process' stdin. 00285 00286 @param args list of unnamed arguments (see start_command() for details) 00287 @param kwargs list of named arguments (see start_command() for details) 00288 00289 @return return code 00290 """ 00291 stdin = kwargs['stdin'] 00292 p = feed_command(*args, **kwargs) 00293 p.stdin.write(stdin) 00294 p.stdin.close() 00295 return p.wait() 00296 00297 def exec_command(prog, flags = "", overwrite = False, quiet = False, verbose = False, env = None, **kwargs): 00298 """!Interface to os.execvpe(), but with the make_command() interface. 00299 00300 @param prog GRASS module 00301 @param flags flags to be used (given as a string) 00302 @param overwrite True to enable overwriting the output (<tt>--o</tt>) 00303 @param quiet True to run quietly (<tt>--q</tt>) 00304 @param verbose True to run verbosely (<tt>--v</tt>) 00305 @param env directory with enviromental variables 00306 @param kwargs module's parameters 00307 00308 """ 00309 args = make_command(prog, flags, overwrite, quiet, verbose, **kwargs) 00310 if env == None: 00311 env = os.environ 00312 os.execvpe(prog, args, env) 00313 00314 # interface to g.message 00315 00316 def message(msg, flag = None): 00317 """!Display a message using `g.message` 00318 00319 @param msg message to be displayed 00320 @param flag flags (given as string) 00321 """ 00322 run_command("g.message", flags = flag, message = msg) 00323 00324 def debug(msg, debug = 1): 00325 """!Display a debugging message using `g.message -d` 00326 00327 @param msg debugging message to be displayed 00328 @param debug debug level (0-5) 00329 """ 00330 run_command("g.message", flags = 'd', message = msg, debug = debug) 00331 00332 def verbose(msg): 00333 """!Display a verbose message using `g.message -v` 00334 00335 @param msg verbose message to be displayed 00336 """ 00337 message(msg, flag = 'v') 00338 00339 def info(msg): 00340 """!Display an informational message using `g.message -i` 00341 00342 @param msg informational message to be displayed 00343 """ 00344 message(msg, flag = 'i') 00345 00346 def percent(i, n, s): 00347 """!Display a progress info message using `g.message -p` 00348 00349 @code 00350 message(_("Percent complete...")) 00351 n = 100 00352 for i in range(n): 00353 percent(i, n, 1) 00354 percent(1, 1, 1) 00355 @endcode 00356 00357 @param i current item 00358 @param n total number of items 00359 @param s increment size 00360 """ 00361 message("%d %d %d" % (i, n, s), flag = 'p') 00362 00363 def warning(msg): 00364 """!Display a warning message using `g.message -w` 00365 00366 @param msg warning message to be displayed 00367 """ 00368 message(msg, flag = 'w') 00369 00370 def error(msg): 00371 """!Display an error message using `g.message -e` 00372 00373 Raise exception when on_error is 'raise'. 00374 00375 @param msg error message to be displayed 00376 """ 00377 global raise_on_error 00378 if raise_on_error: 00379 raise ScriptError(msg) 00380 else: 00381 message(msg, flag = 'e') 00382 00383 def fatal(msg): 00384 """!Display an error message using `g.message -e`, then abort 00385 00386 @param msg error message to be displayed 00387 """ 00388 error(msg) 00389 sys.exit(1) 00390 00391 def set_raise_on_error(raise_exp = True): 00392 """!Define behaviour on error (error() called) 00393 00394 @param raise_exp True to raise ScriptError instead of calling 00395 error() 00396 00397 @return current status 00398 """ 00399 global raise_on_error 00400 tmp_raise = raise_on_error 00401 raise_on_error = raise_exp 00402 00403 # interface to g.parser 00404 00405 def _parse_opts(lines): 00406 options = {} 00407 flags = {} 00408 for line in lines: 00409 line = line.rstrip('\r\n') 00410 if not line: 00411 break 00412 try: 00413 [var, val] = line.split('=', 1) 00414 except: 00415 raise SyntaxError("invalid output from g.parser: %s" % line) 00416 00417 if var.startswith('flag_'): 00418 flags[var[5:]] = bool(int(val)) 00419 elif var.startswith('opt_'): 00420 options[var[4:]] = val 00421 elif var in ['GRASS_OVERWRITE', 'GRASS_VERBOSE']: 00422 os.environ[var] = val 00423 else: 00424 raise SyntaxError("invalid output from g.parser: %s" % line) 00425 00426 return (options, flags) 00427 00428 def parser(): 00429 """!Interface to g.parser, intended to be run from the top-level, e.g.: 00430 00431 @code 00432 if __name__ == "__main__": 00433 options, flags = grass.parser() 00434 main() 00435 @endcode 00436 00437 Thereafter, the global variables "options" and "flags" will be 00438 dictionaries containing option/flag values, keyed by lower-case 00439 option/flag names. The values in "options" are strings, those in 00440 "flags" are Python booleans. 00441 """ 00442 if not os.getenv("GISBASE"): 00443 print >> sys.stderr, "You must be in GRASS GIS to run this program." 00444 sys.exit(1) 00445 00446 cmdline = [basename(sys.argv[0])] 00447 cmdline += ['"' + arg + '"' for arg in sys.argv[1:]] 00448 os.environ['CMDLINE'] = ' '.join(cmdline) 00449 00450 argv = sys.argv[:] 00451 name = argv[0] 00452 if not os.path.isabs(name): 00453 if os.sep in name or (os.altsep and os.altsep in name): 00454 argv[0] = os.path.abspath(name) 00455 else: 00456 argv[0] = os.path.join(sys.path[0], name) 00457 00458 p = Popen(['g.parser', '-s'] + argv, stdout = PIPE) 00459 s = p.communicate()[0] 00460 lines = s.splitlines() 00461 00462 if not lines or lines[0].rstrip('\r\n') != "@ARGS_PARSED@": 00463 sys.stdout.write(s) 00464 sys.exit(p.returncode) 00465 00466 return _parse_opts(lines[1:]) 00467 00468 # interface to g.tempfile 00469 00470 def tempfile(): 00471 """!Returns the name of a temporary file, created with g.tempfile.""" 00472 return read_command("g.tempfile", pid = os.getpid()).strip() 00473 00474 def tempdir(): 00475 """!Returns the name of a temporary dir, created with g.tempfile.""" 00476 tmp = read_command("g.tempfile", pid = os.getpid()).strip() 00477 try_remove(tmp) 00478 os.mkdir(tmp) 00479 00480 return tmp 00481 00482 # key-value parsers 00483 00484 def parse_key_val(s, sep = '=', dflt = None, val_type = None, vsep = None): 00485 """!Parse a string into a dictionary, where entries are separated 00486 by newlines and the key and value are separated by `sep' (default: `=') 00487 00488 @param s string to be parsed 00489 @param sep key/value separator 00490 @param dflt default value to be used 00491 @param val_type value type (None for no cast) 00492 @param vsep vertical separator (default os.linesep) 00493 00494 @return parsed input (dictionary of keys/values) 00495 """ 00496 result = {} 00497 00498 if not s: 00499 return result 00500 00501 if vsep: 00502 lines = s.split(vsep) 00503 try: 00504 lines.remove('\n') 00505 except ValueError: 00506 pass 00507 else: 00508 lines = s.splitlines() 00509 00510 for line in lines: 00511 kv = line.split(sep, 1) 00512 k = kv[0].strip() 00513 if len(kv) > 1: 00514 v = kv[1] 00515 else: 00516 v = dflt 00517 if val_type: 00518 result[k] = val_type(v) 00519 else: 00520 result[k] = v 00521 return result 00522 00523 # interface to g.gisenv 00524 00525 def gisenv(): 00526 """!Returns the output from running g.gisenv (with no arguments), as a 00527 dictionary. Example: 00528 00529 \code 00530 >>> env = grass.gisenv() 00531 >>> print env['GISDBASE'] 00532 /opt/grass-data 00533 \endcode 00534 00535 @return list of GRASS variables 00536 """ 00537 s = read_command("g.gisenv", flags='n') 00538 return parse_key_val(s) 00539 00540 # interface to g.region 00541 00542 def region(): 00543 """!Returns the output from running "g.region -g", as a 00544 dictionary. Example: 00545 00546 \code 00547 >>> region = grass.region() 00548 >>> [region[key] for key in "nsew"] 00549 [228500.0, 215000.0, 645000.0, 630000.0] 00550 >>> (region['nsres'], region['ewres']) 00551 (10.0, 10.0) 00552 \endcode 00553 00554 @return dictionary of region values 00555 """ 00556 s = read_command("g.region", flags='g') 00557 reg = parse_key_val(s, val_type = float) 00558 for k in ['rows', 'cols']: 00559 reg[k] = int(reg[k]) 00560 return reg 00561 00562 def use_temp_region(): 00563 """!Copies the current region to a temporary region with "g.region save=", 00564 then sets WIND_OVERRIDE to refer to that region. Installs an atexit 00565 handler to delete the temporary region upon termination. 00566 """ 00567 name = "tmp.%s.%d" % (os.path.basename(sys.argv[0]), os.getpid()) 00568 run_command("g.region", save = name, overwrite = True) 00569 os.environ['WIND_OVERRIDE'] = name 00570 atexit.register(del_temp_region) 00571 00572 def del_temp_region(): 00573 """!Unsets WIND_OVERRIDE and removes any region named by it.""" 00574 try: 00575 name = os.environ.pop('WIND_OVERRIDE') 00576 run_command("g.remove", quiet = True, region = name) 00577 except: 00578 pass 00579 00580 # interface to g.findfile 00581 00582 def find_file(name, element = 'cell', mapset = None): 00583 """!Returns the output from running g.findfile as a 00584 dictionary. Example: 00585 00586 \code 00587 >>> result = grass.find_file('fields', element = 'vector') 00588 >>> print result['fullname'] 00589 fields@PERMANENT 00590 >>> print result['file'] 00591 /opt/grass-data/spearfish60/PERMANENT/vector/fields 00592 \endcode 00593 00594 @param name file name 00595 @param element element type (default 'cell') 00596 @param mapset mapset name (default all mapsets in search path) 00597 00598 @return parsed output of g.findfile 00599 """ 00600 s = read_command("g.findfile", flags='n', element = element, file = name, mapset = mapset) 00601 return parse_key_val(s) 00602 00603 # interface to g.list 00604 00605 def list_grouped(type, check_search_path = True): 00606 """!List elements grouped by mapsets. 00607 00608 Returns the output from running g.list, as a dictionary where the 00609 keys are mapset names and the values are lists of maps in that 00610 mapset. Example: 00611 00612 @code 00613 >>> grass.list_grouped('rast')['PERMANENT'] 00614 ['aspect', 'erosion1', 'quads', 'soils', 'strm.dist', ... 00615 @endcode 00616 00617 @param type element type (rast, vect, rast3d, region, ...) 00618 @param check_search_path True to add mapsets for the search path with no found elements 00619 00620 @return directory of mapsets/elements 00621 """ 00622 dashes_re = re.compile("^----+$") 00623 mapset_re = re.compile("<(.*)>") 00624 result = {} 00625 if check_search_path: 00626 for mapset in mapsets(search_path = True): 00627 result[mapset] = [] 00628 00629 mapset = None 00630 for line in read_command("g.list", type = type).splitlines(): 00631 if line == "": 00632 continue 00633 if dashes_re.match(line): 00634 continue 00635 m = mapset_re.search(line) 00636 if m: 00637 mapset = m.group(1) 00638 if mapset not in result.keys(): 00639 result[mapset] = [] 00640 continue 00641 if mapset: 00642 result[mapset].extend(line.split()) 00643 00644 return result 00645 00646 def _concat(xs): 00647 result = [] 00648 for x in xs: 00649 result.extend(x) 00650 return result 00651 00652 def list_pairs(type): 00653 """!List of elements as tuples. 00654 00655 Returns the output from running g.list, as a list of (map, mapset) 00656 pairs. Example: 00657 00658 @code 00659 >>> grass.list_pairs('rast') 00660 [('aspect', 'PERMANENT'), ('erosion1', 'PERMANENT'), ('quads', 'PERMANENT'), ... 00661 @endcode 00662 00663 @param type element type (rast, vect, rast3d, region, ...) 00664 00665 @return list of tuples (map, mapset) 00666 """ 00667 return _concat([[(map, mapset) for map in maps] 00668 for mapset, maps in list_grouped(type).iteritems()]) 00669 00670 def list_strings(type): 00671 """!List of elements as strings. 00672 00673 Returns the output from running g.list, as a list of qualified 00674 names. Example: 00675 00676 @code 00677 >>> grass.list_strings('rast') 00678 ['aspect@PERMANENT', 'erosion1@PERMANENT', 'quads@PERMANENT', 'soils@PERMANENT', ... 00679 @endcode 00680 00681 @param type element type 00682 00683 @return list of strings ('map@@mapset') 00684 """ 00685 return ["%s@%s" % pair for pair in list_pairs(type)] 00686 00687 # interface to g.mlist 00688 00689 def mlist_grouped(type, pattern = None, check_search_path = True): 00690 """!List of elements grouped by mapsets. 00691 00692 Returns the output from running g.mlist, as a dictionary where the 00693 keys are mapset names and the values are lists of maps in that 00694 mapset. Example: 00695 00696 @code 00697 >>> grass.mlist_grouped('rast', pattern='r*')['PERMANENT'] 00698 ['railroads', 'roads', 'rstrct.areas', 'rushmore'] 00699 @endcode 00700 00701 @param type element type (rast, vect, rast3d, region, ...) 00702 @param pattern pattern string 00703 @param check_search_path True to add mapsets for the search path with no found elements 00704 00705 @return directory of mapsets/elements 00706 """ 00707 result = {} 00708 if check_search_path: 00709 for mapset in mapsets(search_path = True): 00710 result[mapset] = [] 00711 00712 mapset = None 00713 for line in read_command("g.mlist", flags = "m", 00714 type = type, pattern = pattern).splitlines(): 00715 try: 00716 name, mapset = line.split('@') 00717 except ValueError: 00718 warning(_("Invalid element '%s'") % line) 00719 continue 00720 00721 if mapset in result: 00722 result[mapset].append(name) 00723 else: 00724 result[mapset] = [name, ] 00725 00726 return result 00727 00728 # color parsing 00729 00730 named_colors = { 00731 "white": (1.00, 1.00, 1.00), 00732 "black": (0.00, 0.00, 0.00), 00733 "red": (1.00, 0.00, 0.00), 00734 "green": (0.00, 1.00, 0.00), 00735 "blue": (0.00, 0.00, 1.00), 00736 "yellow": (1.00, 1.00, 0.00), 00737 "magenta": (1.00, 0.00, 1.00), 00738 "cyan": (0.00, 1.00, 1.00), 00739 "aqua": (0.00, 0.75, 0.75), 00740 "grey": (0.75, 0.75, 0.75), 00741 "gray": (0.75, 0.75, 0.75), 00742 "orange": (1.00, 0.50, 0.00), 00743 "brown": (0.75, 0.50, 0.25), 00744 "purple": (0.50, 0.00, 1.00), 00745 "violet": (0.50, 0.00, 1.00), 00746 "indigo": (0.00, 0.50, 1.00)} 00747 00748 def parse_color(val, dflt = None): 00749 """!Parses the string "val" as a GRASS colour, which can be either one of 00750 the named colours or an R:G:B tuple e.g. 255:255:255. Returns an 00751 (r,g,b) triple whose components are floating point values between 0 00752 and 1. Example: 00753 00754 \code 00755 >>> grass.parse_color("red") 00756 (1.0, 0.0, 0.0) 00757 >>> grass.parse_color("255:0:0") 00758 (1.0, 0.0, 0.0) 00759 \endcode 00760 00761 @param val color value 00762 @param dflt default color value 00763 00764 @return tuple RGB 00765 """ 00766 if val in named_colors: 00767 return named_colors[val] 00768 00769 vals = val.split(':') 00770 if len(vals) == 3: 00771 return tuple(float(v) / 255 for v in vals) 00772 00773 return dflt 00774 00775 # check GRASS_OVERWRITE 00776 00777 def overwrite(): 00778 """!Return True if existing files may be overwritten""" 00779 owstr = 'GRASS_OVERWRITE' 00780 return owstr in os.environ and os.environ[owstr] != '0' 00781 00782 # check GRASS_VERBOSE 00783 00784 def verbosity(): 00785 """!Return the verbosity level selected by GRASS_VERBOSE""" 00786 vbstr = os.getenv('GRASS_VERBOSE') 00787 if vbstr: 00788 return int(vbstr) 00789 else: 00790 return 2 00791 00792 ## various utilities, not specific to GRASS 00793 00794 # basename inc. extension stripping 00795 00796 def basename(path, ext = None): 00797 """!Remove leading directory components and an optional extension 00798 from the specified path 00799 00800 @param path path 00801 @param ext extension 00802 """ 00803 name = os.path.basename(path) 00804 if not ext: 00805 return name 00806 fs = name.rsplit('.', 1) 00807 if len(fs) > 1 and fs[1].lower() == ext: 00808 name = fs[0] 00809 return name 00810 00811 # find a program (replacement for "which") 00812 00813 def find_program(pgm, args = []): 00814 """!Attempt to run a program, with optional arguments. 00815 00816 @param pgm program name 00817 @param args list of arguments 00818 00819 @return False if the attempt failed due to a missing executable 00820 @return True otherwise 00821 """ 00822 nuldev = file(os.devnull, 'w+') 00823 try: 00824 ret = call([pgm] + args, stdin = nuldev, stdout = nuldev, stderr = nuldev) 00825 if ret == 0: 00826 found = True 00827 else: 00828 found = False 00829 except: 00830 found = False 00831 nuldev.close() 00832 00833 return found 00834 00835 # try to remove a file, without complaints 00836 00837 def try_remove(path): 00838 """!Attempt to remove a file; no exception is generated if the 00839 attempt fails. 00840 00841 @param path path to file to remove 00842 """ 00843 try: 00844 os.remove(path) 00845 except: 00846 pass 00847 00848 # try to remove a directory, without complaints 00849 00850 def try_rmdir(path): 00851 """!Attempt to remove a directory; no exception is generated if the 00852 attempt fails. 00853 00854 @param path path to directory to remove 00855 """ 00856 try: 00857 os.rmdir(path) 00858 except: 00859 shutil.rmtree(path, ignore_errors = True) 00860 00861 def float_or_dms(s): 00862 """!Convert DMS to float. 00863 00864 @param s DMS value 00865 00866 @return float value 00867 """ 00868 return sum(float(x) / 60 ** n for (n, x) in enumerate(s.split(':'))) 00869 00870 # interface to g.mapsets 00871 00872 def mapsets(search_path = False): 00873 """!List available mapsets 00874 00875 @param searchPatch True to list mapsets only in search path 00876 00877 @return list of mapsets 00878 """ 00879 if search_path: 00880 flags = 'p' 00881 else: 00882 flags = 'l' 00883 mapsets = read_command('g.mapsets', 00884 flags = flags, 00885 fs = 'newline', 00886 quiet = True) 00887 if not mapsets: 00888 fatal(_("Unable to list mapsets")) 00889 00890 return mapsets.splitlines() 00891 00892 # interface to `g.proj -c` 00893 00894 def create_location(dbase, location, 00895 epsg = None, proj4 = None, filename = None, wkt = None, 00896 datum = None, desc = None): 00897 """!Create new location 00898 00899 Raise ScriptError on error. 00900 00901 @param dbase path to GRASS database 00902 @param location location name to create 00903 @param epgs if given create new location based on EPSG code 00904 @param proj4 if given create new location based on Proj4 definition 00905 @param filename if given create new location based on georeferenced file 00906 @param wkt if given create new location based on WKT definition (path to PRJ file) 00907 @param datum datum transformation parameters (used for epsg and proj4) 00908 @param desc description of the location (creates MYNAME file) 00909 """ 00910 gisdbase = None 00911 if epsg or proj4 or filename or wkt: 00912 gisdbase = gisenv()['GISDBASE'] 00913 run_command('g.gisenv', 00914 set = 'GISDBASE=%s' % dbase) 00915 if not os.path.exists(dbase): 00916 os.mkdir(dbase) 00917 00918 kwargs = dict() 00919 if datum: 00920 kwargs['datum'] = datum 00921 00922 if epsg: 00923 ps = pipe_command('g.proj', 00924 quiet = True, 00925 flags = 'c', 00926 epsg = epsg, 00927 location = location, 00928 stderr = PIPE, 00929 **kwargs) 00930 elif proj4: 00931 ps = pipe_command('g.proj', 00932 quiet = True, 00933 flags = 'c', 00934 proj4 = proj4, 00935 location = location, 00936 stderr = PIPE, 00937 **kwargs) 00938 elif filename: 00939 ps = pipe_command('g.proj', 00940 quiet = True, 00941 flags = 'c', 00942 georef = filename, 00943 location = location, 00944 stderr = PIPE) 00945 elif wkt: 00946 ps = pipe_command('g.proj', 00947 quiet = True, 00948 flags = 'c', 00949 wkt = wkt, 00950 location = location, 00951 stderr = PIPE) 00952 else: 00953 _create_location_xy(dbase, location) 00954 00955 if epsg or proj4 or filename or wkt: 00956 error = ps.communicate()[1] 00957 run_command('g.gisenv', 00958 set = 'GISDBASE=%s' % gisdbase) 00959 00960 if ps.returncode != 0 and error: 00961 raise ScriptError(repr(error)) 00962 00963 try: 00964 fd = codecs.open(os.path.join(dbase, location, 00965 'PERMANENT', 'MYNAME'), 00966 encoding = 'utf-8', mode = 'w') 00967 if desc: 00968 fd.write(desc + os.linesep) 00969 else: 00970 fd.write(os.linesep) 00971 fd.close() 00972 except OSError, e: 00973 raise ScriptError(repr(e)) 00974 00975 def _create_location_xy(database, location): 00976 """!Create unprojected location 00977 00978 Raise ScriptError on error. 00979 00980 @param database GRASS database where to create new location 00981 @param location location name 00982 """ 00983 cur_dir = os.getcwd() 00984 try: 00985 os.chdir(database) 00986 os.mkdir(location) 00987 os.mkdir(os.path.join(location, 'PERMANENT')) 00988 00989 # create DEFAULT_WIND and WIND files 00990 regioninfo = ['proj: 0', 00991 'zone: 0', 00992 'north: 1', 00993 'south: 0', 00994 'east: 1', 00995 'west: 0', 00996 'cols: 1', 00997 'rows: 1', 00998 'e-w resol: 1', 00999 'n-s resol: 1', 01000 'top: 1', 01001 'bottom: 0', 01002 'cols3: 1', 01003 'rows3: 1', 01004 'depths: 1', 01005 'e-w resol3: 1', 01006 'n-s resol3: 1', 01007 't-b resol: 1'] 01008 01009 defwind = open(os.path.join(location, 01010 "PERMANENT", "DEFAULT_WIND"), 'w') 01011 for param in regioninfo: 01012 defwind.write(param + '%s' % os.linesep) 01013 defwind.close() 01014 01015 shutil.copy(os.path.join(location, "PERMANENT", "DEFAULT_WIND"), 01016 os.path.join(location, "PERMANENT", "WIND")) 01017 01018 os.chdir(cur_dir) 01019 except OSError, e: 01020 raise ScriptError(repr(e)) 01021 01022 # interface to g.version 01023 01024 def version(): 01025 """!Get GRASS version as dictionary 01026 01027 @code 01028 print version() 01029 01030 {'date': '2011', 'libgis_date': '2011-04-13 13:19:03 +0200 (Wed, 13 Apr 2011)', 01031 'version': '6.4.2svn', 'libgis_revision': '45934', 'revision': '47445'} 01032 @endcode 01033 """ 01034 data = parse_command('g.version', 01035 flags = 'rg') 01036 for k, v in data.iteritems(): 01037 data[k.strip()] = v.replace('"', '').strip() 01038 01039 return data 01040 01041 # get debug_level 01042 if find_program('g.gisenv', ['--help']): 01043 debug_level = int(gisenv().get('DEBUG', 0))