Heya fellows,
This is part 3 of the multi-part series "The Evolution of a Script". The code of this post can be found on Github (see here).
One of the big benefits of using argparse is that it generates a usage help (a --help
flag) automatically. It's common practice to separate the events which are triggered by flags from the creation of the argumentparser. Here's a argparse template I often use.
import argparse
def main(argv=None):
parser = build_parser()
args = parser.parse_args(argv)
if args.arg_name:
pass
return 0
def build_parser():
parser = argparse.ArgumentParser()
# positional/optional arguments:
parser.add_argument()
return parser
def run_main():
try:
sys.exit(main())
except Exception as e:
sys.stderr.write(e)
sys.exit(1)
if __name__ == '__main__':
run_main()
If you're wondering where the arguments from outside are passed into the script: the default value of the argv
identifier is None. Argparse knows then internally that it has to use the arguments from outside.
When converting our script into an argparse tool we can throw all the logic away which informs the user about incorrect usage. All this is now done by argparse
! We wrap argparse around our script:
#!/usr/bin/python
import argparse
import requests
import collections
import sys
def main(argv=None):
parser = build_parser()
args = parser.parse_args(argv)
url = ''
if args.URL:
url = args.URL
if ('http://' or 'https://' or 'http://www.' or 'https://www.') not in url:
if url[:4] == 'www.':
url = url[4:]
url = 'http://' + url
try:
resp = requests.get(url)
except requests.exceptions.RequestException as e:
print(f'Response Failed.')
return 1
header = dict(collections.OrderedDict(resp.headers))
body = resp.text
for section in sorted(header.items()):
print(f"{section[0]}: {section[1]}")
print()
print(body)
return 0
def build_parser():
parser = argparse.ArgumentParser(
prog='tihttp',
description='A tiny HTTP client for sending GET requests.'
)
parser.add_argument('URL',action='store',)
return parser
def run_main():
try:
sys.exit(main())
except Exception as e:
sys.stderr.write(e)
sys.exit(1)
if __name__ == '__main__':
run_main()
Adding the -H
, -B
flags and the boolean logic returns a more sophisticated version of our script:
#!/usr/bin/python
import argparse
import requests
import collections
import sys
def main(argv=None):
parser = build_parser()
args = parser.parse_args(argv)
url = ''
if args.URL:
url = args.URL
if ('http://' or 'https://' or 'http://www.' or 'https://www.') not in url:
if url[:4] == 'www.':
url = url[4:]
url = 'http://' + url
try:
resp = requests.get(url)
except requests.exceptions.RequestException as e:
print(f'Response Failed.')
return 1
header = dict(collections.OrderedDict(resp.headers))
body = resp.text
if args.body and not args.header:
print(body)
return 0
if args.header and not args.body:
for section in sorted(header.items()):
print(f"{section[0]}: {section[1]}")
return 0
if (args.header and args.body) or (not args.header and not args.body):
for section in sorted(header.items()):
print(f"{section[0]}: {section[1]}")
print()
print(body)
return 0
return 1
def build_parser():
parser = argparse.ArgumentParser(
prog='tihttp',
description=f'A tiny HTTP client for sending GET requests.'
)
# positional arguments:
parser.add_argument(
'URL',
action='store',
)
# optional arguments:
parser.add_argument(
'-H',
'--header-only',
dest='header',
action='store_true',
help='Prints only the header of the Response.')
parser.add_argument(
'-B',
'--body-only',
dest='body',
action='store_true',
help='Prints only the body of the Response.')
return parser
def run_main():
try:
sys.exit(main())
except Exception as e:
sys.stderr.write(e)
sys.exit(1)
if __name__ == '__main__':
run_main()
Adding the help flag returns now a nicely formatted usage help!
$ tihttp --help
usage: tihttp [-h] [-H] [-B] URL
A tiny HTTP client for sending GET and POST requests.
positional arguments:
URL
optional arguments:
-h, --help show this help message and exit
-H, --header-only Prints only the header of the Response.
-B, --body-only Prints only the body of the Response.
Top comments (0)