예제 #1
0
def parse_old_menu(menu_data):
    """
    Take an old-style menuData dictionary and return a CursesMenu

    :param dict menu_data:
    :return: A new CursesMenu
    :rtype: CursesMenu
    """
    menu_title = menu_data['title']
    menu = CursesMenu(menu_title)
    for item in menu_data["options"]:
        item_type = item["type"]
        item_title = item["title"]
        if item_type == menuItem.COMMAND:
            item_command = item["command"]
            menu.append_item(CommandItem(item_title, item_command, menu))
        elif item_type == menuItem.FUNCTION:
            item_function = item["function"]
            menu.append_item(FunctionItem(item_title, item_function, menu))
        elif item_type == menuItem.EXITMENU:
            menu.append_item(ExitItem(item_title, menu))
        elif item_type == menuItem.NUMBER:
            menu.append_item(SelectionItem(item_title, menu))
        elif item_type == menuItem.MENU:
            new_menu = parse_old_menu(item)
            menu.append_item(SubmenuItem(item_title, menu, new_menu))

    return menu
예제 #2
0
def parse_old_menu(menu_data):
    """
    Take an old-style menuData dictionary and return a CursesMenu

    :param dict menu_data:
    :return: A new CursesMenu
    :rtype: CursesMenu
    """
    menu_title = menu_data['title']
    menu = CursesMenu(menu_title)
    for item in menu_data["options"]:
        item_type = item["type"]
        item_title = item["title"]
        if item_type == menuItem.COMMAND:
            item_command = item["command"]
            menu.append_item(CommandItem(item_title, item_command, menu))
        elif item_type == menuItem.FUNCTION:
            item_function = item["function"]
            menu.append_item(FunctionItem(item_title, item_function, menu))
        elif item_type == menuItem.EXITMENU:
            menu.append_item(ExitItem(item_title, menu))
        elif item_type == menuItem.NUMBER:
            menu.append_item(SelectionItem(item_title, menu))
        elif item_type == menuItem.MENU:
            new_menu = parse_old_menu(item)
            menu.append_item(SubmenuItem(item_title, menu, new_menu))

    return menu
    def test_action(self):
        root_menu = CursesMenu("root_menu", "test_action")
        submenu1 = CursesMenu("submenu1", "test_action")
        submenu2 = CursesMenu("submenu2", "test_action")
        submenu_item_1 = SubmenuItem("submenu_item_1",
                                     submenu1,
                                     menu=root_menu)
        submenu_item_2 = SubmenuItem("submenu_item_2",
                                     submenu2,
                                     menu=root_menu)

        root_menu.append_item(submenu_item_1)
        root_menu.append_item(submenu_item_2)

        root_menu.start()
        root_menu.wait_for_start(timeout=10)
        self.assertIs(CursesMenu.currently_active_menu, root_menu)
        submenu_item_1.action()
        submenu1.wait_for_start(timeout=10)
        self.assertIs(CursesMenu.currently_active_menu, submenu1)
        CursesMenu.currently_active_menu.exit()
        submenu1.join(timeout=10)
        self.assertIs(CursesMenu.currently_active_menu, root_menu)
        submenu_item_2.action()
        submenu2.wait_for_start(timeout=10)
        self.assertIs(CursesMenu.currently_active_menu, submenu2)
예제 #4
0
def submenu_logging(menu_obj):
    submenu = CursesMenu("Logging Configuration")
    q1_item = FunctionItem("Do you want to turn enable logging?", input,
                           ['yes'])
    q2_item = FunctionItem(
        "If yes, do you want logging to stdout or a log file?", input,
        ['FILE'])
    submenu.append_item(q1_item)
    submenu.append_item(q2_item)
    submenu_item = SubmenuItem("Show a submenu", submenu, menu=menu_obj)
    return submenu_item
예제 #5
0
def create_menu(list_dict_stories, type_new):
    title = 'Pynews - {} stories'.format(type_new.capitalize())
    menu = CursesMenu(title, 'Select the new and press enter')
    msg = 'This new does not have an URL'
    for story in list_dict_stories:
        title = clean_title(story['title'])
        if 'url' in story:
            item = FunctionItem(title, url_open, args=[story['url']])
        else:
            item = FunctionItem(title, lambda x: print(x), args=[msg])
        menu.append_item(item)
    return menu
예제 #6
0
def create_menu(list_dict_stories, type_new):
    title = 'Pynews - {} stories'.format(type_new.capitalize())
    menu = CursesMenu(title, 'Select the new and press enter')
    msg = 'This new does not have an URL'
    for story in list_dict_stories:
        title = clean_title(story['title'])
        if 'url' in story:
            item = FunctionItem(title, url_open, args=[story['url']])
        else:
            item = FunctionItem(title, lambda x: print(x), args=[msg])
        menu.append_item(item)
    return menu
예제 #7
0
def submenu_backup(menu_obj):
    submenu = CursesMenu("Access Key Backup")
    q1_item = FunctionItem(
        "Do you want to retain a copy of newly created access keys?", input,
        ["yes"])
    q2_item = FunctionItem(
        "Enter the directory where a backup copy of the access keys should be stored",
        input, ["~/Backup"])
    submenu.append_item(q1_item)
    submenu.append_item(q2_item)
    submenu_item = SubmenuItem("Show a submenu", submenu, menu=menu_obj)
    return submenu_item
예제 #8
0
def generate_menu(tasks):
    """ Create menu for process selection """
    menu = CursesMenu("Select something to kill him!")

    # a CommandItem runs a console command
    for pid, name in tasks.items():
        label = "{:<8} - {}".format('[' + str(pid) + ']', name[:40])
        command = "kill {}".format(pid)

        menu.append_item(cmitems.CommandItem(label, command))

    # show the menu and allow the user to interact
    menu.show()
예제 #9
0
def generate_menu(menu=None, menu_cfg=None, parent_title=None):
    if not menu_cfg:
        menu_cfg = c.get_menu()

    if not menu:
        title = get_string(menu_cfg, 'title')
        subtitle = get_string(menu_cfg, 'subtitle', params=parent_title)

        menu = CursesMenu(title, subtitle)

    options = menu_cfg['options']

    if type(options) == str and get_string(menu_cfg, 'type') == 'submenu':
        options_list = c.get_config()[options]
        for option in options_list:
            if 'on_item_select' in menu_cfg:
                title = get_string(menu_cfg, 'title')
                subtitle = get_string(menu_cfg['on_item_select'], 'subtitle', params=option)

                submenu = CursesMenu(title, subtitle)
                option_menu = generate_menu(menu_cfg=menu_cfg['on_item_select'], parent_title=option)
                item = SubmenuItem(option, option_menu, menu=submenu)
            else:
                item = FunctionItem(option, getattr(c.get_action_module(), menu_cfg['action']), [option])  # TODO allow for customisation of module name
            menu.append_item(item)

    else:
        for option in menu_cfg['options']:

            cmd_type = get_string(option, 'type')
            title = get_string(option, 'title')
            action = get_string(option, 'action')

            subtitle = get_string(option, 'subtitle')

            if cmd_type == 'function':
                item = FunctionItem(title, getattr(actions, action))

            elif cmd_type == 'submenu':
                submenu = CursesMenu(title, subtitle)
                item = SubmenuItem(title, submenu, menu=menu)
                generate_menu(submenu, option, title)
            else:
                item = MenuItem(title)

            menu.append_item(item)

    return menu
예제 #10
0
class Menu:
    def __init__(self, recipes):
        self.recipes = recipes

        self.title = 'PyVegan - List of Recipes'
        self.menu = CursesMenu(self.title, 'Select one and press enter')
        self.error_msg = 'This search isn\'t a valid one'

    def build(self):
        for recipe in self.recipes:
            if recipe.link:
                item = FunctionItem(recipe.title, url_open, args=[recipe.link])
            else:
                item = FunctionItem(recipe.title,
                                    lambda x: print(x),
                                    args=[self.error_msg])
            self.menu.append_item(item)

    def show(self):
        self.menu.show()
예제 #11
0
def main():
    """ Builds main menu, branches to submenus """

    # parent menu
    menu = CursesMenu("Local Configuration Menu", "keyup Project")

    try:
        submenu_backup = submenu_backup(menu)
        submenu_logging = submenu_logging(menu)

        # assemble main menu
        menu.append_item(submenu_backup)
        menu.append_item(submenu_logging)

        menu.show()
        user_selection = menu.selected_option
    except Exception as e:
        print('Unknown Exception: %s. Exit' % str(e))
        return False
    return True
예제 #12
0
    def display_commands(self, user=None):
        """[displats all commands for user]
        """

        if user:
            menu = CursesMenu("Spotify Collobrative Playlist",
                              "User: "******"Spotify Collobrative Playlist",
                              "User",
                              show_exit_option=True)
        sl1 = SelectionItem("Choose Active Playlist", 1)
        sl2 = SelectionItem("Add new song to playlist", 2)
        sl3 = SelectionItem("List Playlists", 3)
        sl4 = SelectionItem("Print Songs in Playlist", 4)
        sl5 = SelectionItem("Create Playlist", 5)
        sl6 = SelectionItem("Exit", 6)
        menu.append_item(sl1)
        menu.append_item(sl2)
        menu.append_item(sl3)
        menu.append_item(sl4)
        menu.append_item(sl5)
        menu.append_item(sl6)
        menu.start()
        menu.join()
        return menu.returned_value
    def test_action(self):
        root_menu = CursesMenu("root_menu", "test_action")
        submenu1 = CursesMenu("submenu1", "test_action")
        submenu2 = CursesMenu("submenu2", "test_action")
        submenu_item_1 = SubmenuItem("submenu_item_1", submenu1, menu=root_menu)
        submenu_item_2 = SubmenuItem("submenu_item_2", submenu2, menu=root_menu)

        root_menu.append_item(submenu_item_1)
        root_menu.append_item(submenu_item_2)

        root_menu.start()
        root_menu.wait_for_start(timeout=10)
        self.assertIs(CursesMenu.currently_active_menu, root_menu)
        submenu_item_1.action()
        submenu1.wait_for_start(timeout=10)
        self.assertIs(CursesMenu.currently_active_menu, submenu1)
        CursesMenu.currently_active_menu.exit()
        submenu1.join(timeout=10)
        self.assertIs(CursesMenu.currently_active_menu, root_menu)
        submenu_item_2.action()
        submenu2.wait_for_start(timeout=10)
        self.assertIs(CursesMenu.currently_active_menu, submenu2)
예제 #14
0
    def run(self):
        menu = CursesMenu("Openstack Toolset", "Restore OpenStack Virtual Machine Block Device from SAN - By Real World")
        options = ['Restore State']

        for idx, item in enumerate(options):
            menu.append_item(SelectionItem(item, idx))

        submenu = CursesMenu("Contact the Author.")
        contact = SubmenuItem("Author: Karl Kloppenborg", submenu=submenu)
        contact2 = SubmenuItem("Email: [email protected]", submenu=submenu)
        submenu.append_item(contact)
        submenu.append_item(contact2)

        sub = SubmenuItem("Help!", submenu, menu=menu)
        menu.append_item(sub)

        menu.show()
        return menu.selected_option
예제 #15
0
    def create_menu(self) -> None:
        # Create the menu
        self.menu = CursesMenu("PyMeterReader Configuration Wizard",
                               "Choose item to configure")

        function_item = FunctionItem("Volkszähler Gateway",
                                     self.input_gw, ["Enter URL: "],
                                     should_exit=True)
        self.menu.append_item(function_item)

        for meter in self.meters:
            meter_menu = CursesMenu(
                f"Connect channels for meter {meter.meter_id} at {meter.meter_address}",
                "By channel")
            for channel in meter.channels:
                map_menu = CursesMenu(
                    f"Choose uuid for {channel.channel_name}")
                for choice in self.gateway_channels:
                    map_menu.append_item(
                        FunctionItem(f"{choice.uuid}: {choice.title}",
                                     self.__assign,
                                     [meter, channel, choice.uuid, '30m'],
                                     should_exit=True))
                map_menu.append_item(
                    FunctionItem("Enter private UUID",
                                 self.__assign, [meter, channel, None, '30m'],
                                 should_exit=True))
                meter_menu.append_item(
                    SubmenuItem(
                        f"{channel.channel_name}: {channel.value} {channel.unit}",
                        map_menu, self.menu))
            submenu_item = SubmenuItem(f"Meter {meter.meter_id}", meter_menu,
                                       self.menu)

            self.menu.append_item(submenu_item)

        view_item = FunctionItem("View current mapping", self.__view_mapping)
        self.menu.append_item(view_item)

        save_item = FunctionItem("Save current mapping", self.__safe_mapping)
        self.menu.append_item(save_item)

        register_service = FunctionItem(
            "Register PymeterReader as systemd service.",
            self.__register_service)
        self.menu.append_item(register_service)

        reset_item = FunctionItem("Reset all mappings", self.__clear)
        self.menu.append_item(reset_item)

        self.menu.show()
예제 #16
0
# Create the menu
menu = CursesMenu("Title", "Subtitle")

# Create some items

# MenuItem is the base class for all items, it doesn't do anything when selected
menu_item = MenuItem("Menu Item")

# A FunctionItem runs a Python function when selected
function_item = FunctionItem("Call a Python function", input,
                             ["Enter an input"])

# A CommandItem runs a console command
command_item = CommandItem("Run a console command", "touch hello.txt")

# A SelectionMenu constructs a menu from a list of strings
selection_menu = SelectionMenu(["item1", "item2", "item3"])

# A SubmenuItem lets you add a menu (the selection_menu above, for example)
# as a submenu of another menu
submenu_item = SubmenuItem("Submenu item", selection_menu, menu)

# Once we're done creating them, we just add the items to the menu
menu.append_item(menu_item)
menu.append_item(function_item)
menu.append_item(command_item)
menu.append_item(submenu_item)

# Finally, we call show to show the menu and allow the user to interact
menu.show()
예제 #17
0
class Wizard:
    def __init__(self):
        self.url = "http://localhost/middleware.php"
        self.gateway = VolkszaehlerGateway(self.url)
        self.gateway_channels = self.gateway.get_channels()
        self.menu = None
        print("Detecting meters...")
        self.meters = detect()
        self.channel_config = {}
        self.restart_ui = True
        while self.restart_ui:
            self.restart_ui = False
            self.create_menu()

    def input_gw(self, text):
        def is_valid_url():
            return re.match(r"^https?://[/\w\d.]+.php$", self.url)

        self.restart_ui = True
        self.menu.clear_screen()
        self.url = "invalid"
        while self.url and not is_valid_url():
            self.url = input(text)
            if not self.url:
                self.menu.stdscr.addstr(
                    3, 0, "Defaulting to http://localhost/middleware.php")
                self.url = "http://localhost/middleware.php"
                self.menu.stdscr.getkey()
            elif not is_valid_url():
                self.menu.stdscr.addstr(
                    3, 0, "Entered url is not valid."
                    " It must start with 'http://' or 'https://' and end with '.php'"
                )
                self.menu.stdscr.getkey()
        self.gateway = VolkszaehlerGateway(self.url)
        self.gateway_channels = self.gateway.get_channels()
        if self.gateway_channels:
            self.menu.stdscr.addstr(
                3, 0,
                f"Found {len(self.gateway_channels)} public channels at gateway '{self.url}'."
            )
        else:
            self.menu.stdscr.addstr(
                3, 0, f"Unable to find any public channels at '{self.url}'.")
        self.menu.stdscr.getkey()

    def create_menu(self):
        # Create the menu
        self.menu = CursesMenu("PyMeterReader Configuration Wizard",
                               "Choose item to configure")

        function_item = FunctionItem("Volkszähler Gateway",
                                     self.input_gw, ["Enter URL: "],
                                     should_exit=True)
        self.menu.append_item(function_item)

        for meter in self.meters:
            meter_menu = CursesMenu(
                f"Connect channels for meter {meter.identifier} at {meter.tty}",
                "By channel")
            for channel, value in meter.channels.items():
                map_menu = CursesMenu(f"Choose uuid for {channel}")
                for choice in self.gateway_channels:
                    map_menu.append_item(
                        FunctionItem(f"{choice['uuid']}: {choice['title']}",
                                     self.__assign,
                                     [meter, channel, choice['uuid'], '30m'],
                                     should_exit=True))
                map_menu.append_item(
                    FunctionItem("Enter private UUID",
                                 self.__assign, [meter, channel, None, '30m'],
                                 should_exit=True))
                meter_menu.append_item(
                    SubmenuItem(f"{channel}: {value[0]} {value[1]}", map_menu,
                                self.menu))
            submenu_item = SubmenuItem(f"Meter {meter.identifier}", meter_menu,
                                       self.menu)

            self.menu.append_item(submenu_item)

        view_item = FunctionItem("View current mapping", self.__view_mapping)
        self.menu.append_item(view_item)

        save_item = FunctionItem("Save current mapping", self.__safe_mapping)
        self.menu.append_item(save_item)

        register_service = FunctionItem(
            "Register PymeterReader as systemd service.",
            self.__register_service)
        self.menu.append_item(register_service)

        reset_item = FunctionItem("Reset all mappings", self.__clear)
        self.menu.append_item(reset_item)

        self.menu.show()

    def __register_service(self):
        self.menu.clear_screen()
        self.menu.stdscr.addstr(0, 0, "Installing service...")
        run(
            'sudo systemctl stop pymeterreader',  # pylint: disable=subprocess-run-check
            universal_newlines=True,
            shell=True)

        target_service_file = "/etc/systemd/system/pymeterreader.service"

        service_str = SERVICE_TEMPLATE.format(
            'pymeterreader -c /etc/pymeterreader.yaml')
        try:
            with open(target_service_file, 'w') as target_file:
                target_file.write(service_str)
            run(
                'systemctl daemon-reload',  # pylint: disable=subprocess-run-check
                universal_newlines=True,
                shell=True)
            if not exists('/etc/pymeterreader.yaml'):
                self.menu.stdscr.addstr(
                    1, 0,
                    "Copy example configuration file to '/etc/pymeterreader.yaml'"
                )
                with open('example_configuration.yaml', 'r') as file:
                    example_config = file.read()
                with open('/etc/pymeterreader.yaml', 'w') as file:
                    file.write(example_config)
            self.menu.stdscr.addstr(
                2, 0, "Registered pymeterreader as servicee.\n"
                "Enable with 'sudo systemctl enable pymeterreader'\n."
                "IMPORTANT: Create configuration file '/etc/pymeterreader.yaml'"
            )
        except OSError as err:
            if isinstance(err, PermissionError):
                self.menu.stdscr.addstr(
                    4, 0, "Cannot write service file to /etc/systemd/system. "
                    "Run as root (sudo) to solve this.")
        self.menu.stdscr.addstr(6, 0, "(press any key)")
        self.menu.stdscr.getkey()

    def __clear(self):
        """
        Remove channel mappings
        """
        self.channel_config.clear()

    def __safe_mapping(self):
        """
        Save yaml to system
        """
        self.menu.clear_screen()
        result = generate_yaml(self.channel_config, self.url)
        try:
            with open('/etc/pymeterreader.yaml', 'w') as config_file:
                config_file.write(result)
            self.menu.stdscr.addstr(0, 0, "Saved to /etc/pymeterreader.yaml")
        except PermissionError:
            self.menu.stdscr.addstr(
                0, 0,
                "Insufficient permissions: cannot write to /etc/pymeterreader.yaml"
            )
        self.menu.stdscr.addstr(1, 0, "(press any key)")
        self.menu.stdscr.getkey()

    def __view_mapping(self):
        self.menu.clear_screen()
        self.menu.stdscr.addstr(0, 0, "Mapped channels:")
        row = 2
        for meter in self.channel_config.values():
            for channel, content in meter['channels'].items():
                self.menu.stdscr.addstr(
                    row, 2,
                    f"{channel} at {meter.get('id')} mapped to UUID {content.get('uuid')}"
                )
                row += 1
        self.menu.stdscr.addstr(row, 0, "(press any key)")
        self.menu.stdscr.getkey()

    def __assign(self, meter: Device, channel, uuid: str, interval: str):
        if uuid is None:
            self.menu.clear_screen()
            uuid = input("Enter private UUID: ")
        if meter.identifier not in self.channel_config:
            self.channel_config[meter.identifier] = {
                'channels': {},
                'id': meter.identifier,
                'protocol': meter.protocol
            }
        self.channel_config[meter.identifier]['channels'][channel] = {
            'uuid': uuid,
            'interval': interval
        }
예제 #18
0
        menu.show()
        user_selection = menu.selected_option
    except Exception as e:
        print('Unknown Exception: %s. Exit' % str(e))
        return False
    return True


if __name__ == '__main__':
    menu = CursesMenu("Local Configuration Menu", "xlines Project")
    # backup
    submenu = CursesMenu("Exclusions",
                         'Do you want to add a new file type exclusion?')
    q1_item1 = FunctionItem("Yes", input, ["yes"])
    q1_item2 = FunctionItem("No", print('Exit'), ["no"])
    submenu.append_item(q1_item1)
    submenu.append_item(q1_item2)
    submenu_exclusions = SubmenuItem("Configure Exclusion List",
                                     submenu,
                                     menu=menu)
    menu.append_item(submenu_exclusions)
    if q1_item1 == "yes":
        display_exclusions()
        submenu = CursesMenu(
            "Access Key Backup",
            'Enter the directory where a backup copy of the access keys should be stored'
        )
        q2_item1 = FunctionItem("~/Backup/", input, ["~/Backup"])
        submenu.append(q2_item1)
        submenu.show()
예제 #19
0
파일: editor.py 프로젝트: olagrottvik/bust
class Editor(object):
    """A console-based menu system for creating and editing module descripting JSON files

    """
    def __init__(self, edit, jsonfile, output_dir='output/'):
        """Constructor

        Either reconstructs a module object from JSON, or create a new based on user input
        """
        self.jsonfile = jsonfile
        self.output_dir = output_dir
        self.recently_saved = False

        if edit:
            # Load the specified JSON file
            try:
                json = json_parser(jsonfile)
                self.settings = Settings(jsonfile, json['settings'])
                self.bus = Bus(json['bus'])
                self.mod = Module(json['module'], self.bus, self.settings)
                self.recently_saved = True
            except Exception as e:
                print('An unresolvable error has occurred:')
                print(str(e))
                print('Exiting...')
                exit()
        else:
            bus_dic = OrderedDict()
            bus_dic['type'] = get_list_choice('Choose a bus type: ',
                                              Bus.supported_bus)
            bus_dic['addr_width'] = 32
            bus_dic['data_width'] = 32
            bus_dic['reset'] = 'async'
            self.bus = Bus(bus_dic)

            # Get name, addr_width, data_width and description
            mod = OrderedDict()
            mod['name'] = get_identifier('Enter a module name: ')
            '''! @todo Add int check'''
            mod['addr_width'] = 32
            mod['data_width'] = 32
            mod['description'] = input('Enter a description for the module: ')
            mod['register'] = []

            self.settings = Settings(None, None)
            self.mod = Module(mod, self.bus, self.settings)

    def show_menu(self):
        self.menu = CursesMenu('bust - Module Editor', self.set_subtitle())

        self.menu.append_item(FunctionItem('Edit name', self.edit_name))
        self.menu.append_item(
            FunctionItem('List registers', self.list_registers))
        self.menu.append_item(
            FunctionItem('Add new register', self.add_register))
        self.menu.append_item(
            FunctionItem('Remove register', self.remove_register))
        self.menu.append_item(
            FunctionItem('Update addresses', self.update_addresses))
        self.menu.append_item(FunctionItem('Save JSON', self.save_JSON))
        self.menu.show()

    def update_menu(self):
        self.menu.subtitle = self.set_subtitle()

    def edit_name(self):
        print('Change the module name from current: ' + self.mod.name)
        self.mod.name = get_identifier('Enter a new name: ')
        self.recently_saved = False
        self.update_menu()

    def return_registers(self):
        while True:
            clear_screen()
            if len(self.mod.registers) < 1:
                print('No registers created at this point...')
                cont()
                return
            else:
                table = PrettyTable()
                table.field_names = [
                    '#', 'Name', 'Mode', 'Address', 'Type', 'Length', 'Reset',
                    'Description'
                ]
                for i, reg in enumerate(self.mod.registers):
                    table.add_row([
                        i, reg.name, reg.mode,
                        hex(reg.address), reg.sig_type, reg.length, reg.reset,
                        add_line_breaks(reg.description, 25)
                    ])
                return table

    def list_registers(self):
        table = self.return_registers()
        if table is None:
            return
        print(table)
        print(
            '\nEnter the register number for register details, or q to quit...'
        )
        while True:
            choice = input('Choice: ')
            if self.valid_register_input(choice):
                break
            else:
                print(choice + ' is not a valid choice')
        if choice == 'q':
            return
        else:
            clear_screen()
            self.print_register(int(choice), table)
            cont()

    def print_register(self, reg_num, table):
        reg = self.mod.registers[reg_num]
        print(table.get_string(start=reg_num, end=(reg_num + 1)))

        if len(reg.fields) > 0:
            print('\nFields:')
            table_fields = PrettyTable()
            table_fields.field_names = [
                '#', 'Name', 'Type', 'Position', 'Length', 'Reset',
                'Description'
            ]
            for i, field in enumerate(reg.fields):

                table_fields.add_row([
                    i, field.name, field.sig_type,
                    field.get_pos_str(), field.length, field.reset,
                    add_line_breaks(field.description, 25)
                ])

            print(table_fields)

    def add_register(self):
        """Adds a register to the module object

        Get user input to create a register that may or may not consists of individual fields
        """
        reg = OrderedDict()
        reg_names = [regs.name for regs in self.mod.registers]
        print('Input register information: ')
        try:
            reg['name'] = get_identifier('Name: ', reg_names)
            reg['description'] = input('Description: ')
            reg['mode'] = get_list_choice("Choose register mode: ",
                                          Register.supported_modes, 'lower', 0)

            fields = []

            width_consumed = 0
            while True:
                field_dic = OrderedDict()
                add_fields = input('Do you want to add a field? (Y/n): ')
                field_names = [field['name'] for field in fields]
                if add_fields.upper() == 'N':
                    break
                elif add_fields.upper() == 'Y' or add_fields == '':
                    field_dic['name'] = get_identifier('Field name: ',
                                                       field_names)
                    field_dic['type'] = get_list_choice(
                        'Field type: ', Field.supported_types)

                    if field_dic['type'] == 'slv':
                        max_width = self.mod.data_width - width_consumed

                        field_dic['length'] = get_int(
                            'Field length: ', 10, 1, max_width,
                            "The minimum width of a field is 1!",
                            "The maximum width of this field cannot extend" +
                            " the module data width minus the width already" +
                            " consumed by other fields: " + str(max_width))
                        width_consumed += field_dic['length']

                    else:
                        width_consumed += 1
                        field_dic['length'] = 1

                    max_reset = 2**field_dic['length'] - 1
                    field_dic['reset'] = hex(
                        get_int(
                            'Field reset in hex (default=0x0): ', 16, 0x0,
                            max_reset, "The minimum reset value is 0x0",
                            "The maximum reset value is based on the field width, "
                            + "and is " + str(hex(max_reset)), 0x0))

                    field_dic['description'] = input('Field description: ')

                    fields.append(field_dic)
                    # Check if all available data bits are use
                    if width_consumed == self.mod.data_width:
                        print(
                            "All available bits (" + str(self.mod.data_width) +
                            ") is consumed.\n" +
                            "No more fields can be added to this register.\n")
                        break
                    elif width_consumed > self.mod.data_width:
                        raise RuntimeError(
                            "More bits used by fields than available...")

                else:
                    print(add_fields + ' is not a valid choice...')

            if len(fields) > 0:
                reg['type'] = 'fields'
                reg['fields'] = fields

            else:
                reg['type'] = get_list_choice('Register type: ',
                                              Register.supported_types, None,
                                              0)

            # Make sure reg length is set to help calculate max reset later
            # Registers of field type will get an auto reset based on the field resets
            if reg['type'] == 'default':
                reg['length'] = self.mod.data_width
            elif reg['type'] == 'sl':
                reg['length'] = 1
            elif reg['type'] == 'slv':
                while True:
                    try:
                        reg['length'] = int(input('Length: '))
                        break
                    except Exception:
                        print('That is not a valid length...')

            if input('Auto-assign address? (Y/n): ').upper() == 'N':
                # Make sure the address is not out of range and that it is free
                max_address = 2**self.mod.addr_width - 1

                while True:
                    reg['address'] = get_int(
                        "Address in hex: ", 16, 0x0, max_address,
                        "The minimum address is 0x0",
                        "The maximum address is based on the module address width, "
                        + "and is " + str(hex(max_address)), 0x0)
                    # Perform an extra check of address range, although redundant
                    if self.mod.is_address_out_of_range(reg['address']):
                        print("Address is out of range...")
                        continue

                    # Check if the address has not been taken
                    if not self.mod.is_address_free(reg['address']):
                        print(
                            "The chosen address is already assigned to another register..."
                        )
                        continue

                    # Check whether the address is not byte-addressed, and give the user a choice to continue
                    if not self.mod.is_address_byte_based(reg['address']):
                        choice = input(
                            "The selected address is not byte-based. Continue? (y/N): "
                        )
                        if not choice.upper() == 'Y':
                            continue
                    break

            if reg['type'] != 'fields':

                max_reset = 2**reg['length'] - 1
                reg['reset'] = hex(
                    get_int(
                        'Register reset in hex (default=0x0): ', 16, 0x0,
                        max_reset, "The minimum reset value is 0x0",
                        "The maximum reset value is based on the register width, "
                        + "and is " + str(hex(max_reset)), 0x0))

            table = PrettyTable()
            table.field_names = [
                '#', 'Name', 'Mode', 'Address', 'Type', 'Length', 'Reset',
                'Description'
            ]

            # Table values based on what values exists
            table_name = reg['name']
            table_mode = reg['mode']

            if 'address' in reg:
                table_address = reg['address']
            else:
                table_address = 'auto'

            table_type = reg['type']

            if reg['type'] == 'fields':
                table_length = 'auto'
            elif 'length' in reg:
                table_length = reg['length']
            else:
                table_length = self.mod.bus.data_width

            if reg['type'] == 'fields':
                table_reset = 'auto'
            elif 'reset' in reg:
                table_reset = reg['reset']
            else:
                table_reset = 'auto'

            table_description = add_line_breaks(reg['description'], 25)

            table.add_row([
                len(self.mod.registers), table_name, table_mode, table_address,
                table_type, table_length, table_reset, table_description
            ])

            print(table)

            if 'fields' in reg:
                print('\nFields:')
                table_fields = PrettyTable()
                table_fields.field_names = [
                    '#', 'Name', 'Type', 'Length', 'Reset', 'Description'
                ]
                for i, field in enumerate(reg['fields']):

                    table_fields.add_row([
                        i, field['name'], field['type'], field['length'],
                        field['reset'], field['description']
                    ])

                print(table_fields)

            if input('Confirm creation of register? (Y/n): ').upper() != 'N':
                self.mod.add_register(reg)

                self.recently_saved = False
                self.update_menu()
            else:
                return

        except KeyboardInterrupt:
            print('\nAdding register aborted!')
            cont()

        except Exception as e:
            print('\nAdding register failed!')
            print(str(e))
            cont()

    def remove_register(self):
        table = self.return_registers()
        if table is None:
            return
        print(table)
        print('\nEnter the register number for removal, or q to quit...')
        while True:
            choice = input('Choice: ')
            if self.valid_register_input(choice):
                break
            else:
                print(choice + ' is not a valid choice')
        if choice == 'q':
            return
        else:
            clear_screen()
            self.print_register(int(choice), table)

            if input('Are you sure you want to delete this register? (y/N): '
                     ).upper() == 'Y':
                del self.mod.registers[int(choice)]
                self.recently_saved = False

        self.update_menu()

    def update_addresses(self):
        self.mod.update_addresses()
        print("Addresses are updated..")
        self.recently_saved = False
        self.update_menu()
        cont()

    def save_JSON(self):
        print('Saving ' + self.jsonfile + ' ...')

        # Get JSON with addresses
        json = self.mod.return_JSON(True)
        try:
            write_string_to_file(json, self.jsonfile, ".")
        except Exception as e:
            print('Saving failed...')
            print(e)
            cont()
            return

        self.recently_saved = True
        cont()
        self.update_menu()

    def set_subtitle(self):
        if self.recently_saved:
            s = ' - SAVED'
        else:
            s = ' - NOT SAVED'
        string = self.mod.name
        string += ' / ' + str(self.mod.addr_width)
        string += ' / ' + str(self.mod.data_width)
        string += ' / ' + str(hex(self.mod.baseaddr))
        string += s
        return string

    def valid_register_input(self, s):
        """ Returns boolean determining if a choice of register is valid

        The input is first checked against the quit-character, and then checked if it matches any
        valid indexes of the mod.registers list.
        """
        if s.upper() == 'Q':
            return True
        elif is_int(s):
            index = int(s)
            for i, reg in enumerate(self.mod.registers):
                if index == i:
                    return True
        return False
