WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Conversation

@arjxn-py
Copy link

This PR wraps the contents of pythonrc.py inside a setup() function to avoid polluting the variables panel of jupyterlab debugger when launched from VS Code and this extension is installed.

Context

Image

When JupyterLab is launched from VS Code, the debugger’s Globals panel becomes cluttered with variables injected from the VS Code Python extension’s pythonrc.py. Examples include original_ps1, is_wsl, result, and other internal helper variables. These show up as top-level globals in Jupyter kernels, making the debugger view noisy.

This change potentially reduces unwanted side effects for external tools (e.g., JupyterLab) while keeping functionality intact.

@arjxn-py
Copy link
Author

@microsoft-github-policy-service agree company="QuantStack"

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR attempts to wrap the pythonrc.py logic inside a setup() function to prevent internal variables from leaking into the JupyterLab debugger's global namespace. The change aims to reduce clutter in the debugger's Variables panel when JupyterLab is launched from VS Code.

Key changes:

  • All module-level code is moved inside a new setup() function
  • The setup() function is called at module initialization and then deleted
  • All classes, functions, and variables are now local to the setup() function scope

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +83
def setup():
import platform
import sys

if sys.platform != "win32":
import readline

original_ps1 = ">>> "
is_wsl = "microsoft-standard-WSL" in platform.release()


class REPLHooks:
def __init__(self):
self.global_exit = None
self.failure_flag = False
self.original_excepthook = sys.excepthook
self.original_displayhook = sys.displayhook
sys.excepthook = self.my_excepthook
sys.displayhook = self.my_displayhook

def my_displayhook(self, value):
if value is None:
self.failure_flag = False

self.original_displayhook(value)

def my_excepthook(self, type_, value, traceback):
self.global_exit = value
self.failure_flag = True

self.original_excepthook(type_, value, traceback)


def get_last_command():
# Get the last history item
last_command = ""
if sys.platform != "win32":
last_command = readline.get_history_item(readline.get_current_history_length())

return last_command

import readline

class PS1:
hooks = REPLHooks()
sys.excepthook = hooks.my_excepthook
sys.displayhook = hooks.my_displayhook
original_ps1 = ">>> "
is_wsl = "microsoft-standard-WSL" in platform.release()

# str will get called for every prompt with exit code to show success/failure
def __str__(self):
exit_code = int(bool(self.hooks.failure_flag))
self.hooks.failure_flag = False
# Guide following official VS Code doc for shell integration sequence:
result = ""
# For non-windows allow recent_command history.
class REPLHooks:
def __init__(self):
self.global_exit = None
self.failure_flag = False
self.original_excepthook = sys.excepthook
self.original_displayhook = sys.displayhook
sys.excepthook = self.my_excepthook
sys.displayhook = self.my_displayhook

def my_displayhook(self, value):
if value is None:
self.failure_flag = False
self.original_displayhook(value)

def my_excepthook(self, type_, value, traceback):
self.global_exit = value
self.failure_flag = True
self.original_excepthook(type_, value, traceback)

def get_last_command():
# Get the last history item
last_command = ""
if sys.platform != "win32":
result = "{soh}{command_executed}{command_line}{command_finished}{prompt_started}{stx}{prompt}{soh}{command_start}{stx}".format(
soh="\001",
stx="\002",
command_executed="\x1b]633;C\x07",
command_line="\x1b]633;E;" + str(get_last_command()) + "\x07",
command_finished="\x1b]633;D;" + str(exit_code) + "\x07",
prompt_started="\x1b]633;A\x07",
prompt=original_ps1,
command_start="\x1b]633;B\x07",
)
else:
result = "{command_finished}{prompt_started}{prompt}{command_start}{command_executed}".format(
command_finished="\x1b]633;D;" + str(exit_code) + "\x07",
prompt_started="\x1b]633;A\x07",
prompt=original_ps1,
command_start="\x1b]633;B\x07",
command_executed="\x1b]633;C\x07",
)

# result = f"{chr(27)}]633;D;{exit_code}{chr(7)}{chr(27)}]633;A{chr(7)}{original_ps1}{chr(27)}]633;B{chr(7)}{chr(27)}]633;C{chr(7)}"

return result


if sys.platform != "win32" and (not is_wsl):
sys.ps1 = PS1()

if sys.platform == "darwin":
print("Cmd click to launch VS Code Native REPL")
else:
print("Ctrl click to launch VS Code Native REPL")
last_command = readline.get_history_item(readline.get_current_history_length())
return last_command

class PS1:
hooks = REPLHooks()
sys.excepthook = hooks.my_excepthook
sys.displayhook = hooks.my_displayhook

