The Python Oracle

How to run a Python file with boolean arguments

--------------------------------------------------
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Beneath the City Looping

--

Chapters
00:00 How To Run A Python File With Boolean Arguments
00:58 Answer 1 Score 4
02:04 Accepted Answer Score 4
02:34 Answer 3 Score 1
02:59 Answer 4 Score 1
03:50 Thank you

--

Full question
https://stackoverflow.com/questions/6924...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #sys

#avk47



ANSWER 1

Score 4


I would use argparse for this type of thing. Use a boolean flag argument. I also like to provide a positive and a negative version for ease of use.

import argparse

...

if __name__ == "__main__":
    parser = argparse.ArgumentParser(prog='log-to-pickle')

    parser.add_argument('--imperial-units', dest='imperial_units', action='store_true')
    parser.add_argument('--no-imperial-units', dest='imperial_units', action='store_false')
    parser.set_defaults(imperial_units=True)

    args = parser.parse_args()

    log_to_pickle(args.imperial_units)

Using argparse you'll get some nice help messages too:

$ python3 file.py -h
usage: log-to-pickle [-h] [--imperial-units] [--no-imperial-units]

optional arguments:
  -h, --help           show this help message and exit
  --imperial-units
  --no-imperial-units

Now you can call the application like this:

# These are the same given the default.
$ python3 file.py
$ python3 file.py --imperial-units

Or to do the negative version:

$ python3 file.py --no-imperial-units

If you really want to provide a string argument to the bool flag, then I would make a custom method to transform string to boolean:

import argparse


def bool_arg(val):
    return val.lower() in ('y', 'yes', 't', 'true', 'on', '1')


if __name__ == "__main__":
    parser = argparse.ArgumentParser(prog='log-to-pickle')

    parser.add_argument('--imperial-units', type=bool_arg, default=True)

    args = parser.parse_args()

    print(args.imperial_units)

Examples:

$ python3 file.py --imperial-units y
True

$ python3 file.py --imperial-units True
True

$ python3 file.py --imperial-units 0
False



ACCEPTED ANSWER

Score 4


There are a few wrong things here but the root cause is that the code doesn't use sys.argv correctly. Try printing sys.argv:

if __name__ == "__main__":
    import sys
    print(sys.argv)
$ python3 argv.py imperial_units=True
['argv.py', 'imperial_units=True']

You need to parse the command line arguments.

if __name__ == "__main__":
    if len(sys.argv) <= 1 or sys.argv[1] == "imperial_units=True":
        log_to_pickle(True)
    else:
        log_to_pickle(False)

Take a look at the argparse package for more robust command line argument handling.




ANSWER 3

Score 1


sys.argv provides a list of arguments. You can iterate through it to find an argument that contains "imperial_units". You can then process this to get the boolean.

if __name__ == "__main__":
    #Find arguments which contain imperial_units
    arg = [x.split("=")[1] for x in sys.argv if "imperial_units" in x]
    #If the length is 0, no args were found, default to true
    #Otherwise use value after = and convert it to bool
    arg = True if len(arg) == 0 else bool(arg[0])
    log_to_pickle(arg)



ANSWER 4

Score 1


argparse results in a more user-friendly program with help text and uses an arguably more standard method of dash-delimited parameters. Since you only want one thing, the unit of measure, I think it is best implemented with a choice flag that includes a default, but you could make a single argument such as --use-metric that defaults to False.

#!/usr/bin/env python3
import argparse

parser = argparse.ArgumentParser(description='CSV to Pickle with unit conversion to metric')
parser.add_argument('-u', '--unit', default='imperial', choices=['imperial', 'metric'],
                    help='Source unit type (imperial or metric)')
parser.add_argument('from_file', help="CSV file to convert")
parser.add_argument('to_file', help="Converted Pickle file")

args = parser.parse_args()
print(args.unit)

Options for using the program are

$ ./test.py --help
usage: test.py [-h] [-u {imperial,metric}] from_file to_file

CSV to Pickle with unit conversion to metric

positional arguments:
  from_file             CSV file to convert
  to_file               Converted Pickle file

optional arguments:
  -h, --help            show this help message and exit
  -u {imperial,metric}, --unit {imperial,metric}
                        Source unit type (imperial or metric)

$ ./test.py --unit metric aaa.csv aaa.pkl
metric
$ ./test.py -u imperial aaa.csv aaa.plk
imperial
$ ./test.py aaa.csv aaa.pkl
imperial
$ ./test.py --unit=other aaa.csv aaa.pkl
usage: test.py [-h] [-u {imperial,metric}] from_file to_file
test.py: error: argument -u/--unit: invalid choice: 'other' (choose from 'imperial', 'metric')