Plac is a wrapper over argparse and works in all versions of
Python starting from Python 2.3 up to Python 3.1.
With blatant immodesty, plac claims to be the easiest to use command
line arguments parser module in the Python world. Its goal is to reduce the
learning curve of argparse from hours to minutes. It does so by
removing the need to build a command line arguments parser by hand:
actually it is smart enough to infer the parser from function
annotations.
Here is a simple example (in Python 3) to whet your appetite:
$ cat example.py
def main(arg: "required argument"):
"do something with arg"
print('Got %s' % arg)
if __name__ == '__main__':
import plac; plac.call(main) # passes sys.argv[1:] to main
$ python example.py -h
usage: example.py [-h] arg
do something with arg
positional arguments:
arg required argument
optional arguments:
-h, --help show this help message and exit
$ python example.py
usage: example.py [-h] arg
example.py: error: too few arguments
$ python example.py arg
Got arg
$ python example.py arg1 arg2
usage: example.py [-h] arg
example.py: error: unrecognized arguments: arg2
You can find in the documentation a lot of other simple and not so simple
examples:
Have you seen http://pypi.python.org/pypi/CLIArgs ? Your module looks surprisingly similar in intent, though perhaps the feature sets don't exactly correspond.
I did not known about CLIargs. The underlying philosophy is the same, to infer the parser from the function signature. Only the implementation is different. Since plac relies on function annotations it has more power, but I guess I must concede that it cannot boast anymore about being the easiest command line argument parser in the world! ;-)
I think your approach with plac is a good one, as it eliminates an intermediate language for options, reusing the Python language's function syntax.
I notice that plac does not support required options, citing the "options should not be required" argument. I suggest that the name "option" is getting in the way for things passed in on the command line that are prefixed with dashes. Think of them just being named parameters. Certainly, Python has named parameters to functions, and they can be required if not specified in the positional manner.
Consider a function/command-line program with 5 arguments. Each argument is required, but as a human, you prefer not to have to remember the order in which they are specified -- you would rather just name each argument. Python supports this concept, as you can just use named parameters for each argument, but plac, optparse, and argprase do not support the same concept for command line program calls, even though they are conceptually equivalent.
> Consider a function/command-line program with 5 arguments. > Each argument is required, but as a human, you prefer not > t to have to remember the order in which they are > specified -- you would rather just name each argument. > Python supports this concept, as you can just use named > d parameters for each argument, but plac, optparse, and > argprase do not support the same concept for command line > program calls, even though they are conceptually > equivalent.
I have two observations.
#1. There is a matter of opinions about the concept of "required options" vs "required named parameters". Everybody is free to have his opinion; personally I would not want to have 5 required named arguments on a command line tool: in that case I would start using a configuration file.
#2. Then there is matter of technical merit. Argparse *do* support required options and therefore plac supports them too:
I wrote my own simple lightweight command line parser for Python (and something similar for several other languages) that I've been using for years. Named items are prefixed with a dash or slash and separated from optional values by a colon or equal sign (eg. "/quiet", "-f:filename" or "/language=en-US") are "options" and all other undecorated things are "parameters." The options go into an object that has an attribute for each option and the paramters go into a list. So for the command line test.py /c test.txt /r /displayname:Testing
> As you see, the feature is there I am not interested in > making it easy to use.
I could care less about Python or a library written in it, but when your first post claims this tool is written with concision and simplicity in mind, as well as aiming to be declarative? You do not seem to be consistent.
How is easy to use separate from your design objectives? As a library designer, defend yourself.
I believe that a library (or a language for that matter) should be opinionated. In other words, the library should not try to be everything to everybody. Making things easy to use means offering a preferred path for using the library, decided by the library designer: only the preferred path should be kept easy to follow, not every possible usage of the library.
Notice that I do not believe the preferred path should be forced, i.e. there should always be a backdoor to do things which were not anticipated by the library author (which is a fallible human).
The feature requested by Matt Gerrans is not in the preferred path of plac: I do not like the concept of required options and I am not interested in making them easy to use. Still, plac offers a way to implement them, but that way is not guaranteed to be nice.
It is just impossible to make everything easy to use. Aiming to simplicity means making tradeoffs; and the difficult thing is to make the right ones, the ones that will satisfy most users. No tradeoff will satisfy *all* users, but okay, library authors can't perform miracles. I think the alternative of trying to please everybody (typical of libraries/languages designed by committee) is much worse, since simplicity of use is nearly guaranteed to be lost.
I agree; programmers do have a habit of having an "engineer's mentality" when designing systems and ultimately compromise "usability" because they want to make everything programmable and give no thought into avoiding hours writing code people should probably avoid using anyway.
I also agree that "required options" are a bad idea; guards are always a bad idea and indicate lack of understanding about what a program should do (IMHO).
As an aside, I like the way PowerShell handles options, but it uses objects as parameters rather than textual parameters. Setting a default value for a parameter n for some program as (Read-Host "Enter a value for n: ") is very productive when prototyping scripts you ideally want to run non-interactively, but need to test interactively in the shell REPL to get a good feel for what it should do.
UPDATE: I have just released plac 0.5. This release is *huge*: the size of plac and of its documentation doubled.
Now plac is much more than a simple command-line arguments parser: it is also a generic tool to write command languages, similar to the cmd module in the standard library, only better.
You define plac commands from Python functions: plac will build a parser from the function signature and interpret the command line accordingly.
There is also a runner to run plac scripts and plac tests, which are pretty similar to Python doctests.
I'm happy with the stone-age module, but I do like your proposition about the need to "scale down" gracefully. I use slightly different terms to describe it: "graceful degradation" is the path to increased complexity and power, which often results in "degradation" of the developer experience. "Scale down" is the flip side and much to be desired.