예제 #20
0
class Wizard:
    CONFIG_FILE_NAME = "pymeterreader.yaml"
    POSIX_CONFIG_PATH = Path("/etc") / CONFIG_FILE_NAME

    def __init__(self) -> None:
        logging.basicConfig(level=logging.INFO)
        self.url = "http://localhost/middleware.php"
        self.gateway = VolkszaehlerGateway(self.url)
        self.gateway_channels = self.gateway.get_channels()
        self.menu: CursesMenu
        print("Detecting meters...")
        self.meters = detect()
        self.channel_config: tp.Dict[str, tp.Dict[str,
                                                  tp.Union[str,
                                                           tp.Dict]]] = {}
        self.restart_ui = True
        while self.restart_ui:
            self.restart_ui = False
            self.create_menu()

    def input_gw(self, text) -> None:
        def is_valid_url():
            return re.match(r"^https?://[/\w\d.]+.php$", self.url)

        self.restart_ui = True
        self.menu.clear_screen()
        self.url = "invalid"
        while self.url and not is_valid_url():
            self.url = input(text)
            if not self.url:
                self.menu.stdscr.addstr(
                    3, 0, "Defaulting to http://localhost/middleware.php")
                self.url = "http://localhost/middleware.php"
                self.menu.stdscr.getkey()
            elif not is_valid_url():
                self.menu.stdscr.addstr(
                    3, 0, "Entered url is not valid."
                    " It must start with 'http://' or 'https://' and end with '.php'"
                )
                self.menu.stdscr.getkey()
        self.gateway = VolkszaehlerGateway(self.url)
        self.gateway_channels = self.gateway.get_channels()
        if self.gateway_channels:
            self.menu.stdscr.addstr(
                3, 0,
                f"Found {len(self.gateway_channels)} public channels at gateway '{self.url}'."
            )
        else:
            self.menu.stdscr.addstr(
                3, 0, f"Unable to find any public channels at '{self.url}'.")
        self.menu.stdscr.getkey()

    def create_menu(self) -> None:
        # Create the menu
        self.menu = CursesMenu("PyMeterReader Configuration Wizard",
                               "Choose item to configure")

        function_item = FunctionItem("Volkszähler Gateway",
                                     self.input_gw, ["Enter URL: "],
                                     should_exit=True)
        self.menu.append_item(function_item)

        for meter in self.meters:
            meter_menu = CursesMenu(
                f"Connect channels for meter {meter.meter_id} at {meter.meter_address}",
                "By channel")
            for channel in meter.channels:
                map_menu = CursesMenu(
                    f"Choose uuid for {channel.channel_name}")
                for choice in self.gateway_channels:
                    map_menu.append_item(
                        FunctionItem(f"{choice.uuid}: {choice.title}",
                                     self.__assign,
                                     [meter, channel, choice.uuid, '30m'],
                                     should_exit=True))
                map_menu.append_item(
                    FunctionItem("Enter private UUID",
                                 self.__assign, [meter, channel, None, '30m'],
                                 should_exit=True))
                meter_menu.append_item(
                    SubmenuItem(
                        f"{channel.channel_name}: {channel.value} {channel.unit}",
                        map_menu, self.menu))
            submenu_item = SubmenuItem(f"Meter {meter.meter_id}", meter_menu,
                                       self.menu)

            self.menu.append_item(submenu_item)

        view_item = FunctionItem("View current mapping", self.__view_mapping)
        self.menu.append_item(view_item)

        save_item = FunctionItem("Save current mapping", self.__safe_mapping)
        self.menu.append_item(save_item)

        register_service = FunctionItem(
            "Register PymeterReader as systemd service.",
            self.__register_service)
        self.menu.append_item(register_service)

        reset_item = FunctionItem("Reset all mappings", self.__clear)
        self.menu.append_item(reset_item)

        self.menu.show()

    def __register_service(self) -> None:
        self.menu.clear_screen()
        if platform.system() != "Linux":
            self.menu.stdscr.addstr(
                0, 0,
                "Systemd Service registration is only supported on Linux!")
            self.menu.stdscr.addstr(1, 0, "(press any key)")
            self.menu.stdscr.getkey()
            return
        self.menu.stdscr.addstr(0, 0, "Installing service...")
        run(
            'sudo systemctl stop pymeterreader',  # pylint: disable=subprocess-run-check
            universal_newlines=True,
            shell=True)

        target_service_file = "/etc/systemd/system/pymeterreader.service"

        service_str = SERVICE_TEMPLATE.format(
            f'pymeterreader -c {self.POSIX_CONFIG_PATH.absolute()}')
        try:
            with open(target_service_file, 'w') as target_file:
                target_file.write(service_str)
            run(
                'systemctl daemon-reload',  # pylint: disable=subprocess-run-check
                universal_newlines=True,
                shell=True)
            if not exists(self.POSIX_CONFIG_PATH):
                self.menu.stdscr.addstr(
                    1, 0,
                    f"Copy example configuration file to '{self.POSIX_CONFIG_PATH.absolute()}'"
                )
                with open('example_configuration.yaml', 'r') as file:
                    example_config = file.read()
                with open(self.POSIX_CONFIG_PATH, 'w') as file:
                    file.write(example_config)
            self.menu.stdscr.addstr(
                2, 0, "Registered pymeterreader as service.\n"
                "Enable with 'sudo systemctl enable pymeterreader'\n."
                f"IMPORTANT: Create configuration file '{self.POSIX_CONFIG_PATH.absolute()}'"
            )
        except FileNotFoundError as err:
            self.menu.stdscr.addstr(4, 0, f"Could not access file: {err}!")
        except PermissionError:
            self.menu.stdscr.addstr(
                4, 0, "Cannot write service file to /etc/systemd/system. "
                "Run as root (sudo) to solve this.")
        self.menu.stdscr.addstr(6, 0, "(press any key)")
        self.menu.stdscr.getkey()

    def __clear(self) -> None:
        """
        Remove channel mappings
        """
        self.channel_config.clear()

    def __safe_mapping(self) -> None:
        """
        Save yaml to system
        """
        self.menu.clear_screen()
        result = generate_yaml(self.channel_config, self.url)
        try:
            if platform.system() in ["Linux", "Darwin"]:
                config_path = self.POSIX_CONFIG_PATH
            else:
                config_path = Path(".") / "pymeterreader.yaml"
            with open(config_path, "w") as config_file:
                config_file.write(result)
            self.menu.stdscr.addstr(0, 0, f"Saved to {config_path.absolute()}")
        except PermissionError:
            self.menu.stdscr.addstr(
                0, 0,
                f"Insufficient permissions: cannot write to {config_path.absolute()}!"
            )
        except FileNotFoundError:
            self.menu.stdscr.addstr(
                0, 0, f"Could not access path: {config_path.absolute()}!")
        self.menu.stdscr.addstr(1, 0, "(press any key)")
        self.menu.stdscr.getkey()

    def __view_mapping(self) -> None:
        self.menu.clear_screen()
        self.menu.stdscr.addstr(0, 0, "Mapped channels:")
        row = 2
        for meter in self.channel_config.values():
            for channel, content in meter['channels'].items():
                self.menu.stdscr.addstr(
                    row, 2,
                    f"{channel} at {meter.get('id')} mapped to UUID {content.get('uuid')}"
                )
                row += 1
        self.menu.stdscr.addstr(row, 0, "(press any key)")
        self.menu.stdscr.getkey()

    def __assign(self, meter: Device, channel: ChannelValue,
                 uuid: tp.Optional[str], interval: str) -> None:
        if uuid is None:
            self.menu.clear_screen()
            uuid = input("Enter private UUID: ")
        if meter.meter_id not in self.channel_config:
            self.channel_config[meter.meter_id] = {
                'channels': {},
                'protocol': meter.protocol,
                'meter_address': meter.meter_address,
                'meter_id': meter.meter_id
            }
        self.channel_config[meter.meter_id]['channels'][
            channel.channel_name] = {
                'uuid': uuid,
                'interval': interval
            }
