[GRASS-SVN] r60979 - in sandbox/wenzeslaus/gunittest: . testsuite
svn_grass at osgeo.org
svn_grass at osgeo.org
Wed Jun 25 21:17:20 PDT 2014
Author: wenzeslaus
Date: 2014-06-25 21:17:20 -0700 (Wed, 25 Jun 2014)
New Revision: 60979
Added:
sandbox/wenzeslaus/gunittest/gmodules.py
sandbox/wenzeslaus/gunittest/utils.py
Modified:
sandbox/wenzeslaus/gunittest/__init__.py
sandbox/wenzeslaus/gunittest/testsuite/test_doctests.py
Log:
gunittest: adding custom fucntions for running modules (commands) based on start_command() function
Modified: sandbox/wenzeslaus/gunittest/__init__.py
===================================================================
--- sandbox/wenzeslaus/gunittest/__init__.py 2014-06-25 21:58:42 UTC (rev 60978)
+++ sandbox/wenzeslaus/gunittest/__init__.py 2014-06-26 04:17:20 UTC (rev 60979)
@@ -0,0 +1 @@
+import case, checkers, gmodules, utils
Added: sandbox/wenzeslaus/gunittest/gmodules.py
===================================================================
--- sandbox/wenzeslaus/gunittest/gmodules.py (rev 0)
+++ sandbox/wenzeslaus/gunittest/gmodules.py 2014-06-26 04:17:20 UTC (rev 60979)
@@ -0,0 +1,133 @@
+# -*- coding: utf-8 -*-
+
+import subprocess
+from grass.script.core import start_command
+
+from .utils import do_doctest_gettext_workaround
+
+
+class CalledModuleError(subprocess.CalledProcessError):
+ def __init__(self, returncode, module, kwargs, errors=None):
+ # expecting module name to be args[0]
+ super(CalledModuleError, self).__init__(returncode, module)
+ # TODO: this must be somewhere when doctest is called, not here
+ # TODO: ultimate solution is not to use _ as a buildin in lib/python
+ # for now it is the only place where it works
+ do_doctest_gettext_workaround()
+ # TODO: format parameters
+ # TODO: ignore std* params
+ msg = _("Module run %s %s ended with error") % (module, kwargs)
+ msg += _("\nProcess ended with non-zero return code %s") % returncode
+ if errors:
+ msg += _(". See the following errors:\n%s") % errors
+ else:
+ msg += _(". See errors in the (error) output.")
+ self.msg = msg
+ # TODO: handle other parameters
+
+ def __str__(self):
+ return self.msg
+
+
+def run_module(module, **kwargs):
+ """Run module with parameters given in `kwargs`.
+
+ :param str module: module name
+ :param kwargs: module parameters
+
+ :raises CalledModuleError: if module return code is non-zero
+ """
+ process = start_command(module, **kwargs)
+ returncode = process.wait()
+ if returncode:
+ raise CalledModuleError(returncode, module, kwargs)
+
+
+def read_module(module, **kwargs):
+ """Run module with parameters given in `kwargs` and return its output.
+
+ :param str module: module name
+ :param kwargs: module parameters
+
+ :raises CalledModuleError: if module return code is non-zero
+ """
+ if 'stdout' in kwargs:
+ raise ValueError('stdout argument not allowed, it would be overridden.')
+ kwargs['stdout'] = subprocess.PIPE
+ process = start_command(module, **kwargs)
+ output = process.communicate()[0]
+ returncode = process.poll()
+ if returncode:
+ raise CalledModuleError(returncode, module, kwargs)
+ return output
+
+
+def write_module(module, stdin, **kwargs):
+ """Run module with given parameters and feed module standard input.
+
+ :param str module: module name
+ :param stdin: string to be used as module standard input (stdin)
+ :param kwargs: module parameters
+
+ :raises CalledModuleError: if module return code is non-zero
+ """
+ if not stdin:
+ raise ValueError('stdin argument is required.')
+ kwargs['stdin'] = subprocess.PIPE # to be able to send data to stdin
+ process = start_command(module, **kwargs)
+ process.communicate(stdin)
+ returncode = process.poll()
+ if returncode:
+ raise CalledModuleError(returncode, module, kwargs)
+
+
+def call_module(module, stdin=None, merge_stderr=False, **kwargs):
+ r"""Run module with parameters given in `kwargs` and return its output.
+
+ >>> print call_module('g.region', flags='pg') # doctest: +ELLIPSIS
+ n=...
+ s=...
+ w=...
+ >>> call_module('g.region', aabbbccc='notexist') # doctest: +IGNORE_EXCEPTION_DETAIL
+ Traceback (most recent call last):
+ ...
+ CalledModuleError: Module run g.region ... ended with error
+ >>> call_module('m.proj', flags='i', input='-', stdin="50.0 41.5")
+ '8642890.65|6965155.61|0.00\n'
+
+ If `stdin` is not set and `kwargs` contains ``input`` with value set
+ to ``-`` (dash), the function raises an error.
+
+ :param str module: module name
+ :param stdin: string to be used as module standard input (stdin) or `None`
+ :param merge_stderr: if the standard error output should be merged with stdout
+ :param kwargs: module parameters
+
+ :returns: module standard output (stdout)
+
+ :raises CalledModuleError: if module return code is non-zero
+ :raises ValueError: if the parameters are not correct
+ """
+ # implemenation inspired by subprocess.check_output() function
+ if stdin:
+ kwargs['stdin'] = subprocess.PIPE # to be able to send data to stdin
+ elif 'input' in kwargs and kwargs['input'] != '-':
+ raise ValueError(_("stdin must be set when input='-'"))
+ if 'stdout' in kwargs:
+ raise ValueError(_("stdout argument not allowed, it would be overridden"))
+ if 'stderr' in kwargs:
+ raise ValueError(_("stderr argument not allowed, it would be overridden"))
+
+ kwargs['stdout'] = subprocess.PIPE
+ if merge_stderr:
+ kwargs['stderr'] = subprocess.STDOUT
+ else:
+ kwargs['stderr'] = subprocess.PIPE
+ process = start_command(module, **kwargs)
+ # input=None means no stdin (our default)
+ # for stderr=STDOUT errors in None which is fine for CalledModuleError
+ output, errors = process.communicate(input=stdin)
+ returncode = process.poll()
+ if returncode:
+ raise CalledModuleError(returncode, module, kwargs, errors)
+ return output
Modified: sandbox/wenzeslaus/gunittest/testsuite/test_doctests.py
===================================================================
--- sandbox/wenzeslaus/gunittest/testsuite/test_doctests.py 2014-06-25 21:58:42 UTC (rev 60978)
+++ sandbox/wenzeslaus/gunittest/testsuite/test_doctests.py 2014-06-26 04:17:20 UTC (rev 60979)
@@ -26,5 +26,7 @@
def load_tests(loader, tests, ignore):
+ # this should be called at some top level
+ tests.addTests(doctest.DocTestSuite(gunittest.gmodules))
tests.addTests(doctest.DocTestSuite(gunittest.checkers))
return tests
Added: sandbox/wenzeslaus/gunittest/utils.py
===================================================================
--- sandbox/wenzeslaus/gunittest/utils.py (rev 0)
+++ sandbox/wenzeslaus/gunittest/utils.py 2014-06-26 04:17:20 UTC (rev 60979)
@@ -0,0 +1,27 @@
+import sys
+
+
+def do_doctest_gettext_workaround():
+ """Setups environment for doing a doctest with gettext usage.
+
+ When using gettext with dynamically defined underscore function
+ (``_("For translation")``), doctest does not work properly. One option is
+ to use `import as` instead of dynamically defined underscore function but
+ this would require change all modules which are used by tested module.
+ This should be considered for the future. The second option is to define
+ dummy underscore function and one other function which creates the right
+ environment to satisfy all. This is done by this function.
+ """
+ def new_displayhook(string):
+ """A replacement for default `sys.displayhook`"""
+ if string is not None:
+ sys.stdout.write("%r\n" % (string,))
+
+ def new_translator(string):
+ """A fake gettext underscore function."""
+ return string
+
+ sys.displayhook = new_displayhook
+
+ import __builtin__
+ __builtin__._ = new_translator
More information about the grass-commit
mailing list