[GRASS-dev] [GRASS GIS] #2326: Command functions in grass.script.core miss a correct error reporting
GRASS GIS
trac at osgeo.org
Tue Jun 24 15:59:44 PDT 2014
#2326: Command functions in grass.script.core miss a correct error reporting
--------------------------------+-------------------------------------------
Reporter: wenzeslaus | Owner: grass-dev@…
Type: enhancement | Status: new
Priority: major | Milestone: 7.1.0
Component: Python | Version: svn-trunk
Keywords: script, exceptions | Platform: All
Cpu: Unspecified |
--------------------------------+-------------------------------------------
Comment(by wenzeslaus):
Replying to [comment:8 glynn]:
> Replying to [comment:6 wenzeslaus]:
>
> > Here are my suggestions for changes in `grass.script.core`.
>
> These changes are excessive. All that is required is to check the exit
code and generate an error if it is non-zero. If the child process returns
a zero exit code, the existing behaviour should not be affected.
>
> In particular, stderr should not be captured. It isn't limited to errors
(e.g. messages and percentages are written to stderr), and such
information should normally be sent to the terminal as its generated.
>
That's true but I don't know how to solve the following case.
I'm currently testing the testing framework. When I make a mistake in my
testing code, an exception (`ValueError` in this case) is raised:
{{{
> python -m unittest discover sandbox/wenzeslaus/gunittest
..DBMI-SQLite driver error:
Error in sqlite3_prepare():
SELECT cat, YEAR_BUILTX FROM bridges
no such column: YEAR_BUILTX
DBMI-SQLite driver error:
Error in sqlite3_prepare():
SELECT cat, YEAR_BUILTX FROM bridges
no such column: YEAR_BUILTX
ERROR: Column type not supported
E............................
======================================================================
ERROR: test_assertVectorFitsUnivar
(testsuite.test_assertions.TestRasterMapAssertations)
----------------------------------------------------------------------
Traceback (most recent call last):
File
"/home/vasek/dev/grass/sandbox/wenzeslaus/gunittest/testsuite/test_assertions.py",
line 80, in test_assertVectorFitsUnivar
reference=V_UNIVAR_BRIDGES_WIDTH_SUBSET)
File "/usr/lib/python2.7/unittest/case.py", line 475, in assertRaises
callableObj(*args, **kwargs)
File "/home/vasek/dev/grass/sandbox/wenzeslaus/gunittest/case.py", line
102, in assertVectorFitsUnivar
reference=reference, msg=msg, sep='=')
File "/home/vasek/dev/grass/sandbox/wenzeslaus/gunittest/case.py", line
66, in assertCommandKeyValue
": %s\n" % (module, ", ".join(missing)))
ValueError: v.univar output does not contain the following keys provided
in reference: max, mean, min, n, nmissing, nnull, range, sum
----------------------------------------------------------------------
Ran 31 tests in 1.227s
FAILED (errors=1)
}}}
But of course the error report is misleading because the problem is not in
the "key provided" or "v.univar output", the problem is that I used
current version of `read_command` which does not raise. If the
`read_command` function raise, I would get `ScriptError` (or whatever)
with an error message saying that `v.univar` failed. But this is not
enough to fix the problem.
If we catch the stderr we can report what has happened. In this case I
would get a message about wrong column name. However, if we will let
stderr be printed to the console, we will have to search in the output for
the errors which does not contain any information about command which
caused them (unfortunately, in this case they are even wrong and not in
GRASS format).
The only option I see is to have both functions. One capturing the stderr
for cases when the module (command) is used more like a function and one
letting the stderr go wherever it is directed. But it don't like it
because this applies at least to three functions which would create 6
different functions. Parameter, as noted bellow, might be a more
acceptable solution.
> Also, checking kwargs!["args"] isn't useful.
If you mean `cmd = kwargs.get("args")`, this is from `Popen`, source code,
I don't know what exactly they are trying to accomplish.
>
> In most cases, the failure to check exit codes was inherited from the
original shell script. run_command() replaces "simple" command execution,
read_command() replaces backticks. pipe_command() and feed_command() are
used for a GRASS command at one end of a pipeline. write_command()
replaces "echo data | command".
>
Beginning and end of the pipe line still does not convince me about
usefulness of the functions. I still see them as unnecessary complication
of interface. If one need something like this, he or she can use
`start_commnad` directly. Direct working with `Popen` object cannot be
avoided in any case.
> My suggestion would be that the functions which wait for the process to
terminate (run_command, read_command, write_command) should call a
check_status() function, e.g.
> {{{
> def check_status(p, args, kwargs):
> if p.wait() == 0:
> return 0
> raise CalledCommandError(p.returncode, args, kwargs)
> }}}
>
> run_command() and write_command() would replace
> {{{
> return p.wait()
> }}}
> with
> {{{
> return check_status(p)
> }}}
>
I don't agree with the name. It does not `check_status` it waits and then
checks status, so I would suggest `_wait_check_status`.
> This usage pattern would allow check_status() to be modified to provide
more options regarding error handling, e.g. raise an exception, call
fatal(), or just return the exit code, with the behaviour controlled by a
variable or a keyword argument.
>
Sure, this is the way to go (`called_command_error` from comment:7 is
doing something like that).
> Alternatively, we could just modify the Popen wrapper to provide a
modified .wait() method which does this automatically. This would probably
"do the right thing" for scripts which use start_command() etc and
subsequently call p.wait() themselves.
I vote against. The lower level API (when using `Popen` object) should
behave in the same way as Python `Popen` to allow users/programmers switch
between them easily. Moreover, it would be a violation of some OOP
principles, although in case of Python not so big violation, I believe.
--
Ticket URL: <http://trac.osgeo.org/grass/ticket/2326#comment:9>
GRASS GIS <http://grass.osgeo.org>
More information about the grass-dev
mailing list