The Radiant
The Radiant

Reputation: 55

Menu Class uses menu option from non - instantiated menus

I am trying to create a Menu class for my python CLI application. When a user selects an option, the corresponding function is fired.

from collections import namedtuple

Option = namedtuple('Option', ['label', 'callback'])
class Menu:

    SEPARATOR = '-'

    _title = ''
    _options = []

    def __init__(self, title, options):
        self._title = title

        for option in options:
            self._options.append(Option(option[0], option[1]))

    def header(self, text):
        line = self.SEPARATOR * (len(text) + 2)
        return f"{line}\n {text}\n{line}\n"

    def display(self):
        string = self.header(self._title)

        for i, option in enumerate(self._options):
            string += f"{i + 1} {option.label}\n"

        return string

    def callback(self, i):
        if i <= len(self._options):
            return self._options[i - 1].callback

    def getInput(self):
        incorrect = True
        while incorrect:
            option = int(input('>> '))
            if option < 1 or option > len(self._options):
                print("Invalid Input")
            else:
                incorrect = False
        return self.options[option-1].callback()

My first menu:

mainMenu = Menu.Menu(
        "Main Menu - Please Select an Option", [
        ('Setup Attacker', setupAttacker),
        ('Setup Victim', setupVictim),
        ('Run Attack Simulation', runAttackSim),
        ('View Results', viewResults),
        ('Exit', quitProgram)])

Things were going well until I made my second menu.

setupVictimMenu = Menu.Menu(
    "Setup Victim - Please Select an Option", [
    ('Download Server Software', installServerSoftware),
    ('Open a Port...', openPort),
    ('Send Malicious File', sendMaliciousFile)])

On running the program it gave me this output:

-------------------------------------
 Main Menu - Please Select an Option
-------------------------------------
1 Download Server Software
2 Open a Port...
3 Send Malicious File
4 Setup Attacker
5 Setup Victim
6 Run Attack Simulation
7 View Results
8 Exit

Both menu options were combined! I think the issue has something to do with options variable in the Class Menu. It has taken both lists.

Do note that the second list is a submenu to the first, so I don't understand why the options are combined despite the fact that the submenu isn't instantiated at the point that the first menu is called.

Upvotes: 1

Views: 1542

Answers (1)

Nizam Mohamed
Nizam Mohamed

Reputation: 9230

The _options variable is a class variable. It's shared among instances of Menu class.
Make it an instance variable to make it private to an instance.

class Menu:

    SEPARATOR = "-"

    _title = ""
    # _options = []

    def __init__(self, title, options):
        self._title = title
        self._options = [Option(*option) for option in options]

Upvotes: 1

Related Questions