Skip to content

Commit abcd3e4

Browse files
committed
argparse: Add support for custom argument types.
This commit adds support for optional custom argument type validation to argparse.ArgumentParser, allowing for shorter argument validation code for both simple builtins and complex types. For example, assuming that a particular command line argument must be an integer, using "parser.add_argument('-a', type=int)" will make sure that any value passed to that argument that cannot be converted into an integer will trigger an argument validation error. Signed-off-by: Alessandro Gatti <[email protected]>
1 parent a7c805c commit abcd3e4

File tree

3 files changed

+53
-5
lines changed

3 files changed

+53
-5
lines changed

python-stdlib/argparse/argparse.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,36 @@ class _ArgError(BaseException):
1111

1212

1313
class _Arg:
14-
def __init__(self, names, dest, action, nargs, const, default, help):
14+
def __init__(self, names, dest, action, nargs, const, default, help, type):
1515
self.names = names
1616
self.dest = dest
1717
self.action = action
1818
self.nargs = nargs
1919
self.const = const
2020
self.default = default
2121
self.help = help
22+
self.type = type
23+
24+
def _pop(self, optname, args):
25+
arg = args.pop(0)
26+
if self.type:
27+
try:
28+
return self.type(arg)
29+
except Exception as e:
30+
raise _ArgError("invalid value for %s: %s (%s)" % (optname, arg, str(e)))
31+
return arg
2232

2333
def parse(self, optname, args):
2434
# parse args for this arg
2535
if self.action == "store":
2636
if self.nargs is None:
2737
if args:
28-
return args.pop(0)
38+
return self._pop(optname, args)
2939
else:
3040
raise _ArgError("expecting value for %s" % optname)
3141
elif self.nargs == "?":
3242
if args:
33-
return args.pop(0)
43+
return self._pop(optname, args)
3444
else:
3545
return self.default
3646
else:
@@ -52,7 +62,7 @@ def parse(self, optname, args):
5262
else:
5363
break
5464
else:
55-
ret.append(args.pop(0))
65+
ret.append(self._pop(optname, args))
5666
n -= 1
5767
if n > 0:
5868
raise _ArgError("expecting value for %s" % optname)
@@ -103,6 +113,9 @@ def add_argument(self, *args, **kwargs):
103113
dest = args[0]
104114
if not args:
105115
args = [dest]
116+
arg_type = kwargs.get("type", None)
117+
if arg_type is not None and not callable(arg_type):
118+
raise ValueError("type is not callable")
106119
list.append(
107120
_Arg(
108121
args,
@@ -112,6 +125,7 @@ def add_argument(self, *args, **kwargs):
112125
const,
113126
default,
114127
kwargs.get("help", ""),
128+
arg_type,
115129
)
116130
)
117131

python-stdlib/argparse/manifest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
metadata(version="0.4.0")
1+
metadata(version="0.4.1")
22

33
# Originally written by Damien George.
44

python-stdlib/argparse/test_argparse.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,37 @@
6666
args, rest = parser.parse_known_args(["a", "b", "c", "-b", "2", "--x", "5", "1"])
6767
assert args.a == ["a", "b"] and args.b == "2"
6868
assert rest == ["c", "--x", "5", "1"]
69+
70+
71+
class CustomArgType:
72+
def __init__(self, add):
73+
self.add = add
74+
75+
def __call__(self, value):
76+
return int(value) + self.add
77+
78+
79+
parser = argparse.ArgumentParser()
80+
parser.add_argument("-a", type=int)
81+
parser.add_argument("-b", type=str)
82+
parser.add_argument("-c", type=CustomArgType(1))
83+
try:
84+
parser.add_argument("-d", type=())
85+
assert False
86+
except ValueError as e:
87+
assert str(e) == "type is not callable"
88+
parser.add_argument("-d", type=int, nargs="+")
89+
parser.add_argument("-e", type=CustomArgType(1), nargs="+")
90+
parser.add_argument("-f", type=CustomArgType(1), nargs="?")
91+
args = parser.parse_args(["-a", "123"])
92+
assert args.a == 123
93+
args = parser.parse_args(["-b", "string"])
94+
assert args.b == "string"
95+
args = parser.parse_args(["-c", "123"])
96+
assert args.c == 124
97+
args = parser.parse_args(["-d", "123", "124", "125"])
98+
assert args.d == [123, 124, 125]
99+
args = parser.parse_args(["-e", "123", "124", "125"])
100+
assert args.e == [124, 125, 126]
101+
args = parser.parse_args(["-f", "123"])
102+
assert args.f == 124

0 commit comments

Comments
 (0)