无法捕获 argparse 的异常/错误
Unable to catch exception/ error for argparse
我有以下脚本,其中我定义了一个 logger 和 argparse 实例化函数,然后我在 主要函数。
场景 1: 对于下面的代码,如果将非整数值传递给参数解析器,错误处理将按预期工作。
import argparse
import logging
def set_logger() -> logging.Logger:
dtfmt = '%d-%m-%y %H:%M:%S'
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s :: [%(processName)s] :: %(levelname)s: %(message)s',
datefmt=dtfmt,
handlers=[logging.StreamHandler()])
return logging.getLogger()
def argg() -> argparse.Namespace:
parser = argparse.ArgumentParser(prog='ProgramName',
description="A program that does mircales when it runs. LOL!",
exit_on_error=False)
parser.add_argument('--integers', type=int)
return parser.parse_args()
def main():
logger = set_logger()
try:
print(f'Integer value: {argg().integers} supplied.')
except (AttributeError, argparse.ArgumentError)as e:
logger.error(e)
if __name__ == '__main__':
main()
传递值 'a' 时,记录器生成的错误消息如下所示(预期行为):
09-09-21 00:58:42 :: [MainProcess] :: ERROR: argument --integers: invalid int value: 'a'
场景 2: 但是,如果 argg() 函数如下重新定义,即包含子解析器,则当传递无效值时错误处理将无法工作到参数解析器。
def argg():
parser = argparse.ArgumentParser(prog='ProgramName',
description="A program that does mircales when it runs. LOL!",
exit_on_error=False)
subparsers = parser.add_subparsers(dest='mode')
subparser1 = subparsers.add_parser('regular', help="run program in regular mode")
subparser1.add_argument('-int', '--integers', type=int, required=True)
return parser.parse_args()
在这种情况下传递值 'a' 会导致默认的 argparse 错误,如下所示:
ProgramName regular: error: argument -int/--integers: invalid int value: 'a'
我的问题是,为什么在场景 2(即带有子参数的 argparse)中错误处理会失败(记录器未被调用)?
没有记录器的东西,在 ipython
会话中。你的第一个案例
In [11]: def argg0(argv) -> argparse.Namespace:
...: parser = argparse.ArgumentParser(prog='ProgramName',
...: description="A program that does mircales when it runs. LOL!",
...: exit_on_error=False)
...: parser.add_argument('--integers', type=int)
...: return parser.parse_args(argv)
...:
In [12]: argg0(['--integers','xxx'])
Traceback (most recent call last):
File "/home/paul/mypy/argparse310.py", line 2476, in _get_value
result = type_func(arg_string)
ValueError: invalid literal for int() with base 10: 'xxx'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<ipython-input-12-f7f84a36f9f8>", line 1, in <module>
argg0(['--integers','xxx'])
File "<ipython-input-11-0f7c85331b7b>", line 6, in argg0
return parser.parse_args(argv)
File "/home/paul/mypy/argparse310.py", line 1818, in parse_args
args, argv = self.parse_known_args(args, namespace)
File "/home/paul/mypy/argparse310.py", line 1856, in parse_known_args
namespace, args = self._parse_known_args(args, namespace)
File "/home/paul/mypy/argparse310.py", line 2060, in _parse_known_args
start_index = consume_optional(start_index)
File "/home/paul/mypy/argparse310.py", line 2000, in consume_optional
take_action(action, args, option_string)
File "/home/paul/mypy/argparse310.py", line 1912, in take_action
argument_values = self._get_values(action, argument_strings)
File "/home/paul/mypy/argparse310.py", line 2443, in _get_values
value = self._get_value(action, arg_string)
File "/home/paul/mypy/argparse310.py", line 2489, in _get_value
raise ArgumentError(action, msg % args)
ArgumentError: argument --integers: invalid int value: 'xxx'
和子解析器案例:
In [13]: def argg1(argv):
...: parser = argparse.ArgumentParser(prog='ProgramName',
...: description="A program that does mircales when it runs. LOL!",
...: exit_on_error=False)
...: subparsers = parser.add_subparsers(dest='mode')
...: subparser1 = subparsers.add_parser('regular', help="run program in regular mode")
...: subparser1.add_argument('-int', '--integers', type=int, required=True)
...: return parser.parse_args(argv)
...:
In [15]: argg1(['regular','--integers','xxx'])
usage: ProgramName regular [-h] -int INTEGERS
ProgramName regular: error: argument -int/--integers: invalid int value: 'xxx'
ipython
错误回溯添加:
An exception has occurred, use %tb to see the full traceback.
Traceback (most recent call last):
File "/home/paul/mypy/argparse310.py", line 2476, in _get_value
result = type_func(arg_string)
ValueError: invalid literal for int() with base 10: 'xxx'
...
ArgumentError: argument -int/--integers: invalid int value: 'xxx'
因此 exit_on_error=False
在子解析器的情况下不起作用。
编辑
我刚刚意识到 exit_on_error
确实有效 - 但它必须是 subparser
定义的一部分:
subparser1 = subparsers.add_parser('regular', help="run program in regular mode",exit_on_error=False)
子解析器是使用与常规解析器相同的 class 创建的,因此采用大部分相同的可选参数。它不继承它们;它们必须明确包含在内。我在其他情况下看到过这种情况,例如 help formatter class
.
我有以下脚本,其中我定义了一个 logger 和 argparse 实例化函数,然后我在 主要函数。
场景 1: 对于下面的代码,如果将非整数值传递给参数解析器,错误处理将按预期工作。
import argparse
import logging
def set_logger() -> logging.Logger:
dtfmt = '%d-%m-%y %H:%M:%S'
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s :: [%(processName)s] :: %(levelname)s: %(message)s',
datefmt=dtfmt,
handlers=[logging.StreamHandler()])
return logging.getLogger()
def argg() -> argparse.Namespace:
parser = argparse.ArgumentParser(prog='ProgramName',
description="A program that does mircales when it runs. LOL!",
exit_on_error=False)
parser.add_argument('--integers', type=int)
return parser.parse_args()
def main():
logger = set_logger()
try:
print(f'Integer value: {argg().integers} supplied.')
except (AttributeError, argparse.ArgumentError)as e:
logger.error(e)
if __name__ == '__main__':
main()
传递值 'a' 时,记录器生成的错误消息如下所示(预期行为):
09-09-21 00:58:42 :: [MainProcess] :: ERROR: argument --integers: invalid int value: 'a'
场景 2: 但是,如果 argg() 函数如下重新定义,即包含子解析器,则当传递无效值时错误处理将无法工作到参数解析器。
def argg():
parser = argparse.ArgumentParser(prog='ProgramName',
description="A program that does mircales when it runs. LOL!",
exit_on_error=False)
subparsers = parser.add_subparsers(dest='mode')
subparser1 = subparsers.add_parser('regular', help="run program in regular mode")
subparser1.add_argument('-int', '--integers', type=int, required=True)
return parser.parse_args()
在这种情况下传递值 'a' 会导致默认的 argparse 错误,如下所示:
ProgramName regular: error: argument -int/--integers: invalid int value: 'a'
我的问题是,为什么在场景 2(即带有子参数的 argparse)中错误处理会失败(记录器未被调用)?
没有记录器的东西,在 ipython
会话中。你的第一个案例
In [11]: def argg0(argv) -> argparse.Namespace:
...: parser = argparse.ArgumentParser(prog='ProgramName',
...: description="A program that does mircales when it runs. LOL!",
...: exit_on_error=False)
...: parser.add_argument('--integers', type=int)
...: return parser.parse_args(argv)
...:
In [12]: argg0(['--integers','xxx'])
Traceback (most recent call last):
File "/home/paul/mypy/argparse310.py", line 2476, in _get_value
result = type_func(arg_string)
ValueError: invalid literal for int() with base 10: 'xxx'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<ipython-input-12-f7f84a36f9f8>", line 1, in <module>
argg0(['--integers','xxx'])
File "<ipython-input-11-0f7c85331b7b>", line 6, in argg0
return parser.parse_args(argv)
File "/home/paul/mypy/argparse310.py", line 1818, in parse_args
args, argv = self.parse_known_args(args, namespace)
File "/home/paul/mypy/argparse310.py", line 1856, in parse_known_args
namespace, args = self._parse_known_args(args, namespace)
File "/home/paul/mypy/argparse310.py", line 2060, in _parse_known_args
start_index = consume_optional(start_index)
File "/home/paul/mypy/argparse310.py", line 2000, in consume_optional
take_action(action, args, option_string)
File "/home/paul/mypy/argparse310.py", line 1912, in take_action
argument_values = self._get_values(action, argument_strings)
File "/home/paul/mypy/argparse310.py", line 2443, in _get_values
value = self._get_value(action, arg_string)
File "/home/paul/mypy/argparse310.py", line 2489, in _get_value
raise ArgumentError(action, msg % args)
ArgumentError: argument --integers: invalid int value: 'xxx'
和子解析器案例:
In [13]: def argg1(argv):
...: parser = argparse.ArgumentParser(prog='ProgramName',
...: description="A program that does mircales when it runs. LOL!",
...: exit_on_error=False)
...: subparsers = parser.add_subparsers(dest='mode')
...: subparser1 = subparsers.add_parser('regular', help="run program in regular mode")
...: subparser1.add_argument('-int', '--integers', type=int, required=True)
...: return parser.parse_args(argv)
...:
In [15]: argg1(['regular','--integers','xxx'])
usage: ProgramName regular [-h] -int INTEGERS
ProgramName regular: error: argument -int/--integers: invalid int value: 'xxx'
ipython
错误回溯添加:
An exception has occurred, use %tb to see the full traceback.
Traceback (most recent call last):
File "/home/paul/mypy/argparse310.py", line 2476, in _get_value
result = type_func(arg_string)
ValueError: invalid literal for int() with base 10: 'xxx'
...
ArgumentError: argument -int/--integers: invalid int value: 'xxx'
因此 exit_on_error=False
在子解析器的情况下不起作用。
编辑
我刚刚意识到 exit_on_error
确实有效 - 但它必须是 subparser
定义的一部分:
subparser1 = subparsers.add_parser('regular', help="run program in regular mode",exit_on_error=False)
子解析器是使用与常规解析器相同的 class 创建的,因此采用大部分相同的可选参数。它不继承它们;它们必须明确包含在内。我在其他情况下看到过这种情况,例如 help formatter class
.