# str will get called for every prompt with exit code to show success/failure
def __str__(self):
exit_code = int(bool(self.hooks.failure_flag))
self.hooks.failure_flag = False
# Guide following official VS Code doc for shell integration sequence:
result = ""
# For non-windows allow recent_command history.
if sys.platform != "win32":
result = "{soh}{command_executed}{command_line}{command_finished}{prompt_started}{stx}{prompt}{soh}{command_start}{stx}".format(
soh="\001",
stx="\002",
command_executed="\x1b]633;C\x07",
command_line="\x1b]633;E;" + str(get_last_command()) + "\x07",
command_finished="\x1b]633;D;" + str(exit_code) + "\x07",
prompt_started="\x1b]633;A\x07",
prompt=original_ps1,
command_start="\x1b]633;B\x07",
)
else:
result = "{command_finished}{prompt_started}{prompt}{command_start}{command_executed}".format(
command_finished="\x1b]633;D;" + str(exit_code) + "\x07",
prompt_started="\x1b]633;A\x07",
prompt=original_ps1,
command_start="\x1b]633;B\x07",
command_executed="\x1b]633;C\x07",
)

# result = f"{chr(27)}]633;D;{exit_code}{chr(7)}{chr(27)}]633;A{chr(7)}{original_ps1}{chr(27)}]633;B{chr(7)}{chr(27)}]633;C{chr(7)}"

return result

if sys.platform != "win32" and (not is_wsl):
sys.ps1 = PS1()

if sys.platform == "darwin":
print("Cmd click to launch VS Code Native REPL")
else:
print("Ctrl click to launch VS Code Native REPL")


setup()
del setup
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

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

After wrapping all code in the setup() function and deleting it, the classes PS1 and REPLHooks will no longer be accessible as module-level attributes. This breaks the existing test suite which references pythonrc.PS1() and pythonrc.REPLHooks() in test_shell_integration.py. These classes need to remain accessible at module level for the tests to work.

Copilot uses AI. Check for mistakes.
Comment on lines +30 to +35
def get_last_command():
# Get the last history item
last_command = ""
if sys.platform != "win32":
result = "{soh}{command_executed}{command_line}{command_finished}{prompt_started}{stx}{prompt}{soh}{command_start}{stx}".format(
soh="\001",
stx="\002",
command_executed="\x1b]633;C\x07",
command_line="\x1b]633;E;" + str(get_last_command()) + "\x07",
command_finished="\x1b]633;D;" + str(exit_code) + "\x07",
prompt_started="\x1b]633;A\x07",
prompt=original_ps1,
command_start="\x1b]633;B\x07",
)
else:
result = "{command_finished}{prompt_started}{prompt}{command_start}{command_executed}".format(
command_finished="\x1b]633;D;" + str(exit_code) + "\x07",
prompt_started="\x1b]633;A\x07",
prompt=original_ps1,
command_start="\x1b]633;B\x07",
command_executed="\x1b]633;C\x07",
)

# result = f"{chr(27)}]633;D;{exit_code}{chr(7)}{chr(27)}]633;A{chr(7)}{original_ps1}{chr(27)}]633;B{chr(7)}{chr(27)}]633;C{chr(7)}"

return result


if sys.platform != "win32" and (not is_wsl):
sys.ps1 = PS1()

if sys.platform == "darwin":
print("Cmd click to launch VS Code Native REPL")
else:
print("Ctrl click to launch VS Code Native REPL")
last_command = readline.get_history_item(readline.get_current_history_length())
return last_command
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

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

The get_last_command() function is defined as a nested function inside setup() and will not be accessible when called by PS1.str() on line 54 after setup() completes. Since PS1 instances persist beyond the setup() call, this will result in a NameError when the PS1 prompt tries to format the command line. The function needs to be defined at a scope that remains accessible to the PS1 instance.

Copilot uses AI. Check for mistakes.
command_line="\x1b]633;E;" + str(get_last_command()) + "\x07",
command_finished="\x1b]633;D;" + str(exit_code) + "\x07",
prompt_started="\x1b]633;A\x07",
prompt=original_ps1,
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

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

The variable original_ps1 is used by the PS1.str() method on lines 57 and 64, but it's defined as a local variable in setup() on line 8. After setup() completes, this will cause a NameError when PS1 tries to format the prompt. The variable needs to be accessible to PS1 instances that persist beyond the setup() call.

Copilot uses AI. Check for mistakes.
print("Cmd click to launch VS Code Native REPL")
else:
print("Ctrl click to launch VS Code Native REPL")
last_command = readline.get_history_item(readline.get_current_history_length())
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

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

The readline module is conditionally imported inside setup() on line 6, but it's used by get_last_command() on line 34. When PS1.str() calls get_last_command() after setup() completes, readline will not be in scope, resulting in a NameError. The import needs to be accessible to the persistent get_last_command() function.

Copilot uses AI. Check for mistakes.
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

Successfully merging this pull request may close these issues.

2 participants