|
38 | 38 | Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) { |
39 | 39 | link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1); |
40 | 40 | }); |
41 | | - </script><div id=content class=content><main><div class=sidetoc><nav class=pagetoc></nav></div><h1 id=python-cli-application><a class=header href=#python-cli-application>Python CLI application</a></h1><p>In this section, you'll see how to implement a CLI application using Python features, instead of relying on shell features. First, you'll learn how to work with command line arguments using the <code>sys</code> module. Followed by <code>argparse</code> module, which is specifically designed for creating CLI applications.<h2 id=sysargv><a class=header href=#sysargv>sys.argv</a></h2><p>Command line arguments passed when executing a Python program can be accessed using the <code>sys.argv</code> list. The first element (index <code>0</code>) contains the name of the Python script or <code>-c</code> or empty string, depending on how the interpreter was called. See <a href=https://docs.python.org/3/library/sys.html#sys.argv>docs.python: sys.argv</a> for details.<p>Rest of the elements will have the command line arguments, if any were passed along the script to be executed. The data type of <code>sys.argv</code> elements is <code>str</code> class. The <code>eval()</code> function allows to execute a string as a Python instruction. Here's an example:<pre><code class=language-bash>$ python3.9 -c 'import sys; print(eval(sys.argv[1]))' '23 ** 2' |
| 41 | + </script><div id=content class=content><main><div class=sidetoc><nav class=pagetoc></nav></div><h1 id=python-cli-application><a class=header href=#python-cli-application>Python CLI application</a></h1><p>In this section, you'll see how to implement a CLI application using Python features, instead of relying on shell features. First, you'll learn how to work with command line arguments using the <code>sys</code> module. Followed by <code>argparse</code> module, which is specifically designed for creating CLI applications.<h2 id=sysargv><a class=header href=#sysargv>sys.argv</a></h2><p>Command line arguments passed when executing a Python program can be accessed using the <code>sys.argv</code> list. The first element (index <code>0</code>) contains the name of the Python script or <code>-c</code> or empty string, depending on how the interpreter was called. See <a href=https://docs.python.org/3/library/sys.html#sys.argv>docs.python: sys.argv</a> for details.<p>Rest of the elements will have the command line arguments, if any were passed along the script to be executed. The data type of <code>sys.argv</code> elements is <code>str</code> class. The <code>eval()</code> function allows you to execute a string as a Python instruction. Here's an example:<pre><code class=language-bash>$ python3.9 -c 'import sys; print(eval(sys.argv[1]))' '23 ** 2' |
42 | 42 | 529 |
43 | 43 |
|
44 | 44 | # bash shortcut |
|
47 | 47 | 529 |
48 | 48 | $ pc '0x2F' |
49 | 49 | 47 |
50 | | -</code></pre><blockquote><p><img src=../images/warning.svg alt=warning> <img src=../images/warning.svg alt=warning> Using <code>eval()</code> function isn't recommended if the input passed to it isn't under your control, for example an input typed by a user from a website application. The arbitrary code execution issue would apply to the <code>bash</code> shortcuts seen in previous section as well, because the input argument is interpreted without any sanity check. However, for the purpose of this calculator project, it is assumed that you are the sole user of the application. See <a href=https://stackoverflow.com/questions/2371436/evaluating-a-mathematical-expression-in-a-string>stackoverflow: evaluating a mathematical expression</a> for more details about the dangers of using <code>eval()</code> function and alternate ways to evaluate a string as mathematical expression.</blockquote><h2 id=argparse><a class=header href=#argparse>argparse</a></h2><p>Quoting from <a href=https://docs.python.org/3/library/argparse.html>docs.python: argparse</a>:<blockquote><p>The <code>argparse</code> module makes it easy to write user-friendly command-line interfaces. The program defines what arguments it requires, and <code>argparse</code> will figure out how to parse those out of <code>sys.argv</code>. The <code>argparse</code> module also automatically generates help and usage messages and issues errors when users give the program invalid arguments.</blockquote><h2 id=argparse-initialization><a class=header href=#argparse-initialization>argparse initialization</a></h2><p>If this is your first time using the <code>argparse</code> module, it is recommended to understand the initialization instructions and see the effect they provide by default. Quoting from <a href=https://docs.python.org/3/library/argparse.html>docs.python: argparse</a>:<blockquote><p>The <code>ArgumentParser</code> object will hold all the information necessary to parse the command line into Python data types.</blockquote><blockquote><p><code>ArgumentParser</code> parses arguments through the <code>parse_args()</code> method. This will inspect the command line, convert each argument to the appropriate type and then invoke the appropriate action.</blockquote><pre><code class=language-python># arg_help.py |
| 50 | +</code></pre><blockquote><p><img src=../images/warning.svg alt=warning> <img src=../images/warning.svg alt=warning> Using <code>eval()</code> function isn't recommended if the input passed to it isn't under your control, for example an input typed by a user from a website application. The arbitrary code execution issue would apply to the <code>bash</code> shortcuts seen in previous section as well, because the input argument is interpreted without any sanity check.<p>However, for the purpose of this calculator project, it is assumed that you are the sole user of the application. See <a href=https://stackoverflow.com/q/2371436/4082052>stackoverflow: evaluating a mathematical expression</a> for more details about the dangers of using <code>eval()</code> function and alternate ways to evaluate a string as mathematical expression.</blockquote><h2 id=argparse><a class=header href=#argparse>argparse</a></h2><p>Quoting from <a href=https://docs.python.org/3/library/argparse.html>docs.python: argparse</a>:<blockquote><p>The <code>argparse</code> module makes it easy to write user-friendly command-line interfaces. The program defines what arguments it requires, and <code>argparse</code> will figure out how to parse those out of <code>sys.argv</code>. The <code>argparse</code> module also automatically generates help and usage messages and issues errors when users give the program invalid arguments.</blockquote><h2 id=argparse-initialization><a class=header href=#argparse-initialization>argparse initialization</a></h2><p>If this is your first time using the <code>argparse</code> module, it is recommended to understand the initialization instructions and see the effect they provide by default. Quoting from <a href=https://docs.python.org/3/library/argparse.html>docs.python: argparse</a>:<blockquote><p>The <code>ArgumentParser</code> object will hold all the information necessary to parse the command line into Python data types.<p><code>ArgumentParser</code> parses arguments through the <code>parse_args()</code> method. This will inspect the command line, convert each argument to the appropriate type and then invoke the appropriate action.</blockquote><pre><code class=language-python># arg_help.py |
51 | 51 | import argparse |
52 | 52 |
|
53 | 53 | parser = argparse.ArgumentParser() |
|
141 | 141 | print(result) |
142 | 142 | except (NameError, SyntaxError): |
143 | 143 | sys.exit("Error: Not a valid input expression") |
144 | | -</code></pre><p>The <code>type</code> parameter for <code>add_argument()</code> method allows you to specify what data type should be applied for that option. The <code>-f</code> option is used here to set the precision for floating-point output. The code doesn't actually check if the output is floating-point type, that is left as an exercise for you.<p>The <code>-b</code>, <code>-o</code>, <code>-x</code> and <code>-v</code> options are intended as boolean data type. Using <code>action="store_true"</code> indicates that the associated attribute should be set to <code>False</code> as their default value. When the option is used from the command line, their value will be set to <code>True</code>. The <code>-b</code>, <code>-o</code> and <code>-x</code> options are used here to get the output in binary, octal and hexadecimal formats respectively. The <code>-v</code> option will print both the input expression and the evaluated result.<p>The help documentation for this script is shown below. By default, uppercase of the option name will be used to describe the value expected for that option. Which is why you see <code>-f F</code> here. You can use <code>metavar='precision'</code> to change it to <code>-f precision</code> instead.<pre><code class=language-bash>$ python3.9 options.py -h |
| 144 | +</code></pre><p>The <code>type</code> parameter for <code>add_argument()</code> method allows you to specify what data type should be applied for that option. The <code>-f</code> option is used here to set the precision for floating-point output. The code doesn't actually check if the output is floating-point type, that is left as an exercise for you.<p>The <code>-b</code>, <code>-o</code>, <code>-x</code> and <code>-v</code> options are intended as boolean data types. Using <code>action="store_true"</code> indicates that the associated attribute should be set to <code>False</code> as their default value. When the option is used from the command line, their value will be set to <code>True</code>. The <code>-b</code>, <code>-o</code> and <code>-x</code> options are used here to get the output in binary, octal and hexadecimal formats respectively. The <code>-v</code> option will print both the input expression and the evaluated result.<p>The help documentation for this script is shown below. By default, uppercase of the option name will be used to describe the value expected for that option. Which is why you see <code>-f F</code> here. You can use <code>metavar='precision'</code> to change it to <code>-f precision</code> instead.<pre><code class=language-bash>$ python3.9 options.py -h |
145 | 145 | usage: options.py [-h] [-f F] [-b] [-o] [-x] [-v] ip_expr |
146 | 146 |
|
147 | 147 | positional arguments: |
|
223 | 223 | print(result) |
224 | 224 | except (NameError, SyntaxError): |
225 | 225 | sys.exit("Error: Not a valid input expression") |
226 | | -</code></pre><p>The <code>nargs</code> parameter allows to specify how many arguments can be accepted with a single action. You can use an integer value to get that many arguments as a list or use specific regular expression like metacharacter to indicate varying number of arguments. The <code>ip_expr</code> argument is made optional here by setting <code>nargs</code> to <code>?</code>.<p>If <code>ip_expr</code> isn't passed as an argument by the user, the attribute will get <code>None</code> as the value. The <code>-</code> character is often used to indicate <code>stdin</code> as the input data. So, if <code>ip_expr</code> is <code>None</code> or <code>-</code>, the code will try to read a line from <code>stdin</code> as the input expression. The <code>strip()</code> string method is applied to the <code>stdin</code> data mainly to prevent newline from messing up the output for <code>-v</code> option. Rest of the code is the same as seen before.<p>The help documentation for this script is shown below. The only difference is that the input expression is now optional as indicated by <code>[ip_expr]</code>.<pre><code class=language-bash>$ python3.9 py_calc.py -h |
| 226 | +</code></pre><p>The <code>nargs</code> parameter allows to specify how many arguments can be accepted with a single action. You can use an integer value to get that many arguments as a list or use specific regular expression like metacharacters to indicate varying number of arguments. The <code>ip_expr</code> argument is made optional here by setting <code>nargs</code> to <code>?</code>.<p>If <code>ip_expr</code> isn't passed as an argument by the user, the attribute will get <code>None</code> as the value. The <code>-</code> character is often used to indicate <code>stdin</code> as the input data. So, if <code>ip_expr</code> is <code>None</code> or <code>-</code>, the code will try to read a line from <code>stdin</code> as the input expression. The <code>strip()</code> string method is applied to the <code>stdin</code> data mainly to prevent newline from messing up the output for <code>-v</code> option. Rest of the code is the same as seen before.<p>The help documentation for this script is shown below. The only difference is that the input expression is now optional as indicated by <code>[ip_expr]</code>.<pre><code class=language-bash>$ python3.9 py_calc.py -h |
227 | 227 | usage: py_calc.py [-h] [-f F] [-b] [-o] [-x] [-v] [ip_expr] |
228 | 228 |
|
229 | 229 | positional arguments: |
|
0 commit comments