1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
# -*- coding: utf-8 -*-
"""Specialized interfaces for invoking modules for testing framework
Copyright (C) 2014 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 GIS
for details.
:authors: Vaclav Petras, Soeren Gebbert
"""
import subprocess
from grass.script.core import start_command
from grass.exceptions import CalledModuleError
from grass.pygrass.modules import Module
from .utils import do_doctest_gettext_workaround
class SimpleModule(Module):
"""Simple wrapper around pygrass.modules.Module to make sure that
run\_, finish\_, stdout and stderr are set correctly.
>>> mapcalc = SimpleModule('r.mapcalc', expression='test_a = 1',
... overwrite=True)
>>> mapcalc.run()
Module('r.mapcalc')
>>> mapcalc.popen.returncode
0
>>> colors = SimpleModule('r.colors',
... map='test_a', rules='-', stdin_='1 red')
>>> colors.run()
Module('r.colors')
>>> colors.popen.returncode
0
>>> str(colors.inputs.stdin)
'1 red'
>>> str(colors.outputs.stdout)
''
>>> colors.outputs.stderr.strip()
"Color table for raster map <test_a> set to 'rules'"
"""
def __init__(self, cmd, *args, **kargs):
for banned in ['stdout_', 'stderr_', 'finish_', 'run_']:
if banned in kargs:
raise ValueError('Do not set %s parameter'
', it would be overriden' % banned)
kargs['stdout_'] = subprocess.PIPE
kargs['stderr_'] = subprocess.PIPE
kargs['finish_'] = True
kargs['run_'] = False
Module.__init__(self, cmd, *args, **kargs)
def call_module(module, stdin=None,
merge_stderr=False, capture_stdout=True, capture_stderr=True,
**kwargs):
r"""Run module with parameters given in `kwargs` and return its output.
>>> print call_module('g.region', flags='pg') # doctest: +ELLIPSIS
projection=...
zone=...
n=...
s=...
w=...
>>> call_module('m.proj', flags='i', input='-', stdin="50.0 41.5")
'8642890.65|6965155.61|0.00\n'
>>> call_module('g.region', aabbbccc='notexist') # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
CalledModuleError: Module run g.region ... ended with error
If `stdin` is not set and `kwargs` contains ``input`` with value set
to ``-`` (dash), the function raises an error.
Note that ``input`` nor ``output`` parameters are used by this
function itself, these are usually module parameters which this
function just passes to it. However, when ``input`` is in parameters
the function checks if its values is correct considering value of
``stdin`` parameter.
: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) as string or None if apture_stdout is False
:raises CalledModuleError: if module return code is non-zero
:raises ValueError: if the parameters are not correct
.. note::
The data read is buffered in memory, so do not use this method
if the data size is large or unlimited.
"""
# TODO: remove this:
do_doctest_gettext_workaround()
# implementation inspired by subprocess.check_output() function
if stdin:
if 'input' in kwargs and kwargs['input'] != '-':
raise ValueError(_("input='-' must be used when stdin is specified"))
if stdin == subprocess.PIPE:
raise ValueError(_("stdin must be string or buffer, not PIPE"))
kwargs['stdin'] = subprocess.PIPE # to be able to send data to stdin
elif 'input' in kwargs and kwargs['input'] == '-':
raise ValueError(_("stdin must be used when input='-'"))
if merge_stderr and not (capture_stdout and capture_stderr):
raise ValueError(_("You cannot merge stdout and stderr and not capture them"))
if 'stdout' in kwargs:
raise TypeError(_("stdout argument not allowed, it could be overridden"))
if 'stderr' in kwargs:
raise TypeError(_("stderr argument not allowed, it could be overridden"))
if capture_stdout:
kwargs['stdout'] = subprocess.PIPE
if capture_stderr:
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 no stdout, output is None which is out interface
# for stderr=STDOUT or no stderr, errors is 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
|