Вопрос или проблема
Я изменяю код argparse
, чтобы он больше не требовал наличие единицы измерения для числового значения, так как единица всегда одна и та же (“m”). Я бы хотел, чтобы код выдавал предупреждение о депрекации только при вызове с окончанием “m” в значении параметра. То есть ./foo.py --bar=1m
должен выдавать предупреждение о том, что окончание “m” устарело, а ./foo.py --bar=1
не должен выдавать такого предупреждения. Как я могу это сделать?
Я попытался установить type=str_to_bar
:
def str_to_bar(value: str) -> Decimal:
number_value = value.removesuffix("m")
if number_value != value:
structlog.get_logger().warning(
"Указание bar с завершающим символом 'm' не будет поддерживаться в будущих версиях. "
"Пожалуйста, используйте обычное десятичное число, например '0.3'.",
DeprecationWarning,
)
return Decimal(number_value)
К сожалению, argparse
рассматривает DeprecationWarning
как фатальную ошибку, так что это не вариант.
Предупреждения о депрекации должны генерироваться с помощью warnings.warn
, а не логгерами. Таким образом, пользователю остается decidir, хочет ли он превратить предупреждение в ошибку, подавить его или захватить его и перенаправить в систему логирования.
Путаница, с которой вы сталкиваетесь, вызвана неожиданным взаимодействием между structlog
и argparse
. Вызов предупреждения в structlog вызовет TypeError
из-за аргумента DeprecationWarning
, и argparse попытается обработать этот TypeError
, полагая, что исключение указывает на то, что для аргумента было предоставлено неверное значение.
>>> structlog.get_logger().warning("foo", DeprecationWarning)
...
TypeError: not all arguments converted during string formatting
Ответ или решение
Чтобы правильно обработать устаревший формат значения аргумента при использовании модуля argparse
, вам нужно активировать предупреждение об устаревании, не вызывая при этом ошибки. Как вы отметили, использование DeprecationWarning
при логировании может привести к ошибкам. Вместо этого рекомендуется использовать модуль warnings
для генерации предупреждений.
Вот пример, как вы можете это сделать:
- Импортируйте модуль
warnings
. - Определите функцию, которая будет обрабатывать значение аргумента, проверяя наличие суффикса "m".
- Используйте
warnings.warn
для генерации предупреждений об устаревании.
Приведенный ниже код демонстрирует этот процесс:
import argparse
import warnings
from decimal import Decimal
def str_to_bar(value: str) -> Decimal:
# Проверяем, есть ли суффикс "m"
if value.endswith("m"):
# Генерируем предупреждение об устаревании
warnings.warn(
"Указание 'bar' с завершающим символом 'm' устарело и в будущих версиях не будет поддерживаться. "
"Пожалуйста, используйте обычное десятичное число, например '0.3'.",
DeprecationWarning
)
# Удаляем суффикс "m" перед преобразованием в Decimal
number_value = value[:-1]
else:
number_value = value
return Decimal(number_value)
def main():
parser = argparse.ArgumentParser(description='Пример обработки аргументов.')
parser.add_argument('--bar', type=str_to_bar, required=True, help='Значение bar в десятичном формате.')
args = parser.parse_args()
# Теперь вы можете использовать args.bar как Decimal
print(f'Значение bar: {args.bar}')
if __name__ == "__main__":
main()
Основные моменты:
- В функции
str_to_bar
мы проверяем, имеет ли значение аргумента суффикс "m". Если да, то вызывает предупреждение, используяwarnings.warn
. - Мы удаляем суффикс "m" перед преобразованием значения в
Decimal
. - С помощью
argparse
мы задаем тип аргумента какstr_to_bar
, и эта функция будет вызвана, когда пользователь введет значение для аргумента--bar
.
Таким образом, при запуске вашего скрипта с аргументом --bar=1m
будет выведено предупреждение об устаревании, но программа не завершится с ошибкой. Однако при вводе только числового значения, например, --bar=1
, предупреждение не будет сгенерировано.