##// END OF EJS Templates
Various fixes for IPython.core tests to pass under win32.
Fernando Perez -
Show More
@@ -1,168 +1,174 b''
1 """Tests for code execution (%run and related), which is particularly tricky.
1 """Tests for code execution (%run and related), which is particularly tricky.
2
2
3 Because of how %run manages namespaces, and the fact that we are trying here to
3 Because of how %run manages namespaces, and the fact that we are trying here to
4 verify subtle object deletion and reference counting issues, the %run tests
4 verify subtle object deletion and reference counting issues, the %run tests
5 will be kept in this separate file. This makes it easier to aggregate in one
5 will be kept in this separate file. This makes it easier to aggregate in one
6 place the tricks needed to handle it; most other magics are much easier to test
6 place the tricks needed to handle it; most other magics are much easier to test
7 and we do so in a common test_magic file.
7 and we do so in a common test_magic file.
8 """
8 """
9 from __future__ import absolute_import
9 from __future__ import absolute_import
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # stdlib
15 # stdlib
16 import os
16 import os
17 import sys
17 import sys
18 import tempfile
18 import tempfile
19
19
20 # third-party
20 # third-party
21 import nose.tools as nt
21 import nose.tools as nt
22
22
23 # our own
23 # our own
24 from IPython.utils.platutils import find_cmd
24 from IPython.utils.platutils import find_cmd
25 from IPython.utils import genutils
25 from IPython.utils import genutils
26 from IPython.testing import decorators as dec
26 from IPython.testing import decorators as dec
27 from IPython.testing import tools as tt
27 from IPython.testing import tools as tt
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Test functions begin
30 # Test functions begin
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 def doctest_refbug():
33 def doctest_refbug():
34 """Very nasty problem with references held by multiple runs of a script.
34 """Very nasty problem with references held by multiple runs of a script.
35 See: https://bugs.launchpad.net/ipython/+bug/269966
35 See: https://bugs.launchpad.net/ipython/+bug/269966
36
36
37 In [1]: _ip.clear_main_mod_cache()
37 In [1]: _ip.clear_main_mod_cache()
38 # random
38 # random
39
39
40 In [2]: %run refbug
40 In [2]: %run refbug
41
41
42 In [3]: call_f()
42 In [3]: call_f()
43 lowercased: hello
43 lowercased: hello
44
44
45 In [4]: %run refbug
45 In [4]: %run refbug
46
46
47 In [5]: call_f()
47 In [5]: call_f()
48 lowercased: hello
48 lowercased: hello
49 lowercased: hello
49 lowercased: hello
50 """
50 """
51
51
52
52
53 def doctest_run_builtins():
53 def doctest_run_builtins():
54 r"""Check that %run doesn't damage __builtins__.
54 r"""Check that %run doesn't damage __builtins__.
55
55
56 In [1]: import tempfile
56 In [1]: import tempfile
57
57
58 In [2]: bid1 = id(__builtins__)
58 In [2]: bid1 = id(__builtins__)
59
59
60 In [3]: fname = tempfile.mkstemp('.py')[1]
60 In [3]: fname = tempfile.mkstemp('.py')[1]
61
61
62 In [3]: f = open(fname,'w')
62 In [3]: f = open(fname,'w')
63
63
64 In [4]: f.write('pass\n')
64 In [4]: f.write('pass\n')
65
65
66 In [5]: f.flush()
66 In [5]: f.flush()
67
67
68 In [6]: t1 = type(__builtins__)
68 In [6]: t1 = type(__builtins__)
69
69
70 In [7]: %run "$fname"
70 In [7]: %run "$fname"
71
71
72 In [7]: f.close()
72 In [7]: f.close()
73
73
74 In [8]: bid2 = id(__builtins__)
74 In [8]: bid2 = id(__builtins__)
75
75
76 In [9]: t2 = type(__builtins__)
76 In [9]: t2 = type(__builtins__)
77
77
78 In [10]: t1 == t2
78 In [10]: t1 == t2
79 Out[10]: True
79 Out[10]: True
80
80
81 In [10]: bid1 == bid2
81 In [10]: bid1 == bid2
82 Out[10]: True
82 Out[10]: True
83
83
84 In [12]: try:
84 In [12]: try:
85 ....: os.unlink(fname)
85 ....: os.unlink(fname)
86 ....: except:
86 ....: except:
87 ....: pass
87 ....: pass
88 ....:
88 ....:
89 """
89 """
90
90
91 # For some tests, it will be handy to organize them in a class with a common
91 # For some tests, it will be handy to organize them in a class with a common
92 # setup that makes a temp file
92 # setup that makes a temp file
93
93
94 class TestMagicRunPass(tt.TempFileMixin):
94 class TestMagicRunPass(tt.TempFileMixin):
95
95
96 def setup(self):
96 def setup(self):
97 """Make a valid python temp file."""
97 """Make a valid python temp file."""
98 self.mktmp('pass\n')
98 self.mktmp('pass\n')
99
99
100 def run_tmpfile(self):
100 def run_tmpfile(self):
101 _ip = get_ipython()
101 _ip = get_ipython()
102 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
102 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
103 # See below and ticket https://bugs.launchpad.net/bugs/366353
103 # See below and ticket https://bugs.launchpad.net/bugs/366353
104 _ip.magic('run "%s"' % self.fname)
104 _ip.magic('run "%s"' % self.fname)
105
105
106 def test_builtins_id(self):
106 def test_builtins_id(self):
107 """Check that %run doesn't damage __builtins__ """
107 """Check that %run doesn't damage __builtins__ """
108 _ip = get_ipython()
108 _ip = get_ipython()
109 # Test that the id of __builtins__ is not modified by %run
109 # Test that the id of __builtins__ is not modified by %run
110 bid1 = id(_ip.user_ns['__builtins__'])
110 bid1 = id(_ip.user_ns['__builtins__'])
111 self.run_tmpfile()
111 self.run_tmpfile()
112 bid2 = id(_ip.user_ns['__builtins__'])
112 bid2 = id(_ip.user_ns['__builtins__'])
113 tt.assert_equals(bid1, bid2)
113 tt.assert_equals(bid1, bid2)
114
114
115 def test_builtins_type(self):
115 def test_builtins_type(self):
116 """Check that the type of __builtins__ doesn't change with %run.
116 """Check that the type of __builtins__ doesn't change with %run.
117
117
118 However, the above could pass if __builtins__ was already modified to
118 However, the above could pass if __builtins__ was already modified to
119 be a dict (it should be a module) by a previous use of %run. So we
119 be a dict (it should be a module) by a previous use of %run. So we
120 also check explicitly that it really is a module:
120 also check explicitly that it really is a module:
121 """
121 """
122 _ip = get_ipython()
122 _ip = get_ipython()
123 self.run_tmpfile()
123 self.run_tmpfile()
124 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
124 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
125
125
126 def test_prompts(self):
126 def test_prompts(self):
127 """Test that prompts correctly generate after %run"""
127 """Test that prompts correctly generate after %run"""
128 self.run_tmpfile()
128 self.run_tmpfile()
129 _ip = get_ipython()
129 _ip = get_ipython()
130 p2 = str(_ip.outputcache.prompt2).strip()
130 p2 = str(_ip.outputcache.prompt2).strip()
131 nt.assert_equals(p2[:3], '...')
131 nt.assert_equals(p2[:3], '...')
132
132
133
133
134 class TestMagicRunSimple(tt.TempFileMixin):
134 class TestMagicRunSimple(tt.TempFileMixin):
135
135
136 def test_simpledef(self):
136 def test_simpledef(self):
137 """Test that simple class definitions work."""
137 """Test that simple class definitions work."""
138 src = ("class foo: pass\n"
138 src = ("class foo: pass\n"
139 "def f(): return foo()")
139 "def f(): return foo()")
140 self.mktmp(src)
140 self.mktmp(src)
141 _ip.magic('run "%s"' % self.fname)
141 _ip.magic('run "%s"' % self.fname)
142 _ip.runlines('t = isinstance(f(), foo)')
142 _ip.runlines('t = isinstance(f(), foo)')
143 nt.assert_true(_ip.user_ns['t'])
143 nt.assert_true(_ip.user_ns['t'])
144
144
145 # We have to skip these in win32 because genutils.getoutputerr() crashes,
146 # due to the fact that subprocess does not support close_fds when
147 # redirecting stdout/err. So unless someone who knows more tells us how to
148 # implement genutils.getoutputerr() in win32, we're stuck avoiding these.
149 @dec.skip_win32
145 def test_obj_del(self):
150 def test_obj_del(self):
146 """Test that object's __del__ methods are called on exit."""
151 """Test that object's __del__ methods are called on exit."""
147
152
148 # This test is known to fail on win32.
153 # This test is known to fail on win32.
149 # See ticket https://bugs.launchpad.net/bugs/366334
154 # See ticket https://bugs.launchpad.net/bugs/366334
150 src = ("class A(object):\n"
155 src = ("class A(object):\n"
151 " def __del__(self):\n"
156 " def __del__(self):\n"
152 " print 'object A deleted'\n"
157 " print 'object A deleted'\n"
153 "a = A()\n")
158 "a = A()\n")
154 self.mktmp(src)
159 self.mktmp(src)
155 tt.ipexec_validate(self.fname, 'object A deleted')
160 tt.ipexec_validate(self.fname, 'object A deleted')
156
161
162 @dec.skip_win32
157 def test_tclass(self):
163 def test_tclass(self):
158 mydir = os.path.dirname(__file__)
164 mydir = os.path.dirname(__file__)
159 tc = os.path.join(mydir, 'tclass')
165 tc = os.path.join(mydir, 'tclass')
160 src = ("%%run '%s' C-first\n"
166 src = ("%%run '%s' C-first\n"
161 "%%run '%s' C-second\n") % (tc, tc)
167 "%%run '%s' C-second\n") % (tc, tc)
162 self.mktmp(src, '.ipy')
168 self.mktmp(src, '.ipy')
163 out = """\
169 out = """\
164 ARGV 1-: ['C-first']
170 ARGV 1-: ['C-first']
165 ARGV 1-: ['C-second']
171 ARGV 1-: ['C-second']
166 tclass.py: deleting object: C-first
172 tclass.py: deleting object: C-first
167 """
173 """
168 tt.ipexec_validate(self.fname, out)
174 tt.ipexec_validate(self.fname, out)
@@ -1,266 +1,274 b''
1 """Generic testing tools that do NOT depend on Twisted.
1 """Generic testing tools that do NOT depend on Twisted.
2
2
3 In particular, this module exposes a set of top-level assert* functions that
3 In particular, this module exposes a set of top-level assert* functions that
4 can be used in place of nose.tools.assert* in method generators (the ones in
4 can be used in place of nose.tools.assert* in method generators (the ones in
5 nose can not, at least as of nose 0.10.4).
5 nose can not, at least as of nose 0.10.4).
6
6
7 Note: our testing package contains testing.util, which does depend on Twisted
7 Note: our testing package contains testing.util, which does depend on Twisted
8 and provides utilities for tests that manage Deferreds. All testing support
8 and provides utilities for tests that manage Deferreds. All testing support
9 tools that only depend on nose, IPython or the standard library should go here
9 tools that only depend on nose, IPython or the standard library should go here
10 instead.
10 instead.
11
11
12
12
13 Authors
13 Authors
14 -------
14 -------
15 - Fernando Perez <Fernando.Perez@berkeley.edu>
15 - Fernando Perez <Fernando.Perez@berkeley.edu>
16 """
16 """
17
17
18 #*****************************************************************************
18 #*****************************************************************************
19 # Copyright (C) 2009 The IPython Development Team
19 # Copyright (C) 2009 The IPython Development Team
20 #
20 #
21 # Distributed under the terms of the BSD License. The full license is in
21 # Distributed under the terms of the BSD License. The full license is in
22 # the file COPYING, distributed as part of this software.
22 # the file COPYING, distributed as part of this software.
23 #*****************************************************************************
23 #*****************************************************************************
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Required modules and packages
26 # Required modules and packages
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29 import os
29 import os
30 import re
30 import re
31 import sys
31 import sys
32 import tempfile
32 import tempfile
33
33
34 try:
34 try:
35 # These tools are used by parts of the runtime, so we make the nose
35 # These tools are used by parts of the runtime, so we make the nose
36 # dependency optional at this point. Nose is a hard dependency to run the
36 # dependency optional at this point. Nose is a hard dependency to run the
37 # test suite, but NOT to use ipython itself.
37 # test suite, but NOT to use ipython itself.
38 import nose.tools as nt
38 import nose.tools as nt
39 has_nose = True
39 has_nose = True
40 except ImportError:
40 except ImportError:
41 has_nose = False
41 has_nose = False
42
42
43 from IPython.utils import genutils, platutils
43 from IPython.utils import genutils, platutils
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Globals
46 # Globals
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 # Make a bunch of nose.tools assert wrappers that can be used in test
49 # Make a bunch of nose.tools assert wrappers that can be used in test
50 # generators. This will expose an assert* function for each one in nose.tools.
50 # generators. This will expose an assert* function for each one in nose.tools.
51
51
52 _tpl = """
52 _tpl = """
53 def %(name)s(*a,**kw):
53 def %(name)s(*a,**kw):
54 return nt.%(name)s(*a,**kw)
54 return nt.%(name)s(*a,**kw)
55 """
55 """
56
56
57 if has_nose:
57 if has_nose:
58 for _x in [a for a in dir(nt) if a.startswith('assert')]:
58 for _x in [a for a in dir(nt) if a.startswith('assert')]:
59 exec _tpl % dict(name=_x)
59 exec _tpl % dict(name=_x)
60
60
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62 # Functions and classes
62 # Functions and classes
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64
64
65
65
66 def full_path(startPath,files):
66 def full_path(startPath,files):
67 """Make full paths for all the listed files, based on startPath.
67 """Make full paths for all the listed files, based on startPath.
68
68
69 Only the base part of startPath is kept, since this routine is typically
69 Only the base part of startPath is kept, since this routine is typically
70 used with a script's __file__ variable as startPath. The base of startPath
70 used with a script's __file__ variable as startPath. The base of startPath
71 is then prepended to all the listed files, forming the output list.
71 is then prepended to all the listed files, forming the output list.
72
72
73 Parameters
73 Parameters
74 ----------
74 ----------
75 startPath : string
75 startPath : string
76 Initial path to use as the base for the results. This path is split
76 Initial path to use as the base for the results. This path is split
77 using os.path.split() and only its first component is kept.
77 using os.path.split() and only its first component is kept.
78
78
79 files : string or list
79 files : string or list
80 One or more files.
80 One or more files.
81
81
82 Examples
82 Examples
83 --------
83 --------
84
84
85 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
85 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
86 ['/foo/a.txt', '/foo/b.txt']
86 ['/foo/a.txt', '/foo/b.txt']
87
87
88 >>> full_path('/foo',['a.txt','b.txt'])
88 >>> full_path('/foo',['a.txt','b.txt'])
89 ['/a.txt', '/b.txt']
89 ['/a.txt', '/b.txt']
90
90
91 If a single file is given, the output is still a list:
91 If a single file is given, the output is still a list:
92 >>> full_path('/foo','a.txt')
92 >>> full_path('/foo','a.txt')
93 ['/a.txt']
93 ['/a.txt']
94 """
94 """
95
95
96 files = genutils.list_strings(files)
96 files = genutils.list_strings(files)
97 base = os.path.split(startPath)[0]
97 base = os.path.split(startPath)[0]
98 return [ os.path.join(base,f) for f in files ]
98 return [ os.path.join(base,f) for f in files ]
99
99
100
100
101 def parse_test_output(txt):
101 def parse_test_output(txt):
102 """Parse the output of a test run and return errors, failures.
102 """Parse the output of a test run and return errors, failures.
103
103
104 Parameters
104 Parameters
105 ----------
105 ----------
106 txt : str
106 txt : str
107 Text output of a test run, assumed to contain a line of one of the
107 Text output of a test run, assumed to contain a line of one of the
108 following forms::
108 following forms::
109 'FAILED (errors=1)'
109 'FAILED (errors=1)'
110 'FAILED (failures=1)'
110 'FAILED (failures=1)'
111 'FAILED (errors=1, failures=1)'
111 'FAILED (errors=1, failures=1)'
112
112
113 Returns
113 Returns
114 -------
114 -------
115 nerr, nfail: number of errors and failures.
115 nerr, nfail: number of errors and failures.
116 """
116 """
117
117
118 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
118 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
119 if err_m:
119 if err_m:
120 nerr = int(err_m.group(1))
120 nerr = int(err_m.group(1))
121 nfail = 0
121 nfail = 0
122 return nerr, nfail
122 return nerr, nfail
123
123
124 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
124 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
125 if fail_m:
125 if fail_m:
126 nerr = 0
126 nerr = 0
127 nfail = int(fail_m.group(1))
127 nfail = int(fail_m.group(1))
128 return nerr, nfail
128 return nerr, nfail
129
129
130 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
130 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
131 re.MULTILINE)
131 re.MULTILINE)
132 if both_m:
132 if both_m:
133 nerr = int(both_m.group(1))
133 nerr = int(both_m.group(1))
134 nfail = int(both_m.group(2))
134 nfail = int(both_m.group(2))
135 return nerr, nfail
135 return nerr, nfail
136
136
137 # If the input didn't match any of these forms, assume no error/failures
137 # If the input didn't match any of these forms, assume no error/failures
138 return 0, 0
138 return 0, 0
139
139
140
140
141 # So nose doesn't think this is a test
141 # So nose doesn't think this is a test
142 parse_test_output.__test__ = False
142 parse_test_output.__test__ = False
143
143
144
144
145 def temp_pyfile(src, ext='.py'):
145 def temp_pyfile(src, ext='.py'):
146 """Make a temporary python file, return filename and filehandle.
146 """Make a temporary python file, return filename and filehandle.
147
147
148 Parameters
148 Parameters
149 ----------
149 ----------
150 src : string or list of strings (no need for ending newlines if list)
150 src : string or list of strings (no need for ending newlines if list)
151 Source code to be written to the file.
151 Source code to be written to the file.
152
152
153 ext : optional, string
153 ext : optional, string
154 Extension for the generated file.
154 Extension for the generated file.
155
155
156 Returns
156 Returns
157 -------
157 -------
158 (filename, open filehandle)
158 (filename, open filehandle)
159 It is the caller's responsibility to close the open file and unlink it.
159 It is the caller's responsibility to close the open file and unlink it.
160 """
160 """
161 fname = tempfile.mkstemp(ext)[1]
161 fname = tempfile.mkstemp(ext)[1]
162 f = open(fname,'w')
162 f = open(fname,'w')
163 f.write(src)
163 f.write(src)
164 f.flush()
164 f.flush()
165 return fname, f
165 return fname, f
166
166
167
167
168 def default_argv():
168 def default_argv():
169 """Return a valid default argv for creating testing instances of ipython"""
169 """Return a valid default argv for creating testing instances of ipython"""
170
170
171 # Get the install directory for the user configuration and tell ipython to
171 # Get the install directory for the user configuration and tell ipython to
172 # use the default profile from there.
172 # use the default profile from there.
173 from IPython.config import default
173 from IPython.config import default
174 ipcdir = os.path.dirname(default.__file__)
174 ipcdir = os.path.dirname(default.__file__)
175 ipconf = os.path.join(ipcdir,'ipython_config.py')
175 ipconf = os.path.join(ipcdir,'ipython_config.py')
176 return ['--colors=NoColor', '--no-term-title','--no-banner',
176 return ['--colors=NoColor', '--no-term-title','--no-banner',
177 '--config-file=%s' % ipconf, '--autocall=0',
177 '--config-file="%s"' % ipconf, '--autocall=0',
178 '--prompt-out=""']
178 '--prompt-out=""']
179
179
180
180
181 def ipexec(fname, options=None):
181 def ipexec(fname, options=None):
182 """Utility to call 'ipython filename'.
182 """Utility to call 'ipython filename'.
183
183
184 Starts IPython witha minimal and safe configuration to make startup as fast
184 Starts IPython witha minimal and safe configuration to make startup as fast
185 as possible.
185 as possible.
186
186
187 Note that this starts IPython in a subprocess!
187 Note that this starts IPython in a subprocess!
188
188
189 Parameters
189 Parameters
190 ----------
190 ----------
191 fname : str
191 fname : str
192 Name of file to be executed (should have .py or .ipy extension).
192 Name of file to be executed (should have .py or .ipy extension).
193
193
194 options : optional, list
194 options : optional, list
195 Extra command-line flags to be passed to IPython.
195 Extra command-line flags to be passed to IPython.
196
196
197 Returns
197 Returns
198 -------
198 -------
199 (stdout, stderr) of ipython subprocess.
199 (stdout, stderr) of ipython subprocess.
200 """
200 """
201 if options is None: options = []
201 if options is None: options = []
202 cmdargs = ' '.join(default_argv() + options)
202 cmdargs = ' '.join(default_argv() + options)
203
203
204 _ip = get_ipython()
204 _ip = get_ipython()
205 test_dir = os.path.dirname(__file__)
205 test_dir = os.path.dirname(__file__)
206 # Find the ipython script from the package we're using, so that the test
207 # suite can be run from the source tree without an installed IPython
208 ipython_package_dir = genutils.get_ipython_package_dir()
209 ipython_script = os.path.join(ipython_package_dir,'scripts','ipython')
210 ipython_cmd = 'python "%s"' % ipython_script
211 # Absolute path for filename
206 full_fname = os.path.join(test_dir, fname)
212 full_fname = os.path.join(test_dir, fname)
207 ipython_cmd = platutils.find_cmd('ipython')
213 full_cmd = '%s %s "%s"' % (ipython_cmd, cmdargs, full_fname)
208 full_cmd = '%s %s %s' % (ipython_cmd, cmdargs, full_fname)
209 return genutils.getoutputerror(full_cmd)
214 return genutils.getoutputerror(full_cmd)
210
215
211
216
212 def ipexec_validate(fname, expected_out, expected_err=None,
217 def ipexec_validate(fname, expected_out, expected_err=None,
213 options=None):
218 options=None):
214 """Utility to call 'ipython filename' and validate output/error.
219 """Utility to call 'ipython filename' and validate output/error.
215
220
216 This function raises an AssertionError if the validation fails.
221 This function raises an AssertionError if the validation fails.
217
222
218 Note that this starts IPython in a subprocess!
223 Note that this starts IPython in a subprocess!
219
224
220 Parameters
225 Parameters
221 ----------
226 ----------
222 fname : str
227 fname : str
223 Name of the file to be executed (should have .py or .ipy extension).
228 Name of the file to be executed (should have .py or .ipy extension).
224
229
225 expected_out : str
230 expected_out : str
226 Expected stdout of the process.
231 Expected stdout of the process.
227
232
228 expected_err : optional, str
233 expected_err : optional, str
229 Expected stderr of the process.
234 Expected stderr of the process.
230
235
231 options : optional, list
236 options : optional, list
232 Extra command-line flags to be passed to IPython.
237 Extra command-line flags to be passed to IPython.
233
238
234 Returns
239 Returns
235 -------
240 -------
236 None
241 None
237 """
242 """
238
243
239 import nose.tools as nt
244 import nose.tools as nt
240
245
241 out, err = ipexec(fname)
246 out, err = ipexec(fname)
242 nt.assert_equals(out.strip(), expected_out.strip())
247 nt.assert_equals(out.strip(), expected_out.strip())
243 if expected_err:
248 if expected_err:
244 nt.assert_equals(err.strip(), expected_err.strip())
249 nt.assert_equals(err.strip(), expected_err.strip())
245
250
246
251
247 class TempFileMixin(object):
252 class TempFileMixin(object):
248 """Utility class to create temporary Python/IPython files.
253 """Utility class to create temporary Python/IPython files.
249
254
250 Meant as a mixin class for test cases."""
255 Meant as a mixin class for test cases."""
251
256
252 def mktmp(self, src, ext='.py'):
257 def mktmp(self, src, ext='.py'):
253 """Make a valid python temp file."""
258 """Make a valid python temp file."""
254 fname, f = temp_pyfile(src, ext)
259 fname, f = temp_pyfile(src, ext)
255 self.tmpfile = f
260 self.tmpfile = f
256 self.fname = fname
261 self.fname = fname
257
262
258 def teardown(self):
263 def teardown(self):
259 self.tmpfile.close()
264 if hasattr(self, 'tmpfile'):
260 try:
265 # If the tmpfile wasn't made because of skipped tests, like in
261 os.unlink(self.fname)
266 # win32, there's nothing to cleanup.
262 except:
267 self.tmpfile.close()
263 # On Windows, even though we close the file, we still can't delete
268 try:
264 # it. I have no clue why
269 os.unlink(self.fname)
265 pass
270 except:
271 # On Windows, even though we close the file, we still can't
272 # delete it. I have no clue why
273 pass
266
274
General Comments 0
You need to be logged in to leave comments. Login now