예제 #21
0
from cursesmenu import CursesMenu
from cursesmenu.items import *
from scriptku import menucurse

#Top Level Menu
toplv_menu = CursesMenu("Menu Raspberry Legend! - written by Pratama", "pilih satu")

#Youtube Menu
yt_menu = CursesMenu("Utility utk download youtube video", "pilih salah satu")

toplv_yt_item = SubmenuItem("Youtube Video Downloader", yt_menu, menu=toplv_menu)
yt1 = FunctionItem("Download single youtube video", menucurse.yt1)
yt_edit_links = FunctionItem("Edit list download", menucurse.yt_edit_links)
yt_bulk = FunctionItem("Bulk download youtube videos", menucurse.yt_bulk)

#Bulk rename menu
bulk_rename_item = FunctionItem("Bulk rename - WARNING(DANGEROUS TOOLS, USE AT YOUR OWN RISK)", menucurse.bulk_rename)

#Top Level Menu Append
toplv_menu.append_item(toplv_yt_item)
toplv_menu.append_item(bulk_rename_item)

#Youtube Menu Append
yt_menu.append_item(yt1)
yt_menu.append_item(yt_edit_links)
yt_menu.append_item(yt_bulk)

#Show the Top Level Menu
toplv_menu.show()
예제 #22
0
from modules import SSH as ssh
from modules import SshX as ssh_X
from modules import Xfce as xfce

