How can I specify a minimum or maximum floating point argument using argprase
? I'd like to be able to provide a command-line argument between a min and max floating point value.
The closest thing I can find is the choices
option in add_argument()
, but that only specifies allowable values for the argument.
parser.add_argument("L", type=float, choices=range(2))
The command-line argument 0.5
for L fails:
invalid choice: 0.5 (choose from 0, 1)
Here is a list of floating-point numbers we can call the max() function on. Out of all the floating-point values, max() finds 105.8 as the largest.
To add an optional argument, simply omit the required parameter in add_argument() . args = parser. parse_args()if args.
The argparse module provides a convenient interface to handle command-line arguments. It displays the generic usage of the program, help, and errors. The parse_args() function of the ArgumentParser class parses arguments and adds value as an attribute dest of the object.
You can (and should) use a custom type function. It's much more user friendly.
def range_limited_float_type(arg):
""" Type function for argparse - a float within some predefined bounds """
try:
f = float(arg)
except ValueError:
raise argparse.ArgumentTypeError("Must be a floating point number")
if f < MIN_VAL or f > MAX_VAL:
raise argparse.ArgumentTypeError("Argument must be < " + str(MAX_VAL) + "and > " + str(MIN_VAL))
return f
parser.add_argument(
'-f',
'--float',
type=range_limited_float_type,
help='Your argument description'
)
Based on the nice solution from @rdas I created a new solution that allows dynamic specification of a float range that should be checked by ArgumentParser.
def float_range(mini,maxi):
"""Return function handle of an argument type function for
ArgumentParser checking a float range: mini <= arg <= maxi
mini - minimum acceptable argument
maxi - maximum acceptable argument"""
# Define the function with default arguments
def float_range_checker(arg):
"""New Type function for argparse - a float within predefined range."""
try:
f = float(arg)
except ValueError:
raise argparse.ArgumentTypeError("must be a floating point number")
if f < mini or f > maxi:
raise argparse.ArgumentTypeError("must be in range [" + str(mini) + " .. " + str(maxi)+"]")
return f
# Return function handle to checking function
return float_range_checker
You can use this function as a dynamic argument type generator in ArgumentParser:
parser = ArgumentParser(description='%(prog)s: My programm')
parser.add_argument('--Temperature', type=float_range(8,25),
help='Set target temperature between [8°C .. 25°C].')
The function float_range(mini,maxi)
creates a local context where mini
and maxi
are known variables. Inside this context function float_range_checker()
is defined and a handle to it returned. When ArgumentParser
calls this function handle, the context with the values provided at calling float_range()
is restored and the range check can take place.
After playing around with this, the simplest answer is to handle the command-line input validation of minimum or maximum values outside of argprase
.
This leaves writing a function and conditional to check the float value. Exit the program if the conditional is met:
import sys
# function to print error to stderr
def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs
# input validation
if args.L <=0:
eprint("Input error. Length is less than 0. Please enter a positive length. Exiting.")
sys.exit(1)
Inspired from the already given answers, here's a more general solution that extends to all types that can be created from a string input and with working '<' and '>' operators:
def ranged_type(value_type, min_value, max_value):
"""
Return function handle of an argument type function for ArgumentParser checking a range:
min_value <= arg <= max_value
Parameters
----------
value_type - value-type to convert arg to
min_value - minimum acceptable argument
max_value - maximum acceptable argument
Returns
-------
function handle of an argument type function for ArgumentParser
Usage
-----
ranged_type(float, 0.0, 1.0)
"""
def range_checker(arg: str):
try:
f = value_type(arg)
except ValueError:
raise argparse.ArgumentTypeError(f'must be a valid {value_type}')
if f < min_value or f > max_value:
raise argparse.ArgumentTypeError(f'must be within [{min_value}, {min_value}]')
return f
# Return function handle to checking function
return range_checker
You can use it for both floats and ints, but is not limited to that:
parser.add_argument('--float_example',
type=ranged_type(float, 0.0, 1.0))
parser.add_argument('--int_example',
type=ranged_type(int, -5, 5))
Even works with strings
parser.add_argument('--str_example',
type=ranged_type(str, "a", "d"))
A little test/proof-of-concept:
parser = argparse.ArgumentParser(prog='argtest')
parser.add_argument('--float_example',
type=ranged_type(float, 0.0, 1.0))
parser.add_argument('--int_example',
type=ranged_type(int, -5, 5))
parser.add_argument('--str_example',
type=ranged_type(str, "a", "d"))
print(parser.parse_args())
With the following results:
> python argtest.py --float_example 0.5 --str_example b --int_example 4
Namespace(float_example=0.5, int_example=4, str_example='b')
> python argtest.py --float_example -0.5
usage: argtest [-h] [--float_example FLOAT_EXAMPLE] [--int_example INT_EXAMPLE] [--str_example STR_EXAMPLE]
argtest: error: argument --float_example: must be within [0.0, 1.0]
> python argtest.py --int_example 12
usage: argtest [-h] [--float_example FLOAT_EXAMPLE] [--int_example INT_EXAMPLE] [--str_example STR_EXAMPLE]
argtest: error: argument --int_example: must be within [-5, 5]
> python argtest.py --str_example g
usage: argtest [-h] [--float_example FLOAT_EXAMPLE] [--int_example INT_EXAMPLE] [--str_example STR_EXAMPLE]
argtest: error: argument --str_example: must be within [a, d]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With