##// END OF EJS Templates
Fix for %run on a Python file using non-default encoding.
Thomas Kluyver -
Show More
@@ -1,242 +1,249 b''
1 1 """Tests for code execution (%run and related), which is particularly tricky.
2 2
3 3 Because of how %run manages namespaces, and the fact that we are trying here to
4 4 verify subtle object deletion and reference counting issues, the %run tests
5 5 will be kept in this separate file. This makes it easier to aggregate in one
6 6 place the tricks needed to handle it; most other magics are much easier to test
7 7 and we do so in a common test_magic file.
8 8 """
9 9 from __future__ import absolute_import
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 import os
16 16 import sys
17 17 import tempfile
18 18
19 19 import nose.tools as nt
20 20 from nose import SkipTest
21 21
22 22 from IPython.testing import decorators as dec
23 23 from IPython.testing import tools as tt
24 24 from IPython.utils import py3compat
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Test functions begin
28 28 #-----------------------------------------------------------------------------
29 29
30 30 def doctest_refbug():
31 31 """Very nasty problem with references held by multiple runs of a script.
32 32 See: https://github.com/ipython/ipython/issues/141
33 33
34 34 In [1]: _ip.clear_main_mod_cache()
35 35 # random
36 36
37 37 In [2]: %run refbug
38 38
39 39 In [3]: call_f()
40 40 lowercased: hello
41 41
42 42 In [4]: %run refbug
43 43
44 44 In [5]: call_f()
45 45 lowercased: hello
46 46 lowercased: hello
47 47 """
48 48
49 49
50 50 def doctest_run_builtins():
51 51 r"""Check that %run doesn't damage __builtins__.
52 52
53 53 In [1]: import tempfile
54 54
55 55 In [2]: bid1 = id(__builtins__)
56 56
57 57 In [3]: fname = tempfile.mkstemp('.py')[1]
58 58
59 59 In [3]: f = open(fname,'w')
60 60
61 61 In [4]: dummy= f.write('pass\n')
62 62
63 63 In [5]: f.flush()
64 64
65 65 In [6]: t1 = type(__builtins__)
66 66
67 67 In [7]: %run $fname
68 68
69 69 In [7]: f.close()
70 70
71 71 In [8]: bid2 = id(__builtins__)
72 72
73 73 In [9]: t2 = type(__builtins__)
74 74
75 75 In [10]: t1 == t2
76 76 Out[10]: True
77 77
78 78 In [10]: bid1 == bid2
79 79 Out[10]: True
80 80
81 81 In [12]: try:
82 82 ....: os.unlink(fname)
83 83 ....: except:
84 84 ....: pass
85 85 ....:
86 86 """
87 87
88 88 @py3compat.doctest_refactor_print
89 89 def doctest_reset_del():
90 90 """Test that resetting doesn't cause errors in __del__ methods.
91 91
92 92 In [2]: class A(object):
93 93 ...: def __del__(self):
94 94 ...: print str("Hi")
95 95 ...:
96 96
97 97 In [3]: a = A()
98 98
99 99 In [4]: get_ipython().reset()
100 100 Hi
101 101
102 102 In [5]: 1+1
103 103 Out[5]: 2
104 104 """
105 105
106 106 # For some tests, it will be handy to organize them in a class with a common
107 107 # setup that makes a temp file
108 108
109 109 class TestMagicRunPass(tt.TempFileMixin):
110 110
111 111 def setup(self):
112 112 """Make a valid python temp file."""
113 113 self.mktmp('pass\n')
114 114
115 115 def run_tmpfile(self):
116 116 _ip = get_ipython()
117 117 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
118 118 # See below and ticket https://bugs.launchpad.net/bugs/366353
119 119 _ip.magic('run %s' % self.fname)
120 120
121 121 def run_tmpfile_p(self):
122 122 _ip = get_ipython()
123 123 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
124 124 # See below and ticket https://bugs.launchpad.net/bugs/366353
125 125 _ip.magic('run -p %s' % self.fname)
126 126
127 127 def test_builtins_id(self):
128 128 """Check that %run doesn't damage __builtins__ """
129 129 _ip = get_ipython()
130 130 # Test that the id of __builtins__ is not modified by %run
131 131 bid1 = id(_ip.user_ns['__builtins__'])
132 132 self.run_tmpfile()
133 133 bid2 = id(_ip.user_ns['__builtins__'])
134 134 tt.assert_equals(bid1, bid2)
135 135
136 136 def test_builtins_type(self):
137 137 """Check that the type of __builtins__ doesn't change with %run.
138 138
139 139 However, the above could pass if __builtins__ was already modified to
140 140 be a dict (it should be a module) by a previous use of %run. So we
141 141 also check explicitly that it really is a module:
142 142 """
143 143 _ip = get_ipython()
144 144 self.run_tmpfile()
145 145 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
146 146
147 147 def test_prompts(self):
148 148 """Test that prompts correctly generate after %run"""
149 149 self.run_tmpfile()
150 150 _ip = get_ipython()
151 151 p2 = _ip.prompt_manager.render('in2').strip()
152 152 nt.assert_equals(p2[:3], '...')
153 153
154 154 def test_run_profile( self ):
155 155 """Test that the option -p, which invokes the profiler, do not
156 156 crash by invoking execfile"""
157 157 _ip = get_ipython()
158 158 self.run_tmpfile_p()
159 159
160 160
161 161 class TestMagicRunSimple(tt.TempFileMixin):
162 162
163 163 def test_simpledef(self):
164 164 """Test that simple class definitions work."""
165 165 src = ("class foo: pass\n"
166 166 "def f(): return foo()")
167 167 self.mktmp(src)
168 168 _ip.magic('run %s' % self.fname)
169 169 _ip.run_cell('t = isinstance(f(), foo)')
170 170 nt.assert_true(_ip.user_ns['t'])
171 171
172 172 def test_obj_del(self):
173 173 """Test that object's __del__ methods are called on exit."""
174 174 if sys.platform == 'win32':
175 175 try:
176 176 import win32api
177 177 except ImportError:
178 178 raise SkipTest("Test requires pywin32")
179 179 src = ("class A(object):\n"
180 180 " def __del__(self):\n"
181 181 " print 'object A deleted'\n"
182 182 "a = A()\n")
183 183 self.mktmp(py3compat.doctest_refactor_print(src))
184 184 if dec.module_not_available('sqlite3'):
185 185 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
186 186 else:
187 187 err = None
188 188 tt.ipexec_validate(self.fname, 'object A deleted', err)
189 189
190 190 @dec.skip_known_failure
191 191 def test_aggressive_namespace_cleanup(self):
192 192 """Test that namespace cleanup is not too aggressive GH-238
193 193
194 194 Returning from another run magic deletes the namespace"""
195 195 # see ticket https://github.com/ipython/ipython/issues/238
196 196 class secondtmp(tt.TempFileMixin): pass
197 197 empty = secondtmp()
198 198 empty.mktmp('')
199 199 src = ("ip = get_ipython()\n"
200 200 "for i in range(5):\n"
201 201 " try:\n"
202 202 " ip.magic('run %s')\n"
203 203 " except NameError, e:\n"
204 204 " print i;break\n" % empty.fname)
205 205 self.mktmp(py3compat.doctest_refactor_print(src))
206 206 _ip.magic('run %s' % self.fname)
207 207 _ip.run_cell('ip == get_ipython()')
208 208 tt.assert_equals(_ip.user_ns['i'], 5)
209 209
210 210 @dec.skip_win32
211 211 def test_tclass(self):
212 212 mydir = os.path.dirname(__file__)
213 213 tc = os.path.join(mydir, 'tclass')
214 214 src = ("%%run '%s' C-first\n"
215 215 "%%run '%s' C-second\n"
216 216 "%%run '%s' C-third\n") % (tc, tc, tc)
217 217 self.mktmp(src, '.ipy')
218 218 out = """\
219 219 ARGV 1-: ['C-first']
220 220 ARGV 1-: ['C-second']
221 221 tclass.py: deleting object: C-first
222 222 ARGV 1-: ['C-third']
223 223 tclass.py: deleting object: C-second
224 224 tclass.py: deleting object: C-third
225 225 """
226 226 if dec.module_not_available('sqlite3'):
227 227 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
228 228 else:
229 229 err = None
230 230 tt.ipexec_validate(self.fname, out, err)
231 231
232 232 def test_run_i_after_reset(self):
233 233 """Check that %run -i still works after %reset (gh-693)"""
234 234 src = "yy = zz\n"
235 235 self.mktmp(src)
236 236 _ip.run_cell("zz = 23")
237 237 _ip.magic('run -i %s' % self.fname)
238 238 tt.assert_equals(_ip.user_ns['yy'], 23)
239 239 _ip.magic('reset -f')
240 240 _ip.run_cell("zz = 23")
241 241 _ip.magic('run -i %s' % self.fname)
242 242 tt.assert_equals(_ip.user_ns['yy'], 23)
243
244 def test_unicode(self):
245 """Check that files in odd encodings are accepted."""
246 mydir = os.path.dirname(__file__)
247 na = os.path.join(mydir, 'nonascii.py')
248 _ip.magic('run %s' % na)
249 tt.assert_equals(_ip.user_ns['u'], u'ΠŽΡ‚β„–Π€')
@@ -1,175 +1,175 b''
1 1 # coding: utf-8
2 2 """Compatibility tricks for Python 3. Mainly to do with unicode."""
3 3 import __builtin__
4 4 import functools
5 5 import sys
6 6 import re
7 7 import types
8 8
9 9 orig_open = open
10 10
11 11 def no_code(x, encoding=None):
12 12 return x
13 13
14 14 def decode(s, encoding=None):
15 15 encoding = encoding or sys.stdin.encoding or sys.getdefaultencoding()
16 16 return s.decode(encoding, "replace")
17 17
18 18 def encode(u, encoding=None):
19 19 encoding = encoding or sys.stdin.encoding or sys.getdefaultencoding()
20 20 return u.encode(encoding, "replace")
21 21
22 22 def cast_unicode(s, encoding=None):
23 23 if isinstance(s, bytes):
24 24 return decode(s, encoding)
25 25 return s
26 26
27 27 def cast_bytes(s, encoding=None):
28 28 if not isinstance(s, bytes):
29 29 return encode(s, encoding)
30 30 return s
31 31
32 32 def _modify_str_or_docstring(str_change_func):
33 33 @functools.wraps(str_change_func)
34 34 def wrapper(func_or_str):
35 35 if isinstance(func_or_str, str):
36 36 func = None
37 37 doc = func_or_str
38 38 else:
39 39 func = func_or_str
40 40 doc = func.__doc__
41 41
42 42 doc = str_change_func(doc)
43 43
44 44 if func:
45 45 func.__doc__ = doc
46 46 return func
47 47 return doc
48 48 return wrapper
49 49
50 50 if sys.version_info[0] >= 3:
51 51 PY3 = True
52 52
53 53 input = input
54 54 builtin_mod_name = "builtins"
55 55
56 56 str_to_unicode = no_code
57 57 unicode_to_str = no_code
58 58 str_to_bytes = encode
59 59 bytes_to_str = decode
60 60 cast_bytes_py2 = no_code
61 61
62 62 def isidentifier(s, dotted=False):
63 63 if dotted:
64 64 return all(isidentifier(a) for a in s.split("."))
65 65 return s.isidentifier()
66 66
67 67 open = orig_open
68 68
69 69 MethodType = types.MethodType
70 70
71 71 def execfile(fname, glob, loc=None):
72 72 loc = loc if (loc is not None) else glob
73 exec compile(open(fname).read(), fname, 'exec') in glob, loc
73 exec compile(open(fname, 'rb').read(), fname, 'exec') in glob, loc
74 74
75 75 # Refactor print statements in doctests.
76 76 _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
77 77 def _print_statement_sub(match):
78 78 expr = match.groups('expr')
79 79 return "print(%s)" % expr
80 80
81 81 @_modify_str_or_docstring
82 82 def doctest_refactor_print(doc):
83 83 """Refactor 'print x' statements in a doctest to print(x) style. 2to3
84 84 unfortunately doesn't pick up on our doctests.
85 85
86 86 Can accept a string or a function, so it can be used as a decorator."""
87 87 return _print_statement_re.sub(_print_statement_sub, doc)
88 88
89 89 # Abstract u'abc' syntax:
90 90 @_modify_str_or_docstring
91 91 def u_format(s):
92 92 """"{u}'abc'" --> "'abc'" (Python 3)
93 93
94 94 Accepts a string or a function, so it can be used as a decorator."""
95 95 return s.format(u='')
96 96
97 97 else:
98 98 PY3 = False
99 99
100 100 input = raw_input
101 101 builtin_mod_name = "__builtin__"
102 102
103 103 str_to_unicode = decode
104 104 unicode_to_str = encode
105 105 str_to_bytes = no_code
106 106 bytes_to_str = no_code
107 107 cast_bytes_py2 = cast_bytes
108 108
109 109 import re
110 110 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
111 111 def isidentifier(s, dotted=False):
112 112 if dotted:
113 113 return all(isidentifier(a) for a in s.split("."))
114 114 return bool(_name_re.match(s))
115 115
116 116 class open(object):
117 117 """Wrapper providing key part of Python 3 open() interface."""
118 118 def __init__(self, fname, mode="r", encoding="utf-8"):
119 119 self.f = orig_open(fname, mode)
120 120 self.enc = encoding
121 121
122 122 def write(self, s):
123 123 return self.f.write(s.encode(self.enc))
124 124
125 125 def read(self, size=-1):
126 126 return self.f.read(size).decode(self.enc)
127 127
128 128 def close(self):
129 129 return self.f.close()
130 130
131 131 def __enter__(self):
132 132 return self
133 133
134 134 def __exit__(self, etype, value, traceback):
135 135 self.f.close()
136 136
137 137 def MethodType(func, instance):
138 138 return types.MethodType(func, instance, type(instance))
139 139
140 140 # don't override system execfile on 2.x:
141 141 execfile = execfile
142 142
143 143 def doctest_refactor_print(func_or_str):
144 144 return func_or_str
145 145
146 146
147 147 # Abstract u'abc' syntax:
148 148 @_modify_str_or_docstring
149 149 def u_format(s):
150 150 """"{u}'abc'" --> "u'abc'" (Python 2)
151 151
152 152 Accepts a string or a function, so it can be used as a decorator."""
153 153 return s.format(u='u')
154 154
155 155 if sys.platform == 'win32':
156 156 def execfile(fname, glob=None, loc=None):
157 157 loc = loc if (loc is not None) else glob
158 158 # The rstrip() is necessary b/c trailing whitespace in files will
159 159 # cause an IndentationError in Python 2.6 (this was fixed in 2.7,
160 160 # but we still support 2.6). See issue 1027.
161 161 scripttext = __builtin__.open(fname).read().rstrip() + '\n'
162 162 # compile converts unicode filename to str assuming
163 163 # ascii. Let's do the conversion before calling compile
164 164 if isinstance(fname, unicode):
165 165 filename = unicode_to_str(fname)
166 166 else:
167 167 filename = fname
168 168 exec compile(scripttext, filename, 'exec') in glob, loc
169 169 else:
170 170 def execfile(fname, *where):
171 171 if isinstance(fname, unicode):
172 172 filename = fname.encode(sys.getfilesystemencoding())
173 173 else:
174 174 filename = fname
175 175 __builtin__.execfile(filename, *where)
General Comments 0
You need to be logged in to leave comments. Login now