argparse support of/by argparse

Chris Angelico rosuav at gmail.com
Thu Jul 15 01:11:37 EDT 2021


On Thu, Jul 15, 2021 at 2:57 PM Dan Stromberg <drsalists at gmail.com> wrote:
>
>
> On Mon, Jul 12, 2021 at 12:34 PM Chris Angelico <rosuav at gmail.com> wrote:
>>
>> On Tue, Jul 13, 2021 at 5:22 AM lucas <lucas at bourneuf.net> wrote:
>> > Running CPython on it will raise a TypeError, and running Mypy on it
>> > will indicate that no issues were found.
>> >
>> > I was wondering if there is any way for me to have mypy detecting the
>> > args.n type, based on the type keyword of the parser.add_argument function ?
>> >
>> > It appears that some type annotations were added to tierce party
>> > modules, provided by mypy itself. Is there a technical issue preventing
>> > such work to be made for argparse (or other CLI ; i didn't find anything
>> > for others either)
>> >
>>
>> Seems complicated, since it depends on a lot of run-time information.
>> What if you flip the problem on its head? Instead of creating the
>> argparser and letting that govern the types, maybe create a dataclass,
>> and then programmatically build the parser.
>
>
> This is why I eschew argparse.  I instead frequently do something like:
>
> def usage(retval):
>     """Output a usage message."""
>     if retval:
>         write = sys.stderr.write
>     else:
>         write = sys.stdout.write
>
>     write(f'{sys.argv[0]} --age 50 --help\n')
>
>     sys.exit(retval)
>
>
> def main():
>     """Compute maximum heart rate as a function of age."""
>     age = -1
>     while sys.argv[1:]:
>         if sys.argv[1] == '--age':
>             age = float(sys.argv[2])
>             del sys.argv[1]
>         elif sys.argv[1] in ('-h', '--help'):
>             usage(0)
>         else:
>             sys.stderr.write(f'{sys.argv[0]}: unrecognized option: {sys.argv[1]}\n')
>             usage(1)
>         del sys.argv[1]
>
>     if age == -1:
>         sys.stderr.write('--age is a required option\n')
>         usage(1)
>
>
> It is of course a little more typing, but tools like mypy and pylint are much more effective this way.  This is a small program, but in a large one, this approach can really help with correctness.
>
> If someone has a mypy extension/plugin that can do argparse as well, I may switch.  Until then....
>

The more complicated the program, the more you lose by this approach.
Yes, mypy is satisfied with your code, but your argument parsing is
more rigid and you don't get all the other benefits of argparse. Plus
it's all too easy to make a copy and paste error, where you make a new
parameter that accidentally puts its value into the same variable as
an old parameter, or something.

Much better to make a wrapper around argparse. I've made good use of
clize [1], and have made ad-hoc wrappers for various purposes. Try
adding mypy support to something like that instead - it's likely to be
a lot easier. In fact, since clize primarily uses function arguments,
it'd probably Just Work™ for the most part, although I haven't tried.

[1] https://pypi.org/project/clize/

ChrisA


More information about the Python-list mailing list