Как оформить цикл по опциональным параметрам argparse
В поисках помощи, так как столкнулся с непониманием, как правильно оформить цикл который будет обрабатывать входные аргументы, которые я ввожу через терминал. Задача стоит, на основе введенных аргументов, записать подходящие под условия строки из одного CSV фала в другой.
У меня реализован вариант с вводом или всех параметров, или никакого (что приведет к остановке программы). Я подозреваю что это должен быть цикл, так как у меня изначально реализован сбор данных в список, который потом проверяется на соответствие условий, но поняв как сделать этот цикл с опциональными параметрами, в дальнейшем можно будет избавиться от выгрузки полного списка в память и записывать конкретную строку, которая подходит под условия цикла.
Я пытался сделать вариант с условиями для опциональных параметров, для той реализации которая у меня, но выдает ошибку TypeError: descriptor 'upper' for 'str' objects doesn't apply to a 'NoneType' object, потому что не переданный аргумент не может быть обработан условием. Буду бесконечно благодарён за любой ответ, спасибо!
import argparse
import csv
def check_args():
for args in args_list:
if args is None:
args_list.remove(args)
def make_title():
name_file = ''
templist = []
for var in args_list:
templist.append(var)
name_file = name_file + '-'.join(templist) + ".csv"
return name_file
def read_csv():
results = []
with open('tz_opendata.csv', 'r+') as File:
reader = csv.DictReader(File, delimiter=';')
for line in reader:
if line["BRAND"] == str.upper(args.brand) and line["MAKE_YEAR"] == str.upper(args.year) and \
line["FUEL"] == str.upper(args.fuel) and line["COLOR"] == str.upper(args.color):
results.append(line)
# print(line)
return results
def write_csv(fieldnames, data):
with open(make_title(), "w+", newline='') as csv_file:
writer = csv.DictWriter(csv_file, delimiter=',', fieldnames=fieldnames, extrasaction='ignore')
writer.writeheader()
for row in data:
writer.writerow(row)
print('~~~DONE~~~')
def make_haader():
result = read_csv()
if args.reg_num == 'yes':
fieldnames = ['D_REG', 'BRAND', 'MODEL', 'MAKE_YEAR', 'COLOR', 'FUEL', 'N_REG_NEW']
else:
fieldnames = ['D_REG', 'BRAND', 'MODEL', 'MAKE_YEAR', 'COLOR', 'FUEL']
temp_list = []
for values in result[1:]:
inner_dict = dict(zip(fieldnames, values))
temp_list.append(inner_dict)
write_csv(fieldnames, result)
if __name__ == '__main__':
parser = argparse.ArgumentParser(prog='CAR DATA 1.0', description='Know car data')
parser.add_argument('o', default='tz_opendata.csv', type=str)
parser.add_argument('--brand', type=str)
parser.add_argument('--year', type=str)
parser.add_argument('--fuel', type=str)
parser.add_argument('--color', type=str)
parser.add_argument('--reg_num', type=str)
args = parser.parse_args()
argsdict = vars(args)
args_list = [argsdict['brand'], argsdict['year'], argsdict['color'], argsdict['fuel'], argsdict['reg_num']]
finlist = []
if all(args is None for i in args_list):
print("~~~NOT ENOUGTH ARGS~~~")
else:
check_args()
make_haader()
Ответы (2 шт):
Ну, так если навскидку, то каждое такое сравнение:
line["BRAND"] == str.upper(args.brand) and ...
Нужно заменить на такое:
(args.brand == None or line["BRAND"] == str.upper(args.brand)) and ...
Тогда такие сравнения будут истинны если агрумент не задан, либо задан и сравнение с полем выполняется. Ошибки с upper при этом уже не будет, потому что если в выражении с or истинна левая часть, то правая часть уже не проверяется и не выполняется.
Только не забудьте взять каждое выражение в скобки, потому что без скобок все операторы and выполнятся раньше чем операторы or (у операторов and больше приоритет чем у or).
Можно воспользоваться таким трюком:
if __name__ == '__main__':
upper_str = str.upper
parser = argparse.ArgumentParser(prog='CAR DATA 1.0', description='Know car data')
parser.add_argument('o', default='tz_opendata.csv', type=str)
parser.add_argument('--brand', type=upper_str)
parser.add_argument('--year', type=upper_str)
parser.add_argument('--fuel', type=upper_str)
parser.add_argument('--color', type=upper_str)
parser.add_argument('--reg_num', type=upper_str)
args = parser.parse_args()
После этого argparse сам приведет все параметры, созданные с type=upper_str к верхнему регистру.