Обработка конкретного формата значения аргумента как устаревшего в argparse

Вопрос или проблема

Я изменяю код 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 для генерации предупреждений.

Вот пример, как вы можете это сделать:

  1. Импортируйте модуль warnings.
  2. Определите функцию, которая будет обрабатывать значение аргумента, проверяя наличие суффикса "m".
  3. Используйте 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, предупреждение не будет сгенерировано.

Оцените материал
Добавить комментарий

Капча загружается...