# Створення основного меню
menu = CursesMenu("Ubuntu universal script", platform.version())
# Створення основних пунктів
_menu_items = [
    CommandItem("Update paсkages", "sudo apt update"),
    CommandItem("Upgrade paсkages", "sudo apt upgrade"),
    CommandItem("Autoremove paсkages", "sudo apt autoremove"),
    CommandItem("Remove other kernel`s", "bash bash/remove_kernel.sh"),
    CommandItem(
        "Cleaning pickings removed paсkages",
        "sudo dpkg -l | awk '/^rc/ {print $2}' | xargs sudo dpkg --purge"),

    # Відображення підменю
    SubmenuItem("Install soft", soft.menu, menu),
    SubmenuItem("Remove software", remove.menu, menu),
    SubmenuItem("Xfce soft", xfce.menu, menu),
    SubmenuItem("SSH Connect", ssh.menu, menu),
    SubmenuItem("SSH connect with X-window support", ssh_X.menu, menu)
]

# Додавання пунктів до основного меню
for item in _menu_items:
    menu.append_item(item)

# Показ меню
menu.show()
예제 #23
0
class TestSampleMenu(BaseTestCase):
    def setUp(self):
        super(TestSampleMenu, self).setUp()

        self.menu = CursesMenu("self.menu", "TestSampleMenu")
        self.item1 = MenuItem("self.item1", self.menu)
        self.item2 = MenuItem("self.item2", self.menu)
        self.menu.append_item(self.item1)
        self.menu.append_item(self.item2)
        self.menu.start()
        self.menu.wait_for_start(timeout=10)

    def tearDown(self):
        super(TestSampleMenu, self).tearDown()
        self.menu.exit()
        self.menu.join(timeout=10)

    def test_go_down(self):
        self.menu.go_down()
        self.assertEqual(self.menu.current_option, 1)
        self.assertIs(self.menu.current_item, self.item2)
        self.menu.go_down()
        self.assertEqual(self.menu.current_option, 2)
        self.assertEqual(self.menu.current_item, self.menu.exit_item)
        self.menu.go_down()
        self.assertEqual(self.menu.current_option, 0)
        self.assertIs(self.menu.current_item, self.item1)

    def test_go_up(self):
        self.menu.go_up()
        self.assertEqual(self.menu.current_option, 2)
        self.assertIs(self.menu.current_item, self.menu.exit_item)
        self.menu.go_up()
        self.assertEqual(self.menu.current_option, 1)
        self.assertEqual(self.menu.current_item, self.item2)
        self.menu.go_up()
        self.assertEqual(self.menu.current_option, 0)
        self.assertIs(self.menu.current_item, self.item1)

    def test_go_to(self):
        self.menu.go_to(1)
        self.assertEqual(self.menu.current_option, 1)
        self.assertEqual(self.menu.current_item, self.item2)

    def test_select(self):
        self.menu.select()
        self.assertEqual(self.menu.selected_option, 0)
        self.assertIs(self.menu.selected_item, self.item1)
        self.menu.go_down()
        self.menu.select()
        self.assertEqual(self.menu.selected_option, 1)
        self.assertIs(self.menu.selected_item, self.item2)
        self.menu.go_down()
        self.menu.select()
        self.assertEqual(self.menu.selected_option, 2)
        self.assertIs(self.menu.selected_item, self.menu.exit_item)
        self.menu.join(timeout=10)
        self.assertFalse(self.menu.is_alive())

    def test_exit(self):
        self.menu.exit()
        self.menu.join(timeout=10)
        self.assertFalse(self.menu.is_alive())
