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
inspect.getsource only works for objects loaded from files, not interactive session #57129
Comments
inspect.getsource called with a class defined in the same file fails with "The argument may be a module, class, method, function, traceback, frame, |
The error message makes me think that |
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
>>> |
I forgot to mention that I executed this code directly in IDLE. 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. |
In duplicate bpo-24491, zorceta notes: "Both python.exe and IDLE can't. IPython is able to, as it inserts REPL input into linecache." |
When provided object is not from a file, like input in interactive shell, Whether interactive shell input can be put into btw, I changed the title, since I don't think, what original author thought need to be documented, is absolutely right. |
should be 'When My mistake. |
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 |
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 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 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 |
So, what would be the right approach here? Store the interactive session's input text in memory? |
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. |
See https://bugs.python.org/issue33826?@ok_message=msg%20328824%20created%0Aissue%2033826%20message_count%2C%20messages%20edited%20ok&@template=item#msg319692 how IPython stores source from interactive input and why it's not appropriate for vanilla REPL IMO. |
Do we really need to say that getsource(object) can only get the object's source if it is accessible from the object? Getsource also fails if a module is loaded from a .pyc with not corresponding .py available. The problem is not the call being in __main__. When I put the three lines (with the 3rd wrapped with print()) in an IDLE editor and run, and re-inspect, I get ======================== RESTART: F:\Python\a\tem3.py ======================== class A:
pass >>> inspect.getsource(A)
'class A:\n pass\n' Ditto if I run > py -i -m a.tem3 If I continue in IDLE's Shell
>>> inspect.getsource(B)
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
inspect.getsource(B)
File "F:\dev\37\lib\inspect.py", line 973, in getsource
lines, lnum = getsourcelines(object)
File "F:\dev\37\lib\inspect.py", line 955, in getsourcelines
lines, lnum = findsource(object)
File "F:\dev\37\lib\inspect.py", line 812, in findsource
raise OSError('could not find class definition')
OSError: could not find class definition IDLE does store interactive inputs into linecache, so that tracebacks contain the offending line (unlike interactive python). But it does so on a statement by statement basis, so that each entry is treated as a separate file. In a traceback for an exception in a multiline statement, the line number is relative to the statement. >>> def f():
# line2 of f
1/0
>>> f()
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
f()
File "<pyshell#12>", line 3, in f
1/0
ZeroDivisionError: division by zero Interactive python displays '<stdin>' as the file for all entries. IDLE numbers them, so previous statements remained cached. I consider enhanced interactive tracebacks to be an important feature. But I don't see how to attach individual pseudofile names to classes and functions so that getsource could find their source lines. |
This is also an issue even for non-interactive scenarios: When doing Perhaps this case will be easier to fix? |
It would be convenient if Is there some simple hack ways like |
this commit fix can not run greenplumpython in python repl more to check issue python/cpython#57129
CC @pablogsal |
This works now as part of #110775 We can add some tests and close the issue |
Signed-off-by: Pablo Galindo <pablogsal@gmail.com>
From greenplum-db/GreenplumPython#139, I found I can use |
Please read previous comments: the next version of Python will fix this directly. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
Linked PRs
The text was updated successfully, but these errors were encountered: