classification
Title: inspect.getsource only works for objects loaded from files, not interactive session
Type: behavior Stage: needs patch
Components: IDLE, Interpreter Core Versions: Python 3.6, Python 3.5, Python 3.4, Python 2.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: Claudiu.Popa, Naddiseo, Steven.Barker, eric.araujo, ned.deily, nikitakit, r.david.murray, vmsp, zorceta
Priority: normal Keywords:

Created on 2011-09-06 18:37 by Claudiu.Popa, last changed 2017-07-06 04:04 by r.david.murray.

Messages (12)
msg143645 - (view) Author: Claudiu Popa (Claudiu.Popa) * (Python triager) Date: 2011-09-06 18:37
inspect.getsource called with a class defined in the same file fails with
TypeError: <module '__main__' (built-in)> is a built-in class, although the documentation says that:

"The argument may be a module, class, method, function, traceback, frame,
or code object.  The source code is returned as a single string." I think that should be specified in documentation that this function works only for objects living in a module.
msg143773 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2011-09-09 17:16
> inspect.getsource called with a class defined in the same file fails
> with TypeError: <module '__main__' (built-in)> is a built-in class

The error message makes me think that getsource(__main__) was used, not getsource(SomeClass).  Can you check again?
msg143790 - (view) Author: Claudiu Popa (Claudiu.Popa) * (Python triager) Date: 2011-09-09 18:59
Yes. On Python 3.2 (r32:88445, Feb 20 2011, 21:29:02) [MSC v.1500 32 bit (Intel)] on win32, the result for the following lines:

import inspect
class A:
    pass
inspect.getsource(A)

is:

Traceback (most recent call last):
  File "E:/Scripts/Snippets/test_inspect_bug.py", line 4, in <module>
    inspect.getsource(A)
  File "C:\Python32\lib\inspect.py", line 694, in getsource
    lines, lnum = getsourcelines(object)
  File "C:\Python32\lib\inspect.py", line 683, in getsourcelines
    lines, lnum = findsource(object)
  File "C:\Python32\lib\inspect.py", line 522, in findsource
    file = getsourcefile(object)
  File "C:\Python32\lib\inspect.py", line 441, in getsourcefile
    filename = getfile(object)
  File "C:\Python32\lib\inspect.py", line 406, in getfile
    raise TypeError('{!r} is a built-in class'.format(object))
TypeError: <module '__main__' (built-in)> is a built-in class
>>>
msg143831 - (view) Author: Claudiu Popa (Claudiu.Popa) * (Python triager) Date: 2011-09-10 06:45
I forgot to mention that I executed this code directly in IDLE. It seems to work perfectly on command line though.
msg185179 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2013-03-25 02:54
> It seems to work perfectly on command line though.

If the code is saved in a file, yes, but not in an interactive interpreter.  This is not actually related to IDLE, but to the fact that inspect.getsource merely finds the __file__ attribute of the module object for its argument.  If a module object has no file, the error message indicates that it’s a built-in module (like sys), but this fails to take into account the special __main__ module in an interactive interpreter.

It might be worth it to improve the error message, and in any case the documentation can be improved.
msg245714 - (view) Author: Ned Deily (ned.deily) * (Python committer) Date: 2015-06-24 04:04
In duplicate Issue24491, zorceta notes: "Both python.exe and IDLE can't. IPython is able to, as it inserts REPL input into linecache."
msg245721 - (view) Author: Zorceta (zorceta) Date: 2015-06-24 05:45
When provided object is not from a file, like input in interactive shell, `inspect` internals will check for it in `linecache`, which official Python shell and IDLE won't put interactive shell input into, yet. This can be simply solved.

Whether interactive shell input can be put into `linecache` may be a problem, but it'll make life easier, as interactive shell saves time from edit-save-run 'loop'.

btw, I changed the title, since I don't think, what original author thought need to be documented, is absolutely right.
msg245723 - (view) Author: Zorceta (zorceta) Date: 2015-06-24 06:05
> When provided object is not from a file

