Re: [Tutor] Mocking with mock in unit testing

2014-01-17 Thread James Chapman
Thanks eryksun.

There's a list for testing in python which I also posed the question to and
got pretty much the same answer as you provided.

The line if proc.returncode != 1 was a mistake. That 1 should have been a
zero.

As this question was just about mock and not really dealing with the bad
return code or exception handling or raising my final working example looks
like this:


pinger.py



import subprocess
 class Pinger(object):

def ping_host(self, host_to_ping):
cmd_string = 'ping %s' % (host_to_ping)
cmd_args = cmd_string.split()
proc = subprocess.Popen(cmd_args, shell=True)
proc.wait()
if proc.returncode != 0:
raise Exception('Error code was: %d' % (proc.returncode))

 if __name__ == '__main__':
PINGER = Pinger()
PINGER.ping_host('localhost')





test_pinger.py



import mockimport unittestimport pinger
 class Test_Pinger(unittest.TestCase):

def test_ping_host_succeeds(self):
pinger = pinger.Pinger()
with mock.patch(pinger.subprocess) as subprocess:
subprocess.Popen.return_value.returncode = 0
pinger.ping_host('localhost')
subprocess.Popen.assert_called_once_with(['ping','localhost'],
shell=True)

def test_ping_host_fails_and_throws_exception(self):
pinger = pinger.Pinger()
with mock.patch('pinger.subprocess') as subprocess:
subprocess.Popen.return_value.returncode = 1
self.assertRaises(Exception, pinger.ping_host, 'localhost')

 if __name__ == '__main__':
unittest.main()






--
James


On 17 January 2014 01:05, eryksun eryk...@gmail.com wrote:

 On Thu, Jan 16, 2014 at 5:32 AM, James Chapman ja...@uplinkzero.com
 wrote:
 
  In my unittest I don't want to run the ping command, (It might not be
  available on the build system) I merely want to check that a call to
  subprocess.Popen is made and that the parameters are what I expect?

 You can mock `Popen` where it's accessed.

 @mock.patch('subprocess.Popen')
 def test_ping_host(self, Popen):
 Popen.return_value.returncode = 0
 pinger = Pinger()
 pinger.ping_host('127.0.0.1')
 Popen.assert_called_once_with(['ping','127.0.0.1'], shell=True)

 If the tutor_q module imported `Popen` into its namespace, then you'd
 patch tutor_q.Popen.

  def ping_host(self, host_to_ping):
  cmd_string = 'ping %s' % (host_to_ping)
  cmd_args = cmd_string.split()

 Splitting on spaces doesn't work generally. Use `shlex.split`, or
 build the list manually.

  proc = subprocess.Popen(cmd_args, shell=True)

 Maybe you really need the shell to process your command, but generally
 there's no reason to run the shell just to have it execute the command
 and wait. Plus it opens the door to security exploits.

  proc.wait()
  if proc.returncode != 1:
  raise Exception('Error code was: %d' % (proc.returncode))

 A non-zero return code signals an error. When using `Popen` directly,
 you can be consistent with `check_call` and `check_output` if you
 raise a `CalledProcessError` in this case:

 retcode = proc.wait()
 if retcode:
 raise subprocess.CalledProcessError(retcode, cmd_args)

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Mocking with mock in unit testing

2014-01-17 Thread eryksun
On Fri, Jan 17, 2014 at 4:58 AM, James Chapman ja...@uplinkzero.com wrote:
 import mock
 import unittest
 import pinger

 class Test_Pinger(unittest.TestCase):

 def test_ping_host_succeeds(self):
 pinger = pinger.Pinger()

Are you using CPython? That raises an UnboundLocalError. Take a look
at the CPython bytecode:

def test(self):
pinger = pinger.Pinger()

 dis.dis(test)
  2   0 LOAD_FAST1 (pinger)
  3 LOAD_ATTR0 (Pinger)
  6 CALL_FUNCTION0
  9 STORE_FAST   1 (pinger)
 12 LOAD_CONST   0 (None)
 15 RETURN_VALUE

Notice LOAD_FAST(1), where fast local 1 is the local variable
`pinger`. The value isn't assigned yet, and LOAD_FAST doesn't search
globals and builtins. You need a unique name for the instance, such as
`test_pinger`. Then the compiler knows to use LOAD_GLOBAL:

def test(self):
test_pinger = pinger.Pinger()

 dis.dis(test)
  2   0 LOAD_GLOBAL  0 (pinger)
  3 LOAD_ATTR1 (Pinger)
  6 CALL_FUNCTION0
  9 STORE_FAST   1 (test_pinger)
 12 LOAD_CONST   0 (None)
 15 RETURN_VALUE

Here's a version using a decorator instead:

@mock.patch('pinger.subprocess')
def test_ping_host_succeeds(self, subprocess):
subprocess.Popen.return_value.returncode = 0
test_pinger = pinger.Pinger()
test_pinger.ping_host('localhost')
subprocess.Popen.assert_called_once_with(['ping','localhost'],
 shell=True)
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Mocking with mock in unit testing

2014-01-17 Thread Steven D'Aprano
On Fri, Jan 17, 2014 at 09:58:06AM +, James Chapman wrote:

 As this question was just about mock and not really dealing with the bad
 return code or exception handling or raising my final working example looks
 like this:

Your final *working* example? I don't think so. I can see at least two 
syntax errors, and a programming error.

A word to the wise: code isn't working until you've actually seen it 
work :-)



 pinger.py
 
 
 
 import subprocess
  class Pinger(object):

There is your first SyntaxError, a stray space ahead of the class 
keyword.


 def ping_host(self, host_to_ping):
 cmd_string = 'ping %s' % (host_to_ping)
 cmd_args = cmd_string.split()

This is not a programming error, but it is wasteful. First you join two 
strings: ping, and the host. Then, having glued them together, you 
split them apart exactly where you glued them.

Better to do something like: 

cmd_args = [ping, host_to_ping]

assuming that you know that host_to_ping is only a single word.


 proc = subprocess.Popen(cmd_args, shell=True)

Why shell=True?

The documentation for subprocess.Popen says:

The shell argument (which defaults to False) specifies whether to 
use the shell as the program to execute. If shell is True, it is
recommended to pass args as a string rather than as a sequence.

and also warns that shell=True can be a security hazard. Do you have a 
good reason for using it?

http://docs.python.org/2/library/subprocess.html



 proc.wait()
 if proc.returncode != 0:
 raise Exception('Error code was: %d' % (proc.returncode))
 
  if __name__ == '__main__':
 PINGER = Pinger()
 PINGER.ping_host('localhost')
 
 
 
 
 
 test_pinger.py
 
 
 
 import mockimport unittestimport pinger
  class Test_Pinger(unittest.TestCase):

And here you have two more SyntaxErrors: missing commas between 
arguments to import, and a stray space before the class again.


 def test_ping_host_succeeds(self):
 pinger = pinger.Pinger()

And here is your programming error. Unlike some programming languages 
(Lua, I think) in Python you cannot use the same name to refer to both a 
global variable and a local variable inside the same function. In 
Python, either the variable is treated as a global, or as a local, but 
not both.

The rules Python uses to decide are:

* if you declare a name global inside the function, then it is 
  treated as global inside that function;

* otherwise, if you assign a value to the name *anywhere* inside 
  the function, it is treated as local;

* otherwise it is global.

So in your example, you assign a value to the name pinger, so it is 
treated as local. The offending line of code looks like this:

pinger = pinger.Pinger()

Your *intention* is to look up the global pinger, which is a module, 
then create a pinger.Pinger() instance, then assign it to the local 
variable pinger. But that's not what Python does. Instead, it tries to 
look up a local variable pinger, finds it doesn't have one, and raises 
an UnboundLocalError exception.

I recommend you change the name of the local variable pinger to 
something else, so it no longer clashes with the pinger module name.


Hope this is of help to you,



-- 
Steven
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Mocking with mock in unit testing

2014-01-17 Thread James Chapman
Erm...?

CPython yeah.

If I rename pinger.py to tutor.py and change the unittest it runs fine.
Why?


