[Tutor] Interacting with stderr

Cameron Simpson cs at zip.com.au
Sun Aug 31 07:22:14 CEST 2014


On 30Aug2014 22:32, Crush <crushed26 at gmail.com> wrote:
>Thank you Allan for your criticism. Please see the below changes. As far as the embedded loops, I know no other way to achieve the same out come.

Regrettably I've lost Alan's email on that (I had it:-).

It looks like you've taken he concern over nested use of p.stderr too 
literally. It loops like you avoid using the same stderr by restarting 
"test_loop.sh" in the inner loops and reparsing their error outputs. I'm fairly 
sure that is not what Alan intended and also not what you want to be doing.  
Please explain your thinking here.

Regarding nested loops on the same iterable:

It is ok to nested use of an iterator, with some caution. The typical use case 
is some sort of nesting parse of the output. For example, if you were looking 
for the word "Segmentation", and then intending to act specially on all 
following lines until some marker. Another gleaming example that springs to 
mind would be gathering up python stack traces (multiline outputs) in some 
error log.

You'd fairly naturally end up with code a bit like this:

   for line in p.stderr:
     if "Segemntation" in line:
       # ok, found the start line
       for inner_line in p.stderr:
         if "end segemntation marker" in inner_line:
           break
         ... do something with inner_line

That essentially has the effect that all the lines from "Segmentation" to "end 
segemntation marker" are processed specially by the inner loop, and after you 
see the end marker you return to the outer loop, looking for the next occurence 
of "Segmentation".

There is really only one pitfall with this, and that is the possibility that 
the end marker line is itself important.

Imagine you had two inner loops, one for the "Segmentation" section and another 
to handle some other section, like this:

   for line in p.stderr:
     if "Segemntation" in line:
       # ok, found the start line
       ... do the "Segmentation" section ...
     elif "other-section" in line:
       # ok, found the start line
       ... do the "other-section" section ...
     else:
       # boring line, report it or discard it etc

Simple and straight forward, yes? It will nicely handly input like this:

    blah
    blah
    begin Segmentation
    >> stuff
    >> more stuff
    end segmentation marker
    blah
    blah
    begin other-section
    >> other stuff
    >> even more other stuff
    end the other section
    blah

However, consider the case where the end marker for the "Segmentation" section 
is not some special line generated by the "Segmentation" event, but simply some 
line that is not a match. Like the beginning of an "other-section" section. Eg:

    blah
    blah
    begin Segmentation
    >> stuff
    >> more stuff
    begin other-section
    >> other stuff
    >> even more other stuff
    blah

With input like that, the "end of section" line is itself an important line 
that needs to be considered. But the loop as written "consumes" the marker 
line, and it is not available for recognition on the next outer loop pass 
(because that fetches the next line).

This is where nested loops on the same iterable can have an issue. There are 
several things you can do about it depending on your code and your preferences.  

>def kill_proc(process1, process2):
>   i = psutil.Popen(["ps", "cax"], stdout=PIPE)
>   out, err = i.communicate()
>   for proc in psutil.process_iter():
>       if proc.name == process1 and process2:
>           proc.kill()

This function won't work as you intend. Specificly, the "if" test is wrong. You 
want to change:

   if proc.name == process1 and process2:

into:

   if proc.name == process1 and or proc.name == process2:

or perhaps:

   if proc.name in (process1, process2):

and your psutil.Popen call looks... confused. Popen is a subprocess function, 
not part of psutil (I think). And you don't use either "out" or "err" after you 
collect them, so why use .communicate?

Also, this will kill _every_ instance of mbplay and avconv, not just the ones 
you started. You would be better off just killing your own.

The rest of your code's function is not clear to me. Does it work?

Cheers,
Cameron Simpson <cs at zip.com.au>


More information about the Tutor mailing list