0
#!/usr/bin/env python3

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--selection', '-s')
parser.add_argument('--choice', '-c', default = argparse.SUPPRESS)
args = parser.parse_args()

def main(selection, choice):
    print(selection)
    print(choice)

if __name__=='__main__':
    main(args.selection, args.choice)

The example provided is just to provide something simple and short that accurately articulates the actual problem I am facing in my project. My goal is to be able to ignore an argument within the code body when it is NOT typed into the terminal. I would like to be able to do this through passing the argument as a parameter for a function. I based my code off of searching 'suppress' in the following link: https://docs.python.org/3/library/argparse.html

When I run the code as is with the terminal input looking like so: python3 stackquestion.py -s cheese, I receive the following error on the line where the function is called:

AttributeError: 'Namespace' object has no attribute 'choice'

I've tried adding the following parameter into parser like so:

parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)

I've also tried the above with

parser.add_argument('--choice', '-c')

But I get the same issue on the same line.

@Barmar answered this question in the comments. Using 'default = None' in parser.add_argument works fine; The code runs without any errors. I selected the anser from @BorrajaX because it's a simple solution to my problem.

dvines
  • 51
  • 6
  • It's not clear what you want: do you want to ignore an explicitly passed argument? If so, why? – chepner Sep 23 '22 at 20:03
  • 3
    `SUPPRESS` means that it doesn't create `args.choice` if the option isn't provided. What are you expecting to pass to `main()` in that case? Why not use something like `default=None`? – Barmar Sep 23 '22 at 20:04
  • 2
    In line with Barmar's comment -- the error `AttributeError: 'Namespace' object has no attribute 'choice'` is what you're _asking_ Python to do. You're getting what you're asking for; if you don't want it, stop asking for it. – Charles Duffy Sep 23 '22 at 20:07
  • `main()` never even uses its `choice` parameter, so what's the point of that command-line argument anyway? – wjandrea Sep 23 '22 at 20:09
  • @wjandrea The code I provided is a condensed example of what I am actually doing. I wanted to provide a clear, and simple example that I felt would accurately depict my problem; therefor being able to get an answer that can help solve the bigger issue I'm dealing with. – dvines Oct 25 '22 at 02:16
  • @dvines Well, what I'm saying is it's not clear. Why does `main()` have a `choice` parameter if it's unused? – wjandrea Oct 25 '22 at 02:26
  • BTW, `default=None` is the default, so you can just leave that off. – wjandrea Oct 25 '22 at 02:28
  • 1
    Okay I edited it. I was unware of 'None' already being default. At this point I suppose I can use a simple 'if' statement to prevent 'None' from being printed to terminal, or is there another way to avoid this? – dvines Oct 25 '22 at 04:08
  • 1
    @dvines Something like `if args.choice is not None: print(choice)` should work fine, like in BorrajaX's answer. – wjandrea Oct 25 '22 at 16:40

1 Answers1

3

According to the docs:

Providing default=argparse.SUPPRESS causes no attribute to be added if the command-line argument was not present:

But you're still assuming it will be there by using it in the call to main:

main(args.selection, args.choice)

A suppressed argument won't be there (i.e. there won't be an args.choice in the arguments) unless the caller specifically called your script adding --choice="something". If this doesn't happen, args.choice doesn't exist.

If you really want to use SUPPRESS, you're going to have to check whether the argument is in the args Namespace by doing if 'choice' in args: and operate accordingly.

Another option (probably more common) can be using a specific... thing (normally the value None, which is what argparse uses by default, anyway) to be used as a default, and if args.choice is None, then assume it hasn't been provided by the user.

Maybe you could look at this the other way around: You want to ensure selection is provided and leave choice as optional?

You can try to set up the arguments like this:

parser = argparse.ArgumentParser()
parser.add_argument('--selection', '-s', required=True)
parser.add_argument('--choice', '-c')
args = parser.parse_args()

if __name__ == '__main__':
    if args.choice is None:
        print("No choice provided")
    else:
        print(f"Oh, the user provided choice and it's: {args.choice}")

    print(f"And selection HAS TO BE THERE, right? {args.selection}")
Savir
  • 17,568
  • 15
  • 82
  • 136
  • I simply want to allow the option of 'choice'. If the user doesn't use the 'choice' option, then I want the program to run without the 'choice' argument; choice has no detrimental affect on the program. If the user DOES want choice, then it is include where 'choice' is being called. I was unaware that 'None' was the default 'default'. – dvines Oct 25 '22 at 03:58
  • 1
    This is a good answer except for the required optional argument. (Even the name is self-contradictory.) See [this SO question](/q/24180527/4518341). If I were you, I'd make it a positional argument instead. – wjandrea Oct 25 '22 at 16:35