-
Notifications
You must be signed in to change notification settings - Fork 187
Open
Description
Summary
Jupyter commands fail on Windows when the current working directory path contains special characters (specifically parentheses) in the username, even when Python and Jupyter are properly installed and accessible.
Problem Description
When running Jupyter commands from a directory path containing parentheses in the Windows username, the command execution fails with:
'C:\Users\JohnDoe' is not recognized as an internal or external command,
operable program or batch file.
Reproduction Steps
Failing Case
C:\Users\JohnDoe(TEST)>python.exe -m jupyter notebook --no-browser
'C:\Users\JohnDoe' is not recognized as an internal or external command,
operable program or batch file.
Working Case (Same System, Different Directory)
C:\Users\JohnDoe(TEST)\AppData\Local\env\tools>python.exe -m jupyter notebook --no-browser
[I 2024-xx-xx xx:xx:xx.xxx NotebookApp] Serving notebooks from local directory: C:\Users\JohnDoe(TEST)\AppData\Local\env\tools
[... works fine ...]
Root Cause Analysis
The issue occurs in jupyter_core/command.py
in the _execvp()
function. On Windows, when executing subcommands, the function constructs a command line without properly quoting paths that contain special characters.
Technical Details
- Location:
jupyter_core/command.py
, lines 114-137, specifically line 127 - Issue: Unquoted command paths with parentheses cause Windows to interpret
C:\Users\JohnDoe(TEST)\path\to\jupyter-notebook.exe
asC:\Users\JohnDoe
(stopping at the parenthesis) - Platform: Windows-specific issue due to how
subprocess.Popen
handles unquoted paths withshell=True
Proposed solution
Updated the command line construction to properly quote both the command path and arguments:
def _execvp(cmd: str, argv: list[str]) -> None:
"""execvp, except on Windows where it uses Popen
Python provides execvp on Windows, but its behavior is problematic (Python bug#9148).
"""
if sys.platform.startswith("win"):
# PATH is ignored when shell=False,
# so rely on shutil.which
cmd_path = which(cmd)
if cmd_path is None:
msg = f"{cmd!r} not found"
raise OSError(msg, errno.ENOENT)
# Quote the command path and arguments to handle Windows paths with special characters
cmd_line = f'"{cmd_path}"' + ''.join(f' "{arg}"' for arg in argv[1:])
p = Popen(cmd_line, shell=True) # noqa: S602
# Don't raise KeyboardInterrupt in the parent process.
# Set this after spawning, to avoid subprocess inheriting handler.
import signal
signal.signal(signal.SIGINT, signal.SIG_IGN)
p.wait()
sys.exit(p.returncode)
else:
os.execvp(cmd, argv) # noqa: S606
Impact
- Affected Users: Windows users with special characters (parentheses, spaces) in their username or installation paths
- Scope: All Jupyter subcommands (
jupyter notebook
,jupyter lab
,jupyter kernelspec
, etc.)
Metadata
Metadata
Assignees
Labels
No labels