bpo-42572: Improve argparse docs for the type parameter. (GH-23849)

This commit is contained in:
Raymond Hettinger 2020-12-20 10:14:54 -08:00 committed by GitHub
parent a44ce6c9f7
commit b0398a4b7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 53 additions and 46 deletions

View File

@ -1050,63 +1050,70 @@ command-line argument was not present::
type type
^^^^ ^^^^
By default, :class:`ArgumentParser` objects read command-line arguments in as simple By default, the parser reads command-line arguments in as simple
strings. However, quite often the command-line string should instead be strings. However, quite often the command-line string should instead be
interpreted as another type, like a :class:`float` or :class:`int`. The interpreted as another type, such as a :class:`float` or :class:`int`. The
``type`` keyword argument of :meth:`~ArgumentParser.add_argument` allows any ``type`` keyword for :meth:`~ArgumentParser.add_argument` allows any
necessary type-checking and type conversions to be performed. Common built-in necessary type-checking and type conversions to be performed.
types and functions can be used directly as the value of the ``type`` argument::
>>> parser = argparse.ArgumentParser() If the type_ keyword is used with the default_ keyword, the type converter
>>> parser.add_argument('foo', type=int) is only applied if the default is a string.
>>> parser.add_argument('bar', type=open)
>>> parser.parse_args('2 temp.txt'.split())
Namespace(bar=<_io.TextIOWrapper name='temp.txt' encoding='UTF-8'>, foo=2)
See the section on the default_ keyword argument for information on when the The argument to ``type`` can be any callable that accepts a single string.
``type`` argument is applied to default arguments. If the function raises :exc:`ArgumentTypeError`, :exc:`TypeError`, or
:exc:`ValueError`, the exception is caught and a nicely formatted error
message is displayed. No other exception types are handled.
To ease the use of various types of files, the argparse module provides the Common built-in types and functions can be used as type converters:
factory FileType which takes the ``mode=``, ``bufsize=``, ``encoding=`` and
``errors=`` arguments of the :func:`open` function. For example,
``FileType('w')`` can be used to create a writable file::
>>> parser = argparse.ArgumentParser() .. testcode::
>>> parser.add_argument('bar', type=argparse.FileType('w'))
>>> parser.parse_args(['out.txt'])
Namespace(bar=<_io.TextIOWrapper name='out.txt' encoding='UTF-8'>)
``type=`` can take any callable that takes a single string argument and returns import argparse
the converted value:: import pathlib
>>> def perfect_square(string): parser = argparse.ArgumentParser()
... value = int(string) parser.add_argument('count', type=int)
... sqrt = math.sqrt(value) parser.add_argument('distance', type=float)
... if sqrt != int(sqrt): parser.add_argument('street', type=ascii)
... msg = "%r is not a perfect square" % string parser.add_argument('code_point', type=ord)
... raise argparse.ArgumentTypeError(msg) parser.add_argument('source_file', type=open)
... return value parser.add_argument('dest_file', type=argparse.FileType('w', encoding='latin-1'))
parser.add_argument('datapath', type=pathlib.Path)
User defined functions can be used as well:
.. doctest::
>>> def hyphenated(string):
... return '-'.join([word[:4] for word in string.casefold().split()])
... ...
>>> parser = argparse.ArgumentParser(prog='PROG') >>> parser = argparse.ArgumentParser()
>>> parser.add_argument('foo', type=perfect_square) >>> _ = parser.add_argument('short_title', type=hyphenated)
>>> parser.parse_args(['9']) >>> parser.parse_args(['"The Tale of Two Cities"'])
Namespace(foo=9) Namespace(short_title='"the-tale-of-two-citi')
>>> parser.parse_args(['7'])
usage: PROG [-h] foo
PROG: error: argument foo: '7' is not a perfect square
The choices_ keyword argument may be more convenient for type checkers that The :func:`bool` function is not recommended as a type converter. All it does
simply check against a range of values:: is convert empty strings to ``False`` and non-empty strings to ``True``.
This is usually not what is desired.
>>> parser = argparse.ArgumentParser(prog='PROG') In general, the ``type`` keyword is a convenience that should only be used for
>>> parser.add_argument('foo', type=int, choices=range(5, 10)) simple conversions that can only raise one of the three supported exceptions.
>>> parser.parse_args(['7']) Anything with more interesting error-handling or resource management should be
Namespace(foo=7) done downstream after the arguments are parsed.
>>> parser.parse_args(['11'])
usage: PROG [-h] {5,6,7,8,9}
PROG: error: argument foo: invalid choice: 11 (choose from 5, 6, 7, 8, 9)
See the choices_ section for more details. For example, JSON or YAML conversions have complex error cases that require
better reporting than can be given by the ``type`` keyword. An
:exc:`~json.JSONDecodeError` would not be well formatted and a
:exc:`FileNotFound` exception would not be handled at all.
Even :class:`~argparse.FileType` has its limitations for use with the ``type``
keyword. If one argument uses *FileType* and then a subsequent argument fails,
an error is reported but the file is not automatically closed. In this case, it
would be better to wait until after the parser has run and then use the
:keyword:`with`-statement to manage the files.
For type checkers that simply check against a fixed set of values, consider
using the choices_ keyword instead.
choices choices