Search code examples
pythonargparse

Specific argument causes argparse to parse arguments incorrectly


I am using python argparse in a script that has so far worked perfectly. However, passing a specific filepath as an argument causes the parser to fail.

Here is my argparse setup:

parser = argparse.ArgumentParser(prog="writeup_converter.py", description="Takes a folder of Obsidian markdown files and copies them across to a new location, automatically copying any attachments. Options available include converting to a new set of Markdown files, removing and adding prefixes to attachments, and converting for use on a website")

#positional arguments
parser.add_argument("source_folder", help="The folder of markdown files to copy from.")
parser.add_argument("source_attachments", help="The attachments folder in your Obsidian Vault that holds attachments in the notes.")
parser.add_argument("target_folder", help="The place to drop your converted markdown files")
parser.add_argument("target_attachments", help="The place to drop your converted attachments. Must be set as your attachments folder in Obsidian (or just drop them in the root of your vault if you hate yourself)")

#optional flags
parser.add_argument("-r", "--remove_prefix", help="Prefix to remove from all your attachment file paths.")
parser.add_argument("-v", "--verbose", action="store_true", help="Verbose mode. Gives details of which files are being copied. Disabled by default in case of large directories")
parser.add_argument("-w", "--website", help="Use website formatting when files are copied. Files combined into one markdown file with HTML elements, specify the name of this file after the flag")
parser.add_argument("-l", "--asset_rel_path", help="Relative path for site assets e.g. /assets/images/blogs/..., include this or full system path will be added to links")

print(sys.argv)
exit()

#parse arguments
args = parser.parse_args()

I've added the print and exit for debugging purposes. Previously when I run the program with this configuration, it works well - however this set of arguments produces a strange error:

PS D:\OneDrive\Documents\writeup-converter> python .\writeup_converter.py -v -r Cybersecurity "..\Personal-Vault\Cybersecurity\SESH\2021-22 Sessions\Shells Session Writeups\" "..\Personal-Vault\Attachments\" "..\Cybersecurity-Notes\Writeups\SESH\DVWA\" "..\Cybersecurity-Notes\Attachments\"
usage: writeup_converter.py [-h] [-r REMOVE_PREFIX] [-v] [-w WEBSITE] [-l ASSET_REL_PATH] source_folder source_attachments target_folder target_attachments
writeup_converter.py: error: the following arguments are required: source_attachments, target_folder, target_attachments

It seems to not recognise the positional arguments that are definitely present. I added those debugging statements to see what the state of the arguments were according to Python:

['.\\writeup_converter.py', '-v', '-r', 'Cybersecurity', '..\\Personal-Vault\\Cybersecurity\\SESH\\2021-22 Sessions\\Shells Session Writeups" ..\\Personal-Vault\\Attachments\\ ..\\Cybersecurity-Notes\\Writeups\\SESH\\DVWA\\ ..\\Cybersecurity-Notes\\Attachments\\']

As you can see, the four positional arguments have been combined into one. Experimenting further I found that the first argument specifically causes this issue:

PS D:\OneDrive\Documents\writeup-converter> python .\writeup_converter.py a b c d
['.\\writeup_converter.py', 'a', 'b', 'c', 'd']
PS D:\OneDrive\Documents\writeup-converter> python .\writeup_converter.py "a b" b c d
['.\\writeup_converter.py', 'a b', 'b', 'c', 'd']
PS D:\OneDrive\Documents\writeup-converter> python .\writeup_converter.py "a\ b" b c d
['.\\writeup_converter.py', 'a\\ b', 'b', 'c', 'd']
PS D:\OneDrive\Documents\writeup-converter> python .\writeup_converter.py "a\ b" "b" c d
['.\\writeup_converter.py', 'a\\ b', 'b', 'c', 'd']
PS D:\OneDrive\Documents\writeup-converter> python .\writeup_converter.py "..\Personal-Vault\Cybersecurity\SESH\2021-22 Sessions\Shells Session Writeups\" "b" c d
['.\\writeup_converter.py', '..\\Personal-Vault\\Cybersecurity\\SESH\\2021-22 Sessions\\Shells Session Writeups" b c d']

As you can see, the arguments are parsed correctly until the string "..\Personal-Vault\Cybersecurity\SESH\2021-22 Sessions\Shells Session Writeups\" is used. I can't figure out a reason for this, so any ideas would be appreciated. This behaviour occurs in both Python and CMD.


Solution

  • About ten seconds after posting this I realised the error thanks to Stack Overflow syntax highlighting - the backslash in the path was escaping the quotation mark. Escaping this causes argparse to behave correctly:

    PS D:\OneDrive\Documents\writeup-converter> python .\writeup_converter.py -v -r Cybersecurity "..\Personal-Vault\Cybersecurity\SESH\2021-22 Sessions\Shells Session Writeups\\" ..\Personal-Vault\Attachments\ ..\Cybersecurity-Notes\Writeups\SESH\DVWA\ ..\Cybersecurity-Notes\Attachments\
    ['.\\writeup_converter.py', '-v', '-r', 'Cybersecurity', '..\\Personal-Vault\\Cybersecurity\\SESH\\2021-22 Sessions\\Shells Session Writeups\\', '..\\Personal-Vault\\Attachments\\', '..\\Cybersecurity-Notes\\Writeups\\SESH\\DVWA\\', '..\\Cybersecurity-Notes\\Attachments\\']