Разобрать командную строку с состоянием в Python - PullRequest
0 голосов
/ 12 июля 2020

В некоторых командных строках программы есть состояние, которое применяется к аргументам, следующим за параметром установки состояния (например, аргумент '-' для rm и touch; ffmpeg печально известен синтаксическим анализом аргументов с отслеживанием состояния). Например:

readmulticsv --cols 1,2,4 file1.csv --date_format "%Y-%m-%d" file2.csv --cols 4,3,9 file3.csv file4.csv

Здесь он будет извлекать столбцы 1, 2 и 4 из файлов file1.csv и file2.csv, а затем извлекать столбцы 4, 3 и 9 в в этом порядке из файлов file3.csv и file4.csv. Далее он начнет интерпретировать даты (в первом столбце аргумента --cols) в file1.csv с форматом по умолчанию «% m /% d /% Y», но переключится на «% Y-% m-% d» "для остальных файлов. Мне нужен список списков, где каждый список элементов имеет имя файла и значения соответствующих переменных состояния:

[["file1.csv", "1,2,4", "%m/%d/%Y"],
 ["file2.csv", "1,2,4", "%Y-%m-%d"],
...
]

Реализовать это просто, если вы пройдете sys.argv вручную.

Есть ли способ сделать это с помощью argparse? Моя программа использует argparse для многих других опций и его приятной справочной функции, а весь код написан вокруг его объекта Namespace. Я мог бы использовать parse_known_args () и оставить все остальное на «прогулку», но это исключает --cols, --date_format и файлы из справки и пространства имен. Я попытался найти Action (), но не знаю, что делать дальше. Документы для настройки этого мне не очень понятны, и я не вижу, как получить доступ к существующему состоянию.

Есть ли альтернативный синтаксический анализатор аргументов, который может сделать все это (справка, значения по умолчанию, пространство имен )?

Мое приложение - это программа для расчета фондовой базы, прироста и роста путем чтения файлов транзакций CSV, где инвестиции переводятся между брокерами с различными форматами файлов и изменениями формата за несколько десятилетий. Я мог бы написать конвертер для каждого из старых форматов, но я бы предпочел написать одну программу, которая работает непосредственно с исходными данными.

Спасибо,

- jh -

1 Ответ

0 голосов
/ 13 июля 2020

Одна из важных вещей, которые добавляет argparse по сравнению с предыдущими optparse и getopt, - это возможность обрабатывать positionals. Он использует синтаксис, подобный re, и сопоставление с образцом для выделения строк (из списка sys.argv) позиционным и необязательным (помеченным) аргументам. 1009 * и optional.

С:

--cols 1,2,4 file1.csv --date_format "%Y-%m-%d" file2.csv --cols 4,3,9 file3.csv file4.csv

Я могу представить, что определение

parser.add_argument('--cols', nargs='+', action='append')
parser.add_argument('--date_format', nargs='+', action='append')

приводит к

args.cols = [['1,2,4','file1.csv'], ['4,3,9', 'file3.csv', 'file4.csv']]
args.date_format = [["%Y-%m-%d", 'file2.csv']]

argparse не сохраняет информацию о том, как чередуются параметры cols и date.

У меня возникло искушение собрать имена файлов в позиционных числах, но нет способа упорядочить последовательные позиции между каждым необязательным.

В недавнем предыдущем SO я предложил предварительно заполнить args списками, например

 argparse.Namespace(cols=[[]], date_format=[["%m/%d/%Y"]])

и изменить действие cols, чтобы заменить последний пустой список. Новый date_format обновит как cols, так и date_format, чтобы начать новое «состояние».

Python с использованием разных параметров несколько раз с argparse

В подклассах Action по умолчанию __call__ записывает новое значение (я) в атрибут (с setattr), перезаписывая значение по умолчанию или то, что было записано ранее. Подкласс append, выбирает атрибут (getattr), добавляет к нему и записывает обратно. Классы по умолчанию работают только со своими dest.

Единственное «состояние», к которому Action имеет доступ, - это namespace. Но, вероятно, этого будет достаточно, если вы создадите подклассы настраиваемых действий для извлечения и сохранения соответствующих атрибутов. Пользовательские действия могут даже записывать и читать атрибуты, которые не указаны в вызовах add_argument. (В документации set_defaults используется для добавления атрибута функции для подпараметров.)

Другой подход к настройке - определение нового класса Namespace. По умолчанию используется простой способ отображения самого себя. По возможности argparse использует getattr, hasattr и setattr для взаимодействия с пространством имен, поэтому он накладывает минимальные ограничения на этот класс.

Таким образом, между type функциями, action подклассами, namespace классов, и formatter есть много места для настройки argparse. Но вам нужно изучить код argparse.py. И поймите, что вы мало что можете сделать, чтобы изменить базовую c последовательность синтаксического анализа.

Обработка sys.argv перед синтаксическим анализом - это еще один инструмент, как и пост-обработка пространства имен args.

...