Skip to content

Conversation

@devdanzin
Copy link
Member

@devdanzin devdanzin commented Oct 27, 2024

inspect.getsource would fetch sourcecode from _pyrepl.__main__ for classes defined in the REPL when using PyREPL because sys.modules["__main__"] points to that module.

This PR makes inspect.getsource raise OSError('source code not available') for classes defined in the REPL by detecting that .__module__ is "__main__". Tests pass with this change, but if you know of a corner case that would be broken by it please say so.

@ZeroIntensity ZeroIntensity added the topic-repl Related to the interactive shell label Oct 27, 2024
Lib/inspect.py Outdated
Comment on lines 821 to 823
# Protect against fetching the wrong source in PyREPL
if object.__module__ == '__main__':
raise OSError('source code not available')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm worried about this being a breaking change. __module__ now has more precedent over __file__--maybe people could have been relying on that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I share similar concerns. Also why this only affects pyREPL and not any other main module ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also why this only affects pyREPL and not any other main module ?

I think because for other __main__ modules, __main__.__file__ points to the correct source code.

In basic REPL, sys.modules["__main__"] doesn't have a __file__ attribute, so it raises OSError('source code not available') when inspected.

But with PyREPL, sys.modules["__main__"].__file__ is _pyrepl.__main__, which is where the source code is being pulled from. So we could instead skip loading from __file__ if we detect PyREPL is in use, what do you think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, we could just delete __file__ from __main__, right?

diff --git a/Lib/_pyrepl/main.py b/Lib/_pyrepl/main.py
index a6f824dcc4a..17c55eb9c9f 100644
--- a/Lib/_pyrepl/main.py
+++ b/Lib/_pyrepl/main.py
@@ -35,6 +35,7 @@ def interactive_console(mainmodule=None, quiet=False, pythonstartup=False):
         import __main__
         namespace = __main__.__dict__
         namespace.pop("__pyrepl_interactive_console", None)
+        namespace.pop("__file__", None)

     # sys._baserepl() above does this internally, we do it here
     startup_path = os.getenv("PYTHONSTARTUP")

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That fixes the problem no?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think that would be much less invasive.

@devdanzin
Copy link
Member Author

I've changed the approach to removing __file__ from the namespace created by PyREPL, so that inspect.getsource() doesn't fetch bogus code for classes defined in the REPL.

Some changes had to be made to tests that expected __file__ to be there and to the method of detecting PyREPL in tests.

Wording of the NEWS entry seems poor to me, would gladly apply any suggested improvements.

@Eclips4 Eclips4 added the needs backport to 3.13 bugs and security fixes label Oct 28, 2024
Comment on lines +1314 to +1318
def test_inspect_getsource(self):
code = "import inspect\nclass A: pass\n\nprint(inspect.getsource(A))\nexit()\n"
output, exit_code = self.run_repl(code)
self.assertEqual(exit_code, 0)
self.assertIn("OSError('source code not available')", output)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that testing whether inspect.getsource works on other objects (functions, methods, traceback, frames) is worthwhile, but I'm not sure if it should be done in this PR. So, I'd be fine with doing it in a follow-up

@python-cla-bot
Copy link

python-cla-bot bot commented Apr 18, 2025

All commit authors signed the Contributor License Agreement.

CLA signed

@serhiy-storchaka serhiy-storchaka added the needs backport to 3.14 bugs and security fixes label May 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting review needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes topic-repl Related to the interactive shell

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants