Show More
@@ -1,447 +1,455 b'' | |||||
1 | """Tests for the object inspection functionality. |
|
1 | """Tests for the object inspection functionality. | |
2 | """ |
|
2 | """ | |
3 |
|
3 | |||
4 | # Copyright (c) IPython Development Team. |
|
4 | # Copyright (c) IPython Development Team. | |
5 | # Distributed under the terms of the Modified BSD License. |
|
5 | # Distributed under the terms of the Modified BSD License. | |
6 |
|
6 | |||
7 |
|
7 | |||
8 | from inspect import signature, Signature, Parameter |
|
8 | from inspect import signature, Signature, Parameter | |
9 | import os |
|
9 | import os | |
10 | import re |
|
10 | import re | |
11 |
|
11 | |||
12 | import nose.tools as nt |
|
12 | import nose.tools as nt | |
13 |
|
13 | |||
14 | from .. import oinspect |
|
14 | from .. import oinspect | |
15 |
|
15 | |||
16 | from decorator import decorator |
|
16 | from decorator import decorator | |
17 |
|
17 | |||
18 | from IPython.testing.tools import AssertPrints, AssertNotPrints |
|
18 | from IPython.testing.tools import AssertPrints, AssertNotPrints | |
19 | from IPython.utils.path import compress_user |
|
19 | from IPython.utils.path import compress_user | |
20 |
|
20 | |||
21 |
|
21 | |||
22 | #----------------------------------------------------------------------------- |
|
22 | #----------------------------------------------------------------------------- | |
23 | # Globals and constants |
|
23 | # Globals and constants | |
24 | #----------------------------------------------------------------------------- |
|
24 | #----------------------------------------------------------------------------- | |
25 |
|
25 | |||
26 | inspector = None |
|
26 | inspector = None | |
27 |
|
27 | |||
28 | def setup_module(): |
|
28 | def setup_module(): | |
29 | global inspector |
|
29 | global inspector | |
30 | inspector = oinspect.Inspector() |
|
30 | inspector = oinspect.Inspector() | |
31 |
|
31 | |||
32 |
|
32 | |||
33 | #----------------------------------------------------------------------------- |
|
33 | #----------------------------------------------------------------------------- | |
34 | # Local utilities |
|
34 | # Local utilities | |
35 | #----------------------------------------------------------------------------- |
|
35 | #----------------------------------------------------------------------------- | |
36 |
|
36 | |||
37 | # WARNING: since this test checks the line number where a function is |
|
37 | # WARNING: since this test checks the line number where a function is | |
38 | # defined, if any code is inserted above, the following line will need to be |
|
38 | # defined, if any code is inserted above, the following line will need to be | |
39 | # updated. Do NOT insert any whitespace between the next line and the function |
|
39 | # updated. Do NOT insert any whitespace between the next line and the function | |
40 | # definition below. |
|
40 | # definition below. | |
41 | THIS_LINE_NUMBER = 41 # Put here the actual number of this line |
|
41 | THIS_LINE_NUMBER = 41 # Put here the actual number of this line | |
42 |
|
42 | |||
43 | from unittest import TestCase |
|
43 | from unittest import TestCase | |
44 |
|
44 | |||
45 | class Test(TestCase): |
|
45 | class Test(TestCase): | |
46 |
|
46 | |||
47 | def test_find_source_lines(self): |
|
47 | def test_find_source_lines(self): | |
48 | self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines), |
|
48 | self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines), | |
49 | THIS_LINE_NUMBER+6) |
|
49 | THIS_LINE_NUMBER+6) | |
50 |
|
50 | |||
51 |
|
51 | |||
52 | # A couple of utilities to ensure these tests work the same from a source or a |
|
52 | # A couple of utilities to ensure these tests work the same from a source or a | |
53 | # binary install |
|
53 | # binary install | |
54 | def pyfile(fname): |
|
54 | def pyfile(fname): | |
55 | return os.path.normcase(re.sub('.py[co]$', '.py', fname)) |
|
55 | return os.path.normcase(re.sub('.py[co]$', '.py', fname)) | |
56 |
|
56 | |||
57 |
|
57 | |||
58 | def match_pyfiles(f1, f2): |
|
58 | def match_pyfiles(f1, f2): | |
59 |
|
|
59 | assert pyfile(f1) == pyfile(f2) | |
60 |
|
60 | |||
61 |
|
61 | |||
62 | def test_find_file(): |
|
62 | def test_find_file(): | |
63 | match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__)) |
|
63 | match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__)) | |
64 |
|
64 | |||
65 |
|
65 | |||
66 | def test_find_file_decorated1(): |
|
66 | def test_find_file_decorated1(): | |
67 |
|
67 | |||
68 | @decorator |
|
68 | @decorator | |
69 | def noop1(f): |
|
69 | def noop1(f): | |
70 | def wrapper(*a, **kw): |
|
70 | def wrapper(*a, **kw): | |
71 | return f(*a, **kw) |
|
71 | return f(*a, **kw) | |
72 | return wrapper |
|
72 | return wrapper | |
73 |
|
73 | |||
74 | @noop1 |
|
74 | @noop1 | |
75 | def f(x): |
|
75 | def f(x): | |
76 | "My docstring" |
|
76 | "My docstring" | |
77 |
|
77 | |||
78 | match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__)) |
|
78 | match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__)) | |
79 |
|
|
79 | assert f.__doc__ == "My docstring" | |
80 |
|
80 | |||
81 |
|
81 | |||
82 | def test_find_file_decorated2(): |
|
82 | def test_find_file_decorated2(): | |
83 |
|
83 | |||
84 | @decorator |
|
84 | @decorator | |
85 | def noop2(f, *a, **kw): |
|
85 | def noop2(f, *a, **kw): | |
86 | return f(*a, **kw) |
|
86 | return f(*a, **kw) | |
87 |
|
87 | |||
88 | @noop2 |
|
88 | @noop2 | |
89 | @noop2 |
|
89 | @noop2 | |
90 | @noop2 |
|
90 | @noop2 | |
91 | def f(x): |
|
91 | def f(x): | |
92 | "My docstring 2" |
|
92 | "My docstring 2" | |
93 |
|
93 | |||
94 | match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__)) |
|
94 | match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__)) | |
95 |
|
|
95 | assert f.__doc__ == "My docstring 2" | |
96 |
|
96 | |||
97 |
|
97 | |||
98 | def test_find_file_magic(): |
|
98 | def test_find_file_magic(): | |
99 | run = ip.find_line_magic('run') |
|
99 | run = ip.find_line_magic('run') | |
100 | nt.assert_not_equal(oinspect.find_file(run), None) |
|
100 | nt.assert_not_equal(oinspect.find_file(run), None) | |
101 |
|
101 | |||
102 |
|
102 | |||
103 | # A few generic objects we can then inspect in the tests below |
|
103 | # A few generic objects we can then inspect in the tests below | |
104 |
|
104 | |||
105 | class Call(object): |
|
105 | class Call(object): | |
106 | """This is the class docstring.""" |
|
106 | """This is the class docstring.""" | |
107 |
|
107 | |||
108 | def __init__(self, x, y=1): |
|
108 | def __init__(self, x, y=1): | |
109 | """This is the constructor docstring.""" |
|
109 | """This is the constructor docstring.""" | |
110 |
|
110 | |||
111 | def __call__(self, *a, **kw): |
|
111 | def __call__(self, *a, **kw): | |
112 | """This is the call docstring.""" |
|
112 | """This is the call docstring.""" | |
113 |
|
113 | |||
114 | def method(self, x, z=2): |
|
114 | def method(self, x, z=2): | |
115 | """Some method's docstring""" |
|
115 | """Some method's docstring""" | |
116 |
|
116 | |||
117 | class HasSignature(object): |
|
117 | class HasSignature(object): | |
118 | """This is the class docstring.""" |
|
118 | """This is the class docstring.""" | |
119 | __signature__ = Signature([Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)]) |
|
119 | __signature__ = Signature([Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)]) | |
120 |
|
120 | |||
121 | def __init__(self, *args): |
|
121 | def __init__(self, *args): | |
122 | """This is the init docstring""" |
|
122 | """This is the init docstring""" | |
123 |
|
123 | |||
124 |
|
124 | |||
125 | class SimpleClass(object): |
|
125 | class SimpleClass(object): | |
126 | def method(self, x, z=2): |
|
126 | def method(self, x, z=2): | |
127 | """Some method's docstring""" |
|
127 | """Some method's docstring""" | |
128 |
|
128 | |||
129 |
|
129 | |||
130 | class Awkward(object): |
|
130 | class Awkward(object): | |
131 | def __getattr__(self, name): |
|
131 | def __getattr__(self, name): | |
132 | raise Exception(name) |
|
132 | raise Exception(name) | |
133 |
|
133 | |||
134 | class NoBoolCall: |
|
134 | class NoBoolCall: | |
135 | """ |
|
135 | """ | |
136 | callable with `__bool__` raising should still be inspect-able. |
|
136 | callable with `__bool__` raising should still be inspect-able. | |
137 | """ |
|
137 | """ | |
138 |
|
138 | |||
139 | def __call__(self): |
|
139 | def __call__(self): | |
140 | """does nothing""" |
|
140 | """does nothing""" | |
141 | pass |
|
141 | pass | |
142 |
|
142 | |||
143 | def __bool__(self): |
|
143 | def __bool__(self): | |
144 | """just raise NotImplemented""" |
|
144 | """just raise NotImplemented""" | |
145 | raise NotImplementedError('Must be implemented') |
|
145 | raise NotImplementedError('Must be implemented') | |
146 |
|
146 | |||
147 |
|
147 | |||
148 | class SerialLiar(object): |
|
148 | class SerialLiar(object): | |
149 | """Attribute accesses always get another copy of the same class. |
|
149 | """Attribute accesses always get another copy of the same class. | |
150 |
|
150 | |||
151 | unittest.mock.call does something similar, but it's not ideal for testing |
|
151 | unittest.mock.call does something similar, but it's not ideal for testing | |
152 | as the failure mode is to eat all your RAM. This gives up after 10k levels. |
|
152 | as the failure mode is to eat all your RAM. This gives up after 10k levels. | |
153 | """ |
|
153 | """ | |
154 | def __init__(self, max_fibbing_twig, lies_told=0): |
|
154 | def __init__(self, max_fibbing_twig, lies_told=0): | |
155 | if lies_told > 10000: |
|
155 | if lies_told > 10000: | |
156 | raise RuntimeError('Nose too long, honesty is the best policy') |
|
156 | raise RuntimeError('Nose too long, honesty is the best policy') | |
157 | self.max_fibbing_twig = max_fibbing_twig |
|
157 | self.max_fibbing_twig = max_fibbing_twig | |
158 | self.lies_told = lies_told |
|
158 | self.lies_told = lies_told | |
159 | max_fibbing_twig[0] = max(max_fibbing_twig[0], lies_told) |
|
159 | max_fibbing_twig[0] = max(max_fibbing_twig[0], lies_told) | |
160 |
|
160 | |||
161 | def __getattr__(self, item): |
|
161 | def __getattr__(self, item): | |
162 | return SerialLiar(self.max_fibbing_twig, self.lies_told + 1) |
|
162 | return SerialLiar(self.max_fibbing_twig, self.lies_told + 1) | |
163 |
|
163 | |||
164 | #----------------------------------------------------------------------------- |
|
164 | #----------------------------------------------------------------------------- | |
165 | # Tests |
|
165 | # Tests | |
166 | #----------------------------------------------------------------------------- |
|
166 | #----------------------------------------------------------------------------- | |
167 |
|
167 | |||
168 | def test_info(): |
|
168 | def test_info(): | |
169 | "Check that Inspector.info fills out various fields as expected." |
|
169 | "Check that Inspector.info fills out various fields as expected." | |
170 |
i = inspector.info(Call, oname= |
|
170 | i = inspector.info(Call, oname="Call") | |
171 |
|
|
171 | assert i["type_name"] == "type" | |
172 | expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'> |
|
172 | expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'> | |
173 |
|
|
173 | assert i["base_class"] == expted_class | |
174 | nt.assert_regex(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>") |
|
174 | nt.assert_regex( | |
|
175 | i["string_form"], | |||
|
176 | "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>", | |||
|
177 | ) | |||
175 | fname = __file__ |
|
178 | fname = __file__ | |
176 | if fname.endswith(".pyc"): |
|
179 | if fname.endswith(".pyc"): | |
177 | fname = fname[:-1] |
|
180 | fname = fname[:-1] | |
178 | # case-insensitive comparison needed on some filesystems |
|
181 | # case-insensitive comparison needed on some filesystems | |
179 | # e.g. Windows: |
|
182 | # e.g. Windows: | |
180 |
|
|
183 | assert i["file"].lower() == compress_user(fname).lower() | |
181 |
|
|
184 | assert i["definition"] == None | |
182 |
|
|
185 | assert i["docstring"] == Call.__doc__ | |
183 |
|
|
186 | assert i["source"] == None | |
184 |
nt.assert_true(i[ |
|
187 | nt.assert_true(i["isclass"]) | |
185 |
|
|
188 | assert i["init_definition"] == "Call(x, y=1)" | |
186 |
|
|
189 | assert i["init_docstring"] == Call.__init__.__doc__ | |
187 |
|
190 | |||
188 | i = inspector.info(Call, detail_level=1) |
|
191 | i = inspector.info(Call, detail_level=1) | |
189 |
nt.assert_not_equal(i[ |
|
192 | nt.assert_not_equal(i["source"], None) | |
190 |
|
|
193 | assert i["docstring"] == None | |
191 |
|
194 | |||
192 | c = Call(1) |
|
195 | c = Call(1) | |
193 | c.__doc__ = "Modified instance docstring" |
|
196 | c.__doc__ = "Modified instance docstring" | |
194 | i = inspector.info(c) |
|
197 | i = inspector.info(c) | |
195 |
|
|
198 | assert i["type_name"] == "Call" | |
196 |
|
|
199 | assert i["docstring"] == "Modified instance docstring" | |
197 |
|
|
200 | assert i["class_docstring"] == Call.__doc__ | |
198 |
|
|
201 | assert i["init_docstring"] == Call.__init__.__doc__ | |
199 |
|
|
202 | assert i["call_docstring"] == Call.__call__.__doc__ | |
|
203 | ||||
200 |
|
204 | |||
201 | def test_class_signature(): |
|
205 | def test_class_signature(): | |
202 |
info = inspector.info(HasSignature, |
|
206 | info = inspector.info(HasSignature, "HasSignature") | |
203 |
|
|
207 | assert info["init_definition"] == "HasSignature(test)" | |
204 |
|
|
208 | assert info["init_docstring"] == HasSignature.__init__.__doc__ | |
|
209 | ||||
205 |
|
210 | |||
206 | def test_info_awkward(): |
|
211 | def test_info_awkward(): | |
207 | # Just test that this doesn't throw an error. |
|
212 | # Just test that this doesn't throw an error. | |
208 | inspector.info(Awkward()) |
|
213 | inspector.info(Awkward()) | |
209 |
|
214 | |||
210 | def test_bool_raise(): |
|
215 | def test_bool_raise(): | |
211 | inspector.info(NoBoolCall()) |
|
216 | inspector.info(NoBoolCall()) | |
212 |
|
217 | |||
213 | def test_info_serialliar(): |
|
218 | def test_info_serialliar(): | |
214 | fib_tracker = [0] |
|
219 | fib_tracker = [0] | |
215 | inspector.info(SerialLiar(fib_tracker)) |
|
220 | inspector.info(SerialLiar(fib_tracker)) | |
216 |
|
221 | |||
217 | # Nested attribute access should be cut off at 100 levels deep to avoid |
|
222 | # Nested attribute access should be cut off at 100 levels deep to avoid | |
218 | # infinite loops: https://github.com/ipython/ipython/issues/9122 |
|
223 | # infinite loops: https://github.com/ipython/ipython/issues/9122 | |
219 | nt.assert_less(fib_tracker[0], 9000) |
|
224 | nt.assert_less(fib_tracker[0], 9000) | |
220 |
|
225 | |||
221 | def support_function_one(x, y=2, *a, **kw): |
|
226 | def support_function_one(x, y=2, *a, **kw): | |
222 | """A simple function.""" |
|
227 | """A simple function.""" | |
223 |
|
228 | |||
224 | def test_calldef_none(): |
|
229 | def test_calldef_none(): | |
225 | # We should ignore __call__ for all of these. |
|
230 | # We should ignore __call__ for all of these. | |
226 | for obj in [support_function_one, SimpleClass().method, any, str.upper]: |
|
231 | for obj in [support_function_one, SimpleClass().method, any, str.upper]: | |
227 | i = inspector.info(obj) |
|
232 | i = inspector.info(obj) | |
228 | nt.assert_is(i['call_def'], None) |
|
233 | nt.assert_is(i['call_def'], None) | |
229 |
|
234 | |||
230 | def f_kwarg(pos, *, kwonly): |
|
235 | def f_kwarg(pos, *, kwonly): | |
231 | pass |
|
236 | pass | |
232 |
|
237 | |||
233 | def test_definition_kwonlyargs(): |
|
238 | def test_definition_kwonlyargs(): | |
234 |
i = inspector.info(f_kwarg, oname= |
|
239 | i = inspector.info(f_kwarg, oname="f_kwarg") # analysis:ignore | |
235 |
|
|
240 | assert i["definition"] == "f_kwarg(pos, *, kwonly)" | |
|
241 | ||||
236 |
|
242 | |||
237 | def test_getdoc(): |
|
243 | def test_getdoc(): | |
238 | class A(object): |
|
244 | class A(object): | |
239 | """standard docstring""" |
|
245 | """standard docstring""" | |
240 | pass |
|
246 | pass | |
241 |
|
247 | |||
242 | class B(object): |
|
248 | class B(object): | |
243 | """standard docstring""" |
|
249 | """standard docstring""" | |
244 | def getdoc(self): |
|
250 | def getdoc(self): | |
245 | return "custom docstring" |
|
251 | return "custom docstring" | |
246 |
|
252 | |||
247 | class C(object): |
|
253 | class C(object): | |
248 | """standard docstring""" |
|
254 | """standard docstring""" | |
249 | def getdoc(self): |
|
255 | def getdoc(self): | |
250 | return None |
|
256 | return None | |
251 |
|
257 | |||
252 | a = A() |
|
258 | a = A() | |
253 | b = B() |
|
259 | b = B() | |
254 | c = C() |
|
260 | c = C() | |
255 |
|
261 | |||
256 |
|
|
262 | assert oinspect.getdoc(a) == "standard docstring" | |
257 |
|
|
263 | assert oinspect.getdoc(b) == "custom docstring" | |
258 |
|
|
264 | assert oinspect.getdoc(c) == "standard docstring" | |
259 |
|
265 | |||
260 |
|
266 | |||
261 | def test_empty_property_has_no_source(): |
|
267 | def test_empty_property_has_no_source(): | |
262 | i = inspector.info(property(), detail_level=1) |
|
268 | i = inspector.info(property(), detail_level=1) | |
263 | nt.assert_is(i['source'], None) |
|
269 | nt.assert_is(i['source'], None) | |
264 |
|
270 | |||
265 |
|
271 | |||
266 | def test_property_sources(): |
|
272 | def test_property_sources(): | |
267 | import posixpath |
|
273 | import posixpath | |
268 | # A simple adder whose source and signature stays |
|
274 | # A simple adder whose source and signature stays | |
269 | # the same across Python distributions |
|
275 | # the same across Python distributions | |
270 | def simple_add(a, b): |
|
276 | def simple_add(a, b): | |
271 | "Adds two numbers" |
|
277 | "Adds two numbers" | |
272 | return a + b |
|
278 | return a + b | |
273 |
|
279 | |||
274 | class A(object): |
|
280 | class A(object): | |
275 | @property |
|
281 | @property | |
276 | def foo(self): |
|
282 | def foo(self): | |
277 | return 'bar' |
|
283 | return 'bar' | |
278 |
|
284 | |||
279 | foo = foo.setter(lambda self, v: setattr(self, 'bar', v)) |
|
285 | foo = foo.setter(lambda self, v: setattr(self, 'bar', v)) | |
280 |
|
286 | |||
281 | dname = property(posixpath.dirname) |
|
287 | dname = property(posixpath.dirname) | |
282 | adder = property(simple_add) |
|
288 | adder = property(simple_add) | |
283 |
|
289 | |||
284 | i = inspector.info(A.foo, detail_level=1) |
|
290 | i = inspector.info(A.foo, detail_level=1) | |
285 | nt.assert_in('def foo(self):', i['source']) |
|
291 | nt.assert_in('def foo(self):', i['source']) | |
286 | nt.assert_in('lambda self, v:', i['source']) |
|
292 | nt.assert_in('lambda self, v:', i['source']) | |
287 |
|
293 | |||
288 | i = inspector.info(A.dname, detail_level=1) |
|
294 | i = inspector.info(A.dname, detail_level=1) | |
289 | nt.assert_in('def dirname(p)', i['source']) |
|
295 | nt.assert_in('def dirname(p)', i['source']) | |
290 |
|
296 | |||
291 | i = inspector.info(A.adder, detail_level=1) |
|
297 | i = inspector.info(A.adder, detail_level=1) | |
292 | nt.assert_in('def simple_add(a, b)', i['source']) |
|
298 | nt.assert_in('def simple_add(a, b)', i['source']) | |
293 |
|
299 | |||
294 |
|
300 | |||
295 | def test_property_docstring_is_in_info_for_detail_level_0(): |
|
301 | def test_property_docstring_is_in_info_for_detail_level_0(): | |
296 | class A(object): |
|
302 | class A(object): | |
297 | @property |
|
303 | @property | |
298 | def foobar(self): |
|
304 | def foobar(self): | |
299 | """This is `foobar` property.""" |
|
305 | """This is `foobar` property.""" | |
300 | pass |
|
306 | pass | |
301 |
|
307 | |||
302 |
ip.user_ns[ |
|
308 | ip.user_ns["a_obj"] = A() | |
303 |
|
|
309 | assert ( | |
304 |
|
|
310 | "This is `foobar` property." | |
305 |
ip.object_inspect( |
|
311 | == ip.object_inspect("a_obj.foobar", detail_level=0)["docstring"] | |
|
312 | ) | |||
306 |
|
313 | |||
307 |
ip.user_ns[ |
|
314 | ip.user_ns["a_cls"] = A | |
308 |
|
|
315 | assert ( | |
309 |
|
|
316 | "This is `foobar` property." | |
310 |
ip.object_inspect( |
|
317 | == ip.object_inspect("a_cls.foobar", detail_level=0)["docstring"] | |
|
318 | ) | |||
311 |
|
319 | |||
312 |
|
320 | |||
313 | def test_pdef(): |
|
321 | def test_pdef(): | |
314 | # See gh-1914 |
|
322 | # See gh-1914 | |
315 | def foo(): pass |
|
323 | def foo(): pass | |
316 | inspector.pdef(foo, 'foo') |
|
324 | inspector.pdef(foo, 'foo') | |
317 |
|
325 | |||
318 |
|
326 | |||
319 | def test_pinfo_nonascii(): |
|
327 | def test_pinfo_nonascii(): | |
320 | # See gh-1177 |
|
328 | # See gh-1177 | |
321 | from . import nonascii2 |
|
329 | from . import nonascii2 | |
322 | ip.user_ns['nonascii2'] = nonascii2 |
|
330 | ip.user_ns['nonascii2'] = nonascii2 | |
323 | ip._inspect('pinfo', 'nonascii2', detail_level=1) |
|
331 | ip._inspect('pinfo', 'nonascii2', detail_level=1) | |
324 |
|
332 | |||
325 | def test_pinfo_type(): |
|
333 | def test_pinfo_type(): | |
326 | """ |
|
334 | """ | |
327 | type can fail in various edge case, for example `type.__subclass__()` |
|
335 | type can fail in various edge case, for example `type.__subclass__()` | |
328 | """ |
|
336 | """ | |
329 | ip._inspect('pinfo', 'type') |
|
337 | ip._inspect('pinfo', 'type') | |
330 |
|
338 | |||
331 |
|
339 | |||
332 | def test_pinfo_docstring_no_source(): |
|
340 | def test_pinfo_docstring_no_source(): | |
333 | """Docstring should be included with detail_level=1 if there is no source""" |
|
341 | """Docstring should be included with detail_level=1 if there is no source""" | |
334 | with AssertPrints('Docstring:'): |
|
342 | with AssertPrints('Docstring:'): | |
335 | ip._inspect('pinfo', 'str.format', detail_level=0) |
|
343 | ip._inspect('pinfo', 'str.format', detail_level=0) | |
336 | with AssertPrints('Docstring:'): |
|
344 | with AssertPrints('Docstring:'): | |
337 | ip._inspect('pinfo', 'str.format', detail_level=1) |
|
345 | ip._inspect('pinfo', 'str.format', detail_level=1) | |
338 |
|
346 | |||
339 |
|
347 | |||
340 | def test_pinfo_no_docstring_if_source(): |
|
348 | def test_pinfo_no_docstring_if_source(): | |
341 | """Docstring should not be included with detail_level=1 if source is found""" |
|
349 | """Docstring should not be included with detail_level=1 if source is found""" | |
342 | def foo(): |
|
350 | def foo(): | |
343 | """foo has a docstring""" |
|
351 | """foo has a docstring""" | |
344 |
|
352 | |||
345 | ip.user_ns['foo'] = foo |
|
353 | ip.user_ns['foo'] = foo | |
346 |
|
354 | |||
347 | with AssertPrints('Docstring:'): |
|
355 | with AssertPrints('Docstring:'): | |
348 | ip._inspect('pinfo', 'foo', detail_level=0) |
|
356 | ip._inspect('pinfo', 'foo', detail_level=0) | |
349 | with AssertPrints('Source:'): |
|
357 | with AssertPrints('Source:'): | |
350 | ip._inspect('pinfo', 'foo', detail_level=1) |
|
358 | ip._inspect('pinfo', 'foo', detail_level=1) | |
351 | with AssertNotPrints('Docstring:'): |
|
359 | with AssertNotPrints('Docstring:'): | |
352 | ip._inspect('pinfo', 'foo', detail_level=1) |
|
360 | ip._inspect('pinfo', 'foo', detail_level=1) | |
353 |
|
361 | |||
354 |
|
362 | |||
355 | def test_pinfo_docstring_if_detail_and_no_source(): |
|
363 | def test_pinfo_docstring_if_detail_and_no_source(): | |
356 | """ Docstring should be displayed if source info not available """ |
|
364 | """ Docstring should be displayed if source info not available """ | |
357 | obj_def = '''class Foo(object): |
|
365 | obj_def = '''class Foo(object): | |
358 | """ This is a docstring for Foo """ |
|
366 | """ This is a docstring for Foo """ | |
359 | def bar(self): |
|
367 | def bar(self): | |
360 | """ This is a docstring for Foo.bar """ |
|
368 | """ This is a docstring for Foo.bar """ | |
361 | pass |
|
369 | pass | |
362 | ''' |
|
370 | ''' | |
363 |
|
371 | |||
364 | ip.run_cell(obj_def) |
|
372 | ip.run_cell(obj_def) | |
365 | ip.run_cell('foo = Foo()') |
|
373 | ip.run_cell('foo = Foo()') | |
366 |
|
374 | |||
367 | with AssertNotPrints("Source:"): |
|
375 | with AssertNotPrints("Source:"): | |
368 | with AssertPrints('Docstring:'): |
|
376 | with AssertPrints('Docstring:'): | |
369 | ip._inspect('pinfo', 'foo', detail_level=0) |
|
377 | ip._inspect('pinfo', 'foo', detail_level=0) | |
370 | with AssertPrints('Docstring:'): |
|
378 | with AssertPrints('Docstring:'): | |
371 | ip._inspect('pinfo', 'foo', detail_level=1) |
|
379 | ip._inspect('pinfo', 'foo', detail_level=1) | |
372 | with AssertPrints('Docstring:'): |
|
380 | with AssertPrints('Docstring:'): | |
373 | ip._inspect('pinfo', 'foo.bar', detail_level=0) |
|
381 | ip._inspect('pinfo', 'foo.bar', detail_level=0) | |
374 |
|
382 | |||
375 | with AssertNotPrints('Docstring:'): |
|
383 | with AssertNotPrints('Docstring:'): | |
376 | with AssertPrints('Source:'): |
|
384 | with AssertPrints('Source:'): | |
377 | ip._inspect('pinfo', 'foo.bar', detail_level=1) |
|
385 | ip._inspect('pinfo', 'foo.bar', detail_level=1) | |
378 |
|
386 | |||
379 |
|
387 | |||
380 | def test_pinfo_magic(): |
|
388 | def test_pinfo_magic(): | |
381 | with AssertPrints('Docstring:'): |
|
389 | with AssertPrints('Docstring:'): | |
382 | ip._inspect('pinfo', 'lsmagic', detail_level=0) |
|
390 | ip._inspect('pinfo', 'lsmagic', detail_level=0) | |
383 |
|
391 | |||
384 | with AssertPrints('Source:'): |
|
392 | with AssertPrints('Source:'): | |
385 | ip._inspect('pinfo', 'lsmagic', detail_level=1) |
|
393 | ip._inspect('pinfo', 'lsmagic', detail_level=1) | |
386 |
|
394 | |||
387 |
|
395 | |||
388 | def test_init_colors(): |
|
396 | def test_init_colors(): | |
389 | # ensure colors are not present in signature info |
|
397 | # ensure colors are not present in signature info | |
390 | info = inspector.info(HasSignature) |
|
398 | info = inspector.info(HasSignature) | |
391 | init_def = info['init_definition'] |
|
399 | init_def = info['init_definition'] | |
392 | nt.assert_not_in('[0m', init_def) |
|
400 | nt.assert_not_in('[0m', init_def) | |
393 |
|
401 | |||
394 |
|
402 | |||
395 | def test_builtin_init(): |
|
403 | def test_builtin_init(): | |
396 | info = inspector.info(list) |
|
404 | info = inspector.info(list) | |
397 | init_def = info['init_definition'] |
|
405 | init_def = info['init_definition'] | |
398 | nt.assert_is_not_none(init_def) |
|
406 | nt.assert_is_not_none(init_def) | |
399 |
|
407 | |||
400 |
|
408 | |||
401 | def test_render_signature_short(): |
|
409 | def test_render_signature_short(): | |
402 | def short_fun(a=1): pass |
|
410 | def short_fun(a=1): pass | |
403 | sig = oinspect._render_signature( |
|
411 | sig = oinspect._render_signature( | |
404 | signature(short_fun), |
|
412 | signature(short_fun), | |
405 | short_fun.__name__, |
|
413 | short_fun.__name__, | |
406 | ) |
|
414 | ) | |
407 |
|
|
415 | assert sig == "short_fun(a=1)" | |
408 |
|
416 | |||
409 |
|
417 | |||
410 | def test_render_signature_long(): |
|
418 | def test_render_signature_long(): | |
411 | from typing import Optional |
|
419 | from typing import Optional | |
412 |
|
420 | |||
413 | def long_function( |
|
421 | def long_function( | |
414 | a_really_long_parameter: int, |
|
422 | a_really_long_parameter: int, | |
415 | and_another_long_one: bool = False, |
|
423 | and_another_long_one: bool = False, | |
416 | let_us_make_sure_this_is_looong: Optional[str] = None, |
|
424 | let_us_make_sure_this_is_looong: Optional[str] = None, | |
417 | ) -> bool: pass |
|
425 | ) -> bool: pass | |
418 |
|
426 | |||
419 | sig = oinspect._render_signature( |
|
427 | sig = oinspect._render_signature( | |
420 | signature(long_function), |
|
428 | signature(long_function), | |
421 | long_function.__name__, |
|
429 | long_function.__name__, | |
422 | ) |
|
430 | ) | |
423 | nt.assert_in(sig, [ |
|
431 | nt.assert_in(sig, [ | |
424 | # Python >=3.9 |
|
432 | # Python >=3.9 | |
425 | '''\ |
|
433 | '''\ | |
426 | long_function( |
|
434 | long_function( | |
427 | a_really_long_parameter: int, |
|
435 | a_really_long_parameter: int, | |
428 | and_another_long_one: bool = False, |
|
436 | and_another_long_one: bool = False, | |
429 | let_us_make_sure_this_is_looong: Optional[str] = None, |
|
437 | let_us_make_sure_this_is_looong: Optional[str] = None, | |
430 | ) -> bool\ |
|
438 | ) -> bool\ | |
431 | ''', |
|
439 | ''', | |
432 | # Python >=3.7 |
|
440 | # Python >=3.7 | |
433 | '''\ |
|
441 | '''\ | |
434 | long_function( |
|
442 | long_function( | |
435 | a_really_long_parameter: int, |
|
443 | a_really_long_parameter: int, | |
436 | and_another_long_one: bool = False, |
|
444 | and_another_long_one: bool = False, | |
437 | let_us_make_sure_this_is_looong: Union[str, NoneType] = None, |
|
445 | let_us_make_sure_this_is_looong: Union[str, NoneType] = None, | |
438 | ) -> bool\ |
|
446 | ) -> bool\ | |
439 | ''', # Python <=3.6 |
|
447 | ''', # Python <=3.6 | |
440 | '''\ |
|
448 | '''\ | |
441 | long_function( |
|
449 | long_function( | |
442 | a_really_long_parameter:int, |
|
450 | a_really_long_parameter:int, | |
443 | and_another_long_one:bool=False, |
|
451 | and_another_long_one:bool=False, | |
444 | let_us_make_sure_this_is_looong:Union[str, NoneType]=None, |
|
452 | let_us_make_sure_this_is_looong:Union[str, NoneType]=None, | |
445 | ) -> bool\ |
|
453 | ) -> bool\ | |
446 | ''', |
|
454 | ''', | |
447 | ]) |
|
455 | ]) |
@@ -1,88 +1,85 b'' | |||||
1 | """Tests for pylab tools module. |
|
1 | """Tests for pylab tools module. | |
2 | """ |
|
2 | """ | |
3 | #----------------------------------------------------------------------------- |
|
3 | #----------------------------------------------------------------------------- | |
4 | # Copyright (c) 2011, the IPython Development Team. |
|
4 | # Copyright (c) 2011, the IPython Development Team. | |
5 | # |
|
5 | # | |
6 | # Distributed under the terms of the Modified BSD License. |
|
6 | # Distributed under the terms of the Modified BSD License. | |
7 | # |
|
7 | # | |
8 | # The full license is in the file COPYING.txt, distributed with this software. |
|
8 | # The full license is in the file COPYING.txt, distributed with this software. | |
9 | #----------------------------------------------------------------------------- |
|
9 | #----------------------------------------------------------------------------- | |
10 |
|
10 | |||
11 | #----------------------------------------------------------------------------- |
|
11 | #----------------------------------------------------------------------------- | |
12 | # Imports |
|
12 | # Imports | |
13 | #----------------------------------------------------------------------------- |
|
13 | #----------------------------------------------------------------------------- | |
14 |
|
14 | |||
15 | # Stdlib imports |
|
15 | # Stdlib imports | |
16 | import time |
|
16 | import time | |
17 |
|
17 | |||
18 | # Third-party imports |
|
|||
19 | import nose.tools as nt |
|
|||
20 |
|
||||
21 | # Our own imports |
|
18 | # Our own imports | |
22 | from IPython.lib import backgroundjobs as bg |
|
19 | from IPython.lib import backgroundjobs as bg | |
23 |
|
20 | |||
24 | #----------------------------------------------------------------------------- |
|
21 | #----------------------------------------------------------------------------- | |
25 | # Globals and constants |
|
22 | # Globals and constants | |
26 | #----------------------------------------------------------------------------- |
|
23 | #----------------------------------------------------------------------------- | |
27 | t_short = 0.0001 # very short interval to wait on jobs |
|
24 | t_short = 0.0001 # very short interval to wait on jobs | |
28 |
|
25 | |||
29 | #----------------------------------------------------------------------------- |
|
26 | #----------------------------------------------------------------------------- | |
30 | # Local utilities |
|
27 | # Local utilities | |
31 | #----------------------------------------------------------------------------- |
|
28 | #----------------------------------------------------------------------------- | |
32 | def sleeper(interval=t_short, *a, **kw): |
|
29 | def sleeper(interval=t_short, *a, **kw): | |
33 | args = dict(interval=interval, |
|
30 | args = dict(interval=interval, | |
34 | other_args=a, |
|
31 | other_args=a, | |
35 | kw_args=kw) |
|
32 | kw_args=kw) | |
36 | time.sleep(interval) |
|
33 | time.sleep(interval) | |
37 | return args |
|
34 | return args | |
38 |
|
35 | |||
39 | def crasher(interval=t_short, *a, **kw): |
|
36 | def crasher(interval=t_short, *a, **kw): | |
40 | time.sleep(interval) |
|
37 | time.sleep(interval) | |
41 | raise Exception("Dead job with interval %s" % interval) |
|
38 | raise Exception("Dead job with interval %s" % interval) | |
42 |
|
39 | |||
43 | #----------------------------------------------------------------------------- |
|
40 | #----------------------------------------------------------------------------- | |
44 | # Classes and functions |
|
41 | # Classes and functions | |
45 | #----------------------------------------------------------------------------- |
|
42 | #----------------------------------------------------------------------------- | |
46 |
|
43 | |||
47 | def test_result(): |
|
44 | def test_result(): | |
48 | """Test job submission and result retrieval""" |
|
45 | """Test job submission and result retrieval""" | |
49 | jobs = bg.BackgroundJobManager() |
|
46 | jobs = bg.BackgroundJobManager() | |
50 | j = jobs.new(sleeper) |
|
47 | j = jobs.new(sleeper) | |
51 | j.join() |
|
48 | j.join() | |
52 |
|
|
49 | assert j.result["interval"] == t_short | |
53 |
|
50 | |||
54 |
|
51 | |||
55 | def test_flush(): |
|
52 | def test_flush(): | |
56 | """Test job control""" |
|
53 | """Test job control""" | |
57 | jobs = bg.BackgroundJobManager() |
|
54 | jobs = bg.BackgroundJobManager() | |
58 | j = jobs.new(sleeper) |
|
55 | j = jobs.new(sleeper) | |
59 | j.join() |
|
56 | j.join() | |
60 |
|
|
57 | assert len(jobs.completed) == 1 | |
61 |
|
|
58 | assert len(jobs.dead) == 0 | |
62 | jobs.flush() |
|
59 | jobs.flush() | |
63 |
|
|
60 | assert len(jobs.completed) == 0 | |
64 |
|
61 | |||
65 |
|
62 | |||
66 | def test_dead(): |
|
63 | def test_dead(): | |
67 | """Test control of dead jobs""" |
|
64 | """Test control of dead jobs""" | |
68 | jobs = bg.BackgroundJobManager() |
|
65 | jobs = bg.BackgroundJobManager() | |
69 | j = jobs.new(crasher) |
|
66 | j = jobs.new(crasher) | |
70 | j.join() |
|
67 | j.join() | |
71 |
|
|
68 | assert len(jobs.completed) == 0 | |
72 |
|
|
69 | assert len(jobs.dead) == 1 | |
73 | jobs.flush() |
|
70 | jobs.flush() | |
74 |
|
|
71 | assert len(jobs.dead) == 0 | |
75 |
|
72 | |||
76 |
|
73 | |||
77 | def test_longer(): |
|
74 | def test_longer(): | |
78 | """Test control of longer-running jobs""" |
|
75 | """Test control of longer-running jobs""" | |
79 | jobs = bg.BackgroundJobManager() |
|
76 | jobs = bg.BackgroundJobManager() | |
80 | # Sleep for long enough for the following two checks to still report the |
|
77 | # Sleep for long enough for the following two checks to still report the | |
81 | # job as running, but not so long that it makes the test suite noticeably |
|
78 | # job as running, but not so long that it makes the test suite noticeably | |
82 | # slower. |
|
79 | # slower. | |
83 | j = jobs.new(sleeper, 0.1) |
|
80 | j = jobs.new(sleeper, 0.1) | |
84 |
|
|
81 | assert len(jobs.running) == 1 | |
85 |
|
|
82 | assert len(jobs.completed) == 0 | |
86 | j.join() |
|
83 | j.join() | |
87 |
|
|
84 | assert len(jobs.running) == 0 | |
88 |
|
|
85 | assert len(jobs.completed) == 1 |
@@ -1,266 +1,272 b'' | |||||
1 | """Tests for IPython.lib.display. |
|
1 | """Tests for IPython.lib.display. | |
2 |
|
2 | |||
3 | """ |
|
3 | """ | |
4 | #----------------------------------------------------------------------------- |
|
4 | #----------------------------------------------------------------------------- | |
5 | # Copyright (c) 2012, the IPython Development Team. |
|
5 | # Copyright (c) 2012, the IPython Development Team. | |
6 | # |
|
6 | # | |
7 | # Distributed under the terms of the Modified BSD License. |
|
7 | # Distributed under the terms of the Modified BSD License. | |
8 | # |
|
8 | # | |
9 | # The full license is in the file COPYING.txt, distributed with this software. |
|
9 | # The full license is in the file COPYING.txt, distributed with this software. | |
10 | #----------------------------------------------------------------------------- |
|
10 | #----------------------------------------------------------------------------- | |
11 |
|
11 | |||
12 | #----------------------------------------------------------------------------- |
|
12 | #----------------------------------------------------------------------------- | |
13 | # Imports |
|
13 | # Imports | |
14 | #----------------------------------------------------------------------------- |
|
14 | #----------------------------------------------------------------------------- | |
15 | from tempfile import NamedTemporaryFile, mkdtemp |
|
15 | from tempfile import NamedTemporaryFile, mkdtemp | |
16 | from os.path import split, join as pjoin, dirname |
|
16 | from os.path import split, join as pjoin, dirname | |
17 | import pathlib |
|
17 | import pathlib | |
18 | from unittest import TestCase, mock |
|
18 | from unittest import TestCase, mock | |
19 | import struct |
|
19 | import struct | |
20 | import wave |
|
20 | import wave | |
21 | from io import BytesIO |
|
21 | from io import BytesIO | |
22 |
|
22 | |||
23 | # Third-party imports |
|
23 | # Third-party imports | |
24 | import nose.tools as nt |
|
24 | import nose.tools as nt | |
25 |
|
25 | |||
26 | try: |
|
26 | try: | |
27 | import numpy |
|
27 | import numpy | |
28 | except ImportError: |
|
28 | except ImportError: | |
29 | pass |
|
29 | pass | |
30 |
|
30 | |||
31 | # Our own imports |
|
31 | # Our own imports | |
32 | from IPython.lib import display |
|
32 | from IPython.lib import display | |
33 |
|
33 | |||
34 | from IPython.testing.decorators import skipif_not_numpy |
|
34 | from IPython.testing.decorators import skipif_not_numpy | |
35 |
|
35 | |||
36 | #----------------------------------------------------------------------------- |
|
36 | #----------------------------------------------------------------------------- | |
37 | # Classes and functions |
|
37 | # Classes and functions | |
38 | #----------------------------------------------------------------------------- |
|
38 | #----------------------------------------------------------------------------- | |
39 |
|
39 | |||
40 | #-------------------------- |
|
40 | #-------------------------- | |
41 | # FileLink tests |
|
41 | # FileLink tests | |
42 | #-------------------------- |
|
42 | #-------------------------- | |
43 |
|
43 | |||
44 | def test_instantiation_FileLink(): |
|
44 | def test_instantiation_FileLink(): | |
45 | """FileLink: Test class can be instantiated""" |
|
45 | """FileLink: Test class can be instantiated""" | |
46 | fl = display.FileLink('example.txt') |
|
46 | fl = display.FileLink('example.txt') | |
47 | # TODO: remove if when only Python >= 3.6 is supported |
|
47 | # TODO: remove if when only Python >= 3.6 is supported | |
48 | fl = display.FileLink(pathlib.PurePath('example.txt')) |
|
48 | fl = display.FileLink(pathlib.PurePath('example.txt')) | |
49 |
|
49 | |||
50 | def test_warning_on_non_existent_path_FileLink(): |
|
50 | def test_warning_on_non_existent_path_FileLink(): | |
51 | """FileLink: Calling _repr_html_ on non-existent files returns a warning |
|
51 | """FileLink: Calling _repr_html_ on non-existent files returns a warning | |
52 | """ |
|
52 | """ | |
53 | fl = display.FileLink('example.txt') |
|
53 | fl = display.FileLink('example.txt') | |
54 | nt.assert_true(fl._repr_html_().startswith('Path (<tt>example.txt</tt>)')) |
|
54 | nt.assert_true(fl._repr_html_().startswith('Path (<tt>example.txt</tt>)')) | |
55 |
|
55 | |||
56 | def test_existing_path_FileLink(): |
|
56 | def test_existing_path_FileLink(): | |
57 | """FileLink: Calling _repr_html_ functions as expected on existing filepath |
|
57 | """FileLink: Calling _repr_html_ functions as expected on existing filepath | |
58 | """ |
|
58 | """ | |
59 | tf = NamedTemporaryFile() |
|
59 | tf = NamedTemporaryFile() | |
60 | fl = display.FileLink(tf.name) |
|
60 | fl = display.FileLink(tf.name) | |
61 | actual = fl._repr_html_() |
|
61 | actual = fl._repr_html_() | |
62 | expected = "<a href='%s' target='_blank'>%s</a><br>" % (tf.name,tf.name) |
|
62 | expected = "<a href='%s' target='_blank'>%s</a><br>" % (tf.name, tf.name) | |
63 |
|
|
63 | assert actual == expected | |
|
64 | ||||
64 |
|
65 | |||
65 | def test_existing_path_FileLink_repr(): |
|
66 | def test_existing_path_FileLink_repr(): | |
66 | """FileLink: Calling repr() functions as expected on existing filepath |
|
67 | """FileLink: Calling repr() functions as expected on existing filepath | |
67 | """ |
|
68 | """ | |
68 | tf = NamedTemporaryFile() |
|
69 | tf = NamedTemporaryFile() | |
69 | fl = display.FileLink(tf.name) |
|
70 | fl = display.FileLink(tf.name) | |
70 | actual = repr(fl) |
|
71 | actual = repr(fl) | |
71 | expected = tf.name |
|
72 | expected = tf.name | |
72 |
|
|
73 | assert actual == expected | |
|
74 | ||||
73 |
|
75 | |||
74 | def test_error_on_directory_to_FileLink(): |
|
76 | def test_error_on_directory_to_FileLink(): | |
75 | """FileLink: Raises error when passed directory |
|
77 | """FileLink: Raises error when passed directory | |
76 | """ |
|
78 | """ | |
77 | td = mkdtemp() |
|
79 | td = mkdtemp() | |
78 | nt.assert_raises(ValueError,display.FileLink,td) |
|
80 | nt.assert_raises(ValueError,display.FileLink,td) | |
79 |
|
81 | |||
80 | #-------------------------- |
|
82 | #-------------------------- | |
81 | # FileLinks tests |
|
83 | # FileLinks tests | |
82 | #-------------------------- |
|
84 | #-------------------------- | |
83 |
|
85 | |||
84 | def test_instantiation_FileLinks(): |
|
86 | def test_instantiation_FileLinks(): | |
85 | """FileLinks: Test class can be instantiated |
|
87 | """FileLinks: Test class can be instantiated | |
86 | """ |
|
88 | """ | |
87 | fls = display.FileLinks('example') |
|
89 | fls = display.FileLinks('example') | |
88 |
|
90 | |||
89 | def test_warning_on_non_existent_path_FileLinks(): |
|
91 | def test_warning_on_non_existent_path_FileLinks(): | |
90 | """FileLinks: Calling _repr_html_ on non-existent files returns a warning |
|
92 | """FileLinks: Calling _repr_html_ on non-existent files returns a warning | |
91 | """ |
|
93 | """ | |
92 | fls = display.FileLinks('example') |
|
94 | fls = display.FileLinks('example') | |
93 | nt.assert_true(fls._repr_html_().startswith('Path (<tt>example</tt>)')) |
|
95 | nt.assert_true(fls._repr_html_().startswith('Path (<tt>example</tt>)')) | |
94 |
|
96 | |||
95 | def test_existing_path_FileLinks(): |
|
97 | def test_existing_path_FileLinks(): | |
96 | """FileLinks: Calling _repr_html_ functions as expected on existing dir |
|
98 | """FileLinks: Calling _repr_html_ functions as expected on existing dir | |
97 | """ |
|
99 | """ | |
98 | td = mkdtemp() |
|
100 | td = mkdtemp() | |
99 | tf1 = NamedTemporaryFile(dir=td) |
|
101 | tf1 = NamedTemporaryFile(dir=td) | |
100 | tf2 = NamedTemporaryFile(dir=td) |
|
102 | tf2 = NamedTemporaryFile(dir=td) | |
101 | fl = display.FileLinks(td) |
|
103 | fl = display.FileLinks(td) | |
102 | actual = fl._repr_html_() |
|
104 | actual = fl._repr_html_() | |
103 | actual = actual.split('\n') |
|
105 | actual = actual.split('\n') | |
104 | actual.sort() |
|
106 | actual.sort() | |
105 | # the links should always have forward slashes, even on windows, so replace |
|
107 | # the links should always have forward slashes, even on windows, so replace | |
106 | # backslashes with forward slashes here |
|
108 | # backslashes with forward slashes here | |
107 | expected = ["%s/<br>" % td, |
|
109 | expected = ["%s/<br>" % td, | |
108 | " <a href='%s' target='_blank'>%s</a><br>" %\ |
|
110 | " <a href='%s' target='_blank'>%s</a><br>" %\ | |
109 | (tf2.name.replace("\\","/"),split(tf2.name)[1]), |
|
111 | (tf2.name.replace("\\","/"),split(tf2.name)[1]), | |
110 | " <a href='%s' target='_blank'>%s</a><br>" %\ |
|
112 | " <a href='%s' target='_blank'>%s</a><br>" %\ | |
111 | (tf1.name.replace("\\","/"),split(tf1.name)[1])] |
|
113 | (tf1.name.replace("\\","/"),split(tf1.name)[1])] | |
112 | expected.sort() |
|
114 | expected.sort() | |
113 | # We compare the sorted list of links here as that's more reliable |
|
115 | # We compare the sorted list of links here as that's more reliable | |
114 |
|
|
116 | assert actual == expected | |
|
117 | ||||
115 |
|
118 | |||
116 | def test_existing_path_FileLinks_alt_formatter(): |
|
119 | def test_existing_path_FileLinks_alt_formatter(): | |
117 | """FileLinks: Calling _repr_html_ functions as expected w/ an alt formatter |
|
120 | """FileLinks: Calling _repr_html_ functions as expected w/ an alt formatter | |
118 | """ |
|
121 | """ | |
119 | td = mkdtemp() |
|
122 | td = mkdtemp() | |
120 | tf1 = NamedTemporaryFile(dir=td) |
|
123 | tf1 = NamedTemporaryFile(dir=td) | |
121 | tf2 = NamedTemporaryFile(dir=td) |
|
124 | tf2 = NamedTemporaryFile(dir=td) | |
122 | def fake_formatter(dirname,fnames,included_suffixes): |
|
125 | def fake_formatter(dirname,fnames,included_suffixes): | |
123 | return ["hello","world"] |
|
126 | return ["hello","world"] | |
124 | fl = display.FileLinks(td,notebook_display_formatter=fake_formatter) |
|
127 | fl = display.FileLinks(td,notebook_display_formatter=fake_formatter) | |
125 | actual = fl._repr_html_() |
|
128 | actual = fl._repr_html_() | |
126 | actual = actual.split('\n') |
|
129 | actual = actual.split('\n') | |
127 | actual.sort() |
|
130 | actual.sort() | |
128 | expected = ["hello","world"] |
|
131 | expected = ["hello","world"] | |
129 | expected.sort() |
|
132 | expected.sort() | |
130 | # We compare the sorted list of links here as that's more reliable |
|
133 | # We compare the sorted list of links here as that's more reliable | |
131 |
|
|
134 | assert actual == expected | |
|
135 | ||||
132 |
|
136 | |||
133 | def test_existing_path_FileLinks_repr(): |
|
137 | def test_existing_path_FileLinks_repr(): | |
134 | """FileLinks: Calling repr() functions as expected on existing directory """ |
|
138 | """FileLinks: Calling repr() functions as expected on existing directory """ | |
135 | td = mkdtemp() |
|
139 | td = mkdtemp() | |
136 | tf1 = NamedTemporaryFile(dir=td) |
|
140 | tf1 = NamedTemporaryFile(dir=td) | |
137 | tf2 = NamedTemporaryFile(dir=td) |
|
141 | tf2 = NamedTemporaryFile(dir=td) | |
138 | fl = display.FileLinks(td) |
|
142 | fl = display.FileLinks(td) | |
139 | actual = repr(fl) |
|
143 | actual = repr(fl) | |
140 | actual = actual.split('\n') |
|
144 | actual = actual.split('\n') | |
141 | actual.sort() |
|
145 | actual.sort() | |
142 | expected = ['%s/' % td, ' %s' % split(tf1.name)[1],' %s' % split(tf2.name)[1]] |
|
146 | expected = ['%s/' % td, ' %s' % split(tf1.name)[1],' %s' % split(tf2.name)[1]] | |
143 | expected.sort() |
|
147 | expected.sort() | |
144 | # We compare the sorted list of links here as that's more reliable |
|
148 | # We compare the sorted list of links here as that's more reliable | |
145 |
|
|
149 | assert actual == expected | |
146 |
|
150 | |||
|
151 | ||||
147 | def test_existing_path_FileLinks_repr_alt_formatter(): |
|
152 | def test_existing_path_FileLinks_repr_alt_formatter(): | |
148 | """FileLinks: Calling repr() functions as expected w/ alt formatter |
|
153 | """FileLinks: Calling repr() functions as expected w/ alt formatter | |
149 | """ |
|
154 | """ | |
150 | td = mkdtemp() |
|
155 | td = mkdtemp() | |
151 | tf1 = NamedTemporaryFile(dir=td) |
|
156 | tf1 = NamedTemporaryFile(dir=td) | |
152 | tf2 = NamedTemporaryFile(dir=td) |
|
157 | tf2 = NamedTemporaryFile(dir=td) | |
153 | def fake_formatter(dirname,fnames,included_suffixes): |
|
158 | def fake_formatter(dirname,fnames,included_suffixes): | |
154 | return ["hello","world"] |
|
159 | return ["hello","world"] | |
155 | fl = display.FileLinks(td,terminal_display_formatter=fake_formatter) |
|
160 | fl = display.FileLinks(td,terminal_display_formatter=fake_formatter) | |
156 | actual = repr(fl) |
|
161 | actual = repr(fl) | |
157 | actual = actual.split('\n') |
|
162 | actual = actual.split('\n') | |
158 | actual.sort() |
|
163 | actual.sort() | |
159 | expected = ["hello","world"] |
|
164 | expected = ["hello","world"] | |
160 | expected.sort() |
|
165 | expected.sort() | |
161 | # We compare the sorted list of links here as that's more reliable |
|
166 | # We compare the sorted list of links here as that's more reliable | |
162 |
|
|
167 | assert actual == expected | |
163 |
|
168 | |||
|
169 | ||||
164 | def test_error_on_file_to_FileLinks(): |
|
170 | def test_error_on_file_to_FileLinks(): | |
165 | """FileLinks: Raises error when passed file |
|
171 | """FileLinks: Raises error when passed file | |
166 | """ |
|
172 | """ | |
167 | td = mkdtemp() |
|
173 | td = mkdtemp() | |
168 | tf1 = NamedTemporaryFile(dir=td) |
|
174 | tf1 = NamedTemporaryFile(dir=td) | |
169 | nt.assert_raises(ValueError,display.FileLinks,tf1.name) |
|
175 | nt.assert_raises(ValueError,display.FileLinks,tf1.name) | |
170 |
|
176 | |||
171 | def test_recursive_FileLinks(): |
|
177 | def test_recursive_FileLinks(): | |
172 | """FileLinks: Does not recurse when recursive=False |
|
178 | """FileLinks: Does not recurse when recursive=False | |
173 | """ |
|
179 | """ | |
174 | td = mkdtemp() |
|
180 | td = mkdtemp() | |
175 | tf = NamedTemporaryFile(dir=td) |
|
181 | tf = NamedTemporaryFile(dir=td) | |
176 | subtd = mkdtemp(dir=td) |
|
182 | subtd = mkdtemp(dir=td) | |
177 | subtf = NamedTemporaryFile(dir=subtd) |
|
183 | subtf = NamedTemporaryFile(dir=subtd) | |
178 | fl = display.FileLinks(td) |
|
184 | fl = display.FileLinks(td) | |
179 | actual = str(fl) |
|
185 | actual = str(fl) | |
180 | actual = actual.split('\n') |
|
186 | actual = actual.split('\n') | |
181 |
|
|
187 | assert len(actual) == 4, actual | |
182 | fl = display.FileLinks(td, recursive=False) |
|
188 | fl = display.FileLinks(td, recursive=False) | |
183 | actual = str(fl) |
|
189 | actual = str(fl) | |
184 | actual = actual.split('\n') |
|
190 | actual = actual.split('\n') | |
185 |
|
|
191 | assert len(actual) == 2, actual | |
186 |
|
192 | |||
187 | def test_audio_from_file(): |
|
193 | def test_audio_from_file(): | |
188 | path = pjoin(dirname(__file__), 'test.wav') |
|
194 | path = pjoin(dirname(__file__), 'test.wav') | |
189 | display.Audio(filename=path) |
|
195 | display.Audio(filename=path) | |
190 |
|
196 | |||
191 | class TestAudioDataWithNumpy(TestCase): |
|
197 | class TestAudioDataWithNumpy(TestCase): | |
192 |
|
198 | |||
193 | @skipif_not_numpy |
|
199 | @skipif_not_numpy | |
194 | def test_audio_from_numpy_array(self): |
|
200 | def test_audio_from_numpy_array(self): | |
195 | test_tone = get_test_tone() |
|
201 | test_tone = get_test_tone() | |
196 | audio = display.Audio(test_tone, rate=44100) |
|
202 | audio = display.Audio(test_tone, rate=44100) | |
197 |
|
|
203 | assert len(read_wav(audio.data)) == len(test_tone) | |
198 |
|
204 | |||
199 | @skipif_not_numpy |
|
205 | @skipif_not_numpy | |
200 | def test_audio_from_list(self): |
|
206 | def test_audio_from_list(self): | |
201 | test_tone = get_test_tone() |
|
207 | test_tone = get_test_tone() | |
202 | audio = display.Audio(list(test_tone), rate=44100) |
|
208 | audio = display.Audio(list(test_tone), rate=44100) | |
203 |
|
|
209 | assert len(read_wav(audio.data)) == len(test_tone) | |
204 |
|
210 | |||
205 | @skipif_not_numpy |
|
211 | @skipif_not_numpy | |
206 | def test_audio_from_numpy_array_without_rate_raises(self): |
|
212 | def test_audio_from_numpy_array_without_rate_raises(self): | |
207 | nt.assert_raises(ValueError, display.Audio, get_test_tone()) |
|
213 | nt.assert_raises(ValueError, display.Audio, get_test_tone()) | |
208 |
|
214 | |||
209 | @skipif_not_numpy |
|
215 | @skipif_not_numpy | |
210 | def test_audio_data_normalization(self): |
|
216 | def test_audio_data_normalization(self): | |
211 | expected_max_value = numpy.iinfo(numpy.int16).max |
|
217 | expected_max_value = numpy.iinfo(numpy.int16).max | |
212 | for scale in [1, 0.5, 2]: |
|
218 | for scale in [1, 0.5, 2]: | |
213 | audio = display.Audio(get_test_tone(scale), rate=44100) |
|
219 | audio = display.Audio(get_test_tone(scale), rate=44100) | |
214 | actual_max_value = numpy.max(numpy.abs(read_wav(audio.data))) |
|
220 | actual_max_value = numpy.max(numpy.abs(read_wav(audio.data))) | |
215 |
|
|
221 | assert actual_max_value == expected_max_value | |
216 |
|
222 | |||
217 | @skipif_not_numpy |
|
223 | @skipif_not_numpy | |
218 | def test_audio_data_without_normalization(self): |
|
224 | def test_audio_data_without_normalization(self): | |
219 | max_int16 = numpy.iinfo(numpy.int16).max |
|
225 | max_int16 = numpy.iinfo(numpy.int16).max | |
220 | for scale in [1, 0.5, 0.2]: |
|
226 | for scale in [1, 0.5, 0.2]: | |
221 | test_tone = get_test_tone(scale) |
|
227 | test_tone = get_test_tone(scale) | |
222 | test_tone_max_abs = numpy.max(numpy.abs(test_tone)) |
|
228 | test_tone_max_abs = numpy.max(numpy.abs(test_tone)) | |
223 | expected_max_value = int(max_int16 * test_tone_max_abs) |
|
229 | expected_max_value = int(max_int16 * test_tone_max_abs) | |
224 | audio = display.Audio(test_tone, rate=44100, normalize=False) |
|
230 | audio = display.Audio(test_tone, rate=44100, normalize=False) | |
225 | actual_max_value = numpy.max(numpy.abs(read_wav(audio.data))) |
|
231 | actual_max_value = numpy.max(numpy.abs(read_wav(audio.data))) | |
226 |
|
|
232 | assert actual_max_value == expected_max_value | |
227 |
|
233 | |||
228 | def test_audio_data_without_normalization_raises_for_invalid_data(self): |
|
234 | def test_audio_data_without_normalization_raises_for_invalid_data(self): | |
229 | nt.assert_raises( |
|
235 | nt.assert_raises( | |
230 | ValueError, |
|
236 | ValueError, | |
231 | lambda: display.Audio([1.001], rate=44100, normalize=False)) |
|
237 | lambda: display.Audio([1.001], rate=44100, normalize=False)) | |
232 | nt.assert_raises( |
|
238 | nt.assert_raises( | |
233 | ValueError, |
|
239 | ValueError, | |
234 | lambda: display.Audio([-1.001], rate=44100, normalize=False)) |
|
240 | lambda: display.Audio([-1.001], rate=44100, normalize=False)) | |
235 |
|
241 | |||
236 | def simulate_numpy_not_installed(): |
|
242 | def simulate_numpy_not_installed(): | |
237 | try: |
|
243 | try: | |
238 | import numpy |
|
244 | import numpy | |
239 | return mock.patch('numpy.array', mock.MagicMock(side_effect=ImportError)) |
|
245 | return mock.patch('numpy.array', mock.MagicMock(side_effect=ImportError)) | |
240 | except ModuleNotFoundError: |
|
246 | except ModuleNotFoundError: | |
241 | return lambda x:x |
|
247 | return lambda x:x | |
242 |
|
248 | |||
243 | @simulate_numpy_not_installed() |
|
249 | @simulate_numpy_not_installed() | |
244 | class TestAudioDataWithoutNumpy(TestAudioDataWithNumpy): |
|
250 | class TestAudioDataWithoutNumpy(TestAudioDataWithNumpy): | |
245 | # All tests from `TestAudioDataWithNumpy` are inherited. |
|
251 | # All tests from `TestAudioDataWithNumpy` are inherited. | |
246 |
|
252 | |||
247 | @skipif_not_numpy |
|
253 | @skipif_not_numpy | |
248 | def test_audio_raises_for_nested_list(self): |
|
254 | def test_audio_raises_for_nested_list(self): | |
249 | stereo_signal = [list(get_test_tone())] * 2 |
|
255 | stereo_signal = [list(get_test_tone())] * 2 | |
250 | nt.assert_raises( |
|
256 | nt.assert_raises( | |
251 | TypeError, |
|
257 | TypeError, | |
252 | lambda: display.Audio(stereo_signal, rate=44100)) |
|
258 | lambda: display.Audio(stereo_signal, rate=44100)) | |
253 |
|
259 | |||
254 | @skipif_not_numpy |
|
260 | @skipif_not_numpy | |
255 | def get_test_tone(scale=1): |
|
261 | def get_test_tone(scale=1): | |
256 | return numpy.sin(2 * numpy.pi * 440 * numpy.linspace(0, 1, 44100)) * scale |
|
262 | return numpy.sin(2 * numpy.pi * 440 * numpy.linspace(0, 1, 44100)) * scale | |
257 |
|
263 | |||
258 | def read_wav(data): |
|
264 | def read_wav(data): | |
259 | with wave.open(BytesIO(data)) as wave_file: |
|
265 | with wave.open(BytesIO(data)) as wave_file: | |
260 | wave_data = wave_file.readframes(wave_file.getnframes()) |
|
266 | wave_data = wave_file.readframes(wave_file.getnframes()) | |
261 | num_samples = wave_file.getnframes() * wave_file.getnchannels() |
|
267 | num_samples = wave_file.getnframes() * wave_file.getnchannels() | |
262 | return struct.unpack('<%sh' % num_samples, wave_data) |
|
268 | return struct.unpack('<%sh' % num_samples, wave_data) | |
263 |
|
269 | |||
264 | def test_code_from_file(): |
|
270 | def test_code_from_file(): | |
265 | c = display.Code(filename=__file__) |
|
271 | c = display.Code(filename=__file__) | |
266 | assert c._repr_html_().startswith('<style>') |
|
272 | assert c._repr_html_().startswith('<style>') |
@@ -1,34 +1,32 b'' | |||||
1 | """Test installing editor hooks""" |
|
1 | """Test installing editor hooks""" | |
2 | import sys |
|
2 | import sys | |
3 | from unittest import mock |
|
3 | from unittest import mock | |
4 |
|
4 | |||
5 | import nose.tools as nt |
|
|||
6 |
|
||||
7 | from IPython import get_ipython |
|
5 | from IPython import get_ipython | |
8 | from IPython.lib import editorhooks |
|
6 | from IPython.lib import editorhooks | |
9 |
|
7 | |||
10 | def test_install_editor(): |
|
8 | def test_install_editor(): | |
11 | called = [] |
|
9 | called = [] | |
12 | def fake_popen(*args, **kwargs): |
|
10 | def fake_popen(*args, **kwargs): | |
13 | called.append({ |
|
11 | called.append({ | |
14 | 'args': args, |
|
12 | 'args': args, | |
15 | 'kwargs': kwargs, |
|
13 | 'kwargs': kwargs, | |
16 | }) |
|
14 | }) | |
17 | return mock.MagicMock(**{'wait.return_value': 0}) |
|
15 | return mock.MagicMock(**{'wait.return_value': 0}) | |
18 | editorhooks.install_editor('foo -l {line} -f {filename}', wait=False) |
|
16 | editorhooks.install_editor('foo -l {line} -f {filename}', wait=False) | |
19 |
|
17 | |||
20 | with mock.patch('subprocess.Popen', fake_popen): |
|
18 | with mock.patch('subprocess.Popen', fake_popen): | |
21 | get_ipython().hooks.editor('the file', 64) |
|
19 | get_ipython().hooks.editor('the file', 64) | |
22 |
|
20 | |||
23 |
|
|
21 | assert len(called) == 1 | |
24 |
args = called[0][ |
|
22 | args = called[0]["args"] | |
25 |
kwargs = called[0][ |
|
23 | kwargs = called[0]["kwargs"] | |
26 |
|
24 | |||
27 |
|
|
25 | assert kwargs == {"shell": True} | |
28 |
|
26 | |||
29 |
if sys.platform.startswith( |
|
27 | if sys.platform.startswith("win"): | |
30 |
expected = [ |
|
28 | expected = ["foo", "-l", "64", "-f", "the file"] | |
31 | else: |
|
29 | else: | |
32 | expected = "foo -l 64 -f 'the file'" |
|
30 | expected = "foo -l 64 -f 'the file'" | |
33 | cmd = args[0] |
|
31 | cmd = args[0] | |
34 |
|
|
32 | assert cmd == expected |
@@ -1,191 +1,191 b'' | |||||
1 | """Tests for IPython.utils.path.py""" |
|
1 | """Tests for IPython.utils.path.py""" | |
2 | # Copyright (c) IPython Development Team. |
|
2 | # Copyright (c) IPython Development Team. | |
3 | # Distributed under the terms of the Modified BSD License. |
|
3 | # Distributed under the terms of the Modified BSD License. | |
4 |
|
4 | |||
5 | from contextlib import contextmanager |
|
5 | from contextlib import contextmanager | |
6 | from unittest.mock import patch |
|
6 | from unittest.mock import patch | |
7 |
|
7 | |||
8 | import nose.tools as nt |
|
8 | import nose.tools as nt | |
9 | import pytest |
|
9 | import pytest | |
10 |
|
10 | |||
11 | from IPython.lib import latextools |
|
11 | from IPython.lib import latextools | |
12 | from IPython.testing.decorators import ( |
|
12 | from IPython.testing.decorators import ( | |
13 | onlyif_cmds_exist, |
|
13 | onlyif_cmds_exist, | |
14 | skipif_not_matplotlib, |
|
14 | skipif_not_matplotlib, | |
15 | skip_iptest_but_not_pytest, |
|
15 | skip_iptest_but_not_pytest, | |
16 | ) |
|
16 | ) | |
17 | from IPython.utils.process import FindCmdError |
|
17 | from IPython.utils.process import FindCmdError | |
18 |
|
18 | |||
19 |
|
19 | |||
20 | @pytest.mark.parametrize('command', ['latex', 'dvipng']) |
|
20 | @pytest.mark.parametrize('command', ['latex', 'dvipng']) | |
21 | @skip_iptest_but_not_pytest |
|
21 | @skip_iptest_but_not_pytest | |
22 | def test_check_latex_to_png_dvipng_fails_when_no_cmd(command): |
|
22 | def test_check_latex_to_png_dvipng_fails_when_no_cmd(command): | |
23 | def mock_find_cmd(arg): |
|
23 | def mock_find_cmd(arg): | |
24 | if arg == command: |
|
24 | if arg == command: | |
25 | raise FindCmdError |
|
25 | raise FindCmdError | |
26 |
|
26 | |||
27 | with patch.object(latextools, "find_cmd", mock_find_cmd): |
|
27 | with patch.object(latextools, "find_cmd", mock_find_cmd): | |
28 |
assert latextools.latex_to_png_dvipng("whatever", True) |
|
28 | assert latextools.latex_to_png_dvipng("whatever", True) is None | |
29 |
|
29 | |||
30 |
|
30 | |||
31 | @contextmanager |
|
31 | @contextmanager | |
32 | def no_op(*args, **kwargs): |
|
32 | def no_op(*args, **kwargs): | |
33 | yield |
|
33 | yield | |
34 |
|
34 | |||
35 |
|
35 | |||
36 | @skip_iptest_but_not_pytest |
|
36 | @skip_iptest_but_not_pytest | |
37 | @onlyif_cmds_exist("latex", "dvipng") |
|
37 | @onlyif_cmds_exist("latex", "dvipng") | |
38 | @pytest.mark.parametrize("s, wrap", [(u"$$x^2$$", False), (u"x^2", True)]) |
|
38 | @pytest.mark.parametrize("s, wrap", [(u"$$x^2$$", False), (u"x^2", True)]) | |
39 | def test_latex_to_png_dvipng_runs(s, wrap): |
|
39 | def test_latex_to_png_dvipng_runs(s, wrap): | |
40 | """ |
|
40 | """ | |
41 | Test that latex_to_png_dvipng just runs without error. |
|
41 | Test that latex_to_png_dvipng just runs without error. | |
42 | """ |
|
42 | """ | |
43 | def mock_kpsewhich(filename): |
|
43 | def mock_kpsewhich(filename): | |
44 | assert filename == "breqn.sty" |
|
44 | assert filename == "breqn.sty" | |
45 | return None |
|
45 | return None | |
46 |
|
46 | |||
47 | latextools.latex_to_png_dvipng(s, wrap) |
|
47 | latextools.latex_to_png_dvipng(s, wrap) | |
48 |
|
48 | |||
49 | with patch_latextool(mock_kpsewhich): |
|
49 | with patch_latextool(mock_kpsewhich): | |
50 | latextools.latex_to_png_dvipng(s, wrap) |
|
50 | latextools.latex_to_png_dvipng(s, wrap) | |
51 |
|
51 | |||
52 |
|
52 | |||
53 | def mock_kpsewhich(filename): |
|
53 | def mock_kpsewhich(filename): | |
54 | assert filename == "breqn.sty" |
|
54 | assert filename == "breqn.sty" | |
55 | return None |
|
55 | return None | |
56 |
|
56 | |||
57 | @contextmanager |
|
57 | @contextmanager | |
58 | def patch_latextool(mock=mock_kpsewhich): |
|
58 | def patch_latextool(mock=mock_kpsewhich): | |
59 | with patch.object(latextools, "kpsewhich", mock): |
|
59 | with patch.object(latextools, "kpsewhich", mock): | |
60 | yield |
|
60 | yield | |
61 |
|
61 | |||
62 | @pytest.mark.parametrize('context', [no_op, patch_latextool]) |
|
62 | @pytest.mark.parametrize('context', [no_op, patch_latextool]) | |
63 | @pytest.mark.parametrize('s_wrap', [("$x^2$", False), ("x^2", True)]) |
|
63 | @pytest.mark.parametrize('s_wrap', [("$x^2$", False), ("x^2", True)]) | |
64 | @skip_iptest_but_not_pytest |
|
64 | @skip_iptest_but_not_pytest | |
65 | def test_latex_to_png_mpl_runs(s_wrap, context): |
|
65 | def test_latex_to_png_mpl_runs(s_wrap, context): | |
66 | """ |
|
66 | """ | |
67 | Test that latex_to_png_mpl just runs without error. |
|
67 | Test that latex_to_png_mpl just runs without error. | |
68 | """ |
|
68 | """ | |
69 | try: |
|
69 | try: | |
70 | import matplotlib |
|
70 | import matplotlib | |
71 | except ImportError: |
|
71 | except ImportError: | |
72 | pytest.skip("This needs matplotlib to be available") |
|
72 | pytest.skip("This needs matplotlib to be available") | |
73 | return |
|
73 | return | |
74 | s, wrap = s_wrap |
|
74 | s, wrap = s_wrap | |
75 | with context(): |
|
75 | with context(): | |
76 | latextools.latex_to_png_mpl(s, wrap) |
|
76 | latextools.latex_to_png_mpl(s, wrap) | |
77 |
|
77 | |||
78 | @skipif_not_matplotlib |
|
78 | @skipif_not_matplotlib | |
79 | def test_latex_to_html(): |
|
79 | def test_latex_to_html(): | |
80 | img = latextools.latex_to_html("$x^2$") |
|
80 | img = latextools.latex_to_html("$x^2$") | |
81 | assert "data:image/png;base64,iVBOR" in img |
|
81 | assert "data:image/png;base64,iVBOR" in img | |
82 |
|
82 | |||
83 |
|
83 | |||
84 | def test_genelatex_no_wrap(): |
|
84 | def test_genelatex_no_wrap(): | |
85 | """ |
|
85 | """ | |
86 | Test genelatex with wrap=False. |
|
86 | Test genelatex with wrap=False. | |
87 | """ |
|
87 | """ | |
88 | def mock_kpsewhich(filename): |
|
88 | def mock_kpsewhich(filename): | |
89 | assert False, ("kpsewhich should not be called " |
|
89 | assert False, ("kpsewhich should not be called " | |
90 | "(called with {0})".format(filename)) |
|
90 | "(called with {0})".format(filename)) | |
91 |
|
91 | |||
92 | with patch_latextool(mock_kpsewhich): |
|
92 | with patch_latextool(mock_kpsewhich): | |
93 | assert '\n'.join(latextools.genelatex("body text", False)) == r'''\documentclass{article} |
|
93 | assert '\n'.join(latextools.genelatex("body text", False)) == r'''\documentclass{article} | |
94 | \usepackage{amsmath} |
|
94 | \usepackage{amsmath} | |
95 | \usepackage{amsthm} |
|
95 | \usepackage{amsthm} | |
96 | \usepackage{amssymb} |
|
96 | \usepackage{amssymb} | |
97 | \usepackage{bm} |
|
97 | \usepackage{bm} | |
98 | \pagestyle{empty} |
|
98 | \pagestyle{empty} | |
99 | \begin{document} |
|
99 | \begin{document} | |
100 | body text |
|
100 | body text | |
101 | \end{document}''' |
|
101 | \end{document}''' | |
102 |
|
102 | |||
103 |
|
103 | |||
104 | def test_genelatex_wrap_with_breqn(): |
|
104 | def test_genelatex_wrap_with_breqn(): | |
105 | """ |
|
105 | """ | |
106 | Test genelatex with wrap=True for the case breqn.sty is installed. |
|
106 | Test genelatex with wrap=True for the case breqn.sty is installed. | |
107 | """ |
|
107 | """ | |
108 | def mock_kpsewhich(filename): |
|
108 | def mock_kpsewhich(filename): | |
109 | assert filename == "breqn.sty" |
|
109 | assert filename == "breqn.sty" | |
110 | return "path/to/breqn.sty" |
|
110 | return "path/to/breqn.sty" | |
111 |
|
111 | |||
112 | with patch_latextool(mock_kpsewhich): |
|
112 | with patch_latextool(mock_kpsewhich): | |
113 | assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article} |
|
113 | assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article} | |
114 | \usepackage{amsmath} |
|
114 | \usepackage{amsmath} | |
115 | \usepackage{amsthm} |
|
115 | \usepackage{amsthm} | |
116 | \usepackage{amssymb} |
|
116 | \usepackage{amssymb} | |
117 | \usepackage{bm} |
|
117 | \usepackage{bm} | |
118 | \usepackage{breqn} |
|
118 | \usepackage{breqn} | |
119 | \pagestyle{empty} |
|
119 | \pagestyle{empty} | |
120 | \begin{document} |
|
120 | \begin{document} | |
121 | \begin{dmath*} |
|
121 | \begin{dmath*} | |
122 | x^2 |
|
122 | x^2 | |
123 | \end{dmath*} |
|
123 | \end{dmath*} | |
124 | \end{document}''' |
|
124 | \end{document}''' | |
125 |
|
125 | |||
126 |
|
126 | |||
127 | def test_genelatex_wrap_without_breqn(): |
|
127 | def test_genelatex_wrap_without_breqn(): | |
128 | """ |
|
128 | """ | |
129 | Test genelatex with wrap=True for the case breqn.sty is not installed. |
|
129 | Test genelatex with wrap=True for the case breqn.sty is not installed. | |
130 | """ |
|
130 | """ | |
131 | def mock_kpsewhich(filename): |
|
131 | def mock_kpsewhich(filename): | |
132 | assert filename == "breqn.sty" |
|
132 | assert filename == "breqn.sty" | |
133 | return None |
|
133 | return None | |
134 |
|
134 | |||
135 | with patch_latextool(mock_kpsewhich): |
|
135 | with patch_latextool(mock_kpsewhich): | |
136 | assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article} |
|
136 | assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article} | |
137 | \usepackage{amsmath} |
|
137 | \usepackage{amsmath} | |
138 | \usepackage{amsthm} |
|
138 | \usepackage{amsthm} | |
139 | \usepackage{amssymb} |
|
139 | \usepackage{amssymb} | |
140 | \usepackage{bm} |
|
140 | \usepackage{bm} | |
141 | \pagestyle{empty} |
|
141 | \pagestyle{empty} | |
142 | \begin{document} |
|
142 | \begin{document} | |
143 | $$x^2$$ |
|
143 | $$x^2$$ | |
144 | \end{document}''' |
|
144 | \end{document}''' | |
145 |
|
145 | |||
146 |
|
146 | |||
147 | @skipif_not_matplotlib |
|
147 | @skipif_not_matplotlib | |
148 | @onlyif_cmds_exist('latex', 'dvipng') |
|
148 | @onlyif_cmds_exist('latex', 'dvipng') | |
149 | def test_latex_to_png_color(): |
|
149 | def test_latex_to_png_color(): | |
150 | """ |
|
150 | """ | |
151 | Test color settings for latex_to_png. |
|
151 | Test color settings for latex_to_png. | |
152 | """ |
|
152 | """ | |
153 | latex_string = "$x^2$" |
|
153 | latex_string = "$x^2$" | |
154 | default_value = latextools.latex_to_png(latex_string, wrap=False) |
|
154 | default_value = latextools.latex_to_png(latex_string, wrap=False) | |
155 | default_hexblack = latextools.latex_to_png(latex_string, wrap=False, |
|
155 | default_hexblack = latextools.latex_to_png(latex_string, wrap=False, | |
156 | color='#000000') |
|
156 | color='#000000') | |
157 | dvipng_default = latextools.latex_to_png_dvipng(latex_string, False) |
|
157 | dvipng_default = latextools.latex_to_png_dvipng(latex_string, False) | |
158 | dvipng_black = latextools.latex_to_png_dvipng(latex_string, False, 'Black') |
|
158 | dvipng_black = latextools.latex_to_png_dvipng(latex_string, False, 'Black') | |
159 | assert dvipng_default == dvipng_black |
|
159 | assert dvipng_default == dvipng_black | |
160 | mpl_default = latextools.latex_to_png_mpl(latex_string, False) |
|
160 | mpl_default = latextools.latex_to_png_mpl(latex_string, False) | |
161 | mpl_black = latextools.latex_to_png_mpl(latex_string, False, 'Black') |
|
161 | mpl_black = latextools.latex_to_png_mpl(latex_string, False, 'Black') | |
162 | assert mpl_default == mpl_black |
|
162 | assert mpl_default == mpl_black | |
163 | assert default_value in [dvipng_black, mpl_black] |
|
163 | assert default_value in [dvipng_black, mpl_black] | |
164 | assert default_hexblack in [dvipng_black, mpl_black] |
|
164 | assert default_hexblack in [dvipng_black, mpl_black] | |
165 |
|
165 | |||
166 | # Test that dvips name colors can be used without error |
|
166 | # Test that dvips name colors can be used without error | |
167 | dvipng_maroon = latextools.latex_to_png_dvipng(latex_string, False, |
|
167 | dvipng_maroon = latextools.latex_to_png_dvipng(latex_string, False, | |
168 | 'Maroon') |
|
168 | 'Maroon') | |
169 | # And that it doesn't return the black one |
|
169 | # And that it doesn't return the black one | |
170 | assert dvipng_black != dvipng_maroon |
|
170 | assert dvipng_black != dvipng_maroon | |
171 |
|
171 | |||
172 | mpl_maroon = latextools.latex_to_png_mpl(latex_string, False, 'Maroon') |
|
172 | mpl_maroon = latextools.latex_to_png_mpl(latex_string, False, 'Maroon') | |
173 | assert mpl_black != mpl_maroon |
|
173 | assert mpl_black != mpl_maroon | |
174 | mpl_white = latextools.latex_to_png_mpl(latex_string, False, 'White') |
|
174 | mpl_white = latextools.latex_to_png_mpl(latex_string, False, 'White') | |
175 | mpl_hexwhite = latextools.latex_to_png_mpl(latex_string, False, '#FFFFFF') |
|
175 | mpl_hexwhite = latextools.latex_to_png_mpl(latex_string, False, '#FFFFFF') | |
176 | assert mpl_white == mpl_hexwhite |
|
176 | assert mpl_white == mpl_hexwhite | |
177 |
|
177 | |||
178 | mpl_white_scale = latextools.latex_to_png_mpl(latex_string, False, |
|
178 | mpl_white_scale = latextools.latex_to_png_mpl(latex_string, False, | |
179 | 'White', 1.2) |
|
179 | 'White', 1.2) | |
180 | assert mpl_white != mpl_white_scale |
|
180 | assert mpl_white != mpl_white_scale | |
181 |
|
181 | |||
182 |
|
182 | |||
183 | def test_latex_to_png_invalid_hex_colors(): |
|
183 | def test_latex_to_png_invalid_hex_colors(): | |
184 | """ |
|
184 | """ | |
185 | Test that invalid hex colors provided to dvipng gives an exception. |
|
185 | Test that invalid hex colors provided to dvipng gives an exception. | |
186 | """ |
|
186 | """ | |
187 | latex_string = "$x^2$" |
|
187 | latex_string = "$x^2$" | |
188 | nt.assert_raises(ValueError, lambda: latextools.latex_to_png(latex_string, |
|
188 | nt.assert_raises(ValueError, lambda: latextools.latex_to_png(latex_string, | |
189 | backend='dvipng', color="#f00bar")) |
|
189 | backend='dvipng', color="#f00bar")) | |
190 | nt.assert_raises(ValueError, lambda: latextools.latex_to_png(latex_string, |
|
190 | nt.assert_raises(ValueError, lambda: latextools.latex_to_png(latex_string, | |
191 | backend='dvipng', color="#f00")) |
|
191 | backend='dvipng', color="#f00")) |
@@ -1,492 +1,502 b'' | |||||
1 | # coding: utf-8 |
|
1 | # coding: utf-8 | |
2 | """Tests for IPython.lib.pretty.""" |
|
2 | """Tests for IPython.lib.pretty.""" | |
3 |
|
3 | |||
4 | # Copyright (c) IPython Development Team. |
|
4 | # Copyright (c) IPython Development Team. | |
5 | # Distributed under the terms of the Modified BSD License. |
|
5 | # Distributed under the terms of the Modified BSD License. | |
6 |
|
6 | |||
7 |
|
7 | |||
8 | from collections import Counter, defaultdict, deque, OrderedDict |
|
8 | from collections import Counter, defaultdict, deque, OrderedDict | |
9 | import os |
|
9 | import os | |
10 | import types |
|
10 | import types | |
11 | import string |
|
11 | import string | |
12 | import unittest |
|
12 | import unittest | |
13 |
|
13 | |||
14 | import nose.tools as nt |
|
14 | import nose.tools as nt | |
15 | import pytest |
|
15 | import pytest | |
16 |
|
16 | |||
17 | from IPython.lib import pretty |
|
17 | from IPython.lib import pretty | |
18 | from IPython.testing.decorators import skip_without, skip_iptest_but_not_pytest |
|
18 | from IPython.testing.decorators import skip_without, skip_iptest_but_not_pytest | |
19 |
|
19 | |||
20 | from io import StringIO |
|
20 | from io import StringIO | |
21 |
|
21 | |||
22 |
|
22 | |||
23 | class MyList(object): |
|
23 | class MyList(object): | |
24 | def __init__(self, content): |
|
24 | def __init__(self, content): | |
25 | self.content = content |
|
25 | self.content = content | |
26 | def _repr_pretty_(self, p, cycle): |
|
26 | def _repr_pretty_(self, p, cycle): | |
27 | if cycle: |
|
27 | if cycle: | |
28 | p.text("MyList(...)") |
|
28 | p.text("MyList(...)") | |
29 | else: |
|
29 | else: | |
30 | with p.group(3, "MyList(", ")"): |
|
30 | with p.group(3, "MyList(", ")"): | |
31 | for (i, child) in enumerate(self.content): |
|
31 | for (i, child) in enumerate(self.content): | |
32 | if i: |
|
32 | if i: | |
33 | p.text(",") |
|
33 | p.text(",") | |
34 | p.breakable() |
|
34 | p.breakable() | |
35 | else: |
|
35 | else: | |
36 | p.breakable("") |
|
36 | p.breakable("") | |
37 | p.pretty(child) |
|
37 | p.pretty(child) | |
38 |
|
38 | |||
39 |
|
39 | |||
40 | class MyDict(dict): |
|
40 | class MyDict(dict): | |
41 | def _repr_pretty_(self, p, cycle): |
|
41 | def _repr_pretty_(self, p, cycle): | |
42 | p.text("MyDict(...)") |
|
42 | p.text("MyDict(...)") | |
43 |
|
43 | |||
44 | class MyObj(object): |
|
44 | class MyObj(object): | |
45 | def somemethod(self): |
|
45 | def somemethod(self): | |
46 | pass |
|
46 | pass | |
47 |
|
47 | |||
48 |
|
48 | |||
49 | class Dummy1(object): |
|
49 | class Dummy1(object): | |
50 | def _repr_pretty_(self, p, cycle): |
|
50 | def _repr_pretty_(self, p, cycle): | |
51 | p.text("Dummy1(...)") |
|
51 | p.text("Dummy1(...)") | |
52 |
|
52 | |||
53 | class Dummy2(Dummy1): |
|
53 | class Dummy2(Dummy1): | |
54 | _repr_pretty_ = None |
|
54 | _repr_pretty_ = None | |
55 |
|
55 | |||
56 | class NoModule(object): |
|
56 | class NoModule(object): | |
57 | pass |
|
57 | pass | |
58 |
|
58 | |||
59 | NoModule.__module__ = None |
|
59 | NoModule.__module__ = None | |
60 |
|
60 | |||
61 | class Breaking(object): |
|
61 | class Breaking(object): | |
62 | def _repr_pretty_(self, p, cycle): |
|
62 | def _repr_pretty_(self, p, cycle): | |
63 | with p.group(4,"TG: ",":"): |
|
63 | with p.group(4,"TG: ",":"): | |
64 | p.text("Breaking(") |
|
64 | p.text("Breaking(") | |
65 | p.break_() |
|
65 | p.break_() | |
66 | p.text(")") |
|
66 | p.text(")") | |
67 |
|
67 | |||
68 | class BreakingRepr(object): |
|
68 | class BreakingRepr(object): | |
69 | def __repr__(self): |
|
69 | def __repr__(self): | |
70 | return "Breaking(\n)" |
|
70 | return "Breaking(\n)" | |
71 |
|
71 | |||
72 | class BadRepr(object): |
|
72 | class BadRepr(object): | |
73 |
|
73 | |||
74 | def __repr__(self): |
|
74 | def __repr__(self): | |
75 | return 1/0 |
|
75 | return 1/0 | |
76 |
|
76 | |||
77 |
|
77 | |||
78 | def test_indentation(): |
|
78 | def test_indentation(): | |
79 | """Test correct indentation in groups""" |
|
79 | """Test correct indentation in groups""" | |
80 | count = 40 |
|
80 | count = 40 | |
81 | gotoutput = pretty.pretty(MyList(range(count))) |
|
81 | gotoutput = pretty.pretty(MyList(range(count))) | |
82 | expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")" |
|
82 | expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")" | |
83 |
|
83 | |||
84 |
|
|
84 | assert gotoutput == expectedoutput | |
85 |
|
85 | |||
86 |
|
86 | |||
87 | def test_dispatch(): |
|
87 | def test_dispatch(): | |
88 | """ |
|
88 | """ | |
89 | Test correct dispatching: The _repr_pretty_ method for MyDict |
|
89 | Test correct dispatching: The _repr_pretty_ method for MyDict | |
90 | must be found before the registered printer for dict. |
|
90 | must be found before the registered printer for dict. | |
91 | """ |
|
91 | """ | |
92 | gotoutput = pretty.pretty(MyDict()) |
|
92 | gotoutput = pretty.pretty(MyDict()) | |
93 | expectedoutput = "MyDict(...)" |
|
93 | expectedoutput = "MyDict(...)" | |
94 |
|
94 | |||
95 |
|
|
95 | assert gotoutput == expectedoutput | |
96 |
|
96 | |||
97 |
|
97 | |||
98 | def test_callability_checking(): |
|
98 | def test_callability_checking(): | |
99 | """ |
|
99 | """ | |
100 | Test that the _repr_pretty_ method is tested for callability and skipped if |
|
100 | Test that the _repr_pretty_ method is tested for callability and skipped if | |
101 | not. |
|
101 | not. | |
102 | """ |
|
102 | """ | |
103 | gotoutput = pretty.pretty(Dummy2()) |
|
103 | gotoutput = pretty.pretty(Dummy2()) | |
104 | expectedoutput = "Dummy1(...)" |
|
104 | expectedoutput = "Dummy1(...)" | |
105 |
|
105 | |||
106 |
|
|
106 | assert gotoutput == expectedoutput | |
107 |
|
107 | |||
108 |
|
108 | |||
109 | @pytest.mark.parametrize( |
|
109 | @pytest.mark.parametrize( | |
110 | "obj,expected_output", |
|
110 | "obj,expected_output", | |
111 | zip( |
|
111 | zip( | |
112 | [ |
|
112 | [ | |
113 | set(), |
|
113 | set(), | |
114 | frozenset(), |
|
114 | frozenset(), | |
115 | set([1]), |
|
115 | set([1]), | |
116 | frozenset([1]), |
|
116 | frozenset([1]), | |
117 | set([1, 2]), |
|
117 | set([1, 2]), | |
118 | frozenset([1, 2]), |
|
118 | frozenset([1, 2]), | |
119 | set([-1, -2, -3]), |
|
119 | set([-1, -2, -3]), | |
120 | ], |
|
120 | ], | |
121 | [ |
|
121 | [ | |
122 | "set()", |
|
122 | "set()", | |
123 | "frozenset()", |
|
123 | "frozenset()", | |
124 | "{1}", |
|
124 | "{1}", | |
125 | "frozenset({1})", |
|
125 | "frozenset({1})", | |
126 | "{1, 2}", |
|
126 | "{1, 2}", | |
127 | "frozenset({1, 2})", |
|
127 | "frozenset({1, 2})", | |
128 | "{-3, -2, -1}", |
|
128 | "{-3, -2, -1}", | |
129 | ], |
|
129 | ], | |
130 | ), |
|
130 | ), | |
131 | ) |
|
131 | ) | |
132 | @skip_iptest_but_not_pytest |
|
132 | @skip_iptest_but_not_pytest | |
133 | def test_sets(obj, expected_output): |
|
133 | def test_sets(obj, expected_output): | |
134 | """ |
|
134 | """ | |
135 | Test that set and frozenset use Python 3 formatting. |
|
135 | Test that set and frozenset use Python 3 formatting. | |
136 | """ |
|
136 | """ | |
137 | got_output = pretty.pretty(obj) |
|
137 | got_output = pretty.pretty(obj) | |
138 |
|
|
138 | assert got_output == expected_output | |
139 |
|
139 | |||
140 |
|
140 | |||
141 | @skip_without('xxlimited') |
|
141 | @skip_without('xxlimited') | |
142 | def test_pprint_heap_allocated_type(): |
|
142 | def test_pprint_heap_allocated_type(): | |
143 | """ |
|
143 | """ | |
144 | Test that pprint works for heap allocated types. |
|
144 | Test that pprint works for heap allocated types. | |
145 | """ |
|
145 | """ | |
146 | import xxlimited |
|
146 | import xxlimited | |
147 | output = pretty.pretty(xxlimited.Null) |
|
147 | output = pretty.pretty(xxlimited.Null) | |
148 |
|
|
148 | assert output == "xxlimited.Null" | |
|
149 | ||||
149 |
|
150 | |||
150 | def test_pprint_nomod(): |
|
151 | def test_pprint_nomod(): | |
151 | """ |
|
152 | """ | |
152 | Test that pprint works for classes with no __module__. |
|
153 | Test that pprint works for classes with no __module__. | |
153 | """ |
|
154 | """ | |
154 | output = pretty.pretty(NoModule) |
|
155 | output = pretty.pretty(NoModule) | |
155 |
|
|
156 | assert output == "NoModule" | |
156 |
|
157 | |||
|
158 | ||||
157 | def test_pprint_break(): |
|
159 | def test_pprint_break(): | |
158 | """ |
|
160 | """ | |
159 | Test that p.break_ produces expected output |
|
161 | Test that p.break_ produces expected output | |
160 | """ |
|
162 | """ | |
161 | output = pretty.pretty(Breaking()) |
|
163 | output = pretty.pretty(Breaking()) | |
162 | expected = "TG: Breaking(\n ):" |
|
164 | expected = "TG: Breaking(\n ):" | |
163 |
|
|
165 | assert output == expected | |
164 |
|
166 | |||
165 | def test_pprint_break_repr(): |
|
167 | def test_pprint_break_repr(): | |
166 | """ |
|
168 | """ | |
167 | Test that p.break_ is used in repr |
|
169 | Test that p.break_ is used in repr | |
168 | """ |
|
170 | """ | |
169 | output = pretty.pretty([[BreakingRepr()]]) |
|
171 | output = pretty.pretty([[BreakingRepr()]]) | |
170 | expected = "[[Breaking(\n )]]" |
|
172 | expected = "[[Breaking(\n )]]" | |
171 |
|
|
173 | assert output == expected | |
172 |
|
174 | |||
173 | output = pretty.pretty([[BreakingRepr()]*2]) |
|
175 | output = pretty.pretty([[BreakingRepr()]*2]) | |
174 | expected = "[[Breaking(\n ),\n Breaking(\n )]]" |
|
176 | expected = "[[Breaking(\n ),\n Breaking(\n )]]" | |
175 |
|
|
177 | assert output == expected | |
176 |
|
178 | |||
177 | def test_bad_repr(): |
|
179 | def test_bad_repr(): | |
178 | """Don't catch bad repr errors""" |
|
180 | """Don't catch bad repr errors""" | |
179 | with nt.assert_raises(ZeroDivisionError): |
|
181 | with nt.assert_raises(ZeroDivisionError): | |
180 | pretty.pretty(BadRepr()) |
|
182 | pretty.pretty(BadRepr()) | |
181 |
|
183 | |||
182 | class BadException(Exception): |
|
184 | class BadException(Exception): | |
183 | def __str__(self): |
|
185 | def __str__(self): | |
184 | return -1 |
|
186 | return -1 | |
185 |
|
187 | |||
186 | class ReallyBadRepr(object): |
|
188 | class ReallyBadRepr(object): | |
187 | __module__ = 1 |
|
189 | __module__ = 1 | |
188 | @property |
|
190 | @property | |
189 | def __class__(self): |
|
191 | def __class__(self): | |
190 | raise ValueError("I am horrible") |
|
192 | raise ValueError("I am horrible") | |
191 |
|
193 | |||
192 | def __repr__(self): |
|
194 | def __repr__(self): | |
193 | raise BadException() |
|
195 | raise BadException() | |
194 |
|
196 | |||
195 | def test_really_bad_repr(): |
|
197 | def test_really_bad_repr(): | |
196 | with nt.assert_raises(BadException): |
|
198 | with nt.assert_raises(BadException): | |
197 | pretty.pretty(ReallyBadRepr()) |
|
199 | pretty.pretty(ReallyBadRepr()) | |
198 |
|
200 | |||
199 |
|
201 | |||
200 | class SA(object): |
|
202 | class SA(object): | |
201 | pass |
|
203 | pass | |
202 |
|
204 | |||
203 | class SB(SA): |
|
205 | class SB(SA): | |
204 | pass |
|
206 | pass | |
205 |
|
207 | |||
206 | class TestsPretty(unittest.TestCase): |
|
208 | class TestsPretty(unittest.TestCase): | |
207 |
|
209 | |||
208 | def test_super_repr(self): |
|
210 | def test_super_repr(self): | |
209 | # "<super: module_name.SA, None>" |
|
211 | # "<super: module_name.SA, None>" | |
210 | output = pretty.pretty(super(SA)) |
|
212 | output = pretty.pretty(super(SA)) | |
211 | self.assertRegex(output, r"<super: \S+.SA, None>") |
|
213 | self.assertRegex(output, r"<super: \S+.SA, None>") | |
212 |
|
214 | |||
213 | # "<super: module_name.SA, <module_name.SB at 0x...>>" |
|
215 | # "<super: module_name.SA, <module_name.SB at 0x...>>" | |
214 | sb = SB() |
|
216 | sb = SB() | |
215 | output = pretty.pretty(super(SA, sb)) |
|
217 | output = pretty.pretty(super(SA, sb)) | |
216 | self.assertRegex(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>") |
|
218 | self.assertRegex(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>") | |
217 |
|
219 | |||
218 |
|
220 | |||
219 | def test_long_list(self): |
|
221 | def test_long_list(self): | |
220 | lis = list(range(10000)) |
|
222 | lis = list(range(10000)) | |
221 | p = pretty.pretty(lis) |
|
223 | p = pretty.pretty(lis) | |
222 | last2 = p.rsplit('\n', 2)[-2:] |
|
224 | last2 = p.rsplit('\n', 2)[-2:] | |
223 | self.assertEqual(last2, [' 999,', ' ...]']) |
|
225 | self.assertEqual(last2, [' 999,', ' ...]']) | |
224 |
|
226 | |||
225 | def test_long_set(self): |
|
227 | def test_long_set(self): | |
226 | s = set(range(10000)) |
|
228 | s = set(range(10000)) | |
227 | p = pretty.pretty(s) |
|
229 | p = pretty.pretty(s) | |
228 | last2 = p.rsplit('\n', 2)[-2:] |
|
230 | last2 = p.rsplit('\n', 2)[-2:] | |
229 | self.assertEqual(last2, [' 999,', ' ...}']) |
|
231 | self.assertEqual(last2, [' 999,', ' ...}']) | |
230 |
|
232 | |||
231 | def test_long_tuple(self): |
|
233 | def test_long_tuple(self): | |
232 | tup = tuple(range(10000)) |
|
234 | tup = tuple(range(10000)) | |
233 | p = pretty.pretty(tup) |
|
235 | p = pretty.pretty(tup) | |
234 | last2 = p.rsplit('\n', 2)[-2:] |
|
236 | last2 = p.rsplit('\n', 2)[-2:] | |
235 | self.assertEqual(last2, [' 999,', ' ...)']) |
|
237 | self.assertEqual(last2, [' 999,', ' ...)']) | |
236 |
|
238 | |||
237 | def test_long_dict(self): |
|
239 | def test_long_dict(self): | |
238 | d = { n:n for n in range(10000) } |
|
240 | d = { n:n for n in range(10000) } | |
239 | p = pretty.pretty(d) |
|
241 | p = pretty.pretty(d) | |
240 | last2 = p.rsplit('\n', 2)[-2:] |
|
242 | last2 = p.rsplit('\n', 2)[-2:] | |
241 | self.assertEqual(last2, [' 999: 999,', ' ...}']) |
|
243 | self.assertEqual(last2, [' 999: 999,', ' ...}']) | |
242 |
|
244 | |||
243 | def test_unbound_method(self): |
|
245 | def test_unbound_method(self): | |
244 | output = pretty.pretty(MyObj.somemethod) |
|
246 | output = pretty.pretty(MyObj.somemethod) | |
245 | self.assertIn('MyObj.somemethod', output) |
|
247 | self.assertIn('MyObj.somemethod', output) | |
246 |
|
248 | |||
247 |
|
249 | |||
248 | class MetaClass(type): |
|
250 | class MetaClass(type): | |
249 | def __new__(cls, name): |
|
251 | def __new__(cls, name): | |
250 | return type.__new__(cls, name, (object,), {'name': name}) |
|
252 | return type.__new__(cls, name, (object,), {'name': name}) | |
251 |
|
253 | |||
252 | def __repr__(self): |
|
254 | def __repr__(self): | |
253 | return "[CUSTOM REPR FOR CLASS %s]" % self.name |
|
255 | return "[CUSTOM REPR FOR CLASS %s]" % self.name | |
254 |
|
256 | |||
255 |
|
257 | |||
256 | ClassWithMeta = MetaClass('ClassWithMeta') |
|
258 | ClassWithMeta = MetaClass('ClassWithMeta') | |
257 |
|
259 | |||
258 |
|
260 | |||
259 | def test_metaclass_repr(): |
|
261 | def test_metaclass_repr(): | |
260 | output = pretty.pretty(ClassWithMeta) |
|
262 | output = pretty.pretty(ClassWithMeta) | |
261 |
|
|
263 | assert output == "[CUSTOM REPR FOR CLASS ClassWithMeta]" | |
262 |
|
264 | |||
263 |
|
265 | |||
264 | def test_unicode_repr(): |
|
266 | def test_unicode_repr(): | |
265 | u = u"üniçodé" |
|
267 | u = u"üniçodé" | |
266 | ustr = u |
|
268 | ustr = u | |
267 |
|
269 | |||
268 | class C(object): |
|
270 | class C(object): | |
269 | def __repr__(self): |
|
271 | def __repr__(self): | |
270 | return ustr |
|
272 | return ustr | |
271 |
|
273 | |||
272 | c = C() |
|
274 | c = C() | |
273 | p = pretty.pretty(c) |
|
275 | p = pretty.pretty(c) | |
274 |
|
|
276 | assert p == u | |
275 | p = pretty.pretty([c]) |
|
277 | p = pretty.pretty([c]) | |
276 |
|
|
278 | assert p == u"[%s]" % u | |
277 |
|
279 | |||
278 |
|
280 | |||
279 | def test_basic_class(): |
|
281 | def test_basic_class(): | |
280 | def type_pprint_wrapper(obj, p, cycle): |
|
282 | def type_pprint_wrapper(obj, p, cycle): | |
281 | if obj is MyObj: |
|
283 | if obj is MyObj: | |
282 | type_pprint_wrapper.called = True |
|
284 | type_pprint_wrapper.called = True | |
283 | return pretty._type_pprint(obj, p, cycle) |
|
285 | return pretty._type_pprint(obj, p, cycle) | |
284 | type_pprint_wrapper.called = False |
|
286 | type_pprint_wrapper.called = False | |
285 |
|
287 | |||
286 | stream = StringIO() |
|
288 | stream = StringIO() | |
287 | printer = pretty.RepresentationPrinter(stream) |
|
289 | printer = pretty.RepresentationPrinter(stream) | |
288 | printer.type_pprinters[type] = type_pprint_wrapper |
|
290 | printer.type_pprinters[type] = type_pprint_wrapper | |
289 | printer.pretty(MyObj) |
|
291 | printer.pretty(MyObj) | |
290 | printer.flush() |
|
292 | printer.flush() | |
291 | output = stream.getvalue() |
|
293 | output = stream.getvalue() | |
292 |
|
294 | |||
293 |
|
|
295 | assert output == "%s.MyObj" % __name__ | |
294 | nt.assert_true(type_pprint_wrapper.called) |
|
296 | nt.assert_true(type_pprint_wrapper.called) | |
295 |
|
297 | |||
296 |
|
298 | |||
|
299 | # TODO : pytest.mark.parametrise once nose is gone. | |||
297 | def test_collections_defaultdict(): |
|
300 | def test_collections_defaultdict(): | |
298 | # Create defaultdicts with cycles |
|
301 | # Create defaultdicts with cycles | |
299 | a = defaultdict() |
|
302 | a = defaultdict() | |
300 | a.default_factory = a |
|
303 | a.default_factory = a | |
301 | b = defaultdict(list) |
|
304 | b = defaultdict(list) | |
302 | b['key'] = b |
|
305 | b['key'] = b | |
303 |
|
306 | |||
304 | # Dictionary order cannot be relied on, test against single keys. |
|
307 | # Dictionary order cannot be relied on, test against single keys. | |
305 | cases = [ |
|
308 | cases = [ | |
306 | (defaultdict(list), 'defaultdict(list, {})'), |
|
309 | (defaultdict(list), 'defaultdict(list, {})'), | |
307 | (defaultdict(list, {'key': '-' * 50}), |
|
310 | (defaultdict(list, {'key': '-' * 50}), | |
308 | "defaultdict(list,\n" |
|
311 | "defaultdict(list,\n" | |
309 | " {'key': '--------------------------------------------------'})"), |
|
312 | " {'key': '--------------------------------------------------'})"), | |
310 | (a, 'defaultdict(defaultdict(...), {})'), |
|
313 | (a, 'defaultdict(defaultdict(...), {})'), | |
311 | (b, "defaultdict(list, {'key': defaultdict(...)})"), |
|
314 | (b, "defaultdict(list, {'key': defaultdict(...)})"), | |
312 | ] |
|
315 | ] | |
313 | for obj, expected in cases: |
|
316 | for obj, expected in cases: | |
314 |
|
|
317 | assert pretty.pretty(obj) == expected | |
315 |
|
318 | |||
316 |
|
319 | |||
|
320 | # TODO : pytest.mark.parametrise once nose is gone. | |||
317 | def test_collections_ordereddict(): |
|
321 | def test_collections_ordereddict(): | |
318 | # Create OrderedDict with cycle |
|
322 | # Create OrderedDict with cycle | |
319 | a = OrderedDict() |
|
323 | a = OrderedDict() | |
320 | a['key'] = a |
|
324 | a['key'] = a | |
321 |
|
325 | |||
322 | cases = [ |
|
326 | cases = [ | |
323 | (OrderedDict(), 'OrderedDict()'), |
|
327 | (OrderedDict(), 'OrderedDict()'), | |
324 | (OrderedDict((i, i) for i in range(1000, 1010)), |
|
328 | (OrderedDict((i, i) for i in range(1000, 1010)), | |
325 | 'OrderedDict([(1000, 1000),\n' |
|
329 | 'OrderedDict([(1000, 1000),\n' | |
326 | ' (1001, 1001),\n' |
|
330 | ' (1001, 1001),\n' | |
327 | ' (1002, 1002),\n' |
|
331 | ' (1002, 1002),\n' | |
328 | ' (1003, 1003),\n' |
|
332 | ' (1003, 1003),\n' | |
329 | ' (1004, 1004),\n' |
|
333 | ' (1004, 1004),\n' | |
330 | ' (1005, 1005),\n' |
|
334 | ' (1005, 1005),\n' | |
331 | ' (1006, 1006),\n' |
|
335 | ' (1006, 1006),\n' | |
332 | ' (1007, 1007),\n' |
|
336 | ' (1007, 1007),\n' | |
333 | ' (1008, 1008),\n' |
|
337 | ' (1008, 1008),\n' | |
334 | ' (1009, 1009)])'), |
|
338 | ' (1009, 1009)])'), | |
335 | (a, "OrderedDict([('key', OrderedDict(...))])"), |
|
339 | (a, "OrderedDict([('key', OrderedDict(...))])"), | |
336 | ] |
|
340 | ] | |
337 | for obj, expected in cases: |
|
341 | for obj, expected in cases: | |
338 |
|
|
342 | assert pretty.pretty(obj) == expected | |
339 |
|
343 | |||
340 |
|
344 | |||
|
345 | # TODO : pytest.mark.parametrise once nose is gone. | |||
341 | def test_collections_deque(): |
|
346 | def test_collections_deque(): | |
342 | # Create deque with cycle |
|
347 | # Create deque with cycle | |
343 | a = deque() |
|
348 | a = deque() | |
344 | a.append(a) |
|
349 | a.append(a) | |
345 |
|
350 | |||
346 | cases = [ |
|
351 | cases = [ | |
347 | (deque(), 'deque([])'), |
|
352 | (deque(), 'deque([])'), | |
348 | (deque(i for i in range(1000, 1020)), |
|
353 | (deque(i for i in range(1000, 1020)), | |
349 | 'deque([1000,\n' |
|
354 | 'deque([1000,\n' | |
350 | ' 1001,\n' |
|
355 | ' 1001,\n' | |
351 | ' 1002,\n' |
|
356 | ' 1002,\n' | |
352 | ' 1003,\n' |
|
357 | ' 1003,\n' | |
353 | ' 1004,\n' |
|
358 | ' 1004,\n' | |
354 | ' 1005,\n' |
|
359 | ' 1005,\n' | |
355 | ' 1006,\n' |
|
360 | ' 1006,\n' | |
356 | ' 1007,\n' |
|
361 | ' 1007,\n' | |
357 | ' 1008,\n' |
|
362 | ' 1008,\n' | |
358 | ' 1009,\n' |
|
363 | ' 1009,\n' | |
359 | ' 1010,\n' |
|
364 | ' 1010,\n' | |
360 | ' 1011,\n' |
|
365 | ' 1011,\n' | |
361 | ' 1012,\n' |
|
366 | ' 1012,\n' | |
362 | ' 1013,\n' |
|
367 | ' 1013,\n' | |
363 | ' 1014,\n' |
|
368 | ' 1014,\n' | |
364 | ' 1015,\n' |
|
369 | ' 1015,\n' | |
365 | ' 1016,\n' |
|
370 | ' 1016,\n' | |
366 | ' 1017,\n' |
|
371 | ' 1017,\n' | |
367 | ' 1018,\n' |
|
372 | ' 1018,\n' | |
368 | ' 1019])'), |
|
373 | ' 1019])'), | |
369 | (a, 'deque([deque(...)])'), |
|
374 | (a, 'deque([deque(...)])'), | |
370 | ] |
|
375 | ] | |
371 | for obj, expected in cases: |
|
376 | for obj, expected in cases: | |
372 |
|
|
377 | assert pretty.pretty(obj) == expected | |
373 |
|
378 | |||
|
379 | ||||
|
380 | # TODO : pytest.mark.parametrise once nose is gone. | |||
374 | def test_collections_counter(): |
|
381 | def test_collections_counter(): | |
375 | class MyCounter(Counter): |
|
382 | class MyCounter(Counter): | |
376 | pass |
|
383 | pass | |
377 | cases = [ |
|
384 | cases = [ | |
378 | (Counter(), 'Counter()'), |
|
385 | (Counter(), 'Counter()'), | |
379 | (Counter(a=1), "Counter({'a': 1})"), |
|
386 | (Counter(a=1), "Counter({'a': 1})"), | |
380 | (MyCounter(a=1), "MyCounter({'a': 1})"), |
|
387 | (MyCounter(a=1), "MyCounter({'a': 1})"), | |
381 | ] |
|
388 | ] | |
382 | for obj, expected in cases: |
|
389 | for obj, expected in cases: | |
383 |
|
|
390 | assert pretty.pretty(obj) == expected | |
384 |
|
391 | |||
|
392 | # TODO : pytest.mark.parametrise once nose is gone. | |||
385 | def test_mappingproxy(): |
|
393 | def test_mappingproxy(): | |
386 | MP = types.MappingProxyType |
|
394 | MP = types.MappingProxyType | |
387 | underlying_dict = {} |
|
395 | underlying_dict = {} | |
388 | mp_recursive = MP(underlying_dict) |
|
396 | mp_recursive = MP(underlying_dict) | |
389 | underlying_dict[2] = mp_recursive |
|
397 | underlying_dict[2] = mp_recursive | |
390 | underlying_dict[3] = underlying_dict |
|
398 | underlying_dict[3] = underlying_dict | |
391 |
|
399 | |||
392 | cases = [ |
|
400 | cases = [ | |
393 | (MP({}), "mappingproxy({})"), |
|
401 | (MP({}), "mappingproxy({})"), | |
394 | (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"), |
|
402 | (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"), | |
395 | (MP({k: k.upper() for k in string.ascii_lowercase}), |
|
403 | (MP({k: k.upper() for k in string.ascii_lowercase}), | |
396 | "mappingproxy({'a': 'A',\n" |
|
404 | "mappingproxy({'a': 'A',\n" | |
397 | " 'b': 'B',\n" |
|
405 | " 'b': 'B',\n" | |
398 | " 'c': 'C',\n" |
|
406 | " 'c': 'C',\n" | |
399 | " 'd': 'D',\n" |
|
407 | " 'd': 'D',\n" | |
400 | " 'e': 'E',\n" |
|
408 | " 'e': 'E',\n" | |
401 | " 'f': 'F',\n" |
|
409 | " 'f': 'F',\n" | |
402 | " 'g': 'G',\n" |
|
410 | " 'g': 'G',\n" | |
403 | " 'h': 'H',\n" |
|
411 | " 'h': 'H',\n" | |
404 | " 'i': 'I',\n" |
|
412 | " 'i': 'I',\n" | |
405 | " 'j': 'J',\n" |
|
413 | " 'j': 'J',\n" | |
406 | " 'k': 'K',\n" |
|
414 | " 'k': 'K',\n" | |
407 | " 'l': 'L',\n" |
|
415 | " 'l': 'L',\n" | |
408 | " 'm': 'M',\n" |
|
416 | " 'm': 'M',\n" | |
409 | " 'n': 'N',\n" |
|
417 | " 'n': 'N',\n" | |
410 | " 'o': 'O',\n" |
|
418 | " 'o': 'O',\n" | |
411 | " 'p': 'P',\n" |
|
419 | " 'p': 'P',\n" | |
412 | " 'q': 'Q',\n" |
|
420 | " 'q': 'Q',\n" | |
413 | " 'r': 'R',\n" |
|
421 | " 'r': 'R',\n" | |
414 | " 's': 'S',\n" |
|
422 | " 's': 'S',\n" | |
415 | " 't': 'T',\n" |
|
423 | " 't': 'T',\n" | |
416 | " 'u': 'U',\n" |
|
424 | " 'u': 'U',\n" | |
417 | " 'v': 'V',\n" |
|
425 | " 'v': 'V',\n" | |
418 | " 'w': 'W',\n" |
|
426 | " 'w': 'W',\n" | |
419 | " 'x': 'X',\n" |
|
427 | " 'x': 'X',\n" | |
420 | " 'y': 'Y',\n" |
|
428 | " 'y': 'Y',\n" | |
421 | " 'z': 'Z'})"), |
|
429 | " 'z': 'Z'})"), | |
422 | (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"), |
|
430 | (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"), | |
423 | (underlying_dict, |
|
431 | (underlying_dict, | |
424 | "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"), |
|
432 | "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"), | |
425 | ] |
|
433 | ] | |
426 | for obj, expected in cases: |
|
434 | for obj, expected in cases: | |
427 |
|
|
435 | assert pretty.pretty(obj) == expected | |
428 |
|
436 | |||
429 |
|
437 | |||
|
438 | # TODO : pytest.mark.parametrise once nose is gone. | |||
430 | def test_simplenamespace(): |
|
439 | def test_simplenamespace(): | |
431 | SN = types.SimpleNamespace |
|
440 | SN = types.SimpleNamespace | |
432 |
|
441 | |||
433 | sn_recursive = SN() |
|
442 | sn_recursive = SN() | |
434 | sn_recursive.first = sn_recursive |
|
443 | sn_recursive.first = sn_recursive | |
435 | sn_recursive.second = sn_recursive |
|
444 | sn_recursive.second = sn_recursive | |
436 | cases = [ |
|
445 | cases = [ | |
437 | (SN(), "namespace()"), |
|
446 | (SN(), "namespace()"), | |
438 | (SN(x=SN()), "namespace(x=namespace())"), |
|
447 | (SN(x=SN()), "namespace(x=namespace())"), | |
439 | (SN(a_long_name=[SN(s=string.ascii_lowercase)]*3, a_short_name=None), |
|
448 | (SN(a_long_name=[SN(s=string.ascii_lowercase)]*3, a_short_name=None), | |
440 | "namespace(a_long_name=[namespace(s='abcdefghijklmnopqrstuvwxyz'),\n" |
|
449 | "namespace(a_long_name=[namespace(s='abcdefghijklmnopqrstuvwxyz'),\n" | |
441 | " namespace(s='abcdefghijklmnopqrstuvwxyz'),\n" |
|
450 | " namespace(s='abcdefghijklmnopqrstuvwxyz'),\n" | |
442 | " namespace(s='abcdefghijklmnopqrstuvwxyz')],\n" |
|
451 | " namespace(s='abcdefghijklmnopqrstuvwxyz')],\n" | |
443 | " a_short_name=None)"), |
|
452 | " a_short_name=None)"), | |
444 | (sn_recursive, "namespace(first=namespace(...), second=namespace(...))"), |
|
453 | (sn_recursive, "namespace(first=namespace(...), second=namespace(...))"), | |
445 | ] |
|
454 | ] | |
446 | for obj, expected in cases: |
|
455 | for obj, expected in cases: | |
447 |
|
|
456 | assert pretty.pretty(obj) == expected | |
448 |
|
457 | |||
449 |
|
458 | |||
450 | def test_pretty_environ(): |
|
459 | def test_pretty_environ(): | |
451 | dict_repr = pretty.pretty(dict(os.environ)) |
|
460 | dict_repr = pretty.pretty(dict(os.environ)) | |
452 | # reindent to align with 'environ' prefix |
|
461 | # reindent to align with 'environ' prefix | |
453 | dict_indented = dict_repr.replace('\n', '\n' + (' ' * len('environ'))) |
|
462 | dict_indented = dict_repr.replace('\n', '\n' + (' ' * len('environ'))) | |
454 | env_repr = pretty.pretty(os.environ) |
|
463 | env_repr = pretty.pretty(os.environ) | |
455 |
|
|
464 | assert env_repr == "environ" + dict_indented | |
456 |
|
465 | |||
457 |
|
466 | |||
458 | def test_function_pretty(): |
|
467 | def test_function_pretty(): | |
459 | "Test pretty print of function" |
|
468 | "Test pretty print of function" | |
460 | # posixpath is a pure python module, its interface is consistent |
|
469 | # posixpath is a pure python module, its interface is consistent | |
461 | # across Python distributions |
|
470 | # across Python distributions | |
462 | import posixpath |
|
471 | import posixpath | |
463 | nt.assert_equal(pretty.pretty(posixpath.join), '<function posixpath.join(a, *p)>') |
|
472 | ||
464 |
|
473 | assert pretty.pretty(posixpath.join) == "<function posixpath.join(a, *p)>" | ||
|
474 | ||||
465 | # custom function |
|
475 | # custom function | |
466 | def meaning_of_life(question=None): |
|
476 | def meaning_of_life(question=None): | |
467 | if question: |
|
477 | if question: | |
468 | return 42 |
|
478 | return 42 | |
469 | return "Don't panic" |
|
479 | return "Don't panic" | |
470 |
|
480 | |||
471 | nt.assert_in('meaning_of_life(question=None)', pretty.pretty(meaning_of_life)) |
|
481 | nt.assert_in('meaning_of_life(question=None)', pretty.pretty(meaning_of_life)) | |
472 |
|
482 | |||
473 |
|
483 | |||
474 | class OrderedCounter(Counter, OrderedDict): |
|
484 | class OrderedCounter(Counter, OrderedDict): | |
475 | 'Counter that remembers the order elements are first encountered' |
|
485 | 'Counter that remembers the order elements are first encountered' | |
476 |
|
486 | |||
477 | def __repr__(self): |
|
487 | def __repr__(self): | |
478 | return '%s(%r)' % (self.__class__.__name__, OrderedDict(self)) |
|
488 | return '%s(%r)' % (self.__class__.__name__, OrderedDict(self)) | |
479 |
|
489 | |||
480 | def __reduce__(self): |
|
490 | def __reduce__(self): | |
481 | return self.__class__, (OrderedDict(self),) |
|
491 | return self.__class__, (OrderedDict(self),) | |
482 |
|
492 | |||
483 | class MySet(set): # Override repr of a basic type |
|
493 | class MySet(set): # Override repr of a basic type | |
484 | def __repr__(self): |
|
494 | def __repr__(self): | |
485 | return 'mine' |
|
495 | return 'mine' | |
486 |
|
496 | |||
487 | def test_custom_repr(): |
|
497 | def test_custom_repr(): | |
488 | """A custom repr should override a pretty printer for a parent type""" |
|
498 | """A custom repr should override a pretty printer for a parent type""" | |
489 | oc = OrderedCounter("abracadabra") |
|
499 | oc = OrderedCounter("abracadabra") | |
490 | nt.assert_in("OrderedCounter(OrderedDict", pretty.pretty(oc)) |
|
500 | nt.assert_in("OrderedCounter(OrderedDict", pretty.pretty(oc)) | |
491 |
|
501 | |||
492 |
|
|
502 | assert pretty.pretty(MySet()) == "mine" |
@@ -1,26 +1,27 b'' | |||||
1 | # coding: utf-8 |
|
1 | # coding: utf-8 | |
2 | from IPython.lib import passwd |
|
2 | from IPython.lib import passwd | |
3 | from IPython.lib.security import passwd_check, salt_len |
|
3 | from IPython.lib.security import passwd_check, salt_len | |
4 | import nose.tools as nt |
|
|||
5 |
|
4 | |||
6 | def test_passwd_structure(): |
|
5 | def test_passwd_structure(): | |
7 |
p = passwd( |
|
6 | p = passwd("passphrase") | |
8 |
algorithm, salt, hashed = p.split( |
|
7 | algorithm, salt, hashed = p.split(":") | |
9 |
|
|
8 | assert algorithm == "sha1" | |
10 |
|
|
9 | assert len(salt) == salt_len | |
11 |
|
|
10 | assert len(hashed) == 40 | |
12 |
|
11 | |||
13 | def test_roundtrip(): |
|
12 | def test_roundtrip(): | |
14 |
p = passwd( |
|
13 | p = passwd("passphrase") | |
15 |
|
|
14 | assert passwd_check(p, "passphrase") is True | |
|
15 | ||||
16 |
|
16 | |||
17 | def test_bad(): |
|
17 | def test_bad(): | |
18 | p = passwd('passphrase') |
|
18 | p = passwd('passphrase') | |
19 |
|
|
19 | assert passwd_check(p, p) is False | |
20 |
|
|
20 | assert passwd_check(p, "a:b:c:d") is False | |
21 |
|
|
21 | assert passwd_check(p, "a:b") is False | |
|
22 | ||||
22 |
|
23 | |||
23 | def test_passwd_check_unicode(): |
|
24 | def test_passwd_check_unicode(): | |
24 | # GH issue #4524 |
|
25 | # GH issue #4524 | |
25 | phash = u'sha1:23862bc21dd3:7a415a95ae4580582e314072143d9c382c491e4f' |
|
26 | phash = u'sha1:23862bc21dd3:7a415a95ae4580582e314072143d9c382c491e4f' | |
26 | assert passwd_check(phash, u"ΕeΒΆΕ§βββ") No newline at end of file |
|
27 | assert passwd_check(phash, u"ΕeΒΆΕ§βββ") |
@@ -1,172 +1,171 b'' | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | """Tests for IPython.utils.capture""" |
|
2 | """Tests for IPython.utils.capture""" | |
3 |
|
3 | |||
4 | #----------------------------------------------------------------------------- |
|
4 | #----------------------------------------------------------------------------- | |
5 | # Copyright (C) 2013 The IPython Development Team |
|
5 | # Copyright (C) 2013 The IPython Development Team | |
6 | # |
|
6 | # | |
7 | # Distributed under the terms of the BSD License. The full license is in |
|
7 | # Distributed under the terms of the BSD License. The full license is in | |
8 | # the file COPYING, distributed as part of this software. |
|
8 | # the file COPYING, distributed as part of this software. | |
9 | #----------------------------------------------------------------------------- |
|
9 | #----------------------------------------------------------------------------- | |
10 |
|
10 | |||
11 | #----------------------------------------------------------------------------- |
|
11 | #----------------------------------------------------------------------------- | |
12 | # Imports |
|
12 | # Imports | |
13 | #----------------------------------------------------------------------------- |
|
13 | #----------------------------------------------------------------------------- | |
14 |
|
14 | |||
15 |
|
15 | |||
16 | import sys |
|
16 | import sys | |
17 |
|
17 | |||
18 | import nose.tools as nt |
|
|||
19 | import pytest |
|
18 | import pytest | |
20 |
|
19 | |||
21 | from IPython.testing.decorators import skip_iptest_but_not_pytest |
|
20 | from IPython.testing.decorators import skip_iptest_but_not_pytest | |
22 |
|
21 | |||
23 | from IPython.utils import capture |
|
22 | from IPython.utils import capture | |
24 |
|
23 | |||
25 | #----------------------------------------------------------------------------- |
|
24 | #----------------------------------------------------------------------------- | |
26 | # Globals |
|
25 | # Globals | |
27 | #----------------------------------------------------------------------------- |
|
26 | #----------------------------------------------------------------------------- | |
28 |
|
27 | |||
29 | _mime_map = dict( |
|
28 | _mime_map = dict( | |
30 | _repr_png_="image/png", |
|
29 | _repr_png_="image/png", | |
31 | _repr_jpeg_="image/jpeg", |
|
30 | _repr_jpeg_="image/jpeg", | |
32 | _repr_svg_="image/svg+xml", |
|
31 | _repr_svg_="image/svg+xml", | |
33 | _repr_html_="text/html", |
|
32 | _repr_html_="text/html", | |
34 | _repr_json_="application/json", |
|
33 | _repr_json_="application/json", | |
35 | _repr_javascript_="application/javascript", |
|
34 | _repr_javascript_="application/javascript", | |
36 | ) |
|
35 | ) | |
37 |
|
36 | |||
38 | basic_data = { |
|
37 | basic_data = { | |
39 | 'image/png' : b'binarydata', |
|
38 | 'image/png' : b'binarydata', | |
40 | 'text/html' : "<b>bold</b>", |
|
39 | 'text/html' : "<b>bold</b>", | |
41 | } |
|
40 | } | |
42 | basic_metadata = { |
|
41 | basic_metadata = { | |
43 | 'image/png' : { |
|
42 | 'image/png' : { | |
44 | 'width' : 10, |
|
43 | 'width' : 10, | |
45 | 'height' : 20, |
|
44 | 'height' : 20, | |
46 | }, |
|
45 | }, | |
47 | } |
|
46 | } | |
48 |
|
47 | |||
49 | full_data = { |
|
48 | full_data = { | |
50 | 'image/png' : b'binarydata', |
|
49 | 'image/png' : b'binarydata', | |
51 | 'image/jpeg' : b'binarydata', |
|
50 | 'image/jpeg' : b'binarydata', | |
52 | 'image/svg+xml' : "<svg>", |
|
51 | 'image/svg+xml' : "<svg>", | |
53 | 'text/html' : "<b>bold</b>", |
|
52 | 'text/html' : "<b>bold</b>", | |
54 | 'application/javascript' : "alert();", |
|
53 | 'application/javascript' : "alert();", | |
55 | 'application/json' : "{}", |
|
54 | 'application/json' : "{}", | |
56 | } |
|
55 | } | |
57 | full_metadata = { |
|
56 | full_metadata = { | |
58 | 'image/png' : {"png" : "exists"}, |
|
57 | 'image/png' : {"png" : "exists"}, | |
59 | 'image/jpeg' : {"jpeg" : "exists"}, |
|
58 | 'image/jpeg' : {"jpeg" : "exists"}, | |
60 | 'image/svg+xml' : {"svg" : "exists"}, |
|
59 | 'image/svg+xml' : {"svg" : "exists"}, | |
61 | 'text/html' : {"html" : "exists"}, |
|
60 | 'text/html' : {"html" : "exists"}, | |
62 | 'application/javascript' : {"js" : "exists"}, |
|
61 | 'application/javascript' : {"js" : "exists"}, | |
63 | 'application/json' : {"json" : "exists"}, |
|
62 | 'application/json' : {"json" : "exists"}, | |
64 | } |
|
63 | } | |
65 |
|
64 | |||
66 | hello_stdout = "hello, stdout" |
|
65 | hello_stdout = "hello, stdout" | |
67 | hello_stderr = "hello, stderr" |
|
66 | hello_stderr = "hello, stderr" | |
68 |
|
67 | |||
69 | #----------------------------------------------------------------------------- |
|
68 | #----------------------------------------------------------------------------- | |
70 | # Test Functions |
|
69 | # Test Functions | |
71 | #----------------------------------------------------------------------------- |
|
70 | #----------------------------------------------------------------------------- | |
72 | @pytest.mark.parametrize("method_mime", _mime_map.items()) |
|
71 | @pytest.mark.parametrize("method_mime", _mime_map.items()) | |
73 | @skip_iptest_but_not_pytest |
|
72 | @skip_iptest_but_not_pytest | |
74 | def test_rich_output_empty(method_mime): |
|
73 | def test_rich_output_empty(method_mime): | |
75 | """RichOutput with no args""" |
|
74 | """RichOutput with no args""" | |
76 | rich = capture.RichOutput() |
|
75 | rich = capture.RichOutput() | |
77 | method, mime = method_mime |
|
76 | method, mime = method_mime | |
78 |
|
|
77 | assert getattr(rich, method)() is None | |
79 |
|
78 | |||
80 | def test_rich_output(): |
|
79 | def test_rich_output(): | |
81 | """test RichOutput basics""" |
|
80 | """test RichOutput basics""" | |
82 | data = basic_data |
|
81 | data = basic_data | |
83 | metadata = basic_metadata |
|
82 | metadata = basic_metadata | |
84 | rich = capture.RichOutput(data=data, metadata=metadata) |
|
83 | rich = capture.RichOutput(data=data, metadata=metadata) | |
85 |
|
|
84 | assert rich._repr_html_() == data["text/html"] | |
86 |
|
|
85 | assert rich._repr_png_() == (data["image/png"], metadata["image/png"]) | |
87 |
|
|
86 | assert rich._repr_latex_() is None | |
88 |
|
|
87 | assert rich._repr_javascript_() is None | |
89 |
|
|
88 | assert rich._repr_svg_() is None | |
90 |
|
89 | |||
91 |
|
90 | |||
92 | @skip_iptest_but_not_pytest |
|
91 | @skip_iptest_but_not_pytest | |
93 | @pytest.mark.parametrize("method_mime", _mime_map.items()) |
|
92 | @pytest.mark.parametrize("method_mime", _mime_map.items()) | |
94 | def test_rich_output_no_metadata(method_mime): |
|
93 | def test_rich_output_no_metadata(method_mime): | |
95 | """test RichOutput with no metadata""" |
|
94 | """test RichOutput with no metadata""" | |
96 | data = full_data |
|
95 | data = full_data | |
97 | rich = capture.RichOutput(data=data) |
|
96 | rich = capture.RichOutput(data=data) | |
98 | method, mime = method_mime |
|
97 | method, mime = method_mime | |
99 |
|
|
98 | assert getattr(rich, method)() == data[mime] | |
100 |
|
99 | |||
101 |
|
100 | |||
102 | @skip_iptest_but_not_pytest |
|
101 | @skip_iptest_but_not_pytest | |
103 | @pytest.mark.parametrize("method_mime", _mime_map.items()) |
|
102 | @pytest.mark.parametrize("method_mime", _mime_map.items()) | |
104 | def test_rich_output_metadata(method_mime): |
|
103 | def test_rich_output_metadata(method_mime): | |
105 | """test RichOutput with metadata""" |
|
104 | """test RichOutput with metadata""" | |
106 | data = full_data |
|
105 | data = full_data | |
107 | metadata = full_metadata |
|
106 | metadata = full_metadata | |
108 | rich = capture.RichOutput(data=data, metadata=metadata) |
|
107 | rich = capture.RichOutput(data=data, metadata=metadata) | |
109 | method, mime = method_mime |
|
108 | method, mime = method_mime | |
110 |
|
|
109 | assert getattr(rich, method)() == (data[mime], metadata[mime]) | |
111 |
|
110 | |||
112 | def test_rich_output_display(): |
|
111 | def test_rich_output_display(): | |
113 | """test RichOutput.display |
|
112 | """test RichOutput.display | |
114 |
|
113 | |||
115 | This is a bit circular, because we are actually using the capture code we are testing |
|
114 | This is a bit circular, because we are actually using the capture code we are testing | |
116 | to test itself. |
|
115 | to test itself. | |
117 | """ |
|
116 | """ | |
118 | data = full_data |
|
117 | data = full_data | |
119 | rich = capture.RichOutput(data=data) |
|
118 | rich = capture.RichOutput(data=data) | |
120 | with capture.capture_output() as cap: |
|
119 | with capture.capture_output() as cap: | |
121 | rich.display() |
|
120 | rich.display() | |
122 |
|
|
121 | assert len(cap.outputs) == 1 | |
123 | rich2 = cap.outputs[0] |
|
122 | rich2 = cap.outputs[0] | |
124 |
|
|
123 | assert rich2.data == rich.data | |
125 |
|
|
124 | assert rich2.metadata == rich.metadata | |
126 |
|
125 | |||
127 | def test_capture_output(): |
|
126 | def test_capture_output(): | |
128 | """capture_output works""" |
|
127 | """capture_output works""" | |
129 | rich = capture.RichOutput(data=full_data) |
|
128 | rich = capture.RichOutput(data=full_data) | |
130 | with capture.capture_output() as cap: |
|
129 | with capture.capture_output() as cap: | |
131 | print(hello_stdout, end="") |
|
130 | print(hello_stdout, end="") | |
132 | print(hello_stderr, end="", file=sys.stderr) |
|
131 | print(hello_stderr, end="", file=sys.stderr) | |
133 | rich.display() |
|
132 | rich.display() | |
134 |
|
|
133 | assert hello_stdout == cap.stdout | |
135 |
|
|
134 | assert hello_stderr == cap.stderr | |
136 |
|
135 | |||
137 |
|
136 | |||
138 | def test_capture_output_no_stdout(): |
|
137 | def test_capture_output_no_stdout(): | |
139 | """test capture_output(stdout=False)""" |
|
138 | """test capture_output(stdout=False)""" | |
140 | rich = capture.RichOutput(data=full_data) |
|
139 | rich = capture.RichOutput(data=full_data) | |
141 | with capture.capture_output(stdout=False) as cap: |
|
140 | with capture.capture_output(stdout=False) as cap: | |
142 | print(hello_stdout, end="") |
|
141 | print(hello_stdout, end="") | |
143 | print(hello_stderr, end="", file=sys.stderr) |
|
142 | print(hello_stderr, end="", file=sys.stderr) | |
144 | rich.display() |
|
143 | rich.display() | |
145 |
|
|
144 | assert "" == cap.stdout | |
146 |
|
|
145 | assert hello_stderr == cap.stderr | |
147 |
|
|
146 | assert len(cap.outputs) == 1 | |
148 |
|
147 | |||
149 |
|
148 | |||
150 | def test_capture_output_no_stderr(): |
|
149 | def test_capture_output_no_stderr(): | |
151 | """test capture_output(stderr=False)""" |
|
150 | """test capture_output(stderr=False)""" | |
152 | rich = capture.RichOutput(data=full_data) |
|
151 | rich = capture.RichOutput(data=full_data) | |
153 | # add nested capture_output so stderr doesn't make it to nose output |
|
152 | # add nested capture_output so stderr doesn't make it to nose output | |
154 | with capture.capture_output(), capture.capture_output(stderr=False) as cap: |
|
153 | with capture.capture_output(), capture.capture_output(stderr=False) as cap: | |
155 | print(hello_stdout, end="") |
|
154 | print(hello_stdout, end="") | |
156 | print(hello_stderr, end="", file=sys.stderr) |
|
155 | print(hello_stderr, end="", file=sys.stderr) | |
157 | rich.display() |
|
156 | rich.display() | |
158 |
|
|
157 | assert hello_stdout == cap.stdout | |
159 |
|
|
158 | assert "" == cap.stderr | |
160 |
|
|
159 | assert len(cap.outputs) == 1 | |
161 |
|
160 | |||
162 |
|
161 | |||
163 | def test_capture_output_no_display(): |
|
162 | def test_capture_output_no_display(): | |
164 | """test capture_output(display=False)""" |
|
163 | """test capture_output(display=False)""" | |
165 | rich = capture.RichOutput(data=full_data) |
|
164 | rich = capture.RichOutput(data=full_data) | |
166 | with capture.capture_output(display=False) as cap: |
|
165 | with capture.capture_output(display=False) as cap: | |
167 | print(hello_stdout, end="") |
|
166 | print(hello_stdout, end="") | |
168 | print(hello_stderr, end="", file=sys.stderr) |
|
167 | print(hello_stderr, end="", file=sys.stderr) | |
169 | rich.display() |
|
168 | rich.display() | |
170 |
|
|
169 | assert hello_stdout == cap.stdout | |
171 |
|
|
170 | assert hello_stderr == cap.stderr | |
172 |
|
|
171 | assert cap.outputs == [] |
@@ -1,492 +1,494 b'' | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | """Tests for IPython.utils.path.py""" |
|
2 | """Tests for IPython.utils.path.py""" | |
3 |
|
3 | |||
4 | # Copyright (c) IPython Development Team. |
|
4 | # Copyright (c) IPython Development Team. | |
5 | # Distributed under the terms of the Modified BSD License. |
|
5 | # Distributed under the terms of the Modified BSD License. | |
6 |
|
6 | |||
7 | import os |
|
7 | import os | |
8 | import shutil |
|
8 | import shutil | |
9 | import sys |
|
9 | import sys | |
10 | import tempfile |
|
10 | import tempfile | |
11 | import unittest |
|
11 | import unittest | |
12 | from contextlib import contextmanager |
|
12 | from contextlib import contextmanager | |
13 | from unittest.mock import patch |
|
13 | from unittest.mock import patch | |
14 | from os.path import join, abspath |
|
14 | from os.path import join, abspath | |
15 | from imp import reload |
|
15 | from imp import reload | |
16 |
|
16 | |||
17 | from nose import SkipTest, with_setup |
|
17 | from nose import SkipTest, with_setup | |
18 | import nose.tools as nt |
|
18 | import nose.tools as nt | |
19 |
|
19 | |||
20 | import IPython |
|
20 | import IPython | |
21 | from IPython import paths |
|
21 | from IPython import paths | |
22 | from IPython.testing import decorators as dec |
|
22 | from IPython.testing import decorators as dec | |
23 | from IPython.testing.decorators import (skip_if_not_win32, skip_win32, |
|
23 | from IPython.testing.decorators import (skip_if_not_win32, skip_win32, | |
24 | onlyif_unicode_paths, |
|
24 | onlyif_unicode_paths, | |
25 | skip_win32_py38,) |
|
25 | skip_win32_py38,) | |
26 | from IPython.testing.tools import make_tempfile |
|
26 | from IPython.testing.tools import make_tempfile | |
27 | from IPython.utils import path |
|
27 | from IPython.utils import path | |
28 | from IPython.utils.tempdir import TemporaryDirectory |
|
28 | from IPython.utils.tempdir import TemporaryDirectory | |
29 |
|
29 | |||
30 |
|
30 | |||
31 | # Platform-dependent imports |
|
31 | # Platform-dependent imports | |
32 | try: |
|
32 | try: | |
33 | import winreg as wreg |
|
33 | import winreg as wreg | |
34 | except ImportError: |
|
34 | except ImportError: | |
35 | #Fake _winreg module on non-windows platforms |
|
35 | #Fake _winreg module on non-windows platforms | |
36 | import types |
|
36 | import types | |
37 | wr_name = "winreg" |
|
37 | wr_name = "winreg" | |
38 | sys.modules[wr_name] = types.ModuleType(wr_name) |
|
38 | sys.modules[wr_name] = types.ModuleType(wr_name) | |
39 | try: |
|
39 | try: | |
40 | import winreg as wreg |
|
40 | import winreg as wreg | |
41 | except ImportError: |
|
41 | except ImportError: | |
42 | import _winreg as wreg |
|
42 | import _winreg as wreg | |
43 | #Add entries that needs to be stubbed by the testing code |
|
43 | #Add entries that needs to be stubbed by the testing code | |
44 | (wreg.OpenKey, wreg.QueryValueEx,) = (None, None) |
|
44 | (wreg.OpenKey, wreg.QueryValueEx,) = (None, None) | |
45 |
|
45 | |||
46 | #----------------------------------------------------------------------------- |
|
46 | #----------------------------------------------------------------------------- | |
47 | # Globals |
|
47 | # Globals | |
48 | #----------------------------------------------------------------------------- |
|
48 | #----------------------------------------------------------------------------- | |
49 | env = os.environ |
|
49 | env = os.environ | |
50 | TMP_TEST_DIR = tempfile.mkdtemp() |
|
50 | TMP_TEST_DIR = tempfile.mkdtemp() | |
51 | HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir") |
|
51 | HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir") | |
52 | # |
|
52 | # | |
53 | # Setup/teardown functions/decorators |
|
53 | # Setup/teardown functions/decorators | |
54 | # |
|
54 | # | |
55 |
|
55 | |||
56 | def setup_module(): |
|
56 | def setup_module(): | |
57 | """Setup testenvironment for the module: |
|
57 | """Setup testenvironment for the module: | |
58 |
|
58 | |||
59 | - Adds dummy home dir tree |
|
59 | - Adds dummy home dir tree | |
60 | """ |
|
60 | """ | |
61 | # Do not mask exceptions here. In particular, catching WindowsError is a |
|
61 | # Do not mask exceptions here. In particular, catching WindowsError is a | |
62 | # problem because that exception is only defined on Windows... |
|
62 | # problem because that exception is only defined on Windows... | |
63 | os.makedirs(os.path.join(HOME_TEST_DIR, 'ipython')) |
|
63 | os.makedirs(os.path.join(HOME_TEST_DIR, 'ipython')) | |
64 |
|
64 | |||
65 |
|
65 | |||
66 | def teardown_module(): |
|
66 | def teardown_module(): | |
67 | """Teardown testenvironment for the module: |
|
67 | """Teardown testenvironment for the module: | |
68 |
|
68 | |||
69 | - Remove dummy home dir tree |
|
69 | - Remove dummy home dir tree | |
70 | """ |
|
70 | """ | |
71 | # Note: we remove the parent test dir, which is the root of all test |
|
71 | # Note: we remove the parent test dir, which is the root of all test | |
72 | # subdirs we may have created. Use shutil instead of os.removedirs, so |
|
72 | # subdirs we may have created. Use shutil instead of os.removedirs, so | |
73 | # that non-empty directories are all recursively removed. |
|
73 | # that non-empty directories are all recursively removed. | |
74 | shutil.rmtree(TMP_TEST_DIR) |
|
74 | shutil.rmtree(TMP_TEST_DIR) | |
75 |
|
75 | |||
76 |
|
76 | |||
77 | def setup_environment(): |
|
77 | def setup_environment(): | |
78 | """Setup testenvironment for some functions that are tested |
|
78 | """Setup testenvironment for some functions that are tested | |
79 | in this module. In particular this functions stores attributes |
|
79 | in this module. In particular this functions stores attributes | |
80 | and other things that we need to stub in some test functions. |
|
80 | and other things that we need to stub in some test functions. | |
81 | This needs to be done on a function level and not module level because |
|
81 | This needs to be done on a function level and not module level because | |
82 | each testfunction needs a pristine environment. |
|
82 | each testfunction needs a pristine environment. | |
83 | """ |
|
83 | """ | |
84 | global oldstuff, platformstuff |
|
84 | global oldstuff, platformstuff | |
85 | oldstuff = (env.copy(), os.name, sys.platform, path.get_home_dir, IPython.__file__, os.getcwd()) |
|
85 | oldstuff = (env.copy(), os.name, sys.platform, path.get_home_dir, IPython.__file__, os.getcwd()) | |
86 |
|
86 | |||
87 | def teardown_environment(): |
|
87 | def teardown_environment(): | |
88 | """Restore things that were remembered by the setup_environment function |
|
88 | """Restore things that were remembered by the setup_environment function | |
89 | """ |
|
89 | """ | |
90 | (oldenv, os.name, sys.platform, path.get_home_dir, IPython.__file__, old_wd) = oldstuff |
|
90 | (oldenv, os.name, sys.platform, path.get_home_dir, IPython.__file__, old_wd) = oldstuff | |
91 | os.chdir(old_wd) |
|
91 | os.chdir(old_wd) | |
92 | reload(path) |
|
92 | reload(path) | |
93 |
|
93 | |||
94 | for key in list(env): |
|
94 | for key in list(env): | |
95 | if key not in oldenv: |
|
95 | if key not in oldenv: | |
96 | del env[key] |
|
96 | del env[key] | |
97 | env.update(oldenv) |
|
97 | env.update(oldenv) | |
98 | if hasattr(sys, 'frozen'): |
|
98 | if hasattr(sys, 'frozen'): | |
99 | del sys.frozen |
|
99 | del sys.frozen | |
100 |
|
100 | |||
101 | # Build decorator that uses the setup_environment/setup_environment |
|
101 | # Build decorator that uses the setup_environment/setup_environment | |
102 | with_environment = with_setup(setup_environment, teardown_environment) |
|
102 | with_environment = with_setup(setup_environment, teardown_environment) | |
103 |
|
103 | |||
104 | @skip_if_not_win32 |
|
104 | @skip_if_not_win32 | |
105 | @with_environment |
|
105 | @with_environment | |
106 | def test_get_home_dir_1(): |
|
106 | def test_get_home_dir_1(): | |
107 | """Testcase for py2exe logic, un-compressed lib |
|
107 | """Testcase for py2exe logic, un-compressed lib | |
108 | """ |
|
108 | """ | |
109 | unfrozen = path.get_home_dir() |
|
109 | unfrozen = path.get_home_dir() | |
110 | sys.frozen = True |
|
110 | sys.frozen = True | |
111 |
|
111 | |||
112 | #fake filename for IPython.__init__ |
|
112 | #fake filename for IPython.__init__ | |
113 | IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py")) |
|
113 | IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py")) | |
114 |
|
114 | |||
115 | home_dir = path.get_home_dir() |
|
115 | home_dir = path.get_home_dir() | |
116 |
|
|
116 | assert home_dir == unfrozen | |
117 |
|
117 | |||
118 |
|
118 | |||
119 | @skip_if_not_win32 |
|
119 | @skip_if_not_win32 | |
120 | @with_environment |
|
120 | @with_environment | |
121 | def test_get_home_dir_2(): |
|
121 | def test_get_home_dir_2(): | |
122 | """Testcase for py2exe logic, compressed lib |
|
122 | """Testcase for py2exe logic, compressed lib | |
123 | """ |
|
123 | """ | |
124 | unfrozen = path.get_home_dir() |
|
124 | unfrozen = path.get_home_dir() | |
125 | sys.frozen = True |
|
125 | sys.frozen = True | |
126 | #fake filename for IPython.__init__ |
|
126 | #fake filename for IPython.__init__ | |
127 | IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower() |
|
127 | IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower() | |
128 |
|
128 | |||
129 | home_dir = path.get_home_dir(True) |
|
129 | home_dir = path.get_home_dir(True) | |
130 |
|
|
130 | assert home_dir == unfrozen | |
131 |
|
131 | |||
132 |
|
132 | |||
133 | @skip_win32_py38 |
|
133 | @skip_win32_py38 | |
134 | @with_environment |
|
134 | @with_environment | |
135 | def test_get_home_dir_3(): |
|
135 | def test_get_home_dir_3(): | |
136 | """get_home_dir() uses $HOME if set""" |
|
136 | """get_home_dir() uses $HOME if set""" | |
137 | env["HOME"] = HOME_TEST_DIR |
|
137 | env["HOME"] = HOME_TEST_DIR | |
138 | home_dir = path.get_home_dir(True) |
|
138 | home_dir = path.get_home_dir(True) | |
139 | # get_home_dir expands symlinks |
|
139 | # get_home_dir expands symlinks | |
140 |
|
|
140 | assert home_dir == os.path.realpath(env["HOME"]) | |
141 |
|
141 | |||
142 |
|
142 | |||
143 | @with_environment |
|
143 | @with_environment | |
144 | def test_get_home_dir_4(): |
|
144 | def test_get_home_dir_4(): | |
145 | """get_home_dir() still works if $HOME is not set""" |
|
145 | """get_home_dir() still works if $HOME is not set""" | |
146 |
|
146 | |||
147 | if 'HOME' in env: del env['HOME'] |
|
147 | if 'HOME' in env: del env['HOME'] | |
148 | # this should still succeed, but we don't care what the answer is |
|
148 | # this should still succeed, but we don't care what the answer is | |
149 | home = path.get_home_dir(False) |
|
149 | home = path.get_home_dir(False) | |
150 |
|
150 | |||
151 | @skip_win32_py38 |
|
151 | @skip_win32_py38 | |
152 | @with_environment |
|
152 | @with_environment | |
153 | def test_get_home_dir_5(): |
|
153 | def test_get_home_dir_5(): | |
154 | """raise HomeDirError if $HOME is specified, but not a writable dir""" |
|
154 | """raise HomeDirError if $HOME is specified, but not a writable dir""" | |
155 | env['HOME'] = abspath(HOME_TEST_DIR+'garbage') |
|
155 | env['HOME'] = abspath(HOME_TEST_DIR+'garbage') | |
156 | # set os.name = posix, to prevent My Documents fallback on Windows |
|
156 | # set os.name = posix, to prevent My Documents fallback on Windows | |
157 | os.name = 'posix' |
|
157 | os.name = 'posix' | |
158 | nt.assert_raises(path.HomeDirError, path.get_home_dir, True) |
|
158 | nt.assert_raises(path.HomeDirError, path.get_home_dir, True) | |
159 |
|
159 | |||
160 | # Should we stub wreg fully so we can run the test on all platforms? |
|
160 | # Should we stub wreg fully so we can run the test on all platforms? | |
161 | @skip_if_not_win32 |
|
161 | @skip_if_not_win32 | |
162 | @with_environment |
|
162 | @with_environment | |
163 | def test_get_home_dir_8(): |
|
163 | def test_get_home_dir_8(): | |
164 | """Using registry hack for 'My Documents', os=='nt' |
|
164 | """Using registry hack for 'My Documents', os=='nt' | |
165 |
|
165 | |||
166 | HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing. |
|
166 | HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing. | |
167 | """ |
|
167 | """ | |
168 | os.name = 'nt' |
|
168 | os.name = 'nt' | |
169 | # Remove from stub environment all keys that may be set |
|
169 | # Remove from stub environment all keys that may be set | |
170 | for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']: |
|
170 | for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']: | |
171 | env.pop(key, None) |
|
171 | env.pop(key, None) | |
172 |
|
172 | |||
173 | class key: |
|
173 | class key: | |
174 | def __enter__(self): |
|
174 | def __enter__(self): | |
175 | pass |
|
175 | pass | |
176 | def Close(self): |
|
176 | def Close(self): | |
177 | pass |
|
177 | pass | |
178 | def __exit__(*args, **kwargs): |
|
178 | def __exit__(*args, **kwargs): | |
179 | pass |
|
179 | pass | |
180 |
|
180 | |||
181 | with patch.object(wreg, 'OpenKey', return_value=key()), \ |
|
181 | with patch.object(wreg, 'OpenKey', return_value=key()), \ | |
182 | patch.object(wreg, 'QueryValueEx', return_value=[abspath(HOME_TEST_DIR)]): |
|
182 | patch.object(wreg, 'QueryValueEx', return_value=[abspath(HOME_TEST_DIR)]): | |
183 | home_dir = path.get_home_dir() |
|
183 | home_dir = path.get_home_dir() | |
184 |
|
|
184 | assert home_dir == abspath(HOME_TEST_DIR) | |
185 |
|
185 | |||
186 | @with_environment |
|
186 | @with_environment | |
187 | def test_get_xdg_dir_0(): |
|
187 | def test_get_xdg_dir_0(): | |
188 | """test_get_xdg_dir_0, check xdg_dir""" |
|
188 | """test_get_xdg_dir_0, check xdg_dir""" | |
189 | reload(path) |
|
189 | reload(path) | |
190 | path._writable_dir = lambda path: True |
|
190 | path._writable_dir = lambda path: True | |
191 | path.get_home_dir = lambda : 'somewhere' |
|
191 | path.get_home_dir = lambda : 'somewhere' | |
192 | os.name = "posix" |
|
192 | os.name = "posix" | |
193 | sys.platform = "linux2" |
|
193 | sys.platform = "linux2" | |
194 | env.pop('IPYTHON_DIR', None) |
|
194 | env.pop('IPYTHON_DIR', None) | |
195 | env.pop('IPYTHONDIR', None) |
|
195 | env.pop('IPYTHONDIR', None) | |
196 | env.pop('XDG_CONFIG_HOME', None) |
|
196 | env.pop('XDG_CONFIG_HOME', None) | |
197 |
|
197 | |||
198 |
|
|
198 | assert path.get_xdg_dir() == os.path.join("somewhere", ".config") | |
199 |
|
199 | |||
200 |
|
200 | |||
201 | @with_environment |
|
201 | @with_environment | |
202 | def test_get_xdg_dir_1(): |
|
202 | def test_get_xdg_dir_1(): | |
203 | """test_get_xdg_dir_1, check nonexistent xdg_dir""" |
|
203 | """test_get_xdg_dir_1, check nonexistent xdg_dir""" | |
204 | reload(path) |
|
204 | reload(path) | |
205 | path.get_home_dir = lambda : HOME_TEST_DIR |
|
205 | path.get_home_dir = lambda : HOME_TEST_DIR | |
206 | os.name = "posix" |
|
206 | os.name = "posix" | |
207 | sys.platform = "linux2" |
|
207 | sys.platform = "linux2" | |
208 | env.pop('IPYTHON_DIR', None) |
|
208 | env.pop('IPYTHON_DIR', None) | |
209 | env.pop('IPYTHONDIR', None) |
|
209 | env.pop('IPYTHONDIR', None) | |
210 | env.pop('XDG_CONFIG_HOME', None) |
|
210 | env.pop('XDG_CONFIG_HOME', None) | |
211 |
|
|
211 | assert path.get_xdg_dir() is None | |
212 |
|
212 | |||
213 | @with_environment |
|
213 | @with_environment | |
214 | def test_get_xdg_dir_2(): |
|
214 | def test_get_xdg_dir_2(): | |
215 | """test_get_xdg_dir_2, check xdg_dir default to ~/.config""" |
|
215 | """test_get_xdg_dir_2, check xdg_dir default to ~/.config""" | |
216 | reload(path) |
|
216 | reload(path) | |
217 | path.get_home_dir = lambda : HOME_TEST_DIR |
|
217 | path.get_home_dir = lambda : HOME_TEST_DIR | |
218 | os.name = "posix" |
|
218 | os.name = "posix" | |
219 | sys.platform = "linux2" |
|
219 | sys.platform = "linux2" | |
220 | env.pop('IPYTHON_DIR', None) |
|
220 | env.pop('IPYTHON_DIR', None) | |
221 | env.pop('IPYTHONDIR', None) |
|
221 | env.pop('IPYTHONDIR', None) | |
222 | env.pop('XDG_CONFIG_HOME', None) |
|
222 | env.pop('XDG_CONFIG_HOME', None) | |
223 | cfgdir=os.path.join(path.get_home_dir(), '.config') |
|
223 | cfgdir=os.path.join(path.get_home_dir(), '.config') | |
224 | if not os.path.exists(cfgdir): |
|
224 | if not os.path.exists(cfgdir): | |
225 | os.makedirs(cfgdir) |
|
225 | os.makedirs(cfgdir) | |
226 |
|
226 | |||
227 |
|
|
227 | assert path.get_xdg_dir() == cfgdir | |
228 |
|
228 | |||
229 | @with_environment |
|
229 | @with_environment | |
230 | def test_get_xdg_dir_3(): |
|
230 | def test_get_xdg_dir_3(): | |
231 | """test_get_xdg_dir_3, check xdg_dir not used on OS X""" |
|
231 | """test_get_xdg_dir_3, check xdg_dir not used on OS X""" | |
232 | reload(path) |
|
232 | reload(path) | |
233 | path.get_home_dir = lambda : HOME_TEST_DIR |
|
233 | path.get_home_dir = lambda : HOME_TEST_DIR | |
234 | os.name = "posix" |
|
234 | os.name = "posix" | |
235 | sys.platform = "darwin" |
|
235 | sys.platform = "darwin" | |
236 | env.pop('IPYTHON_DIR', None) |
|
236 | env.pop('IPYTHON_DIR', None) | |
237 | env.pop('IPYTHONDIR', None) |
|
237 | env.pop('IPYTHONDIR', None) | |
238 | env.pop('XDG_CONFIG_HOME', None) |
|
238 | env.pop('XDG_CONFIG_HOME', None) | |
239 | cfgdir=os.path.join(path.get_home_dir(), '.config') |
|
239 | cfgdir=os.path.join(path.get_home_dir(), '.config') | |
240 | if not os.path.exists(cfgdir): |
|
240 | if not os.path.exists(cfgdir): | |
241 | os.makedirs(cfgdir) |
|
241 | os.makedirs(cfgdir) | |
242 |
|
242 | |||
243 |
|
|
243 | assert path.get_xdg_dir() is None | |
244 |
|
244 | |||
245 | def test_filefind(): |
|
245 | def test_filefind(): | |
246 | """Various tests for filefind""" |
|
246 | """Various tests for filefind""" | |
247 | f = tempfile.NamedTemporaryFile() |
|
247 | f = tempfile.NamedTemporaryFile() | |
248 | # print 'fname:',f.name |
|
248 | # print 'fname:',f.name | |
249 | alt_dirs = paths.get_ipython_dir() |
|
249 | alt_dirs = paths.get_ipython_dir() | |
250 | t = path.filefind(f.name, alt_dirs) |
|
250 | t = path.filefind(f.name, alt_dirs) | |
251 | # print 'found:',t |
|
251 | # print 'found:',t | |
252 |
|
252 | |||
253 |
|
253 | |||
254 | @dec.skip_if_not_win32 |
|
254 | @dec.skip_if_not_win32 | |
255 | def test_get_long_path_name_win32(): |
|
255 | def test_get_long_path_name_win32(): | |
256 | with TemporaryDirectory() as tmpdir: |
|
256 | with TemporaryDirectory() as tmpdir: | |
257 |
|
257 | |||
258 | # Make a long path. Expands the path of tmpdir prematurely as it may already have a long |
|
258 | # Make a long path. Expands the path of tmpdir prematurely as it may already have a long | |
259 | # path component, so ensure we include the long form of it |
|
259 | # path component, so ensure we include the long form of it | |
260 | long_path = os.path.join(path.get_long_path_name(tmpdir), 'this is my long path name') |
|
260 | long_path = os.path.join(path.get_long_path_name(tmpdir), 'this is my long path name') | |
261 | os.makedirs(long_path) |
|
261 | os.makedirs(long_path) | |
262 |
|
262 | |||
263 | # Test to see if the short path evaluates correctly. |
|
263 | # Test to see if the short path evaluates correctly. | |
264 | short_path = os.path.join(tmpdir, 'THISIS~1') |
|
264 | short_path = os.path.join(tmpdir, 'THISIS~1') | |
265 | evaluated_path = path.get_long_path_name(short_path) |
|
265 | evaluated_path = path.get_long_path_name(short_path) | |
266 |
|
|
266 | assert evaluated_path.lower() == long_path.lower() | |
267 |
|
267 | |||
268 |
|
268 | |||
269 | @dec.skip_win32 |
|
269 | @dec.skip_win32 | |
270 | def test_get_long_path_name(): |
|
270 | def test_get_long_path_name(): | |
271 |
p = path.get_long_path_name( |
|
271 | p = path.get_long_path_name("/usr/local") | |
272 |
|
|
272 | assert p == "/usr/local" | |
273 |
|
273 | |||
274 |
|
274 | |||
275 | class TestRaiseDeprecation(unittest.TestCase): |
|
275 | class TestRaiseDeprecation(unittest.TestCase): | |
276 |
|
276 | |||
277 | @dec.skip_win32 # can't create not-user-writable dir on win |
|
277 | @dec.skip_win32 # can't create not-user-writable dir on win | |
278 | @with_environment |
|
278 | @with_environment | |
279 | def test_not_writable_ipdir(self): |
|
279 | def test_not_writable_ipdir(self): | |
280 | tmpdir = tempfile.mkdtemp() |
|
280 | tmpdir = tempfile.mkdtemp() | |
281 | os.name = "posix" |
|
281 | os.name = "posix" | |
282 | env.pop('IPYTHON_DIR', None) |
|
282 | env.pop('IPYTHON_DIR', None) | |
283 | env.pop('IPYTHONDIR', None) |
|
283 | env.pop('IPYTHONDIR', None) | |
284 | env.pop('XDG_CONFIG_HOME', None) |
|
284 | env.pop('XDG_CONFIG_HOME', None) | |
285 | env['HOME'] = tmpdir |
|
285 | env['HOME'] = tmpdir | |
286 | ipdir = os.path.join(tmpdir, '.ipython') |
|
286 | ipdir = os.path.join(tmpdir, '.ipython') | |
287 | os.mkdir(ipdir, 0o555) |
|
287 | os.mkdir(ipdir, 0o555) | |
288 | try: |
|
288 | try: | |
289 | open(os.path.join(ipdir, "_foo_"), 'w').close() |
|
289 | open(os.path.join(ipdir, "_foo_"), 'w').close() | |
290 | except IOError: |
|
290 | except IOError: | |
291 | pass |
|
291 | pass | |
292 | else: |
|
292 | else: | |
293 | # I can still write to an unwritable dir, |
|
293 | # I can still write to an unwritable dir, | |
294 | # assume I'm root and skip the test |
|
294 | # assume I'm root and skip the test | |
295 | raise SkipTest("I can't create directories that I can't write to") |
|
295 | raise SkipTest("I can't create directories that I can't write to") | |
296 | with self.assertWarnsRegex(UserWarning, 'is not a writable location'): |
|
296 | with self.assertWarnsRegex(UserWarning, 'is not a writable location'): | |
297 | ipdir = paths.get_ipython_dir() |
|
297 | ipdir = paths.get_ipython_dir() | |
298 | env.pop('IPYTHON_DIR', None) |
|
298 | env.pop('IPYTHON_DIR', None) | |
299 |
|
299 | |||
300 | @with_environment |
|
300 | @with_environment | |
301 | def test_get_py_filename(): |
|
301 | def test_get_py_filename(): | |
302 | os.chdir(TMP_TEST_DIR) |
|
302 | os.chdir(TMP_TEST_DIR) | |
303 |
with make_tempfile( |
|
303 | with make_tempfile("foo.py"): | |
304 |
|
|
304 | assert path.get_py_filename("foo.py") == "foo.py" | |
305 |
|
|
305 | assert path.get_py_filename("foo") == "foo.py" | |
306 |
with make_tempfile( |
|
306 | with make_tempfile("foo"): | |
307 |
|
|
307 | assert path.get_py_filename("foo") == "foo" | |
308 |
nt.assert_raises(IOError, path.get_py_filename, |
|
308 | nt.assert_raises(IOError, path.get_py_filename, "foo.py") | |
309 |
nt.assert_raises(IOError, path.get_py_filename, |
|
309 | nt.assert_raises(IOError, path.get_py_filename, "foo") | |
310 |
nt.assert_raises(IOError, path.get_py_filename, |
|
310 | nt.assert_raises(IOError, path.get_py_filename, "foo.py") | |
311 |
true_fn = |
|
311 | true_fn = "foo with spaces.py" | |
312 | with make_tempfile(true_fn): |
|
312 | with make_tempfile(true_fn): | |
313 |
|
|
313 | assert path.get_py_filename("foo with spaces") == true_fn | |
314 |
|
|
314 | assert path.get_py_filename("foo with spaces.py") == true_fn | |
315 | nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"') |
|
315 | nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"') | |
316 | nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'") |
|
316 | nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'") | |
317 |
|
317 | |||
318 | @onlyif_unicode_paths |
|
318 | @onlyif_unicode_paths | |
319 | def test_unicode_in_filename(): |
|
319 | def test_unicode_in_filename(): | |
320 | """When a file doesn't exist, the exception raised should be safe to call |
|
320 | """When a file doesn't exist, the exception raised should be safe to call | |
321 | str() on - i.e. in Python 2 it must only have ASCII characters. |
|
321 | str() on - i.e. in Python 2 it must only have ASCII characters. | |
322 |
|
322 | |||
323 | https://github.com/ipython/ipython/issues/875 |
|
323 | https://github.com/ipython/ipython/issues/875 | |
324 | """ |
|
324 | """ | |
325 | try: |
|
325 | try: | |
326 | # these calls should not throw unicode encode exceptions |
|
326 | # these calls should not throw unicode encode exceptions | |
327 | path.get_py_filename('fooéè.py') |
|
327 | path.get_py_filename('fooéè.py') | |
328 | except IOError as ex: |
|
328 | except IOError as ex: | |
329 | str(ex) |
|
329 | str(ex) | |
330 |
|
330 | |||
331 |
|
331 | |||
332 | class TestShellGlob(unittest.TestCase): |
|
332 | class TestShellGlob(unittest.TestCase): | |
333 |
|
333 | |||
334 | @classmethod |
|
334 | @classmethod | |
335 | def setUpClass(cls): |
|
335 | def setUpClass(cls): | |
336 | cls.filenames_start_with_a = ['a0', 'a1', 'a2'] |
|
336 | cls.filenames_start_with_a = ['a0', 'a1', 'a2'] | |
337 | cls.filenames_end_with_b = ['0b', '1b', '2b'] |
|
337 | cls.filenames_end_with_b = ['0b', '1b', '2b'] | |
338 | cls.filenames = cls.filenames_start_with_a + cls.filenames_end_with_b |
|
338 | cls.filenames = cls.filenames_start_with_a + cls.filenames_end_with_b | |
339 | cls.tempdir = TemporaryDirectory() |
|
339 | cls.tempdir = TemporaryDirectory() | |
340 | td = cls.tempdir.name |
|
340 | td = cls.tempdir.name | |
341 |
|
341 | |||
342 | with cls.in_tempdir(): |
|
342 | with cls.in_tempdir(): | |
343 | # Create empty files |
|
343 | # Create empty files | |
344 | for fname in cls.filenames: |
|
344 | for fname in cls.filenames: | |
345 | open(os.path.join(td, fname), 'w').close() |
|
345 | open(os.path.join(td, fname), 'w').close() | |
346 |
|
346 | |||
347 | @classmethod |
|
347 | @classmethod | |
348 | def tearDownClass(cls): |
|
348 | def tearDownClass(cls): | |
349 | cls.tempdir.cleanup() |
|
349 | cls.tempdir.cleanup() | |
350 |
|
350 | |||
351 | @classmethod |
|
351 | @classmethod | |
352 | @contextmanager |
|
352 | @contextmanager | |
353 | def in_tempdir(cls): |
|
353 | def in_tempdir(cls): | |
354 | save = os.getcwd() |
|
354 | save = os.getcwd() | |
355 | try: |
|
355 | try: | |
356 | os.chdir(cls.tempdir.name) |
|
356 | os.chdir(cls.tempdir.name) | |
357 | yield |
|
357 | yield | |
358 | finally: |
|
358 | finally: | |
359 | os.chdir(save) |
|
359 | os.chdir(save) | |
360 |
|
360 | |||
361 | def check_match(self, patterns, matches): |
|
361 | def check_match(self, patterns, matches): | |
362 | with self.in_tempdir(): |
|
362 | with self.in_tempdir(): | |
363 | # glob returns unordered list. that's why sorted is required. |
|
363 | # glob returns unordered list. that's why sorted is required. | |
364 |
|
|
364 | assert sorted(path.shellglob(patterns)) == sorted(matches) | |
365 | sorted(matches)) |
|
|||
366 |
|
365 | |||
367 | def common_cases(self): |
|
366 | def common_cases(self): | |
368 | return [ |
|
367 | return [ | |
369 | (['*'], self.filenames), |
|
368 | (['*'], self.filenames), | |
370 | (['a*'], self.filenames_start_with_a), |
|
369 | (['a*'], self.filenames_start_with_a), | |
371 | (['*c'], ['*c']), |
|
370 | (['*c'], ['*c']), | |
372 | (['*', 'a*', '*b', '*c'], self.filenames |
|
371 | (['*', 'a*', '*b', '*c'], self.filenames | |
373 | + self.filenames_start_with_a |
|
372 | + self.filenames_start_with_a | |
374 | + self.filenames_end_with_b |
|
373 | + self.filenames_end_with_b | |
375 | + ['*c']), |
|
374 | + ['*c']), | |
376 | (['a[012]'], self.filenames_start_with_a), |
|
375 | (['a[012]'], self.filenames_start_with_a), | |
377 | ] |
|
376 | ] | |
378 |
|
377 | |||
379 | @skip_win32 |
|
378 | @skip_win32 | |
380 | def test_match_posix(self): |
|
379 | def test_match_posix(self): | |
381 | for (patterns, matches) in self.common_cases() + [ |
|
380 | for (patterns, matches) in self.common_cases() + [ | |
382 | ([r'\*'], ['*']), |
|
381 | ([r'\*'], ['*']), | |
383 | ([r'a\*', 'a*'], ['a*'] + self.filenames_start_with_a), |
|
382 | ([r'a\*', 'a*'], ['a*'] + self.filenames_start_with_a), | |
384 | ([r'a\[012]'], ['a[012]']), |
|
383 | ([r'a\[012]'], ['a[012]']), | |
385 | ]: |
|
384 | ]: | |
386 | yield (self.check_match, patterns, matches) |
|
385 | yield (self.check_match, patterns, matches) | |
387 |
|
386 | |||
388 | @skip_if_not_win32 |
|
387 | @skip_if_not_win32 | |
389 | def test_match_windows(self): |
|
388 | def test_match_windows(self): | |
390 | for (patterns, matches) in self.common_cases() + [ |
|
389 | for (patterns, matches) in self.common_cases() + [ | |
391 | # In windows, backslash is interpreted as path |
|
390 | # In windows, backslash is interpreted as path | |
392 | # separator. Therefore, you can't escape glob |
|
391 | # separator. Therefore, you can't escape glob | |
393 | # using it. |
|
392 | # using it. | |
394 | ([r'a\*', 'a*'], [r'a\*'] + self.filenames_start_with_a), |
|
393 | ([r'a\*', 'a*'], [r'a\*'] + self.filenames_start_with_a), | |
395 | ([r'a\[012]'], [r'a\[012]']), |
|
394 | ([r'a\[012]'], [r'a\[012]']), | |
396 | ]: |
|
395 | ]: | |
397 | yield (self.check_match, patterns, matches) |
|
396 | yield (self.check_match, patterns, matches) | |
398 |
|
397 | |||
399 |
|
398 | |||
|
399 | # TODO : pytest.mark.parametrise once nose is gone. | |||
400 | def test_unescape_glob(): |
|
400 | def test_unescape_glob(): | |
401 |
|
|
401 | assert path.unescape_glob(r"\*\[\!\]\?") == "*[!]?" | |
402 |
|
|
402 | assert path.unescape_glob(r"\\*") == r"\*" | |
403 |
|
|
403 | assert path.unescape_glob(r"\\\*") == r"\*" | |
404 |
|
|
404 | assert path.unescape_glob(r"\\a") == r"\a" | |
405 |
|
|
405 | assert path.unescape_glob(r"\a") == r"\a" | |
406 |
|
406 | |||
407 |
|
407 | |||
408 | @onlyif_unicode_paths |
|
408 | @onlyif_unicode_paths | |
409 | def test_ensure_dir_exists(): |
|
409 | def test_ensure_dir_exists(): | |
410 | with TemporaryDirectory() as td: |
|
410 | with TemporaryDirectory() as td: | |
411 | d = os.path.join(td, 'βir') |
|
411 | d = os.path.join(td, 'βir') | |
412 | path.ensure_dir_exists(d) # create it |
|
412 | path.ensure_dir_exists(d) # create it | |
413 | assert os.path.isdir(d) |
|
413 | assert os.path.isdir(d) | |
414 | path.ensure_dir_exists(d) # no-op |
|
414 | path.ensure_dir_exists(d) # no-op | |
415 | f = os.path.join(td, 'Ζile') |
|
415 | f = os.path.join(td, 'Ζile') | |
416 | open(f, 'w').close() # touch |
|
416 | open(f, 'w').close() # touch | |
417 | with nt.assert_raises(IOError): |
|
417 | with nt.assert_raises(IOError): | |
418 | path.ensure_dir_exists(f) |
|
418 | path.ensure_dir_exists(f) | |
419 |
|
419 | |||
420 | class TestLinkOrCopy(unittest.TestCase): |
|
420 | class TestLinkOrCopy(unittest.TestCase): | |
421 | def setUp(self): |
|
421 | def setUp(self): | |
422 | self.tempdir = TemporaryDirectory() |
|
422 | self.tempdir = TemporaryDirectory() | |
423 | self.src = self.dst("src") |
|
423 | self.src = self.dst("src") | |
424 | with open(self.src, "w") as f: |
|
424 | with open(self.src, "w") as f: | |
425 | f.write("Hello, world!") |
|
425 | f.write("Hello, world!") | |
426 |
|
426 | |||
427 | def tearDown(self): |
|
427 | def tearDown(self): | |
428 | self.tempdir.cleanup() |
|
428 | self.tempdir.cleanup() | |
429 |
|
429 | |||
430 | def dst(self, *args): |
|
430 | def dst(self, *args): | |
431 | return os.path.join(self.tempdir.name, *args) |
|
431 | return os.path.join(self.tempdir.name, *args) | |
432 |
|
432 | |||
433 | def assert_inode_not_equal(self, a, b): |
|
433 | def assert_inode_not_equal(self, a, b): | |
434 | nt.assert_not_equal(os.stat(a).st_ino, os.stat(b).st_ino, |
|
434 | assert ( | |
435 | "%r and %r do reference the same indoes" %(a, b)) |
|
435 | os.stat(a).st_ino != os.stat(b).st_ino | |
|
436 | ), "%r and %r do reference the same indoes" % (a, b) | |||
436 |
|
437 | |||
437 | def assert_inode_equal(self, a, b): |
|
438 | def assert_inode_equal(self, a, b): | |
438 | nt.assert_equal(os.stat(a).st_ino, os.stat(b).st_ino, |
|
439 | assert ( | |
439 | "%r and %r do not reference the same indoes" %(a, b)) |
|
440 | os.stat(a).st_ino == os.stat(b).st_ino | |
|
441 | ), "%r and %r do not reference the same indoes" % (a, b) | |||
440 |
|
442 | |||
441 | def assert_content_equal(self, a, b): |
|
443 | def assert_content_equal(self, a, b): | |
442 | with open(a) as a_f: |
|
444 | with open(a) as a_f: | |
443 | with open(b) as b_f: |
|
445 | with open(b) as b_f: | |
444 |
|
|
446 | assert a_f.read() == b_f.read() | |
445 |
|
447 | |||
446 | @skip_win32 |
|
448 | @skip_win32 | |
447 | def test_link_successful(self): |
|
449 | def test_link_successful(self): | |
448 | dst = self.dst("target") |
|
450 | dst = self.dst("target") | |
449 | path.link_or_copy(self.src, dst) |
|
451 | path.link_or_copy(self.src, dst) | |
450 | self.assert_inode_equal(self.src, dst) |
|
452 | self.assert_inode_equal(self.src, dst) | |
451 |
|
453 | |||
452 | @skip_win32 |
|
454 | @skip_win32 | |
453 | def test_link_into_dir(self): |
|
455 | def test_link_into_dir(self): | |
454 | dst = self.dst("some_dir") |
|
456 | dst = self.dst("some_dir") | |
455 | os.mkdir(dst) |
|
457 | os.mkdir(dst) | |
456 | path.link_or_copy(self.src, dst) |
|
458 | path.link_or_copy(self.src, dst) | |
457 | expected_dst = self.dst("some_dir", os.path.basename(self.src)) |
|
459 | expected_dst = self.dst("some_dir", os.path.basename(self.src)) | |
458 | self.assert_inode_equal(self.src, expected_dst) |
|
460 | self.assert_inode_equal(self.src, expected_dst) | |
459 |
|
461 | |||
460 | @skip_win32 |
|
462 | @skip_win32 | |
461 | def test_target_exists(self): |
|
463 | def test_target_exists(self): | |
462 | dst = self.dst("target") |
|
464 | dst = self.dst("target") | |
463 | open(dst, "w").close() |
|
465 | open(dst, "w").close() | |
464 | path.link_or_copy(self.src, dst) |
|
466 | path.link_or_copy(self.src, dst) | |
465 | self.assert_inode_equal(self.src, dst) |
|
467 | self.assert_inode_equal(self.src, dst) | |
466 |
|
468 | |||
467 | @skip_win32 |
|
469 | @skip_win32 | |
468 | def test_no_link(self): |
|
470 | def test_no_link(self): | |
469 | real_link = os.link |
|
471 | real_link = os.link | |
470 | try: |
|
472 | try: | |
471 | del os.link |
|
473 | del os.link | |
472 | dst = self.dst("target") |
|
474 | dst = self.dst("target") | |
473 | path.link_or_copy(self.src, dst) |
|
475 | path.link_or_copy(self.src, dst) | |
474 | self.assert_content_equal(self.src, dst) |
|
476 | self.assert_content_equal(self.src, dst) | |
475 | self.assert_inode_not_equal(self.src, dst) |
|
477 | self.assert_inode_not_equal(self.src, dst) | |
476 | finally: |
|
478 | finally: | |
477 | os.link = real_link |
|
479 | os.link = real_link | |
478 |
|
480 | |||
479 | @skip_if_not_win32 |
|
481 | @skip_if_not_win32 | |
480 | def test_windows(self): |
|
482 | def test_windows(self): | |
481 | dst = self.dst("target") |
|
483 | dst = self.dst("target") | |
482 | path.link_or_copy(self.src, dst) |
|
484 | path.link_or_copy(self.src, dst) | |
483 | self.assert_content_equal(self.src, dst) |
|
485 | self.assert_content_equal(self.src, dst) | |
484 |
|
486 | |||
485 | def test_link_twice(self): |
|
487 | def test_link_twice(self): | |
486 | # Linking the same file twice shouldn't leave duplicates around. |
|
488 | # Linking the same file twice shouldn't leave duplicates around. | |
487 | # See https://github.com/ipython/ipython/issues/6450 |
|
489 | # See https://github.com/ipython/ipython/issues/6450 | |
488 | dst = self.dst('target') |
|
490 | dst = self.dst('target') | |
489 | path.link_or_copy(self.src, dst) |
|
491 | path.link_or_copy(self.src, dst) | |
490 | path.link_or_copy(self.src, dst) |
|
492 | path.link_or_copy(self.src, dst) | |
491 | self.assert_inode_equal(self.src, dst) |
|
493 | self.assert_inode_equal(self.src, dst) | |
492 |
|
|
494 | assert sorted(os.listdir(self.tempdir.name)) == ["src", "target"] |
@@ -1,195 +1,198 b'' | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | """ |
|
2 | """ | |
3 | Tests for platutils.py |
|
3 | Tests for platutils.py | |
4 | """ |
|
4 | """ | |
5 |
|
5 | |||
6 | #----------------------------------------------------------------------------- |
|
6 | #----------------------------------------------------------------------------- | |
7 | # Copyright (C) 2008-2011 The IPython Development Team |
|
7 | # Copyright (C) 2008-2011 The IPython Development Team | |
8 | # |
|
8 | # | |
9 | # Distributed under the terms of the BSD License. The full license is in |
|
9 | # Distributed under the terms of the BSD License. The full license is in | |
10 | # the file COPYING, distributed as part of this software. |
|
10 | # the file COPYING, distributed as part of this software. | |
11 | #----------------------------------------------------------------------------- |
|
11 | #----------------------------------------------------------------------------- | |
12 |
|
12 | |||
13 | #----------------------------------------------------------------------------- |
|
13 | #----------------------------------------------------------------------------- | |
14 | # Imports |
|
14 | # Imports | |
15 | #----------------------------------------------------------------------------- |
|
15 | #----------------------------------------------------------------------------- | |
16 |
|
16 | |||
17 | import sys |
|
17 | import sys | |
18 | import signal |
|
18 | import signal | |
19 | import os |
|
19 | import os | |
20 | import time |
|
20 | import time | |
21 | from _thread import interrupt_main # Py 3 |
|
21 | from _thread import interrupt_main # Py 3 | |
22 | import threading |
|
22 | import threading | |
23 | from unittest import SkipTest |
|
23 | from unittest import SkipTest | |
24 |
|
24 | |||
25 | import nose.tools as nt |
|
25 | import nose.tools as nt | |
26 |
|
26 | |||
27 | from IPython.utils.process import (find_cmd, FindCmdError, arg_split, |
|
27 | from IPython.utils.process import (find_cmd, FindCmdError, arg_split, | |
28 | system, getoutput, getoutputerror, |
|
28 | system, getoutput, getoutputerror, | |
29 | get_output_error_code) |
|
29 | get_output_error_code) | |
30 | from IPython.utils.capture import capture_output |
|
30 | from IPython.utils.capture import capture_output | |
31 | from IPython.testing import decorators as dec |
|
31 | from IPython.testing import decorators as dec | |
32 | from IPython.testing import tools as tt |
|
32 | from IPython.testing import tools as tt | |
33 |
|
33 | |||
34 | python = os.path.basename(sys.executable) |
|
34 | python = os.path.basename(sys.executable) | |
35 |
|
35 | |||
36 | #----------------------------------------------------------------------------- |
|
36 | #----------------------------------------------------------------------------- | |
37 | # Tests |
|
37 | # Tests | |
38 | #----------------------------------------------------------------------------- |
|
38 | #----------------------------------------------------------------------------- | |
39 |
|
39 | |||
40 |
|
40 | |||
41 | @dec.skip_win32 |
|
41 | @dec.skip_win32 | |
42 | def test_find_cmd_ls(): |
|
42 | def test_find_cmd_ls(): | |
43 | """Make sure we can find the full path to ls.""" |
|
43 | """Make sure we can find the full path to ls.""" | |
44 | path = find_cmd('ls') |
|
44 | path = find_cmd('ls') | |
45 | nt.assert_true(path.endswith('ls')) |
|
45 | nt.assert_true(path.endswith('ls')) | |
46 |
|
46 | |||
47 |
|
47 | |||
48 | def has_pywin32(): |
|
48 | def has_pywin32(): | |
49 | try: |
|
49 | try: | |
50 | import win32api |
|
50 | import win32api | |
51 | except ImportError: |
|
51 | except ImportError: | |
52 | return False |
|
52 | return False | |
53 | return True |
|
53 | return True | |
54 |
|
54 | |||
55 |
|
55 | |||
56 | @dec.onlyif(has_pywin32, "This test requires win32api to run") |
|
56 | @dec.onlyif(has_pywin32, "This test requires win32api to run") | |
57 | def test_find_cmd_pythonw(): |
|
57 | def test_find_cmd_pythonw(): | |
58 | """Try to find pythonw on Windows.""" |
|
58 | """Try to find pythonw on Windows.""" | |
59 | path = find_cmd('pythonw') |
|
59 | path = find_cmd('pythonw') | |
60 | assert path.lower().endswith('pythonw.exe'), path |
|
60 | assert path.lower().endswith('pythonw.exe'), path | |
61 |
|
61 | |||
62 |
|
62 | |||
63 | @dec.onlyif(lambda : sys.platform != 'win32' or has_pywin32(), |
|
63 | @dec.onlyif(lambda : sys.platform != 'win32' or has_pywin32(), | |
64 | "This test runs on posix or in win32 with win32api installed") |
|
64 | "This test runs on posix or in win32 with win32api installed") | |
65 | def test_find_cmd_fail(): |
|
65 | def test_find_cmd_fail(): | |
66 | """Make sure that FindCmdError is raised if we can't find the cmd.""" |
|
66 | """Make sure that FindCmdError is raised if we can't find the cmd.""" | |
67 | nt.assert_raises(FindCmdError,find_cmd,'asdfasdf') |
|
67 | nt.assert_raises(FindCmdError,find_cmd,'asdfasdf') | |
68 |
|
68 | |||
69 |
|
69 | |||
|
70 | # TODO: move to pytest.mark.parametrize once nose gone | |||
70 | @dec.skip_win32 |
|
71 | @dec.skip_win32 | |
71 | def test_arg_split(): |
|
72 | def test_arg_split(): | |
72 | """Ensure that argument lines are correctly split like in a shell.""" |
|
73 | """Ensure that argument lines are correctly split like in a shell.""" | |
73 | tests = [['hi', ['hi']], |
|
74 | tests = [['hi', ['hi']], | |
74 | [u'hi', [u'hi']], |
|
75 | [u'hi', [u'hi']], | |
75 | ['hello there', ['hello', 'there']], |
|
76 | ['hello there', ['hello', 'there']], | |
76 | # \u01ce == \N{LATIN SMALL LETTER A WITH CARON} |
|
77 | # \u01ce == \N{LATIN SMALL LETTER A WITH CARON} | |
77 | # Do not use \N because the tests crash with syntax error in |
|
78 | # Do not use \N because the tests crash with syntax error in | |
78 | # some cases, for example windows python2.6. |
|
79 | # some cases, for example windows python2.6. | |
79 | [u'h\u01cello', [u'h\u01cello']], |
|
80 | [u'h\u01cello', [u'h\u01cello']], | |
80 | ['something "with quotes"', ['something', '"with quotes"']], |
|
81 | ['something "with quotes"', ['something', '"with quotes"']], | |
81 | ] |
|
82 | ] | |
82 | for argstr, argv in tests: |
|
83 | for argstr, argv in tests: | |
83 |
|
|
84 | assert arg_split(argstr) == argv | |
84 |
|
85 | |||
|
86 | ||||
|
87 | # TODO: move to pytest.mark.parametrize once nose gone | |||
85 | @dec.skip_if_not_win32 |
|
88 | @dec.skip_if_not_win32 | |
86 | def test_arg_split_win32(): |
|
89 | def test_arg_split_win32(): | |
87 | """Ensure that argument lines are correctly split like in a shell.""" |
|
90 | """Ensure that argument lines are correctly split like in a shell.""" | |
88 | tests = [['hi', ['hi']], |
|
91 | tests = [['hi', ['hi']], | |
89 | [u'hi', [u'hi']], |
|
92 | [u'hi', [u'hi']], | |
90 | ['hello there', ['hello', 'there']], |
|
93 | ['hello there', ['hello', 'there']], | |
91 | [u'h\u01cello', [u'h\u01cello']], |
|
94 | [u'h\u01cello', [u'h\u01cello']], | |
92 | ['something "with quotes"', ['something', 'with quotes']], |
|
95 | ['something "with quotes"', ['something', 'with quotes']], | |
93 | ] |
|
96 | ] | |
94 | for argstr, argv in tests: |
|
97 | for argstr, argv in tests: | |
95 |
|
|
98 | assert arg_split(argstr) == argv | |
96 |
|
99 | |||
97 |
|
100 | |||
98 | class SubProcessTestCase(tt.TempFileMixin): |
|
101 | class SubProcessTestCase(tt.TempFileMixin): | |
99 | def setUp(self): |
|
102 | def setUp(self): | |
100 | """Make a valid python temp file.""" |
|
103 | """Make a valid python temp file.""" | |
101 | lines = [ "import sys", |
|
104 | lines = [ "import sys", | |
102 | "print('on stdout', end='', file=sys.stdout)", |
|
105 | "print('on stdout', end='', file=sys.stdout)", | |
103 | "print('on stderr', end='', file=sys.stderr)", |
|
106 | "print('on stderr', end='', file=sys.stderr)", | |
104 | "sys.stdout.flush()", |
|
107 | "sys.stdout.flush()", | |
105 | "sys.stderr.flush()"] |
|
108 | "sys.stderr.flush()"] | |
106 | self.mktmp('\n'.join(lines)) |
|
109 | self.mktmp('\n'.join(lines)) | |
107 |
|
110 | |||
108 | def test_system(self): |
|
111 | def test_system(self): | |
109 | status = system('%s "%s"' % (python, self.fname)) |
|
112 | status = system('%s "%s"' % (python, self.fname)) | |
110 | self.assertEqual(status, 0) |
|
113 | self.assertEqual(status, 0) | |
111 |
|
114 | |||
112 | def test_system_quotes(self): |
|
115 | def test_system_quotes(self): | |
113 | status = system('%s -c "import sys"' % python) |
|
116 | status = system('%s -c "import sys"' % python) | |
114 | self.assertEqual(status, 0) |
|
117 | self.assertEqual(status, 0) | |
115 |
|
118 | |||
116 | def assert_interrupts(self, command): |
|
119 | def assert_interrupts(self, command): | |
117 | """ |
|
120 | """ | |
118 | Interrupt a subprocess after a second. |
|
121 | Interrupt a subprocess after a second. | |
119 | """ |
|
122 | """ | |
120 | if threading.main_thread() != threading.current_thread(): |
|
123 | if threading.main_thread() != threading.current_thread(): | |
121 | raise nt.SkipTest("Can't run this test if not in main thread.") |
|
124 | raise nt.SkipTest("Can't run this test if not in main thread.") | |
122 |
|
125 | |||
123 | # Some tests can overwrite SIGINT handler (by using pdb for example), |
|
126 | # Some tests can overwrite SIGINT handler (by using pdb for example), | |
124 | # which then breaks this test, so just make sure it's operating |
|
127 | # which then breaks this test, so just make sure it's operating | |
125 | # normally. |
|
128 | # normally. | |
126 | signal.signal(signal.SIGINT, signal.default_int_handler) |
|
129 | signal.signal(signal.SIGINT, signal.default_int_handler) | |
127 |
|
130 | |||
128 | def interrupt(): |
|
131 | def interrupt(): | |
129 | # Wait for subprocess to start: |
|
132 | # Wait for subprocess to start: | |
130 | time.sleep(0.5) |
|
133 | time.sleep(0.5) | |
131 | interrupt_main() |
|
134 | interrupt_main() | |
132 |
|
135 | |||
133 | threading.Thread(target=interrupt).start() |
|
136 | threading.Thread(target=interrupt).start() | |
134 | start = time.time() |
|
137 | start = time.time() | |
135 | try: |
|
138 | try: | |
136 | result = command() |
|
139 | result = command() | |
137 | except KeyboardInterrupt: |
|
140 | except KeyboardInterrupt: | |
138 | # Success! |
|
141 | # Success! | |
139 | pass |
|
142 | pass | |
140 | end = time.time() |
|
143 | end = time.time() | |
141 | self.assertTrue( |
|
144 | self.assertTrue( | |
142 | end - start < 2, "Process didn't die quickly: %s" % (end - start) |
|
145 | end - start < 2, "Process didn't die quickly: %s" % (end - start) | |
143 | ) |
|
146 | ) | |
144 | return result |
|
147 | return result | |
145 |
|
148 | |||
146 | def test_system_interrupt(self): |
|
149 | def test_system_interrupt(self): | |
147 | """ |
|
150 | """ | |
148 | When interrupted in the way ipykernel interrupts IPython, the |
|
151 | When interrupted in the way ipykernel interrupts IPython, the | |
149 | subprocess is interrupted. |
|
152 | subprocess is interrupted. | |
150 | """ |
|
153 | """ | |
151 | def command(): |
|
154 | def command(): | |
152 | return system('%s -c "import time; time.sleep(5)"' % python) |
|
155 | return system('%s -c "import time; time.sleep(5)"' % python) | |
153 |
|
156 | |||
154 | status = self.assert_interrupts(command) |
|
157 | status = self.assert_interrupts(command) | |
155 | self.assertNotEqual( |
|
158 | self.assertNotEqual( | |
156 | status, 0, "The process wasn't interrupted. Status: %s" % (status,) |
|
159 | status, 0, "The process wasn't interrupted. Status: %s" % (status,) | |
157 | ) |
|
160 | ) | |
158 |
|
161 | |||
159 | def test_getoutput(self): |
|
162 | def test_getoutput(self): | |
160 | out = getoutput('%s "%s"' % (python, self.fname)) |
|
163 | out = getoutput('%s "%s"' % (python, self.fname)) | |
161 | # we can't rely on the order the line buffered streams are flushed |
|
164 | # we can't rely on the order the line buffered streams are flushed | |
162 | try: |
|
165 | try: | |
163 | self.assertEqual(out, 'on stderron stdout') |
|
166 | self.assertEqual(out, 'on stderron stdout') | |
164 | except AssertionError: |
|
167 | except AssertionError: | |
165 | self.assertEqual(out, 'on stdouton stderr') |
|
168 | self.assertEqual(out, 'on stdouton stderr') | |
166 |
|
169 | |||
167 | def test_getoutput_quoted(self): |
|
170 | def test_getoutput_quoted(self): | |
168 | out = getoutput('%s -c "print (1)"' % python) |
|
171 | out = getoutput('%s -c "print (1)"' % python) | |
169 | self.assertEqual(out.strip(), '1') |
|
172 | self.assertEqual(out.strip(), '1') | |
170 |
|
173 | |||
171 | #Invalid quoting on windows |
|
174 | #Invalid quoting on windows | |
172 | @dec.skip_win32 |
|
175 | @dec.skip_win32 | |
173 | def test_getoutput_quoted2(self): |
|
176 | def test_getoutput_quoted2(self): | |
174 | out = getoutput("%s -c 'print (1)'" % python) |
|
177 | out = getoutput("%s -c 'print (1)'" % python) | |
175 | self.assertEqual(out.strip(), '1') |
|
178 | self.assertEqual(out.strip(), '1') | |
176 | out = getoutput("%s -c 'print (\"1\")'" % python) |
|
179 | out = getoutput("%s -c 'print (\"1\")'" % python) | |
177 | self.assertEqual(out.strip(), '1') |
|
180 | self.assertEqual(out.strip(), '1') | |
178 |
|
181 | |||
179 | def test_getoutput_error(self): |
|
182 | def test_getoutput_error(self): | |
180 | out, err = getoutputerror('%s "%s"' % (python, self.fname)) |
|
183 | out, err = getoutputerror('%s "%s"' % (python, self.fname)) | |
181 | self.assertEqual(out, 'on stdout') |
|
184 | self.assertEqual(out, 'on stdout') | |
182 | self.assertEqual(err, 'on stderr') |
|
185 | self.assertEqual(err, 'on stderr') | |
183 |
|
186 | |||
184 | def test_get_output_error_code(self): |
|
187 | def test_get_output_error_code(self): | |
185 | quiet_exit = '%s -c "import sys; sys.exit(1)"' % python |
|
188 | quiet_exit = '%s -c "import sys; sys.exit(1)"' % python | |
186 | out, err, code = get_output_error_code(quiet_exit) |
|
189 | out, err, code = get_output_error_code(quiet_exit) | |
187 | self.assertEqual(out, '') |
|
190 | self.assertEqual(out, '') | |
188 | self.assertEqual(err, '') |
|
191 | self.assertEqual(err, '') | |
189 | self.assertEqual(code, 1) |
|
192 | self.assertEqual(code, 1) | |
190 | out, err, code = get_output_error_code('%s "%s"' % (python, self.fname)) |
|
193 | out, err, code = get_output_error_code('%s "%s"' % (python, self.fname)) | |
191 | self.assertEqual(out, 'on stdout') |
|
194 | self.assertEqual(out, 'on stdout') | |
192 | self.assertEqual(err, 'on stderr') |
|
195 | self.assertEqual(err, 'on stderr') | |
193 | self.assertEqual(code, 0) |
|
196 | self.assertEqual(code, 0) | |
194 |
|
197 | |||
195 |
|
198 |
@@ -1,200 +1,205 b'' | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | """Tests for IPython.utils.text""" |
|
2 | """Tests for IPython.utils.text""" | |
3 |
|
3 | |||
4 | #----------------------------------------------------------------------------- |
|
4 | #----------------------------------------------------------------------------- | |
5 | # Copyright (C) 2011 The IPython Development Team |
|
5 | # Copyright (C) 2011 The IPython Development Team | |
6 | # |
|
6 | # | |
7 | # Distributed under the terms of the BSD License. The full license is in |
|
7 | # Distributed under the terms of the BSD License. The full license is in | |
8 | # the file COPYING, distributed as part of this software. |
|
8 | # the file COPYING, distributed as part of this software. | |
9 | #----------------------------------------------------------------------------- |
|
9 | #----------------------------------------------------------------------------- | |
10 |
|
10 | |||
11 | #----------------------------------------------------------------------------- |
|
11 | #----------------------------------------------------------------------------- | |
12 | # Imports |
|
12 | # Imports | |
13 | #----------------------------------------------------------------------------- |
|
13 | #----------------------------------------------------------------------------- | |
14 |
|
14 | |||
15 | import os |
|
15 | import os | |
16 | import math |
|
16 | import math | |
17 | import random |
|
17 | import random | |
18 | import sys |
|
18 | import sys | |
19 |
|
19 | |||
20 | import nose.tools as nt |
|
20 | import nose.tools as nt | |
21 | from pathlib import Path |
|
21 | from pathlib import Path | |
22 |
|
22 | |||
23 | from IPython.utils import text |
|
23 | from IPython.utils import text | |
24 |
|
24 | |||
25 | #----------------------------------------------------------------------------- |
|
25 | #----------------------------------------------------------------------------- | |
26 | # Globals |
|
26 | # Globals | |
27 | #----------------------------------------------------------------------------- |
|
27 | #----------------------------------------------------------------------------- | |
28 |
|
28 | |||
29 | def test_columnize(): |
|
29 | def test_columnize(): | |
30 | """Basic columnize tests.""" |
|
30 | """Basic columnize tests.""" | |
31 | size = 5 |
|
31 | size = 5 | |
32 | items = [l*size for l in 'abcd'] |
|
32 | items = [l*size for l in 'abcd'] | |
33 |
|
33 | |||
34 | out = text.columnize(items, displaywidth=80) |
|
34 | out = text.columnize(items, displaywidth=80) | |
35 |
|
|
35 | assert out == "aaaaa bbbbb ccccc ddddd\n" | |
36 | out = text.columnize(items, displaywidth=25) |
|
36 | out = text.columnize(items, displaywidth=25) | |
37 |
|
|
37 | assert out == "aaaaa ccccc\nbbbbb ddddd\n" | |
38 | out = text.columnize(items, displaywidth=12) |
|
38 | out = text.columnize(items, displaywidth=12) | |
39 |
|
|
39 | assert out == "aaaaa ccccc\nbbbbb ddddd\n" | |
40 | out = text.columnize(items, displaywidth=10) |
|
40 | out = text.columnize(items, displaywidth=10) | |
41 |
|
|
41 | assert out == "aaaaa\nbbbbb\nccccc\nddddd\n" | |
42 |
|
42 | |||
43 | out = text.columnize(items, row_first=True, displaywidth=80) |
|
43 | out = text.columnize(items, row_first=True, displaywidth=80) | |
44 |
|
|
44 | assert out == "aaaaa bbbbb ccccc ddddd\n" | |
45 | out = text.columnize(items, row_first=True, displaywidth=25) |
|
45 | out = text.columnize(items, row_first=True, displaywidth=25) | |
46 |
|
|
46 | assert out == "aaaaa bbbbb\nccccc ddddd\n" | |
47 | out = text.columnize(items, row_first=True, displaywidth=12) |
|
47 | out = text.columnize(items, row_first=True, displaywidth=12) | |
48 |
|
|
48 | assert out == "aaaaa bbbbb\nccccc ddddd\n" | |
49 | out = text.columnize(items, row_first=True, displaywidth=10) |
|
49 | out = text.columnize(items, row_first=True, displaywidth=10) | |
50 |
|
|
50 | assert out == "aaaaa\nbbbbb\nccccc\nddddd\n" | |
51 |
|
51 | |||
52 | out = text.columnize(items, displaywidth=40, spread=True) |
|
52 | out = text.columnize(items, displaywidth=40, spread=True) | |
53 |
|
|
53 | assert out == "aaaaa bbbbb ccccc ddddd\n" | |
54 | out = text.columnize(items, displaywidth=20, spread=True) |
|
54 | out = text.columnize(items, displaywidth=20, spread=True) | |
55 |
|
|
55 | assert out == "aaaaa ccccc\nbbbbb ddddd\n" | |
56 | out = text.columnize(items, displaywidth=12, spread=True) |
|
56 | out = text.columnize(items, displaywidth=12, spread=True) | |
57 |
|
|
57 | assert out == "aaaaa ccccc\nbbbbb ddddd\n" | |
58 | out = text.columnize(items, displaywidth=10, spread=True) |
|
58 | out = text.columnize(items, displaywidth=10, spread=True) | |
59 |
|
|
59 | assert out == "aaaaa\nbbbbb\nccccc\nddddd\n" | |
60 |
|
60 | |||
61 |
|
61 | |||
62 | def test_columnize_random(): |
|
62 | def test_columnize_random(): | |
63 | """Test with random input to hopefully catch edge case """ |
|
63 | """Test with random input to hopefully catch edge case """ | |
64 | for row_first in [True, False]: |
|
64 | for row_first in [True, False]: | |
65 | for nitems in [random.randint(2,70) for i in range(2,20)]: |
|
65 | for nitems in [random.randint(2,70) for i in range(2,20)]: | |
66 | displaywidth = random.randint(20,200) |
|
66 | displaywidth = random.randint(20,200) | |
67 | rand_len = [random.randint(2,displaywidth) for i in range(nitems)] |
|
67 | rand_len = [random.randint(2,displaywidth) for i in range(nitems)] | |
68 | items = ['x'*l for l in rand_len] |
|
68 | items = ['x'*l for l in rand_len] | |
69 | out = text.columnize(items, row_first=row_first, displaywidth=displaywidth) |
|
69 | out = text.columnize(items, row_first=row_first, displaywidth=displaywidth) | |
70 | longer_line = max([len(x) for x in out.split('\n')]) |
|
70 | longer_line = max([len(x) for x in out.split('\n')]) | |
71 | longer_element = max(rand_len) |
|
71 | longer_element = max(rand_len) | |
72 | if longer_line > displaywidth: |
|
72 | if longer_line > displaywidth: | |
73 | print("Columnize displayed something lager than displaywidth : %s " % longer_line) |
|
73 | print("Columnize displayed something lager than displaywidth : %s " % longer_line) | |
74 | print("longer element : %s " % longer_element) |
|
74 | print("longer element : %s " % longer_element) | |
75 | print("displaywidth : %s " % displaywidth) |
|
75 | print("displaywidth : %s " % displaywidth) | |
76 | print("number of element : %s " % nitems) |
|
76 | print("number of element : %s " % nitems) | |
77 | print("size of each element :\n %s" % rand_len) |
|
77 | print("size of each element :\n %s" % rand_len) | |
78 | assert False, "row_first={0}".format(row_first) |
|
78 | assert False, "row_first={0}".format(row_first) | |
79 |
|
79 | |||
|
80 | ||||
|
81 | # TODO: pytest mark.parametrize once nose removed. | |||
80 | def test_columnize_medium(): |
|
82 | def test_columnize_medium(): | |
81 | """Test with inputs than shouldn't be wider than 80""" |
|
83 | """Test with inputs than shouldn't be wider than 80""" | |
82 | size = 40 |
|
84 | size = 40 | |
83 | items = [l*size for l in 'abc'] |
|
85 | items = [l*size for l in 'abc'] | |
84 | for row_first in [True, False]: |
|
86 | for row_first in [True, False]: | |
85 | out = text.columnize(items, row_first=row_first, displaywidth=80) |
|
87 | out = text.columnize(items, row_first=row_first, displaywidth=80) | |
86 |
|
|
88 | assert out == "\n".join(items + [""]), "row_first={0}".format(row_first) | |
|
89 | ||||
87 |
|
90 | |||
|
91 | # TODO: pytest mark.parametrize once nose removed. | |||
88 | def test_columnize_long(): |
|
92 | def test_columnize_long(): | |
89 | """Test columnize with inputs longer than the display window""" |
|
93 | """Test columnize with inputs longer than the display window""" | |
90 | size = 11 |
|
94 | size = 11 | |
91 | items = [l*size for l in 'abc'] |
|
95 | items = [l*size for l in 'abc'] | |
92 | for row_first in [True, False]: |
|
96 | for row_first in [True, False]: | |
93 | out = text.columnize(items, row_first=row_first, displaywidth=size-1) |
|
97 | out = text.columnize(items, row_first=row_first, displaywidth=size - 1) | |
94 |
|
|
98 | assert out == "\n".join(items + [""]), "row_first={0}".format(row_first) | |
|
99 | ||||
95 |
|
100 | |||
96 | def eval_formatter_check(f): |
|
101 | def eval_formatter_check(f): | |
97 | ns = dict(n=12, pi=math.pi, stuff='hello there', os=os, u=u"cafΓ©", b="cafΓ©") |
|
102 | ns = dict(n=12, pi=math.pi, stuff='hello there', os=os, u=u"cafΓ©", b="cafΓ©") | |
98 | s = f.format("{n} {n//4} {stuff.split()[0]}", **ns) |
|
103 | s = f.format("{n} {n//4} {stuff.split()[0]}", **ns) | |
99 |
|
|
104 | assert s == "12 3 hello" | |
100 | s = f.format(' '.join(['{n//%i}'%i for i in range(1,8)]), **ns) |
|
105 | s = f.format(' '.join(['{n//%i}'%i for i in range(1,8)]), **ns) | |
101 |
|
|
106 | assert s == "12 6 4 3 2 2 1" | |
102 | s = f.format('{[n//i for i in range(1,8)]}', **ns) |
|
107 | s = f.format('{[n//i for i in range(1,8)]}', **ns) | |
103 |
|
|
108 | assert s == "[12, 6, 4, 3, 2, 2, 1]" | |
104 | s = f.format("{stuff!s}", **ns) |
|
109 | s = f.format("{stuff!s}", **ns) | |
105 |
|
|
110 | assert s == ns["stuff"] | |
106 | s = f.format("{stuff!r}", **ns) |
|
111 | s = f.format("{stuff!r}", **ns) | |
107 |
|
|
112 | assert s == repr(ns["stuff"]) | |
108 |
|
113 | |||
109 | # Check with unicode: |
|
114 | # Check with unicode: | |
110 | s = f.format("{u}", **ns) |
|
115 | s = f.format("{u}", **ns) | |
111 |
|
|
116 | assert s == ns["u"] | |
112 | # This decodes in a platform dependent manner, but it shouldn't error out |
|
117 | # This decodes in a platform dependent manner, but it shouldn't error out | |
113 | s = f.format("{b}", **ns) |
|
118 | s = f.format("{b}", **ns) | |
114 |
|
119 | |||
115 | nt.assert_raises(NameError, f.format, '{dne}', **ns) |
|
120 | nt.assert_raises(NameError, f.format, '{dne}', **ns) | |
116 |
|
121 | |||
117 | def eval_formatter_slicing_check(f): |
|
122 | def eval_formatter_slicing_check(f): | |
118 | ns = dict(n=12, pi=math.pi, stuff='hello there', os=os) |
|
123 | ns = dict(n=12, pi=math.pi, stuff='hello there', os=os) | |
119 | s = f.format(" {stuff.split()[:]} ", **ns) |
|
124 | s = f.format(" {stuff.split()[:]} ", **ns) | |
120 |
|
|
125 | assert s == " ['hello', 'there'] " | |
121 | s = f.format(" {stuff.split()[::-1]} ", **ns) |
|
126 | s = f.format(" {stuff.split()[::-1]} ", **ns) | |
122 |
|
|
127 | assert s == " ['there', 'hello'] " | |
123 | s = f.format("{stuff[::2]}", **ns) |
|
128 | s = f.format("{stuff[::2]}", **ns) | |
124 |
|
|
129 | assert s == ns["stuff"][::2] | |
125 |
|
130 | |||
126 | nt.assert_raises(SyntaxError, f.format, "{n:x}", **ns) |
|
131 | nt.assert_raises(SyntaxError, f.format, "{n:x}", **ns) | |
127 |
|
132 | |||
128 | def eval_formatter_no_slicing_check(f): |
|
133 | def eval_formatter_no_slicing_check(f): | |
129 | ns = dict(n=12, pi=math.pi, stuff='hello there', os=os) |
|
134 | ns = dict(n=12, pi=math.pi, stuff='hello there', os=os) | |
130 |
|
135 | |||
131 | s = f.format('{n:x} {pi**2:+f}', **ns) |
|
136 | s = f.format('{n:x} {pi**2:+f}', **ns) | |
132 |
|
|
137 | assert s == "c +9.869604" | |
133 |
|
138 | |||
134 |
s = f.format( |
|
139 | s = f.format("{stuff[slice(1,4)]}", **ns) | |
135 |
|
|
140 | assert s == "ell" | |
136 |
|
141 | |||
137 | s = f.format("{a[:]}", a=[1, 2]) |
|
142 | s = f.format("{a[:]}", a=[1, 2]) | |
138 |
|
|
143 | assert s == "[1, 2]" | |
139 |
|
144 | |||
140 | def test_eval_formatter(): |
|
145 | def test_eval_formatter(): | |
141 | f = text.EvalFormatter() |
|
146 | f = text.EvalFormatter() | |
142 | eval_formatter_check(f) |
|
147 | eval_formatter_check(f) | |
143 | eval_formatter_no_slicing_check(f) |
|
148 | eval_formatter_no_slicing_check(f) | |
144 |
|
149 | |||
145 | def test_full_eval_formatter(): |
|
150 | def test_full_eval_formatter(): | |
146 | f = text.FullEvalFormatter() |
|
151 | f = text.FullEvalFormatter() | |
147 | eval_formatter_check(f) |
|
152 | eval_formatter_check(f) | |
148 | eval_formatter_slicing_check(f) |
|
153 | eval_formatter_slicing_check(f) | |
149 |
|
154 | |||
150 | def test_dollar_formatter(): |
|
155 | def test_dollar_formatter(): | |
151 | f = text.DollarFormatter() |
|
156 | f = text.DollarFormatter() | |
152 | eval_formatter_check(f) |
|
157 | eval_formatter_check(f) | |
153 | eval_formatter_slicing_check(f) |
|
158 | eval_formatter_slicing_check(f) | |
154 |
|
159 | |||
155 | ns = dict(n=12, pi=math.pi, stuff='hello there', os=os) |
|
160 | ns = dict(n=12, pi=math.pi, stuff='hello there', os=os) | |
156 | s = f.format("$n", **ns) |
|
161 | s = f.format("$n", **ns) | |
157 |
|
|
162 | assert s == "12" | |
158 | s = f.format("$n.real", **ns) |
|
163 | s = f.format("$n.real", **ns) | |
159 |
|
|
164 | assert s == "12" | |
160 | s = f.format("$n/{stuff[:5]}", **ns) |
|
165 | s = f.format("$n/{stuff[:5]}", **ns) | |
161 |
|
|
166 | assert s == "12/hello" | |
162 | s = f.format("$n $$HOME", **ns) |
|
167 | s = f.format("$n $$HOME", **ns) | |
163 |
|
|
168 | assert s == "12 $HOME" | |
164 | s = f.format("${foo}", foo="HOME") |
|
169 | s = f.format("${foo}", foo="HOME") | |
165 |
|
|
170 | assert s == "$HOME" | |
166 |
|
171 | |||
167 |
|
172 | |||
168 | def test_strip_email(): |
|
173 | def test_strip_email(): | |
169 | src = """\ |
|
174 | src = """\ | |
170 | >> >>> def f(x): |
|
175 | >> >>> def f(x): | |
171 | >> ... return x+1 |
|
176 | >> ... return x+1 | |
172 | >> ... |
|
177 | >> ... | |
173 | >> >>> zz = f(2.5)""" |
|
178 | >> >>> zz = f(2.5)""" | |
174 | cln = """\ |
|
179 | cln = """\ | |
175 | >>> def f(x): |
|
180 | >>> def f(x): | |
176 | ... return x+1 |
|
181 | ... return x+1 | |
177 | ... |
|
182 | ... | |
178 | >>> zz = f(2.5)""" |
|
183 | >>> zz = f(2.5)""" | |
179 |
|
|
184 | assert text.strip_email_quotes(src) == cln | |
180 |
|
185 | |||
181 |
|
186 | |||
182 | def test_strip_email2(): |
|
187 | def test_strip_email2(): | |
183 | src = '> > > list()' |
|
188 | src = '> > > list()' | |
184 | cln = 'list()' |
|
189 | cln = 'list()' | |
185 |
|
|
190 | assert text.strip_email_quotes(src) == cln | |
186 |
|
191 | |||
187 | def test_LSString(): |
|
192 | def test_LSString(): | |
188 | lss = text.LSString("abc\ndef") |
|
193 | lss = text.LSString("abc\ndef") | |
189 |
|
|
194 | assert lss.l == ["abc", "def"] | |
190 |
|
|
195 | assert lss.s == "abc def" | |
191 | lss = text.LSString(os.getcwd()) |
|
196 | lss = text.LSString(os.getcwd()) | |
192 | nt.assert_is_instance(lss.p[0], Path) |
|
197 | nt.assert_is_instance(lss.p[0], Path) | |
193 |
|
198 | |||
194 | def test_SList(): |
|
199 | def test_SList(): | |
195 |
sl = text.SList([ |
|
200 | sl = text.SList(["a 11", "b 1", "a 2"]) | |
196 |
|
|
201 | assert sl.n == "a 11\nb 1\na 2" | |
197 |
|
|
202 | assert sl.s == "a 11 b 1 a 2" | |
198 |
|
|
203 | assert sl.grep(lambda x: x.startswith("a")) == text.SList(["a 11", "a 2"]) | |
199 |
|
|
204 | assert sl.fields(0) == text.SList(["a", "b", "a"]) | |
200 |
|
|
205 | assert sl.sort(field=1, nums=True) == text.SList(["b 1", "a 2", "a 11"]) |
General Comments 0
You need to be logged in to leave comments.
Login now