Указывая имена файлов по умолчанию с помощью argparse, но не открывая их в --help? - PullRequest
12 голосов
/ 23 ноября 2011

Допустим, у меня есть скрипт, который выполняет некоторую работу с файлом.Он принимает имя этого файла в командной строке, но если он не указан, по умолчанию используется известное имя файла (скажем, content.txt).С питоном argparse я использую следующее:

parser = argparse.ArgumentParser(description='my illustrative example')
parser.add_argument('--content', metavar='file', 
                     default='content.txt', type=argparse.FileType('r'),
                     help='file to process (defaults to content.txt)')
args = parser.parse_args()
# do some work on args.content, which is a file-like object

Это прекрасно работает.Единственная проблема заключается в том, что, если я запускаю python myscript --help, я получаю ArgumentError, если файла нет (что, я думаю, имеет смысл), и текст справки не отображается.Я бы предпочел не открывать файл, если пользователь просто хочет --help.Есть какой-либо способ сделать это?Я знаю, что мог бы сделать аргумент строкой и сам позаботиться об открытии файла позже (и я этим занимался), но было бы удобно, чтобы argparse позаботился об этом.

Ответы [ 4 ]

12 голосов
/ 23 ноября 2011

Вы можете создать подкласс argparse.FileType:

import argparse
import warnings

class ForgivingFileType(argparse.FileType):
    def __call__(self, string):
        try:
            super(ForgivingFileType,self).__call__(string)
        except IOError as err:
            warnings.warn(err)

parser = argparse.ArgumentParser(description='my illustrative example')
parser.add_argument('--content', metavar='file', 
                     default='content.txt', type=ForgivingFileType('r'),
                     help='file to process (defaults to content.txt)')
args = parser.parse_args()

Это работает без необходимости использования личных методов, таких как ArgumentParser._parse_known_args.

9 голосов
/ 23 ноября 2011

Глядя на код argparse, я вижу:

  • ArgumentParser.parse_args вызывает parse_known_args и следит за тем, чтобы не было никаких ожидающих аргументов для анализа.
  • ArgumentParser.parse_known_args устанавливает значения по умолчанию и вызывает ArgumentParser._parse_known_args

Следовательно, обходной путь должен заключаться в прямом использовании ArgumentParser._parse_known_args для обнаружения -h и после этого, как обычно, ArgumentParser.parse_args.

import sys, argparse
parser = argparse.ArgumentParser(description='my illustrative example', argument_default=argparse.SUPPRESS)
parser.add_argument('--content', metavar='file',
                     default='content.txt', type=argparse.FileType('r'),
                     help='file to process (defaults to content.txt)')
parser._parse_known_args(sys.argv[1:], argparse.Namespace())
args = parser.parse_args()

Обратите внимание, что ArgumentParser._parse_known_args требуется пара параметров: аргументы из командной строки и пространства имен.

Конечно, я бы не рекомендовал этот подход, поскольку он использует преимуществавнутренняя реализация argparse, и это может измениться в будущем.Тем не менее, я не нахожу это слишком грязным, поэтому вы все равно можете использовать его, если считаете, что риски обслуживания окупаются.

2 голосов
/ 22 октября 2016

Использовать стандартный ввод по умолчанию:

parser.add_argument('file', default='-', nargs='?', type=argparse.FileType('r'))
1 голос
/ 23 ноября 2011

Возможно, вы могли бы определить свои собственные type или action в вызове add_argument, который проверяет, существует ли файл, и возвращает дескриптор файла, если он существует, иNone (или что-то еще) в противном случае.

Это потребует от вас также написания некоторого собственного кода, но если значение по умолчанию не всегда может быть использовано, вам, вероятно, придется выполнить некоторую проверку рано или поздно.Как утверждает Мэнни Д., вы можете пересмотреть значение по умолчанию.

...