How to Write Perfect Python Command-line Interfaces — Learn by Example

So let’s try to use this method…The “beginners” methodsys.argv is a list containing all the arguments typed by the user when running your script (including the script name itself).For example, if I type:> python caesar_script.py –key 23 –decrypt my secret messagepb vhfuhw phvvdjhthe list contains:['caesar_script.py', '–key', '23', '–decrypt', 'my', 'secret', 'message'] So we would loop on this arguments list, looking for a '–key' (or '-k' ) to know the key value, and looking for a '–decrypt' to use the decryption mode (actually by simply using the opposite of the key as the key).Our script would finally look like this piece of code:This script more or less respects the recommendations stated above:There are a default key value and a default modeBasic error cases are handled (no input text provided or unknown arguments)A succinct documentation is printed in these error cases, and when calling the script with no argument:> python caesar_script_using_sys_argv.pyUsage: python caesar.py [ –key <key> ] [ –encrypt|decrypt ] <text>However, this version of the Caesar script is quite long (39 lines, which doesn’t even include the logic of the encryption itself) and ugly.There has to be a better way to parse command line arguments…What about argparse?argparse is the Python standard library module for parsing command-line arguments.Let us see how would our Caesar script look like using argparse :This would respect our guidelines, and provide a more precise documentation and a more interactive error handling than the handmade script above:> python caesar_script_using_argparse.py –encode My messageusage: caesar_script_using_argparse.py [-h] [-e | -d] [-k KEY] [text [text …]]caesar_script_using_argparse.py: error: unrecognized arguments: –encode> python caesar_script_using_argparse.py –help usage: caesar_script_using_argparse.py [-h] [-e | -d] [-k KEY] [text [text …]]positional arguments: textoptional arguments: -h, –help show this help message and exit -e, –encrypt -d, –decrypt -k KEY, –key KEYHowever, regarding the code, I find that — this is a bit subjective — the first lines of my function (from line 7 to line 13), where the arguments are defined, are not very elegant: it is too verbose and programmatic whereas it could be done in a more compact and declarative way.Do better with click!We’re in luck: there is a Python library which offers the same features as argparse (and more), with a prettier code style: its name is click.Here is the third version of our Caesar script, using click:Notice that the arguments and options are now declared in decorators which make them directly accessible as parameters of my function.Let me clarify some subtleties in the above code:The nargs parameter for a script argument specifies the number of successive words expected for this argument (with “a quoted string like this” counting as 1 word)..The default value is 1..Here, nargs=-1 allow providing any number of words.The notation –encrypt/–decrypt allow to define mutually exclusive options (like with the add_mutually_exclusive_group function from argparse) which will result in a boolean parameter.The click.echo is a small utility provided by the library, which does the same as a print but which is compatible with Python 2 and 3, and has some extra features (colors handling, etc.).Adding some confidentialityOur script arguments are supposed to be top secret messages that will be encrypted..Isn’t it ironic to ask the user to type his plain texts directly in his terminal, leaving them in his commands history?A solution to do it in a more secure way is to use a hidden prompt..Or we could read the text from an input file, which would be much more practical for long texts..Or why not let the choice to the user?And let’s do the same for the output: the user could ever save it into a file, or print it in the terminal..This leads us to this last improved version of our Caesar script:What is new in this version?First, notice that I added a help parameter to each argument or option..Since the script becomes a little bit more complex, it allows to add some details about its behavior to the documentation, which now looks like this:> python caesar_script_v2.py –helpUsage: caesar_script_v2.py [OPTIONS]Options: –input_file FILENAME File in which there is the text you want to encrypt/decrypt..If not provided, a prompt will allow you to type the input text..–output_file FILENAME File in which the encrypted/decrypted text will be written..If not provided, the output text will just be printed..-d, –decrypt / -e, –encrypt Whether you want to encrypt the input text or decrypt it.. More details

Leave a Reply