Simple command line argument parser for Python
Project description
QuickParse
Simple command line argument parser for Python
Example
list_things.py:
from quickparse import QuickParse
def list_things(a_list, quickparse):
if quickparse.numeric:
if isinstance(quickparse.numeric, tuple):
print(', '.join(map(str, a_list[:quickparse.numeric[-1]])))
else:
print(', '.join(map(str, a_list[:quickparse.numeric])))
else:
print("How many items? Give a numeric value like '-3'")
commands_config = {
'ls': list_things,
'': lambda: print("Command is missing, use 'ls'"),
}
things = ['apple', 'banana', 'blueberry', 'orange', 'pear', 'pineapple']
QuickParse(commands_config).execute(things)
Run it:
$ python list_things.py ls -5
apple, banana, blueberry, orange, pear
The way it works:
commands_configtells QuickParse to look forlsas a command and calllist_thingson it - when no commands show help- QuickParse parses arguments as normal while
lsis privileged as a command - QuickParse finds
-5so it adds asquickparse.numeric = 5(quickparsebeing theQuickParseinstance that otherwise would come asquickparse = QuickParse(commands_config)) - QuickParse sees
list_thingsbeing associated tols, soquickparse.execute(things)calls it, passing on the arguments ofexecute(..)- one positional argument in this case - since
list_thingsexpects a named argumentquickparse, QuickParse makes sure it passes on the reference to its own instance ofquickparse - if there are multiple numeric flags are given all are passed down with
quickparse.numericin a tuple
GNU Argument Syntax implementation with extensions
GNU Argument Syntax: https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
Extensions
Numeric '-' values
$ my_cmd -12
Numeric '+' values
$ my_cmd +12
Long '-' options - only with explicit config
$ my_cmd -list
By default it becomes -l -i -s -t, but adding QuickParse(options_config = [ ('-list', ) ]) will stop unpacking.
Long '+' options by default
$ my_cmd +list
Equivalent options - using options_config
$ my_cmd -l
is equivalent to
$ my_cmd --list
if adding QuickParse(options_config = [ ('-l', '--list') ])
Command-subcommand hierarchy and function bindings - using commands_config
Defining a random sample from git looks like this:
commands_config = {
'': do_show_help,
'commit': do_commit,
'log': do_log,
'stash': {
'': do_stash,
'list': do_stash_list,
}
}
options_config = [
('-a', '--all'),
]
QuickParse(commands_config, options_config).execute()
Commands are called according to commands_config.
That is $ git log -3 calls do_log
do_log may look like this:
def do_log(quickparse):
print(get_log_entries()[:quickparse.numeric])
If there is a named argument in do_log's signature called quickparse, the instance coming from QuickParse(commands_config, options_config) is passed down holding all the results of parsing.
Parsing happens by using the defaults and applying what options_config adds to it.
Argument Formats
| Argument Format | Example | Remarks |
|---|---|---|
-<number> |
$ my_cmd -12 |
(default) |
+<number> |
$ my_cmd +12 |
(default) |
-<single_letter> |
$ my_cmd -x |
(default) |
+<single_letter> |
$ my_cmd +x |
(default) |
-<single_letter><value> |
$ my_cmd -nFoo |
unpacking is the default: -n -F -ooptions_config needs a type entry saying it expects a value (other than bool) |
+<single_letter><value> |
$ my_cmd +nFoo |
unpacking is the default: +n +F +ooptions_config needs a type entry saying it expects a value (other than bool) |
-<single_letter>=<value> |
$ my_cmd -n=Foo |
(default) |
+<single_letter>=<value> |
$ my_cmd +n=Foo |
(default) |
-<single_letter> <value> |
$ my_cmd -n Foo |
options_config needs a type entry saying it expects a value (other than bool) |
+<single_letter> <value> |
$ my_cmd +n Foo |
options_config needs a type entry saying it expects a value (other than bool) |
-<letters> |
$ my_cmd -abc |
unpacking is the default: -a -b -c if in options_config it's taken as -abc |
+<letters> |
$ my_cmd +abc |
unpacking is the default: +a +b +c if in options_config it's taken as +abc |
-<letters>=<value> |
$ my_cmd -name=Foo |
(default) |
+<letters>=<value> |
$ my_cmd +name=Foo |
(default) |
--<letters> |
$ my_cmd --list |
(default) |
--<letters>=<value> |
$ my_cmd --message=Bar |
(default) |
--<letters> <value> |
$ my_cmd --message Bar |
options_config needs a type entry saying it expects a value (other than bool) |
-- |
$ my_cmd -- --param-anyway |
parameters delimiter (default) |
<letters> means [a-zA-Z] and '-'s not in the first place
An argument like '-a*' gets unpacked if...
- '-a' is not defined to expect a value
- the '*' part has only letters, not '-' or '='
How to change the interpretation of -swing
It can mean (default):
-s -w -i -n -g
or
-s wing / -s=wing
To acheve the latter make the parser aware that '-s' expects a str value:
options_config = [
('-s', str),
]
Make the parser aware that an option expects a value after a space
Add type explicitly in options_config.
For just getting as it is add str.
How to define option types
Use build-in types like int or float, or create a callable that raises exceptions.
Using bool is a special case: parser will not expect a value but explicitly adds an error if one provided.
How to add empty value to an option
--option=
Some commands support '-' as empty value like curl -C - -O http://domanin.com/
To avoid ambiguities this syntax is not supported.
Use --option= instead.
How to define options
options_test.py:
from quickparse import QuickParse
options_config = [
('-u', '--utc', '--universal'),
('-l', '--long'),
('-n', '--name', str),
]
quickparse = QuickParse(options_config=options_config)
print(f'quickparse.options: {quickparse.options}')
print(f'quickparse.errors: {quickparse.errors}')
Run it:
$ python options_test.py
quickparse.options: {}
quickparse.errors: {}
$ python options_test.py -u
quickparse.options: {'-u': True, '--utc': True, '--universal': True}
quickparse.errors: {}
$ python options_test.py -ul
quickparse.options: {'-u': True, '--utc': True, '--universal': True, '-l': True, '--long': True}
quickparse.errors: {}
$ python options_test.py -uln
quickparse.options: {'-u': True, '--utc': True, '--universal': True, '-l': True, '--long': True, '-n': True, '--name': True}
quickparse.errors: {'-n': {'type': 1, 'message': "No value got for '-n/--name' - validator: str"}, '--name': {'type': 1, 'message': "No value got for '-n/--name' - validator: str"}}
$ python options_test.py -ul -nthe_name
quickparse.options: {'-u': True, '--utc': True, '--universal': True, '-l': True, '--long': True, '-n': 'the_name', '--name': 'the_name'}
quickparse.errors: {}
$ python options_test.py -ul -n the_name
quickparse.options: {'-u': True, '--utc': True, '--universal': True, '-l': True, '--long': True, '-n': 'the_name', '--name': 'the_name'}
quickparse.errors: {}
$ python options_test.py -ul -n=the_name
quickparse.options: {'-u': True, '--utc': True, '--universal': True, '-l': True, '--long': True, '-n': 'the_name', '--name': 'the_name'}
quickparse.errors: {}
$ python options_test.py -ul --name the_name
quickparse.options: {'-u': True, '--utc': True, '--universal': True, '-l': True, '--long': True, '--name': 'the_name', '-n': 'the_name'}
quickparse.errors: {}
$ python options_test.py -ul --name=the_name
quickparse.options: {'-u': True, '--utc': True, '--universal': True, '-l': True, '--long': True, '--name': 'the_name', '-n': 'the_name'}
quickparse.errors: {}
Test your command line arguments
quickparse_test_args.py (committed in the repo):
from pprint import pformat
from quickparse import QuickParse
def do_show_help():
print("Executing 'do_show_help'...")
def do_commit():
print("Executing 'do_commit'...")
def do_log(quickparse):
print("Executing 'do_log'...")
def do_stash():
print("Executing 'do_stash'...")
def do_stash_list():
print("Executing 'do_stash_list'...")
commands_config = {
'': do_show_help,
'commit': do_commit,
'log': do_log,
'stash': {
'': do_stash,
'list': do_stash_list,
}
}
options_config = [
('-m', '--message', str),
('-p', '--patch'),
]
quickparse = QuickParse(commands_config, options_config)
print(f'Commands:\n{pformat(quickparse.commands)}')
print(f'Parameters:\n{pformat(quickparse.parameters)}')
print(f'Options:\n{pformat(quickparse.options)}')
print(f'\'-\' numeric argument:\n{pformat(quickparse.numeric)}')
print(f'\'+\' numeric argument:\n{pformat(quickparse.plusnumeric)}')
print(f'Functions to call:\n{pformat(quickparse.to_execute)}')
quickparse.execute()
Error handling
If the parser parameters 'commands_config' or 'options_config' are not valid, ValueError is rased from the underlying AssertionError.
If the arguments are not compliant with the config (e.g. no value provided for an option that requires one) then no exceptions are raised but an errors list is populated on the QuickParse object.
See the error object again from options_test.py
$ python options_test.py -uln
quickparse.options: {'-u': True, '--utc': True, '--universal': True, '-l': True, '--long': True, '-n': True, '--name': True}
quickparse.errors: {'-n': {'type': 1, 'message': "No value got for '-n/--name' - validator: str"}, '--name': {'type': 1, 'message': "No value got for '-n/--name' - validator: str"}}
quickparse.errors dict is about validation of options. These are the types:
ERROR_TYPE_VALIDATION = 0
ERROR_VALUE_NOT_FOUND = 1
ERROR_INCOMPLETE_COMMAND = 2
quickparse.has_errors is also available to check if any errors occurred.
Validation
Well, I still need to elaborate the docs on this but here is a quick example snippet.
quickparse.validate({
'parameters': { 'mincount': 1, },
'options': {
'mandatory': '--branch',
'optional': '--stage',
},
'numeric': { 'maxcount': 0 },
'plusnumeric': { 'maxcount': 0 },
})
assert 'parameters.mincount' not in quickparse.errors, f'Add a target'
assert not quickparse.has_errors, '\n'.join(quickparse.error_messages)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file quickparse-0.9.1.tar.gz.
File metadata
- Download URL: quickparse-0.9.1.tar.gz
- Upload date:
- Size: 14.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.4 CPython/3.8.6 Linux/5.10.10-051010-generic
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86d4b923378a40b3ff030af3b3f7769a6ef4f6ac29eb261d06acfcc0190f4ec5
|
|
| MD5 |
0866ec465c1528ced824b67724cbaf72
|
|
| BLAKE2b-256 |
72cdf1c04e06c3cfb7e65368490f828002438a4c4680c3f245c865150d29a4be
|
File details
Details for the file quickparse-0.9.1-py3-none-any.whl.
File metadata
- Download URL: quickparse-0.9.1-py3-none-any.whl
- Upload date:
- Size: 11.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.4 CPython/3.8.6 Linux/5.10.10-051010-generic
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4578732e6ecbf3dfb54f5900ac825c9548efc02606339c7fcc3d9071be3b8cf5
|
|
| MD5 |
6b091819f5827bb033519dfad86e9edf
|
|
| BLAKE2b-256 |
266f60e2cb2845a6bc0cce6b24ce3a4a150e653c5ea89c8dc40fe11f76032a6e
|