gmodules.py 5.0 KB

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