Skip to content

Commit b0398a4

Browse files
authored
bpo-42572: Improve argparse docs for the type parameter. (GH-23849)
1 parent a44ce6c commit b0398a4

File tree

1 file changed

+57
-50
lines changed

1 file changed

+57
-50
lines changed

Doc/library/argparse.rst

Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,63 +1050,70 @@ command-line argument was not present::
10501050
type
10511051
^^^^
10521052

1053-
By default, :class:`ArgumentParser` objects read command-line arguments in as simple
1053+
By default, the parser reads command-line arguments in as simple
10541054
strings. However, quite often the command-line string should instead be
1055-
interpreted as another type, like a :class:`float` or :class:`int`. The
1056-
``type`` keyword argument of :meth:`~ArgumentParser.add_argument` allows any
1057-
necessary type-checking and type conversions to be performed. Common built-in
1058-
types and functions can be used directly as the value of the ``type`` argument::
1055+
interpreted as another type, such as a :class:`float` or :class:`int`. The
1056+
``type`` keyword for :meth:`~ArgumentParser.add_argument` allows any
1057+
necessary type-checking and type conversions to be performed.
10591058

1060-
>>> parser = argparse.ArgumentParser()
1061-
>>> parser.add_argument('foo', type=int)
1062-
>>> parser.add_argument('bar', type=open)
1063-
>>> parser.parse_args('2 temp.txt'.split())
1064-
Namespace(bar=<_io.TextIOWrapper name='temp.txt' encoding='UTF-8'>, foo=2)
1059+
If the type_ keyword is used with the default_ keyword, the type converter
1060+
is only applied if the default is a string.
10651061

1066-
See the section on the default_ keyword argument for information on when the
1067-
``type`` argument is applied to default arguments.
1062+
The argument to ``type`` can be any callable that accepts a single string.
1063+
If the function raises :exc:`ArgumentTypeError`, :exc:`TypeError`, or
1064+
:exc:`ValueError`, the exception is caught and a nicely formatted error
1065+
message is displayed. No other exception types are handled.
10681066

1069-
To ease the use of various types of files, the argparse module provides the
1070-
factory FileType which takes the ``mode=``, ``bufsize=``, ``encoding=`` and
1071-
``errors=`` arguments of the :func:`open` function. For example,
1072-
``FileType('w')`` can be used to create a writable file::
1067+
Common built-in types and functions can be used as type converters:
10731068

1074-
>>> parser = argparse.ArgumentParser()
1075-
>>> parser.add_argument('bar', type=argparse.FileType('w'))
1076-
>>> parser.parse_args(['out.txt'])
1077-
Namespace(bar=<_io.TextIOWrapper name='out.txt' encoding='UTF-8'>)
1078-
1079-
``type=`` can take any callable that takes a single string argument and returns
1080-
the converted value::
1081-
1082-
>>> def perfect_square(string):
1083-
... value = int(string)
1084-
... sqrt = math.sqrt(value)
1085-
... if sqrt != int(sqrt):
1086-
... msg = "%r is not a perfect square" % string
1087-
... raise argparse.ArgumentTypeError(msg)
1088-
... return value
1089-
...
1090-
>>> parser = argparse.ArgumentParser(prog='PROG')
1091-
>>> parser.add_argument('foo', type=perfect_square)
1092-
>>> parser.parse_args(['9'])
1093-
Namespace(foo=9)
1094-
>>> parser.parse_args(['7'])
1095-
usage: PROG [-h] foo
1096-
PROG: error: argument foo: '7' is not a perfect square
1069+
.. testcode::
10971070

1098-
The choices_ keyword argument may be more convenient for type checkers that
1099-
simply check against a range of values::
1071+
import argparse
1072+
import pathlib
11001073

1101-
>>> parser = argparse.ArgumentParser(prog='PROG')
1102-
>>> parser.add_argument('foo', type=int, choices=range(5, 10))
1103-
>>> parser.parse_args(['7'])
1104-
Namespace(foo=7)
1105-
>>> parser.parse_args(['11'])
1106-
usage: PROG [-h] {5,6,7,8,9}
1107-
PROG: error: argument foo: invalid choice: 11 (choose from 5, 6, 7, 8, 9)
1108-
1109-
See the choices_ section for more details.
1074+
parser = argparse.ArgumentParser()
1075+
parser.add_argument('count', type=int)
1076+
parser.add_argument('distance', type=float)
1077+
parser.add_argument('street', type=ascii)
1078+
parser.add_argument('code_point', type=ord)
1079+
parser.add_argument('source_file', type=open)
1080+
parser.add_argument('dest_file', type=argparse.FileType('w', encoding='latin-1'))
1081+
parser.add_argument('datapath', type=pathlib.Path)
1082+
1083+
User defined functions can be used as well:
1084+
1085+
.. doctest::
1086+
1087+
>>> def hyphenated(string):
1088+
... return '-'.join([word[:4] for word in string.casefold().split()])
1089+
...
1090+
>>> parser = argparse.ArgumentParser()
1091+
>>> _ = parser.add_argument('short_title', type=hyphenated)
1092+
>>> parser.parse_args(['"The Tale of Two Cities"'])
1093+
Namespace(short_title='"the-tale-of-two-citi')
1094+
1095+
The :func:`bool` function is not recommended as a type converter. All it does
1096+
is convert empty strings to ``False`` and non-empty strings to ``True``.
1097+
This is usually not what is desired.
1098+
1099+
In general, the ``type`` keyword is a convenience that should only be used for
1100+
simple conversions that can only raise one of the three supported exceptions.
1101+
Anything with more interesting error-handling or resource management should be
1102+
done downstream after the arguments are parsed.
1103+
1104+
For example, JSON or YAML conversions have complex error cases that require
1105+
better reporting than can be given by the ``type`` keyword. An
1106+
:exc:`~json.JSONDecodeError` would not be well formatted and a
1107+
:exc:`FileNotFound` exception would not be handled at all.
1108+
1109+
Even :class:`~argparse.FileType` has its limitations for use with the ``type``
1110+
keyword. If one argument uses *FileType* and then a subsequent argument fails,
1111+
an error is reported but the file is not automatically closed. In this case, it
1112+
would be better to wait until after the parser has run and then use the
1113+
:keyword:`with`-statement to manage the files.
1114+
1115+
For type checkers that simply check against a fixed set of values, consider
1116+
using the choices_ keyword instead.
11101117

11111118

11121119
choices

0 commit comments

Comments
 (0)