Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting the source of an object defined in an iPython session. #11249

Open
spott opened this issue Jul 31, 2018 · 4 comments
Open

Getting the source of an object defined in an iPython session. #11249

spott opened this issue Jul 31, 2018 · 4 comments

Comments

@spott
Copy link

spott commented Jul 31, 2018

Usually, if you want to get the source of an object, you can get it via the inspect module:

import inspect
inspect.getsource(MyObject)

However, in a Jupyter notebook / ipython console, this doesn't work:

import inspect

class Foo:
    def __init__(self, info):
        self.info = info

inspect.getsource(Foo)

Throws a TypeError: TypeError: <module '__main__'> is a built-in class. This appears to be because __file__ isn't defined in ipython sessions.

Is there a way to inspect an object to get its source in a Jupyter notebook? The only way that comes to mind is something like get_ipython and then walking the history until you find the class definition you want. Is there another way?

This appears to be related to #29, but that was closed, so maybe I'm missing something.

@HackBrettHB
Copy link

HackBrettHB commented Jan 30, 2021

Is there a solution or workaround to this by now?

@diego898
Copy link

diego898 commented Jul 7, 2022

Want to refresh this issue

@adivekar-utexas
Copy link

Folks, it's been four years...any workaround/potential to fix this?

@s-m-e
Copy link

s-m-e commented May 29, 2023

The root problem is inspect.getfile, if I understand it correctly.

Digging around, I found this gem on Stackoverflow - ping @theevann:

import inspect, sys

def new_getfile(object, _old_getfile=inspect.getfile):
    if not inspect.isclass(object):
        return _old_getfile(object)
    
    # Lookup by parent module (as in current inspect)
    if hasattr(object, '__module__'):
        object_ = sys.modules.get(object.__module__)
        if hasattr(object_, '__file__'):
            return object_.__file__
    
    # If parent module is __main__, lookup by methods (NEW)
    for name, member in inspect.getmembers(object):
        if inspect.isfunction(member) and object.__qualname__ + '.' + member.__name__ == member.__qualname__:
            return inspect.getfile(member)
    else:
        raise TypeError('Source for {!r} not found'.format(object))

inspect.getfile = new_getfile

... which allows to retrieve the code of MyClass defined in some cell as follows:

import inspect
from IPython.core.magics.code import extract_symbols

obj = MyClass
cell_code = "".join(inspect.linecache.getlines(new_getfile(obj)))
class_code = extract_symbols(cell_code, obj.__name__)[0][0]
print(class_code)

Bottom line: This proves that it can be done (though it should probably be done better). It would be nice if IPython had similar functionalities for notebooks / sessions as inspect has for regular Python modules.

The lack of an API like this breaks tools like typeguard, among other, see e.g. here.

The CPython project considers this an issue in IPython and refused a change in its standard library - probably correctly, because source code retrieval really depends on (moving) implementation details in IPython.

mrchtr pushed a commit to ml6team/fondant that referenced this issue Feb 5, 2024
When running the lightweight components in a notebook, the component
class code inspection fails with error `source code is not available`.
Full error log here
[log.txt](https://github.com/ml6team/fondant/files/14114022/new.3.txt)

The error is related to the fact that `inspect` relies on the class
located in a source file which is not the case in a notebook where
everything runs interactively. This is described in details
[here](https://stackoverflow.com/questions/35854373/python-get-source-code-of-class-using-inspect#:~:text=getsource%20works%20by%20actually%20opening%20the%20source%20file%20that%20defines%20the%20object%20you%27re%20looking%20at.)

Implemented the workaround suggested
[here](ipython/ipython#11249)

---------

Co-authored-by: Robbe Sneyders <robbe.sneyders@ml6.eu>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants