gmodules.py 4.9 KB

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