-
import mock
import unittest
import tutor

class Test_Pinger(unittest.TestCase):

def test_ping_host_succeeds(self):
pinger = tutor.Pinger()
with mock.patch(tutor.subprocess) as subprocess:
subprocess.Popen.return_value.returncode = 0
pinger.ping_host('localhost')
subprocess.Popen.assert_called_once_with(['ping','localhost'],
shell=True)


def test_ping_host_fails_and_throws_exception(self):
pinger = tutor.Pinger()
with mock.patch('tutor.subprocess') as subprocess:
subprocess.Popen.return_value.returncode = 1
self.assertRaises(Exception, pinger.ping_host, 'localhost')



if __name__ == '__main__':
unittest.main()
-


--
James


On 17 January 2014 10:50, eryksun eryk...@gmail.com wrote:

 On Fri, Jan 17, 2014 at 4:58 AM, James Chapman ja...@uplinkzero.com
 wrote:
  import mock
  import unittest
  import pinger
 
  class Test_Pinger(unittest.TestCase):
 
  def test_ping_host_succeeds(self):
  pinger = pinger.Pinger()

 Are you using CPython? That raises an UnboundLocalError. Take a look
 at the CPython bytecode:

 def test(self):
 pinger = pinger.Pinger()

  dis.dis(test)
   2   0 LOAD_FAST1 (pinger)
   3 LOAD_ATTR0 (Pinger)
   6 CALL_FUNCTION0
   9 STORE_FAST   1 (pinger)
  12 LOAD_CONST   0 (None)
  15 RETURN_VALUE

 Notice LOAD_FAST(1), where fast local 1 is the local variable
 `pinger`. The value isn't assigned yet, and LOAD_FAST doesn't search
 globals and builtins. You need a unique name for the instance, such as
 `test_pinger`. Then the compiler knows to use LOAD_GLOBAL:

 def test(self):
 test_pinger = pinger.Pinger()

  dis.dis(test)
   2   0 LOAD_GLOBAL  0 (pinger)
   3 LOAD_ATTR1 (Pinger)
   6 CALL_FUNCTION0
   9 STORE_FAST   1 (test_pinger)
  12 LOAD_CONST   0 (None)
  15 RETURN_VALUE

 Here's a version using a decorator instead:

 @mock.patch('pinger.subprocess')
 def test_ping_host_succeeds(self, subprocess):
 subprocess.Popen.return_value.returncode = 0
 test_pinger = pinger.Pinger()
 test_pinger.ping_host('localhost')
 subprocess.Popen.assert_called_once_with(['ping','localhost'],
  shell=True)

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Mocking with mock in unit testing

