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)