##// END OF EJS Templates
Merge pull request #11783 from Carreau/cleanup-support-functions...
Matthias Bussonnier -
r25086:46e64d12 merge
parent child Browse files
Show More
@@ -1,480 +1,437 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 import sys
12
11
13 import nose.tools as nt
12 import nose.tools as nt
14
13
15 from .. import oinspect
14 from .. import oinspect
16 from IPython.core.magic import (Magics, magics_class, line_magic,
15
17 cell_magic, line_cell_magic,
18 register_line_magic, register_cell_magic,
19 register_line_cell_magic)
20 from decorator import decorator
16 from decorator import decorator
21 from IPython import get_ipython
17
22 from IPython.testing.tools import AssertPrints, AssertNotPrints
18 from IPython.testing.tools import AssertPrints, AssertNotPrints
23 from IPython.utils.path import compress_user
19 from IPython.utils.path import compress_user
24
20
25
21
26 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
27 # Globals and constants
23 # Globals and constants
28 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
29
25
30 inspector = oinspect.Inspector()
26 inspector = oinspect.Inspector()
31 ip = get_ipython()
27 ip = get_ipython()
32
28
33 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
34 # Local utilities
30 # Local utilities
35 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
36
32
37 # WARNING: since this test checks the line number where a function is
33 # 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
34 # 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
35 # updated. Do NOT insert any whitespace between the next line and the function
40 # definition below.
36 # definition below.
41 THIS_LINE_NUMBER = 41 # Put here the actual number of this line
37 THIS_LINE_NUMBER = 37 # Put here the actual number of this line
42
38
43 from unittest import TestCase
39 from unittest import TestCase
44
40
45 class Test(TestCase):
41 class Test(TestCase):
46
42
47 def test_find_source_lines(self):
43 def test_find_source_lines(self):
48 self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines),
44 self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines),
49 THIS_LINE_NUMBER+6)
45 THIS_LINE_NUMBER+6)
50
46
51
47
52 # A couple of utilities to ensure these tests work the same from a source or a
48 # A couple of utilities to ensure these tests work the same from a source or a
53 # binary install
49 # binary install
54 def pyfile(fname):
50 def pyfile(fname):
55 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
51 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
56
52
57
53
58 def match_pyfiles(f1, f2):
54 def match_pyfiles(f1, f2):
59 nt.assert_equal(pyfile(f1), pyfile(f2))
55 nt.assert_equal(pyfile(f1), pyfile(f2))
60
56
61
57
62 def test_find_file():
58 def test_find_file():
63 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
59 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
64
60
65
61
66 def test_find_file_decorated1():
62 def test_find_file_decorated1():
67
63
68 @decorator
64 @decorator
69 def noop1(f):
65 def noop1(f):
70 def wrapper(*a, **kw):
66 def wrapper(*a, **kw):
71 return f(*a, **kw)
67 return f(*a, **kw)
72 return wrapper
68 return wrapper
73
69
74 @noop1
70 @noop1
75 def f(x):
71 def f(x):
76 "My docstring"
72 "My docstring"
77
73
78 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
74 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
79 nt.assert_equal(f.__doc__, "My docstring")
75 nt.assert_equal(f.__doc__, "My docstring")
80
76
81
77
82 def test_find_file_decorated2():
78 def test_find_file_decorated2():
83
79
84 @decorator
80 @decorator
85 def noop2(f, *a, **kw):
81 def noop2(f, *a, **kw):
86 return f(*a, **kw)
82 return f(*a, **kw)
87
83
88 @noop2
84 @noop2
89 @noop2
85 @noop2
90 @noop2
86 @noop2
91 def f(x):
87 def f(x):
92 "My docstring 2"
88 "My docstring 2"
93
89
94 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
90 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
95 nt.assert_equal(f.__doc__, "My docstring 2")
91 nt.assert_equal(f.__doc__, "My docstring 2")
96
92
97
93
98 def test_find_file_magic():
94 def test_find_file_magic():
99 run = ip.find_line_magic('run')
95 run = ip.find_line_magic('run')
100 nt.assert_not_equal(oinspect.find_file(run), None)
96 nt.assert_not_equal(oinspect.find_file(run), None)
101
97
102
98
103 # A few generic objects we can then inspect in the tests below
99 # A few generic objects we can then inspect in the tests below
104
100
105 class Call(object):
101 class Call(object):
106 """This is the class docstring."""
102 """This is the class docstring."""
107
103
108 def __init__(self, x, y=1):
104 def __init__(self, x, y=1):
109 """This is the constructor docstring."""
105 """This is the constructor docstring."""
110
106
111 def __call__(self, *a, **kw):
107 def __call__(self, *a, **kw):
112 """This is the call docstring."""
108 """This is the call docstring."""
113
109
114 def method(self, x, z=2):
110 def method(self, x, z=2):
115 """Some method's docstring"""
111 """Some method's docstring"""
116
112
117 class HasSignature(object):
113 class HasSignature(object):
118 """This is the class docstring."""
114 """This is the class docstring."""
119 __signature__ = Signature([Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)])
115 __signature__ = Signature([Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)])
120
116
121 def __init__(self, *args):
117 def __init__(self, *args):
122 """This is the init docstring"""
118 """This is the init docstring"""
123
119
124
120
125 class SimpleClass(object):
121 class SimpleClass(object):
126 def method(self, x, z=2):
122 def method(self, x, z=2):
127 """Some method's docstring"""
123 """Some method's docstring"""
128
124
129
125
130 class OldStyle:
131 """An old-style class for testing."""
132 pass
133
134
135 def f(x, y=2, *a, **kw):
136 """A simple function."""
137
138
139 def g(y, z=3, *a, **kw):
140 pass # no docstring
141
142
143 @register_line_magic
144 def lmagic(line):
145 "A line magic"
146
147
148 @register_cell_magic
149 def cmagic(line, cell):
150 "A cell magic"
151
152
153 @register_line_cell_magic
154 def lcmagic(line, cell=None):
155 "A line/cell magic"
156
157
158 @magics_class
159 class SimpleMagics(Magics):
160 @line_magic
161 def Clmagic(self, cline):
162 "A class-based line magic"
163
164 @cell_magic
165 def Ccmagic(self, cline, ccell):
166 "A class-based cell magic"
167
168 @line_cell_magic
169 def Clcmagic(self, cline, ccell=None):
170 "A class-based line/cell magic"
171
172
126
173 class Awkward(object):
127 class Awkward(object):
174 def __getattr__(self, name):
128 def __getattr__(self, name):
175 raise Exception(name)
129 raise Exception(name)
176
130
177 class NoBoolCall:
131 class NoBoolCall:
178 """
132 """
179 callable with `__bool__` raising should still be inspect-able.
133 callable with `__bool__` raising should still be inspect-able.
180 """
134 """
181
135
182 def __call__(self):
136 def __call__(self):
183 """does nothing"""
137 """does nothing"""
184 pass
138 pass
185
139
186 def __bool__(self):
140 def __bool__(self):
187 """just raise NotImplemented"""
141 """just raise NotImplemented"""
188 raise NotImplementedError('Must be implemented')
142 raise NotImplementedError('Must be implemented')
189
143
190
144
191 class SerialLiar(object):
145 class SerialLiar(object):
192 """Attribute accesses always get another copy of the same class.
146 """Attribute accesses always get another copy of the same class.
193
147
194 unittest.mock.call does something similar, but it's not ideal for testing
148 unittest.mock.call does something similar, but it's not ideal for testing
195 as the failure mode is to eat all your RAM. This gives up after 10k levels.
149 as the failure mode is to eat all your RAM. This gives up after 10k levels.
196 """
150 """
197 def __init__(self, max_fibbing_twig, lies_told=0):
151 def __init__(self, max_fibbing_twig, lies_told=0):
198 if lies_told > 10000:
152 if lies_told > 10000:
199 raise RuntimeError('Nose too long, honesty is the best policy')
153 raise RuntimeError('Nose too long, honesty is the best policy')
200 self.max_fibbing_twig = max_fibbing_twig
154 self.max_fibbing_twig = max_fibbing_twig
201 self.lies_told = lies_told
155 self.lies_told = lies_told
202 max_fibbing_twig[0] = max(max_fibbing_twig[0], lies_told)
156 max_fibbing_twig[0] = max(max_fibbing_twig[0], lies_told)
203
157
204 def __getattr__(self, item):
158 def __getattr__(self, item):
205 return SerialLiar(self.max_fibbing_twig, self.lies_told + 1)
159 return SerialLiar(self.max_fibbing_twig, self.lies_told + 1)
206
160
207 #-----------------------------------------------------------------------------
161 #-----------------------------------------------------------------------------
208 # Tests
162 # Tests
209 #-----------------------------------------------------------------------------
163 #-----------------------------------------------------------------------------
210
164
211 def test_info():
165 def test_info():
212 "Check that Inspector.info fills out various fields as expected."
166 "Check that Inspector.info fills out various fields as expected."
213 i = inspector.info(Call, oname='Call')
167 i = inspector.info(Call, oname='Call')
214 nt.assert_equal(i['type_name'], 'type')
168 nt.assert_equal(i['type_name'], 'type')
215 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
169 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
216 nt.assert_equal(i['base_class'], expted_class)
170 nt.assert_equal(i['base_class'], expted_class)
217 nt.assert_regex(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>")
171 nt.assert_regex(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>")
218 fname = __file__
172 fname = __file__
219 if fname.endswith(".pyc"):
173 if fname.endswith(".pyc"):
220 fname = fname[:-1]
174 fname = fname[:-1]
221 # case-insensitive comparison needed on some filesystems
175 # case-insensitive comparison needed on some filesystems
222 # e.g. Windows:
176 # e.g. Windows:
223 nt.assert_equal(i['file'].lower(), compress_user(fname).lower())
177 nt.assert_equal(i['file'].lower(), compress_user(fname).lower())
224 nt.assert_equal(i['definition'], None)
178 nt.assert_equal(i['definition'], None)
225 nt.assert_equal(i['docstring'], Call.__doc__)
179 nt.assert_equal(i['docstring'], Call.__doc__)
226 nt.assert_equal(i['source'], None)
180 nt.assert_equal(i['source'], None)
227 nt.assert_true(i['isclass'])
181 nt.assert_true(i['isclass'])
228 nt.assert_equal(i['init_definition'], "Call(x, y=1)")
182 nt.assert_equal(i['init_definition'], "Call(x, y=1)")
229 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
183 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
230
184
231 i = inspector.info(Call, detail_level=1)
185 i = inspector.info(Call, detail_level=1)
232 nt.assert_not_equal(i['source'], None)
186 nt.assert_not_equal(i['source'], None)
233 nt.assert_equal(i['docstring'], None)
187 nt.assert_equal(i['docstring'], None)
234
188
235 c = Call(1)
189 c = Call(1)
236 c.__doc__ = "Modified instance docstring"
190 c.__doc__ = "Modified instance docstring"
237 i = inspector.info(c)
191 i = inspector.info(c)
238 nt.assert_equal(i['type_name'], 'Call')
192 nt.assert_equal(i['type_name'], 'Call')
239 nt.assert_equal(i['docstring'], "Modified instance docstring")
193 nt.assert_equal(i['docstring'], "Modified instance docstring")
240 nt.assert_equal(i['class_docstring'], Call.__doc__)
194 nt.assert_equal(i['class_docstring'], Call.__doc__)
241 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
195 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
242 nt.assert_equal(i['call_docstring'], Call.__call__.__doc__)
196 nt.assert_equal(i['call_docstring'], Call.__call__.__doc__)
243
197
244 def test_class_signature():
198 def test_class_signature():
245 info = inspector.info(HasSignature, 'HasSignature')
199 info = inspector.info(HasSignature, 'HasSignature')
246 nt.assert_equal(info['init_definition'], "HasSignature(test)")
200 nt.assert_equal(info['init_definition'], "HasSignature(test)")
247 nt.assert_equal(info['init_docstring'], HasSignature.__init__.__doc__)
201 nt.assert_equal(info['init_docstring'], HasSignature.__init__.__doc__)
248
202
249 def test_info_awkward():
203 def test_info_awkward():
250 # Just test that this doesn't throw an error.
204 # Just test that this doesn't throw an error.
251 inspector.info(Awkward())
205 inspector.info(Awkward())
252
206
253 def test_bool_raise():
207 def test_bool_raise():
254 inspector.info(NoBoolCall())
208 inspector.info(NoBoolCall())
255
209
256 def test_info_serialliar():
210 def test_info_serialliar():
257 fib_tracker = [0]
211 fib_tracker = [0]
258 inspector.info(SerialLiar(fib_tracker))
212 inspector.info(SerialLiar(fib_tracker))
259
213
260 # Nested attribute access should be cut off at 100 levels deep to avoid
214 # Nested attribute access should be cut off at 100 levels deep to avoid
261 # infinite loops: https://github.com/ipython/ipython/issues/9122
215 # infinite loops: https://github.com/ipython/ipython/issues/9122
262 nt.assert_less(fib_tracker[0], 9000)
216 nt.assert_less(fib_tracker[0], 9000)
263
217
218 def support_function_one(x, y=2, *a, **kw):
219 """A simple function."""
220
264 def test_calldef_none():
221 def test_calldef_none():
265 # We should ignore __call__ for all of these.
222 # We should ignore __call__ for all of these.
266 for obj in [f, SimpleClass().method, any, str.upper]:
223 for obj in [support_function_one, SimpleClass().method, any, str.upper]:
267 print(obj)
224 print(obj)
268 i = inspector.info(obj)
225 i = inspector.info(obj)
269 nt.assert_is(i['call_def'], None)
226 nt.assert_is(i['call_def'], None)
270
227
271 def f_kwarg(pos, *, kwonly):
228 def f_kwarg(pos, *, kwonly):
272 pass
229 pass
273
230
274 def test_definition_kwonlyargs():
231 def test_definition_kwonlyargs():
275 i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
232 i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
276 nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)")
233 nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)")
277
234
278 def test_getdoc():
235 def test_getdoc():
279 class A(object):
236 class A(object):
280 """standard docstring"""
237 """standard docstring"""
281 pass
238 pass
282
239
283 class B(object):
240 class B(object):
284 """standard docstring"""
241 """standard docstring"""
285 def getdoc(self):
242 def getdoc(self):
286 return "custom docstring"
243 return "custom docstring"
287
244
288 class C(object):
245 class C(object):
289 """standard docstring"""
246 """standard docstring"""
290 def getdoc(self):
247 def getdoc(self):
291 return None
248 return None
292
249
293 a = A()
250 a = A()
294 b = B()
251 b = B()
295 c = C()
252 c = C()
296
253
297 nt.assert_equal(oinspect.getdoc(a), "standard docstring")
254 nt.assert_equal(oinspect.getdoc(a), "standard docstring")
298 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
255 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
299 nt.assert_equal(oinspect.getdoc(c), "standard docstring")
256 nt.assert_equal(oinspect.getdoc(c), "standard docstring")
300
257
301
258
302 def test_empty_property_has_no_source():
259 def test_empty_property_has_no_source():
303 i = inspector.info(property(), detail_level=1)
260 i = inspector.info(property(), detail_level=1)
304 nt.assert_is(i['source'], None)
261 nt.assert_is(i['source'], None)
305
262
306
263
307 def test_property_sources():
264 def test_property_sources():
308 import posixpath
265 import posixpath
309 # A simple adder whose source and signature stays
266 # A simple adder whose source and signature stays
310 # the same across Python distributions
267 # the same across Python distributions
311 def simple_add(a, b):
268 def simple_add(a, b):
312 "Adds two numbers"
269 "Adds two numbers"
313 return a + b
270 return a + b
314
271
315 class A(object):
272 class A(object):
316 @property
273 @property
317 def foo(self):
274 def foo(self):
318 return 'bar'
275 return 'bar'
319
276
320 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
277 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
321
278
322 dname = property(posixpath.dirname)
279 dname = property(posixpath.dirname)
323 adder = property(simple_add)
280 adder = property(simple_add)
324
281
325 i = inspector.info(A.foo, detail_level=1)
282 i = inspector.info(A.foo, detail_level=1)
326 nt.assert_in('def foo(self):', i['source'])
283 nt.assert_in('def foo(self):', i['source'])
327 nt.assert_in('lambda self, v:', i['source'])
284 nt.assert_in('lambda self, v:', i['source'])
328
285
329 i = inspector.info(A.dname, detail_level=1)
286 i = inspector.info(A.dname, detail_level=1)
330 nt.assert_in('def dirname(p)', i['source'])
287 nt.assert_in('def dirname(p)', i['source'])
331
288
332 i = inspector.info(A.adder, detail_level=1)
289 i = inspector.info(A.adder, detail_level=1)
333 nt.assert_in('def simple_add(a, b)', i['source'])
290 nt.assert_in('def simple_add(a, b)', i['source'])
334
291
335
292
336 def test_property_docstring_is_in_info_for_detail_level_0():
293 def test_property_docstring_is_in_info_for_detail_level_0():
337 class A(object):
294 class A(object):
338 @property
295 @property
339 def foobar(self):
296 def foobar(self):
340 """This is `foobar` property."""
297 """This is `foobar` property."""
341 pass
298 pass
342
299
343 ip.user_ns['a_obj'] = A()
300 ip.user_ns['a_obj'] = A()
344 nt.assert_equal(
301 nt.assert_equal(
345 'This is `foobar` property.',
302 'This is `foobar` property.',
346 ip.object_inspect('a_obj.foobar', detail_level=0)['docstring'])
303 ip.object_inspect('a_obj.foobar', detail_level=0)['docstring'])
347
304
348 ip.user_ns['a_cls'] = A
305 ip.user_ns['a_cls'] = A
349 nt.assert_equal(
306 nt.assert_equal(
350 'This is `foobar` property.',
307 'This is `foobar` property.',
351 ip.object_inspect('a_cls.foobar', detail_level=0)['docstring'])
308 ip.object_inspect('a_cls.foobar', detail_level=0)['docstring'])
352
309
353
310
354 def test_pdef():
311 def test_pdef():
355 # See gh-1914
312 # See gh-1914
356 def foo(): pass
313 def foo(): pass
357 inspector.pdef(foo, 'foo')
314 inspector.pdef(foo, 'foo')
358
315
359
316
360 def test_pinfo_nonascii():
317 def test_pinfo_nonascii():
361 # See gh-1177
318 # See gh-1177
362 from . import nonascii2
319 from . import nonascii2
363 ip.user_ns['nonascii2'] = nonascii2
320 ip.user_ns['nonascii2'] = nonascii2
364 ip._inspect('pinfo', 'nonascii2', detail_level=1)
321 ip._inspect('pinfo', 'nonascii2', detail_level=1)
365
322
366 def test_pinfo_type():
323 def test_pinfo_type():
367 """
324 """
368 type can fail in various edge case, for example `type.__subclass__()`
325 type can fail in various edge case, for example `type.__subclass__()`
369 """
326 """
370 ip._inspect('pinfo', 'type')
327 ip._inspect('pinfo', 'type')
371
328
372
329
373 def test_pinfo_docstring_no_source():
330 def test_pinfo_docstring_no_source():
374 """Docstring should be included with detail_level=1 if there is no source"""
331 """Docstring should be included with detail_level=1 if there is no source"""
375 with AssertPrints('Docstring:'):
332 with AssertPrints('Docstring:'):
376 ip._inspect('pinfo', 'str.format', detail_level=0)
333 ip._inspect('pinfo', 'str.format', detail_level=0)
377 with AssertPrints('Docstring:'):
334 with AssertPrints('Docstring:'):
378 ip._inspect('pinfo', 'str.format', detail_level=1)
335 ip._inspect('pinfo', 'str.format', detail_level=1)
379
336
380
337
381 def test_pinfo_no_docstring_if_source():
338 def test_pinfo_no_docstring_if_source():
382 """Docstring should not be included with detail_level=1 if source is found"""
339 """Docstring should not be included with detail_level=1 if source is found"""
383 def foo():
340 def foo():
384 """foo has a docstring"""
341 """foo has a docstring"""
385
342
386 ip.user_ns['foo'] = foo
343 ip.user_ns['foo'] = foo
387
344
388 with AssertPrints('Docstring:'):
345 with AssertPrints('Docstring:'):
389 ip._inspect('pinfo', 'foo', detail_level=0)
346 ip._inspect('pinfo', 'foo', detail_level=0)
390 with AssertPrints('Source:'):
347 with AssertPrints('Source:'):
391 ip._inspect('pinfo', 'foo', detail_level=1)
348 ip._inspect('pinfo', 'foo', detail_level=1)
392 with AssertNotPrints('Docstring:'):
349 with AssertNotPrints('Docstring:'):
393 ip._inspect('pinfo', 'foo', detail_level=1)
350 ip._inspect('pinfo', 'foo', detail_level=1)
394
351
395
352
396 def test_pinfo_docstring_if_detail_and_no_source():
353 def test_pinfo_docstring_if_detail_and_no_source():
397 """ Docstring should be displayed if source info not available """
354 """ Docstring should be displayed if source info not available """
398 obj_def = '''class Foo(object):
355 obj_def = '''class Foo(object):
399 """ This is a docstring for Foo """
356 """ This is a docstring for Foo """
400 def bar(self):
357 def bar(self):
401 """ This is a docstring for Foo.bar """
358 """ This is a docstring for Foo.bar """
402 pass
359 pass
403 '''
360 '''
404
361
405 ip.run_cell(obj_def)
362 ip.run_cell(obj_def)
406 ip.run_cell('foo = Foo()')
363 ip.run_cell('foo = Foo()')
407
364
408 with AssertNotPrints("Source:"):
365 with AssertNotPrints("Source:"):
409 with AssertPrints('Docstring:'):
366 with AssertPrints('Docstring:'):
410 ip._inspect('pinfo', 'foo', detail_level=0)
367 ip._inspect('pinfo', 'foo', detail_level=0)
411 with AssertPrints('Docstring:'):
368 with AssertPrints('Docstring:'):
412 ip._inspect('pinfo', 'foo', detail_level=1)
369 ip._inspect('pinfo', 'foo', detail_level=1)
413 with AssertPrints('Docstring:'):
370 with AssertPrints('Docstring:'):
414 ip._inspect('pinfo', 'foo.bar', detail_level=0)
371 ip._inspect('pinfo', 'foo.bar', detail_level=0)
415
372
416 with AssertNotPrints('Docstring:'):
373 with AssertNotPrints('Docstring:'):
417 with AssertPrints('Source:'):
374 with AssertPrints('Source:'):
418 ip._inspect('pinfo', 'foo.bar', detail_level=1)
375 ip._inspect('pinfo', 'foo.bar', detail_level=1)
419
376
420
377
421 def test_pinfo_magic():
378 def test_pinfo_magic():
422 with AssertPrints('Docstring:'):
379 with AssertPrints('Docstring:'):
423 ip._inspect('pinfo', 'lsmagic', detail_level=0)
380 ip._inspect('pinfo', 'lsmagic', detail_level=0)
424
381
425 with AssertPrints('Source:'):
382 with AssertPrints('Source:'):
426 ip._inspect('pinfo', 'lsmagic', detail_level=1)
383 ip._inspect('pinfo', 'lsmagic', detail_level=1)
427
384
428
385
429 def test_init_colors():
386 def test_init_colors():
430 # ensure colors are not present in signature info
387 # ensure colors are not present in signature info
431 info = inspector.info(HasSignature)
388 info = inspector.info(HasSignature)
432 init_def = info['init_definition']
389 init_def = info['init_definition']
433 nt.assert_not_in('[0m', init_def)
390 nt.assert_not_in('[0m', init_def)
434
391
435
392
436 def test_builtin_init():
393 def test_builtin_init():
437 info = inspector.info(list)
394 info = inspector.info(list)
438 init_def = info['init_definition']
395 init_def = info['init_definition']
439 nt.assert_is_not_none(init_def)
396 nt.assert_is_not_none(init_def)
440
397
441
398
442 def test_render_signature_short():
399 def test_render_signature_short():
443 def short_fun(a=1): pass
400 def short_fun(a=1): pass
444 sig = oinspect._render_signature(
401 sig = oinspect._render_signature(
445 signature(short_fun),
402 signature(short_fun),
446 short_fun.__name__,
403 short_fun.__name__,
447 )
404 )
448 nt.assert_equal(sig, 'short_fun(a=1)')
405 nt.assert_equal(sig, 'short_fun(a=1)')
449
406
450
407
451 def test_render_signature_long():
408 def test_render_signature_long():
452 from typing import Optional
409 from typing import Optional
453
410
454 def long_function(
411 def long_function(
455 a_really_long_parameter: int,
412 a_really_long_parameter: int,
456 and_another_long_one: bool = False,
413 and_another_long_one: bool = False,
457 let_us_make_sure_this_is_looong: Optional[str] = None,
414 let_us_make_sure_this_is_looong: Optional[str] = None,
458 ) -> bool: pass
415 ) -> bool: pass
459
416
460 sig = oinspect._render_signature(
417 sig = oinspect._render_signature(
461 signature(long_function),
418 signature(long_function),
462 long_function.__name__,
419 long_function.__name__,
463 )
420 )
464 nt.assert_in(sig, [
421 nt.assert_in(sig, [
465 # Python >=3.7
422 # Python >=3.7
466 '''\
423 '''\
467 long_function(
424 long_function(
468 a_really_long_parameter: int,
425 a_really_long_parameter: int,
469 and_another_long_one: bool = False,
426 and_another_long_one: bool = False,
470 let_us_make_sure_this_is_looong: Union[str, NoneType] = None,
427 let_us_make_sure_this_is_looong: Union[str, NoneType] = None,
471 ) -> bool\
428 ) -> bool\
472 ''', # Python <=3.6
429 ''', # Python <=3.6
473 '''\
430 '''\
474 long_function(
431 long_function(
475 a_really_long_parameter:int,
432 a_really_long_parameter:int,
476 and_another_long_one:bool=False,
433 and_another_long_one:bool=False,
477 let_us_make_sure_this_is_looong:Union[str, NoneType]=None,
434 let_us_make_sure_this_is_looong:Union[str, NoneType]=None,
478 ) -> bool\
435 ) -> bool\
479 ''',
436 ''',
480 ])
437 ])
General Comments 0
You need to be logged in to leave comments. Login now