2014-01-17 Thread James Chapman
Ah of course!
pinger = pinger.Pinger()  I should have noticed that myself.  (I
renamed the file to pinger.py after establishing it all worked and then
didn't re-run).
ping = pinger.Pinger() works fine.

As for the syntax errors, those will be copy paste / different email client
errors.

--
James


On 17 January 2014 11:23, Steven D'Aprano st...@pearwood.info wrote:

 On Fri, Jan 17, 2014 at 09:58:06AM +, James Chapman wrote:

  As this question was just about mock and not really dealing with the bad
  return code or exception handling or raising my final working example
 looks
  like this:

 Your final *working* example? I don't think so. I can see at least two
 syntax errors, and a programming error.

 A word to the wise: code isn't working until you've actually seen it
 work :-)



  pinger.py
 
  
 
  import subprocess
   class Pinger(object):

 There is your first SyntaxError, a stray space ahead of the class
 keyword.


  def ping_host(self, host_to_ping):
  cmd_string = 'ping %s' % (host_to_ping)
  cmd_args = cmd_string.split()

 This is not a programming error, but it is wasteful. First you join two
 strings: ping, and the host. Then, having glued them together, you
 split them apart exactly where you glued them.

 Better to do something like:

 cmd_args = [ping, host_to_ping]

 assuming that you know that host_to_ping is only a single word.


  proc = subprocess.Popen(cmd_args, shell=True)

 Why shell=True?

 The documentation for subprocess.Popen says:

 The shell argument (which defaults to False) specifies whether to
 use the shell as the program to execute. If shell is True, it is
 recommended to pass args as a string rather than as a sequence.

 and also warns that shell=True can be a security hazard. Do you have a
 good reason for using it?

 http://docs.python.org/2/library/subprocess.html



  proc.wait()
  if proc.returncode != 0:
  raise Exception('Error code was: %d' % (proc.returncode))
 
   if __name__ == '__main__':
  PINGER = Pinger()
  PINGER.ping_host('localhost')
 
  
 
 
 
  test_pinger.py
 
  
 
  import mockimport unittestimport pinger
   class Test_Pinger(unittest.TestCase):

 And here you have two more SyntaxErrors: missing commas between
 arguments to import, and a stray space before the class again.


  def test_ping_host_succeeds(self):
  pinger = pinger.Pinger()

 And here is your programming error. Unlike some programming languages
 (Lua, I think) in Python you cannot use the same name to refer to both a
 global variable and a local variable inside the same function. In
 Python, either the variable is treated as a global, or as a local, but
 not both.

 The rules Python uses to decide are:

 * if you declare a name global inside the function, then it is
   treated as global inside that function;

 * otherwise, if you assign a value to the name *anywhere* inside
   the function, it is treated as local;

 * otherwise it is global.

 So in your example, you assign a value to the name pinger, so it is
 treated as local. The offending line of code looks like this:

 pinger = pinger.Pinger()

 Your *intention* is to look up the global pinger, which is a module,
 then create a pinger.Pinger() instance, then assign it to the local
 variable pinger. But that's not what Python does. Instead, it tries to
 look up a local variable pinger, finds it doesn't have one, and raises
 an UnboundLocalError exception.

 I recommend you change the name of the local variable pinger to
 something else, so it no longer clashes with the pinger module name.


 Hope this is of help to you,



 --
 Steven
 ___
 Tutor maillist  -  Tutor@python.org
 To unsubscribe or change subscription options:
 https://mail.python.org/mailman/listinfo/tutor

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Mocking with mock in unit testing

2014-01-17 Thread eryksun
On Fri, Jan 17, 2014 at 6:23 AM, Steven D'Aprano st...@pearwood.info wrote:
 On Fri, Jan 17, 2014 at 09:58:06AM +, James Chapman wrote:

 import subprocess
  class Pinger(object):

 There is your first SyntaxError, a stray space ahead of the class
 keyword.

The rich text version is correct (and colorful), but a non-breaking
space ended up on a line in between the span elements in the pre
block:

span s=
tyle=3Dcolor:rgb(220,20,60)subprocess/span
=C2=A0
span style=3Dcolor:rgb(255,119,0);font-weight:boldclass/span

The automated conversion to plain text removed the line break.


 Better to do something like:

 cmd_args = [ping, host_to_ping]

 assuming that you know that host_to_ping is only a single word.

If it isn't a single word, then use `shlex.split`, as I previously suggested.


 Why shell=True?

 and also warns that shell=True can be a security hazard. Do you have a
 good reason for using it?

I already asked this and got the response this question was just about mock.


 import mockimport unittestimport pinger
  class Test_Pinger(unittest.TestCase):

 And here you have two more SyntaxErrors: missing commas between
 arguments to import, and a stray space before the class again.

This is also fine in the rich text version. BTW, the botched plain
text conversion is missing line breaks, not commas.


 def test_ping_host_succeeds(self):
 pinger = pinger.Pinger()

 And here is your programming error. Unlike some programming languages
 (Lua, I think) in Python you cannot use the same name to refer to both a
 global variable and a local variable inside the same function. In
 Python, either the variable is treated as a global, or as a local, but
 not both.

As you say, for a function. Optimized code requires the name to be
bound locally, else it raises UnboundLocalError. The unoptimized code
of a class body, on the other hand, can load a name from globals or
builtins and then store the same name to locals.

 x = 'global x'
 class C(object):
... x = x + , but now local
... print x
...
global x, but now local
 x
'global x'
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Mocking with mock in unit testing

