How do I pass an argument with special characters from launch.json?

Viewed 3037

I'm trying to pass arguments to my Python program via launch.json and one of my arguments requires special characters as it is the password (I plan to add more secure ways to input the password but that's not the point).

Here's my launch.json (with the password changed but still with special characters)

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Current File",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "args": [
                "-u",
                "camera@iot-project.com",
                "-p",
                "Y^bKKiUPu!fM6!dBsvnALmuXbP6fqT$d"
            ],
            "console": "integratedTerminal"
        }
    ]
}

When I set my password argument to "'Y^bKKiUPu!fM6!dBsvnALmuXbP6fqT$d'", it actually passes the single quotes into the Python program, which isn't what I want (running the program in a terminal with single quotes works).

Here is my Python program:

import sys
import getopt
import pyrebase

# Get full command-line arguments
argument_list = sys.argv

# Keep all but the first
argument_list = argument_list[1:]
# Parse arguments
try:
    options, arguments = getopt.getopt(argument_list, "u:p:", ["username", "password"])
except getopt.GetoptError as error:
    print(error)
    exit(1)

# Get username and password from arguments
for option, argument in options:
    if option in ["-u", "--username"]:
        username = argument
    if option in ["-p", "--password"]:
        password = argument

config = {
    "apiKey": "*apikeyhere*",
    "authDomain": "*domain*.firebaseapp.com",
    "databaseURL": None,
    "storageBucket": "*domain*.appspot.com",
}

firebase = pyrebase.initialize_app(config)

print(username)
print(password)

firebaseAuth = firebase.auth()
user = firebaseAuth.sign_in_with_email_and_password(username, password)
1 Answers

For the Python extension and for the console configuration, instead of "integratedTerminal", you can use "internalConsole".

{
    "name": "run-py-with-special-chars-internalconsole",
    "type": "python",
    "request": "launch",
    "cwd": "${workspaceFolder}/Q",
    "program": "${workspaceFolder}/Q/test.py",
    "args": [
        "-u",
        "camera@iot-project.com",
        "-p",
        "Y^bKKiUPu!fM6!dBsvnALmuXbP6fqT$d"
    ],
    "console": "internalConsole"  // <--------------------
}

Here's a stripped-down version of your code and print-ed output to the Debug Console tab:

vs code debug console

where the password is preserved, same as running the script manually:

$ python test.py -u 'camera@iot-project.com' -p 'Y^bKKiUPu!fM6!dBsvnALmuXbP6fqT$d'

The internalConsole option uses VS Code's debugger console. I was trying to find a nice reference for it while writing this answer, but all I found was this: Debug Console, which says that "Expressions can be evaluated in the Debug Console REPL".

This seems to mean that special characters are not evaluated as special commands as compared to the integratedTerminal, which basically uses the underlying shell of your OS. On Linux and Mac, this can mean bash, and an ! means a different thing on the terminal.

You can see the problem with the integratedTerminal option when you look at the Terminal output

bash-3.2$  env DEBUGPY_LAUNCHER_PORT=56036 /path/to/bin/python 
           /path/to/.vscode/extensions/ms-python.python-2020.3.69010/pythonFiles/lib/python/debugpy/no_wheels/debugpy/launcher 
           /path/to/test.py -u camera@iot-project.com -p Y^bKKiUPu!fM6!dBsvnALmuXbP6fqT$d 
bash: !fM6!dBsvnALmuXbP6fqT$d: event not found

and it passes the password with special characters as unquoted.

Related