Есть ли другой способ отображения моих таблиц на основе аргументов, введенных с помощью модуля argparse? - PullRequest
0 голосов
/ 19 января 2019

Цель состоит в том, чтобы отображать таблицы на основе аргументов, введенных в терминале.

Я пытался создать функцию, которая выводила бы каждую отдельную таблицу с использованием операторов if, elif и else, но при этом отображалось бы толькостолы индивидуально.

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


def generate_table(inventory):
    args = arguments()
    data = generate_data(inventory)

    main_headers = ['os_version', 'serial_number']
    lldp_headers = ['lldp']
    out_file = ['outfile']
    main_header = []
    lldp_header = []
    main_table_header = PrettyTable()
    lldp_table_header = PrettyTable()

    for arg in vars(args):
        if arg in main_headers and getattr(args, arg):
            main_header.append(arg)
        elif arg in lldp_headers and getattr(args, arg):
            lldp_header.append(arg)
        elif arg in out_file and getattr(args, arg):
            out_file.append(arg)
            output_file(inventory)

    main_header.insert(0, 'Hostname')
    main_table_header.field_names = main_header
    lldp_table_header.field_names = ['Hostname', 'Neighbor', 'Local Interface', 'Neighbor Interface']

    for hostname, details in data.items():
        row = [hostname]
        for column in main_table_header.field_names[1:]:
            row.append(details[column])
        main_table_header.add_row(row)
        for lldp_data in details['lldp']:
            neighbor = lldp_data['device-id']
            local_int = lldp_data['local-interface']
            neigh_int = lldp_data['connecting-interface']
        lldp_table_header.add_row([hostname, neighbor, local_int, neigh_int])


    print(main_table_header)
    print(lldp_table_header)




def arguments():
    parser = argparse.ArgumentParser(description='Argparse for Training Course.')
    parser.add_argument('-s', '--serial_number', action='store_true', help='Device Serial Numbers')
    parser.add_argument('-v', '--os_version', action='store_true', help='Output Devices OS')
    parser.add_argument('--lldp', action='store_true', help='Output LLDP Data')
    parser.add_argument('--outfile', action='store_true', help='Output to file')
    parser.add_argument('--inventory', help='Inventory File', default=["inventory.yml"], required=True)
    args = parser.parse_args()

    return args


def get_inventory(inventory):
    with open(inventory) as fh:
        yml_file = yaml.load(fh)

    return yml_file


def main():
    args = arguments()
    if not os.path.isfile(args.inventory):
        sys.exit('Please specify valid, readable YAML file with data')

    inventory = get_inventory(args.inventory)
    generate_table(inventory)



if __name__ == '__main__':
    main()
YAML FILE:

csr1:
  username: admin
  password: pass
  transport: restconf
csr2:
  username: admin
  password: pass
  transport: restconf

Это то, что я ожидаю:

python3 rest5.py --inventory inventory.yml -v
+----------+------------+
| Hostname | os_version |
+----------+------------+
| csr1     |    16.6    |
| csr2     |    16.6    |
+----------+------------+

python3 rest5.py --inventory inventory.yml -s
+----------+---------------+
| Hostname | serial_number |
+----------+---------------+
| csr1     |  9KIBQAQ3OPE  |
| csr2     |  9KIBQAQ3OPE  |
+----------+---------------+

python3 rest5.py --inventory inventory.yml -s -v
+----------+---------------+------------+
| Hostname | serial_number | os_version |
+----------+---------------+------------+
| csr1     |  9KIBQAQ3OPE  |    16.6    |
| csr2     |  9KIBQAQ3OPE  |    16.6    |
+----------+---------------+------------+
python3 rest5.py --inventory inventory.yml --lldp
+----------+--------------+-----------------+--------------------+
| Hostname |   Neighbor   | Local Interface | Neighbor Interface |
+----------+--------------+-----------------+--------------------+
| csr1     | csr2.com     |       Gi1       |        Gi1         |
| csr2     | csr1.com     |       Gi1       |        Gi1         |
+----------+--------------+-----------------+--------------------+
python3 rest5.py --inventory inventory.yml --lldp -s -v
+----------+---------------+------------+
| Hostname | serial_number | os_version |
+----------+---------------+------------+
| csr1     |  9KIBQAQ3OPE  |    16.6    |
| csr2     |  9KIBQAQ3OPE  |    16.6    |
+----------+---------------+------------+
+----------+--------------+-----------------+--------------------+
| Hostname |   Neighbor   | Local Interface | Neighbor Interface |
+----------+--------------+-----------------+--------------------+
| csr1     | csr2.com     |       Gi1       |        Gi1         |
| csr2     | csr1.com     |       Gi1       |        Gi1         |
+----------+--------------+-----------------+--------------------+

