diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 70a64c3..9e52f1e 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -182,11 +182,12 @@ def getsource(obj, oname='') -> Union[str,None]: except TypeError: # The object itself provided no meaningful source, try looking for # its class definition instead. - if hasattr(obj, '__class__'): - try: - src = inspect.getsource(obj.__class__) - except TypeError: - return None + try: + src = inspect.getsource(obj.__class__) + except (OSError, TypeError): + return None + except OSError: + return None return src @@ -308,17 +309,17 @@ def find_file(obj) -> str: fname = None try: fname = inspect.getabsfile(obj) - except (OSError, TypeError): + except TypeError: # For an instance, the file that matters is where its class was # declared. - if hasattr(obj, '__class__'): - try: - fname = inspect.getabsfile(obj.__class__) - except (OSError, TypeError): - # Can happen for builtins - pass - except: + try: + fname = inspect.getabsfile(obj.__class__) + except (OSError, TypeError): + # Can happen for builtins + pass + except OSError: pass + return cast_unicode(fname) @@ -341,15 +342,14 @@ def find_source_lines(obj): obj = _get_wrapped(obj) try: + lineno = inspect.getsourcelines(obj)[1] + except TypeError: + # For instances, try the class object like getsource() does try: - lineno = inspect.getsourcelines(obj)[1] - except TypeError: - # For instances, try the class object like getsource() does - if hasattr(obj, '__class__'): - lineno = inspect.getsourcelines(obj.__class__)[1] - else: - lineno = None - except: + lineno = inspect.getsourcelines(obj.__class__)[1] + except (OSError, TypeError): + return None + except OSError: return None return lineno diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index 58d07db..94deb35 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -6,8 +6,11 @@ from inspect import signature, Signature, Parameter +import inspect import os +import pytest import re +import sys from .. import oinspect @@ -28,6 +31,10 @@ def setup_module(): inspector = oinspect.Inspector() +class SourceModuleMainTest: + __module__ = "__main__" + + #----------------------------------------------------------------------------- # Local utilities #----------------------------------------------------------------------------- @@ -36,15 +43,28 @@ def setup_module(): # defined, if any code is inserted above, the following line will need to be # updated. Do NOT insert any whitespace between the next line and the function # definition below. -THIS_LINE_NUMBER = 39 # Put here the actual number of this line +THIS_LINE_NUMBER = 46 # Put here the actual number of this line + + +def test_find_source_lines(): + assert oinspect.find_source_lines(test_find_source_lines) == THIS_LINE_NUMBER + 3 + assert oinspect.find_source_lines(type) is None + assert oinspect.find_source_lines(SourceModuleMainTest) is None + assert oinspect.find_source_lines(SourceModuleMainTest()) is None + -from unittest import TestCase +def test_getsource(): + assert oinspect.getsource(type) is None + assert oinspect.getsource(SourceModuleMainTest) is None + assert oinspect.getsource(SourceModuleMainTest()) is None -class Test(TestCase): - def test_find_source_lines(self): - self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines), - THIS_LINE_NUMBER+6) +def test_inspect_getfile_raises_exception(): + """Check oinspect.find_file/getsource/find_source_lines expectations""" + with pytest.raises(TypeError): + inspect.getfile(type) + with pytest.raises(OSError if sys.version_info >= (3, 10) else TypeError): + inspect.getfile(SourceModuleMainTest) # A couple of utilities to ensure these tests work the same from a source or a @@ -59,6 +79,9 @@ def match_pyfiles(f1, f2): def test_find_file(): match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__)) + assert oinspect.find_file(type) is None + assert oinspect.find_file(SourceModuleMainTest) is None + assert oinspect.find_file(SourceModuleMainTest()) is None def test_find_file_decorated1():