##// END OF EJS Templates
Merge pull request #13412 from bnavigator/backport-inspect...
Matthias Bussonnier -
r27352:7f253dcf merge
parent child Browse files
Show More
@@ -15,7 +15,7 b' jobs:'
15 strategy:
15 strategy:
16 matrix:
16 matrix:
17 os: [ubuntu-latest]
17 os: [ubuntu-latest]
18 python-version: ["3.7", "3.8", "3.9"]
18 python-version: ["3.7", "3.8", "3.9", "3.10"]
19 # Test all on ubuntu, test ends on macos
19 # Test all on ubuntu, test ends on macos
20 include:
20 include:
21 - os: macos-latest
21 - os: macos-latest
@@ -39,6 +39,7 b' jobs:'
39 - name: Check manifest
39 - name: Check manifest
40 run: check-manifest
40 run: check-manifest
41 - name: iptest
41 - name: iptest
42 if: matrix.python-version != '3.10'
42 run: |
43 run: |
43 cd /tmp && iptest --coverage xml && cd -
44 cd /tmp && iptest --coverage xml && cd -
44 cp /tmp/ipy_coverage.xml ./
45 cp /tmp/ipy_coverage.xml ./
@@ -182,11 +182,12 b" def getsource(obj, oname='') -> Union[str,None]:"
182 except TypeError:
182 except TypeError:
183 # The object itself provided no meaningful source, try looking for
183 # The object itself provided no meaningful source, try looking for
184 # its class definition instead.
184 # its class definition instead.
185 if hasattr(obj, '__class__'):
185 try:
186 try:
186 src = inspect.getsource(obj.__class__)
187 src = inspect.getsource(obj.__class__)
187 except (OSError, TypeError):
188 except TypeError:
188 return None
189 return None
189 except OSError:
190 return None
190
191
191 return src
192 return src
192
193
@@ -308,14 +309,14 b' def find_file(obj) -> str:'
308 except TypeError:
309 except TypeError:
309 # For an instance, the file that matters is where its class was
310 # For an instance, the file that matters is where its class was
310 # declared.
311 # declared.
311 if hasattr(obj, '__class__'):
312 try:
312 try:
313 fname = inspect.getabsfile(obj.__class__)
313 fname = inspect.getabsfile(obj.__class__)
314 except (OSError, TypeError):
314 except TypeError:
315 # Can happen for builtins
315 # Can happen for builtins
316 pass
316 pass
317 except OSError:
317 except:
318 pass
318 pass
319
319 return cast_unicode(fname)
320 return cast_unicode(fname)
320
321
321
322
@@ -338,15 +339,14 b' def find_source_lines(obj):'
338 obj = _get_wrapped(obj)
339 obj = _get_wrapped(obj)
339
340
340 try:
341 try:
342 lineno = inspect.getsourcelines(obj)[1]
343 except TypeError:
344 # For instances, try the class object like getsource() does
341 try:
345 try:
342 lineno = inspect.getsourcelines(obj)[1]
346 lineno = inspect.getsourcelines(obj.__class__)[1]
343 except TypeError:
347 except (OSError, TypeError):
344 # For instances, try the class object like getsource() does
348 return None
345 if hasattr(obj, '__class__'):
349 except OSError:
346 lineno = inspect.getsourcelines(obj.__class__)[1]
347 else:
348 lineno = None
349 except:
350 return None
350 return None
351
351
352 return lineno
352 return lineno
@@ -12,6 +12,7 b' import unittest'
12 from contextlib import contextmanager
12 from contextlib import contextmanager
13
13
14 import nose.tools as nt
14 import nose.tools as nt
15 import pytest
15
16
16 from traitlets.config.loader import Config
17 from traitlets.config.loader import Config
17 from IPython import get_ipython
18 from IPython import get_ipython
@@ -29,6 +30,15 b' from IPython.core.completer import ('
29 )
30 )
30 from nose.tools import assert_in, assert_not_in
31 from nose.tools import assert_in, assert_not_in
31
32
33 if sys.version_info >= (3, 10):
34 import jedi
35 from pkg_resources import parse_version
36
37 # Requires https://github.com/davidhalter/jedi/pull/1795
38 jedi_issue = parse_version(jedi.__version__) <= parse_version("0.18.0")
39 else:
40 jedi_issue = False
41
32 # -----------------------------------------------------------------------------
42 # -----------------------------------------------------------------------------
33 # Test functions
43 # Test functions
34 # -----------------------------------------------------------------------------
44 # -----------------------------------------------------------------------------
@@ -381,6 +391,8 b' class TestCompleter(unittest.TestCase):'
381 matches = c.all_completions("TestCl")
391 matches = c.all_completions("TestCl")
382 assert matches == ['TestClass'], jedi_status
392 assert matches == ['TestClass'], jedi_status
383 matches = c.all_completions("TestClass.")
393 matches = c.all_completions("TestClass.")
394 if jedi_status and jedi_issue:
395 continue
384 assert len(matches) > 2, jedi_status
396 assert len(matches) > 2, jedi_status
385 matches = c.all_completions("TestClass.a")
397 matches = c.all_completions("TestClass.a")
386 assert matches == ['TestClass.a', 'TestClass.a1'], jedi_status
398 assert matches == ['TestClass.a', 'TestClass.a1'], jedi_status
@@ -435,6 +447,7 b' class TestCompleter(unittest.TestCase):'
435 "encoding" in c.signature
447 "encoding" in c.signature
436 ), "Signature of function was not found by completer"
448 ), "Signature of function was not found by completer"
437
449
450 @pytest.mark.xfail(jedi_issue, reason="Known failure on jedi<=0.18.0")
438 def test_deduplicate_completions(self):
451 def test_deduplicate_completions(self):
439 """
452 """
440 Test that completions are correctly deduplicated (even if ranges are not the same)
453 Test that completions are correctly deduplicated (even if ranges are not the same)
@@ -7,6 +7,7 b''
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 import argparse
9 import argparse
10 import sys
10 from nose.tools import assert_equal
11 from nose.tools import assert_equal
11
12
12 from IPython.core.magic_arguments import (argument, argument_group, kwds,
13 from IPython.core.magic_arguments import (argument, argument_group, kwds,
@@ -74,7 +75,12 b' def foo(self, args):'
74
75
75
76
76 def test_magic_arguments():
77 def test_magic_arguments():
77 assert_equal(magic_foo1.__doc__, '::\n\n %foo1 [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
78 # “optional arguments” was replaced with “options” in argparse help
79 # https://docs.python.org/3/whatsnew/3.10.html#argparse
80 # https://bugs.python.org/issue9694
81 options = "optional arguments" if sys.version_info < (3, 10) else "options"
82
83 assert_equal(magic_foo1.__doc__, f"::\n\n %foo1 [-f FOO]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n")
78 assert_equal(getattr(magic_foo1, 'argcmd_name', None), None)
84 assert_equal(getattr(magic_foo1, 'argcmd_name', None), None)
79 assert_equal(real_name(magic_foo1), 'foo1')
85 assert_equal(real_name(magic_foo1), 'foo1')
80 assert_equal(magic_foo1(None, ''), argparse.Namespace(foo=None))
86 assert_equal(magic_foo1(None, ''), argparse.Namespace(foo=None))
@@ -86,32 +92,32 b' def test_magic_arguments():'
86 assert_equal(magic_foo2(None, ''), argparse.Namespace())
92 assert_equal(magic_foo2(None, ''), argparse.Namespace())
87 assert hasattr(magic_foo2, 'has_arguments')
93 assert hasattr(magic_foo2, 'has_arguments')
88
94
89 assert_equal(magic_foo3.__doc__, '::\n\n %foo3 [-f FOO] [-b BAR] [-z BAZ]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n\nGroup:\n -b BAR, --bar BAR a grouped argument\n\nSecond Group:\n -z BAZ, --baz BAZ another grouped argument\n')
95 assert_equal(magic_foo3.__doc__, f"::\n\n %foo3 [-f FOO] [-b BAR] [-z BAZ]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n\nGroup:\n -b BAR, --bar BAR a grouped argument\n\nSecond Group:\n -z BAZ, --baz BAZ another grouped argument\n")
90 assert_equal(getattr(magic_foo3, 'argcmd_name', None), None)
96 assert_equal(getattr(magic_foo3, 'argcmd_name', None), None)
91 assert_equal(real_name(magic_foo3), 'foo3')
97 assert_equal(real_name(magic_foo3), 'foo3')
92 assert_equal(magic_foo3(None, ''),
98 assert_equal(magic_foo3(None, ''),
93 argparse.Namespace(bar=None, baz=None, foo=None))
99 argparse.Namespace(bar=None, baz=None, foo=None))
94 assert hasattr(magic_foo3, 'has_arguments')
100 assert hasattr(magic_foo3, 'has_arguments')
95
101
96 assert_equal(magic_foo4.__doc__, '::\n\n %foo4 [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
102 assert_equal(magic_foo4.__doc__, f"::\n\n %foo4 [-f FOO]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n")
97 assert_equal(getattr(magic_foo4, 'argcmd_name', None), None)
103 assert_equal(getattr(magic_foo4, 'argcmd_name', None), None)
98 assert_equal(real_name(magic_foo4), 'foo4')
104 assert_equal(real_name(magic_foo4), 'foo4')
99 assert_equal(magic_foo4(None, ''), argparse.Namespace())
105 assert_equal(magic_foo4(None, ''), argparse.Namespace())
100 assert hasattr(magic_foo4, 'has_arguments')
106 assert hasattr(magic_foo4, 'has_arguments')
101
107
102 assert_equal(magic_foo5.__doc__, '::\n\n %frobnicate [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
108 assert_equal(magic_foo5.__doc__, f"::\n\n %frobnicate [-f FOO]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n")
103 assert_equal(getattr(magic_foo5, 'argcmd_name', None), 'frobnicate')
109 assert_equal(getattr(magic_foo5, 'argcmd_name', None), 'frobnicate')
104 assert_equal(real_name(magic_foo5), 'frobnicate')
110 assert_equal(real_name(magic_foo5), 'frobnicate')
105 assert_equal(magic_foo5(None, ''), argparse.Namespace(foo=None))
111 assert_equal(magic_foo5(None, ''), argparse.Namespace(foo=None))
106 assert hasattr(magic_foo5, 'has_arguments')
112 assert hasattr(magic_foo5, 'has_arguments')
107
113
108 assert_equal(magic_magic_foo.__doc__, '::\n\n %magic_foo [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
114 assert_equal(magic_magic_foo.__doc__, f"::\n\n %magic_foo [-f FOO]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n")
109 assert_equal(getattr(magic_magic_foo, 'argcmd_name', None), None)
115 assert_equal(getattr(magic_magic_foo, 'argcmd_name', None), None)
110 assert_equal(real_name(magic_magic_foo), 'magic_foo')
116 assert_equal(real_name(magic_magic_foo), 'magic_foo')
111 assert_equal(magic_magic_foo(None, ''), argparse.Namespace(foo=None))
117 assert_equal(magic_magic_foo(None, ''), argparse.Namespace(foo=None))
112 assert hasattr(magic_magic_foo, 'has_arguments')
118 assert hasattr(magic_magic_foo, 'has_arguments')
113
119
114 assert_equal(foo.__doc__, '::\n\n %foo [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
120 assert_equal(foo.__doc__, f"::\n\n %foo [-f FOO]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n")
115 assert_equal(getattr(foo, 'argcmd_name', None), None)
121 assert_equal(getattr(foo, 'argcmd_name', None), None)
116 assert_equal(real_name(foo), 'foo')
122 assert_equal(real_name(foo), 'foo')
117 assert_equal(foo(None, ''), argparse.Namespace(foo=None))
123 assert_equal(foo(None, ''), argparse.Namespace(foo=None))
@@ -6,10 +6,11 b''
6
6
7
7
8 from inspect import signature, Signature, Parameter
8 from inspect import signature, Signature, Parameter
9 import inspect
9 import os
10 import os
11 import pytest
10 import re
12 import re
11
13 import sys
12 import nose.tools as nt
13
14
14 from .. import oinspect
15 from .. import oinspect
15
16
@@ -30,6 +31,10 b' def setup_module():'
30 inspector = oinspect.Inspector()
31 inspector = oinspect.Inspector()
31
32
32
33
34 class SourceModuleMainTest:
35 __module__ = "__main__"
36
37
33 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
34 # Local utilities
39 # Local utilities
35 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
@@ -38,15 +43,28 b' def setup_module():'
38 # defined, if any code is inserted above, the following line will need to be
43 # 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
44 # updated. Do NOT insert any whitespace between the next line and the function
40 # definition below.
45 # definition below.
41 THIS_LINE_NUMBER = 41 # Put here the actual number of this line
46 THIS_LINE_NUMBER = 46 # Put here the actual number of this line
47
48
49 def test_find_source_lines():
50 assert oinspect.find_source_lines(test_find_source_lines) == THIS_LINE_NUMBER + 3
51 assert oinspect.find_source_lines(type) is None
52 assert oinspect.find_source_lines(SourceModuleMainTest) is None
53 assert oinspect.find_source_lines(SourceModuleMainTest()) is None
54
42
55
43 from unittest import TestCase
56 def test_getsource():
57 assert oinspect.getsource(type) is None
58 assert oinspect.getsource(SourceModuleMainTest) is None
59 assert oinspect.getsource(SourceModuleMainTest()) is None
44
60
45 class Test(TestCase):
46
61
47 def test_find_source_lines(self):
62 def test_inspect_getfile_raises_exception():
48 self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines),
63 """Check oinspect.find_file/getsource/find_source_lines expectations"""
49 THIS_LINE_NUMBER+6)
64 with pytest.raises(TypeError):
65 inspect.getfile(type)
66 with pytest.raises(OSError if sys.version_info >= (3, 10) else TypeError):
67 inspect.getfile(SourceModuleMainTest)
50
68
51
69
52 # A couple of utilities to ensure these tests work the same from a source or a
70 # A couple of utilities to ensure these tests work the same from a source or a
@@ -56,11 +74,14 b' def pyfile(fname):'
56
74
57
75
58 def match_pyfiles(f1, f2):
76 def match_pyfiles(f1, f2):
59 nt.assert_equal(pyfile(f1), pyfile(f2))
77 assert pyfile(f1) == pyfile(f2)
60
78
61
79
62 def test_find_file():
80 def test_find_file():
63 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
81 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
82 assert oinspect.find_file(type) is None
83 assert oinspect.find_file(SourceModuleMainTest) is None
84 assert oinspect.find_file(SourceModuleMainTest()) is None
64
85
65
86
66 def test_find_file_decorated1():
87 def test_find_file_decorated1():
@@ -74,9 +95,9 b' def test_find_file_decorated1():'
74 @noop1
95 @noop1
75 def f(x):
96 def f(x):
76 "My docstring"
97 "My docstring"
77
98
78 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
99 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
79 nt.assert_equal(f.__doc__, "My docstring")
100 assert f.__doc__ == "My docstring"
80
101
81
102
82 def test_find_file_decorated2():
103 def test_find_file_decorated2():
@@ -90,14 +111,14 b' def test_find_file_decorated2():'
90 @noop2
111 @noop2
91 def f(x):
112 def f(x):
92 "My docstring 2"
113 "My docstring 2"
93
114
94 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
115 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
95 nt.assert_equal(f.__doc__, "My docstring 2")
116 assert f.__doc__ == "My docstring 2"
96
117
97
118
98 def test_find_file_magic():
119 def test_find_file_magic():
99 run = ip.find_line_magic('run')
120 run = ip.find_line_magic('run')
100 nt.assert_not_equal(oinspect.find_file(run), None)
121 assert oinspect.find_file(run) is not None
101
122
102
123
103 # A few generic objects we can then inspect in the tests below
124 # A few generic objects we can then inspect in the tests below
@@ -167,41 +188,46 b' class SerialLiar(object):'
167
188
168 def test_info():
189 def test_info():
169 "Check that Inspector.info fills out various fields as expected."
190 "Check that Inspector.info fills out various fields as expected."
170 i = inspector.info(Call, oname='Call')
191 i = inspector.info(Call, oname="Call")
171 nt.assert_equal(i['type_name'], 'type')
192 assert i["type_name"] == "type"
172 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
193 expected_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
173 nt.assert_equal(i['base_class'], expted_class)
194 assert i["base_class"] == expected_class
174 nt.assert_regex(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>")
195 assert re.search(
196 "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>",
197 i["string_form"],
198 )
175 fname = __file__
199 fname = __file__
176 if fname.endswith(".pyc"):
200 if fname.endswith(".pyc"):
177 fname = fname[:-1]
201 fname = fname[:-1]
178 # case-insensitive comparison needed on some filesystems
202 # case-insensitive comparison needed on some filesystems
179 # e.g. Windows:
203 # e.g. Windows:
180 nt.assert_equal(i['file'].lower(), compress_user(fname).lower())
204 assert i["file"].lower() == compress_user(fname).lower()
181 nt.assert_equal(i['definition'], None)
205 assert i["definition"] == None
182 nt.assert_equal(i['docstring'], Call.__doc__)
206 assert i["docstring"] == Call.__doc__
183 nt.assert_equal(i['source'], None)
207 assert i["source"] == None
184 nt.assert_true(i['isclass'])
208 assert i["isclass"] is True
185 nt.assert_equal(i['init_definition'], "Call(x, y=1)")
209 assert i["init_definition"] == "Call(x, y=1)"
186 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
210 assert i["init_docstring"] == Call.__init__.__doc__
187
211
188 i = inspector.info(Call, detail_level=1)
212 i = inspector.info(Call, detail_level=1)
189 nt.assert_not_equal(i['source'], None)
213 assert i["source"] is not None
190 nt.assert_equal(i['docstring'], None)
214 assert i["docstring"] == None
191
215
192 c = Call(1)
216 c = Call(1)
193 c.__doc__ = "Modified instance docstring"
217 c.__doc__ = "Modified instance docstring"
194 i = inspector.info(c)
218 i = inspector.info(c)
195 nt.assert_equal(i['type_name'], 'Call')
219 assert i["type_name"] == "Call"
196 nt.assert_equal(i['docstring'], "Modified instance docstring")
220 assert i["docstring"] == "Modified instance docstring"
197 nt.assert_equal(i['class_docstring'], Call.__doc__)
221 assert i["class_docstring"] == Call.__doc__
198 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
222 assert i["init_docstring"] == Call.__init__.__doc__
199 nt.assert_equal(i['call_docstring'], Call.__call__.__doc__)
223 assert i["call_docstring"] == Call.__call__.__doc__
224
200
225
201 def test_class_signature():
226 def test_class_signature():
202 info = inspector.info(HasSignature, 'HasSignature')
227 info = inspector.info(HasSignature, "HasSignature")
203 nt.assert_equal(info['init_definition'], "HasSignature(test)")
228 assert info["init_definition"] == "HasSignature(test)"
204 nt.assert_equal(info['init_docstring'], HasSignature.__init__.__doc__)
229 assert info["init_docstring"] == HasSignature.__init__.__doc__
230
205
231
206 def test_info_awkward():
232 def test_info_awkward():
207 # Just test that this doesn't throw an error.
233 # Just test that this doesn't throw an error.
@@ -216,7 +242,7 b' def test_info_serialliar():'
216
242
217 # Nested attribute access should be cut off at 100 levels deep to avoid
243 # Nested attribute access should be cut off at 100 levels deep to avoid
218 # infinite loops: https://github.com/ipython/ipython/issues/9122
244 # infinite loops: https://github.com/ipython/ipython/issues/9122
219 nt.assert_less(fib_tracker[0], 9000)
245 assert fib_tracker[0] < 9000
220
246
221 def support_function_one(x, y=2, *a, **kw):
247 def support_function_one(x, y=2, *a, **kw):
222 """A simple function."""
248 """A simple function."""
@@ -225,14 +251,16 b' def test_calldef_none():'
225 # We should ignore __call__ for all of these.
251 # We should ignore __call__ for all of these.
226 for obj in [support_function_one, SimpleClass().method, any, str.upper]:
252 for obj in [support_function_one, SimpleClass().method, any, str.upper]:
227 i = inspector.info(obj)
253 i = inspector.info(obj)
228 nt.assert_is(i['call_def'], None)
254 assert i["call_def"] is None
255
229
256
230 def f_kwarg(pos, *, kwonly):
257 def f_kwarg(pos, *, kwonly):
231 pass
258 pass
232
259
233 def test_definition_kwonlyargs():
260 def test_definition_kwonlyargs():
234 i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
261 i = inspector.info(f_kwarg, oname="f_kwarg") # analysis:ignore
235 nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)")
262 assert i["definition"] == "f_kwarg(pos, *, kwonly)"
263
236
264
237 def test_getdoc():
265 def test_getdoc():
238 class A(object):
266 class A(object):
@@ -243,34 +271,33 b' def test_getdoc():'
243 """standard docstring"""
271 """standard docstring"""
244 def getdoc(self):
272 def getdoc(self):
245 return "custom docstring"
273 return "custom docstring"
246
274
247 class C(object):
275 class C(object):
248 """standard docstring"""
276 """standard docstring"""
249 def getdoc(self):
277 def getdoc(self):
250 return None
278 return None
251
279
252 a = A()
280 a = A()
253 b = B()
281 b = B()
254 c = C()
282 c = C()
255
283
256 nt.assert_equal(oinspect.getdoc(a), "standard docstring")
284 assert oinspect.getdoc(a) == "standard docstring"
257 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
285 assert oinspect.getdoc(b) == "custom docstring"
258 nt.assert_equal(oinspect.getdoc(c), "standard docstring")
286 assert oinspect.getdoc(c) == "standard docstring"
259
287
260
288
261 def test_empty_property_has_no_source():
289 def test_empty_property_has_no_source():
262 i = inspector.info(property(), detail_level=1)
290 i = inspector.info(property(), detail_level=1)
263 nt.assert_is(i['source'], None)
291 assert i["source"] is None
264
292
265
293
266 def test_property_sources():
294 def test_property_sources():
267 import posixpath
268 # A simple adder whose source and signature stays
295 # A simple adder whose source and signature stays
269 # the same across Python distributions
296 # the same across Python distributions
270 def simple_add(a, b):
297 def simple_add(a, b):
271 "Adds two numbers"
298 "Adds two numbers"
272 return a + b
299 return a + b
273
300
274 class A(object):
301 class A(object):
275 @property
302 @property
276 def foo(self):
303 def foo(self):
@@ -278,18 +305,18 b' def test_property_sources():'
278
305
279 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
306 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
280
307
281 dname = property(posixpath.dirname)
308 dname = property(oinspect.getdoc)
282 adder = property(simple_add)
309 adder = property(simple_add)
283
310
284 i = inspector.info(A.foo, detail_level=1)
311 i = inspector.info(A.foo, detail_level=1)
285 nt.assert_in('def foo(self):', i['source'])
312 assert "def foo(self):" in i["source"]
286 nt.assert_in('lambda self, v:', i['source'])
313 assert "lambda self, v:" in i["source"]
287
314
288 i = inspector.info(A.dname, detail_level=1)
315 i = inspector.info(A.dname, detail_level=1)
289 nt.assert_in('def dirname(p)', i['source'])
316 assert "def getdoc(obj)" in i["source"]
290
317
291 i = inspector.info(A.adder, detail_level=1)
318 i = inspector.info(A.adder, detail_level=1)
292 nt.assert_in('def simple_add(a, b)', i['source'])
319 assert "def simple_add(a, b)" in i["source"]
293
320
294
321
295 def test_property_docstring_is_in_info_for_detail_level_0():
322 def test_property_docstring_is_in_info_for_detail_level_0():
@@ -299,15 +326,17 b' def test_property_docstring_is_in_info_for_detail_level_0():'
299 """This is `foobar` property."""
326 """This is `foobar` property."""
300 pass
327 pass
301
328
302 ip.user_ns['a_obj'] = A()
329 ip.user_ns["a_obj"] = A()
303 nt.assert_equal(
330 assert (
304 'This is `foobar` property.',
331 "This is `foobar` property."
305 ip.object_inspect('a_obj.foobar', detail_level=0)['docstring'])
332 == ip.object_inspect("a_obj.foobar", detail_level=0)["docstring"]
333 )
306
334
307 ip.user_ns['a_cls'] = A
335 ip.user_ns["a_cls"] = A
308 nt.assert_equal(
336 assert (
309 'This is `foobar` property.',
337 "This is `foobar` property."
310 ip.object_inspect('a_cls.foobar', detail_level=0)['docstring'])
338 == ip.object_inspect("a_cls.foobar", detail_level=0)["docstring"]
339 )
311
340
312
341
313 def test_pdef():
342 def test_pdef():
@@ -359,11 +388,11 b' def test_pinfo_docstring_if_detail_and_no_source():'
359 def bar(self):
388 def bar(self):
360 """ This is a docstring for Foo.bar """
389 """ This is a docstring for Foo.bar """
361 pass
390 pass
362 '''
391 '''
363
392
364 ip.run_cell(obj_def)
393 ip.run_cell(obj_def)
365 ip.run_cell('foo = Foo()')
394 ip.run_cell('foo = Foo()')
366
395
367 with AssertNotPrints("Source:"):
396 with AssertNotPrints("Source:"):
368 with AssertPrints('Docstring:'):
397 with AssertPrints('Docstring:'):
369 ip._inspect('pinfo', 'foo', detail_level=0)
398 ip._inspect('pinfo', 'foo', detail_level=0)
@@ -388,14 +417,14 b' def test_pinfo_magic():'
388 def test_init_colors():
417 def test_init_colors():
389 # ensure colors are not present in signature info
418 # ensure colors are not present in signature info
390 info = inspector.info(HasSignature)
419 info = inspector.info(HasSignature)
391 init_def = info['init_definition']
420 init_def = info["init_definition"]
392 nt.assert_not_in('[0m', init_def)
421 assert "[0m" not in init_def
393
422
394
423
395 def test_builtin_init():
424 def test_builtin_init():
396 info = inspector.info(list)
425 info = inspector.info(list)
397 init_def = info['init_definition']
426 init_def = info['init_definition']
398 nt.assert_is_not_none(init_def)
427 assert init_def is not None
399
428
400
429
401 def test_render_signature_short():
430 def test_render_signature_short():
@@ -404,7 +433,7 b' def test_render_signature_short():'
404 signature(short_fun),
433 signature(short_fun),
405 short_fun.__name__,
434 short_fun.__name__,
406 )
435 )
407 nt.assert_equal(sig, 'short_fun(a=1)')
436 assert sig == "short_fun(a=1)"
408
437
409
438
410 def test_render_signature_long():
439 def test_render_signature_long():
@@ -420,7 +449,7 b' def test_render_signature_long():'
420 signature(long_function),
449 signature(long_function),
421 long_function.__name__,
450 long_function.__name__,
422 )
451 )
423 nt.assert_in(sig, [
452 assert sig in [
424 # Python >=3.9
453 # Python >=3.9
425 '''\
454 '''\
426 long_function(
455 long_function(
@@ -444,4 +473,4 b' long_function('
444 let_us_make_sure_this_is_looong:Union[str, NoneType]=None,
473 let_us_make_sure_this_is_looong:Union[str, NoneType]=None,
445 ) -> bool\
474 ) -> bool\
446 ''',
475 ''',
447 ])
476 ] No newline at end of file
@@ -9,6 +9,7 b' 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 sys
12 import unittest
13 import unittest
13
14
14 import nose.tools as nt
15 import nose.tools as nt
@@ -118,12 +119,15 b' def test_sets():'
118 yield nt.assert_equal, got_output, expected_output
119 yield nt.assert_equal, got_output, expected_output
119
120
120
121
121 @skip_without('xxlimited')
122 @skip_without("xxlimited" if sys.version_info < (3, 10) else "xxlimited_35")
122 def test_pprint_heap_allocated_type():
123 def test_pprint_heap_allocated_type():
123 """
124 """
124 Test that pprint works for heap allocated types.
125 Test that pprint works for heap allocated types.
125 """
126 """
126 import xxlimited
127 if sys.version_info < (3, 10):
128 import xxlimited
129 else:
130 import xxlimited_35 as xxlimited
127 output = pretty.pretty(xxlimited.Null)
131 output = pretty.pretty(xxlimited.Null)
128 nt.assert_equal(output, 'xxlimited.Null')
132 nt.assert_equal(output, 'xxlimited.Null')
129
133
General Comments 0
You need to be logged in to leave comments. Login now