Фактический результат:

python3 rest5.py --inventory inventory.yml -s
+----------+---------------+
| Hostname | serial_number |
+----------+---------------+
| csr1     |  9KIBQAQ3OPE  |
| csr2     |  9KIBQAQ3OPE  |
+----------+---------------+
+----------+--------------+-----------------+--------------------+
| Hostname |   Neighbor   | Local Interface | Neighbor Interface |
+----------+--------------+-----------------+--------------------+
| csr1     | csr2.com     |       Gi1       |        Gi1         |
| csr2     | csr1.com     |       Gi1       |        Gi1         |
+----------+--------------+-----------------+--------------------+

python3 rest5.py --inventory inventory.yml --lldp
+----------+
| Hostname |
+----------+
| csr1     |
| csr2     |
+----------+
+----------+--------------+-----------------+--------------------+
| Hostname |   Neighbor   | Local Interface | Neighbor Interface |
+----------+--------------+-----------------+--------------------+
| csr1     | csr2.com     |       Gi1       |        Gi1         |
| csr2     | csr1.com     |       Gi1       |        Gi1         |
+----------+--------------+-----------------+--------------------+

Ответы [ 2 ]

0 голосов
/ 19 января 2019
def main():
    args = arguments()
    if not os.path.isfile(args.inventory):
        sys.exit('Please specify valid, readable YAML file with data')

    inventory = get_inventory(args.inventory)
    generate_table(inventory, args)

Вы вызываете get_inventory со строкой, значения из args. Вам также следует вызвать generate_table со значениями от args или args. Переоценка args работает, но делает ваш код более грязным.

def generate_table(inventory, args):
    # args = arguments()    # no need to reevaluate args
    data = generate_data(inventory)
    ...

То же самое можно сделать для output_file, хотя не очевидно, где вы используете args.

В generate_table вы, похоже, используете args в основном в:

for arg in vars(args):
    if arg in main_headers and getattr(args, arg):
        main_header.append(arg)
    elif arg in lldp_headers and getattr(args, arg):
        lldp_header.append(arg)
    elif arg in out_file and getattr(args, arg):
        out_file.append(arg)
        output_file(inventory)

Это неясный кусок кода, трактующий args как пространство имен и словарь. Я думаю, что это просто проверка значений

args.os_version
args.serial_number
args.lldp
args.outfile

Это все store_true, поэтому они всегда будут присутствовать, и значение True/False. Так что вы могли бы

if args.out_file:
    output_file(inventory)

if args.lldp:
    lldp_header.append('lldp')

Но мне не слишком интересно копаться во всех логических шагах.

Убедитесь, что вы понимаете, что произвело parse_args. Во время отладки я рекомендую пользователям

 print(args)

Таким образом, будет меньше сюрпризов.

0 голосов
/ 19 января 2019

Ваш метод generate_table всегда печатает две таблицы, когда вы хотите, чтобы он распечатал только одну:

Ваша оригинальная функция:

def generate_table(inventory):
    args = arguments()
    ... 

    print(main_table_header)
    print(lldp_table_header)

Должно просто измениться на:

def generate_table(inventory):
    args = arguments()
    ... 

    if args.lldp:
        print(lldp_table_header)
    else:
        print(main_table_header)

Другие комментаторы упомянули оптимизации, которые, как правило, улучшают код, который вы должны рассмотреть, например:

  • только генерирует arguments один раз

  • создайте только те таблицы, которые вы собираетесь визуализировать, вместо того, чтобы выполнять действия по созданию таблиц, которые вы не собираетесь печатать в конце

Но, в конце концов, вы были в нескольких шагах от того, чтобы приведенные выше варианты использования работали так, как вы этого хотели.

...