2014-01-17 Thread James Chapman
Really!

import mock
import unittest
import pinger

It should be three lines, but somehow it got all messed up, either
through rich text formatting or copy paste.

Being a bit pedantic now about import statements which are clearly
unintentionally messed up.

- Sent in plain text.



--
James




On 17 January 2014 15:32, Steven D'Aprano st...@pearwood.info wrote:

 On Fri, Jan 17, 2014 at 08:35:04AM -0500, eryksun wrote:
  On Fri, Jan 17, 2014 at 6:23 AM, Steven D'Aprano st...@pearwood.info 
  wrote:
   On Fri, Jan 17, 2014 at 09:58:06AM +, James Chapman wrote:
 [...]
   import mockimport unittestimport pinger
class Test_Pinger(unittest.TestCase):
  
   And here you have two more SyntaxErrors: missing commas between
   arguments to import, and a stray space before the class again.
 
  This is also fine in the rich text version. BTW, the botched plain
  text conversion is missing line breaks, not commas.

 I don't understand this. If I'm interpreting you correctly,


 import mockimport
 unittestimport
 pinger


 would not be fine.


 --
 Steven
 ___
 Tutor maillist  -  Tutor@python.org
 To unsubscribe or change subscription options:
 https://mail.python.org/mailman/listinfo/tutor
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Mocking with mock in unit testing

2014-01-17 Thread Dave Angel
 Steven D'Aprano st...@pearwood.info Wrote in message:
 On Fri, Jan 17, 2014 at 08:35:04AM -0500, eryksun wrote:
 On Fri, Jan 17, 2014 at 6:23 AM, Steven D'Aprano st...@pearwood.info wrote:
  On Fri, Jan 17, 2014 at 09:58:06AM +, James Chapman wrote:
 [...]
  import mockimport unittestimport pinger
   class Test_Pinger(unittest.TestCase):
 
  And here you have two more SyntaxErrors: missing commas between
  arguments to import, and a stray space before the class again.
 
 This is also fine in the rich text version. BTW, the botched plain
 text conversion is missing line breaks, not commas.
 
 I don't understand this. If I'm interpreting you correctly,
 
 
 import mockimport 
 unittestimport 
 pinger
 
 
 would not be fine.
 
 
You're putting the linefeeds in the wrong places.

import mock
import 
 unittest
import 
 pinger

 -- 
 Steven
 ___
 Tutor maillist  -  Tutor@python.org
 To unsubscribe or change subscription options:
 https://mail.python.org/mailman/listinfo/tutor
 
 


-- 
DaveA nr

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Mocking with mock in unit testing

2014-01-17 Thread Steven D'Aprano
On Fri, Jan 17, 2014 at 08:35:04AM -0500, eryksun wrote:
 On Fri, Jan 17, 2014 at 6:23 AM, Steven D'Aprano st...@pearwood.info wrote:
  On Fri, Jan 17, 2014 at 09:58:06AM +, James Chapman wrote:
[...]
  import mockimport unittestimport pinger
   class Test_Pinger(unittest.TestCase):
 
  And here you have two more SyntaxErrors: missing commas between
  arguments to import, and a stray space before the class again.
 
 This is also fine in the rich text version. BTW, the botched plain
 text conversion is missing line breaks, not commas.

I don't understand this. If I'm interpreting you correctly,


import mockimport 
unittestimport 
pinger


would not be fine.


-- 
Steven
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Mocking with mock in unit testing

2014-01-17 Thread eryksun
On Fri, Jan 17, 2014 at 10:32 AM, Steven D'Aprano st...@pearwood.info wrote:
 import mockimport
 unittestimport
 pinger


 would not be fine.

Screenshot:
http://i.imgur.com/wSihI1X.png

The following is in a pre tag, so the whitespace is rendered literally:

span style=S0import/span mock
span style=S0import/span span style=S1unittest/span
span style=S0import/span pinger

span style=S0class/span

---

Replace S0 and S1 as follows:

S0 = color:rgb(255,119,0);font-weight:bold
S1 = color:rgb(220,20,60)