예제 #24
0
class TestSampleMenu(BaseTestCase):
    def setUp(self):
        super(TestSampleMenu, self).setUp()

        self.menu = CursesMenu("self.menu", "TestSampleMenu")
        self.item1 = MenuItem("self.item1", self.menu)
        self.item2 = MenuItem("self.item2", self.menu)
        self.menu.append_item(self.item1)
        self.menu.append_item(self.item2)
        self.menu.start()
        self.menu.wait_for_start(10)

    def tearDown(self):
        super(TestSampleMenu, self).tearDown()
        self.menu.exit()
        self.menu.join()

    def test_go_down(self):
        self.menu.go_down()
        self.assertEqual(self.menu.current_option, 1)
        self.assertIs(self.menu.current_item, self.item2)
        self.menu.go_down()
        self.assertEqual(self.menu.current_option, 2)
        self.assertEqual(self.menu.current_item, self.menu.exit_item)
        self.menu.go_down()
        self.assertEqual(self.menu.current_option, 0)
        self.assertIs(self.menu.current_item, self.item1)

    def test_go_up(self):
        self.menu.go_up()
        self.assertEqual(self.menu.current_option, 2)
        self.assertIs(self.menu.current_item, self.menu.exit_item)
        self.menu.go_up()
        self.assertEqual(self.menu.current_option, 1)
        self.assertEqual(self.menu.current_item, self.item2)
        self.menu.go_up()
        self.assertEqual(self.menu.current_option, 0)
        self.assertIs(self.menu.current_item, self.item1)

    def test_go_to(self):
        self.menu.go_to(1)
        self.assertEqual(self.menu.current_option, 1)
        self.assertEqual(self.menu.current_item, self.item2)

    def test_select(self):
        self.menu.select()
        self.assertEqual(self.menu.selected_option, 0)
        self.assertIs(self.menu.selected_item, self.item1)
        self.menu.go_down()
        self.menu.select()
        self.assertEqual(self.menu.selected_option, 1)
        self.assertIs(self.menu.selected_item, self.item2)
        self.menu.go_down()
        self.menu.select()
        self.assertEqual(self.menu.selected_option, 2)
        self.assertIs(self.menu.selected_item, self.menu.exit_item)
        self.menu.join(timeout=5)
        self.assertFalse(self.menu.is_alive())

    def test_exit(self):
        self.menu.exit()
        self.menu.join(timeout=5)
        self.assertFalse(self.menu.is_alive())
예제 #25
0
#!/usr/bin/env python3

from cursesmenu import CursesMenu
from cursesmenu.items import FunctionItem

dtitle = "default title"
menu = CursesMenu(dtitle)


def myFunc():
    menu.title = "there's a new title"


# myFunc, the'()' were not allowed here, got TypeError str
function_item = FunctionItem("change title", myFunc)
menu.append_item(function_item)
menu.show()