should be

'When `inspect` can't find the source file of provided object'.

My mistake.
msg252846 - (view) Author: (nikitakit) Date: 2015-10-12 06:33
I just ran into this issue trying to introspect an IPython session, in which case the __main__ module doesn't have a file associated with it.

But it turns out that methods defined in a class do have source code associated with them, so it's possible to add a workaround for the common case where a class actually has methods.

Code: https://gist.github.com/nikitakit/642cb96febdf2f812d0b
msg265815 - (view) Author: Steven Barker (Steven.Barker) * Date: 2016-05-18 06:45
The problem being discussed here just came up on Stack Overflow today: http://stackoverflow.com/questions/37288135/inspect-module-for-python/

The cause of the incorrect error message is pretty clear. The relevant code from `inspect.getfile` should do something better when the object has a `__module__` attribute, but the module named (when looked up in `sys.modules`) does not have a `__file__` attribute. Currently it says the module is a builtin class, which is total nonsense.

A very basic fix would be to have an extra error case:

    if isclass(object):
        if hasattr(object, '__module__'):
            object = sys.modules.get(object.__module__)
            if hasattr(object, '__file__'):
                return object.__file__
            raise TypeError()              # need a relevant message here!!!
        raise TypeError('{!r} is a built-in class'.format(object))

It might be easier to make a meaningful message if the code after the first `if` didn't overwrite `object` with the module.

But, really, it would be nice to figure out a better fix, which would make the relevant inspect functions actually work for classes defined interactively in the `__main__` module.
msg297768 - (view) Author: Vitor Pereira (vmsp) * Date: 2017-07-05 15:25
So, what would be the right approach here? Store the interactive session's input text in memory?
msg297797 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2017-07-06 04:04
Probably.  Figure out a protocol to inject them into linecache, perhaps.  But I'm not sure such a thing would be accepted.  If you can figure out a way to make it work at least theoretically, it would probably be best to talk about it on python-ideas first.

In the meantime it would be nice to improve the error message, which is what we should use this issue for.
History
Date User Action Args
2017-07-06 04:04:18r.david.murraysetnosy: + r.david.murray
messages: + msg297797
2017-07-05 15:25:22vmspsetnosy: + vmsp
messages: + msg297768
2016-05-18 06:45:42Steven.Barkersetnosy: + Steven.Barker
messages: + msg265815
2015-10-12 06:33:34nikitakitsetnosy: + nikitakit
messages: + msg252846
2015-06-24 06:05:03zorcetasetmessages: + msg245723
2015-06-24 05:46:58zorcetasetnosy: - docs@python
2015-06-24 05:46:38zorcetasetcomponents: + IDLE, Interpreter Core, - Documentation
2015-06-24 05:45:05zorcetasetmessages: + msg245721
title: Document that inspect.getsource only works for objects loaded from files, not interactive session -> inspect.getsource only works for objects loaded from files, not interactive session
2015-06-24 04:04:41ned.deilylinkissue24491 superseder
2015-06-24 04:04:29ned.deilysetnosy: + ned.deily, zorceta

messages: + msg245714
versions: + Python 3.5, Python 3.6, - Python 3.2, Python 3.3
2013-03-25 02:54:47eric.araujosettitle: inspect.getsource fails to get source of local classes -> Document that inspect.getsource only works for objects loaded from files, not interactive session
stage: needs patch
messages: + msg185179
versions: + Python 3.4
2013-03-24 00:40:58Naddiseosetnosy: + Naddiseo
2011-09-10 06:45:37Claudiu.Popasetmessages: + msg143831
2011-09-09 18:59:58Claudiu.Popasetmessages: + msg143790
2011-09-09 17:16:18eric.araujosetnosy: + eric.araujo
title: Inspect.getsource fails to get source of local classes -> inspect.getsource fails to get source of local classes
messages: + msg143773

versions: - Python 3.1
2011-09-06 18:37:57Claudiu.Popacreate