Skip to content

Breaking change in Python 3.10rc1 #13079

@frenzymadness

Description

@frenzymadness

Hello.

There seems to be one more incompatibility in Python 3.10rc1. The problem is in this function:

def find_file(obj) -> str:
"""Find the absolute path to the file where an object was defined.
This is essentially a robust wrapper around `inspect.getabsfile`.
Returns None if no file can be found.
Parameters
----------
obj : any Python object
Returns
-------
fname : str
The absolute path to the file where the object was defined.
"""
obj = _get_wrapped(obj)
fname = None
try:
fname = inspect.getabsfile(obj)
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 TypeError:
# Can happen for builtins
pass
except:
pass
return cast_unicode(fname)

The call of inspect.getabsfile(obj.__class__) on line 313 raises an OSError instead of the expected TypeError. The change in the CPython is here: https://github.com/python/cpython/pull/27495/files

Small reproducer derived from test_debugger.test_ipdb_magics is:

Python 3.10.0rc1 (default, Aug  3 2021, 00:00:00) [GCC 11.2.1 20210728 (Red Hat 11.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from IPython.core import debugger
>>> class ExampleClass(object):
...     """Docstring for ExampleClass."""
...     def __init__(self):
...         """Docstring for ExampleClass.__init__"""
...         pass
...     def __str__(self):
...         return "ExampleClass()"
... 
>>> a = ExampleClass()
>>> debugger.Pdb().set_trace()
--Return--
None
> <stdin>(1)<module>()

ipdb> pinfo a
Traceback (most recent call last):
  File "/home/lbalhar/Software/ipython/IPython/core/oinspect.py", line 307, in find_file
    fname = inspect.getabsfile(obj)
  File "/usr/lib64/python3.10/inspect.py", line 844, in getabsfile
    _filename = getsourcefile(object) or getfile(object)
  File "/usr/lib64/python3.10/inspect.py", line 817, in getsourcefile
    filename = getfile(object)
  File "/usr/lib64/python3.10/inspect.py", line 797, in getfile
    raise TypeError('module, class, method, function, traceback, frame, or '
TypeError: module, class, method, function, traceback, frame, or code object was expected, got ExampleClass

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.10/bdb.py", line 94, in trace_dispatch
    return self.dispatch_return(frame, arg)
  File "/usr/lib64/python3.10/bdb.py", line 153, in dispatch_return
    self.user_return(frame, arg)
  File "/usr/lib64/python3.10/pdb.py", line 294, in user_return
    self.interaction(frame, None)
  File "/home/lbalhar/Software/ipython/IPython/core/debugger.py", line 356, in interaction
    OldPdb.interaction(self, frame, traceback)
  File "/usr/lib64/python3.10/pdb.py", line 357, in interaction
    self._cmdloop()
  File "/usr/lib64/python3.10/pdb.py", line 322, in _cmdloop
    self.cmdloop()
  File "/usr/lib64/python3.10/cmd.py", line 138, in cmdloop
    stop = self.onecmd(line)
  File "/usr/lib64/python3.10/pdb.py", line 422, in onecmd
    return cmd.Cmd.onecmd(self, line)
  File "/usr/lib64/python3.10/cmd.py", line 217, in onecmd
    return func(arg)
  File "/home/lbalhar/Software/ipython/IPython/core/debugger.py", line 778, in do_pinfo
    self.shell.find_line_magic("pinfo")(arg, namespaces=namespaces)
  File "/home/lbalhar/.virtualenvs/ipython/lib/python3.10/site-packages/decorator.py", line 232, in fun
    return caller(func, *(extras + args), **kw)
  File "/home/lbalhar/Software/ipython/IPython/core/magic.py", line 187, in <lambda>
    call = lambda f, *a, **k: f(*a, **k)
  File "/home/lbalhar/Software/ipython/IPython/core/magics/namespace.py", line 58, in pinfo
    self.shell._inspect('pinfo', oname, detail_level=detail_level,
  File "/home/lbalhar/Software/ipython/IPython/core/interactiveshell.py", line 1779, in _inspect
    pmethod(
  File "/home/lbalhar/Software/ipython/IPython/core/oinspect.py", line 680, in pinfo
    info = self._get_info(obj, oname, formatter, info, detail_level)
  File "/home/lbalhar/Software/ipython/IPython/core/oinspect.py", line 586, in _get_info
    info = self._info(obj, oname=oname, info=info, detail_level=detail_level)
  File "/home/lbalhar/Software/ipython/IPython/core/oinspect.py", line 785, in _info
    fname = find_file(obj)
  File "/home/lbalhar/Software/ipython/IPython/core/oinspect.py", line 313, in find_file
    fname = inspect.getabsfile(obj.__class__)
  File "/usr/lib64/python3.10/inspect.py", line 844, in getabsfile
    _filename = getsourcefile(object) or getfile(object)
  File "/usr/lib64/python3.10/inspect.py", line 817, in getsourcefile
    filename = getfile(object)
  File "/usr/lib64/python3.10/inspect.py", line 785, in getfile
    raise OSError('source code not available')
OSError: source code not available

I can confirm that the reproducer does not raise the error with Python 3.10b4. An easy fix might be to expect also OSError from the mentioned function. This workaround seems to work for me so I'm gonna open a PR with it.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions