0

I am trying to display a menu for a group of routers that is described by a dictionary that contains pieces of information about their status. To do this, I have a function that takes the dictionary routers that contain the device information as input. The dictionary is converted into a list of dictionary objects, called router_list, sorted by the value of device name, with the use of a for-loop. All the devices are saved into the menu_text variable, which in turn is used to enumerate and print the devices.

When I run this code I get this error:

 python3 menu.py 
Traceback (most recent call last):
  File "menu.py", line 28, in <module>
    'password': '2020'
  File "menu.py", line 6, in show_menu
    router_list.append("%s. %s " % ((i+2), value['name'],))
TypeError: string indices must be integers

Here's my code:

def show_menu(routers):
    router_list = []
    i = 0
    for key, value in enumerate(routers):           
        router_list.append("%s. %s " % ((i+2), value['name'],))
        i = i + 1

    menu_text = '\n'.join(router_list)

    print(("""
---------------------------------------------------------
-----------------------------------------------------

0.EXIT
1.CONFIG ALL
"""+ menu_text +"""
---------------------------------------------------------
          """))

if __name__ == '__main__':
    show_menu({
    'name': 'cisco_ios',
    'ip': '192.168.122.217',
    'username': 'admin',
    'password': '2020'
     })
Azeem
  • 11,148
  • 4
  • 27
  • 40
  • How many routers info do you intend to use? The menu would show only the `name` of the router, right? – Azeem May 02 '20 at 03:37
  • https://www.google.com/search?q=TypeError%3A+string+indices+must+be+integers – Joe May 02 '20 at 04:39
  • Does this answer your question? [Why am I seeing "TypeError: string indices must be integers"?](https://stackoverflow.com/questions/6077675/why-am-i-seeing-typeerror-string-indices-must-be-integers) – Joe May 02 '20 at 04:39
  • its depend on the environment sir, actually, i want to used with another function to sand some configuration on the topology by selecting a number from the list menu – Abdelhak Boumezrag May 02 '20 at 19:49

2 Answers2

1

While looping over a dictionary using enumerate(), you get index and key, not key and value. And, value['name'] would result in an error as value doesn't represent the dictionary, it is the key (name, ip, etc. in your case).

For looping over the key/value pair, you can use dict.items() like this:

for k, v in dict.items():
    print(k, v)

Relevant thread: enumerate() for dictionary in python


As you're passing only one router information as dictionary i.e. routers, you don't need to loop over it to extract the name of the router.

You can simply use routers['name'] and you're done!

Example (live):

def show_menu(routers):
    print(("""
---------------------------------------------------------
0.EXIT
1.CONFIG ALL
2."""+ routers['name'] +"""
---------------------------------------------------------
          """))

if __name__ == '__main__':
    show_menu({
    'name': 'cisco_ios',
    'ip': '192.168.122.217',
    'username': 'admin',
    'password': '2020'
     })

Output:

---------------------------------------------------------
0.EXIT
1.CONFIG ALL
2.cisco_ios
---------------------------------------------------------

But, if there are multiple routers then you can use a list of dictionaries denoting routers and loop over it using for like this (live):

def show_menu(routers):
    router_list = []
    i = 0
    for router in routers:
        router_list.append("%s. %s " % ((i+2), router['name'],))
        i = i + 1

    menu_text = '\n'.join(router_list)

    print(("""
---------------------------------------------------------
0.EXIT
1.CONFIG ALL
"""+ menu_text +"""
---------------------------------------------------------
          """))

if __name__ == '__main__':
    show_menu([{
        'name': 'cisco_ios',
        'ip': '192.168.122.217',
        'username': 'admin',
        'password': '2020'
     },
     {
        'name': 'cisco_ios_123',
        'ip': '192.168.xxx.xxx',
        'username': 'admin',
        'password': '2021'
     }
     ])

Output:

---------------------------------------------------------
0.EXIT
1.CONFIG ALL
2. cisco_ios 
3. cisco_ios_123 
---------------------------------------------------------
Azeem
  • 11,148
  • 4
  • 27
  • 40
  • this is true but i have to enumerate those dicts for the selecting – Abdelhak Boumezrag May 02 '20 at 19:58
  • @AbdelhakBoumezrag: Why is that? How do you get that dictionary of router info? If there are multiple routers then what would you get? A single dictionary with all of the routers? Is that right? – Azeem May 03 '20 at 02:59
0

You should pass a list of dictionaries to show_menu(), for example

routers = [
    {
        'name': 'cisco_ios',
        'ip': '192.168.122.217',
        'username': 'admin',
        'password': '2020'
     },
]
show_menu(routers)

The reason is that, in your show_menu() code, you assume that value is a dictionary, so the argument for routers should be a list of dictionaries.

liginity
  • 311
  • 3
  • 7
  • yeah, this is true think you, but actually i want to used with another function to sand some configuration on the topology by selecting a number from the list-menu to refer which device – Abdelhak Boumezrag May 02 '20 at 19:52
  • sorry for late response. I am not very clear about your need, but if you want to use a number to select a router, then the list of router dictionaries should work, as the list index could be the same as the router number. – liginity May 06 '20 at 12:48