[GRASS-SVN] r46843 - in grass/trunk: gui/wxpython/gui_modules
gui/wxpython/support lib/python
svn_grass at osgeo.org
svn_grass at osgeo.org
Wed Jun 29 08:53:42 EDT 2011
Author: martinl
Date: 2011-06-29 05:53:42 -0700 (Wed, 29 Jun 2011)
New Revision: 46843
Added:
grass/trunk/lib/python/task.py
Modified:
grass/trunk/gui/wxpython/gui_modules/gdialogs.py
grass/trunk/gui/wxpython/gui_modules/ghelp.py
grass/trunk/gui/wxpython/gui_modules/gmodeler.py
grass/trunk/gui/wxpython/gui_modules/goutput.py
grass/trunk/gui/wxpython/gui_modules/menuform.py
grass/trunk/gui/wxpython/gui_modules/prompt.py
grass/trunk/gui/wxpython/support/update_menudata.py
grass/trunk/lib/python/Makefile
grass/trunk/lib/python/core.py
Log:
pythonlib: rewrite command_info() using grassTask and processTask (moved from wxGUI)
Modified: grass/trunk/gui/wxpython/gui_modules/gdialogs.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/gdialogs.py 2011-06-29 10:52:43 UTC (rev 46842)
+++ grass/trunk/gui/wxpython/gui_modules/gdialogs.py 2011-06-29 12:53:42 UTC (rev 46843)
@@ -39,6 +39,7 @@
import wx.lib.mixins.listctrl as listmix
from grass.script import core as grass
+from grass.script import task as gtask
import gcmd
import globalvar
@@ -960,7 +961,7 @@
label="%s" % _("Options"))
cmd = self._getCommand()
- task = menuform.GUI().ParseInterface(cmd = [cmd])
+ task = gtask.parse_interface(cmd)
for f in task.get_options()['flags']:
name = f.get('name', '')
desc = f.get('label', '')
Modified: grass/trunk/gui/wxpython/gui_modules/ghelp.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/ghelp.py 2011-06-29 10:52:43 UTC (rev 46842)
+++ grass/trunk/gui/wxpython/gui_modules/ghelp.py 2011-06-29 12:53:42 UTC (rev 46843)
@@ -34,6 +34,8 @@
import wx.lib.flatnotebook as FN
import wx.lib.scrolledpanel as scrolled
+from grass.script import task as gtask
+
import menudata
import gcmd
import globalvar
@@ -812,7 +814,7 @@
self.optionBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
label = " %s " % _("Options"))
- task = menuform.GUI().ParseInterface(cmd = ['g.extension'])
+ task = gtask.parse_interface('g.extension')
for f in task.get_options()['flags']:
name = f.get('name', '')
desc = f.get('label', '')
Modified: grass/trunk/gui/wxpython/gui_modules/gmodeler.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/gmodeler.py 2011-06-29 10:52:43 UTC (rev 46842)
+++ grass/trunk/gui/wxpython/gui_modules/gmodeler.py 2011-06-29 12:53:42 UTC (rev 46843)
@@ -77,6 +77,7 @@
from ghelp import SearchModuleWindow
from grass.script import core as grass
+from grass.script import task as gtask
class Model(object):
"""!Class representing the model"""
@@ -3458,9 +3459,9 @@
def _createPage(self, name, params):
"""!Define notebook page"""
if name in globalvar.grassCmd['all']:
- task = menuform.grassTask(name)
+ task = gtask.grassTask(name)
else:
- task = menuform.grassTask()
+ task = gtask.grassTask()
task.flags = params['flags']
task.params = params['params']
Modified: grass/trunk/gui/wxpython/gui_modules/goutput.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/goutput.py 2011-06-29 10:52:43 UTC (rev 46842)
+++ grass/trunk/gui/wxpython/gui_modules/goutput.py 2011-06-29 12:53:42 UTC (rev 46843)
@@ -32,6 +32,7 @@
from wx.lib.newevent import NewEvent
import grass.script as grass
+from grass.script import task as gtask
import globalvar
import gcmd
@@ -526,7 +527,7 @@
if len(command) == 1:
import menuform
- task = menuform.GUI().ParseInterface(command)
+ task = gtask.parse_interface(command[0])
# if not task.has_required():
# task = None # run command
else:
@@ -552,7 +553,7 @@
if len(command) == 1:
import menuform
try:
- task = menuform.GUI().ParseInterface(command)
+ task = gtask.parse_interface(command[0])
except:
task = None
else:
Modified: grass/trunk/gui/wxpython/gui_modules/menuform.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/menuform.py 2011-06-29 10:52:43 UTC (rev 46842)
+++ grass/trunk/gui/wxpython/gui_modules/menuform.py 2011-06-29 12:53:42 UTC (rev 46843)
@@ -4,8 +4,6 @@
description.
Classes:
- - grassTask
- - processTask
- helpPanel
- mainFrame
- cmdPanel
@@ -95,6 +93,7 @@
sys.path.append(wxbase)
from grass.script import core as grass
+from grass.script import task as gtask
import gselect
import gcmd
@@ -131,8 +130,11 @@
rgb2str[ r ] = s
"""!Hide some options in the GUI"""
-_blackList = { }
-_ignoreBlackList = True
+#_blackList = { 'enabled' : False,
+# 'items' : { 'r.buffer' : {'params' : ['input', 'output'],
+# 'flags' : ['z', 'overwrite']}}}
+_blackList = { 'enabled' : False,
+ 'items' : {} }
def color_resolve(color):
if len(color) > 0 and color[0] in "0123456789":
@@ -372,337 +374,7 @@
if self.request:
event = wxUpdateDialog(data = self.request.data)
wx.PostEvent(self.parent, event)
-
-class grassTask:
- """!This class holds the structures needed for both filling by the
- parser and use by the interface constructor.
- Use as either grassTask() for empty definition or
- grassTask('grass.command') for parsed filling.
- """
- def __init__(self, grassModule = None):
- self.path = grassModule
- self.name = _('unknown')
- self.params = list()
- self.description = ''
- self.label = ''
- self.flags = list()
- self.keywords = list()
- self.errorMsg = ''
- self.firstParam = None
-
- if grassModule is not None:
- try:
- processTask(tree = etree.fromstring(getInterfaceDescription(grassModule)),
- task = self)
- except gcmd.GException, e:
- self.errorMsg = e.value
-
- self.define_first()
-
- def define_first(self):
- """!Define first parameter"""
- if len(self.params) > 0:
- self.firstParam = self.params[0]['name']
-
- def get_error_msg(self):
- """!Get error message ('' for no error)"""
- return self.errorMsg
-
- def get_name(self):
- """!Get task name"""
- return self.name
-
- def get_list_params(self, element = 'name'):
- """!Get list of parameters"""
- params = []
- for p in self.params:
- params.append(p['name'])
-
- return params
-
- def get_list_flags(self, element = 'name'):
- """!Get list of parameters"""
- flags = []
- for p in self.flags:
- flags.append(p['name'])
-
- return flags
-
- def get_param(self, value, element = 'name', raiseError = True):
- """!Find and return a param by name."""
- 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 set_param(self, aParam, aValue, element = 'value'):
- """!Set param value/values.
- """
- try:
- param = self.get_param(aParam)
- except ValueError:
- return
-
- param[element] = aValue
-
- def get_flag(self, aFlag):
- """!Find and return a flag by name.
- """
- for f in self.flags:
- if f['name'] == aFlag:
- return f
- raise ValueError, _("Flag not found: %s") % aFlag
-
- def set_flag(self, aFlag, aValue, element = 'value'):
- """!Enable / disable flag.
- """
- try:
- param = self.get_flag(aFlag)
- except ValueError:
- return
-
- param[element] = aValue
-
- def getCmdError(self):
- """!Get error string produced by getCmd(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 getCmd(self, ignoreErrors = False):
- """!Produce an array of command name and arguments for feeding
- into some execve-like command processor.
-
- If ignoreErrors = = True then it will return whatever has been
- built so far, even though it would not be a correct command
- for GRASS.
- """
- cmd = [self.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 is True and not suppress_required:
- cmd += [ '%s=%s' % (p['name'], _('<required>')) ]
- elif p.get('value','') != '' and p['value'] != p.get('default','') :
- # Output only values that have been set, and different from defaults
- cmd += [ '%s=%s' % (p['name'], p['value']) ]
-
- errList = self.getCmdError()
- if ignoreErrors is False and errList:
- raise ValueError, '\n'.join(errList)
-
- return cmd
-
- 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)
-
- 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
-
-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
- @return grassTask instance
- """
- def __init__(self, tree, task = None):
- if task:
- self.task = task
- else:
- self.task = grassTask()
-
- self.root = tree
-
- self.__processModule()
- self.__processParams()
- self.__processFlags()
- self.task.define_first()
-
- def __processModule(self):
- """!Process module description"""
- self.task.name = self.root.get('name', default = 'unknown')
-
- # keywords
- for keyword in self._getNodeText(self.root, 'keywords').split(','):
- self.task.keywords.append(keyword.strip())
-
- self.task.label = self._getNodeText(self.root, 'label')
- self.task.description = self._getNodeText(self.root, 'description')
-
- def __processParams(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._getNodeText(pv, 'name'))
- desc = self._getNodeText(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 not _ignoreBlackList and \
- self.task.name in _blackList and \
- p.get('name') in _blackList[self.task.name]['params']:
- hidden = True
- else:
- hidden = False
-
- self.task.params.append( {
- "name" : p.get('name'),
- "type" : p.get('type'),
- "required" : required,
- "multiple" : multiple,
- "label" : self._getNodeText(p, 'label'),
- "description" : self._getNodeText(p, 'description'),
- 'gisprompt' : gisprompt,
- 'age' : age,
- 'element' : element,
- 'prompt' : prompt,
- "guisection" : self._getNodeText(p, 'guisection'),
- "guidependency" : self._getNodeText(p, 'guidependency'),
- "default" : self._getNodeText(p, 'default'),
- "values" : values,
- "values_desc" : values_desc,
- "value" : '',
- "key_desc" : key_desc,
- "hidden" : hidden
- })
-
- def __processFlags(self):
- """!Process flags"""
- global _ignoreBlackList
- for p in self.root.findall('flag'):
- if not _ignoreBlackList and \
- self.task.name in _blackList and \
- p.get('name') in _blackList[self.task.name]['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._getNodeText(p, 'label'),
- "description" : self._getNodeText(p, 'description'),
- "guisection" : self._getNodeText(p, 'guisection'),
- "suppress_required" : suppress_required,
- "value" : False,
- "hidden" : hidden
- } )
-
- def _getNodeText(self, node, tag, default = ''):
- """!Get node text"""
- p = node.find(tag)
- if p is not None:
- return utils.normalize_whitespace(p.text)
-
- return default
-
- def GetTask(self):
- """!Get grassTask instance"""
- return self.task
-
-
class mainFrame(wx.Frame):
"""!This is the Frame containing the dialog for options input.
@@ -2135,26 +1807,6 @@
event.Skip()
-def getInterfaceDescription(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:
- cmdout, cmderr = grass.Popen([cmd, '--interface-description'], stdout = grass.PIPE,
- stderr = grass.PIPE).communicate()
- except OSError, e:
- raise gcmd.GException, _("Unable to fetch interface description for command '%s'.") % cmd + \
- _("Details:") + "%s" % e
- if cmderr and cmderr[:7] != 'WARNING':
- raise gcmd.GException, _("Unable to fetch interface description for command '%s'.") % cmd + \
- _("Details:") + " %s" % cmderr
-
- return cmdout.replace('grass-interface.dtd', os.path.join(globalvar.ETCDIR, 'grass-interface.dtd'))
-
class GrassGUIApp(wx.App):
"""!Stand-alone GRASS command GUI
"""
@@ -2190,29 +1842,16 @@
self.grass_task = None
self.cmd = list()
- global _ignoreBlackList
+ global _blackList
if self.parent:
- _ignoreBlackList = False
+ _blackList['enabled'] = True
else:
- _ignoreBlackList = True
-
+ _blackList['enabled'] = False
+
def GetCmd(self):
"""!Get validated command"""
return self.cmd
- def ParseInterface(self, cmd, parser = processTask):
- """!Parse interface
-
- @param cmd command to be parsed (given as list)
- """
- # enc = locale.getdefaultlocale()[1]
- # if enc and enc.lower() not in ("utf8", "utf-8"):
- # tree = etree.fromstring(getInterfaceDescription(cmd[0]).decode(enc).encode("utf-8"))
- # else:
- tree = etree.fromstring(getInterfaceDescription(cmd[0]))
-
- return processTask(tree).GetTask()
-
def ParseCommand(self, cmd, gmpath = None, completed = None):
"""!Parse command
@@ -2235,7 +1874,13 @@
dcmd_params.update(completed[2])
# parse the interface decription
- self.grass_task = self.ParseInterface(cmd)
+ try:
+ global _blackList
+ self.grass_task = gtask.parse_interface(cmd[0],
+ blackList = _blackList)
+ except ValueError, e: #grass.ScriptError, e:
+ gcmd.GError(e.value)
+ return
# if layer parameters previously set, re-insert them into dialog
if completed is not None:
@@ -2283,7 +1928,7 @@
curr_mapset = grass.gisenv()['MAPSET']
if mapset and mapset != curr_mapset:
value = value + '@' + mapset
-
+
self.grass_task.set_param(key, value)
cmd_validated.append(key + '=' + value)
i += 1
@@ -2332,8 +1977,8 @@
"""
# parse the interface decription
if not self.grass_task:
- tree = etree.fromstring(getInterfaceDescription(cmd))
- self.grass_task = processTask(tree).GetTask()
+ tree = etree.fromstring(gtask.get_interface_description(cmd))
+ self.grass_task = gtask.processTask(tree).GetTask()
for p in self.grass_task.params:
if p.get('name', '') in ('input', 'map'):
@@ -2442,14 +2087,14 @@
if sys.argv[1] != 'test':
q = wx.LogNull()
cmd = utils.split(sys.argv[1])
- task = grassTask(cmd[0])
+ task = gtask.grassTask(cmd[0], blackList = _blackList)
task.set_options(cmd[1:])
app = GrassGUIApp(task)
app.MainLoop()
else: #Test
# Test grassTask from within a GRASS session
if os.getenv("GISBASE") is not None:
- task = grassTask("d.vect")
+ task = gtask.grassTask("d.vect")
task.get_param('map')['value'] = "map_name"
task.get_flag('v')['value'] = True
task.get_param('layer')['value'] = 1
@@ -2457,7 +2102,7 @@
assert ' '.join(task.getCmd()) == "d.vect -v map = map_name layer = 1 bcolor = red"
# Test interface building with handmade grassTask,
# possibly outside of a GRASS session.
- task = grassTask()
+ task = gtask.grassTask()
task.name = "TestTask"
task.description = "This is an artificial grassTask() object intended for testing purposes."
task.keywords = ["grass","test","task"]
Modified: grass/trunk/gui/wxpython/gui_modules/prompt.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/prompt.py 2011-06-29 10:52:43 UTC (rev 46842)
+++ grass/trunk/gui/wxpython/gui_modules/prompt.py 2011-06-29 12:53:42 UTC (rev 46843)
@@ -31,6 +31,7 @@
import wx.lib.mixins.listctrl as listmix
from grass.script import core as grass
+from grass.script import task as gtask
import globalvar
import menudata
@@ -176,7 +177,7 @@
# get module's description
if name in self._choicesCmd and not self._module:
try:
- self._module = menuform.GUI().ParseInterface(cmd = [name])
+ self._module = gtask.parse_interface(name)
except IOError:
self._module = None
@@ -495,7 +496,7 @@
self.autoCompList = list()
self.autoCompFilter = None
- # command description (menuform.grassTask)
+ # command description (gtask.grassTask)
self.cmdDesc = None
self.cmdbuffer = self._readHistory()
self.cmdindex = len(self.cmdbuffer)
@@ -783,7 +784,7 @@
self.OnCmdErase(None)
else:
try:
- self.cmdDesc = menuform.GUI().ParseInterface(cmd = [cmd])
+ self.cmdDesc = gtask.parse_interface(cmd)
except IOError:
self.cmdDesc = None
@@ -1015,11 +1016,11 @@
if cmd not in globalvar.grassCmd['all']:
return
- usage, description = self.GetCommandUsage(cmd)
-
+ info = gtask.command_info(cmd)
+
self.CallTipSetBackground("#f4f4d1")
self.CallTipSetForeground("BLACK")
- self.CallTipShow(pos, usage + '\n\n' + description)
+ self.CallTipShow(pos, info['usage'] + '\n\n' + info['description'])
elif event.GetKeyCode() in [wx.WXK_UP, wx.WXK_DOWN] and \
@@ -1092,7 +1093,7 @@
cmd != 'r.mapcalc' and \
(not self.cmdDesc or cmd != self.cmdDesc.get_name()):
try:
- self.cmdDesc = menuform.GUI().ParseInterface(cmd = [cmd])
+ self.cmdDesc = gtask.parse_interface(cmd)
except IOError:
self.cmdDesc = None
event.Skip()
@@ -1117,49 +1118,7 @@
self.SetCurrentPos(pos)
return entry
-
- def GetCommandUsage(self, command):
- """!Returns command syntax by running command help"""
- usage = ''
- description = ''
-
- ret, out = gcmd.RunCommand(command, 'help', getErrorMsg = True)
-
- if ret == 0:
- cmdhelp = out.splitlines()
- addline = False
- helplist = []
- description = ''
- for line in cmdhelp:
- if "Usage:" in line:
- addline = True
- continue
- elif "Flags:" in line:
- addline = False
- break
- elif addline == True:
- line = line.strip()
- helplist.append(line)
-
- for line in cmdhelp:
- if "Description:" in line:
- addline = True
- continue
- elif "Keywords:" in line:
- addline = False
- break
- elif addline == True:
- description += (line + ' ')
-
- description = description.strip()
-
- for line in helplist:
- usage += line + '\n'
-
- return usage.strip(), description
- else:
- return ''
-
+
def OnDestroy(self, event):
"""!The clipboard contents can be preserved after
the app has exited"""
Modified: grass/trunk/gui/wxpython/support/update_menudata.py
===================================================================
--- grass/trunk/gui/wxpython/support/update_menudata.py 2011-06-29 10:52:43 UTC (rev 46842)
+++ grass/trunk/gui/wxpython/support/update_menudata.py 2011-06-29 12:53:42 UTC (rev 46843)
@@ -28,6 +28,7 @@
import elementtree.ElementTree as etree # Python <= 2.4
from grass.script import core as grass
+from grass.script import task as gtask
sys.path.append('gui_modules')
import menudata
@@ -51,7 +52,7 @@
if module in ignore:
continue
try:
- interface = menuform.GUI().ParseInterface(cmd = [module])
+ interface = gtask.parse_interface(module)
except IOError, e:
grass.error(e)
continue
Modified: grass/trunk/lib/python/Makefile
===================================================================
--- grass/trunk/lib/python/Makefile 2011-06-29 10:52:43 UTC (rev 46842)
+++ grass/trunk/lib/python/Makefile 2011-06-29 12:53:42 UTC (rev 46843)
@@ -8,7 +8,7 @@
GDIR = $(PYDIR)/grass
DSTDIR = $(GDIR)/script
-MODULES = core db raster vector array setup
+MODULES = core db raster vector array setup task
PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)
Modified: grass/trunk/lib/python/core.py
===================================================================
--- grass/trunk/lib/python/core.py 2011-06-29 10:52:43 UTC (rev 46842)
+++ grass/trunk/lib/python/core.py 2011-06-29 12:53:42 UTC (rev 46843)
@@ -861,71 +861,6 @@
"""
return sum(float(x) / 60 ** n for (n, x) in enumerate(s.split(':')))
-def command_info(cmd):
- """!Returns 'help' information for any command as dictionary with entries
- for description, keywords, usage, flags, and parameters"""
-
- cmdinfo = {}
- s = start_command(cmd, 'help', stdout = subprocess.PIPE, stderr = subprocess.PIPE)
- out, err = s.communicate()
-
- sections = err.split('\n\n')
-
- #Description
- first, desc = sections[0].split(':\n', 1)
- desclines = desc.splitlines()
- for line in desclines:
- line = line.strip()+' '
-
- # Keywords
- first, keywords = sections[1].split(':\n', 1)
- keylines = keywords.splitlines()
- list = []
- list = keywords.strip().split(',')
- cmdinfo['keywords'] = list
-
- cmdinfo['description'] = ''.join(desclines).strip()
-
- # Usage
- first, usage = sections[2].split(':\n', 1)
- usagelines = usage.splitlines()
- list = []
- for line in usagelines:
- line = line.strip()
- if line == '': continue
- line = line+' '
- list.append(line)
-
- cmdinfo['usage'] = ''.join(list).strip()
-
- # Flags
- first, flags = sections[3].split(':\n', 1)
- flaglines = flags.splitlines()
- dict = {}
- for line in flaglines:
- line = line.strip()
- if line == '': continue
- item = line.split(' ',1)[0].strip()
- val = line.split(' ',1)[1].strip()
- dict[item] = val
-
- cmdinfo['flags'] = dict
-
- # Parameters
- first, params = err.rsplit(':\n', 1)
- paramlines = params.splitlines()
- dict = {}
- for line in paramlines:
- line = line.strip()
- if line == '': continue
- item = line.split(' ',1)[0].strip()
- val = line.split(' ',1)[1].strip()
- dict[item] = val
-
- cmdinfo['parameters'] = dict
-
- return cmdinfo
-
# interface to g.mapsets
def mapsets(accessible = True):
Added: grass/trunk/lib/python/task.py
===================================================================
--- grass/trunk/lib/python/task.py (rev 0)
+++ grass/trunk/lib/python/task.py 2011-06-29 12:53:42 UTC (rev 46843)
@@ -0,0 +1,519 @@
+"""!@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
+ """
+ if len(self.params) > 0:
+ self.firstParam = self.params[0]['name']
+
+ def get_error_msg(self):
+ """!Get error message ('' for no error)
+ """
+ return self.errorMsg
+
+ def get_name(self):
+ """!Get task 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 getCmdError(self):
+ """!Get error string produced by getCmd(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 getCmd(self, ignoreErrors = False):
+ """!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
+ """
+ cmd = [self.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 is True and not suppress_required:
+ cmd += [ '%s=%s' % (p['name'], _('<required>')) ]
+ elif p.get('value','') != '' and p['value'] != p.get('default','') :
+ # Output only values that have been set, and different from defaults
+ cmd += [ '%s=%s' % (p['name'], p['value']) ]
+
+ errList = self.getCmdError()
+ 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:
+ cmdout, cmderr = Popen([cmd, '--interface-description'], stdout = PIPE,
+ stderr = PIPE).communicate()
+ except OSError, e:
+ raise ScriptError, _("Unable to fetch interface description for command '%s'.") % cmd + \
+ _("Details:") + "%s" % e
+ if cmderr and cmderr[:7] != 'WARNING':
+ raise ScriptError, _("Unable to fetch interface description for command '%s'.") % cmd + \
+ _("Details:") + " %s" % 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() not in ("utf8", "utf-8"):
+ # tree = etree.fromstring(getInterfaceDescription(cmd[0]).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
More information about the grass-commit
mailing list