Search code examples
pythondebuggingvisual-studio-codeinputargs

How do I redirect input and output in VSC python code?


I have tried the "<" and ">" commands but vsc still uses the terminal.

My launch.json:

"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"args": ["<", "${workspaceFolder}input.txt"]

this results in this at the terminal in vsc:

(.venv) PS C:\Users\domip\Desktop\Python>  c:; cd 'c:\Users\domip\Desktop\Python'; & 'c:\Users\domip\Desktop\Python\.venv\Scripts\python.exe' 'c:\Users\domip\.vscode\extensions\ms-python.python-2021.12.1559732655\pythonFiles\lib\python\debugpy\launcher' '63669' '--' 'c:\Users\domip\Desktop\Python\ea2\fizzbuzz.py' '<' 'C:\Users\domip\Desktop\Pythoninput.txt'

However, when debugging it still uses the terminal to ask for input. Same goes if I use ">", "output.txt". The output gets written on the terminal, not in the txt file. I have tried to run it manually and it behaves the same way.
I am new to python. For testing I use the input() function. I tried using a main() function, maybe the args need to be passed to that but no effect. When I was coding in C (in vsc) I had no problem with this. I have tried everything I found on the internet. Nothing helped. Thank you


Solution

  • As you have discovered the < is nicely put inside quotes by the ms-python extension and thus the shell will not see it as a redirect.

    It can be done but requires a bit of configuration.

    You have to setup the debug client and server yourself.

    The debug server is setup as a task. The client is an attach launch configuration.

    First you need to find the location of the debugpy module that is part of the ms-python extension (you can install as a separate module in your environment but why if you already have it).

    I use the following 2 files:

    redir_input.py

    while True:
      try:
        line = input()
      except EOFError:
        break
      print(line)
    

    input.txt

    line 1
    line 2
    line 3
    

    Start a debug session with the redir_input.py file (taking input from the terminal). Terminate the program with Ctrl+Z Enter.

    What we want is the command shown on the terminal. Something like:

    <path>/.venv/Scripts/python <path>/.vscode/extensions/ms-python.python-2021.12.1559732655/pythonFiles/lib/python/debugpy/launcher 64141 -- <path>/redir_input.py
    

    We need the second string: the location of the debugpy module (without the /launcher part)

    <path>/.vscode/extensions/ms-python.python-2021.12.1559732655/pythonFiles/lib/python/debugpy
    

    <path> is something specific for your machine.

    In .vscode/tasks.json create a task that will start the program to debug:

    {
      "version": "2.0.0",
      "tasks": [
        {
          "label": "Script with redirect input",
          "type": "shell",
          "command": "${command:python.interpreterPath} <path>/.vscode/extensions/ms-python.python-2021.12.1559732655/pythonFiles/lib/python/debugpy
      --listen 5678 --wait-for-client ${workspaceFolder}/redir_input.py < ${workspaceFolder}/input.txt",
          "problemMatcher": []
        }
      ]
    }
    

    Now setup a compound launch config, one starts the debug server and one attaches the debug client. The debug server launches a dummy python script because we actually need the prelaunchTask.

    .vscode/launch.json

    {
      "version": "0.2.0",
      "configurations": [
        {
          "name": "Python: Attach to Process port 5678",
          "type": "python",
          "request": "attach",
          "connect": {
            "host": "localhost",
            "port": 5678
          }
        },
        {
          "name": "Python: Start Process port 5678",
          "type": "python",
          "request": "launch",
          "code": "print()",
          "preLaunchTask": "Script with redirect input"
        }
      ],
      "compounds": [
        {
          "name": "Debug with input redir",
          "configurations": [
            "Python: Start Process port 5678",
            "Python: Attach to Process port 5678"
          ]
        }
      ]
    }
    

    Select Debug with input redir as the launch config to run (top of debug bar) and press Run button (little green arrow) or F5

    The debugger waits till the client has attached (--wait-for-client), most likely you want to set a breakpoint on the reading of lines.

    There will be 2 terminals created. Select the correct one with the program/task running.

    You can change the names of the task and launch configs. Be sure to update the names on multiple locations.


    Edit

    A different way is to change the sys.stdin and sys.stdout of the program.

    Then you can use the normal debugger method.

    redir_input_2.py

    import sys
    
    infile = open('input.txt')
    sys.stdin = infile
    
    while True:
      try:
        line = input()
      except EOFError:
        break
      print(line)
    
    if infile: infile.close()
    

    Here I have hard coded it, but you can add argparse to do it when you use specific command line options.

    redir_input_2.py --redir-input input.txt --redir-output output.txt