python argparse add_argument_group required - python-3.x

In this question
argparse: require either of two arguments
I find a reference to the solution I want, but it isn't right.
I need at least 1 of 2 options to be present, option1, option2 or both...
The add_argument_group function doesn't have a required argument.
The add_mutually_exclusive function has it, but it forces me to choose between the 2 options, which is not what I want.
rds,

argument_group just controls the help display. It does not affect the parsing or check for errors. mutually_exclusive_group affects usage display and tests for occurrence, but as you note, its logic is not what you want.
There is a Python bug issue requesting some form of nested 'inclusive' group. But a general form that allows nesting and all versions of and/or/xor logic is not a trivial addition.
I think your simplest solution is to test the args after parsing. If there is a wrong mix of defaults, then raise an error.
Assuming the default for both arguments is None:
if args.option1 is None and args.option2 is None:
parser.error('at least one of option1 and option2 is required')
What would be meaningful usage line? required mutually exclusive' uses(opt1 | opt2).(opt1 & opt2)might indicate that both are required. Your case is anon-exclusive or`
usage: PROG [-h] (--opt1 OPT1 ? --opt2 OPT2)

Related

Builder with optional source

I want to make a Builder with one or more optional sources.
I tried this:
env.Append(BUILDERS = {'my_builder': Builder(action = Action(do_something))})
def do_something(target, source, env):
if source[1]:
do_optional_stuff(source[1])
do_other_stuff(target, source[0])
...
env.my_builder(target.txt, [source1, None]) # Fails
env.my_builder(target.txt, [source2, source3]) # Okay
The trouble is, I get 'NoneType' object has no attribute 'get_ninfo' when I pass in None, because scons is expecting Node arguments, and None isn't acceptable.
Is there anything I can do?
Edit:
As noted in the answer below, it's possible to solve this for the simple case of one optional argument, by varying the length of source list. This doesn't work for making arbitrary arguments optional, so I'd still be interested in a way to do that.
Instead of adding a bogus element, check the length of the source list (or better yet, iterate over the list starting after the first element):
def do_something(target, source, env):
if len(source) > 1:
do_optional_stuff(source[1])
# or:
# for opt_src in source[1:]:
# do_optional_stuff(opt_src)
do_main_stuff(target, source[0])
env.Append(BUILDERS = {'my_builder': Builder(action = Action(do_something))})
env.my_builder('target-2.txt', ['foo.txt'])
env.my_builder('target-1.txt', ['foo.txt', 'bar.txt'])
One issue with this approach is that you need to ensure that your sources are listed in the right order. Depending on the details of what you're doing, you might be able to filter the source list by matching file names or extensions. After all, this is Python code, you have the full power of the language at your disposal.

Can Python use a functions default parameter when an inline if fails when calling it?

If I have a variable that has a value I don't want passed to a function, is it possible to do it without several ifs, especially if there are several variables that may or may not need to be passed in?
Take the following:
def test(param=""):
...do stuff
x = None
test(x if x else ?)
^
What can i put here so it
defaults to the default in
the function definition?
If this isn't possible, is there a quick way of doing this when there are multiple variables that may or may not need to be passed in rather than a lot of ifs?
Basic answer:
if(x): test(x)
else: test()
With *args you can pass in as many variables as you want but I don't think that will help you. The best I can think of is multiple ifs (Python doesn't allow overloading unfortunately).
That would look like:
if x:
if y:
if z: test(x,y,z)
else: test(x,y)
else: test(x)
else: test()
The reason you can't call test(x,z) or test(y) for example is because your method assumes a certain order in the signature so you wouldn't be able to specify which arg you are passing in at function call. In Java you could do it with overloading and different argument types, but not here afaik.

Implementing a switch/command like -h

It seems like it is possible to create optional arguments with argparse that "override" otherwise required arguments (be it positional or required options).
A example would be the --help/-h switch, which just displays the help and exit. Now I need to implement behaviour exactly like this ; I need a switch/option that can be used without using any of the otherwise required arguments.
Take a look at how the 'help' switch is implemented:
self.add_argument(
default_prefix+'h', default_prefix*2+'help',
action='help', default=SUPPRESS,
help=_('show this help message and exit'))
You need to provide an action that short circuits argument processing; the 'help' action does this by exiting the program.

Turn off abbreviation in getopt_long (optarg.h)?

Is it possible to turn off abbreviation in getopt_long()? From the man page:
Long option names may be abbreviated if the abbreviation is unique or is an exact match for >some defined option.
I want to do this because the specification I have received for a piece of code requires full-length exact match of the flags, and there are many flags.
Codeape,
It appears there isn't a way to disable the abbreviation feature. You aren't alone in wishing for this feature. See: http://sourceware.org/bugzilla/show_bug.cgi?id=6863
Unfortunately, It seems the glibc developers don't want the option as the bug report linked above was resolved with "WONTFIX". You may be out of luck here :-\
If you use argp_parse() instead of getopt() (highly reccommended, BTW), you can access the exact flag entered by the user through
state->argv[ state->next - 2 ]
It's a bit of a hack, but should work.
This is not perfect solution but you can check exact arg given by a user after calling getopt_long() (normally within switch) like below:
if (strcmp(argv[optind-1], "--longoption") == 0)
optind points a next argument that you need to process. Thus, you can access the original arg using optind-1.

Can IDL evaluate strings as code?

Is there any functionality in IDL that will allow it to evaluate a a string as code?
Or, failing that, is there a nice, dynamic way of including /KEYWORD in functions? For example, if I wanted to ask them for what type of map projection the user wants, is there a way to do it nicely, without large if/case statements for the /Projection_Type keyword it needs?
With even a small number of user options, the combinations would cause if/case statements to get out of hand very quickly to handle all the possible options.
The best bet is to use a case statement because you can't trust that your user is going to type in the same string for Projection_Type that you're expecting as in the keyword.
Though if you are set on doing something like this, there is the EXECUTE function that treats a string as an IDL statement:
Result = EXECUTE(String [, QuietCompile] [, QuietExecution])
Edited to add, there's also CALL_FUNCTION and CALL_PROCEDURE that are faster but maybe less flexible. Look them all up in the IDL help and see what works for you.

Resources