ABSEIL - alternative of argparse
When writing Python programs, which package do you use for argument parsing?
I beleive most people are using argparse.
In fact, using abseil (absl-py; released from Google) package, argument parsing become much easier and convenient than argparse. In this article I will show you how to use abseil.
Contents
- Contents
- How to install
- Example
- Explanation
- Reasons to use abseil
- More details
- Frequently caused error
How to install
pip install absl-py
Example
Seeing is believing. So I will show abseil 's sample code.
Code
# sample.py from absl import app from absl import flags FLAGS = flags.FLAGS flags.DEFINE_string( 'foo', 'default value', 'help message of this argument.') def main(argv): print('FLAGS.foo is {}'.format(FLAGS.foo)) if __name__ == '__main__': app.run(main)
Result
For example, pass the parameter like below.
$ python sample.py --foo bar
FLAGS.foo is bar
And, You can display a help message with sample.py --help
or sample.py -?
$ python sample.py --help USAGE: sample.py [flags] flags: sample.py: --foo: help message of this argument. (default: 'default value') Try --helpfull to get a list of all flags.
Explanation
I will briefly explain the sample code above.
1. Import absl.app, abls.flags and create a FLAGS instance
from absl import app from absl import flags FLAGS = flags.FLAGS
2. Define the flags. This time we are defining flags to receive in string type
flags.DEFINE_string( 'foo', 'default value', 'help message of this argument.')
3. Call the main function by app.run(main)
if __name__ == '__main__': app.run(main)
4. You can get the parameter with FLAGS.xxx
print('FLAGS.foo is {}'.format(FLAGS.foo))
Pretty easy, right?
Reasons to use abseil
There are three reasons why I use abseil instead of argparse.
It can be written simpler than argparse.
I do not have to write parser = argparse.ArgumentParser()
and parser.parse_args()
.
Help messages are more useful than argparse As you can see the results of the sample execution above, you can see the default value of the flag is also displayed properly in the help message. Since argparse does not show default value.
Arguments of bool type, list type, enum type can be easyly set When you use bool type parameters with argparse, you have to write something like below code.
parser.add_argument('--feature', dest='feature', action='store_true') parser.add_argument('--no-feature', dest='feature', action='store_false') parser.set_defaults(feature=True)
Since there is flags.DEFINE_bool() function in abseil, and you can easily set boolean flag.
For example, if you write below
flags.DEFINE_bool('bar', True, 'some message...')
The arguments --bar
and --nobar
are set automatically.
If you append --nobar
option as run-time argument, FLAGS.bar
will return False
.
Other functions such as flags.DEFINE_list()
and flags.DEFINE_emum()
are also provided, and both are useful.
More details
Functions to define flags
# str, int, float, bool type flags.DEFINE_string('s', 'default value', 'help message of this argument.') flags.DEFINE_integer('i', 1, 'help message of this argument.') flags.DEFINE_float('f', 0.1, 'help message of this argument.') flags.DEFINE_bool('b', True, 'help message of this argument.') # List type # When you give `--hoge x,y`, FLAGS.hoge will be set as ['x', 'y']. flags.DEFINE_list( 'hoge', None, 'help message of this argument.') # Enum type. # In the following cases, if you give a value other than a, b, c you get an error. flags.DEFINE_enum( 'restricted', 'a', ['a', 'b', 'c'], 'help message of this argument.') # alias. --bar is considered as alias of --foo. flags.DEFINE_bool('foo', True, 'help message of this argument.') flags.DEFINE_alias('bar', 'foo')
Get dictionary of flag values.
FLAGS.flag_values_dict()
Set short name of flag.
# You can use -f and --fuge to set FLAGS.fuga. flags.DEFINE_list( 'fuga', None, 'help message of this argument.', short_name='f')
Overwrite flag value.
FLAGS.foo = 'a'
Required flag
if __name__ == '__main__': flags.mark_flags_as_required(['hoge', 'fuga']) app.run(main)
Set flag values from text file
# If you give `--flagfile /path/to/param.txt` at runtime, arguments are read from param.txt. # When command line argument is given, it overrides the value written in param.txt. $ python sample.py --flagfile /path/to/param.txt
In param.txt, write arguments as follows.
--hoge=a --fuga=1
Frequently caused error
Case 1
Traceback (most recent call last): File "./sample.py", line 43, in <module> app.run(main) File "/home/n/anaconda2/envs/absl/lib/python2.7/site-packages/absl/app.py", line 274, in run _run_main(main, args) File "/home/n/anaconda2/envs/absl/lib/python2.7/site-packages/absl/app.py", line 238, in _run_main sys.exit(main(argv)) TypeError: main() takes no arguments (1 given)
How to fix : Replace def main():
with def main(argv):
Case 2
WARNING: Logging before flag parsing goes to stderr. E0606 00:00:59.346868 139914210911616 _flagvalues.py:487] Trying to access flag --s before flags were parsed. Traceback (most recent call last): File "./sample.py", line 44, in <module> main(sys.argv[1:]) File "./sample.py", line 27, in main print('FLAGS.s is {}'.format(FLAGS.s)) File "/home/n/anaconda2/envs/absl/lib/python2.7/site-packages/absl/flags/_flagvalues.py", line 488, in __getattr__ raise _exceptions.UnparsedFlagAccessError(error_message) absl.flags._exceptions.UnparsedFlagAccessError: Trying to access flag --s before flags were parsed.
How to fix : Did you call main
function directly? Call Alternately call app.run(main)
.