There's a non-breaking space on the otherwise empty line between
pinger and class.
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Mocking with mock in unit testing

2014-01-17 Thread Steven D'Aprano
On Fri, Jan 17, 2014 at 11:05:24AM -0500, Dave Angel wrote:
  Steven D'Aprano st...@pearwood.info Wrote in message:

  import mockimport 
  unittestimport 
  pinger
  
  
  would not be fine.
  
  
 You're putting the linefeeds in the wrong places.

Of course I am! 

You would be amazed at how long I had to stare at this before I even 
noticed the import suffix at the end of the first two lines. I had 
actually convinced myself that somehow two of the three import words 
had been deleted, not just whitespace.

It's all clear to me now, the raw HTML code in James' email had:

  span style=color:rgb(255,119,0);font-weight:boldimport/span mock
  span style=color:rgb(255,119,0);font-weight:boldimport/span span 
  style=color:rgb(220,20,60)unittest/span
  span style=color:rgb(255,119,0);font-weight:boldimport/span pinger

(indentation added by me)

which got mangled into plain text as:

  import mockIMPORT unittestIMPORT pinger

(highlighting the latter two imports for emphasis), and not what my 
brain was telling me, which was import mock unittest pinger.



-- 
Steven
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Mocking with mock in unit testing

2014-01-17 Thread Steven D'Aprano
On Fri, Jan 17, 2014 at 03:43:58PM +, James Chapman wrote:
 Really!
 
 import mock
 import unittest
 import pinger
 
 It should be three lines, but somehow it got all messed up, either
 through rich text formatting or copy paste.

Yes, I see what's going on now, excuse the noise. But this is a good 
example of why HTML-based rich text is rubbish.


 Being a bit pedantic now about import statements which are clearly
 unintentionally messed up.

You're asking for help on a mailing list aimed at beginners. It is very 
common to have beginners post code which cannot possible run and claim 
that it is the version of the code they ran. How are we supposed to tell 
which screw ups are unintentional and which are intentional?



-- 
Steven
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Mocking with mock in unit testing

2014-01-17 Thread Alan Gauld

On 18/01/14 00:49, Steven D'Aprano wrote:


which got mangled into plain text as:

   import mockIMPORT unittestIMPORT pinger

(highlighting the latter two imports for emphasis), and not what my
brain was telling me, which was import mock unittest pinger.


If its any consolation I did exactly the same.

Even after the correction came out and I went back to the
original I still missed the import.

It was only when the raw HTML came through I saw it...

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.flickr.com/photos/alangauldphotos

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Mocking with mock in unit testing

2014-01-16 Thread eryksun
On Thu, Jan 16, 2014 at 5:32 AM, James Chapman ja...@uplinkzero.com wrote:

 In my unittest I don't want to run the ping command, (It might not be
 available on the build system) I merely want to check that a call to
 subprocess.Popen is made and that the parameters are what I expect?

You can mock `Popen` where it's accessed.

@mock.patch('subprocess.Popen')
def test_ping_host(self, Popen):
Popen.return_value.returncode = 0
pinger = Pinger()
pinger.ping_host('127.0.0.1')
Popen.assert_called_once_with(['ping','127.0.0.1'], shell=True)

If the tutor_q module imported `Popen` into its namespace, then you'd
patch tutor_q.Popen.

 def ping_host(self, host_to_ping):
 cmd_string = 'ping %s' % (host_to_ping)
 cmd_args = cmd_string.split()

Splitting on spaces doesn't work generally. Use `shlex.split`, or
build the list manually.

 proc = subprocess.Popen(cmd_args, shell=True)

Maybe you really need the shell to process your command, but generally
there's no reason to run the shell just to have it execute the command
and wait. Plus it opens the door to security exploits.

 proc.wait()
 if proc.returncode != 1:
 raise Exception('Error code was: %d' % (proc.returncode))

A non-zero return code signals an error. When using `Popen` directly,
you can be consistent with `check_call` and `check_output` if you
raise a `CalledProcessError` in this case:

retcode = proc.wait()
if retcode:
raise subprocess.CalledProcessError(retcode, cmd_args)
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor