[Python] Why does VS Code Debugger reset `PATH` from `.env`, breaking subprocess behavior in...

Discussão em 'Python' iniciado por Stack, Abril 17, 2025.

  1. Stack

    Stack Membro Participativo

    I'm facing an unusual issue when using subprocess.Popen in Python while debugging in VS Code. The behavior of the PATH environment variable changes only in debug mode, and subprocess calls behave unexpectedly.

    Environment


    • System
      • Windows 22H2 build 19045.5487
      • Python 3.10.16

    • Editor
      • VS Code 1.96.2
      • Extensions (latest at 2025/4/16)
        • Python @2025.4.0
        • Python Debugger @2025.4.1
        • Pylance @2025.4.1

    Let's assume the workspace root is \.

    We have the following .env file in the root:

    PATH=(added_path) # Do not specify the old %PATH% !


    This deliberately sets PATH to an invalid value to test how subprocesses behave when PATH is empty.

    The test script (\test.py) is as follows:

    import subprocess

    print("") # for debug mode commandline formatting

    def construct_psh_cmd(psh_code):
    psh_cmd = "powershell -NoProfile " + '"' + f"$ErrorActionPreference='silentlycontinue'; $tmp = ({psh_code}); if ($tmp)" + "{echo $tmp; Exit;}" + '"'
    return psh_cmd

    def print_psh(psh_code, shell: bool = True):
    psh_cmd = construct_psh_cmd(psh_code)
    with subprocess.Popen(
    psh_cmd,
    stdout=subprocess.PIPE,
    stdin=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
    shell=shell
    ) as stream:
    stdout = stream.communicate()[0].decode()
    print(f"Powershell(Popen.{shell=}): {psh_code} = {stdout}")

    def print_cmd(cmd_code):
    with subprocess.Popen(
    cmd_code,
    stdout=subprocess.PIPE,
    stdin=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
    shell=True,
    ) as stream:
    stdout = stream.communicate()[0].decode()
    print(f"CMD.EXE: {cmd_code} = {stdout}")

    # Test outputs
    print_cmd("echo %PATH%") # CMD
    print_psh("echo $env:pATH") # PowerShell (default shell=True)
    print_psh("echo (100*3)") # Arithmetic (default shell=True)
    print_psh("echo (100*3)", shell=False) # Arithmetic with shell=False


    Observations:

    • In normal (non-debug) execution in the VS Code integrated terminal (PowerShell), all subprocess calls work as expected.
      • The PATH is inherited from the shell, and even the (added_path) in .env is appended to the effective PATH.
    • In debug mode, something changes:
      • The PATH is set only to the (added_path) defined in .env. It _overwrites+ rather than extends the terminal environment.
      • Popen(..., shell=False) fails with FileNotFoundError, which makes sense — powershell.exe is not found.
      • But surprisingly, Popen(..., shell=True) does not fail. However, all echo commands return empty strings, even for simple arithmetic like (100*3).

    It seems that:

    • In debug mode, VS Code launches the Python process using an environment where PATH is overwritten by .env, rather than extended.
    • Even though powershell.exe is not in PATH, shell=True somehow avoids an error — yet silently fails to return any result.
    • This behavior is isolated to VS Code's debugger inside the integrated terminal, not when executing normally in the terminal.

    I suspect that subprocess.Popen eventually calls the Windows API CreateProcess, and this difference may originate there — possibly from how VSCode launches the Python debugger process internally.

    Questions

    1. Why does VSCode override the PATH variable from .env only when debugging, instead of appending it like in regular execution?
    2. Why does Popen(..., shell=True) succeed in launching a command even though powershell.exe should not be found with an empty PATH — yet the command yields no output, not even from an arithmetic expression?

    Notes:


    Continue reading...

Compartilhe esta Página