[GRASS-SVN] r55603 - in grass/trunk: gui/wxpython/lmgr lib/python/pygrass/modules lib/python/pygrass/modules/interface
svn_grass at osgeo.org
svn_grass at osgeo.org
Wed Apr 3 03:45:54 PDT 2013
Author: zarch
Date: 2013-04-03 03:45:53 -0700 (Wed, 03 Apr 2013)
New Revision: 55603
Added:
grass/trunk/lib/python/pygrass/modules/interface/
grass/trunk/lib/python/pygrass/modules/interface/Makefile
grass/trunk/lib/python/pygrass/modules/interface/__init__.py
grass/trunk/lib/python/pygrass/modules/interface/flag.py
grass/trunk/lib/python/pygrass/modules/interface/module.py
grass/trunk/lib/python/pygrass/modules/interface/parameter.py
grass/trunk/lib/python/pygrass/modules/interface/read.py
grass/trunk/lib/python/pygrass/modules/interface/typedict.py
grass/trunk/lib/python/pygrass/modules/shortcuts.py
Modified:
grass/trunk/gui/wxpython/lmgr/pyshell.py
grass/trunk/lib/python/pygrass/modules/Makefile
grass/trunk/lib/python/pygrass/modules/__init__.py
Log:
Split pygrass/modules/__init__ in smaller files
Modified: grass/trunk/gui/wxpython/lmgr/pyshell.py
===================================================================
--- grass/trunk/gui/wxpython/lmgr/pyshell.py 2013-04-03 09:40:20 UTC (rev 55602)
+++ grass/trunk/gui/wxpython/lmgr/pyshell.py 2013-04-03 10:45:53 UTC (rev 55603)
@@ -41,14 +41,14 @@
introText = self.intro,
locals={'grass': grass,
'pygrass': pygrass,
- 'r': pgmodules.raster,
- 'r3': pgmodules.raster3D,
- 'v': pgmodules.vector,
- 'i': pgmodules.imagery,
- 'db': pgmodules.database,
- 'g': pgmodules.general,
- 'ps': pgmodules.postscript,
- 't': pgmodules.temporal,
+ 'r': pgmodules.shortcuts.raster,
+ 'r3': pgmodules.shortcuts.raster3D,
+ 'v': pgmodules.shortcuts.vector,
+ 'i': pgmodules.shortcuts.imagery,
+ 'db': pgmodules.shortcuts.database,
+ 'g': pgmodules.shortcuts.general,
+ 'ps': pgmodules.shortcuts.postscript,
+ 't': pgmodules.shortcuts.temporal,
'giface': self.parent._giface, # for experimetal reasons only
'AddLayer': self.AddLayer})
Modified: grass/trunk/lib/python/pygrass/modules/Makefile
===================================================================
--- grass/trunk/lib/python/pygrass/modules/Makefile 2013-04-03 09:40:20 UTC (rev 55602)
+++ grass/trunk/lib/python/pygrass/modules/Makefile 2013-04-03 10:45:53 UTC (rev 55603)
@@ -9,11 +9,16 @@
PGDIR = $(GDIR)/pygrass
DSTDIR= $(PGDIR)/modules
+MODULES = shortcuts
+CLEAN_SUBDIRS = interface
+
PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)
default: $(PYFILES) $(PYCFILES) $(GDIR)/__init__.py $(GDIR)/__init__.pyc
+ -$(MAKE) -C interface || echo $(CURDIR)/interface >> $(ERRORLOG)
+ -$(MAKE) -C grid || echo $(CURDIR)/grid >> $(ERRORLOG)
$(PYDIR):
$(MKDIR) $@
@@ -28,4 +33,4 @@
$(INSTALL_DATA) $< $@
#doxygen:
-DOXNAME = pythonpygrass
\ No newline at end of file
+DOXNAME = pythonpygrass
Modified: grass/trunk/lib/python/pygrass/modules/__init__.py
===================================================================
--- grass/trunk/lib/python/pygrass/modules/__init__.py 2013-04-03 09:40:20 UTC (rev 55602)
+++ grass/trunk/lib/python/pygrass/modules/__init__.py 2013-04-03 10:45:53 UTC (rev 55603)
@@ -5,669 +5,10 @@
@author: pietro
"""
-from __future__ import print_function
-import subprocess
-import fnmatch
-import re
+import interface
+from interface import Module
-try:
- from collections import OrderedDict
-except ImportError:
- from grass.pygrass.orderdict import OrderedDict
+#import grid
+#from grid.grid import GridModule
-from itertools import izip_longest
-from xml.etree.ElementTree import fromstring
-
-import grass
-
-from grass.pygrass.errors import GrassError, ParameterError
-
-
-def _read_keydesc(par):
- name = par.text.strip()
- items = [e.text.strip() for e in par.findall('item')]
- #import ipdb; ipdb.set_trace()
- return name, tuple(items) if len(items) > 1 else None
-
-
-#
-# this dictionary is used to extract the value of interest from the xml
-# the lambda experssion is used to define small simple functions,
-# is equivalent to: ::
-#
-# def f(p):
-# return p.text.strip()
-#
-# and then we call f(p)
-#
-_GETFROMTAG = {
- 'description': lambda p: p.text.strip(),
- 'keydesc': _read_keydesc,
- 'gisprompt': lambda p: dict(p.items()),
- 'default': lambda p: p.text.strip(),
- 'values': lambda p: [e.text.strip() for e in p.findall('value/name')],
- 'value': lambda p: None,
- 'guisection': lambda p: p.text.strip(),
- 'label': lambda p: p.text.strip(),
- 'suppress_required': lambda p: None,
- 'keywords': lambda p: p.text.strip(),
-}
-
-_GETTYPE = {
- 'string': str,
- 'integer': int,
- 'float': float,
- 'double': float,
- 'all': lambda x: x,
-}
-
-def _element2dict(xparameter):
- diz = dict(xparameter.items())
- for p in xparameter:
- if p.tag in _GETFROMTAG:
- diz[p.tag] = _GETFROMTAG[p.tag](p)
- else:
- print('New tag: %s, ignored' % p.tag)
- return diz
-
-# dictionary used to create docstring for the objects
-_DOC = {
- #------------------------------------------------------------
- # head
- 'head': """{cmd_name}({cmd_params})
-
-Parameters
-----------
-
-""",
- #------------------------------------------------------------
- # param
- 'param': """{name}: {default}{required}{multi}{ptype}
- {description}{values}{keydescvalues}""",
- #------------------------------------------------------------
- # flag_head
- 'flag_head': """
-Flags
-------
-""",
- #------------------------------------------------------------
- # flag
- 'flag': """{name}: {default}
- {description}""",
- #------------------------------------------------------------
- # foot
- 'foot': """
-Special Parameters
-------------------
-
-The Module class have some optional parameters which are distinct using a final
-underscore.
-
-run_: True, optional
- If True execute the module.
-finish_: True, optional
- If True wait untill the end of the module execution, and store the module
- outputs into stdout, stderr attributes of the class.
-stdin_: PIPE,
- Set the standard input
-"""}
-
-
-class Parameter(object):
-
- def __init__(self, xparameter=None, diz=None):
- self._value = None
- diz = _element2dict(xparameter) if xparameter is not None else diz
- if diz is None:
- raise TypeError('Xparameter or diz are required')
- self.name = diz['name']
- self.required = True if diz['required'] == 'yes' else False
- self.multiple = True if diz['multiple'] == 'yes' else False
- # check the type
- if diz['type'] in _GETTYPE:
- self.type = _GETTYPE[diz['type']]
- self.typedesc = diz['type']
- self._type = _GETTYPE[diz['type']]
- else:
- raise TypeError('New type: %s, ignored' % diz['type'])
-
- self.description = diz.get('description', None)
- self.keydesc, self.keydescvalues = diz.get('keydesc', (None, None))
-
- #
- # values
- #
- if 'values' in diz:
- try:
- # chek if it's a range string: "3-30"
- isrange = re.match("(?P<min>\d+)-(?P<max>\d+)",
- diz['values'][0])
- if isrange:
- range_min, range_max = isrange.groups()
- self.values = range(int(range_min), int(range_max) + 1)
- self.isrange = diz['values'][0]
- else:
- self.values = [self._type(i) for i in diz['values']]
- self.isrange = False
- except TypeError:
- self.values = [self._type(i) for i in diz['values']]
- self.isrange = False
-
- #
- # default
- #
- self.default = self._type(
- diz['default']) if 'default' in diz else None
- if self.default is not None:
- self._value = self.default
-
- self.guisection = diz.get('guisection', None)
-
- #
- # gisprompt
- #
- if 'gisprompt' in diz:
- self.type = diz['gisprompt']['prompt']
- self.input = False if diz['gisprompt']['age'] == 'new' else True
- else:
- self.input = True
-
- def _get_value(self):
- return self._value
-
- def _set_value(self, value):
- if isinstance(value, list) or isinstance(value, tuple):
- if self.multiple or self.keydescvalues:
- # check each value
- self._value = [self._type(val) for val in value]
- else:
- str_err = 'The Parameter <%s> does not accept multiple inputs'
- raise TypeError(str_err % self.name)
- elif self.typedesc == 'all':
- self._value = value
- elif isinstance(value, self._type):
- if hasattr(self, 'values'):
- if value in self.values:
- self._value = value
- else:
- raise ValueError('The Parameter <%s>, must be one of: %r' %
- (self.name, self.values))
- else:
- self._value = value
- else:
- str_err = 'The Parameter <%s>, require: %s, get: %s instead'
- raise TypeError(str_err % (self.name, self.typedesc, type(value)))
-
- # here the property function is used to transform value in an attribute
- # in this case we define which function must be use to get/set the value
- value = property(fget=_get_value, fset=_set_value)
-
- def get_bash(self):
- if isinstance(self._value, list) or isinstance(self._value, tuple):
- value = ','.join([str(v) for v in self._value])
- else:
- value = str(self._value)
- return """%s=%s""" % (self.name, value)
-
- def get_python(self):
- if not self.value:
- return ''
- return """%s=%r""" % (self.name, self._value)
-
- def __str__(self):
- return self.get_bash()
-
- def __repr__(self):
- str_repr = "Parameter <%s> (required:%s, type:%s, multiple:%s)"
- return str_repr % (self.name,
- "yes" if self.required else "no",
- self.type if self.type in (
- 'raster', 'vector') else self.typedesc,
- "yes" if self.multiple else "no")
-
- # here we use property with a decorator, in this way we mask a method as
- # a class attribute
- @property
- def __doc__(self):
- """Return the docstring of the parameter
-
- {name}: {default}{required}{multi}{ptype}
- {description}{values}"","""
- if hasattr(self, 'values'):
- if self.isrange:
- vals = self.isrange
- else:
- vals = ', '.join([repr(val) for val in self.values])
- else:
- vals = False
- keydescvals = "\n (%s)" % ', '.join(self.keydescvalues)
- return _DOC['param'].format(name=self.name,
- default=repr(self.default) + ', ' if self.default else '',
- required='required, ' if self.required else 'optional, ',
- multi='multi' if self.multiple else '',
- ptype=self.typedesc, description=self.description,
- values='\n Values: {0}'.format(vals) if vals else '',
- keydescvalues= keydescvals if self.keydescvalues else '')
-
-
-class TypeDict(OrderedDict):
- def __init__(self, dict_type, *args, **kargs):
- self._type = dict_type
- super(TypeDict, self).__init__(*args, **kargs)
-
- def __getattr__(self, key):
- if key in self:
- return self[key].value
- return OrderedDict.__getattr__(self, key)
-
- def __setattr__(self, key, value):
- if key in self:
- self[key].value = value
- else:
- OrderedDict.__setattr__(self, key, value)
-
- def __dir__(self):
- return self.keys()
-
- def __setitem__(self, key, value):
- if isinstance(value, self._type):
- super(TypeDict, self).__setitem__(key, value)
- else:
- cl = repr(self._type).translate(None, "'<> ").split('.')
- str_err = 'The value: %r is not a %s object'
- raise TypeError(str_err % (value, cl[-1].title()))
-
- @property
- def __doc__(self):
- return '\n'.join([self.__getitem__(obj).__doc__
- for obj in self.__iter__()])
-
- def __call__(self):
- return [self.__getitem__(obj) for obj in self.__iter__()]
-
- def used(self):
- key_dict = {}
- for key in self:
- if self.__getattr__(key):
- key_dict[key] = self.__getattr__(key)
- return key_dict
-
-
-class Flag(object):
- def __init__(self, xflag=None, diz=None):
- self.value = False
- diz = _element2dict(xflag) if xflag is not None else diz
- self.name = diz['name']
- self.special = True if self.name in (
- 'verbose', 'overwrite', 'quiet', 'run') else False
- self.description = diz['description']
- self.default = diz.get('default', None)
- self.guisection = diz.get('guisection', None)
-
- def get_bash(self):
- if self.value:
- if self.special:
- return '--%s' % self.name[0]
- else:
- return '-%s' % self.name
- else:
- return ''
-
- def get_python(self):
- if self.value:
- if self.special:
- return '%s=True' % self.name
- else:
- return self.name
- else:
- return ''
-
- def __str__(self):
- return self.get_bash()
-
- def __repr__(self):
- return "Flag <%s> (%s)" % (self.name, self.description)
-
- @property
- def __doc__(self):
- """
- {name}: {default}
- {description}"""
- return _DOC['flag'].format(name=self.name,
- default=repr(self.default),
- description=self.description)
-
-
-class Module(object):
- """
-
- Python allow developers to not specify all the arguments and
- keyword arguments of a method or function.
-
- ::
-
- def f(*args):
- for arg in args:
- print arg
-
- therefore if we call the function like: ::
-
- >>> f('grass', 'gis', 'modules')
- grass
- gis
- modules
-
- or we can define a new list: ::
-
- >>> words = ['grass', 'gis', 'modules']
- >>> f(*words)
- grass
- gis
- modules
-
- we can do the same with keyword arguments, rewrite the above function: ::
-
- def f(*args, **kargs):
- for arg in args:
- print arg
- for key, value in kargs.items():
- print "%s = %r" % (key, value)
-
- now we can use the new function, with: ::
-
- >>> f('grass', 'gis', 'modules', os = 'linux', language = 'python')
- grass
- gis
- modules
- os = 'linux'
- language = 'python'
-
- or, as before we can, define a dictionary and give the dictionary to
- the function, like: ::
-
- >>> keywords = {'os' : 'linux', 'language' : 'python'}
- >>> f(*words, **keywords)
- grass
- gis
- modules
- os = 'linux'
- language = 'python'
-
- In the Module class we heavily use this language feature to pass arguments
- and keyword arguments to the grass module.
- """
- def __init__(self, cmd, *args, **kargs):
- self.name = cmd
- try:
- # call the command with --interface-description
- get_cmd_xml = subprocess.Popen([cmd, "--interface-description"],
- stdout=subprocess.PIPE)
- except OSError:
- str_err = "Module %r not found, please check that the module exist"
- raise GrassError(str_err % self.name)
- # get the xml of the module
- self.xml = get_cmd_xml.communicate()[0]
- # transform and parse the xml into an Element class:
- # http://docs.python.org/library/xml.etree.elementtree.html
- tree = fromstring(self.xml)
-
- for e in tree:
- if e.tag not in ('parameter', 'flag'):
- self.__setattr__(e.tag, _GETFROMTAG[e.tag](e))
-
- #
- # extract parameters from the xml
- #
- self.params_list = [Parameter(p) for p in tree.findall("parameter")]
- self.inputs = TypeDict(Parameter)
- self.outputs = TypeDict(Parameter)
- self.required = []
-
- # Insert parameters into input/output and required
- for par in self.params_list:
- if par.input:
- self.inputs[par.name] = par
- else:
- self.outputs[par.name] = par
- if par.required:
- self.required.append(par)
-
- #
- # extract flags from the xml
- #
- flags_list = [Flag(f) for f in tree.findall("flag")]
- self.flags = TypeDict(Flag)
- for flag in flags_list:
- self.flags[flag.name] = flag
-
- #
- # Add new attributes to the class
- #
- self.run_ = True
- self.finish_ = True
- self.env_ = None
- self.stdin_ = None
- self.stdin = None
- self.stdout_ = None
- self.stderr_ = None
- diz = {'name': 'stdin', 'required': False,
- 'multiple': False, 'type': 'all',
- 'value': None}
- self.inputs['stdin'] = Parameter(diz=diz)
- diz['name'] = 'stdout'
- self.outputs['stdout'] = Parameter(diz=diz)
- diz['name'] = 'stderr'
- self.outputs['stderr'] = Parameter(diz=diz)
- self.popen = None
-
- if args or kargs:
- self.__call__(*args, **kargs)
-
- def __call__(self, *args, **kargs):
- if not args and not kargs:
- self.run()
- return
- #
- # check for extra kargs, set attribute and remove from dictionary
- #
- if 'flags' in kargs:
- for flg in kargs['flags']:
- self.flags[flg].value = True
- del(kargs['flags'])
- if 'run_' in kargs:
- self.run_ = kargs['run_']
- del(kargs['run_'])
- if 'stdin_' in kargs:
- self.inputs['stdin'].value = kargs['stdin_']
- del(kargs['stdin_'])
- if 'stdout_' in kargs:
- self.outputs['stdout'].value = kargs['stdout_']
- del(kargs['stdout_'])
- if 'stderr_' in kargs:
- self.outputs['stderr'].value = kargs['stderr_']
- del(kargs['stderr_'])
- if 'env_' in kargs:
- self.env_ = kargs['env_']
- del(kargs['env_'])
- if 'finish_' in kargs:
- self.finish_ = kargs['finish_']
- del(kargs['finish_'])
-
- #
- # check args
- #
- for param, arg in zip(self.params_list, args):
- param.value = arg
- for key, val in kargs.items():
- if key in self.inputs:
- self.inputs[key].value = val
- elif key in self.outputs:
- self.outputs[key].value = val
- elif key in self.flags:
- # we need to add this, because some parameters (overwrite,
- # verbose and quiet) work like parameters
- self.flags[key].value = val
- else:
- raise ParameterError('%s is not a valid parameter.' % key)
-
- #
- # check reqire parameters
- #
- for par in self.required:
- if par.value is None:
- raise ParameterError(
- "Required parameter <%s> not set." % par.name)
-
- #
- # check if execute
- #
- if self.run_:
- self.run()
-
- def get_bash(self):
- return ' '.join(self.make_cmd())
-
- def get_python(self):
- prefix = self.name.split('.')[0]
- name = '_'.join(self.name.split('.')[1:])
- params = ', '.join([par.get_python() for par in self.params_list
- if par.get_python() != ''])
- special = ', '.join([flg.get_python()
- for flg in self.flags.values()
- if flg.special and flg.get_python() != ''])
- # pre name par flg special
- if self.flags and special:
- return "%s.%s(%s, flags=%r, %s)" % (prefix, name, params,
- self.flags, special)
- elif self.flags:
- return "%s.%s(%s, flags=%r)" % (prefix, name, params, self.flags)
- elif special:
- return "%s.%s(%s, %s)" % (prefix, name, params, special)
- else:
- return "%s.%s(%s)" % (prefix, name, params)
-
- def __str__(self):
- return ' '.join(self.make_cmd())
-
- def __repr__(self):
- return "Module(%r)" % self.name
-
- @property
- def __doc__(self):
- """{cmd_name}({cmd_params})
- """
- head = _DOC['head'].format(cmd_name=self.name,
- cmd_params=('\n' + # go to a new line
- # give space under the function name
- (' ' * (len(self.name) + 1))).join([', '.join(
- # transform each parameter in string
- [str(param) for param in line if param is not None])
- # make a list of parameters with only 3 param per line
- for line in izip_longest(*[iter(self.params_list)] * 3)]),)
- params = '\n'.join([par.__doc__ for par in self.params_list])
- flags = self.flags.__doc__
- return '\n'.join([head, params, _DOC['flag_head'], flags])
-
- def get_dict(self):
- dic = {}
- dic['name'] = self.name
- dic['inputs'] = [(k, v.value) for k, v in self.inputs.items()
- if v.value]
- dic['outputs'] = [(k, v.value) for k, v in self.outputs.items()
- if v.value]
- dic['flags'] = [flg for flg in self.flags if self.flags[flg].value]
- return dic
-
- def make_cmd(self):
- args = [self.name, ]
- for par in self.params_list:
- if par.value is not None:
- args.append(str(par))
- for flg in self.flags:
- if self.flags[flg].value:
- args.append(str(self.flags[flg]))
- return args
-
- def run(self, node=None):
- if self.inputs['stdin'].value:
- self.stdin = self.inputs['stdin'].value
- self.stdin_ = subprocess.PIPE
- if self.outputs['stdout'].value:
- self.stdout_ = self.outputs['stdout'].value
- if self.outputs['stderr'].value:
- self.stderr_ = self.outputs['stderr'].value
- cmd = self.make_cmd()
- self.popen = subprocess.Popen(cmd,
- stdin=self.stdin_,
- stdout=self.stdout_,
- stderr=self.stderr_,
- env=self.env_)
- if self.finish_:
- self.popen.wait()
-
- stdout, stderr = self.popen.communicate(input=self.stdin)
- self.outputs['stdout'].value = stdout if stdout else ''
- self.outputs['stderr'].value = stderr if stderr else ''
-
-
-_CMDS = list(grass.script.core.get_commands()[0])
-_CMDS.sort()
-
-
-class MetaModule(object):
- """Example how to use MetaModule
-
- >>> g = MetaModule('g')
- >>> g_mlist = g.mlist
- >>> g_mlist.name
- 'g.mlist'
- >>> g_mlist.required
- [Parameter <type> (required:yes, type:string, multiple:yes)]
- >>> g_mlist.inputs.type = 'rast'
- >>> g_mlist.stdout_ = -1
- >>> g_mlist.run()
- >>> g_mlist.outputs.stdout # doctest: +ELLIPSIS
- 'basins...soils...'
- >>> r = MetaModule('r')
- >>> what = r.what
- >>> what.description
- 'Queries raster maps on their category values and category labels.'
- >>> what.inputs.map = 'elevation'
- >>> what.inputs.coordinates = [640000,220500] # doctest: +SKIP
- >>> what.run() # doctest: +SKIP
- """
- def __init__(self, prefix):
- self.prefix = prefix
-
- def __dir__(self):
- return [mod[(len(self.prefix) + 1):].replace('.', '_')
- for mod in fnmatch.filter(_CMDS, "%s.*" % self.prefix)]
-
- def __getattr__(self, name):
- return Module('%s.%s' % (self.prefix, name.replace('_', '.')))
-
-
-# http://grass.osgeo.org/grass70/manuals/html70_user/full_index.html
-#[ d.* | db.* | g.* | i.* | m.* | ps.* | r.* | r3.* | t.* | v.* ]
-#
-# d.* display commands
-# db.* database commands
-# g.* general commands
-# i.* imagery commands
-# m.* miscellaneous commands
-# ps.* postscript commands
-# r.* raster commands
-# r3.* raster3D commands
-# t.* temporal commands
-# v.* vector commands
-
-display = MetaModule('d')
-database = MetaModule('db')
-general = MetaModule('g')
-imagery = MetaModule('i')
-miscellaneous = MetaModule('m')
-postscript = MetaModule('ps')
-raster = MetaModule('r')
-raster3D = MetaModule('r3')
-temporal = MetaModule('t')
-vector = MetaModule('v')
+import shortcuts
Added: grass/trunk/lib/python/pygrass/modules/interface/Makefile
===================================================================
--- grass/trunk/lib/python/pygrass/modules/interface/Makefile (rev 0)
+++ grass/trunk/lib/python/pygrass/modules/interface/Makefile 2013-04-03 10:45:53 UTC (rev 55603)
@@ -0,0 +1,32 @@
+MODULE_TOPDIR = ../../../../..
+
+include $(MODULE_TOPDIR)/include/Make/Other.make
+include $(MODULE_TOPDIR)/include/Make/Python.make
+include $(MODULE_TOPDIR)/include/Make/Doxygen.make
+
+PYDIR = $(ETC)/python
+GDIR = $(PYDIR)/grass
+PGDIR = $(GDIR)/pygrass
+DSTDIR= $(PGDIR)/modules/interface
+
+MODULES = read typedict flag parameter module
+
+PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
+PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)
+
+default: $(PYFILES) $(PYCFILES) $(GDIR)/__init__.py $(GDIR)/__init__.pyc
+
+$(PYDIR):
+ $(MKDIR) $@
+
+$(GDIR): | $(PYDIR)
+ $(MKDIR) $@
+
+$(DSTDIR): | $(GDIR)
+ $(MKDIR) $@
+
+$(DSTDIR)/%: % | $(DSTDIR)
+ $(INSTALL_DATA) $< $@
+
+#doxygen:
+DOXNAME = pythonpygrass
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/modules/interface/__init__.py
===================================================================
--- grass/trunk/lib/python/pygrass/modules/interface/__init__.py (rev 0)
+++ grass/trunk/lib/python/pygrass/modules/interface/__init__.py 2013-04-03 10:45:53 UTC (rev 55603)
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Apr 2 18:40:39 2013
+
+ at author: pietro
+"""
+import flag
+import parameter
+import module
+import typedict
+import read
+
+from module import Module
Added: grass/trunk/lib/python/pygrass/modules/interface/flag.py
===================================================================
--- grass/trunk/lib/python/pygrass/modules/interface/flag.py (rev 0)
+++ grass/trunk/lib/python/pygrass/modules/interface/flag.py 2013-04-03 10:45:53 UTC (rev 55603)
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Apr 2 18:39:21 2013
+
+ at author: pietro
+"""
+from read import element2dict
+
+
+class Flag(object):
+ def __init__(self, xflag=None, diz=None):
+ self.value = False
+ diz = element2dict(xflag) if xflag is not None else diz
+ self.name = diz['name']
+ self.special = True if self.name in (
+ 'verbose', 'overwrite', 'quiet', 'run') else False
+ self.description = diz['description']
+ self.default = diz.get('default', None)
+ self.guisection = diz.get('guisection', None)
+
+ def get_bash(self):
+ if self.value:
+ if self.special:
+ return '--%s' % self.name[0]
+ else:
+ return '-%s' % self.name
+ else:
+ return ''
+
+ def get_python(self):
+ if self.value:
+ if self.special:
+ return '%s=True' % self.name
+ else:
+ return self.name
+ else:
+ return ''
+
+ def __str__(self):
+ return self.get_bash()
+
+ def __repr__(self):
+ return "Flag <%s> (%s)" % (self.name, self.description)
+
+ @property
+ def __doc__(self):
+ """
+ {name}: {default}
+ {description}"""
+ return _DOC['flag'].format(name=self.name,
+ default=repr(self.default),
+ description=self.description)
Added: grass/trunk/lib/python/pygrass/modules/interface/module.py
===================================================================
--- grass/trunk/lib/python/pygrass/modules/interface/module.py (rev 0)
+++ grass/trunk/lib/python/pygrass/modules/interface/module.py 2013-04-03 10:45:53 UTC (rev 55603)
@@ -0,0 +1,290 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Apr 2 18:41:27 2013
+
+ at author: pietro
+"""
+
+from __future__ import print_function
+import subprocess
+from itertools import izip_longest
+from xml.etree.ElementTree import fromstring
+
+
+from grass.pygrass.errors import GrassError, ParameterError
+from parameter import Parameter
+from flag import Flag
+from typedict import TypeDict
+from read import GETFROMTAG, DOC
+
+
+class Module(object):
+ """
+
+ Python allow developers to not specify all the arguments and
+ keyword arguments of a method or function.
+
+ ::
+
+ def f(*args):
+ for arg in args:
+ print arg
+
+ therefore if we call the function like: ::
+
+ >>> f('grass', 'gis', 'modules')
+ grass
+ gis
+ modules
+
+ or we can define a new list: ::
+
+ >>> words = ['grass', 'gis', 'modules']
+ >>> f(*words)
+ grass
+ gis
+ modules
+
+ we can do the same with keyword arguments, rewrite the above function: ::
+
+ def f(*args, **kargs):
+ for arg in args:
+ print arg
+ for key, value in kargs.items():
+ print "%s = %r" % (key, value)
+
+ now we can use the new function, with: ::
+
+ >>> f('grass', 'gis', 'modules', os = 'linux', language = 'python')
+ grass
+ gis
+ modules
+ os = 'linux'
+ language = 'python'
+
+ or, as before we can, define a dictionary and give the dictionary to
+ the function, like: ::
+
+ >>> keywords = {'os' : 'linux', 'language' : 'python'}
+ >>> f(*words, **keywords)
+ grass
+ gis
+ modules
+ os = 'linux'
+ language = 'python'
+
+ In the Module class we heavily use this language feature to pass arguments
+ and keyword arguments to the grass module.
+ """
+ def __init__(self, cmd, *args, **kargs):
+ self.name = cmd
+ try:
+ # call the command with --interface-description
+ get_cmd_xml = subprocess.Popen([cmd, "--interface-description"],
+ stdout=subprocess.PIPE)
+ except OSError:
+ str_err = "Module %r not found, please check that the module exist"
+ raise GrassError(str_err % self.name)
+ # get the xml of the module
+ self.xml = get_cmd_xml.communicate()[0]
+ # transform and parse the xml into an Element class:
+ # http://docs.python.org/library/xml.etree.elementtree.html
+ tree = fromstring(self.xml)
+
+ for e in tree:
+ if e.tag not in ('parameter', 'flag'):
+ self.__setattr__(e.tag, GETFROMTAG[e.tag](e))
+
+ #
+ # extract parameters from the xml
+ #
+ self.params_list = [Parameter(p) for p in tree.findall("parameter")]
+ self.inputs = TypeDict(Parameter)
+ self.outputs = TypeDict(Parameter)
+ self.required = []
+
+ # Insert parameters into input/output and required
+ for par in self.params_list:
+ if par.input:
+ self.inputs[par.name] = par
+ else:
+ self.outputs[par.name] = par
+ if par.required:
+ self.required.append(par)
+
+ #
+ # extract flags from the xml
+ #
+ flags_list = [Flag(f) for f in tree.findall("flag")]
+ self.flags = TypeDict(Flag)
+ for flag in flags_list:
+ self.flags[flag.name] = flag
+
+ #
+ # Add new attributes to the class
+ #
+ self.run_ = True
+ self.finish_ = True
+ self.env_ = None
+ self.stdin_ = None
+ self.stdin = None
+ self.stdout_ = None
+ self.stderr_ = None
+ diz = {'name': 'stdin', 'required': False,
+ 'multiple': False, 'type': 'all',
+ 'value': None}
+ self.inputs['stdin'] = Parameter(diz=diz)
+ diz['name'] = 'stdout'
+ self.outputs['stdout'] = Parameter(diz=diz)
+ diz['name'] = 'stderr'
+ self.outputs['stderr'] = Parameter(diz=diz)
+ self.popen = None
+
+ if args or kargs:
+ self.__call__(*args, **kargs)
+
+ def __call__(self, *args, **kargs):
+ if not args and not kargs:
+ self.run()
+ return
+ #
+ # check for extra kargs, set attribute and remove from dictionary
+ #
+ if 'flags' in kargs:
+ for flg in kargs['flags']:
+ self.flags[flg].value = True
+ del(kargs['flags'])
+ if 'run_' in kargs:
+ self.run_ = kargs['run_']
+ del(kargs['run_'])
+ if 'stdin_' in kargs:
+ self.inputs['stdin'].value = kargs['stdin_']
+ del(kargs['stdin_'])
+ if 'stdout_' in kargs:
+ self.outputs['stdout'].value = kargs['stdout_']
+ del(kargs['stdout_'])
+ if 'stderr_' in kargs:
+ self.outputs['stderr'].value = kargs['stderr_']
+ del(kargs['stderr_'])
+ if 'env_' in kargs:
+ self.env_ = kargs['env_']
+ del(kargs['env_'])
+ if 'finish_' in kargs:
+ self.finish_ = kargs['finish_']
+ del(kargs['finish_'])
+
+ #
+ # check args
+ #
+ for param, arg in zip(self.params_list, args):
+ param.value = arg
+ for key, val in kargs.items():
+ if key in self.inputs:
+ self.inputs[key].value = val
+ elif key in self.outputs:
+ self.outputs[key].value = val
+ elif key in self.flags:
+ # we need to add this, because some parameters (overwrite,
+ # verbose and quiet) work like parameters
+ self.flags[key].value = val
+ else:
+ raise ParameterError('%s is not a valid parameter.' % key)
+
+ #
+ # check reqire parameters
+ #
+ for par in self.required:
+ if par.value is None:
+ raise ParameterError(
+ "Required parameter <%s> not set." % par.name)
+
+ #
+ # check if execute
+ #
+ if self.run_:
+ self.run()
+
+ def get_bash(self):
+ return ' '.join(self.make_cmd())
+
+ def get_python(self):
+ prefix = self.name.split('.')[0]
+ name = '_'.join(self.name.split('.')[1:])
+ params = ', '.join([par.get_python() for par in self.params_list
+ if par.get_python() != ''])
+ special = ', '.join([flg.get_python()
+ for flg in self.flags.values()
+ if flg.special and flg.get_python() != ''])
+ # pre name par flg special
+ if self.flags and special:
+ return "%s.%s(%s, flags=%r, %s)" % (prefix, name, params,
+ self.flags, special)
+ elif self.flags:
+ return "%s.%s(%s, flags=%r)" % (prefix, name, params, self.flags)
+ elif special:
+ return "%s.%s(%s, %s)" % (prefix, name, params, special)
+ else:
+ return "%s.%s(%s)" % (prefix, name, params)
+
+ def __str__(self):
+ return ' '.join(self.make_cmd())
+
+ def __repr__(self):
+ return "Module(%r)" % self.name
+
+ @property
+ def __doc__(self):
+ """{cmd_name}({cmd_params})
+ """
+ head = DOC['head'].format(cmd_name=self.name,
+ cmd_params=('\n' + # go to a new line
+ # give space under the function name
+ (' ' * (len(self.name) + 1))).join([', '.join(
+ # transform each parameter in string
+ [str(param) for param in line if param is not None])
+ # make a list of parameters with only 3 param per line
+ for line in izip_longest(*[iter(self.params_list)] * 3)]),)
+ params = '\n'.join([par.__doc__ for par in self.params_list])
+ flags = self.flags.__doc__
+ return '\n'.join([head, params, DOC['flag_head'], flags])
+
+ def get_dict(self):
+ dic = {}
+ dic['name'] = self.name
+ dic['inputs'] = [(k, v.value) for k, v in self.inputs.items()
+ if v.value]
+ dic['outputs'] = [(k, v.value) for k, v in self.outputs.items()
+ if v.value]
+ dic['flags'] = [flg for flg in self.flags if self.flags[flg].value]
+ return dic
+
+ def make_cmd(self):
+ args = [self.name, ]
+ for par in self.params_list:
+ if par.value is not None:
+ args.append(str(par))
+ for flg in self.flags:
+ if self.flags[flg].value:
+ args.append(str(self.flags[flg]))
+ return args
+
+ def run(self, node=None):
+ if self.inputs['stdin'].value:
+ self.stdin = self.inputs['stdin'].value
+ self.stdin_ = subprocess.PIPE
+ if self.outputs['stdout'].value:
+ self.stdout_ = self.outputs['stdout'].value
+ if self.outputs['stderr'].value:
+ self.stderr_ = self.outputs['stderr'].value
+ cmd = self.make_cmd()
+ self.popen = subprocess.Popen(cmd,
+ stdin=self.stdin_,
+ stdout=self.stdout_,
+ stderr=self.stderr_,
+ env=self.env_)
+ if self.finish_:
+ self.popen.wait()
+
+ stdout, stderr = self.popen.communicate(input=self.stdin)
+ self.outputs['stdout'].value = stdout if stdout else ''
+ self.outputs['stderr'].value = stderr if stderr else ''
Added: grass/trunk/lib/python/pygrass/modules/interface/parameter.py
===================================================================
--- grass/trunk/lib/python/pygrass/modules/interface/parameter.py (rev 0)
+++ grass/trunk/lib/python/pygrass/modules/interface/parameter.py 2013-04-03 10:45:53 UTC (rev 55603)
@@ -0,0 +1,149 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Apr 2 18:31:47 2013
+
+ at author: pietro
+"""
+
+from __future__ import print_function
+import re
+
+
+from read import GETTYPE, element2dict, DOC
+
+
+class Parameter(object):
+
+ def __init__(self, xparameter=None, diz=None):
+ self._value = None
+ diz = element2dict(xparameter) if xparameter is not None else diz
+ if diz is None:
+ raise TypeError('Xparameter or diz are required')
+ self.name = diz['name']
+ self.required = True if diz['required'] == 'yes' else False
+ self.multiple = True if diz['multiple'] == 'yes' else False
+ # check the type
+ if diz['type'] in GETTYPE:
+ self.type = GETTYPE[diz['type']]
+ self.typedesc = diz['type']
+ self._type = GETTYPE[diz['type']]
+ else:
+ raise TypeError('New type: %s, ignored' % diz['type'])
+
+ self.description = diz.get('description', None)
+ self.keydesc, self.keydescvalues = diz.get('keydesc', (None, None))
+
+ #
+ # values
+ #
+ if 'values' in diz:
+ try:
+ # chek if it's a range string: "3-30"
+ isrange = re.match("(?P<min>\d+)-(?P<max>\d+)",
+ diz['values'][0])
+ if isrange:
+ range_min, range_max = isrange.groups()
+ self.values = range(int(range_min), int(range_max) + 1)
+ self.isrange = diz['values'][0]
+ else:
+ self.values = [self._type(i) for i in diz['values']]
+ self.isrange = False
+ except TypeError:
+ self.values = [self._type(i) for i in diz['values']]
+ self.isrange = False
+
+ #
+ # default
+ #
+ self.default = self._type(
+ diz['default']) if 'default' in diz else None
+ if self.default is not None:
+ self._value = self.default
+
+ self.guisection = diz.get('guisection', None)
+
+ #
+ # gisprompt
+ #
+ if 'gisprompt' in diz:
+ self.type = diz['gisprompt']['prompt']
+ self.input = False if diz['gisprompt']['age'] == 'new' else True
+ else:
+ self.input = True
+
+ def _get_value(self):
+ return self._value
+
+ def _set_value(self, value):
+ if isinstance(value, list) or isinstance(value, tuple):
+ if self.multiple or self.keydescvalues:
+ # check each value
+ self._value = [self._type(val) for val in value]
+ else:
+ str_err = 'The Parameter <%s> does not accept multiple inputs'
+ raise TypeError(str_err % self.name)
+ elif self.typedesc == 'all':
+ self._value = value
+ elif isinstance(value, self._type):
+ if hasattr(self, 'values'):
+ if value in self.values:
+ self._value = value
+ else:
+ raise ValueError('The Parameter <%s>, must be one of: %r' %
+ (self.name, self.values))
+ else:
+ self._value = value
+ else:
+ str_err = 'The Parameter <%s>, require: %s, get: %s instead'
+ raise TypeError(str_err % (self.name, self.typedesc, type(value)))
+
+ # here the property function is used to transform value in an attribute
+ # in this case we define which function must be use to get/set the value
+ value = property(fget=_get_value, fset=_set_value)
+
+ def get_bash(self):
+ if isinstance(self._value, list) or isinstance(self._value, tuple):
+ value = ','.join([str(v) for v in self._value])
+ else:
+ value = str(self._value)
+ return """%s=%s""" % (self.name, value)
+
+ def get_python(self):
+ if not self.value:
+ return ''
+ return """%s=%r""" % (self.name, self._value)
+
+ def __str__(self):
+ return self.get_bash()
+
+ def __repr__(self):
+ str_repr = "Parameter <%s> (required:%s, type:%s, multiple:%s)"
+ return str_repr % (self.name,
+ "yes" if self.required else "no",
+ self.type if self.type in (
+ 'raster', 'vector') else self.typedesc,
+ "yes" if self.multiple else "no")
+
+ # here we use property with a decorator, in this way we mask a method as
+ # a class attribute
+ @property
+ def __doc__(self):
+ """Return the docstring of the parameter
+
+ {name}: {default}{required}{multi}{ptype}
+ {description}{values}"","""
+ if hasattr(self, 'values'):
+ if self.isrange:
+ vals = self.isrange
+ else:
+ vals = ', '.join([repr(val) for val in self.values])
+ else:
+ vals = False
+ keydescvals = "\n (%s)" % ', '.join(self.keydescvalues)
+ return DOC['param'].format(name=self.name,
+ default=repr(self.default) + ', ' if self.default else '',
+ required='required, ' if self.required else 'optional, ',
+ multi='multi' if self.multiple else '',
+ ptype=self.typedesc, description=self.description,
+ values='\n Values: {0}'.format(vals) if vals else '',
+ keydescvalues= keydescvals if self.keydescvalues else '')
Added: grass/trunk/lib/python/pygrass/modules/interface/read.py
===================================================================
--- grass/trunk/lib/python/pygrass/modules/interface/read.py (rev 0)
+++ grass/trunk/lib/python/pygrass/modules/interface/read.py 2013-04-03 10:45:53 UTC (rev 55603)
@@ -0,0 +1,99 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Apr 2 18:30:34 2013
+
+ at author: pietro
+"""
+from __future__ import print_function
+
+
+def read_keydesc(par):
+ name = par.text.strip()
+ items = [e.text.strip() for e in par.findall('item')]
+ #import ipdb; ipdb.set_trace()
+ return name, tuple(items) if len(items) > 1 else None
+
+
+#
+# this dictionary is used to extract the value of interest from the xml
+# the lambda experssion is used to define small simple functions,
+# is equivalent to: ::
+#
+# def f(p):
+# return p.text.strip()
+#
+# and then we call f(p)
+#
+GETFROMTAG = {
+ 'description': lambda p: p.text.strip(),
+ 'keydesc': read_keydesc,
+ 'gisprompt': lambda p: dict(p.items()),
+ 'default': lambda p: p.text.strip(),
+ 'values': lambda p: [e.text.strip() for e in p.findall('value/name')],
+ 'value': lambda p: None,
+ 'guisection': lambda p: p.text.strip(),
+ 'label': lambda p: p.text.strip(),
+ 'suppress_required': lambda p: None,
+ 'keywords': lambda p: p.text.strip(),
+}
+
+GETTYPE = {
+ 'string': str,
+ 'integer': int,
+ 'float': float,
+ 'double': float,
+ 'all': lambda x: x,
+}
+
+
+def element2dict(xparameter):
+ diz = dict(xparameter.items())
+ for p in xparameter:
+ if p.tag in GETFROMTAG:
+ diz[p.tag] = GETFROMTAG[p.tag](p)
+ else:
+ print('New tag: %s, ignored' % p.tag)
+ return diz
+
+
+# dictionary used to create docstring for the objects
+DOC = {
+ #------------------------------------------------------------
+ # head
+ 'head': """{cmd_name}({cmd_params})
+
+Parameters
+----------
+
+""",
+ #------------------------------------------------------------
+ # param
+ 'param': """{name}: {default}{required}{multi}{ptype}
+ {description}{values}{keydescvalues}""",
+ #------------------------------------------------------------
+ # flag_head
+ 'flag_head': """
+Flags
+------
+""",
+ #------------------------------------------------------------
+ # flag
+ 'flag': """{name}: {default}
+ {description}""",
+ #------------------------------------------------------------
+ # foot
+ 'foot': """
+Special Parameters
+------------------
+
+The Module class have some optional parameters which are distinct using a final
+underscore.
+
+run_: True, optional
+ If True execute the module.
+finish_: True, optional
+ If True wait untill the end of the module execution, and store the module
+ outputs into stdout, stderr attributes of the class.
+stdin_: PIPE,
+ Set the standard input
+"""}
Added: grass/trunk/lib/python/pygrass/modules/interface/typedict.py
===================================================================
--- grass/trunk/lib/python/pygrass/modules/interface/typedict.py (rev 0)
+++ grass/trunk/lib/python/pygrass/modules/interface/typedict.py 2013-04-03 10:45:53 UTC (rev 55603)
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Apr 2 18:37:02 2013
+
+ at author: pietro
+"""
+try:
+ from collections import OrderedDict
+except ImportError:
+ from grass.pygrass.orderdict import OrderedDict
+
+
+class TypeDict(OrderedDict):
+ def __init__(self, dict_type, *args, **kargs):
+ self._type = dict_type
+ super(TypeDict, self).__init__(*args, **kargs)
+
+ def __getattr__(self, key):
+ if key in self:
+ return self[key].value
+ return OrderedDict.__getattr__(self, key)
+
+ def __setattr__(self, key, value):
+ if key in self:
+ self[key].value = value
+ else:
+ OrderedDict.__setattr__(self, key, value)
+
+ def __dir__(self):
+ return self.keys()
+
+ def __setitem__(self, key, value):
+ if isinstance(value, self._type):
+ super(TypeDict, self).__setitem__(key, value)
+ else:
+ cl = repr(self._type).translate(None, "'<> ").split('.')
+ str_err = 'The value: %r is not a %s object'
+ raise TypeError(str_err % (value, cl[-1].title()))
+
+ @property
+ def __doc__(self):
+ return '\n'.join([self.__getitem__(obj).__doc__
+ for obj in self.__iter__()])
+
+ def __call__(self):
+ return [self.__getitem__(obj) for obj in self.__iter__()]
+
+ def used(self):
+ key_dict = {}
+ for key in self:
+ if self.__getattr__(key):
+ key_dict[key] = self.__getattr__(key)
+ return key_dict
\ No newline at end of file
Added: grass/trunk/lib/python/pygrass/modules/shortcuts.py
===================================================================
--- grass/trunk/lib/python/pygrass/modules/shortcuts.py (rev 0)
+++ grass/trunk/lib/python/pygrass/modules/shortcuts.py 2013-04-03 10:45:53 UTC (rev 55603)
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Apr 2 18:49:11 2013
+
+ at author: pietro
+"""
+from __future__ import print_function
+import fnmatch
+
+
+from grass.script.core import get_commands
+from grass.pygrass.modules.interface.module import Module
+
+
+_CMDS = list(get_commands()[0])
+_CMDS.sort()
+
+
+class MetaModule(object):
+ """Example how to use MetaModule
+
+ >>> g = MetaModule('g')
+ >>> g_mlist = g.mlist
+ >>> g_mlist.name
+ 'g.mlist'
+ >>> g_mlist.required
+ [Parameter <type> (required:yes, type:string, multiple:yes)]
+ >>> g_mlist.inputs.type = 'rast'
+ >>> g_mlist.stdout_ = -1
+ >>> g_mlist.run()
+ >>> g_mlist.outputs.stdout # doctest: +ELLIPSIS
+ 'basins...soils...'
+ >>> r = MetaModule('r')
+ >>> what = r.what
+ >>> what.description
+ 'Queries raster maps on their category values and category labels.'
+ >>> what.inputs.map = 'elevation'
+ >>> what.inputs.coordinates = [640000,220500] # doctest: +SKIP
+ >>> what.run() # doctest: +SKIP
+ """
+ def __init__(self, prefix, cls=None):
+ self.prefix = prefix
+ self.cls = cls if cls else Module
+
+ def __dir__(self):
+ return [mod[(len(self.prefix) + 1):].replace('.', '_')
+ for mod in fnmatch.filter(_CMDS, "%s.*" % self.prefix)]
+
+ def __getattr__(self, name):
+ return self.class_('%s.%s' % (self.prefix, name.replace('_', '.')))
+
+
+# http://grass.osgeo.org/grass70/manuals/html70_user/full_index.html
+#[ d.* | db.* | g.* | i.* | m.* | ps.* | r.* | r3.* | t.* | v.* ]
+#
+# d.* display commands
+# db.* database commands
+# g.* general commands
+# i.* imagery commands
+# m.* miscellaneous commands
+# ps.* postscript commands
+# r.* raster commands
+# r3.* raster3D commands
+# t.* temporal commands
+# v.* vector commands
+
+display = MetaModule('d')
+database = MetaModule('db')
+general = MetaModule('g')
+imagery = MetaModule('i')
+miscellaneous = MetaModule('m')
+postscript = MetaModule('ps')
+raster = MetaModule('r')
+raster3D = MetaModule('r3')
+temporal = MetaModule('t')
+vector = MetaModule('v')
Property changes on: grass/trunk/lib/python/pygrass/modules/shortcuts.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
More information about the grass-commit
mailing list