[GRASS-SVN] r54569 - in grass/trunk/lib/python: . script
svn_grass at osgeo.org
svn_grass at osgeo.org
Tue Jan 8 01:34:43 PST 2013
Author: martinl
Date: 2013-01-08 01:34:42 -0800 (Tue, 08 Jan 2013)
New Revision: 54569
Added:
grass/trunk/lib/python/__init__.py
grass/trunk/lib/python/script/
grass/trunk/lib/python/script/Makefile
grass/trunk/lib/python/script/__init__.py
grass/trunk/lib/python/script/array.py
grass/trunk/lib/python/script/core.py
grass/trunk/lib/python/script/db.py
grass/trunk/lib/python/script/raster.py
grass/trunk/lib/python/script/raster3d.py
grass/trunk/lib/python/script/setup.py.sed
grass/trunk/lib/python/script/task.py
grass/trunk/lib/python/script/vector.py
Removed:
grass/trunk/lib/python/__init__.py
grass/trunk/lib/python/array.py
grass/trunk/lib/python/core.py
grass/trunk/lib/python/db.py
grass/trunk/lib/python/grass__init__.py
grass/trunk/lib/python/raster.py
grass/trunk/lib/python/raster3d.py
grass/trunk/lib/python/setup.py.sed
grass/trunk/lib/python/task.py
grass/trunk/lib/python/vector.py
Modified:
grass/trunk/lib/python/
grass/trunk/lib/python/Makefile
Log:
pythonlib: update layout
Property changes on: grass/trunk/lib/python
___________________________________________________________________
Modified: svn:ignore
- OBJ.*
setup.py
+
Modified: grass/trunk/lib/python/Makefile
===================================================================
--- grass/trunk/lib/python/Makefile 2013-01-08 08:35:23 UTC (rev 54568)
+++ grass/trunk/lib/python/Makefile 2013-01-08 09:34:42 UTC (rev 54569)
@@ -1,48 +1,26 @@
MODULE_TOPDIR = ../..
-include $(MODULE_TOPDIR)/include/Make/Other.make
+#include $(MODULE_TOPDIR)/include/Make/Other.make
+include $(MODULE_TOPDIR)/include/Make/Dir.make
include $(MODULE_TOPDIR)/include/Make/Python.make
include $(MODULE_TOPDIR)/include/Make/Doxygen.make
-PYDIR = $(ETC)/python
-GDIR = $(PYDIR)/grass
-DSTDIR = $(GDIR)/script
+PYDIR = $(ETC)/python/grass
-MODULES = core db raster raster3d vector array setup task
+SUBDIRS = script ctypes temporal pygrass
-PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
-PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)
+default: $(PYDIR)/__init__.py
+ $(MAKE) subdirs
+# -$(MAKE) -C script || echo $(CURDIR)/script >> $(ERRORLOG)
+# -$(MAKE) -C ctypes || echo $(CURDIR)/ctypes >> $(ERRORLOG)
+# -$(MAKE) -C temporal || echo $(CURDIR)/temporal >> $(ERRORLOG)
+# -$(MAKE) -C pygrass || echo $(CURDIR)/pygrass >> $(ERRORLOG)
-CLEAN_SUBDIRS = ctypes temporal pygrass
-EXTRA_CLEAN_FILES = setup.py
-
-default: $(PYFILES) $(PYCFILES) $(GDIR)/__init__.py $(GDIR)/__init__.pyc
- -$(MAKE) -C ctypes || echo $(CURDIR)/ctypes >> $(ERRORLOG)
- -$(MAKE) -C temporal || echo $(CURDIR)/temporal >> $(ERRORLOG)
- -$(MAKE) -C pygrass || echo $(CURDIR)/pygrass >> $(ERRORLOG)
-
$(PYDIR):
$(MKDIR) $@
-$(GDIR): | $(PYDIR)
- $(MKDIR) $@
-
-$(DSTDIR): | $(GDIR)
- $(MKDIR) $@
-
-$(GDIR)/__init__.py: grass__init__.py | $(GDIR)
+$(PYDIR)/__init__.py: __init__.py | $(PYDIR)
$(INSTALL_DATA) $< $@
-$(DSTDIR)/%: % | $(DSTDIR)
- $(INSTALL_DATA) $< $@
-
-$(DSTDIR)/setup.py: setup.py | $(DSTDIR)
- $(INSTALL_DATA) $< $@
-
-setup.py: setup.py.sed
- sed \
- -e 's#@LD_LIBRARY_PATH_VAR@#$(LD_LIBRARY_PATH_VAR)#' \
- $< > $@
-
-#doxygen:
+# doxygen
DOXNAME = python
Deleted: grass/trunk/lib/python/__init__.py
===================================================================
--- grass/trunk/lib/python/__init__.py 2013-01-08 08:35:23 UTC (rev 54568)
+++ grass/trunk/lib/python/__init__.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -1,5 +0,0 @@
-from core import *
-from db import *
-from raster import *
-from raster3d import *
-from vector import *
Copied: grass/trunk/lib/python/__init__.py (from rev 54568, grass/trunk/lib/python/grass__init__.py)
===================================================================
--- grass/trunk/lib/python/__init__.py (rev 0)
+++ grass/trunk/lib/python/__init__.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -0,0 +1,4 @@
+import os
+__all__ = ["script", "temporal"]
+if os.path.exists(os.path.join(os.path.dirname(__file__), "lib", "__init__.py")):
+ __all__.append("lib")
Deleted: grass/trunk/lib/python/array.py
===================================================================
--- grass/trunk/lib/python/array.py 2013-01-08 08:35:23 UTC (rev 54568)
+++ grass/trunk/lib/python/array.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -1,356 +0,0 @@
-"""!@package grass.script.array
-
- at brief GRASS Python scripting module (2D and 3D raster with numpy)
-
-Functions to use GRASS 2D and 3D rasters with NumPy.
-
-Usage:
-
- at code
-
->>> import grass.script as grass
->>> from grass.script import array as garray
->>>
->>> # We create a temporary region that is only valid in this python session
-... grass.use_temp_region()
->>> grass.run_command("g.region", n=80, e=120, t=60, s=0, w=0, b=0, res=20, res3=20)
-0
->>>
->>> # Lets create a raster map numpy array
-... # based at the current region settings
-... map2d_1 = garray.array()
->>>
->>> # Write some data
-... for y in range(map2d_1.shape[0]):
-... for x in range(map2d_1.shape[1]):
-... map2d_1[y][x] = y + x
-...
->>> # Lets have a look at the array
-... print map2d_1
-[[ 0. 1. 2. 3. 4. 5.]
- [ 1. 2. 3. 4. 5. 6.]
- [ 2. 3. 4. 5. 6. 7.]
- [ 3. 4. 5. 6. 7. 8.]]
->>> # This will write the numpy array as GRASS raster map
-... # with name map2d_1
-... map2d_1.write(mapname="map2d_1", overwrite=True)
- 100%
-0
->>>
->>> # We create a new array and read map2d_1 to modify it
-... map2d_2 = garray.array()
->>> # Don't do map2d_2 = map2d_1 % 3
-... # because: this will overwrite the internal temporary filename
-... map2d_2.read("map2d_1")
-0
->>> map2d_2 %= 3
->>> # Show the result
-... print map2d_2
-[[ 0. 1. 2. 0. 1. 2.]
- [ 1. 2. 0. 1. 2. 0.]
- [ 2. 0. 1. 2. 0. 1.]
- [ 0. 1. 2. 0. 1. 2.]]
->>> # Write the result as new raster map with name map2d_2
-... map2d_2.write(mapname="map2d_2", overwrite=True)
- 100%
-0
->>>
->>> # Here we create a 3D raster map numpy array
-... # based in the current region settings
-... map3d_1 = garray.array3d()
->>>
->>> # Write some data
-... # Note: the 3D array has map[depth][row][column] order
-... for z in range(map3d_1.shape[0]):
-... for y in range(map3d_1.shape[1]):
-... for x in range(map3d_1.shape[2]):
-... map3d_1[z][y][x] = z + y + x
-...
->>> # Lets have a look at the 3D array
-... print map3d_1
-[[[ 0. 1. 2. 3. 4. 5.]
- [ 1. 2. 3. 4. 5. 6.]
- [ 2. 3. 4. 5. 6. 7.]
- [ 3. 4. 5. 6. 7. 8.]]
-
- [[ 1. 2. 3. 4. 5. 6.]
- [ 2. 3. 4. 5. 6. 7.]
- [ 3. 4. 5. 6. 7. 8.]
- [ 4. 5. 6. 7. 8. 9.]]
-
- [[ 2. 3. 4. 5. 6. 7.]
- [ 3. 4. 5. 6. 7. 8.]
- [ 4. 5. 6. 7. 8. 9.]
- [ 5. 6. 7. 8. 9. 10.]]]
->>> # This will write the numpy array as GRASS 3D raster map
-... # with name map3d_1
-... map3d_1.write(mapname="map3d_1", overwrite=True)
-Loading floating point data with 8 bytes ... (6x4x3)
- 100%
-0
->>> # We create a new 3D array and read map3d_1 to modify it
-... map3d_2 = garray.array3d()
->>> # Don't do map3d_2 = map3d_1 % 3
-... # because: this will overwrite the internal temporary filename
-... map3d_2.read("map3d_1")
-0
->>> map3d_2 %= 3
->>> # Show the result
-... print map3d_2
-[[[ 0. 1. 2. 0. 1. 2.]
- [ 1. 2. 0. 1. 2. 0.]
- [ 2. 0. 1. 2. 0. 1.]
- [ 0. 1. 2. 0. 1. 2.]]
-
- [[ 1. 2. 0. 1. 2. 0.]
- [ 2. 0. 1. 2. 0. 1.]
- [ 0. 1. 2. 0. 1. 2.]
- [ 1. 2. 0. 1. 2. 0.]]
-
- [[ 2. 0. 1. 2. 0. 1.]
- [ 0. 1. 2. 0. 1. 2.]
- [ 1. 2. 0. 1. 2. 0.]
- [ 2. 0. 1. 2. 0. 1.]]]
->>> # Write the result as new 3D raster map with name map3d_2
-... map3d_2.write(mapname="map3d_2", overwrite=True)
-Loading floating point data with 8 bytes ... (6x4x3)
- 100%
-0
-
- at endcode
-
-(C) 2010-2012 by Glynn Clements and the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Glynn Clements
-"""
-
-import os
-import numpy
-
-import core as grass
-
-###############################################################################
-
-class array(numpy.memmap):
- def __new__(cls, dtype=numpy.double):
- """!Define new numpy array
-
- @param cls
- @param dtype data type (default: numpy.double)
- """
- reg = grass.region()
- r = reg['rows']
- c = reg['cols']
- shape = (r, c)
-
- filename = grass.tempfile()
-
- self = numpy.memmap.__new__(
- cls,
- filename=filename,
- dtype=dtype,
- mode='w+',
- shape=shape)
-
- self.filename = filename
- return self
-
- def _close(self):
- numpy.memmap._close(self)
- if isinstance(self, array):
- grass.try_remove(self.filename)
-
- def read(self, mapname, null=None):
- """!Read raster map into array
-
- @param mapname name of raster map to be read
- @param null null value
-
- @return 0 on success
- @return non-zero code on failure
- """
- kind = self.dtype.kind
- size = self.dtype.itemsize
-
- if kind == 'f':
- flags = 'f'
- elif kind in 'biu':
- flags = 'i'
- else:
- raise ValueError(_('Invalid kind <%s>') % kind)
-
- if size not in [1, 2, 4, 8]:
- raise ValueError(_('Invalid size <%d>') % size)
-
- return grass.run_command(
- 'r.out.bin',
- flags=flags,
- input=mapname,
- output=self.filename,
- bytes=size,
- null=null,
- quiet=True,
- overwrite=True)
-
- def write(self, mapname, title=None, null=None, overwrite=None):
- """!Write array into raster map
-
- @param mapname name for raster map
- @param title title for raster map
- @param null null value
- @param overwrite True for overwritting existing raster maps
-
- @return 0 on success
- @return non-zero code on failure
- """
- kind = self.dtype.kind
- size = self.dtype.itemsize
-
- if kind == 'f':
- if size == 4:
- flags = 'f'
- elif size == 8:
- flags = 'd'
- else:
- raise ValueError(_('Invalid FP size <%d>') % size)
- size = None
- elif kind in 'biu':
- if size not in [1, 2, 4]:
- raise ValueError(_('Invalid integer size <%d>') % size)
- flags = None
- else:
- raise ValueError(_('Invalid kind <%s>') % kind)
-
- reg = grass.region()
-
- return grass.run_command(
- 'r.in.bin',
- flags=flags,
- input=self.filename,
- output=mapname,
- title=title,
- bytes=size,
- anull=null,
- overwrite=overwrite,
- verbose=True,
- north=reg['n'],
- south=reg['s'],
- east=reg['e'],
- west=reg['w'],
- rows=reg['rows'],
- cols=reg['cols'])
-
-###############################################################################
-
-class array3d(numpy.memmap):
- def __new__(cls, dtype=numpy.double):
- """!Define new 3d numpy array
-
- @param cls
- @param dtype data type (default: numpy.double)
- """
- reg = grass.region(True)
- r = reg['rows3']
- c = reg['cols3']
- d = reg['depths']
- shape = (d, r, c)
-
- filename = grass.tempfile()
-
- self = numpy.memmap.__new__(
- cls,
- filename=filename,
- dtype=dtype,
- mode='w+',
- shape=shape)
-
- self.filename = filename
-
- return self
-
- def _close(self):
-
- numpy.memmap._close(self)
- if isinstance(self, array):
- grass.try_remove(self.filename)
-
- def read(self, mapname, null=None):
- """!Read 3D raster map into array
-
- @param mapname name of 3D raster map to be read
- @param null null value
-
- @return 0 on success
- @return non-zero code on failure
- """
- kind = self.dtype.kind
- size = self.dtype.itemsize
-
- if kind == 'f':
- flags = None # default is double
- elif kind in 'biu':
- flags = 'i'
- else:
- raise ValueError(_('Invalid kind <%s>') % kind)
-
- if size not in [1, 2, 4, 8]:
- raise ValueError(_('Invalid size <%d>') % size)
-
- return grass.run_command(
- 'r3.out.bin',
- flags=flags,
- input=mapname,
- output=self.filename,
- bytes=size,
- null=null,
- quiet=True,
- overwrite=True)
-
- def write(self, mapname, null=None, overwrite=None):
- """!Write array into 3D raster map
-
- @param mapname name for 3D raster map
- @param null null value
- @param overwrite True for overwriting existing raster maps
-
- @return 0 on success
- @return non-zero code on failure
- """
- kind = self.dtype.kind
- size = self.dtype.itemsize
- flags = None
-
- if kind == 'f':
- if size != 4 and size != 8:
- raise ValueError(_('Invalid FP size <%d>') % size)
- elif kind in 'biu':
- if size not in [1, 2, 4, 8]:
- raise ValueError(_('Invalid integer size <%d>') % size)
- flags = 'i'
- else:
- raise ValueError(_('Invalid kind <%s>') % kind)
-
- reg = grass.region(True)
-
- return grass.run_command(
- 'r3.in.bin',
- flags=flags,
- input=self.filename,
- output=mapname,
- bytes=size,
- null=null,
- overwrite=overwrite,
- verbose=True,
- north=reg['n'],
- south=reg['s'],
- top=reg['t'],
- bottom=reg['b'],
- east=reg['e'],
- west=reg['w'],
- depths=reg['depths'],
- rows=reg['rows3'],
- cols=reg['cols3'])
-
Deleted: grass/trunk/lib/python/core.py
===================================================================
--- grass/trunk/lib/python/core.py 2013-01-08 08:35:23 UTC (rev 54568)
+++ grass/trunk/lib/python/core.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -1,1391 +0,0 @@
-"""!@package grass.script.core
-
- at brief GRASS Python scripting module (core functions)
-
-Core functions to be used in Python scripts.
-
-Usage:
-
- at code
-from grass.script import core as grass
-
-grass.parser()
-...
- at endcode
-
-(C) 2008-2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Glynn Clements
- at author Martin Landa <landa.martin gmail.com>
- at author Michael Barton <michael.barton asu.edu>
-"""
-
-import os
-import sys
-import types
-import re
-import atexit
-import subprocess
-import shutil
-import locale
-import codecs
-
-# i18N
-import gettext
-gettext.install('grasslibs', os.path.join(os.getenv("GISBASE"), 'locale'))
-
-# subprocess wrapper that uses shell on Windows
-
-class Popen(subprocess.Popen):
- def __init__(self, args, bufsize = 0, executable = None,
- stdin = None, stdout = None, stderr = None,
- preexec_fn = None, close_fds = False, shell = None,
- cwd = None, env = None, universal_newlines = False,
- startupinfo = None, creationflags = 0):
-
- if shell == None:
- shell = (sys.platform == "win32")
-
- subprocess.Popen.__init__(self, args, bufsize, executable,
- stdin, stdout, stderr,
- preexec_fn, close_fds, shell,
- cwd, env, universal_newlines,
- startupinfo, creationflags)
-
-PIPE = subprocess.PIPE
-STDOUT = subprocess.STDOUT
-
-class ScriptError(Exception):
- def __init__(self, msg):
- self.value = msg
-
- def __str__(self):
- return self.value
-
-raise_on_error = False # raise exception instead of calling fatal()
-
-def call(*args, **kwargs):
- return Popen(*args, **kwargs).wait()
-
-# GRASS-oriented interface to subprocess module
-
-_popen_args = ["bufsize", "executable", "stdin", "stdout", "stderr",
- "preexec_fn", "close_fds", "cwd", "env",
- "universal_newlines", "startupinfo", "creationflags"]
-
-def decode(string):
- enc = locale.getdefaultlocale()[1]
- if enc:
- return string.decode(enc)
-
- return string
-
-def _make_val(val):
- if isinstance(val, types.StringType) or \
- isinstance(val, types.UnicodeType):
- return val
- if isinstance(val, types.ListType):
- return ",".join(map(_make_val, val))
- if isinstance(val, types.TupleType):
- return _make_val(list(val))
- return str(val)
-
-def get_commands():
- """!Create list of available GRASS commands to use when parsing
- string from the command line
-
- @return list of commands (set) and directory of scripts (collected
- by extension - MS Windows only)
-
- @code
- >>> cmds = list(get_commands()[0])
- >>> cmds.sort()
- >>> cmds[:5]
- ['d.barscale', 'd.colorlist', 'd.colortable', 'd.erase', 'd.font']
-
- @endcode
- """
- gisbase = os.environ['GISBASE']
- cmd = list()
- scripts = {'.py': list()} if sys.platform == 'win32' else {}
-
- def scan(gisbase, directory):
- dir_path = os.path.join(gisbase, directory)
- if os.path.exists(dir_path):
- for fname in os.listdir(os.path.join(gisbase, directory)):
- if scripts: # win32
- name, ext = os.path.splitext(fname)
- if ext != '.manifest':
- cmd.append(name)
- if ext in scripts.keys():
- scripts[ext].append(name)
- else:
- cmd.append(fname)
-
- for directory in ('bin', 'scripts'):
- scan(gisbase, directory)
-
- # scan gui/scripts/
- gui_path = os.path.join(gisbase, 'etc', 'gui', 'scripts')
- if os.path.exists(gui_path):
- os.environ["PATH"] = os.getenv("PATH") + os.pathsep + gui_path
- cmd = cmd + os.listdir(gui_path)
-
- return set(cmd), scripts
-
-
-def make_command(prog, flags = "", overwrite = False, quiet = False, verbose = False, **options):
- """!Return a list of strings suitable for use as the args parameter to
- Popen() or call(). Example:
-
- @code
- >>> grass.make_command("g.message", flags = 'w', message = 'this is a warning')
- ['g.message', '-w', 'message=this is a warning']
- @endcode
-
- @param prog GRASS module
- @param flags flags to be used (given as a string)
- @param overwrite True to enable overwriting the output (<tt>--o</tt>)
- @param quiet True to run quietly (<tt>--q</tt>)
- @param verbose True to run verbosely (<tt>--v</tt>)
- @param options module's parameters
-
- @return list of arguments
- """
- args = [prog]
- if overwrite:
- args.append("--o")
- if quiet:
- args.append("--q")
- if verbose:
- args.append("--v")
- if flags:
- if '-' in flags:
- raise ScriptError("'-' is not a valid flag")
- args.append("-%s" % flags)
- for opt, val in options.iteritems():
- if val != None:
- if opt[0] == '_':
- opt = opt[1:]
- args.append("%s=%s" % (opt, _make_val(val)))
- return args
-
-def start_command(prog, flags = "", overwrite = False, quiet = False, verbose = False, **kwargs):
- """!Returns a Popen object with the command created by make_command.
- Accepts any of the arguments which Popen() accepts apart from "args"
- and "shell".
-
- \code
- >>> p = grass.start_command("g.gisenv", stdout = subprocess.PIPE)
- >>> print p
- <subprocess.Popen object at 0xb7c12f6c>
- >>> print p.communicate()[0]
- GISDBASE='/opt/grass-data';
- LOCATION_NAME='spearfish60';
- MAPSET='glynn';
- GRASS_DB_ENCODING='ascii';
- GUI='text';
- MONITOR='x0';
- \endcode
-
- @param prog GRASS module
- @param flags flags to be used (given as a string)
- @param overwrite True to enable overwriting the output (<tt>--o</tt>)
- @param quiet True to run quietly (<tt>--q</tt>)
- @param verbose True to run verbosely (<tt>--v</tt>)
- @param kwargs module's parameters
-
- @return Popen object
- """
- options = {}
- popts = {}
- for opt, val in kwargs.iteritems():
- if opt in _popen_args:
- popts[opt] = val
- else:
- options[opt] = val
-
- args = make_command(prog, flags, overwrite, quiet, verbose, **options)
-
- if debug_level() > 0:
- sys.stderr.write("D1/%d: %s.start_command(): %s\n" % (debug_level(), __name__, ' '.join(args)))
- sys.stderr.flush()
-
- return Popen(args, **popts)
-
-def run_command(*args, **kwargs):
- """!Passes all arguments to start_command(), then waits for the process to
- complete, returning its exit code. Similar to subprocess.call(), but
- with the make_command() interface.
-
- @param args list of unnamed arguments (see start_command() for details)
- @param kwargs list of named arguments (see start_command() for details)
-
- @return exit code (0 for success)
- """
- ps = start_command(*args, **kwargs)
- return ps.wait()
-
-def pipe_command(*args, **kwargs):
- """!Passes all arguments to start_command(), but also adds
- "stdout = PIPE". Returns the Popen object.
-
- \code
- >>> p = grass.pipe_command("g.gisenv")
- >>> print p
- <subprocess.Popen object at 0xb7c12f6c>
- >>> print p.communicate()[0]
- GISDBASE='/opt/grass-data';
- LOCATION_NAME='spearfish60';
- MAPSET='glynn';
- GRASS_DB_ENCODING='ascii';
- GUI='text';
- MONITOR='x0';
- \endcode
-
- @param args list of unnamed arguments (see start_command() for details)
- @param kwargs list of named arguments (see start_command() for details)
-
- @return Popen object
- """
- kwargs['stdout'] = PIPE
- return start_command(*args, **kwargs)
-
-def feed_command(*args, **kwargs):
- """!Passes all arguments to start_command(), but also adds
- "stdin = PIPE". Returns the Popen object.
-
- @param args list of unnamed arguments (see start_command() for details)
- @param kwargs list of named arguments (see start_command() for details)
-
- @return Popen object
- """
- kwargs['stdin'] = PIPE
- return start_command(*args, **kwargs)
-
-def read_command(*args, **kwargs):
- """!Passes all arguments to pipe_command, then waits for the process to
- complete, returning its stdout (i.e. similar to shell `backticks`).
-
- @param args list of unnamed arguments (see start_command() for details)
- @param kwargs list of named arguments (see start_command() for details)
-
- @return stdout
- """
- ps = pipe_command(*args, **kwargs)
- return ps.communicate()[0]
-
-def parse_command(*args, **kwargs):
- """!Passes all arguments to read_command, then parses the output
- by parse_key_val().
-
- Parsing function can be optionally given by <em>parse</em> parameter
- including its arguments, e.g.
-
- @code
- parse_command(..., parse = (grass.parse_key_val, { 'sep' : ':' }))
- @endcode
-
- or you can simply define <em>delimiter</em>
-
- @code
- parse_command(..., delimiter = ':')
- @endcode
-
- @param args list of unnamed arguments (see start_command() for details)
- @param kwargs list of named arguments (see start_command() for details)
-
- @return parsed module output
- """
- parse = None
- parse_args = {}
- if 'parse' in kwargs:
- if type(kwargs['parse']) is types.TupleType:
- parse = kwargs['parse'][0]
- parse_args = kwargs['parse'][1]
- del kwargs['parse']
-
- if 'delimiter' in kwargs:
- parse_args = { 'sep' : kwargs['delimiter'] }
- del kwargs['delimiter']
-
- if not parse:
- parse = parse_key_val # use default fn
-
- res = read_command(*args, **kwargs)
-
- return parse(res, **parse_args)
-
-def write_command(*args, **kwargs):
- """!Passes all arguments to feed_command, with the string specified
- by the 'stdin' argument fed to the process' stdin.
-
- @param args list of unnamed arguments (see start_command() for details)
- @param kwargs list of named arguments (see start_command() for details)
-
- @return return code
- """
- stdin = kwargs['stdin']
- p = feed_command(*args, **kwargs)
- p.stdin.write(stdin)
- p.stdin.close()
- return p.wait()
-
-def exec_command(prog, flags = "", overwrite = False, quiet = False, verbose = False, env = None, **kwargs):
- """!Interface to os.execvpe(), but with the make_command() interface.
-
- @param prog GRASS module
- @param flags flags to be used (given as a string)
- @param overwrite True to enable overwriting the output (<tt>--o</tt>)
- @param quiet True to run quietly (<tt>--q</tt>)
- @param verbose True to run verbosely (<tt>--v</tt>)
- @param env directory with environmental variables
- @param kwargs module's parameters
-
- """
- args = make_command(prog, flags, overwrite, quiet, verbose, **kwargs)
- if env == None:
- env = os.environ
- os.execvpe(prog, args, env)
-
-# interface to g.message
-
-def message(msg, flag = None):
- """!Display a message using `g.message`
-
- @param msg message to be displayed
- @param flag flags (given as string)
- """
- run_command("g.message", flags = flag, message = msg)
-
-def debug(msg, debug = 1):
- """!Display a debugging message using `g.message -d`
-
- @param msg debugging message to be displayed
- @param debug debug level (0-5)
- """
- run_command("g.message", flags = 'd', message = msg, debug = debug)
-
-def verbose(msg):
- """!Display a verbose message using `g.message -v`
-
- @param msg verbose message to be displayed
- """
- message(msg, flag = 'v')
-
-def info(msg):
- """!Display an informational message using `g.message -i`
-
- @param msg informational message to be displayed
- """
- message(msg, flag = 'i')
-
-def percent(i, n, s):
- """!Display a progress info message using `g.message -p`
-
- @code
- message(_("Percent complete..."))
- n = 100
- for i in range(n):
- percent(i, n, 1)
- percent(1, 1, 1)
- @endcode
-
- @param i current item
- @param n total number of items
- @param s increment size
- """
- message("%d %d %d" % (i, n, s), flag = 'p')
-
-def warning(msg):
- """!Display a warning message using `g.message -w`
-
- @param msg warning message to be displayed
- """
- message(msg, flag = 'w')
-
-def error(msg):
- """!Display an error message using `g.message -e`
-
- @param msg error message to be displayed
- """
- message(msg, flag = 'e')
-
-def fatal(msg):
- """!Display an error message using `g.message -e`, then abort
-
- Raise exception when raise_on_error is 'True'.
-
- @param msg error message to be displayed
- """
- global raise_on_error
- if raise_on_error:
- raise ScriptError(msg)
-
- error(msg)
- sys.exit(1)
-
-def set_raise_on_error(raise_exp = True):
- """!Define behaviour on fatal error (fatal() called)
-
- @param raise_exp True to raise ScriptError instead of calling
- sys.exit(1) in fatal()
-
- @return current status
- """
- global raise_on_error
- tmp_raise = raise_on_error
- raise_on_error = raise_exp
- return tmp_raise
-
-# interface to g.parser
-
-def _parse_opts(lines):
- options = {}
- flags = {}
- for line in lines:
- line = line.rstrip('\r\n')
- if not line:
- break
- try:
- [var, val] = line.split('=', 1)
- except:
- raise SyntaxError("invalid output from g.parser: %s" % line)
-
- if var.startswith('flag_'):
- flags[var[5:]] = bool(int(val))
- elif var.startswith('opt_'):
- options[var[4:]] = val
- elif var in ['GRASS_OVERWRITE', 'GRASS_VERBOSE']:
- os.environ[var] = val
- else:
- raise SyntaxError("invalid output from g.parser: %s" % line)
-
- return (options, flags)
-
-def parser():
- """!Interface to g.parser, intended to be run from the top-level, e.g.:
-
- @code
- if __name__ == "__main__":
- options, flags = grass.parser()
- main()
- @endcode
-
- Thereafter, the global variables "options" and "flags" will be
- dictionaries containing option/flag values, keyed by lower-case
- option/flag names. The values in "options" are strings, those in
- "flags" are Python booleans.
- """
- if not os.getenv("GISBASE"):
- print >> sys.stderr, "You must be in GRASS GIS to run this program."
- sys.exit(1)
-
- cmdline = [basename(sys.argv[0])]
- cmdline += ['"' + arg + '"' for arg in sys.argv[1:]]
- os.environ['CMDLINE'] = ' '.join(cmdline)
-
- argv = sys.argv[:]
- name = argv[0]
- if not os.path.isabs(name):
- if os.sep in name or (os.altsep and os.altsep in name):
- argv[0] = os.path.abspath(name)
- else:
- argv[0] = os.path.join(sys.path[0], name)
-
- p = Popen(['g.parser', '-s'] + argv, stdout = PIPE)
- s = p.communicate()[0]
- lines = s.splitlines()
-
- if not lines or lines[0].rstrip('\r\n') != "@ARGS_PARSED@":
- sys.stdout.write(s)
- sys.exit(p.returncode)
-
- return _parse_opts(lines[1:])
-
-# interface to g.tempfile
-
-def tempfile(create = True):
- """!Returns the name of a temporary file, created with
- g.tempfile.
-
- @param create True to create a file
-
- @return path to a tmp file
- """
- flags = ''
- if not create:
- flags += 'd'
-
- return read_command("g.tempfile", flags = flags, pid = os.getpid()).strip()
-
-def tempdir():
- """!Returns the name of a temporary dir, created with g.tempfile."""
- tmp = tempfile(create = False)
- os.mkdir(tmp)
-
- return tmp
-
-class KeyValue(dict):
- """A general-purpose key-value store.
-
- KeyValue is a subclass of dict, but also allows entries to be read and
- written using attribute syntax. Example:
-
- \code
- >>> region = grass.region()
- >>> region['rows']
- 477
- >>> region.rows
- 477
- \endcode
- """
-
- def __getattr__(self, key):
- return self[key]
-
- def __setattr__(self, key, value):
- self[key] = value
-
-# key-value parsers
-
-def parse_key_val(s, sep = '=', dflt = None, val_type = None, vsep = None):
- """!Parse a string into a dictionary, where entries are separated
- by newlines and the key and value are separated by `sep' (default: `=')
-
- @param s string to be parsed
- @param sep key/value separator
- @param dflt default value to be used
- @param val_type value type (None for no cast)
- @param vsep vertical separator (default os.linesep)
-
- @return parsed input (dictionary of keys/values)
- """
- result = KeyValue()
-
- if not s:
- return result
-
- if vsep:
- lines = s.split(vsep)
- try:
- lines.remove('\n')
- except ValueError:
- pass
- else:
- lines = s.splitlines()
-
- for line in lines:
- kv = line.split(sep, 1)
- k = kv[0].strip()
- if len(kv) > 1:
- v = kv[1].strip()
- else:
- v = dflt
-
- if val_type:
- result[k] = val_type(v)
- else:
- result[k] = v
-
- return result
-
-def _text_to_key_value_dict(filename, sep=":", val_sep=","):
- """
- !Convert a key-value text file, where entries are separated
- by newlines and the key and value are separated by `sep',
- into a key-value dictionary and discover/use the correct
- data types (float, int or string) for values.
-
- @param filename The name or name and path of the text file to convert
- @param sep The character that separates the keys and values, default is ":"
- @param val_sep The character that separates the values of a single key, default is ","
- @return The dictionary
-
- A text file with this content:
- \code
- a: Hello
- b: 1.0
- c: 1,2,3,4,5
- d : hello,8,0.1
- \endcode
-
- Will be represented as this dictionary:
- \code
- {'a': ['Hello'], 'c': [1, 2, 3, 4, 5], 'b': [1.0], 'd': ['hello', 8, 0.1]}
- \endcode
-
- """
- text = open(filename, "r").readlines()
- kvdict = KeyValue()
-
- for line in text:
- if line.find(sep) >= 0:
- key, value = line.split(sep)
- key = key.strip()
- value = value.strip()
- else:
- # Jump over empty values
- continue
- values = value.split(val_sep)
- value_list = []
-
- for value in values:
- not_float = False
- not_int = False
-
- # Convert values into correct types
- # We first try integer then float
- try:
- value_converted = int(value)
- except:
- not_int = True
- if not_int:
- try:
- value_converted = float(value)
- except:
- not_float = True
-
- if not_int and not_float:
- value_converted = value.strip()
-
- value_list.append(value_converted)
-
- kvdict[key] = value_list
- return kvdict
-
-def compare_key_value_text_files(filename_a, filename_b, sep=":",
- val_sep=",", precision=0.000001):
- """
- !Compare two key-value text files that may contain projection parameter
-
- @param filename_a The name of the first key-value text file
- @param filenmae_b The name of the second key-value text file
- @param sep The character that separates the keys and values, default is ":"
- @param val_sep The character that separates the values of a single key, default is ","
- @param precision The precision with which the floating point values are compares
- if abs(a - b) > precision : return False
- @return True if full or almost identical, False if different
-
- This method will print a warning in case keys that are present in the first file
- are not present in the second one.
- The comparison method tries to convert the values into there native format (float, int or string)
- to allow correct comparison.
-
- An example key-value text file may have this content:
- \code
- a: Hello
- b: 1.0
- c: 1,2,3,4,5
- d : hello,8,0.1
- \endcode
- """
- dict_a = _text_to_key_value_dict(filename_a, sep)
- dict_b = _text_to_key_value_dict(filename_b, sep)
-
- missing_keys = 0
-
- # We compare matching keys
- for key in dict_a.keys():
- if dict_b.has_key(key):
- # Floating point values must be handled separately
- if isinstance(dict_a[key], float) and isinstance(dict_b[key], float):
- if abs(dict_a[key] - dict_b[key]) > precision:
- return False
- elif isinstance(dict_a[key], float) or isinstance(dict_b[key], float):
- return False
- else:
- if dict_a[key] != dict_b[key]:
- return False
- else:
- missing_keys += 1
- if missing_keys == len(dict_a):
- return False
- if missing_keys > 0:
- warning(_("Several keys (%i out of %i) are missing "
- "in the target file")%(missing_keys, len(dict_a)))
- return True
-
-# interface to g.gisenv
-
-def gisenv():
- """!Returns the output from running g.gisenv (with no arguments), as a
- dictionary. Example:
-
- \code
- >>> env = grass.gisenv()
- >>> print env['GISDBASE']
- /opt/grass-data
- \endcode
-
- @return list of GRASS variables
- """
- s = read_command("g.gisenv", flags='n')
- return parse_key_val(s)
-
-# interface to g.region
-
-def locn_is_latlong():
- """!Tests if location is lat/long. Value is obtained
- by checking the "g.region -p" projection code.
-
- @return True for a lat/long region, False otherwise
- """
- s = read_command("g.region", flags='p')
- kv = parse_key_val(s, ':')
- if kv['projection'].split(' ')[1] == '3':
- return True
- else:
- return False
-
-def region(region3d = False, complete = False):
- """!Returns the output from running "g.region -g", as a
- dictionary. Example:
-
- \param region3d True to get 3D region
-
- \code
- >>> region = grass.region()
- >>> [region[key] for key in "nsew"]
- [228500.0, 215000.0, 645000.0, 630000.0]
- >>> (region['nsres'], region['ewres'])
- (10.0, 10.0)
- \endcode
-
- @return dictionary of region values
- """
- flgs = 'g'
- if region3d:
- flgs += '3'
- if complete:
- flgs += 'cep'
-
- s = read_command("g.region", flags = flgs)
- reg = parse_key_val(s, val_type = float)
- for k in ['rows', 'cols', 'cells',
- 'rows3', 'cols3', 'cells3', 'depths']:
- if k not in reg:
- continue
- reg[k] = int(reg[k])
-
- return reg
-
-def region_env(region3d = False,
- **kwargs):
- """!Returns region settings as a string which can used as
- GRASS_REGION environmental variable.
-
- If no 'kwargs' are given then the current region is used. Note
- that this function doesn't modify the current region!
-
- See also use_temp_region() for alternative method how to define
- temporary region used for raster-based computation.
-
- \param region3d True to get 3D region
- \param kwargs g.region's parameters like 'rast', 'vect' or 'region'
- \code
- os.environ['GRASS_REGION'] = grass.region_env(region = 'detail')
- grass.mapcalc('map = 1', overwrite = True)
- os.environ.pop('GRASS_REGION')
- \endcode
-
- @return string with region values
- @return empty string on error
- """
- # read proj/zone from WIND file
- env = gisenv()
- windfile = os.path.join (env['GISDBASE'], env['LOCATION_NAME'],
- env['MAPSET'], "WIND")
- fd = open(windfile, "r")
- grass_region = ''
- for line in fd.readlines():
- key, value = map(lambda x: x.strip(), line.split(":", 1))
- if kwargs and key not in ('proj', 'zone'):
- continue
- if not kwargs and not region3d and \
- key in ('top', 'bottom', 'cols3', 'rows3',
- 'depths', 'e-w resol3', 'n-s resol3', 't-b resol'):
- continue
-
- grass_region += '%s: %s;' % (key, value)
-
- if not kwargs: # return current region
- return grass_region
-
- # read other values from `g.region -g`
- flgs = 'ug'
- if region3d:
- flgs += '3'
-
- s = read_command('g.region', flags = flgs, **kwargs)
- if not s:
- return ''
- reg = parse_key_val(s)
-
- kwdata = [('north', 'n'),
- ('south', 's'),
- ('east', 'e'),
- ('west', 'w'),
- ('cols', 'cols'),
- ('rows', 'rows'),
- ('e-w resol', 'ewres'),
- ('n-s resol', 'nsres')]
- if region3d:
- kwdata += [('top', 't'),
- ('bottom', 'b'),
- ('cols3', 'cols3'),
- ('rows3', 'rows3'),
- ('depths', 'depths'),
- ('e-w resol3', 'ewres3'),
- ('n-s resol3', 'nsres3'),
- ('t-b resol', 'tbres')]
-
- for wkey, rkey in kwdata:
- grass_region += '%s: %s;' % (wkey, reg[rkey])
-
- return grass_region
-
-def use_temp_region():
- """!Copies the current region to a temporary region with "g.region save=",
- then sets WIND_OVERRIDE to refer to that region. Installs an atexit
- handler to delete the temporary region upon termination.
- """
- name = "tmp.%s.%d" % (os.path.basename(sys.argv[0]), os.getpid())
- run_command("g.region", save = name, overwrite = True)
- os.environ['WIND_OVERRIDE'] = name
- atexit.register(del_temp_region)
-
-def del_temp_region():
- """!Unsets WIND_OVERRIDE and removes any region named by it."""
- try:
- name = os.environ.pop('WIND_OVERRIDE')
- run_command("g.remove", quiet = True, region = name)
- except:
- pass
-
-# interface to g.findfile
-
-def find_file(name, element = 'cell', mapset = None):
- """!Returns the output from running g.findfile as a
- dictionary. Example:
-
- \code
- >>> result = grass.find_file('fields', element = 'vector')
- >>> print result['fullname']
- fields at PERMANENT
- >>> print result['file']
- /opt/grass-data/spearfish60/PERMANENT/vector/fields
- \endcode
-
- @param name file name
- @param element element type (default 'cell')
- @param mapset mapset name (default all mapsets in search path)
-
- @return parsed output of g.findfile
- """
- if element == 'raster' or element == 'rast':
- verbose(_('Element type should be "cell" and not "%s"') % element)
- element = 'cell'
- s = read_command("g.findfile", flags='n', element = element, file = name, mapset = mapset)
- return parse_key_val(s)
-
-# interface to g.list
-
-def list_grouped(type, check_search_path = True):
- """!List elements grouped by mapsets.
-
- Returns the output from running g.list, as a dictionary where the
- keys are mapset names and the values are lists of maps in that
- mapset. Example:
-
- @code
- >>> grass.list_grouped('rast')['PERMANENT']
- ['aspect', 'erosion1', 'quads', 'soils', 'strm.dist', ...
- @endcode
-
- @param type element type (rast, vect, rast3d, region, ...)
- @param check_search_path True to add mapsets for the search path with no found elements
-
- @return directory of mapsets/elements
- """
- if type == 'raster' or type == 'cell':
- verbose(_('Element type should be "rast" and not "%s"') % element)
- type = 'rast'
- dashes_re = re.compile("^----+$")
- mapset_re = re.compile("<(.*)>")
- result = {}
- if check_search_path:
- for mapset in mapsets(search_path = True):
- result[mapset] = []
-
- mapset = None
- for line in read_command("g.list", type = type).splitlines():
- if line == "":
- continue
- if dashes_re.match(line):
- continue
- m = mapset_re.search(line)
- if m:
- mapset = m.group(1)
- if mapset not in result.keys():
- result[mapset] = []
- continue
- if mapset:
- result[mapset].extend(line.split())
-
- return result
-
-def _concat(xs):
- result = []
- for x in xs:
- result.extend(x)
- return result
-
-def list_pairs(type):
- """!List of elements as tuples.
-
- Returns the output from running g.list, as a list of (map, mapset)
- pairs. Example:
-
- @code
- >>> grass.list_pairs('rast')
- [('aspect', 'PERMANENT'), ('erosion1', 'PERMANENT'), ('quads', 'PERMANENT'), ...
- @endcode
-
- @param type element type (rast, vect, rast3d, region, ...)
-
- @return list of tuples (map, mapset)
- """
- return _concat([[(map, mapset) for map in maps]
- for mapset, maps in list_grouped(type).iteritems()])
-
-def list_strings(type):
- """!List of elements as strings.
-
- Returns the output from running g.list, as a list of qualified
- names. Example:
-
- @code
- >>> grass.list_strings('rast')
- ['aspect at PERMANENT', 'erosion1 at PERMANENT', 'quads at PERMANENT', 'soils at PERMANENT', ...
- @endcode
-
- @param type element type
-
- @return list of strings ('map@@mapset')
- """
- return ["%s@%s" % pair for pair in list_pairs(type)]
-
-# interface to g.mlist
-
-def mlist_strings(type, pattern = None, mapset = None, flag = ''):
- """!List of elements as strings.
-
- Returns the output from running g.mlist, as a list of qualified
- names.
-
- @param type element type (rast, vect, rast3d, region, ...)
- @param pattern pattern string
- @param mapset mapset name (if not given use search path)
- @param flag pattern type: 'r' (basic regexp), 'e' (extended regexp), or '' (glob pattern)
-
- @return list of elements
- """
- if type == 'raster' or type == 'cell':
- verbose(_('Element type should be "rast" and not "%s"') % element)
- type = 'rast'
- result = list()
- for line in read_command("g.mlist",
- quiet = True,
- flags = 'm' + flag,
- type = type,
- pattern = pattern,
- mapset = mapset).splitlines():
- result.append(line.strip())
-
- return result
-
-def mlist_pairs(type, pattern = None, mapset = None, flag = ''):
- """!List of elements as pairs
-
- Returns the output from running g.mlist, as a list of
- (name, mapset) pairs
-
- @param type element type (rast, vect, rast3d, region, ...)
- @param pattern pattern string
- @param mapset mapset name (if not given use search path)
- @param flag pattern type: 'r' (basic regexp), 'e' (extended regexp), or '' (glob pattern)
-
- @return list of elements
- """
- return [tuple(map.split('@', 1)) for map in mlist_strings(type, pattern, mapset, flag)]
-
-def mlist_grouped(type, pattern = None, check_search_path = True, flag = ''):
- """!List of elements grouped by mapsets.
-
- Returns the output from running g.mlist, as a dictionary where the
- keys are mapset names and the values are lists of maps in that
- mapset. Example:
-
- @code
- >>> grass.mlist_grouped('rast', pattern='r*')['PERMANENT']
- ['railroads', 'roads', 'rstrct.areas', 'rushmore']
- @endcode
-
- @param type element type (rast, vect, rast3d, region, ...)
- @param pattern pattern string
- @param check_search_path True to add mapsets for the search path with no found elements
- @param flag pattern type: 'r' (basic regexp), 'e' (extended regexp), or '' (glob pattern)
-
- @return directory of mapsets/elements
- """
- if type == 'raster' or type == 'cell':
- verbose(_('Element type should be "rast" and not "%s"') % element)
- type = 'rast'
- result = {}
- if check_search_path:
- for mapset in mapsets(search_path = True):
- result[mapset] = []
-
- mapset = None
- for line in read_command("g.mlist", quiet = True, flags = "m" + flag,
- type = type, pattern = pattern).splitlines():
- try:
- name, mapset = line.split('@')
- except ValueError:
- warning(_("Invalid element '%s'") % line)
- continue
-
- if mapset in result:
- result[mapset].append(name)
- else:
- result[mapset] = [name, ]
-
- return result
-
-# color parsing
-
-named_colors = {
- "white": (1.00, 1.00, 1.00),
- "black": (0.00, 0.00, 0.00),
- "red": (1.00, 0.00, 0.00),
- "green": (0.00, 1.00, 0.00),
- "blue": (0.00, 0.00, 1.00),
- "yellow": (1.00, 1.00, 0.00),
- "magenta": (1.00, 0.00, 1.00),
- "cyan": (0.00, 1.00, 1.00),
- "aqua": (0.00, 0.75, 0.75),
- "grey": (0.75, 0.75, 0.75),
- "gray": (0.75, 0.75, 0.75),
- "orange": (1.00, 0.50, 0.00),
- "brown": (0.75, 0.50, 0.25),
- "purple": (0.50, 0.00, 1.00),
- "violet": (0.50, 0.00, 1.00),
- "indigo": (0.00, 0.50, 1.00)}
-
-def parse_color(val, dflt = None):
- """!Parses the string "val" as a GRASS colour, which can be either one of
- the named colours or an R:G:B tuple e.g. 255:255:255. Returns an
- (r,g,b) triple whose components are floating point values between 0
- and 1. Example:
-
- \code
- >>> grass.parse_color("red")
- (1.0, 0.0, 0.0)
- >>> grass.parse_color("255:0:0")
- (1.0, 0.0, 0.0)
- \endcode
-
- @param val color value
- @param dflt default color value
-
- @return tuple RGB
- """
- if val in named_colors:
- return named_colors[val]
-
- vals = val.split(':')
- if len(vals) == 3:
- return tuple(float(v) / 255 for v in vals)
-
- return dflt
-
-# check GRASS_OVERWRITE
-
-def overwrite():
- """!Return True if existing files may be overwritten"""
- owstr = 'GRASS_OVERWRITE'
- return owstr in os.environ and os.environ[owstr] != '0'
-
-# check GRASS_VERBOSE
-
-def verbosity():
- """!Return the verbosity level selected by GRASS_VERBOSE"""
- vbstr = os.getenv('GRASS_VERBOSE')
- if vbstr:
- return int(vbstr)
- else:
- return 2
-
-## various utilities, not specific to GRASS
-
-# basename inc. extension stripping
-
-def basename(path, ext = None):
- """!Remove leading directory components and an optional extension
- from the specified path
-
- @param path path
- @param ext extension
- """
- name = os.path.basename(path)
- if not ext:
- return name
- fs = name.rsplit('.', 1)
- if len(fs) > 1 and fs[1].lower() == ext:
- name = fs[0]
- return name
-
-# find a program (replacement for "which")
-
-def find_program(pgm, args = []):
- """!Attempt to run a program, with optional arguments.
-
- @param pgm program name
- @param args list of arguments
-
- @return False if the attempt failed due to a missing executable
- @return True otherwise
- """
- nuldev = file(os.devnull, 'w+')
- try:
- ret = call([pgm] + args, stdin = nuldev, stdout = nuldev, stderr = nuldev)
- if ret == 0:
- found = True
- else:
- found = False
- except:
- found = False
- nuldev.close()
-
- return found
-
-# try to remove a file, without complaints
-
-def try_remove(path):
- """!Attempt to remove a file; no exception is generated if the
- attempt fails.
-
- @param path path to file to remove
- """
- try:
- os.remove(path)
- except:
- pass
-
-# try to remove a directory, without complaints
-
-def try_rmdir(path):
- """!Attempt to remove a directory; no exception is generated if the
- attempt fails.
-
- @param path path to directory to remove
- """
- try:
- os.rmdir(path)
- except:
- shutil.rmtree(path, ignore_errors = True)
-
-def float_or_dms(s):
- """!Convert DMS to float.
-
- @param s DMS value
-
- @return float value
- """
- return sum(float(x) / 60 ** n for (n, x) in enumerate(s.split(':')))
-
-# interface to g.mapsets
-
-def mapsets(search_path = False):
- """!List available mapsets
-
- @param search_path True to list mapsets only in search path
-
- @return list of mapsets
- """
- if search_path:
- flags = 'p'
- else:
- flags = 'l'
- mapsets = read_command('g.mapsets',
- flags = flags,
- sep = 'newline',
- quiet = True)
- if not mapsets:
- fatal(_("Unable to list mapsets"))
-
- return mapsets.splitlines()
-
-# interface to `g.proj -c`
-
-def create_location(dbase, location,
- epsg = None, proj4 = None, filename = None, wkt = None,
- datum = None, datum_trans = None, desc = None):
- """!Create new location
-
- Raise ScriptError on error.
-
- @param dbase path to GRASS database
- @param location location name to create
- @param epsg if given create new location based on EPSG code
- @param proj4 if given create new location based on Proj4 definition
- @param filename if given create new location based on georeferenced file
- @param wkt if given create new location based on WKT definition (path to PRJ file)
- @param datum GRASS format datum code
- @param datum_trans datum transformation parameters (used for epsg and proj4)
- @param desc description of the location (creates MYNAME file)
- """
- gisdbase = None
- if epsg or proj4 or filename or wkt:
- gisdbase = gisenv()['GISDBASE']
- run_command('g.gisenv',
- set = 'GISDBASE=%s' % dbase)
- if not os.path.exists(dbase):
- os.mkdir(dbase)
-
- kwargs = dict()
- if datum:
- kwargs['datum'] = datum
- if datum_trans:
- kwargs['datum_trans'] = datum_trans
-
- if epsg:
- ps = pipe_command('g.proj',
- quiet = True,
- epsg = epsg,
- location = location,
- stderr = PIPE,
- **kwargs)
- elif proj4:
- ps = pipe_command('g.proj',
- quiet = True,
- proj4 = proj4,
- location = location,
- stderr = PIPE,
- **kwargs)
- elif filename:
- ps = pipe_command('g.proj',
- quiet = True,
- georef = filename,
- location = location,
- stderr = PIPE)
- elif wkt:
- ps = pipe_command('g.proj',
- quiet = True,
- wkt = wkt,
- location = location,
- stderr = PIPE)
- else:
- _create_location_xy(dbase, location)
-
- if epsg or proj4 or filename or wkt:
- error = ps.communicate()[1]
- run_command('g.gisenv',
- set = 'GISDBASE=%s' % gisdbase)
-
- if ps.returncode != 0 and error:
- raise ScriptError(repr(error))
-
- try:
- fd = codecs.open(os.path.join(dbase, location,
- 'PERMANENT', 'MYNAME'),
- encoding = 'utf-8', mode = 'w')
- if desc:
- fd.write(desc + os.linesep)
- else:
- fd.write(os.linesep)
- fd.close()
- except OSError, e:
- raise ScriptError(repr(e))
-
-def _create_location_xy(database, location):
- """!Create unprojected location
-
- Raise ScriptError on error.
-
- @param database GRASS database where to create new location
- @param location location name
- """
- cur_dir = os.getcwd()
- try:
- os.chdir(database)
- os.mkdir(location)
- os.mkdir(os.path.join(location, 'PERMANENT'))
-
- # create DEFAULT_WIND and WIND files
- regioninfo = ['proj: 0',
- 'zone: 0',
- 'north: 1',
- 'south: 0',
- 'east: 1',
- 'west: 0',
- 'cols: 1',
- 'rows: 1',
- 'e-w resol: 1',
- 'n-s resol: 1',
- 'top: 1',
- 'bottom: 0',
- 'cols3: 1',
- 'rows3: 1',
- 'depths: 1',
- 'e-w resol3: 1',
- 'n-s resol3: 1',
- 't-b resol: 1']
-
- defwind = open(os.path.join(location,
- "PERMANENT", "DEFAULT_WIND"), 'w')
- for param in regioninfo:
- defwind.write(param + '%s' % os.linesep)
- defwind.close()
-
- shutil.copy(os.path.join(location, "PERMANENT", "DEFAULT_WIND"),
- os.path.join(location, "PERMANENT", "WIND"))
-
- os.chdir(cur_dir)
- except OSError, e:
- raise ScriptError(repr(e))
-
-# interface to g.version
-
-def version():
- """!Get GRASS version as dictionary
-
- @code
- print version()
-
- {'proj4': '4.8.0', 'geos': '3.3.5', 'libgis_revision': '52468',
- 'libgis_date': '2012-07-27 22:53:30 +0200 (Fri, 27 Jul 2012)',
- 'version': '7.0.svn', 'date': '2012', 'gdal': '2.0dev', 'revision': '53670'}
- @endcode
- """
- data = parse_command('g.version',
- flags = 'rge')
- for k, v in data.iteritems():
- data[k.strip()] = v.replace('"', '').strip()
-
- return data
-
-# get debug_level
-_debug_level = None
-
-def debug_level():
- global _debug_level
- if _debug_level is not None:
- return _debug_level
- _debug_level = 0
- if find_program('g.gisenv', ['--help']):
- _debug_level = int(gisenv().get('DEBUG', 0))
Deleted: grass/trunk/lib/python/db.py
===================================================================
--- grass/trunk/lib/python/db.py 2013-01-08 08:35:23 UTC (rev 54568)
+++ grass/trunk/lib/python/db.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -1,155 +0,0 @@
-"""!@package grass.script.db
-
- at brief GRASS Python scripting module (database functions)
-
-Database related functions to be used in Python scripts.
-
-Usage:
-
- at code
-from grass.script import db as grass
-
-grass.db_describe(table)
-...
- at endcode
-
-(C) 2008-2009, 2012 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Glynn Clements
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import tempfile as pytempfile # conflict with core.tempfile
-
-from core import *
-
-def db_describe(table, **args):
- """!Return the list of columns for a database table
- (interface to `db.describe -c'). Example:
-
- \code
- >>> grass.db_describe('lakes')
- {'nrows': 15279, 'cols': [['cat', 'INTEGER', '11'], ['AREA', 'DOUBLE PRECISION', '20'],
- ['PERIMETER', 'DOUBLE PRECISION', '20'], ['FULL_HYDRO', 'DOUBLE PRECISION', '20'],
- ['FULL_HYDR2', 'DOUBLE PRECISION', '20'], ['FTYPE', 'CHARACTER', '24'],
- ['FCODE', 'INTEGER', '11'], ['NAME', 'CHARACTER', '99']], 'ncols': 8}
- \endcode
-
- @param table table name
- @param args
-
- @return parsed module output
- """
- s = read_command('db.describe', flags = 'c', table = table, **args)
- if not s:
- fatal(_("Unable to describe table <%s>") % table)
-
- cols = []
- result = {}
- for l in s.splitlines():
- f = l.split(':')
- key = f[0]
- f[1] = f[1].lstrip(' ')
- if key.startswith('Column '):
- n = int(key.split(' ')[1])
- cols.insert(n, f[1:])
- elif key in ['ncols', 'nrows']:
- result[key] = int(f[1])
- else:
- result[key] = f[1:]
- result['cols'] = cols
-
- return result
-
-# run "db.connect -g" and parse output
-
-def db_table_exist(table, **args):
- """!Return True if database table exists, False otherwise
-
- @param table table name
- @param args
-
- @return True for success, False otherwise
- """
- result = run_command('db.describe', flags = 'c', table = table, **args)
- if result == 0:
- return True
- else:
- return False
-
-def db_connection():
- """!Return the current database connection parameters
- (interface to `db.connect -g'). Example:
-
- \code
- >>> grass.db_connection()
- {'group': 'x', 'schema': '', 'driver': 'dbf', 'database': '$GISDBASE/$LOCATION_NAME/$MAPSET/dbf/'}
- \endcode
-
- @return parsed output of db.connect
- """
- return parse_command('db.connect', flags = 'g')
-
-def db_select(sql = None, filename = None, table = None, **args):
- """!Perform SQL select statement
-
- Note: one of <em>sql</em>, <em>filename</em>, or <em>table</em>
- arguments must be provided.
-
- Examples:
-
- \code
- grass.db_select(sql = 'SELECT cat,CAMPUS FROM busstopsall WHERE cat < 4')
-
- (('1', 'Vet School'), ('2', 'West'), ('3', 'North'))
- \endcode
-
- \code
- grass.db_select(filename = '/path/to/sql/file')
- \endcode
-
- Simplyfied usage
-
- \code
- grass.db_select(table = 'busstopsall')
- \endcode
-
- performs <tt>SELECT * FROM busstopsall</tt>.
-
- @param sql SQL statement to perform (or None)
- @param filename name of file with SQL statements (or None)
- @param table name of table to query (or None)
- @param args see \gmod{db.select} arguments
- """
- fname = tempfile(create = False)
- if sql:
- args['sql'] = sql
- elif filename:
- args['input'] = filename
- elif table:
- args['table'] = table
- else:
- fatal(_("Programmer error: '%(sql)s', '%(filename)s', or '%(table)s' must be provided") %
- {'sql': 'sql', 'filename': 'filename', 'table': 'table'} )
-
- if 'sep' not in args:
- args['sep'] = '|'
-
- ret = run_command('db.select', quiet = True,
- flags = 'c',
- output = fname,
- **args)
-
- if ret != 0:
- fatal(_("Fetching data failed"))
-
- ofile = open(fname)
- result = map(lambda x: tuple(x.rstrip(os.linesep).split(args['sep'])),
- ofile.readlines())
- ofile.close()
- try_remove(fname)
-
- return tuple(result)
Deleted: grass/trunk/lib/python/grass__init__.py
===================================================================
--- grass/trunk/lib/python/grass__init__.py 2013-01-08 08:35:23 UTC (rev 54568)
+++ grass/trunk/lib/python/grass__init__.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -1,4 +0,0 @@
-import os
-__all__ = ["script", "temporal"]
-if os.path.exists(os.path.join(os.path.dirname(__file__), "lib", "__init__.py")):
- __all__.append("lib")
Deleted: grass/trunk/lib/python/raster.py
===================================================================
--- grass/trunk/lib/python/raster.py 2013-01-08 08:35:23 UTC (rev 54568)
+++ grass/trunk/lib/python/raster.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -1,137 +0,0 @@
-"""!@package grass.script.raster
-
- at brief GRASS Python scripting module (raster functions)
-
-Raster related functions to be used in Python scripts.
-
-Usage:
-
- at code
-from grass.script import raster as grass
-
-grass.raster_history(map)
-...
- at endcode
-
-(C) 2008-2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Glynn Clements
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import string
-
-from core import *
-
-# add raster history
-
-def raster_history(map):
- """!Set the command history for a raster map to the command used to
- invoke the script (interface to `r.support').
-
- @param map map name
-
- @return True on success
- @return False on failure
- """
- current_mapset = gisenv()['MAPSET']
- if find_file(name = map)['mapset'] == current_mapset:
- run_command('r.support', map = map, history = os.environ['CMDLINE'])
- return True
-
- warning(_("Unable to write history for <%(map)s>. "
- "Raster map <%(map)s> not found in current mapset." % { 'map' : map, 'map' : map}))
- return False
-
-# run "r.info -gre ..." and parse output
-
-def raster_info(map):
- """!Return information about a raster map (interface to
- `r.info'). Example:
-
- \code
- >>> grass.raster_info('elevation')
- {'north': 228500.0, 'timestamp': '"none"', 'min': 55.578792572021499,
- 'datatype': 'FCELL', 'max': 156.32986450195301, 'ewres': 10.0,
- 'vertical_datum': '', 'west': 630000.0, 'units': '',
- 'title': 'South-West Wake county: Elevation NED 10m (elev_ned10m)',
- 'east': 645000.0, 'nsres': 10.0, 'south': 215000.0}
- \endcode
-
- @param map map name
-
- @return parsed raster info
- """
-
- def float_or_null(s):
- if s == 'NULL':
- return None
- else:
- return float(s)
-
- s = read_command('r.info', flags = 'gre', map = map)
- kv = parse_key_val(s)
- for k in ['min', 'max']:
- kv[k] = float_or_null(kv[k])
- for k in ['north', 'south', 'east', 'west']:
- kv[k] = float(kv[k])
- for k in ['nsres', 'ewres']:
- kv[k] = float_or_dms(kv[k])
- return kv
-
-# interface to r.mapcalc
-
-def mapcalc(exp, quiet = False, verbose = False, overwrite = False, **kwargs):
- """!Interface to r.mapcalc.
-
- @param exp expression
- @param quiet True to run quietly (<tt>--q</tt>)
- @param verbose True to run verbosely (<tt>--v</tt>)
- @param overwrite True to enable overwriting the output (<tt>--o</tt>)
- @param kwargs
- """
- t = string.Template(exp)
- e = t.substitute(**kwargs)
-
- if run_command('r.mapcalc', expression = e,
- quiet = quiet,
- verbose = verbose,
- overwrite = overwrite) != 0:
- fatal(_("An error occurred while running r.mapcalc"))
-
-
-def mapcalc_start(exp, quiet = False, verbose = False, overwrite = False, **kwargs):
- """!Interface to r.mapcalc, doesn't wait for it to finish, returns Popen object.
-
- \code
- >>> expr1 = '"%s" = "%s" * 10' % (output, input)
- >>> expr2 = '...' # etc.
- >>> # launch the jobs:
- >>> p1 = grass.mapcalc_start(expr1)
- >>> p2 = grass.mapcalc_start(expr2) # etc.
- ...
- >>> # wait for them to finish:
- >>> p1.wait()
- >>> p2.wait() # etc.
- \endcode
-
- @param exp expression
- @param quiet True to run quietly (<tt>--q</tt>)
- @param verbose True to run verbosely (<tt>--v</tt>)
- @param overwrite True to enable overwriting the output (<tt>--o</tt>)
- @param kwargs
-
- @return Popen object
- """
- t = string.Template(exp)
- e = t.substitute(**kwargs)
-
- return start_command('r.mapcalc', expression = e,
- quiet = quiet,
- verbose = verbose,
- overwrite = overwrite)
-
Deleted: grass/trunk/lib/python/raster3d.py
===================================================================
--- grass/trunk/lib/python/raster3d.py 2013-01-08 08:35:23 UTC (rev 54568)
+++ grass/trunk/lib/python/raster3d.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -1,89 +0,0 @@
-"""!@package grass.script.raster3d
-
- at brief GRASS Python scripting module (raster3d functions)
-
-Raster3d related functions to be used in Python scripts.
-
-Usage:
-
- at code
-from grass.script import raster3d as grass
-
-grass.raster3d_info(map)
-...
- at endcode
-
-(C) 2008-2009 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Glynn Clements
- at author Martin Landa <landa.martin gmail.com>
- at author Soeren Gebbert <soeren.gebbert gmail.com>
-"""
-
-import os
-import string
-
-from core import *
-
-# add raster history
-
-# run "r3.info -rstgip ..." and parse output
-
-def raster3d_info(map):
- """!Return information about a raster3d map (interface to
- `r3.info'). Example:
-
- \code
- >>> grass.raster3d_info('volume')
- {'tiledimz': 1, 'tbres': 1.0, 'tiledimx': 27, 'tiledimy': 16, 'north': 60.490001999999997, 'tilenumy': 1, 'tilenumz': 1,
- 'min': 1.0, 'datatype': '"DCELL"', 'max': 1.0, 'top': 0.5, 'bottom': -0.5, 'west': -3.2200000000000002, 'tilenumx': 1,
- 'ewres': 0.98222219, 'east': 23.299999, 'nsres': 0.99937511999999995, 'Timestamp': '"none"', 'south': 44.5}
- \endcode
-
- @param map map name
-
- @return parsed raster3d info
- """
-
- def float_or_null(s):
- if s == 'NULL':
- return None
- else:
- return float(s)
-
- s = read_command('r3.info', flags='rg', map=map)
- kv = parse_key_val(s)
- for k in ['min', 'max']:
- kv[k] = float_or_null(kv[k])
- for k in ['north', 'south', 'east', 'west', 'top', 'bottom']:
- kv[k] = float(kv[k])
- for k in ['nsres', 'ewres', 'tbres']:
- kv[k] = float_or_dms(kv[k])
- for k in ['tilenumx', 'tilenumy', 'tilenumz']:
- kv[k] = int(kv[k])
- for k in ['tiledimx', 'tiledimy', 'tiledimz']:
- kv[k] = int(kv[k])
- return kv
-
-# interface to r3.mapcalc
-
-def mapcalc3d(exp, quiet = False, verbose = False, overwrite = False, **kwargs):
- """!Interface to r3.mapcalc.
-
- @param exp expression
- @param quiet True to run quietly (<tt>--q</tt>)
- @param verbose True to run verbosely (<tt>--v</tt>)
- @param overwrite True to enable overwriting the output (<tt>--o</tt>)
- @param kwargs
- """
- t = string.Template(exp)
- e = t.substitute(**kwargs)
-
- if run_command('r3.mapcalc', expression = e,
- quiet = quiet,
- verbose = verbose,
- overwrite = overwrite) != 0:
- fatal(_("An error occurred while running r3.mapcalc"))
Property changes on: grass/trunk/lib/python/script
___________________________________________________________________
Added: svn:ignore
+ setup.py
Copied: grass/trunk/lib/python/script/Makefile (from rev 54568, grass/trunk/lib/python/Makefile)
===================================================================
--- grass/trunk/lib/python/script/Makefile (rev 0)
+++ grass/trunk/lib/python/script/Makefile 2013-01-08 09:34:42 UTC (rev 54569)
@@ -0,0 +1,30 @@
+MODULE_TOPDIR = ../../..
+
+include $(MODULE_TOPDIR)/include/Make/Other.make
+include $(MODULE_TOPDIR)/include/Make/Python.make
+include $(MODULE_TOPDIR)/include/Make/Doxygen.make
+
+DSTDIR = $(ETC)/python/grass/script
+
+MODULES = core db raster raster3d vector array setup task
+
+PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
+PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)
+
+EXTRA_CLEAN_FILES = setup.py
+
+default: $(PYFILES) $(PYCFILES)
+
+$(DSTDIR):
+ $(MKDIR) $@
+
+$(DSTDIR)/%: % | $(DSTDIR)
+ $(INSTALL_DATA) $< $@
+
+$(DSTDIR)/setup.py: setup.py | $(DSTDIR)
+ $(INSTALL_DATA) $< $@
+
+setup.py: setup.py.sed
+ sed \
+ -e 's#@LD_LIBRARY_PATH_VAR@#$(LD_LIBRARY_PATH_VAR)#' \
+ $< > $@
Copied: grass/trunk/lib/python/script/__init__.py (from rev 54568, grass/trunk/lib/python/__init__.py)
===================================================================
--- grass/trunk/lib/python/script/__init__.py (rev 0)
+++ grass/trunk/lib/python/script/__init__.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -0,0 +1,5 @@
+from core import *
+from db import *
+from raster import *
+from raster3d import *
+from vector import *
Copied: grass/trunk/lib/python/script/array.py (from rev 54568, grass/trunk/lib/python/array.py)
===================================================================
--- grass/trunk/lib/python/script/array.py (rev 0)
+++ grass/trunk/lib/python/script/array.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -0,0 +1,356 @@
+"""!@package grass.script.array
+
+ at brief GRASS Python scripting module (2D and 3D raster with numpy)
+
+Functions to use GRASS 2D and 3D rasters with NumPy.
+
+Usage:
+
+ at code
+
+>>> import grass.script as grass
+>>> from grass.script import array as garray
+>>>
+>>> # We create a temporary region that is only valid in this python session
+... grass.use_temp_region()
+>>> grass.run_command("g.region", n=80, e=120, t=60, s=0, w=0, b=0, res=20, res3=20)
+0
+>>>
+>>> # Lets create a raster map numpy array
+... # based at the current region settings
+... map2d_1 = garray.array()
+>>>
+>>> # Write some data
+... for y in range(map2d_1.shape[0]):
+... for x in range(map2d_1.shape[1]):
+... map2d_1[y][x] = y + x
+...
+>>> # Lets have a look at the array
+... print map2d_1
+[[ 0. 1. 2. 3. 4. 5.]
+ [ 1. 2. 3. 4. 5. 6.]
+ [ 2. 3. 4. 5. 6. 7.]
+ [ 3. 4. 5. 6. 7. 8.]]
+>>> # This will write the numpy array as GRASS raster map
+... # with name map2d_1
+... map2d_1.write(mapname="map2d_1", overwrite=True)
+ 100%
+0
+>>>
+>>> # We create a new array and read map2d_1 to modify it
+... map2d_2 = garray.array()
+>>> # Don't do map2d_2 = map2d_1 % 3
+... # because: this will overwrite the internal temporary filename
+... map2d_2.read("map2d_1")
+0
+>>> map2d_2 %= 3
+>>> # Show the result
+... print map2d_2
+[[ 0. 1. 2. 0. 1. 2.]
+ [ 1. 2. 0. 1. 2. 0.]
+ [ 2. 0. 1. 2. 0. 1.]
+ [ 0. 1. 2. 0. 1. 2.]]
+>>> # Write the result as new raster map with name map2d_2
+... map2d_2.write(mapname="map2d_2", overwrite=True)
+ 100%
+0
+>>>
+>>> # Here we create a 3D raster map numpy array
+... # based in the current region settings
+... map3d_1 = garray.array3d()
+>>>
+>>> # Write some data
+... # Note: the 3D array has map[depth][row][column] order
+... for z in range(map3d_1.shape[0]):
+... for y in range(map3d_1.shape[1]):
+... for x in range(map3d_1.shape[2]):
+... map3d_1[z][y][x] = z + y + x
+...
+>>> # Lets have a look at the 3D array
+... print map3d_1
+[[[ 0. 1. 2. 3. 4. 5.]
+ [ 1. 2. 3. 4. 5. 6.]
+ [ 2. 3. 4. 5. 6. 7.]
+ [ 3. 4. 5. 6. 7. 8.]]
+
+ [[ 1. 2. 3. 4. 5. 6.]
+ [ 2. 3. 4. 5. 6. 7.]
+ [ 3. 4. 5. 6. 7. 8.]
+ [ 4. 5. 6. 7. 8. 9.]]
+
+ [[ 2. 3. 4. 5. 6. 7.]
+ [ 3. 4. 5. 6. 7. 8.]
+ [ 4. 5. 6. 7. 8. 9.]
+ [ 5. 6. 7. 8. 9. 10.]]]
+>>> # This will write the numpy array as GRASS 3D raster map
+... # with name map3d_1
+... map3d_1.write(mapname="map3d_1", overwrite=True)
+Loading floating point data with 8 bytes ... (6x4x3)
+ 100%
+0
+>>> # We create a new 3D array and read map3d_1 to modify it
+... map3d_2 = garray.array3d()
+>>> # Don't do map3d_2 = map3d_1 % 3
+... # because: this will overwrite the internal temporary filename
+... map3d_2.read("map3d_1")
+0
+>>> map3d_2 %= 3
+>>> # Show the result
+... print map3d_2
+[[[ 0. 1. 2. 0. 1. 2.]
+ [ 1. 2. 0. 1. 2. 0.]
+ [ 2. 0. 1. 2. 0. 1.]
+ [ 0. 1. 2. 0. 1. 2.]]
+
+ [[ 1. 2. 0. 1. 2. 0.]
+ [ 2. 0. 1. 2. 0. 1.]
+ [ 0. 1. 2. 0. 1. 2.]
+ [ 1. 2. 0. 1. 2. 0.]]
+
+ [[ 2. 0. 1. 2. 0. 1.]
+ [ 0. 1. 2. 0. 1. 2.]
+ [ 1. 2. 0. 1. 2. 0.]
+ [ 2. 0. 1. 2. 0. 1.]]]
+>>> # Write the result as new 3D raster map with name map3d_2
+... map3d_2.write(mapname="map3d_2", overwrite=True)
+Loading floating point data with 8 bytes ... (6x4x3)
+ 100%
+0
+
+ at endcode
+
+(C) 2010-2012 by Glynn Clements and the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Glynn Clements
+"""
+
+import os
+import numpy
+
+import core as grass
+
+###############################################################################
+
+class array(numpy.memmap):
+ def __new__(cls, dtype=numpy.double):
+ """!Define new numpy array
+
+ @param cls
+ @param dtype data type (default: numpy.double)
+ """
+ reg = grass.region()
+ r = reg['rows']
+ c = reg['cols']
+ shape = (r, c)
+
+ filename = grass.tempfile()
+
+ self = numpy.memmap.__new__(
+ cls,
+ filename=filename,
+ dtype=dtype,
+ mode='w+',
+ shape=shape)
+
+ self.filename = filename
+ return self
+
+ def _close(self):
+ numpy.memmap._close(self)
+ if isinstance(self, array):
+ grass.try_remove(self.filename)
+
+ def read(self, mapname, null=None):
+ """!Read raster map into array
+
+ @param mapname name of raster map to be read
+ @param null null value
+
+ @return 0 on success
+ @return non-zero code on failure
+ """
+ kind = self.dtype.kind
+ size = self.dtype.itemsize
+
+ if kind == 'f':
+ flags = 'f'
+ elif kind in 'biu':
+ flags = 'i'
+ else:
+ raise ValueError(_('Invalid kind <%s>') % kind)
+
+ if size not in [1, 2, 4, 8]:
+ raise ValueError(_('Invalid size <%d>') % size)
+
+ return grass.run_command(
+ 'r.out.bin',
+ flags=flags,
+ input=mapname,
+ output=self.filename,
+ bytes=size,
+ null=null,
+ quiet=True,
+ overwrite=True)
+
+ def write(self, mapname, title=None, null=None, overwrite=None):
+ """!Write array into raster map
+
+ @param mapname name for raster map
+ @param title title for raster map
+ @param null null value
+ @param overwrite True for overwritting existing raster maps
+
+ @return 0 on success
+ @return non-zero code on failure
+ """
+ kind = self.dtype.kind
+ size = self.dtype.itemsize
+
+ if kind == 'f':
+ if size == 4:
+ flags = 'f'
+ elif size == 8:
+ flags = 'd'
+ else:
+ raise ValueError(_('Invalid FP size <%d>') % size)
+ size = None
+ elif kind in 'biu':
+ if size not in [1, 2, 4]:
+ raise ValueError(_('Invalid integer size <%d>') % size)
+ flags = None
+ else:
+ raise ValueError(_('Invalid kind <%s>') % kind)
+
+ reg = grass.region()
+
+ return grass.run_command(
+ 'r.in.bin',
+ flags=flags,
+ input=self.filename,
+ output=mapname,
+ title=title,
+ bytes=size,
+ anull=null,
+ overwrite=overwrite,
+ verbose=True,
+ north=reg['n'],
+ south=reg['s'],
+ east=reg['e'],
+ west=reg['w'],
+ rows=reg['rows'],
+ cols=reg['cols'])
+
+###############################################################################
+
+class array3d(numpy.memmap):
+ def __new__(cls, dtype=numpy.double):
+ """!Define new 3d numpy array
+
+ @param cls
+ @param dtype data type (default: numpy.double)
+ """
+ reg = grass.region(True)
+ r = reg['rows3']
+ c = reg['cols3']
+ d = reg['depths']
+ shape = (d, r, c)
+
+ filename = grass.tempfile()
+
+ self = numpy.memmap.__new__(
+ cls,
+ filename=filename,
+ dtype=dtype,
+ mode='w+',
+ shape=shape)
+
+ self.filename = filename
+
+ return self
+
+ def _close(self):
+
+ numpy.memmap._close(self)
+ if isinstance(self, array):
+ grass.try_remove(self.filename)
+
+ def read(self, mapname, null=None):
+ """!Read 3D raster map into array
+
+ @param mapname name of 3D raster map to be read
+ @param null null value
+
+ @return 0 on success
+ @return non-zero code on failure
+ """
+ kind = self.dtype.kind
+ size = self.dtype.itemsize
+
+ if kind == 'f':
+ flags = None # default is double
+ elif kind in 'biu':
+ flags = 'i'
+ else:
+ raise ValueError(_('Invalid kind <%s>') % kind)
+
+ if size not in [1, 2, 4, 8]:
+ raise ValueError(_('Invalid size <%d>') % size)
+
+ return grass.run_command(
+ 'r3.out.bin',
+ flags=flags,
+ input=mapname,
+ output=self.filename,
+ bytes=size,
+ null=null,
+ quiet=True,
+ overwrite=True)
+
+ def write(self, mapname, null=None, overwrite=None):
+ """!Write array into 3D raster map
+
+ @param mapname name for 3D raster map
+ @param null null value
+ @param overwrite True for overwriting existing raster maps
+
+ @return 0 on success
+ @return non-zero code on failure
+ """
+ kind = self.dtype.kind
+ size = self.dtype.itemsize
+ flags = None
+
+ if kind == 'f':
+ if size != 4 and size != 8:
+ raise ValueError(_('Invalid FP size <%d>') % size)
+ elif kind in 'biu':
+ if size not in [1, 2, 4, 8]:
+ raise ValueError(_('Invalid integer size <%d>') % size)
+ flags = 'i'
+ else:
+ raise ValueError(_('Invalid kind <%s>') % kind)
+
+ reg = grass.region(True)
+
+ return grass.run_command(
+ 'r3.in.bin',
+ flags=flags,
+ input=self.filename,
+ output=mapname,
+ bytes=size,
+ null=null,
+ overwrite=overwrite,
+ verbose=True,
+ north=reg['n'],
+ south=reg['s'],
+ top=reg['t'],
+ bottom=reg['b'],
+ east=reg['e'],
+ west=reg['w'],
+ depths=reg['depths'],
+ rows=reg['rows3'],
+ cols=reg['cols3'])
+
Copied: grass/trunk/lib/python/script/core.py (from rev 54568, grass/trunk/lib/python/core.py)
===================================================================
--- grass/trunk/lib/python/script/core.py (rev 0)
+++ grass/trunk/lib/python/script/core.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -0,0 +1,1391 @@
+"""!@package grass.script.core
+
+ at brief GRASS Python scripting module (core functions)
+
+Core functions to be used in Python scripts.
+
+Usage:
+
+ at code
+from grass.script import core as grass
+
+grass.parser()
+...
+ at endcode
+
+(C) 2008-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Glynn Clements
+ at author Martin Landa <landa.martin gmail.com>
+ at author Michael Barton <michael.barton asu.edu>
+"""
+
+import os
+import sys
+import types
+import re
+import atexit
+import subprocess
+import shutil
+import locale
+import codecs
+
+# i18N
+import gettext
+gettext.install('grasslibs', os.path.join(os.getenv("GISBASE"), 'locale'))
+
+# subprocess wrapper that uses shell on Windows
+
+class Popen(subprocess.Popen):
+ def __init__(self, args, bufsize = 0, executable = None,
+ stdin = None, stdout = None, stderr = None,
+ preexec_fn = None, close_fds = False, shell = None,
+ cwd = None, env = None, universal_newlines = False,
+ startupinfo = None, creationflags = 0):
+
+ if shell == None:
+ shell = (sys.platform == "win32")
+
+ subprocess.Popen.__init__(self, args, bufsize, executable,
+ stdin, stdout, stderr,
+ preexec_fn, close_fds, shell,
+ cwd, env, universal_newlines,
+ startupinfo, creationflags)
+
+PIPE = subprocess.PIPE
+STDOUT = subprocess.STDOUT
+
+class ScriptError(Exception):
+ def __init__(self, msg):
+ self.value = msg
+
+ def __str__(self):
+ return self.value
+
+raise_on_error = False # raise exception instead of calling fatal()
+
+def call(*args, **kwargs):
+ return Popen(*args, **kwargs).wait()
+
+# GRASS-oriented interface to subprocess module
+
+_popen_args = ["bufsize", "executable", "stdin", "stdout", "stderr",
+ "preexec_fn", "close_fds", "cwd", "env",
+ "universal_newlines", "startupinfo", "creationflags"]
+
+def decode(string):
+ enc = locale.getdefaultlocale()[1]
+ if enc:
+ return string.decode(enc)
+
+ return string
+
+def _make_val(val):
+ if isinstance(val, types.StringType) or \
+ isinstance(val, types.UnicodeType):
+ return val
+ if isinstance(val, types.ListType):
+ return ",".join(map(_make_val, val))
+ if isinstance(val, types.TupleType):
+ return _make_val(list(val))
+ return str(val)
+
+def get_commands():
+ """!Create list of available GRASS commands to use when parsing
+ string from the command line
+
+ @return list of commands (set) and directory of scripts (collected
+ by extension - MS Windows only)
+
+ @code
+ >>> cmds = list(get_commands()[0])
+ >>> cmds.sort()
+ >>> cmds[:5]
+ ['d.barscale', 'd.colorlist', 'd.colortable', 'd.erase', 'd.font']
+
+ @endcode
+ """
+ gisbase = os.environ['GISBASE']
+ cmd = list()
+ scripts = {'.py': list()} if sys.platform == 'win32' else {}
+
+ def scan(gisbase, directory):
+ dir_path = os.path.join(gisbase, directory)
+ if os.path.exists(dir_path):
+ for fname in os.listdir(os.path.join(gisbase, directory)):
+ if scripts: # win32
+ name, ext = os.path.splitext(fname)
+ if ext != '.manifest':
+ cmd.append(name)
+ if ext in scripts.keys():
+ scripts[ext].append(name)
+ else:
+ cmd.append(fname)
+
+ for directory in ('bin', 'scripts'):
+ scan(gisbase, directory)
+
+ # scan gui/scripts/
+ gui_path = os.path.join(gisbase, 'etc', 'gui', 'scripts')
+ if os.path.exists(gui_path):
+ os.environ["PATH"] = os.getenv("PATH") + os.pathsep + gui_path
+ cmd = cmd + os.listdir(gui_path)
+
+ return set(cmd), scripts
+
+
+def make_command(prog, flags = "", overwrite = False, quiet = False, verbose = False, **options):
+ """!Return a list of strings suitable for use as the args parameter to
+ Popen() or call(). Example:
+
+ @code
+ >>> grass.make_command("g.message", flags = 'w', message = 'this is a warning')
+ ['g.message', '-w', 'message=this is a warning']
+ @endcode
+
+ @param prog GRASS module
+ @param flags flags to be used (given as a string)
+ @param overwrite True to enable overwriting the output (<tt>--o</tt>)
+ @param quiet True to run quietly (<tt>--q</tt>)
+ @param verbose True to run verbosely (<tt>--v</tt>)
+ @param options module's parameters
+
+ @return list of arguments
+ """
+ args = [prog]
+ if overwrite:
+ args.append("--o")
+ if quiet:
+ args.append("--q")
+ if verbose:
+ args.append("--v")
+ if flags:
+ if '-' in flags:
+ raise ScriptError("'-' is not a valid flag")
+ args.append("-%s" % flags)
+ for opt, val in options.iteritems():
+ if val != None:
+ if opt[0] == '_':
+ opt = opt[1:]
+ args.append("%s=%s" % (opt, _make_val(val)))
+ return args
+
+def start_command(prog, flags = "", overwrite = False, quiet = False, verbose = False, **kwargs):
+ """!Returns a Popen object with the command created by make_command.
+ Accepts any of the arguments which Popen() accepts apart from "args"
+ and "shell".
+
+ \code
+ >>> p = grass.start_command("g.gisenv", stdout = subprocess.PIPE)
+ >>> print p
+ <subprocess.Popen object at 0xb7c12f6c>
+ >>> print p.communicate()[0]
+ GISDBASE='/opt/grass-data';
+ LOCATION_NAME='spearfish60';
+ MAPSET='glynn';
+ GRASS_DB_ENCODING='ascii';
+ GUI='text';
+ MONITOR='x0';
+ \endcode
+
+ @param prog GRASS module
+ @param flags flags to be used (given as a string)
+ @param overwrite True to enable overwriting the output (<tt>--o</tt>)
+ @param quiet True to run quietly (<tt>--q</tt>)
+ @param verbose True to run verbosely (<tt>--v</tt>)
+ @param kwargs module's parameters
+
+ @return Popen object
+ """
+ options = {}
+ popts = {}
+ for opt, val in kwargs.iteritems():
+ if opt in _popen_args:
+ popts[opt] = val
+ else:
+ options[opt] = val
+
+ args = make_command(prog, flags, overwrite, quiet, verbose, **options)
+
+ if debug_level() > 0:
+ sys.stderr.write("D1/%d: %s.start_command(): %s\n" % (debug_level(), __name__, ' '.join(args)))
+ sys.stderr.flush()
+
+ return Popen(args, **popts)
+
+def run_command(*args, **kwargs):
+ """!Passes all arguments to start_command(), then waits for the process to
+ complete, returning its exit code. Similar to subprocess.call(), but
+ with the make_command() interface.
+
+ @param args list of unnamed arguments (see start_command() for details)
+ @param kwargs list of named arguments (see start_command() for details)
+
+ @return exit code (0 for success)
+ """
+ ps = start_command(*args, **kwargs)
+ return ps.wait()
+
+def pipe_command(*args, **kwargs):
+ """!Passes all arguments to start_command(), but also adds
+ "stdout = PIPE". Returns the Popen object.
+
+ \code
+ >>> p = grass.pipe_command("g.gisenv")
+ >>> print p
+ <subprocess.Popen object at 0xb7c12f6c>
+ >>> print p.communicate()[0]
+ GISDBASE='/opt/grass-data';
+ LOCATION_NAME='spearfish60';
+ MAPSET='glynn';
+ GRASS_DB_ENCODING='ascii';
+ GUI='text';
+ MONITOR='x0';
+ \endcode
+
+ @param args list of unnamed arguments (see start_command() for details)
+ @param kwargs list of named arguments (see start_command() for details)
+
+ @return Popen object
+ """
+ kwargs['stdout'] = PIPE
+ return start_command(*args, **kwargs)
+
+def feed_command(*args, **kwargs):
+ """!Passes all arguments to start_command(), but also adds
+ "stdin = PIPE". Returns the Popen object.
+
+ @param args list of unnamed arguments (see start_command() for details)
+ @param kwargs list of named arguments (see start_command() for details)
+
+ @return Popen object
+ """
+ kwargs['stdin'] = PIPE
+ return start_command(*args, **kwargs)
+
+def read_command(*args, **kwargs):
+ """!Passes all arguments to pipe_command, then waits for the process to
+ complete, returning its stdout (i.e. similar to shell `backticks`).
+
+ @param args list of unnamed arguments (see start_command() for details)
+ @param kwargs list of named arguments (see start_command() for details)
+
+ @return stdout
+ """
+ ps = pipe_command(*args, **kwargs)
+ return ps.communicate()[0]
+
+def parse_command(*args, **kwargs):
+ """!Passes all arguments to read_command, then parses the output
+ by parse_key_val().
+
+ Parsing function can be optionally given by <em>parse</em> parameter
+ including its arguments, e.g.
+
+ @code
+ parse_command(..., parse = (grass.parse_key_val, { 'sep' : ':' }))
+ @endcode
+
+ or you can simply define <em>delimiter</em>
+
+ @code
+ parse_command(..., delimiter = ':')
+ @endcode
+
+ @param args list of unnamed arguments (see start_command() for details)
+ @param kwargs list of named arguments (see start_command() for details)
+
+ @return parsed module output
+ """
+ parse = None
+ parse_args = {}
+ if 'parse' in kwargs:
+ if type(kwargs['parse']) is types.TupleType:
+ parse = kwargs['parse'][0]
+ parse_args = kwargs['parse'][1]
+ del kwargs['parse']
+
+ if 'delimiter' in kwargs:
+ parse_args = { 'sep' : kwargs['delimiter'] }
+ del kwargs['delimiter']
+
+ if not parse:
+ parse = parse_key_val # use default fn
+
+ res = read_command(*args, **kwargs)
+
+ return parse(res, **parse_args)
+
+def write_command(*args, **kwargs):
+ """!Passes all arguments to feed_command, with the string specified
+ by the 'stdin' argument fed to the process' stdin.
+
+ @param args list of unnamed arguments (see start_command() for details)
+ @param kwargs list of named arguments (see start_command() for details)
+
+ @return return code
+ """
+ stdin = kwargs['stdin']
+ p = feed_command(*args, **kwargs)
+ p.stdin.write(stdin)
+ p.stdin.close()
+ return p.wait()
+
+def exec_command(prog, flags = "", overwrite = False, quiet = False, verbose = False, env = None, **kwargs):
+ """!Interface to os.execvpe(), but with the make_command() interface.
+
+ @param prog GRASS module
+ @param flags flags to be used (given as a string)
+ @param overwrite True to enable overwriting the output (<tt>--o</tt>)
+ @param quiet True to run quietly (<tt>--q</tt>)
+ @param verbose True to run verbosely (<tt>--v</tt>)
+ @param env directory with environmental variables
+ @param kwargs module's parameters
+
+ """
+ args = make_command(prog, flags, overwrite, quiet, verbose, **kwargs)
+ if env == None:
+ env = os.environ
+ os.execvpe(prog, args, env)
+
+# interface to g.message
+
+def message(msg, flag = None):
+ """!Display a message using `g.message`
+
+ @param msg message to be displayed
+ @param flag flags (given as string)
+ """
+ run_command("g.message", flags = flag, message = msg)
+
+def debug(msg, debug = 1):
+ """!Display a debugging message using `g.message -d`
+
+ @param msg debugging message to be displayed
+ @param debug debug level (0-5)
+ """
+ run_command("g.message", flags = 'd', message = msg, debug = debug)
+
+def verbose(msg):
+ """!Display a verbose message using `g.message -v`
+
+ @param msg verbose message to be displayed
+ """
+ message(msg, flag = 'v')
+
+def info(msg):
+ """!Display an informational message using `g.message -i`
+
+ @param msg informational message to be displayed
+ """
+ message(msg, flag = 'i')
+
+def percent(i, n, s):
+ """!Display a progress info message using `g.message -p`
+
+ @code
+ message(_("Percent complete..."))
+ n = 100
+ for i in range(n):
+ percent(i, n, 1)
+ percent(1, 1, 1)
+ @endcode
+
+ @param i current item
+ @param n total number of items
+ @param s increment size
+ """
+ message("%d %d %d" % (i, n, s), flag = 'p')
+
+def warning(msg):
+ """!Display a warning message using `g.message -w`
+
+ @param msg warning message to be displayed
+ """
+ message(msg, flag = 'w')
+
+def error(msg):
+ """!Display an error message using `g.message -e`
+
+ @param msg error message to be displayed
+ """
+ message(msg, flag = 'e')
+
+def fatal(msg):
+ """!Display an error message using `g.message -e`, then abort
+
+ Raise exception when raise_on_error is 'True'.
+
+ @param msg error message to be displayed
+ """
+ global raise_on_error
+ if raise_on_error:
+ raise ScriptError(msg)
+
+ error(msg)
+ sys.exit(1)
+
+def set_raise_on_error(raise_exp = True):
+ """!Define behaviour on fatal error (fatal() called)
+
+ @param raise_exp True to raise ScriptError instead of calling
+ sys.exit(1) in fatal()
+
+ @return current status
+ """
+ global raise_on_error
+ tmp_raise = raise_on_error
+ raise_on_error = raise_exp
+ return tmp_raise
+
+# interface to g.parser
+
+def _parse_opts(lines):
+ options = {}
+ flags = {}
+ for line in lines:
+ line = line.rstrip('\r\n')
+ if not line:
+ break
+ try:
+ [var, val] = line.split('=', 1)
+ except:
+ raise SyntaxError("invalid output from g.parser: %s" % line)
+
+ if var.startswith('flag_'):
+ flags[var[5:]] = bool(int(val))
+ elif var.startswith('opt_'):
+ options[var[4:]] = val
+ elif var in ['GRASS_OVERWRITE', 'GRASS_VERBOSE']:
+ os.environ[var] = val
+ else:
+ raise SyntaxError("invalid output from g.parser: %s" % line)
+
+ return (options, flags)
+
+def parser():
+ """!Interface to g.parser, intended to be run from the top-level, e.g.:
+
+ @code
+ if __name__ == "__main__":
+ options, flags = grass.parser()
+ main()
+ @endcode
+
+ Thereafter, the global variables "options" and "flags" will be
+ dictionaries containing option/flag values, keyed by lower-case
+ option/flag names. The values in "options" are strings, those in
+ "flags" are Python booleans.
+ """
+ if not os.getenv("GISBASE"):
+ print >> sys.stderr, "You must be in GRASS GIS to run this program."
+ sys.exit(1)
+
+ cmdline = [basename(sys.argv[0])]
+ cmdline += ['"' + arg + '"' for arg in sys.argv[1:]]
+ os.environ['CMDLINE'] = ' '.join(cmdline)
+
+ argv = sys.argv[:]
+ name = argv[0]
+ if not os.path.isabs(name):
+ if os.sep in name or (os.altsep and os.altsep in name):
+ argv[0] = os.path.abspath(name)
+ else:
+ argv[0] = os.path.join(sys.path[0], name)
+
+ p = Popen(['g.parser', '-s'] + argv, stdout = PIPE)
+ s = p.communicate()[0]
+ lines = s.splitlines()
+
+ if not lines or lines[0].rstrip('\r\n') != "@ARGS_PARSED@":
+ sys.stdout.write(s)
+ sys.exit(p.returncode)
+
+ return _parse_opts(lines[1:])
+
+# interface to g.tempfile
+
+def tempfile(create = True):
+ """!Returns the name of a temporary file, created with
+ g.tempfile.
+
+ @param create True to create a file
+
+ @return path to a tmp file
+ """
+ flags = ''
+ if not create:
+ flags += 'd'
+
+ return read_command("g.tempfile", flags = flags, pid = os.getpid()).strip()
+
+def tempdir():
+ """!Returns the name of a temporary dir, created with g.tempfile."""
+ tmp = tempfile(create = False)
+ os.mkdir(tmp)
+
+ return tmp
+
+class KeyValue(dict):
+ """A general-purpose key-value store.
+
+ KeyValue is a subclass of dict, but also allows entries to be read and
+ written using attribute syntax. Example:
+
+ \code
+ >>> region = grass.region()
+ >>> region['rows']
+ 477
+ >>> region.rows
+ 477
+ \endcode
+ """
+
+ def __getattr__(self, key):
+ return self[key]
+
+ def __setattr__(self, key, value):
+ self[key] = value
+
+# key-value parsers
+
+def parse_key_val(s, sep = '=', dflt = None, val_type = None, vsep = None):
+ """!Parse a string into a dictionary, where entries are separated
+ by newlines and the key and value are separated by `sep' (default: `=')
+
+ @param s string to be parsed
+ @param sep key/value separator
+ @param dflt default value to be used
+ @param val_type value type (None for no cast)
+ @param vsep vertical separator (default os.linesep)
+
+ @return parsed input (dictionary of keys/values)
+ """
+ result = KeyValue()
+
+ if not s:
+ return result
+
+ if vsep:
+ lines = s.split(vsep)
+ try:
+ lines.remove('\n')
+ except ValueError:
+ pass
+ else:
+ lines = s.splitlines()
+
+ for line in lines:
+ kv = line.split(sep, 1)
+ k = kv[0].strip()
+ if len(kv) > 1:
+ v = kv[1].strip()
+ else:
+ v = dflt
+
+ if val_type:
+ result[k] = val_type(v)
+ else:
+ result[k] = v
+
+ return result
+
+def _text_to_key_value_dict(filename, sep=":", val_sep=","):
+ """
+ !Convert a key-value text file, where entries are separated
+ by newlines and the key and value are separated by `sep',
+ into a key-value dictionary and discover/use the correct
+ data types (float, int or string) for values.
+
+ @param filename The name or name and path of the text file to convert
+ @param sep The character that separates the keys and values, default is ":"
+ @param val_sep The character that separates the values of a single key, default is ","
+ @return The dictionary
+
+ A text file with this content:
+ \code
+ a: Hello
+ b: 1.0
+ c: 1,2,3,4,5
+ d : hello,8,0.1
+ \endcode
+
+ Will be represented as this dictionary:
+ \code
+ {'a': ['Hello'], 'c': [1, 2, 3, 4, 5], 'b': [1.0], 'd': ['hello', 8, 0.1]}
+ \endcode
+
+ """
+ text = open(filename, "r").readlines()
+ kvdict = KeyValue()
+
+ for line in text:
+ if line.find(sep) >= 0:
+ key, value = line.split(sep)
+ key = key.strip()
+ value = value.strip()
+ else:
+ # Jump over empty values
+ continue
+ values = value.split(val_sep)
+ value_list = []
+
+ for value in values:
+ not_float = False
+ not_int = False
+
+ # Convert values into correct types
+ # We first try integer then float
+ try:
+ value_converted = int(value)
+ except:
+ not_int = True
+ if not_int:
+ try:
+ value_converted = float(value)
+ except:
+ not_float = True
+
+ if not_int and not_float:
+ value_converted = value.strip()
+
+ value_list.append(value_converted)
+
+ kvdict[key] = value_list
+ return kvdict
+
+def compare_key_value_text_files(filename_a, filename_b, sep=":",
+ val_sep=",", precision=0.000001):
+ """
+ !Compare two key-value text files that may contain projection parameter
+
+ @param filename_a The name of the first key-value text file
+ @param filenmae_b The name of the second key-value text file
+ @param sep The character that separates the keys and values, default is ":"
+ @param val_sep The character that separates the values of a single key, default is ","
+ @param precision The precision with which the floating point values are compares
+ if abs(a - b) > precision : return False
+ @return True if full or almost identical, False if different
+
+ This method will print a warning in case keys that are present in the first file
+ are not present in the second one.
+ The comparison method tries to convert the values into there native format (float, int or string)
+ to allow correct comparison.
+
+ An example key-value text file may have this content:
+ \code
+ a: Hello
+ b: 1.0
+ c: 1,2,3,4,5
+ d : hello,8,0.1
+ \endcode
+ """
+ dict_a = _text_to_key_value_dict(filename_a, sep)
+ dict_b = _text_to_key_value_dict(filename_b, sep)
+
+ missing_keys = 0
+
+ # We compare matching keys
+ for key in dict_a.keys():
+ if dict_b.has_key(key):
+ # Floating point values must be handled separately
+ if isinstance(dict_a[key], float) and isinstance(dict_b[key], float):
+ if abs(dict_a[key] - dict_b[key]) > precision:
+ return False
+ elif isinstance(dict_a[key], float) or isinstance(dict_b[key], float):
+ return False
+ else:
+ if dict_a[key] != dict_b[key]:
+ return False
+ else:
+ missing_keys += 1
+ if missing_keys == len(dict_a):
+ return False
+ if missing_keys > 0:
+ warning(_("Several keys (%i out of %i) are missing "
+ "in the target file")%(missing_keys, len(dict_a)))
+ return True
+
+# interface to g.gisenv
+
+def gisenv():
+ """!Returns the output from running g.gisenv (with no arguments), as a
+ dictionary. Example:
+
+ \code
+ >>> env = grass.gisenv()
+ >>> print env['GISDBASE']
+ /opt/grass-data
+ \endcode
+
+ @return list of GRASS variables
+ """
+ s = read_command("g.gisenv", flags='n')
+ return parse_key_val(s)
+
+# interface to g.region
+
+def locn_is_latlong():
+ """!Tests if location is lat/long. Value is obtained
+ by checking the "g.region -p" projection code.
+
+ @return True for a lat/long region, False otherwise
+ """
+ s = read_command("g.region", flags='p')
+ kv = parse_key_val(s, ':')
+ if kv['projection'].split(' ')[1] == '3':
+ return True
+ else:
+ return False
+
+def region(region3d = False, complete = False):
+ """!Returns the output from running "g.region -g", as a
+ dictionary. Example:
+
+ \param region3d True to get 3D region
+
+ \code
+ >>> region = grass.region()
+ >>> [region[key] for key in "nsew"]
+ [228500.0, 215000.0, 645000.0, 630000.0]
+ >>> (region['nsres'], region['ewres'])
+ (10.0, 10.0)
+ \endcode
+
+ @return dictionary of region values
+ """
+ flgs = 'g'
+ if region3d:
+ flgs += '3'
+ if complete:
+ flgs += 'cep'
+
+ s = read_command("g.region", flags = flgs)
+ reg = parse_key_val(s, val_type = float)
+ for k in ['rows', 'cols', 'cells',
+ 'rows3', 'cols3', 'cells3', 'depths']:
+ if k not in reg:
+ continue
+ reg[k] = int(reg[k])
+
+ return reg
+
+def region_env(region3d = False,
+ **kwargs):
+ """!Returns region settings as a string which can used as
+ GRASS_REGION environmental variable.
+
+ If no 'kwargs' are given then the current region is used. Note
+ that this function doesn't modify the current region!
+
+ See also use_temp_region() for alternative method how to define
+ temporary region used for raster-based computation.
+
+ \param region3d True to get 3D region
+ \param kwargs g.region's parameters like 'rast', 'vect' or 'region'
+ \code
+ os.environ['GRASS_REGION'] = grass.region_env(region = 'detail')
+ grass.mapcalc('map = 1', overwrite = True)
+ os.environ.pop('GRASS_REGION')
+ \endcode
+
+ @return string with region values
+ @return empty string on error
+ """
+ # read proj/zone from WIND file
+ env = gisenv()
+ windfile = os.path.join (env['GISDBASE'], env['LOCATION_NAME'],
+ env['MAPSET'], "WIND")
+ fd = open(windfile, "r")
+ grass_region = ''
+ for line in fd.readlines():
+ key, value = map(lambda x: x.strip(), line.split(":", 1))
+ if kwargs and key not in ('proj', 'zone'):
+ continue
+ if not kwargs and not region3d and \
+ key in ('top', 'bottom', 'cols3', 'rows3',
+ 'depths', 'e-w resol3', 'n-s resol3', 't-b resol'):
+ continue
+
+ grass_region += '%s: %s;' % (key, value)
+
+ if not kwargs: # return current region
+ return grass_region
+
+ # read other values from `g.region -g`
+ flgs = 'ug'
+ if region3d:
+ flgs += '3'
+
+ s = read_command('g.region', flags = flgs, **kwargs)
+ if not s:
+ return ''
+ reg = parse_key_val(s)
+
+ kwdata = [('north', 'n'),
+ ('south', 's'),
+ ('east', 'e'),
+ ('west', 'w'),
+ ('cols', 'cols'),
+ ('rows', 'rows'),
+ ('e-w resol', 'ewres'),
+ ('n-s resol', 'nsres')]
+ if region3d:
+ kwdata += [('top', 't'),
+ ('bottom', 'b'),
+ ('cols3', 'cols3'),
+ ('rows3', 'rows3'),
+ ('depths', 'depths'),
+ ('e-w resol3', 'ewres3'),
+ ('n-s resol3', 'nsres3'),
+ ('t-b resol', 'tbres')]
+
+ for wkey, rkey in kwdata:
+ grass_region += '%s: %s;' % (wkey, reg[rkey])
+
+ return grass_region
+
+def use_temp_region():
+ """!Copies the current region to a temporary region with "g.region save=",
+ then sets WIND_OVERRIDE to refer to that region. Installs an atexit
+ handler to delete the temporary region upon termination.
+ """
+ name = "tmp.%s.%d" % (os.path.basename(sys.argv[0]), os.getpid())
+ run_command("g.region", save = name, overwrite = True)
+ os.environ['WIND_OVERRIDE'] = name
+ atexit.register(del_temp_region)
+
+def del_temp_region():
+ """!Unsets WIND_OVERRIDE and removes any region named by it."""
+ try:
+ name = os.environ.pop('WIND_OVERRIDE')
+ run_command("g.remove", quiet = True, region = name)
+ except:
+ pass
+
+# interface to g.findfile
+
+def find_file(name, element = 'cell', mapset = None):
+ """!Returns the output from running g.findfile as a
+ dictionary. Example:
+
+ \code
+ >>> result = grass.find_file('fields', element = 'vector')
+ >>> print result['fullname']
+ fields at PERMANENT
+ >>> print result['file']
+ /opt/grass-data/spearfish60/PERMANENT/vector/fields
+ \endcode
+
+ @param name file name
+ @param element element type (default 'cell')
+ @param mapset mapset name (default all mapsets in search path)
+
+ @return parsed output of g.findfile
+ """
+ if element == 'raster' or element == 'rast':
+ verbose(_('Element type should be "cell" and not "%s"') % element)
+ element = 'cell'
+ s = read_command("g.findfile", flags='n', element = element, file = name, mapset = mapset)
+ return parse_key_val(s)
+
+# interface to g.list
+
+def list_grouped(type, check_search_path = True):
+ """!List elements grouped by mapsets.
+
+ Returns the output from running g.list, as a dictionary where the
+ keys are mapset names and the values are lists of maps in that
+ mapset. Example:
+
+ @code
+ >>> grass.list_grouped('rast')['PERMANENT']
+ ['aspect', 'erosion1', 'quads', 'soils', 'strm.dist', ...
+ @endcode
+
+ @param type element type (rast, vect, rast3d, region, ...)
+ @param check_search_path True to add mapsets for the search path with no found elements
+
+ @return directory of mapsets/elements
+ """
+ if type == 'raster' or type == 'cell':
+ verbose(_('Element type should be "rast" and not "%s"') % element)
+ type = 'rast'
+ dashes_re = re.compile("^----+$")
+ mapset_re = re.compile("<(.*)>")
+ result = {}
+ if check_search_path:
+ for mapset in mapsets(search_path = True):
+ result[mapset] = []
+
+ mapset = None
+ for line in read_command("g.list", type = type).splitlines():
+ if line == "":
+ continue
+ if dashes_re.match(line):
+ continue
+ m = mapset_re.search(line)
+ if m:
+ mapset = m.group(1)
+ if mapset not in result.keys():
+ result[mapset] = []
+ continue
+ if mapset:
+ result[mapset].extend(line.split())
+
+ return result
+
+def _concat(xs):
+ result = []
+ for x in xs:
+ result.extend(x)
+ return result
+
+def list_pairs(type):
+ """!List of elements as tuples.
+
+ Returns the output from running g.list, as a list of (map, mapset)
+ pairs. Example:
+
+ @code
+ >>> grass.list_pairs('rast')
+ [('aspect', 'PERMANENT'), ('erosion1', 'PERMANENT'), ('quads', 'PERMANENT'), ...
+ @endcode
+
+ @param type element type (rast, vect, rast3d, region, ...)
+
+ @return list of tuples (map, mapset)
+ """
+ return _concat([[(map, mapset) for map in maps]
+ for mapset, maps in list_grouped(type).iteritems()])
+
+def list_strings(type):
+ """!List of elements as strings.
+
+ Returns the output from running g.list, as a list of qualified
+ names. Example:
+
+ @code
+ >>> grass.list_strings('rast')
+ ['aspect at PERMANENT', 'erosion1 at PERMANENT', 'quads at PERMANENT', 'soils at PERMANENT', ...
+ @endcode
+
+ @param type element type
+
+ @return list of strings ('map@@mapset')
+ """
+ return ["%s@%s" % pair for pair in list_pairs(type)]
+
+# interface to g.mlist
+
+def mlist_strings(type, pattern = None, mapset = None, flag = ''):
+ """!List of elements as strings.
+
+ Returns the output from running g.mlist, as a list of qualified
+ names.
+
+ @param type element type (rast, vect, rast3d, region, ...)
+ @param pattern pattern string
+ @param mapset mapset name (if not given use search path)
+ @param flag pattern type: 'r' (basic regexp), 'e' (extended regexp), or '' (glob pattern)
+
+ @return list of elements
+ """
+ if type == 'raster' or type == 'cell':
+ verbose(_('Element type should be "rast" and not "%s"') % element)
+ type = 'rast'
+ result = list()
+ for line in read_command("g.mlist",
+ quiet = True,
+ flags = 'm' + flag,
+ type = type,
+ pattern = pattern,
+ mapset = mapset).splitlines():
+ result.append(line.strip())
+
+ return result
+
+def mlist_pairs(type, pattern = None, mapset = None, flag = ''):
+ """!List of elements as pairs
+
+ Returns the output from running g.mlist, as a list of
+ (name, mapset) pairs
+
+ @param type element type (rast, vect, rast3d, region, ...)
+ @param pattern pattern string
+ @param mapset mapset name (if not given use search path)
+ @param flag pattern type: 'r' (basic regexp), 'e' (extended regexp), or '' (glob pattern)
+
+ @return list of elements
+ """
+ return [tuple(map.split('@', 1)) for map in mlist_strings(type, pattern, mapset, flag)]
+
+def mlist_grouped(type, pattern = None, check_search_path = True, flag = ''):
+ """!List of elements grouped by mapsets.
+
+ Returns the output from running g.mlist, as a dictionary where the
+ keys are mapset names and the values are lists of maps in that
+ mapset. Example:
+
+ @code
+ >>> grass.mlist_grouped('rast', pattern='r*')['PERMANENT']
+ ['railroads', 'roads', 'rstrct.areas', 'rushmore']
+ @endcode
+
+ @param type element type (rast, vect, rast3d, region, ...)
+ @param pattern pattern string
+ @param check_search_path True to add mapsets for the search path with no found elements
+ @param flag pattern type: 'r' (basic regexp), 'e' (extended regexp), or '' (glob pattern)
+
+ @return directory of mapsets/elements
+ """
+ if type == 'raster' or type == 'cell':
+ verbose(_('Element type should be "rast" and not "%s"') % element)
+ type = 'rast'
+ result = {}
+ if check_search_path:
+ for mapset in mapsets(search_path = True):
+ result[mapset] = []
+
+ mapset = None
+ for line in read_command("g.mlist", quiet = True, flags = "m" + flag,
+ type = type, pattern = pattern).splitlines():
+ try:
+ name, mapset = line.split('@')
+ except ValueError:
+ warning(_("Invalid element '%s'") % line)
+ continue
+
+ if mapset in result:
+ result[mapset].append(name)
+ else:
+ result[mapset] = [name, ]
+
+ return result
+
+# color parsing
+
+named_colors = {
+ "white": (1.00, 1.00, 1.00),
+ "black": (0.00, 0.00, 0.00),
+ "red": (1.00, 0.00, 0.00),
+ "green": (0.00, 1.00, 0.00),
+ "blue": (0.00, 0.00, 1.00),
+ "yellow": (1.00, 1.00, 0.00),
+ "magenta": (1.00, 0.00, 1.00),
+ "cyan": (0.00, 1.00, 1.00),
+ "aqua": (0.00, 0.75, 0.75),
+ "grey": (0.75, 0.75, 0.75),
+ "gray": (0.75, 0.75, 0.75),
+ "orange": (1.00, 0.50, 0.00),
+ "brown": (0.75, 0.50, 0.25),
+ "purple": (0.50, 0.00, 1.00),
+ "violet": (0.50, 0.00, 1.00),
+ "indigo": (0.00, 0.50, 1.00)}
+
+def parse_color(val, dflt = None):
+ """!Parses the string "val" as a GRASS colour, which can be either one of
+ the named colours or an R:G:B tuple e.g. 255:255:255. Returns an
+ (r,g,b) triple whose components are floating point values between 0
+ and 1. Example:
+
+ \code
+ >>> grass.parse_color("red")
+ (1.0, 0.0, 0.0)
+ >>> grass.parse_color("255:0:0")
+ (1.0, 0.0, 0.0)
+ \endcode
+
+ @param val color value
+ @param dflt default color value
+
+ @return tuple RGB
+ """
+ if val in named_colors:
+ return named_colors[val]
+
+ vals = val.split(':')
+ if len(vals) == 3:
+ return tuple(float(v) / 255 for v in vals)
+
+ return dflt
+
+# check GRASS_OVERWRITE
+
+def overwrite():
+ """!Return True if existing files may be overwritten"""
+ owstr = 'GRASS_OVERWRITE'
+ return owstr in os.environ and os.environ[owstr] != '0'
+
+# check GRASS_VERBOSE
+
+def verbosity():
+ """!Return the verbosity level selected by GRASS_VERBOSE"""
+ vbstr = os.getenv('GRASS_VERBOSE')
+ if vbstr:
+ return int(vbstr)
+ else:
+ return 2
+
+## various utilities, not specific to GRASS
+
+# basename inc. extension stripping
+
+def basename(path, ext = None):
+ """!Remove leading directory components and an optional extension
+ from the specified path
+
+ @param path path
+ @param ext extension
+ """
+ name = os.path.basename(path)
+ if not ext:
+ return name
+ fs = name.rsplit('.', 1)
+ if len(fs) > 1 and fs[1].lower() == ext:
+ name = fs[0]
+ return name
+
+# find a program (replacement for "which")
+
+def find_program(pgm, args = []):
+ """!Attempt to run a program, with optional arguments.
+
+ @param pgm program name
+ @param args list of arguments
+
+ @return False if the attempt failed due to a missing executable
+ @return True otherwise
+ """
+ nuldev = file(os.devnull, 'w+')
+ try:
+ ret = call([pgm] + args, stdin = nuldev, stdout = nuldev, stderr = nuldev)
+ if ret == 0:
+ found = True
+ else:
+ found = False
+ except:
+ found = False
+ nuldev.close()
+
+ return found
+
+# try to remove a file, without complaints
+
+def try_remove(path):
+ """!Attempt to remove a file; no exception is generated if the
+ attempt fails.
+
+ @param path path to file to remove
+ """
+ try:
+ os.remove(path)
+ except:
+ pass
+
+# try to remove a directory, without complaints
+
+def try_rmdir(path):
+ """!Attempt to remove a directory; no exception is generated if the
+ attempt fails.
+
+ @param path path to directory to remove
+ """
+ try:
+ os.rmdir(path)
+ except:
+ shutil.rmtree(path, ignore_errors = True)
+
+def float_or_dms(s):
+ """!Convert DMS to float.
+
+ @param s DMS value
+
+ @return float value
+ """
+ return sum(float(x) / 60 ** n for (n, x) in enumerate(s.split(':')))
+
+# interface to g.mapsets
+
+def mapsets(search_path = False):
+ """!List available mapsets
+
+ @param search_path True to list mapsets only in search path
+
+ @return list of mapsets
+ """
+ if search_path:
+ flags = 'p'
+ else:
+ flags = 'l'
+ mapsets = read_command('g.mapsets',
+ flags = flags,
+ sep = 'newline',
+ quiet = True)
+ if not mapsets:
+ fatal(_("Unable to list mapsets"))
+
+ return mapsets.splitlines()
+
+# interface to `g.proj -c`
+
+def create_location(dbase, location,
+ epsg = None, proj4 = None, filename = None, wkt = None,
+ datum = None, datum_trans = None, desc = None):
+ """!Create new location
+
+ Raise ScriptError on error.
+
+ @param dbase path to GRASS database
+ @param location location name to create
+ @param epsg if given create new location based on EPSG code
+ @param proj4 if given create new location based on Proj4 definition
+ @param filename if given create new location based on georeferenced file
+ @param wkt if given create new location based on WKT definition (path to PRJ file)
+ @param datum GRASS format datum code
+ @param datum_trans datum transformation parameters (used for epsg and proj4)
+ @param desc description of the location (creates MYNAME file)
+ """
+ gisdbase = None
+ if epsg or proj4 or filename or wkt:
+ gisdbase = gisenv()['GISDBASE']
+ run_command('g.gisenv',
+ set = 'GISDBASE=%s' % dbase)
+ if not os.path.exists(dbase):
+ os.mkdir(dbase)
+
+ kwargs = dict()
+ if datum:
+ kwargs['datum'] = datum
+ if datum_trans:
+ kwargs['datum_trans'] = datum_trans
+
+ if epsg:
+ ps = pipe_command('g.proj',
+ quiet = True,
+ epsg = epsg,
+ location = location,
+ stderr = PIPE,
+ **kwargs)
+ elif proj4:
+ ps = pipe_command('g.proj',
+ quiet = True,
+ proj4 = proj4,
+ location = location,
+ stderr = PIPE,
+ **kwargs)
+ elif filename:
+ ps = pipe_command('g.proj',
+ quiet = True,
+ georef = filename,
+ location = location,
+ stderr = PIPE)
+ elif wkt:
+ ps = pipe_command('g.proj',
+ quiet = True,
+ wkt = wkt,
+ location = location,
+ stderr = PIPE)
+ else:
+ _create_location_xy(dbase, location)
+
+ if epsg or proj4 or filename or wkt:
+ error = ps.communicate()[1]
+ run_command('g.gisenv',
+ set = 'GISDBASE=%s' % gisdbase)
+
+ if ps.returncode != 0 and error:
+ raise ScriptError(repr(error))
+
+ try:
+ fd = codecs.open(os.path.join(dbase, location,
+ 'PERMANENT', 'MYNAME'),
+ encoding = 'utf-8', mode = 'w')
+ if desc:
+ fd.write(desc + os.linesep)
+ else:
+ fd.write(os.linesep)
+ fd.close()
+ except OSError, e:
+ raise ScriptError(repr(e))
+
+def _create_location_xy(database, location):
+ """!Create unprojected location
+
+ Raise ScriptError on error.
+
+ @param database GRASS database where to create new location
+ @param location location name
+ """
+ cur_dir = os.getcwd()
+ try:
+ os.chdir(database)
+ os.mkdir(location)
+ os.mkdir(os.path.join(location, 'PERMANENT'))
+
+ # create DEFAULT_WIND and WIND files
+ regioninfo = ['proj: 0',
+ 'zone: 0',
+ 'north: 1',
+ 'south: 0',
+ 'east: 1',
+ 'west: 0',
+ 'cols: 1',
+ 'rows: 1',
+ 'e-w resol: 1',
+ 'n-s resol: 1',
+ 'top: 1',
+ 'bottom: 0',
+ 'cols3: 1',
+ 'rows3: 1',
+ 'depths: 1',
+ 'e-w resol3: 1',
+ 'n-s resol3: 1',
+ 't-b resol: 1']
+
+ defwind = open(os.path.join(location,
+ "PERMANENT", "DEFAULT_WIND"), 'w')
+ for param in regioninfo:
+ defwind.write(param + '%s' % os.linesep)
+ defwind.close()
+
+ shutil.copy(os.path.join(location, "PERMANENT", "DEFAULT_WIND"),
+ os.path.join(location, "PERMANENT", "WIND"))
+
+ os.chdir(cur_dir)
+ except OSError, e:
+ raise ScriptError(repr(e))
+
+# interface to g.version
+
+def version():
+ """!Get GRASS version as dictionary
+
+ @code
+ print version()
+
+ {'proj4': '4.8.0', 'geos': '3.3.5', 'libgis_revision': '52468',
+ 'libgis_date': '2012-07-27 22:53:30 +0200 (Fri, 27 Jul 2012)',
+ 'version': '7.0.svn', 'date': '2012', 'gdal': '2.0dev', 'revision': '53670'}
+ @endcode
+ """
+ data = parse_command('g.version',
+ flags = 'rge')
+ for k, v in data.iteritems():
+ data[k.strip()] = v.replace('"', '').strip()
+
+ return data
+
+# get debug_level
+_debug_level = None
+
+def debug_level():
+ global _debug_level
+ if _debug_level is not None:
+ return _debug_level
+ _debug_level = 0
+ if find_program('g.gisenv', ['--help']):
+ _debug_level = int(gisenv().get('DEBUG', 0))
Copied: grass/trunk/lib/python/script/db.py (from rev 54568, grass/trunk/lib/python/db.py)
===================================================================
--- grass/trunk/lib/python/script/db.py (rev 0)
+++ grass/trunk/lib/python/script/db.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -0,0 +1,155 @@
+"""!@package grass.script.db
+
+ at brief GRASS Python scripting module (database functions)
+
+Database related functions to be used in Python scripts.
+
+Usage:
+
+ at code
+from grass.script import db as grass
+
+grass.db_describe(table)
+...
+ at endcode
+
+(C) 2008-2009, 2012 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Glynn Clements
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import tempfile as pytempfile # conflict with core.tempfile
+
+from core import *
+
+def db_describe(table, **args):
+ """!Return the list of columns for a database table
+ (interface to `db.describe -c'). Example:
+
+ \code
+ >>> grass.db_describe('lakes')
+ {'nrows': 15279, 'cols': [['cat', 'INTEGER', '11'], ['AREA', 'DOUBLE PRECISION', '20'],
+ ['PERIMETER', 'DOUBLE PRECISION', '20'], ['FULL_HYDRO', 'DOUBLE PRECISION', '20'],
+ ['FULL_HYDR2', 'DOUBLE PRECISION', '20'], ['FTYPE', 'CHARACTER', '24'],
+ ['FCODE', 'INTEGER', '11'], ['NAME', 'CHARACTER', '99']], 'ncols': 8}
+ \endcode
+
+ @param table table name
+ @param args
+
+ @return parsed module output
+ """
+ s = read_command('db.describe', flags = 'c', table = table, **args)
+ if not s:
+ fatal(_("Unable to describe table <%s>") % table)
+
+ cols = []
+ result = {}
+ for l in s.splitlines():
+ f = l.split(':')
+ key = f[0]
+ f[1] = f[1].lstrip(' ')
+ if key.startswith('Column '):
+ n = int(key.split(' ')[1])
+ cols.insert(n, f[1:])
+ elif key in ['ncols', 'nrows']:
+ result[key] = int(f[1])
+ else:
+ result[key] = f[1:]
+ result['cols'] = cols
+
+ return result
+
+# run "db.connect -g" and parse output
+
+def db_table_exist(table, **args):
+ """!Return True if database table exists, False otherwise
+
+ @param table table name
+ @param args
+
+ @return True for success, False otherwise
+ """
+ result = run_command('db.describe', flags = 'c', table = table, **args)
+ if result == 0:
+ return True
+ else:
+ return False
+
+def db_connection():
+ """!Return the current database connection parameters
+ (interface to `db.connect -g'). Example:
+
+ \code
+ >>> grass.db_connection()
+ {'group': 'x', 'schema': '', 'driver': 'dbf', 'database': '$GISDBASE/$LOCATION_NAME/$MAPSET/dbf/'}
+ \endcode
+
+ @return parsed output of db.connect
+ """
+ return parse_command('db.connect', flags = 'g')
+
+def db_select(sql = None, filename = None, table = None, **args):
+ """!Perform SQL select statement
+
+ Note: one of <em>sql</em>, <em>filename</em>, or <em>table</em>
+ arguments must be provided.
+
+ Examples:
+
+ \code
+ grass.db_select(sql = 'SELECT cat,CAMPUS FROM busstopsall WHERE cat < 4')
+
+ (('1', 'Vet School'), ('2', 'West'), ('3', 'North'))
+ \endcode
+
+ \code
+ grass.db_select(filename = '/path/to/sql/file')
+ \endcode
+
+ Simplyfied usage
+
+ \code
+ grass.db_select(table = 'busstopsall')
+ \endcode
+
+ performs <tt>SELECT * FROM busstopsall</tt>.
+
+ @param sql SQL statement to perform (or None)
+ @param filename name of file with SQL statements (or None)
+ @param table name of table to query (or None)
+ @param args see \gmod{db.select} arguments
+ """
+ fname = tempfile(create = False)
+ if sql:
+ args['sql'] = sql
+ elif filename:
+ args['input'] = filename
+ elif table:
+ args['table'] = table
+ else:
+ fatal(_("Programmer error: '%(sql)s', '%(filename)s', or '%(table)s' must be provided") %
+ {'sql': 'sql', 'filename': 'filename', 'table': 'table'} )
+
+ if 'sep' not in args:
+ args['sep'] = '|'
+
+ ret = run_command('db.select', quiet = True,
+ flags = 'c',
+ output = fname,
+ **args)
+
+ if ret != 0:
+ fatal(_("Fetching data failed"))
+
+ ofile = open(fname)
+ result = map(lambda x: tuple(x.rstrip(os.linesep).split(args['sep'])),
+ ofile.readlines())
+ ofile.close()
+ try_remove(fname)
+
+ return tuple(result)
Copied: grass/trunk/lib/python/script/raster.py (from rev 54568, grass/trunk/lib/python/raster.py)
===================================================================
--- grass/trunk/lib/python/script/raster.py (rev 0)
+++ grass/trunk/lib/python/script/raster.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -0,0 +1,137 @@
+"""!@package grass.script.raster
+
+ at brief GRASS Python scripting module (raster functions)
+
+Raster related functions to be used in Python scripts.
+
+Usage:
+
+ at code
+from grass.script import raster as grass
+
+grass.raster_history(map)
+...
+ at endcode
+
+(C) 2008-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Glynn Clements
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import string
+
+from core import *
+
+# add raster history
+
+def raster_history(map):
+ """!Set the command history for a raster map to the command used to
+ invoke the script (interface to `r.support').
+
+ @param map map name
+
+ @return True on success
+ @return False on failure
+ """
+ current_mapset = gisenv()['MAPSET']
+ if find_file(name = map)['mapset'] == current_mapset:
+ run_command('r.support', map = map, history = os.environ['CMDLINE'])
+ return True
+
+ warning(_("Unable to write history for <%(map)s>. "
+ "Raster map <%(map)s> not found in current mapset." % { 'map' : map, 'map' : map}))
+ return False
+
+# run "r.info -gre ..." and parse output
+
+def raster_info(map):
+ """!Return information about a raster map (interface to
+ `r.info'). Example:
+
+ \code
+ >>> grass.raster_info('elevation')
+ {'north': 228500.0, 'timestamp': '"none"', 'min': 55.578792572021499,
+ 'datatype': 'FCELL', 'max': 156.32986450195301, 'ewres': 10.0,
+ 'vertical_datum': '', 'west': 630000.0, 'units': '',
+ 'title': 'South-West Wake county: Elevation NED 10m (elev_ned10m)',
+ 'east': 645000.0, 'nsres': 10.0, 'south': 215000.0}
+ \endcode
+
+ @param map map name
+
+ @return parsed raster info
+ """
+
+ def float_or_null(s):
+ if s == 'NULL':
+ return None
+ else:
+ return float(s)
+
+ s = read_command('r.info', flags = 'gre', map = map)
+ kv = parse_key_val(s)
+ for k in ['min', 'max']:
+ kv[k] = float_or_null(kv[k])
+ for k in ['north', 'south', 'east', 'west']:
+ kv[k] = float(kv[k])
+ for k in ['nsres', 'ewres']:
+ kv[k] = float_or_dms(kv[k])
+ return kv
+
+# interface to r.mapcalc
+
+def mapcalc(exp, quiet = False, verbose = False, overwrite = False, **kwargs):
+ """!Interface to r.mapcalc.
+
+ @param exp expression
+ @param quiet True to run quietly (<tt>--q</tt>)
+ @param verbose True to run verbosely (<tt>--v</tt>)
+ @param overwrite True to enable overwriting the output (<tt>--o</tt>)
+ @param kwargs
+ """
+ t = string.Template(exp)
+ e = t.substitute(**kwargs)
+
+ if run_command('r.mapcalc', expression = e,
+ quiet = quiet,
+ verbose = verbose,
+ overwrite = overwrite) != 0:
+ fatal(_("An error occurred while running r.mapcalc"))
+
+
+def mapcalc_start(exp, quiet = False, verbose = False, overwrite = False, **kwargs):
+ """!Interface to r.mapcalc, doesn't wait for it to finish, returns Popen object.
+
+ \code
+ >>> expr1 = '"%s" = "%s" * 10' % (output, input)
+ >>> expr2 = '...' # etc.
+ >>> # launch the jobs:
+ >>> p1 = grass.mapcalc_start(expr1)
+ >>> p2 = grass.mapcalc_start(expr2) # etc.
+ ...
+ >>> # wait for them to finish:
+ >>> p1.wait()
+ >>> p2.wait() # etc.
+ \endcode
+
+ @param exp expression
+ @param quiet True to run quietly (<tt>--q</tt>)
+ @param verbose True to run verbosely (<tt>--v</tt>)
+ @param overwrite True to enable overwriting the output (<tt>--o</tt>)
+ @param kwargs
+
+ @return Popen object
+ """
+ t = string.Template(exp)
+ e = t.substitute(**kwargs)
+
+ return start_command('r.mapcalc', expression = e,
+ quiet = quiet,
+ verbose = verbose,
+ overwrite = overwrite)
+
Copied: grass/trunk/lib/python/script/raster3d.py (from rev 54568, grass/trunk/lib/python/raster3d.py)
===================================================================
--- grass/trunk/lib/python/script/raster3d.py (rev 0)
+++ grass/trunk/lib/python/script/raster3d.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -0,0 +1,89 @@
+"""!@package grass.script.raster3d
+
+ at brief GRASS Python scripting module (raster3d functions)
+
+Raster3d related functions to be used in Python scripts.
+
+Usage:
+
+ at code
+from grass.script import raster3d as grass
+
+grass.raster3d_info(map)
+...
+ at endcode
+
+(C) 2008-2009 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Glynn Clements
+ at author Martin Landa <landa.martin gmail.com>
+ at author Soeren Gebbert <soeren.gebbert gmail.com>
+"""
+
+import os
+import string
+
+from core import *
+
+# add raster history
+
+# run "r3.info -rstgip ..." and parse output
+
+def raster3d_info(map):
+ """!Return information about a raster3d map (interface to
+ `r3.info'). Example:
+
+ \code
+ >>> grass.raster3d_info('volume')
+ {'tiledimz': 1, 'tbres': 1.0, 'tiledimx': 27, 'tiledimy': 16, 'north': 60.490001999999997, 'tilenumy': 1, 'tilenumz': 1,
+ 'min': 1.0, 'datatype': '"DCELL"', 'max': 1.0, 'top': 0.5, 'bottom': -0.5, 'west': -3.2200000000000002, 'tilenumx': 1,
+ 'ewres': 0.98222219, 'east': 23.299999, 'nsres': 0.99937511999999995, 'Timestamp': '"none"', 'south': 44.5}
+ \endcode
+
+ @param map map name
+
+ @return parsed raster3d info
+ """
+
+ def float_or_null(s):
+ if s == 'NULL':
+ return None
+ else:
+ return float(s)
+
+ s = read_command('r3.info', flags='rg', map=map)
+ kv = parse_key_val(s)
+ for k in ['min', 'max']:
+ kv[k] = float_or_null(kv[k])
+ for k in ['north', 'south', 'east', 'west', 'top', 'bottom']:
+ kv[k] = float(kv[k])
+ for k in ['nsres', 'ewres', 'tbres']:
+ kv[k] = float_or_dms(kv[k])
+ for k in ['tilenumx', 'tilenumy', 'tilenumz']:
+ kv[k] = int(kv[k])
+ for k in ['tiledimx', 'tiledimy', 'tiledimz']:
+ kv[k] = int(kv[k])
+ return kv
+
+# interface to r3.mapcalc
+
+def mapcalc3d(exp, quiet = False, verbose = False, overwrite = False, **kwargs):
+ """!Interface to r3.mapcalc.
+
+ @param exp expression
+ @param quiet True to run quietly (<tt>--q</tt>)
+ @param verbose True to run verbosely (<tt>--v</tt>)
+ @param overwrite True to enable overwriting the output (<tt>--o</tt>)
+ @param kwargs
+ """
+ t = string.Template(exp)
+ e = t.substitute(**kwargs)
+
+ if run_command('r3.mapcalc', expression = e,
+ quiet = quiet,
+ verbose = verbose,
+ overwrite = overwrite) != 0:
+ fatal(_("An error occurred while running r3.mapcalc"))
Copied: grass/trunk/lib/python/script/setup.py.sed (from rev 54568, grass/trunk/lib/python/setup.py.sed)
===================================================================
--- grass/trunk/lib/python/script/setup.py.sed (rev 0)
+++ grass/trunk/lib/python/script/setup.py.sed 2013-01-08 09:34:42 UTC (rev 54569)
@@ -0,0 +1,71 @@
+"""!@package grass.script.setup
+
+ at brief GRASS Python scripting module (setup)
+
+Setup functions to be used in Python scripts.
+
+Usage:
+
+ at code
+from grass.script import setup as grass
+
+grass.init()
+...
+ at endcode
+
+(C) 2010-2012 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import sys
+import tempfile as tmpfile
+
+def init(gisbase, dbase = '', location = 'demolocation', mapset = 'PERMANENT'):
+ """!Initialize system variables to run scripts without starting
+ GRASS explicitly.
+
+ User is resposible to delete gisrc file.
+
+ @param gisbase path to GRASS installation
+ @param dbase path to GRASS database (default: '')
+ @param location location name (default: 'demolocation')
+ @param mapset mapset within given location (default: 'PERMANENT')
+ @return path to gisrc file
+ """
+ # define PATH
+ os.environ['PATH'] += os.pathsep + os.path.join(gisbase, 'bin')
+ os.environ['PATH'] += os.pathsep + os.path.join(gisbase, 'scripts')
+ if sys.platform.startswith('win'): # added for winGRASS
+ os.environ['PATH'] += os.pathsep + os.path.join(gisbase, 'extralib')
+ # define LD_LIBRARY_PATH
+ if '@LD_LIBRARY_PATH_VAR@' not in os.environ:
+ os.environ['@LD_LIBRARY_PATH_VAR@'] = ''
+ os.environ['@LD_LIBRARY_PATH_VAR@'] += os.pathsep + os.path.join(gisbase, 'lib')
+
+ os.environ['GIS_LOCK'] = str(os.getpid())
+
+ # Set PYTHONPATH to find GRASS Python modules
+ path = os.getenv('PYTHONPATH')
+ dir = os.path.join(gisbase, 'etc', 'python')
+ if path:
+ path = dir + os.pathsep + path
+ else:
+ path = dir
+ os.environ['PYTHONPATH'] = path
+
+ if not dbase:
+ dbase = gisbase
+
+ fd, gisrc = tmpfile.mkstemp()
+ os.environ['GISRC'] = gisrc
+ os.write(fd, "GISDBASE: %s\n" % dbase)
+ os.write(fd, "LOCATION_NAME: %s\n" % location)
+ os.write(fd, "MAPSET: %s\n" % mapset)
+ os.close(fd)
+
+ return gisrc
Copied: grass/trunk/lib/python/script/task.py (from rev 54568, grass/trunk/lib/python/task.py)
===================================================================
--- grass/trunk/lib/python/script/task.py (rev 0)
+++ grass/trunk/lib/python/script/task.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -0,0 +1,555 @@
+"""!@package grass.script.task
+
+ at brief GRASS Python scripting module (task)
+
+Get interface description of GRASS commands
+
+Based on gui/wxpython/gui_modules/menuform.py
+
+Usage:
+
+ at code
+from grass.script import task as gtask
+
+gtask.command_info('r.info')
+...
+ at endcode
+
+(C) 2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import types
+import string
+try:
+ import xml.etree.ElementTree as etree
+except ImportError:
+ import elementtree.ElementTree as etree # Python <= 2.4
+
+from core import *
+
+class grassTask:
+ """!This class holds the structures needed for filling by the
+ parser
+
+ Parameter blackList is a dictionary with fixed structure, eg.
+
+ @code
+ blackList = {'items' : {'d.legend' : { 'flags' : ['m'],
+ 'params' : [] }},
+ 'enabled': True}
+ @endcode
+
+ @param path full path
+ @param blackList hide some options in the GUI (dictionary)
+ """
+ def __init__(self, path = None, blackList = None):
+ self.path = path
+ self.name = _('unknown')
+ self.params = list()
+ self.description = ''
+ self.label = ''
+ self.flags = list()
+ self.keywords = list()
+ self.errorMsg = ''
+ self.firstParam = None
+ if blackList:
+ self.blackList = blackList
+ else:
+ self.blackList = { 'enabled' : False, 'items' : {} }
+
+ if path is not None:
+ try:
+ processTask(tree = etree.fromstring(get_interface_description(path)),
+ task = self)
+ except ScriptError, e:
+ self.errorMsg = e.value
+
+ self.define_first()
+
+ def define_first(self):
+ """!Define first parameter
+
+ @return name of first parameter
+ """
+ if len(self.params) > 0:
+ self.firstParam = self.params[0]['name']
+
+ return self.firstParam
+
+ def get_error_msg(self):
+ """!Get error message ('' for no error)
+ """
+ return self.errorMsg
+
+ def get_name(self):
+ """!Get task name
+ """
+ if sys.platform == 'win32':
+ name, ext = os.path.splitext(self.name)
+ if ext in ('.py', '.sh'):
+ return name
+ else:
+ return self.name
+
+ return self.name
+
+ def get_description(self, full = True):
+ """!Get module's description
+
+ @param full True for label + desc
+ """
+ if self.label:
+ if full:
+ return self.label + ' ' + self.description
+ else:
+ return self.label
+ else:
+ return self.description
+
+ def get_keywords(self):
+ """!Get module's keywords
+ """
+ return self.keywords
+
+ def get_list_params(self, element = 'name'):
+ """!Get list of parameters
+
+ @param element element name
+ """
+ params = []
+ for p in self.params:
+ params.append(p[element])
+
+ return params
+
+ def get_list_flags(self, element = 'name'):
+ """!Get list of flags
+
+ @param element element name
+ """
+ flags = []
+ for p in self.flags:
+ flags.append(p[element])
+
+ return flags
+
+ def get_param(self, value, element = 'name', raiseError = True):
+ """!Find and return a param by name
+
+ @param value param's value
+ @param element element name
+ @param raiseError True for raise on error
+ """
+ try:
+ for p in self.params:
+ val = p[element]
+ if val is None:
+ continue
+ if type(val) in (types.ListType, types.TupleType):
+ if value in val:
+ return p
+ elif type(val) == types.StringType:
+ if p[element][:len(value)] == value:
+ return p
+ else:
+ if p[element] == value:
+ return p
+ except KeyError:
+ pass
+
+ if raiseError:
+ raise ValueError, _("Parameter element '%(element)s' not found: '%(value)s'") % \
+ { 'element' : element, 'value' : value }
+ else:
+ return None
+
+ def get_flag(self, aFlag):
+ """!Find and return a flag by name
+
+ Raises ValueError when the flag is not found.
+
+ @param aFlag name of the flag
+ """
+ for f in self.flags:
+ if f['name'] == aFlag:
+ return f
+ raise ValueError, _("Flag not found: %s") % aFlag
+
+ def get_cmd_error(self):
+ """!Get error string produced by get_cmd(ignoreErrors = False)
+
+ @return list of errors
+ """
+ errorList = list()
+ # determine if suppress_required flag is given
+ for f in self.flags:
+ if f['value'] and f['suppress_required']:
+ return errorList
+
+ for p in self.params:
+ if not p.get('value', '') and p.get('required', False):
+ if not p.get('default', ''):
+ desc = p.get('label', '')
+ if not desc:
+ desc = p['description']
+ errorList.append(_("Parameter '%(name)s' (%(desc)s) is missing.") % \
+ {'name' : p['name'], 'desc' : desc })
+
+ return errorList
+
+ def get_cmd(self, ignoreErrors = False, ignoreRequired = False, ignoreDefault = True):
+ """!Produce an array of command name and arguments for feeding
+ into some execve-like command processor.
+
+ @param ignoreErrors True to return whatever has been built so
+ far, even though it would not be a correct command for GRASS
+ @param ignoreRequired True to ignore required flags, otherwise
+ '@<required@>' is shown
+ @param ignoreDefault True to ignore parameters with default values
+ """
+ cmd = [self.get_name()]
+
+ suppress_required = False
+ for flag in self.flags:
+ if flag['value']:
+ if len(flag['name']) > 1: # e.g. overwrite
+ cmd += [ '--' + flag['name'] ]
+ else:
+ cmd += [ '-' + flag['name'] ]
+ if flag['suppress_required']:
+ suppress_required = True
+ for p in self.params:
+ if p.get('value', '') == '' and p.get('required', False):
+ if p.get('default', '') != '':
+ cmd += [ '%s=%s' % (p['name'], p['default']) ]
+ elif ignoreErrors and not suppress_required and not ignoreRequired:
+ cmd += [ '%s=%s' % (p['name'], _('<required>')) ]
+ elif p.get('value', '') == '' and p.get('default', '') != '' and not ignoreDefault:
+ cmd += [ '%s=%s' % (p['name'], p['default']) ]
+ elif p.get('value', '') != '' and \
+ (p['value'] != p.get('default', '') or not ignoreDefault):
+ # output only values that have been set, and different from defaults
+ cmd += [ '%s=%s' % (p['name'], p['value']) ]
+
+ errList = self.get_cmd_error()
+ if ignoreErrors is False and errList:
+ raise ValueError, '\n'.join(errList)
+
+ return cmd
+
+ def get_options(self):
+ """!Get options
+ """
+ return { 'flags' : self.flags,
+ 'params' : self.params }
+
+ def has_required(self):
+ """!Check if command has at least one required paramater
+ """
+ for p in self.params:
+ if p.get('required', False):
+ return True
+
+ return False
+
+ def set_param(self, aParam, aValue, element = 'value'):
+ """!Set param value/values.
+ """
+ try:
+ param = self.get_param(aParam)
+ except ValueError:
+ return
+
+ param[element] = aValue
+
+ def set_flag(self, aFlag, aValue, element = 'value'):
+ """!Enable / disable flag.
+ """
+ try:
+ param = self.get_flag(aFlag)
+ except ValueError:
+ return
+
+ param[element] = aValue
+
+ def set_options(self, opts):
+ """!Set flags and parameters
+
+ @param opts list of flags and parameters"""
+ for opt in opts:
+ if opt[0] == '-': # flag
+ self.set_flag(opt.lstrip('-'), True)
+ else: # parameter
+ key, value = opt.split('=', 1)
+ self.set_param(key, value)
+
+class processTask:
+ """!A ElementTree handler for the --interface-description output,
+ as defined in grass-interface.dtd. Extend or modify this and the
+ DTD if the XML output of GRASS' parser is extended or modified.
+
+ @param tree root tree node
+ @param task grassTask instance or None
+ @param blackList list of flags/params to hide
+
+ @return grassTask instance
+ """
+ def __init__(self, tree, task = None, blackList = None):
+ if task:
+ self.task = task
+ else:
+ self.task = grassTask()
+ if blackList:
+ self.task.blackList = blackList
+
+ self.root = tree
+
+ self._process_module()
+ self._process_params()
+ self._process_flags()
+ self.task.define_first()
+
+ def _process_module(self):
+ """!Process module description
+ """
+ self.task.name = self.root.get('name', default = 'unknown')
+
+ # keywords
+ for keyword in self._get_node_text(self.root, 'keywords').split(','):
+ self.task.keywords.append(keyword.strip())
+
+ self.task.label = self._get_node_text(self.root, 'label')
+ self.task.description = self._get_node_text(self.root, 'description')
+
+ def _process_params(self):
+ """!Process parameters
+ """
+ for p in self.root.findall('parameter'):
+ # gisprompt
+ node_gisprompt = p.find('gisprompt')
+ gisprompt = False
+ age = element = prompt = None
+ if node_gisprompt is not None:
+ gisprompt = True
+ age = node_gisprompt.get('age', '')
+ element = node_gisprompt.get('element', '')
+ prompt = node_gisprompt.get('prompt', '')
+
+ # value(s)
+ values = []
+ values_desc = []
+ node_values = p.find('values')
+ if node_values is not None:
+ for pv in node_values.findall('value'):
+ values.append(self._get_node_text(pv, 'name'))
+ desc = self._get_node_text(pv, 'description')
+ if desc:
+ values_desc.append(desc)
+
+ # keydesc
+ key_desc = []
+ node_key_desc = p.find('keydesc')
+ if node_key_desc is not None:
+ for ki in node_key_desc.findall('item'):
+ key_desc.append(ki.text)
+
+ if p.get('multiple', 'no') == 'yes':
+ multiple = True
+ else:
+ multiple = False
+ if p.get('required', 'no') == 'yes':
+ required = True
+ else:
+ required = False
+
+ if self.task.blackList['enabled'] and \
+ self.task.name in self.task.blackList['items'] and \
+ p.get('name') in self.task.blackList['items'][self.task.name].get('params', []):
+ hidden = True
+ else:
+ hidden = False
+
+ self.task.params.append( {
+ "name" : p.get('name'),
+ "type" : p.get('type'),
+ "required" : required,
+ "multiple" : multiple,
+ "label" : self._get_node_text(p, 'label'),
+ "description" : self._get_node_text(p, 'description'),
+ 'gisprompt' : gisprompt,
+ 'age' : age,
+ 'element' : element,
+ 'prompt' : prompt,
+ "guisection" : self._get_node_text(p, 'guisection'),
+ "guidependency" : self._get_node_text(p, 'guidependency'),
+ "default" : self._get_node_text(p, 'default'),
+ "values" : values,
+ "values_desc" : values_desc,
+ "value" : '',
+ "key_desc" : key_desc,
+ "hidden" : hidden
+ })
+
+ def _process_flags(self):
+ """!Process flags
+ """
+ for p in self.root.findall('flag'):
+ if self.task.blackList['enabled'] and \
+ self.task.name in self.task.blackList['items'] and \
+ p.get('name') in self.task.blackList['items'][self.task.name].get('flags', []):
+ hidden = True
+ else:
+ hidden = False
+
+ if p.find('suppress_required') is not None:
+ suppress_required = True
+ else:
+ suppress_required = False
+
+ self.task.flags.append( {
+ "name" : p.get('name'),
+ "label" : self._get_node_text(p, 'label'),
+ "description" : self._get_node_text(p, 'description'),
+ "guisection" : self._get_node_text(p, 'guisection'),
+ "suppress_required" : suppress_required,
+ "value" : False,
+ "hidden" : hidden
+ } )
+
+ def _get_node_text(self, node, tag, default = ''):
+ """!Get node text"""
+ p = node.find(tag)
+ if p is not None:
+ return string.join(string.split(p.text), ' ')
+
+ return default
+
+ def get_task(self):
+ """!Get grassTask instance"""
+ return self.task
+
+def get_interface_description(cmd):
+ """!Returns the XML description for the GRASS cmd.
+
+ The DTD must be located in $GISBASE/etc/grass-interface.dtd,
+ otherwise the parser will not succeed.
+
+ @param cmd command (name of GRASS module)
+ """
+ try:
+ p = Popen([cmd, '--interface-description'], stdout = PIPE,
+ stderr = PIPE)
+ cmdout, cmderr = p.communicate()
+
+ # TODO: replace ugly hack bellow
+ if not cmdout and sys.platform == 'win32':
+ if os.path.splitext(cmd)[1] == '':
+ cmd += '.py'
+
+ os.chdir(os.path.join(os.getenv('GISBASE'), 'scripts'))
+ p = Popen([sys.executable, cmd, '--interface-description'],
+ stdout = PIPE, stderr = PIPE)
+ cmdout, cmderr = p.communicate()
+
+ if p.returncode != 0:
+ raise ScriptError, _("Unable to fetch interface description for command '%(cmd)s'."
+ "\n\nDetails: %(det)s") % { 'cmd' : cmd, 'det' : decode(cmderr) }
+
+ except OSError, e:
+ raise ScriptError, _("Unable to fetch interface description for command '%(cmd)s'."
+ "\n\nDetails: %(det)s") % { 'cmd' : cmd, 'det' : e }
+
+ # if cmderr and cmderr[:7] != 'WARNING':
+ # raise ScriptError, _("Unable to fetch interface description for command '%(cmd)s'."
+ # "\n\nDetails: %(det)s") % { 'cmd': cmd, 'det' : decode(cmderr) }
+
+ return cmdout.replace('grass-interface.dtd', os.path.join(os.getenv('GISBASE'), 'etc', 'grass-interface.dtd'))
+
+def parse_interface(name, parser = processTask, blackList = None):
+ """!Parse interface of given GRASS module
+
+ @param name name of GRASS module to be parsed
+ """
+ enc = locale.getdefaultlocale()[1]
+ if enc and enc.lower() == "cp932":
+ p = re.compile('encoding="' + enc + '"', re.IGNORECASE)
+ tree = etree.fromstring(p.sub('encoding="utf-8"',
+ get_interface_description(name).decode(enc).encode("utf-8")))
+ else:
+ tree = etree.fromstring(get_interface_description(name))
+
+ return parser(tree, blackList = blackList).get_task()
+
+def command_info(cmd):
+ """!Returns meta information for any GRASS command as dictionary
+ with entries for description, keywords, usage, flags, and
+ parameters, e.g.
+
+ @code
+ >>> gtask.command_info('g.tempfile')
+
+ {'keywords': ['general', 'map management'],
+ 'params': [{'gisprompt': False, 'multiple': False, 'name': 'pid', 'guidependency': '',
+ 'default': '', 'age': None, 'required': True, 'value': '',
+ 'label': '', 'guisection': '', 'key_desc': [], 'values': [], 'values_desc': [],
+ 'prompt': None, 'hidden': False, 'element': None, 'type': 'integer',
+ 'description': 'Process id to use when naming the tempfile'}],
+ 'flags': [{'description': 'Verbose module output', 'value': False, 'label': '', 'guisection': '',
+ 'suppress_required': False, 'hidden': False, 'name': 'verbose'}, {'description': 'Quiet module output',
+ 'value': False, 'label': '', 'guisection': '', 'suppress_required': False, 'hidden': False, 'name': 'quiet'}],
+ 'description': 'Creates a temporary file and prints the file name.',
+ 'usage': 'g.tempfile pid=integer [--verbose] [--quiet]'
+ }
+
+ >>> gtask.command_info('v.buffer')['keywords']
+
+ ['vector', 'geometry', 'buffer']
+ @endcode
+ """
+ task = parse_interface(cmd)
+ cmdinfo = {}
+
+ cmdinfo['description'] = task.get_description()
+ cmdinfo['keywords'] = task.get_keywords()
+ cmdinfo['flags'] = flags = task.get_options()['flags']
+ cmdinfo['params'] = params = task.get_options()['params']
+
+ usage = task.get_name()
+ flags_short = list()
+ flags_long = list()
+ for f in flags:
+ fname = f.get('name', 'unknown')
+ if len(fname) > 1:
+ flags_long.append(fname)
+ else:
+ flags_short.append(fname)
+
+ if len(flags_short) > 1:
+ usage += ' [-' + ''.join(flags_short) + ']'
+
+ for p in params:
+ ptype = ','.join(p.get('key_desc', []))
+ if not ptype:
+ ptype = p.get('type', '')
+ req = p.get('required', False)
+ if not req:
+ usage += ' ['
+ else:
+ usage += ' '
+ usage += p['name'] + '=' + ptype
+ if p.get('multiple', False):
+ usage += '[,' + ptype + ',...]'
+ if not req:
+ usage += ']'
+
+ for key in flags_long:
+ usage += ' [--' + key + ']'
+
+ cmdinfo['usage'] = usage
+
+ return cmdinfo
Copied: grass/trunk/lib/python/script/vector.py (from rev 54568, grass/trunk/lib/python/vector.py)
===================================================================
--- grass/trunk/lib/python/script/vector.py (rev 0)
+++ grass/trunk/lib/python/script/vector.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -0,0 +1,411 @@
+"""!@package grass.script.vector
+
+ at brief GRASS Python scripting module (vector functions)
+
+Vector related functions to be used in Python scripts.
+
+Usage:
+
+ at code
+from grass.script import vector as grass
+
+grass.vector_db(map)
+...
+ at endcode
+
+(C) 2008-2010 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Glynn Clements
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import types
+import copy
+import __builtin__
+
+from core import *
+
+# run "v.db.connect -g ..." and parse output
+
+def vector_db(map, **args):
+ """!Return the database connection details for a vector map
+ (interface to `v.db.connect -g'). Example:
+
+ \code
+ >>> grass.vector_db('lakes')
+ {1: {'layer': 1, 'name': '',
+ 'database': '/home/martin/grassdata/nc_spm_08/PERMANENT/dbf/',
+ 'driver': 'dbf', 'key': 'cat', 'table': 'lakes'}}
+ \endcode
+
+ @param map vector map
+ @param args other v.db.connect's arguments
+
+ @return dictionary
+ """
+ s = read_command('v.db.connect', quiet = True, flags = 'g', map = map, sep = ';', **args)
+ result = {}
+
+ for l in s.splitlines():
+ f = l.split(';')
+ if len(f) != 5:
+ continue
+
+ if '/' in f[0]:
+ f1 = f[0].split('/')
+ layer = f1[0]
+ name = f1[1]
+ else:
+ layer = f[0]
+ name = ''
+
+ result[int(layer)] = {
+ 'layer' : int(layer),
+ 'name' : name,
+ 'table' : f[1],
+ 'key' : f[2],
+ 'database' : f[3],
+ 'driver' : f[4] }
+
+ return result
+
+def vector_layer_db(map, layer):
+ """!Return the database connection details for a vector map layer.
+ If db connection for given layer is not defined, fatal() is called.
+
+ @param map map name
+ @param layer layer number
+
+ @return parsed output
+ """
+ try:
+ f = vector_db(map)[int(layer)]
+ except KeyError:
+ fatal(_("Database connection not defined for layer %s") % layer)
+
+ return f
+
+# run "v.info -c ..." and parse output
+
+def vector_columns(map, layer = None, getDict = True, **args):
+ """!Return a dictionary (or a list) of the columns for the
+ database table connected to a vector map (interface to `v.info
+ -c').
+
+ @code
+ >>> vector_columns(urbanarea, getDict = True)
+ {'UA_TYPE': {'index': 4, 'type': 'CHARACTER'}, 'UA': {'index': 2, 'type': 'CHARACTER'}, 'NAME': {'index': 3, 'type': 'CHARACTER'}, 'OBJECTID': {'index': 1, 'type': 'INTEGER'}, 'cat': {'index': 0, 'type': 'INTEGER'}}
+
+ >>> vector_columns(urbanarea, getDict = False)
+ ['cat', 'OBJECTID', 'UA', 'NAME', 'UA_TYPE']
+ @endcode
+
+ @param map map name
+ @param layer layer number or name (None for all layers)
+ @param getDict True to return dictionary of columns otherwise list of column names is returned
+ @param args (v.info's arguments)
+
+ @return dictionary/list of columns
+ """
+ s = read_command('v.info', flags = 'c', map = map, layer = layer, quiet = True, **args)
+ if getDict:
+ result = dict()
+ else:
+ result = list()
+ i = 0
+ for line in s.splitlines():
+ ctype, cname = line.split('|')
+ if getDict:
+ result[cname] = { 'type' : ctype,
+ 'index' : i }
+ else:
+ result.append(cname)
+ i+=1
+
+ return result
+
+# add vector history
+
+def vector_history(map):
+ """!Set the command history for a vector map to the command used to
+ invoke the script (interface to `v.support').
+
+ @param map mapname
+
+ @return v.support output
+ """
+ run_command('v.support', map = map, cmdhist = os.environ['CMDLINE'])
+
+# run "v.info -t" and parse output
+
+def vector_info_topo(map):
+ """!Return information about a vector map (interface to `v.info
+ -t'). Example:
+
+ \code
+ >>> grass.vector_info_topo('lakes')
+ {'kernels': 0, 'lines': 0, 'centroids': 15279,
+ 'boundaries': 27764, 'points': 0, 'faces': 0,
+ 'primitives': 43043, 'islands': 7470, 'nodes': 35234, 'map3d': False, 'areas': 15279}
+ \endcode
+
+ @param map map name
+
+ @return parsed output
+ """
+ s = read_command('v.info', flags = 't', map = map)
+ ret = parse_key_val(s, val_type = int)
+ if 'map3d' in ret:
+ ret['map3d'] = bool(ret['map3d'])
+
+ return ret
+
+
+# run "v.info -get ..." and parse output
+
+def vector_info(map):
+ """!Return information about a vector map (interface to
+ `v.info'). Example:
+
+ \code
+ >>> grass.vector_info('random_points')
+ {'comment': '', 'projection': 'x,y', 'creator': 'soeren', 'holes': 0,
+ 'primitives': 20, 'kernels': 0, 'scale': '1:1', 'title': '',
+ 'west': 0.046125489999999998, 'top': 2376.133159, 'boundaries': 0,
+ 'location': 'XYLocation', 'nodes': 0, 'east': 0.97305646000000001,
+ 'source_date': 'Mon Aug 29 10:55:57 2011', 'north': 0.9589993,
+ 'format': 'native', 'faces': 0, 'centroids': 0,
+ 'digitization_threshold': '0.000000', 'islands': 0, 'level': 2,
+ 'mapset': 'test', 'areas': 0, 'name': 'random_points',
+ 'database': '/home/soeren/grassdata', 'bottom': 22.186596999999999,
+ 'lines': 0, 'points': 20, 'map3d': True, 'volumes': 0, 'num_dblinks': 0,
+ 'organization': '', 'south': 0.066047099999999997}
+
+ \endcode
+ @param map map name
+
+ @return parsed vector info
+ """
+
+ s = read_command('v.info', flags = 'get', map = map)
+
+ kv = parse_key_val(s)
+ for k in ['north', 'south', 'east', 'west', 'top', 'bottom']:
+ kv[k] = float(kv[k])
+ for k in ['level', 'num_dblinks']:
+ kv[k] = int(kv[k])
+ for k in ['nodes', 'points', 'lines', 'boundaries', 'centroids', 'areas', 'islands', 'primitives']:
+ kv[k] = int(kv[k])
+ if 'map3d' in kv:
+ kv['map3d'] = bool(int(kv['map3d']))
+ if kv['map3d']:
+ for k in ['faces', 'kernels', 'volumes', 'holes']:
+ kv[k] = int(kv[k])
+
+ return kv
+
+
+# interface for v.db.select
+
+def vector_db_select(map, layer = 1, **kwargs):
+ """!Get attribute data of selected vector map layer.
+
+ Function returns list of columns and dictionary of values ordered by
+ key column value. Example:
+
+ \code
+ >>> print grass.vector_db_select('lakes')['columns']
+ ['cat', 'AREA', 'PERIMETER', 'FULL_HYDRO', 'FULL_HYDR2', 'FTYPE', 'FCODE', 'NAME']
+ >>> print grass.vector_db_select('lakes')['values'][3]
+ ['3', '19512.86146', '708.44683', '4', '55652', 'LAKE/POND', '39000', '']
+ >>> print grass.vector_db_select('lakes', columns = 'FTYPE')['values'][3]
+ ['LAKE/POND']
+ \endcode
+
+ @param map map name
+ @param layer layer number
+ @param kwargs v.db.select options
+
+ @return dictionary ('columns' and 'values')
+ """
+ try:
+ key = vector_db(map = map)[layer]['key']
+ except KeyError:
+ error(_('Missing layer %(layer)d in vector map <%(map)s>') % \
+ { 'layer' : layer, 'map' : map })
+ return { 'columns' : [], 'values' : {} }
+
+ if 'columns' in kwargs:
+ if key not in kwargs['columns'].split(','):
+ # add key column if missing
+ debug("Adding key column to the output")
+ kwargs['columns'] += ',' + key
+
+ ret = read_command('v.db.select',
+ map = map,
+ layer = layer,
+ **kwargs)
+
+ if not ret:
+ error(_('vector_db_select() failed'))
+ return { 'columns' : [], 'values' : {} }
+
+ columns = []
+ values = {}
+ for line in ret.splitlines():
+ if not columns:
+ columns = line.split('|')
+ key_index = columns.index(key)
+ continue
+
+ value = line.split('|')
+ key_value = int(value[key_index])
+ values[key_value] = line.split('|')
+
+ return { 'columns' : columns,
+ 'values' : values }
+
+# interface to v.what
+def vector_what(map, coord, distance = 0.0, ttype = None):
+ """!Query vector map at given locations
+
+ To query one vector map at one location
+ @code
+ print grass.vector_what(map = 'archsites', coord = (595743, 4925281), distance = 250)
+
+ [{'Category': 8, 'Map': 'archsites', 'Layer': 1, 'Key_column': 'cat',
+ 'Database': '/home/martin/grassdata/spearfish60/PERMANENT/dbf/',
+ 'Mapset': 'PERMANENT', 'Driver': 'dbf',
+ 'Attributes': {'str1': 'No_Name', 'cat': '8'},
+ 'Table': 'archsites', 'Type': 'Point', 'Id': 8}]
+ @endcode
+
+ To query one vector map with multiple layers (no additional parameters required)
+ @code
+ for q in grass.vector_what(map = 'some_map', coord = (596532.357143,4920486.21429), distance = 100.0):
+ print q['Map'], q['Layer'], q['Attributes']
+
+ new_bug_sites 1 {'str1': 'Beetle_site', 'GRASSRGB': '', 'cat': '80'}
+ new_bug_sites 2 {'cat': '80'}
+ @endcode
+
+ To query more vector maps at one location
+ @code
+ for q in grass.vector_what(map = ('archsites', 'roads'), coord = (595743, 4925281),
+ distance = 250):
+ print q['Map'], q['Attributes']
+
+ archsites {'str1': 'No_Name', 'cat': '8'}
+ roads {'label': 'interstate', 'cat': '1'}
+ @endcode
+
+ To query one vector map at more locations
+ @code
+ for q in grass.vector_what(map = 'archsites', coord = [(595743, 4925281), (597950, 4918898)],
+ distance = 250):
+ print q['Map'], q['Attributes']
+
+ archsites {'str1': 'No_Name', 'cat': '8'}
+ archsites {'str1': 'Bob_Miller', 'cat': '22'}
+ @endcode
+
+ @param map vector map(s) to query given as string or list/tuple
+ @param coord coordinates of query given as tuple (easting, northing) or list of tuples
+ @param distance query threshold distance (in map units)
+ @param ttype list of topology types (default of v.what are point, line, area, face)
+
+ @return parsed list
+ """
+ if "LC_ALL" in os.environ:
+ locale = os.environ["LC_ALL"]
+ os.environ["LC_ALL"] = "C"
+
+ if type(map) in (types.StringType, types.UnicodeType):
+ map_list = [map]
+ else:
+ map_list = map
+
+ layer_list = ['-1'] * len(map_list)
+
+ coord_list = list()
+ if type(coord) is types.TupleType:
+ coord_list.append('%f,%f' % (coord[0], coord[1]))
+ else:
+ for e, n in coord:
+ coord_list.append('%f,%f' % (e, n))
+
+ cmdParams = dict(quiet = True,
+ flags = 'ag',
+ map = ','.join(map_list),
+ layer = ','.join(layer_list),
+ coordinates = ','.join(coord_list),
+ distance = float(distance))
+ if ttype:
+ cmdParams['type'] = ','.join(ttype)
+
+ ret = read_command('v.what',
+ **cmdParams)
+
+ if "LC_ALL" in os.environ:
+ os.environ["LC_ALL"] = locale
+
+ data = list()
+ if not ret:
+ return data
+
+ dict_attrb = None
+ dict_map = None
+ dict_layer = None
+ attr_pseudo_key = 'Attributes'
+ for item in ret.splitlines():
+ try:
+ key, value = __builtin__.map(lambda x: x.strip(), item.split('=', 1))
+ except ValueError:
+ continue
+ if key in ('East', 'North'):
+ continue
+
+ if key == 'Map':
+ # attach the last one from the previous map
+ if dict_layer is not None:
+ dict_main = copy.copy(dict_map)
+ dict_main.update(dict_layer)
+ data.append(dict_main)
+ dict_map = { key : value }
+ dict_layer = None
+ dict_attrb = None
+ elif key == 'Layer':
+ # attach the last the previous Layer
+ if dict_layer is not None:
+ dict_main = copy.copy(dict_map)
+ dict_main.update(dict_layer)
+ data.append(dict_main)
+ dict_layer = { key: int(value) }
+ dict_attrb = None
+ elif key == 'Key_column':
+ dict_layer[key] = value
+ dict_attrb = dict()
+ dict_layer[attr_pseudo_key] = dict_attrb
+ elif dict_attrb is not None:
+ dict_attrb[key] = value
+ elif dict_layer is not None:
+ if key == 'Category':
+ dict_layer[key] = int(value)
+ else:
+ dict_layer[key] = value
+ else:
+ dict_map[key] = value
+ # TODO: there are some keys which has non-string values
+ # examples: Sq_Meters, Hectares, Acres, Sq_Miles
+
+ # attach the last one
+ if dict_layer is not None:
+ dict_main = copy.copy(dict_map)
+ dict_main.update(dict_layer)
+ data.append(dict_main)
+
+ return data
Deleted: grass/trunk/lib/python/setup.py.sed
===================================================================
--- grass/trunk/lib/python/setup.py.sed 2013-01-08 08:35:23 UTC (rev 54568)
+++ grass/trunk/lib/python/setup.py.sed 2013-01-08 09:34:42 UTC (rev 54569)
@@ -1,71 +0,0 @@
-"""!@package grass.script.setup
-
- at brief GRASS Python scripting module (setup)
-
-Setup functions to be used in Python scripts.
-
-Usage:
-
- at code
-from grass.script import setup as grass
-
-grass.init()
-...
- at endcode
-
-(C) 2010-2012 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import sys
-import tempfile as tmpfile
-
-def init(gisbase, dbase = '', location = 'demolocation', mapset = 'PERMANENT'):
- """!Initialize system variables to run scripts without starting
- GRASS explicitly.
-
- User is resposible to delete gisrc file.
-
- @param gisbase path to GRASS installation
- @param dbase path to GRASS database (default: '')
- @param location location name (default: 'demolocation')
- @param mapset mapset within given location (default: 'PERMANENT')
- @return path to gisrc file
- """
- # define PATH
- os.environ['PATH'] += os.pathsep + os.path.join(gisbase, 'bin')
- os.environ['PATH'] += os.pathsep + os.path.join(gisbase, 'scripts')
- if sys.platform.startswith('win'): # added for winGRASS
- os.environ['PATH'] += os.pathsep + os.path.join(gisbase, 'extralib')
- # define LD_LIBRARY_PATH
- if '@LD_LIBRARY_PATH_VAR@' not in os.environ:
- os.environ['@LD_LIBRARY_PATH_VAR@'] = ''
- os.environ['@LD_LIBRARY_PATH_VAR@'] += os.pathsep + os.path.join(gisbase, 'lib')
-
- os.environ['GIS_LOCK'] = str(os.getpid())
-
- # Set PYTHONPATH to find GRASS Python modules
- path = os.getenv('PYTHONPATH')
- dir = os.path.join(gisbase, 'etc', 'python')
- if path:
- path = dir + os.pathsep + path
- else:
- path = dir
- os.environ['PYTHONPATH'] = path
-
- if not dbase:
- dbase = gisbase
-
- fd, gisrc = tmpfile.mkstemp()
- os.environ['GISRC'] = gisrc
- os.write(fd, "GISDBASE: %s\n" % dbase)
- os.write(fd, "LOCATION_NAME: %s\n" % location)
- os.write(fd, "MAPSET: %s\n" % mapset)
- os.close(fd)
-
- return gisrc
Deleted: grass/trunk/lib/python/task.py
===================================================================
--- grass/trunk/lib/python/task.py 2013-01-08 08:35:23 UTC (rev 54568)
+++ grass/trunk/lib/python/task.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -1,555 +0,0 @@
-"""!@package grass.script.task
-
- at brief GRASS Python scripting module (task)
-
-Get interface description of GRASS commands
-
-Based on gui/wxpython/gui_modules/menuform.py
-
-Usage:
-
- at code
-from grass.script import task as gtask
-
-gtask.command_info('r.info')
-...
- at endcode
-
-(C) 2011 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import types
-import string
-try:
- import xml.etree.ElementTree as etree
-except ImportError:
- import elementtree.ElementTree as etree # Python <= 2.4
-
-from core import *
-
-class grassTask:
- """!This class holds the structures needed for filling by the
- parser
-
- Parameter blackList is a dictionary with fixed structure, eg.
-
- @code
- blackList = {'items' : {'d.legend' : { 'flags' : ['m'],
- 'params' : [] }},
- 'enabled': True}
- @endcode
-
- @param path full path
- @param blackList hide some options in the GUI (dictionary)
- """
- def __init__(self, path = None, blackList = None):
- self.path = path
- self.name = _('unknown')
- self.params = list()
- self.description = ''
- self.label = ''
- self.flags = list()
- self.keywords = list()
- self.errorMsg = ''
- self.firstParam = None
- if blackList:
- self.blackList = blackList
- else:
- self.blackList = { 'enabled' : False, 'items' : {} }
-
- if path is not None:
- try:
- processTask(tree = etree.fromstring(get_interface_description(path)),
- task = self)
- except ScriptError, e:
- self.errorMsg = e.value
-
- self.define_first()
-
- def define_first(self):
- """!Define first parameter
-
- @return name of first parameter
- """
- if len(self.params) > 0:
- self.firstParam = self.params[0]['name']
-
- return self.firstParam
-
- def get_error_msg(self):
- """!Get error message ('' for no error)
- """
- return self.errorMsg
-
- def get_name(self):
- """!Get task name
- """
- if sys.platform == 'win32':
- name, ext = os.path.splitext(self.name)
- if ext in ('.py', '.sh'):
- return name
- else:
- return self.name
-
- return self.name
-
- def get_description(self, full = True):
- """!Get module's description
-
- @param full True for label + desc
- """
- if self.label:
- if full:
- return self.label + ' ' + self.description
- else:
- return self.label
- else:
- return self.description
-
- def get_keywords(self):
- """!Get module's keywords
- """
- return self.keywords
-
- def get_list_params(self, element = 'name'):
- """!Get list of parameters
-
- @param element element name
- """
- params = []
- for p in self.params:
- params.append(p[element])
-
- return params
-
- def get_list_flags(self, element = 'name'):
- """!Get list of flags
-
- @param element element name
- """
- flags = []
- for p in self.flags:
- flags.append(p[element])
-
- return flags
-
- def get_param(self, value, element = 'name', raiseError = True):
- """!Find and return a param by name
-
- @param value param's value
- @param element element name
- @param raiseError True for raise on error
- """
- try:
- for p in self.params:
- val = p[element]
- if val is None:
- continue
- if type(val) in (types.ListType, types.TupleType):
- if value in val:
- return p
- elif type(val) == types.StringType:
- if p[element][:len(value)] == value:
- return p
- else:
- if p[element] == value:
- return p
- except KeyError:
- pass
-
- if raiseError:
- raise ValueError, _("Parameter element '%(element)s' not found: '%(value)s'") % \
- { 'element' : element, 'value' : value }
- else:
- return None
-
- def get_flag(self, aFlag):
- """!Find and return a flag by name
-
- Raises ValueError when the flag is not found.
-
- @param aFlag name of the flag
- """
- for f in self.flags:
- if f['name'] == aFlag:
- return f
- raise ValueError, _("Flag not found: %s") % aFlag
-
- def get_cmd_error(self):
- """!Get error string produced by get_cmd(ignoreErrors = False)
-
- @return list of errors
- """
- errorList = list()
- # determine if suppress_required flag is given
- for f in self.flags:
- if f['value'] and f['suppress_required']:
- return errorList
-
- for p in self.params:
- if not p.get('value', '') and p.get('required', False):
- if not p.get('default', ''):
- desc = p.get('label', '')
- if not desc:
- desc = p['description']
- errorList.append(_("Parameter '%(name)s' (%(desc)s) is missing.") % \
- {'name' : p['name'], 'desc' : desc })
-
- return errorList
-
- def get_cmd(self, ignoreErrors = False, ignoreRequired = False, ignoreDefault = True):
- """!Produce an array of command name and arguments for feeding
- into some execve-like command processor.
-
- @param ignoreErrors True to return whatever has been built so
- far, even though it would not be a correct command for GRASS
- @param ignoreRequired True to ignore required flags, otherwise
- '@<required@>' is shown
- @param ignoreDefault True to ignore parameters with default values
- """
- cmd = [self.get_name()]
-
- suppress_required = False
- for flag in self.flags:
- if flag['value']:
- if len(flag['name']) > 1: # e.g. overwrite
- cmd += [ '--' + flag['name'] ]
- else:
- cmd += [ '-' + flag['name'] ]
- if flag['suppress_required']:
- suppress_required = True
- for p in self.params:
- if p.get('value', '') == '' and p.get('required', False):
- if p.get('default', '') != '':
- cmd += [ '%s=%s' % (p['name'], p['default']) ]
- elif ignoreErrors and not suppress_required and not ignoreRequired:
- cmd += [ '%s=%s' % (p['name'], _('<required>')) ]
- elif p.get('value', '') == '' and p.get('default', '') != '' and not ignoreDefault:
- cmd += [ '%s=%s' % (p['name'], p['default']) ]
- elif p.get('value', '') != '' and \
- (p['value'] != p.get('default', '') or not ignoreDefault):
- # output only values that have been set, and different from defaults
- cmd += [ '%s=%s' % (p['name'], p['value']) ]
-
- errList = self.get_cmd_error()
- if ignoreErrors is False and errList:
- raise ValueError, '\n'.join(errList)
-
- return cmd
-
- def get_options(self):
- """!Get options
- """
- return { 'flags' : self.flags,
- 'params' : self.params }
-
- def has_required(self):
- """!Check if command has at least one required paramater
- """
- for p in self.params:
- if p.get('required', False):
- return True
-
- return False
-
- def set_param(self, aParam, aValue, element = 'value'):
- """!Set param value/values.
- """
- try:
- param = self.get_param(aParam)
- except ValueError:
- return
-
- param[element] = aValue
-
- def set_flag(self, aFlag, aValue, element = 'value'):
- """!Enable / disable flag.
- """
- try:
- param = self.get_flag(aFlag)
- except ValueError:
- return
-
- param[element] = aValue
-
- def set_options(self, opts):
- """!Set flags and parameters
-
- @param opts list of flags and parameters"""
- for opt in opts:
- if opt[0] == '-': # flag
- self.set_flag(opt.lstrip('-'), True)
- else: # parameter
- key, value = opt.split('=', 1)
- self.set_param(key, value)
-
-class processTask:
- """!A ElementTree handler for the --interface-description output,
- as defined in grass-interface.dtd. Extend or modify this and the
- DTD if the XML output of GRASS' parser is extended or modified.
-
- @param tree root tree node
- @param task grassTask instance or None
- @param blackList list of flags/params to hide
-
- @return grassTask instance
- """
- def __init__(self, tree, task = None, blackList = None):
- if task:
- self.task = task
- else:
- self.task = grassTask()
- if blackList:
- self.task.blackList = blackList
-
- self.root = tree
-
- self._process_module()
- self._process_params()
- self._process_flags()
- self.task.define_first()
-
- def _process_module(self):
- """!Process module description
- """
- self.task.name = self.root.get('name', default = 'unknown')
-
- # keywords
- for keyword in self._get_node_text(self.root, 'keywords').split(','):
- self.task.keywords.append(keyword.strip())
-
- self.task.label = self._get_node_text(self.root, 'label')
- self.task.description = self._get_node_text(self.root, 'description')
-
- def _process_params(self):
- """!Process parameters
- """
- for p in self.root.findall('parameter'):
- # gisprompt
- node_gisprompt = p.find('gisprompt')
- gisprompt = False
- age = element = prompt = None
- if node_gisprompt is not None:
- gisprompt = True
- age = node_gisprompt.get('age', '')
- element = node_gisprompt.get('element', '')
- prompt = node_gisprompt.get('prompt', '')
-
- # value(s)
- values = []
- values_desc = []
- node_values = p.find('values')
- if node_values is not None:
- for pv in node_values.findall('value'):
- values.append(self._get_node_text(pv, 'name'))
- desc = self._get_node_text(pv, 'description')
- if desc:
- values_desc.append(desc)
-
- # keydesc
- key_desc = []
- node_key_desc = p.find('keydesc')
- if node_key_desc is not None:
- for ki in node_key_desc.findall('item'):
- key_desc.append(ki.text)
-
- if p.get('multiple', 'no') == 'yes':
- multiple = True
- else:
- multiple = False
- if p.get('required', 'no') == 'yes':
- required = True
- else:
- required = False
-
- if self.task.blackList['enabled'] and \
- self.task.name in self.task.blackList['items'] and \
- p.get('name') in self.task.blackList['items'][self.task.name].get('params', []):
- hidden = True
- else:
- hidden = False
-
- self.task.params.append( {
- "name" : p.get('name'),
- "type" : p.get('type'),
- "required" : required,
- "multiple" : multiple,
- "label" : self._get_node_text(p, 'label'),
- "description" : self._get_node_text(p, 'description'),
- 'gisprompt' : gisprompt,
- 'age' : age,
- 'element' : element,
- 'prompt' : prompt,
- "guisection" : self._get_node_text(p, 'guisection'),
- "guidependency" : self._get_node_text(p, 'guidependency'),
- "default" : self._get_node_text(p, 'default'),
- "values" : values,
- "values_desc" : values_desc,
- "value" : '',
- "key_desc" : key_desc,
- "hidden" : hidden
- })
-
- def _process_flags(self):
- """!Process flags
- """
- for p in self.root.findall('flag'):
- if self.task.blackList['enabled'] and \
- self.task.name in self.task.blackList['items'] and \
- p.get('name') in self.task.blackList['items'][self.task.name].get('flags', []):
- hidden = True
- else:
- hidden = False
-
- if p.find('suppress_required') is not None:
- suppress_required = True
- else:
- suppress_required = False
-
- self.task.flags.append( {
- "name" : p.get('name'),
- "label" : self._get_node_text(p, 'label'),
- "description" : self._get_node_text(p, 'description'),
- "guisection" : self._get_node_text(p, 'guisection'),
- "suppress_required" : suppress_required,
- "value" : False,
- "hidden" : hidden
- } )
-
- def _get_node_text(self, node, tag, default = ''):
- """!Get node text"""
- p = node.find(tag)
- if p is not None:
- return string.join(string.split(p.text), ' ')
-
- return default
-
- def get_task(self):
- """!Get grassTask instance"""
- return self.task
-
-def get_interface_description(cmd):
- """!Returns the XML description for the GRASS cmd.
-
- The DTD must be located in $GISBASE/etc/grass-interface.dtd,
- otherwise the parser will not succeed.
-
- @param cmd command (name of GRASS module)
- """
- try:
- p = Popen([cmd, '--interface-description'], stdout = PIPE,
- stderr = PIPE)
- cmdout, cmderr = p.communicate()
-
- # TODO: replace ugly hack bellow
- if not cmdout and sys.platform == 'win32':
- if os.path.splitext(cmd)[1] == '':
- cmd += '.py'
-
- os.chdir(os.path.join(os.getenv('GISBASE'), 'scripts'))
- p = Popen([sys.executable, cmd, '--interface-description'],
- stdout = PIPE, stderr = PIPE)
- cmdout, cmderr = p.communicate()
-
- if p.returncode != 0:
- raise ScriptError, _("Unable to fetch interface description for command '%(cmd)s'."
- "\n\nDetails: %(det)s") % { 'cmd' : cmd, 'det' : decode(cmderr) }
-
- except OSError, e:
- raise ScriptError, _("Unable to fetch interface description for command '%(cmd)s'."
- "\n\nDetails: %(det)s") % { 'cmd' : cmd, 'det' : e }
-
- # if cmderr and cmderr[:7] != 'WARNING':
- # raise ScriptError, _("Unable to fetch interface description for command '%(cmd)s'."
- # "\n\nDetails: %(det)s") % { 'cmd': cmd, 'det' : decode(cmderr) }
-
- return cmdout.replace('grass-interface.dtd', os.path.join(os.getenv('GISBASE'), 'etc', 'grass-interface.dtd'))
-
-def parse_interface(name, parser = processTask, blackList = None):
- """!Parse interface of given GRASS module
-
- @param name name of GRASS module to be parsed
- """
- enc = locale.getdefaultlocale()[1]
- if enc and enc.lower() == "cp932":
- p = re.compile('encoding="' + enc + '"', re.IGNORECASE)
- tree = etree.fromstring(p.sub('encoding="utf-8"',
- get_interface_description(name).decode(enc).encode("utf-8")))
- else:
- tree = etree.fromstring(get_interface_description(name))
-
- return parser(tree, blackList = blackList).get_task()
-
-def command_info(cmd):
- """!Returns meta information for any GRASS command as dictionary
- with entries for description, keywords, usage, flags, and
- parameters, e.g.
-
- @code
- >>> gtask.command_info('g.tempfile')
-
- {'keywords': ['general', 'map management'],
- 'params': [{'gisprompt': False, 'multiple': False, 'name': 'pid', 'guidependency': '',
- 'default': '', 'age': None, 'required': True, 'value': '',
- 'label': '', 'guisection': '', 'key_desc': [], 'values': [], 'values_desc': [],
- 'prompt': None, 'hidden': False, 'element': None, 'type': 'integer',
- 'description': 'Process id to use when naming the tempfile'}],
- 'flags': [{'description': 'Verbose module output', 'value': False, 'label': '', 'guisection': '',
- 'suppress_required': False, 'hidden': False, 'name': 'verbose'}, {'description': 'Quiet module output',
- 'value': False, 'label': '', 'guisection': '', 'suppress_required': False, 'hidden': False, 'name': 'quiet'}],
- 'description': 'Creates a temporary file and prints the file name.',
- 'usage': 'g.tempfile pid=integer [--verbose] [--quiet]'
- }
-
- >>> gtask.command_info('v.buffer')['keywords']
-
- ['vector', 'geometry', 'buffer']
- @endcode
- """
- task = parse_interface(cmd)
- cmdinfo = {}
-
- cmdinfo['description'] = task.get_description()
- cmdinfo['keywords'] = task.get_keywords()
- cmdinfo['flags'] = flags = task.get_options()['flags']
- cmdinfo['params'] = params = task.get_options()['params']
-
- usage = task.get_name()
- flags_short = list()
- flags_long = list()
- for f in flags:
- fname = f.get('name', 'unknown')
- if len(fname) > 1:
- flags_long.append(fname)
- else:
- flags_short.append(fname)
-
- if len(flags_short) > 1:
- usage += ' [-' + ''.join(flags_short) + ']'
-
- for p in params:
- ptype = ','.join(p.get('key_desc', []))
- if not ptype:
- ptype = p.get('type', '')
- req = p.get('required', False)
- if not req:
- usage += ' ['
- else:
- usage += ' '
- usage += p['name'] + '=' + ptype
- if p.get('multiple', False):
- usage += '[,' + ptype + ',...]'
- if not req:
- usage += ']'
-
- for key in flags_long:
- usage += ' [--' + key + ']'
-
- cmdinfo['usage'] = usage
-
- return cmdinfo
Deleted: grass/trunk/lib/python/vector.py
===================================================================
--- grass/trunk/lib/python/vector.py 2013-01-08 08:35:23 UTC (rev 54568)
+++ grass/trunk/lib/python/vector.py 2013-01-08 09:34:42 UTC (rev 54569)
@@ -1,411 +0,0 @@
-"""!@package grass.script.vector
-
- at brief GRASS Python scripting module (vector functions)
-
-Vector related functions to be used in Python scripts.
-
-Usage:
-
- at code
-from grass.script import vector as grass
-
-grass.vector_db(map)
-...
- at endcode
-
-(C) 2008-2010 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
-
- at author Glynn Clements
- at author Martin Landa <landa.martin gmail.com>
-"""
-
-import os
-import types
-import copy
-import __builtin__
-
-from core import *
-
-# run "v.db.connect -g ..." and parse output
-
-def vector_db(map, **args):
- """!Return the database connection details for a vector map
- (interface to `v.db.connect -g'). Example:
-
- \code
- >>> grass.vector_db('lakes')
- {1: {'layer': 1, 'name': '',
- 'database': '/home/martin/grassdata/nc_spm_08/PERMANENT/dbf/',
- 'driver': 'dbf', 'key': 'cat', 'table': 'lakes'}}
- \endcode
-
- @param map vector map
- @param args other v.db.connect's arguments
-
- @return dictionary
- """
- s = read_command('v.db.connect', quiet = True, flags = 'g', map = map, sep = ';', **args)
- result = {}
-
- for l in s.splitlines():
- f = l.split(';')
- if len(f) != 5:
- continue
-
- if '/' in f[0]:
- f1 = f[0].split('/')
- layer = f1[0]
- name = f1[1]
- else:
- layer = f[0]
- name = ''
-
- result[int(layer)] = {
- 'layer' : int(layer),
- 'name' : name,
- 'table' : f[1],
- 'key' : f[2],
- 'database' : f[3],
- 'driver' : f[4] }
-
- return result
-
-def vector_layer_db(map, layer):
- """!Return the database connection details for a vector map layer.
- If db connection for given layer is not defined, fatal() is called.
-
- @param map map name
- @param layer layer number
-
- @return parsed output
- """
- try:
- f = vector_db(map)[int(layer)]
- except KeyError:
- fatal(_("Database connection not defined for layer %s") % layer)
-
- return f
-
-# run "v.info -c ..." and parse output
-
-def vector_columns(map, layer = None, getDict = True, **args):
- """!Return a dictionary (or a list) of the columns for the
- database table connected to a vector map (interface to `v.info
- -c').
-
- @code
- >>> vector_columns(urbanarea, getDict = True)
- {'UA_TYPE': {'index': 4, 'type': 'CHARACTER'}, 'UA': {'index': 2, 'type': 'CHARACTER'}, 'NAME': {'index': 3, 'type': 'CHARACTER'}, 'OBJECTID': {'index': 1, 'type': 'INTEGER'}, 'cat': {'index': 0, 'type': 'INTEGER'}}
-
- >>> vector_columns(urbanarea, getDict = False)
- ['cat', 'OBJECTID', 'UA', 'NAME', 'UA_TYPE']
- @endcode
-
- @param map map name
- @param layer layer number or name (None for all layers)
- @param getDict True to return dictionary of columns otherwise list of column names is returned
- @param args (v.info's arguments)
-
- @return dictionary/list of columns
- """
- s = read_command('v.info', flags = 'c', map = map, layer = layer, quiet = True, **args)
- if getDict:
- result = dict()
- else:
- result = list()
- i = 0
- for line in s.splitlines():
- ctype, cname = line.split('|')
- if getDict:
- result[cname] = { 'type' : ctype,
- 'index' : i }
- else:
- result.append(cname)
- i+=1
-
- return result
-
-# add vector history
-
-def vector_history(map):
- """!Set the command history for a vector map to the command used to
- invoke the script (interface to `v.support').
-
- @param map mapname
-
- @return v.support output
- """
- run_command('v.support', map = map, cmdhist = os.environ['CMDLINE'])
-
-# run "v.info -t" and parse output
-
-def vector_info_topo(map):
- """!Return information about a vector map (interface to `v.info
- -t'). Example:
-
- \code
- >>> grass.vector_info_topo('lakes')
- {'kernels': 0, 'lines': 0, 'centroids': 15279,
- 'boundaries': 27764, 'points': 0, 'faces': 0,
- 'primitives': 43043, 'islands': 7470, 'nodes': 35234, 'map3d': False, 'areas': 15279}
- \endcode
-
- @param map map name
-
- @return parsed output
- """
- s = read_command('v.info', flags = 't', map = map)
- ret = parse_key_val(s, val_type = int)
- if 'map3d' in ret:
- ret['map3d'] = bool(ret['map3d'])
-
- return ret
-
-
-# run "v.info -get ..." and parse output
-
-def vector_info(map):
- """!Return information about a vector map (interface to
- `v.info'). Example:
-
- \code
- >>> grass.vector_info('random_points')
- {'comment': '', 'projection': 'x,y', 'creator': 'soeren', 'holes': 0,
- 'primitives': 20, 'kernels': 0, 'scale': '1:1', 'title': '',
- 'west': 0.046125489999999998, 'top': 2376.133159, 'boundaries': 0,
- 'location': 'XYLocation', 'nodes': 0, 'east': 0.97305646000000001,
- 'source_date': 'Mon Aug 29 10:55:57 2011', 'north': 0.9589993,
- 'format': 'native', 'faces': 0, 'centroids': 0,
- 'digitization_threshold': '0.000000', 'islands': 0, 'level': 2,
- 'mapset': 'test', 'areas': 0, 'name': 'random_points',
- 'database': '/home/soeren/grassdata', 'bottom': 22.186596999999999,
- 'lines': 0, 'points': 20, 'map3d': True, 'volumes': 0, 'num_dblinks': 0,
- 'organization': '', 'south': 0.066047099999999997}
-
- \endcode
- @param map map name
-
- @return parsed vector info
- """
-
- s = read_command('v.info', flags = 'get', map = map)
-
- kv = parse_key_val(s)
- for k in ['north', 'south', 'east', 'west', 'top', 'bottom']:
- kv[k] = float(kv[k])
- for k in ['level', 'num_dblinks']:
- kv[k] = int(kv[k])
- for k in ['nodes', 'points', 'lines', 'boundaries', 'centroids', 'areas', 'islands', 'primitives']:
- kv[k] = int(kv[k])
- if 'map3d' in kv:
- kv['map3d'] = bool(int(kv['map3d']))
- if kv['map3d']:
- for k in ['faces', 'kernels', 'volumes', 'holes']:
- kv[k] = int(kv[k])
-
- return kv
-
-
-# interface for v.db.select
-
-def vector_db_select(map, layer = 1, **kwargs):
- """!Get attribute data of selected vector map layer.
-
- Function returns list of columns and dictionary of values ordered by
- key column value. Example:
-
- \code
- >>> print grass.vector_db_select('lakes')['columns']
- ['cat', 'AREA', 'PERIMETER', 'FULL_HYDRO', 'FULL_HYDR2', 'FTYPE', 'FCODE', 'NAME']
- >>> print grass.vector_db_select('lakes')['values'][3]
- ['3', '19512.86146', '708.44683', '4', '55652', 'LAKE/POND', '39000', '']
- >>> print grass.vector_db_select('lakes', columns = 'FTYPE')['values'][3]
- ['LAKE/POND']
- \endcode
-
- @param map map name
- @param layer layer number
- @param kwargs v.db.select options
-
- @return dictionary ('columns' and 'values')
- """
- try:
- key = vector_db(map = map)[layer]['key']
- except KeyError:
- error(_('Missing layer %(layer)d in vector map <%(map)s>') % \
- { 'layer' : layer, 'map' : map })
- return { 'columns' : [], 'values' : {} }
-
- if 'columns' in kwargs:
- if key not in kwargs['columns'].split(','):
- # add key column if missing
- debug("Adding key column to the output")
- kwargs['columns'] += ',' + key
-
- ret = read_command('v.db.select',
- map = map,
- layer = layer,
- **kwargs)
-
- if not ret:
- error(_('vector_db_select() failed'))
- return { 'columns' : [], 'values' : {} }
-
- columns = []
- values = {}
- for line in ret.splitlines():
- if not columns:
- columns = line.split('|')
- key_index = columns.index(key)
- continue
-
- value = line.split('|')
- key_value = int(value[key_index])
- values[key_value] = line.split('|')
-
- return { 'columns' : columns,
- 'values' : values }
-
-# interface to v.what
-def vector_what(map, coord, distance = 0.0, ttype = None):
- """!Query vector map at given locations
-
- To query one vector map at one location
- @code
- print grass.vector_what(map = 'archsites', coord = (595743, 4925281), distance = 250)
-
- [{'Category': 8, 'Map': 'archsites', 'Layer': 1, 'Key_column': 'cat',
- 'Database': '/home/martin/grassdata/spearfish60/PERMANENT/dbf/',
- 'Mapset': 'PERMANENT', 'Driver': 'dbf',
- 'Attributes': {'str1': 'No_Name', 'cat': '8'},
- 'Table': 'archsites', 'Type': 'Point', 'Id': 8}]
- @endcode
-
- To query one vector map with multiple layers (no additional parameters required)
- @code
- for q in grass.vector_what(map = 'some_map', coord = (596532.357143,4920486.21429), distance = 100.0):
- print q['Map'], q['Layer'], q['Attributes']
-
- new_bug_sites 1 {'str1': 'Beetle_site', 'GRASSRGB': '', 'cat': '80'}
- new_bug_sites 2 {'cat': '80'}
- @endcode
-
- To query more vector maps at one location
- @code
- for q in grass.vector_what(map = ('archsites', 'roads'), coord = (595743, 4925281),
- distance = 250):
- print q['Map'], q['Attributes']
-
- archsites {'str1': 'No_Name', 'cat': '8'}
- roads {'label': 'interstate', 'cat': '1'}
- @endcode
-
- To query one vector map at more locations
- @code
- for q in grass.vector_what(map = 'archsites', coord = [(595743, 4925281), (597950, 4918898)],
- distance = 250):
- print q['Map'], q['Attributes']
-
- archsites {'str1': 'No_Name', 'cat': '8'}
- archsites {'str1': 'Bob_Miller', 'cat': '22'}
- @endcode
-
- @param map vector map(s) to query given as string or list/tuple
- @param coord coordinates of query given as tuple (easting, northing) or list of tuples
- @param distance query threshold distance (in map units)
- @param ttype list of topology types (default of v.what are point, line, area, face)
-
- @return parsed list
- """
- if "LC_ALL" in os.environ:
- locale = os.environ["LC_ALL"]
- os.environ["LC_ALL"] = "C"
-
- if type(map) in (types.StringType, types.UnicodeType):
- map_list = [map]
- else:
- map_list = map
-
- layer_list = ['-1'] * len(map_list)
-
- coord_list = list()
- if type(coord) is types.TupleType:
- coord_list.append('%f,%f' % (coord[0], coord[1]))
- else:
- for e, n in coord:
- coord_list.append('%f,%f' % (e, n))
-
- cmdParams = dict(quiet = True,
- flags = 'ag',
- map = ','.join(map_list),
- layer = ','.join(layer_list),
- coordinates = ','.join(coord_list),
- distance = float(distance))
- if ttype:
- cmdParams['type'] = ','.join(ttype)
-
- ret = read_command('v.what',
- **cmdParams)
-
- if "LC_ALL" in os.environ:
- os.environ["LC_ALL"] = locale
-
- data = list()
- if not ret:
- return data
-
- dict_attrb = None
- dict_map = None
- dict_layer = None
- attr_pseudo_key = 'Attributes'
- for item in ret.splitlines():
- try:
- key, value = __builtin__.map(lambda x: x.strip(), item.split('=', 1))
- except ValueError:
- continue
- if key in ('East', 'North'):
- continue
-
- if key == 'Map':
- # attach the last one from the previous map
- if dict_layer is not None:
- dict_main = copy.copy(dict_map)
- dict_main.update(dict_layer)
- data.append(dict_main)
- dict_map = { key : value }
- dict_layer = None
- dict_attrb = None
- elif key == 'Layer':
- # attach the last the previous Layer
- if dict_layer is not None:
- dict_main = copy.copy(dict_map)
- dict_main.update(dict_layer)
- data.append(dict_main)
- dict_layer = { key: int(value) }
- dict_attrb = None
- elif key == 'Key_column':
- dict_layer[key] = value
- dict_attrb = dict()
- dict_layer[attr_pseudo_key] = dict_attrb
- elif dict_attrb is not None:
- dict_attrb[key] = value
- elif dict_layer is not None:
- if key == 'Category':
- dict_layer[key] = int(value)
- else:
- dict_layer[key] = value
- else:
- dict_map[key] = value
- # TODO: there are some keys which has non-string values
- # examples: Sq_Meters, Hectares, Acres, Sq_Miles
-
- # attach the last one
- if dict_layer is not None:
- dict_main = copy.copy(dict_map)
- dict_main.update(dict_layer)
- data.append(dict_main)
-
- return data
More information about the grass-commit
mailing list