commit ea2176b77c56919c3269731027c2568e0af57729 Author: Nathan C Date: Sat Sep 28 14:33:49 2024 -0600 initial commit of the Python utility menu diff --git a/README.md b/README.md new file mode 100644 index 0000000..0c72fc0 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# Utility Menu + +![Latest](https://drive.google.com/drive/folders/1-ALAxC1rN4Z4BtvgPgxd0xybvjdrDRhh?usp=drive_link) + +## Description + +A template for quickly generating a friendly console utility from a custom CLASS framework. + +Windows: +python menu.py + +Linux: +python3 menu.py + +## Table of Contents + +- [Description](#description) +- [Notes](#notes) +- [Prerequisites](#prerequisites) +- [Installation](#installation) + +## Notes + +- Wraps custom CLASS methods in a user friendly UI +- Follow the included template.py +- Full ANSI encoding. SSH compatible + +### Prerequisites + +Python 3.x +PIP + +## Installation + +Windows: +pip install -r requirements.txt + +Linux: +pip3 install -r requirements.txt diff --git a/__pycache__/desktop.ini b/__pycache__/desktop.ini new file mode 100644 index 0000000..434e1c0 Binary files /dev/null and b/__pycache__/desktop.ini differ diff --git a/__pycache__/oahu.cpython-310.pyc b/__pycache__/oahu.cpython-310.pyc new file mode 100644 index 0000000..a95e2ff Binary files /dev/null and b/__pycache__/oahu.cpython-310.pyc differ diff --git a/__pycache__/template.cpython-310.pyc b/__pycache__/template.cpython-310.pyc new file mode 100644 index 0000000..4a034da Binary files /dev/null and b/__pycache__/template.cpython-310.pyc differ diff --git a/__pycache__/template.cpython-311.pyc b/__pycache__/template.cpython-311.pyc new file mode 100644 index 0000000..74eab2a Binary files /dev/null and b/__pycache__/template.cpython-311.pyc differ diff --git a/__pycache__/therm.cpython-310.pyc b/__pycache__/therm.cpython-310.pyc new file mode 100644 index 0000000..8da2411 Binary files /dev/null and b/__pycache__/therm.cpython-310.pyc differ diff --git a/__pycache__/therm.cpython-311.pyc b/__pycache__/therm.cpython-311.pyc new file mode 100644 index 0000000..1914cc0 Binary files /dev/null and b/__pycache__/therm.cpython-311.pyc differ diff --git a/desktop.ini b/desktop.ini new file mode 100644 index 0000000..434e1c0 Binary files /dev/null and b/desktop.ini differ diff --git a/menu.py b/menu.py new file mode 100644 index 0000000..66e6472 --- /dev/null +++ b/menu.py @@ -0,0 +1,93 @@ +# main.py + +from rich.console import Console +from rich.table import Table +from rich.console import Group +from rich import print +from rich.panel import Panel +from rich.traceback import install + +# ***edit here to assign Class for menu generation*** +from template import TEMPLATE as Class_For_Menu # Import the class(es) from specified file + +def main_menu(): + obj = Class_For_Menu() # create object(s) of imported class(es) + install() + console = Console() + INPUT_TXT = "[green]Input[/green] or [red][bold]q[/bold][/red] to quit:\n" + while True: + # display titles as menu options + console.clear() + menu_text = "" + for i, method in enumerate(obj.methods, start=1): + menu_text += f"{i}. {method['title']}\n" + menu_text += f"{len(obj.methods) + 1}. Exit" + console.print(print_panel(obj, menu_text)) + + # get and proceess menu choice + choice = console.input("Select an option: ") + try: + # Convert the choice to an index + choice_index = int(choice) - 1 + + if 0 <= choice_index < len(obj.methods): + # print the method description, get input + console.clear() + method_description = obj.methods[choice_index]["description"] + form_text = f"[green]{method_description}[/green]" + console.print(print_panel(obj, form_text)) + input_string = console.input(INPUT_TXT) + # Check for Quit / 'q' + while input_string != "q": + # dynamically call the method and print result + console.clear() + method_name = obj.methods[choice_index]["name"] + method = getattr(obj, method_name) + # print the results + result_table = method(input_string) + form_group = Group(format_results(result_table), form_text) + console.print(print_panel(obj, form_group)) + input_string = console.input(INPUT_TXT) + elif choice_index == len(obj.methods): + console.print("[bold magenta]Goodbye![/bold magenta]") + break + else: + console.print("[bold red]Invalid option, please try again.[/bold red]") + + except ValueError: + console.print("[bold red]Please enter a valid number.[/bold red]") + except Exception as e: + console.print(f"[bold red]An error occurred: {e}[/bold red]") + +def format_results(result_array): + """print the result of the operation as a table""" + table = Table() + + # Add header with white color + for header in result_array[0]: + table.add_column(header, style="white", header_style="bold white") + + # Define colors for up to 5 columns + colors = ["cyan", "magenta", "green", "yellow", "blue"] + + # Add the rest of the rows with colored columns + for row in result_array[1:]: + colored_row = [ + f"[{colors[i % len(colors)]}]{row[i]}[/{colors[i % len(colors)]}]" + for i in range(len(row)) + ] + table.add_row(*colored_row) + return table + +def print_panel(object, form): + """print the output data in a panel""" + panel = Panel.fit( + form, + title=object.title, + border_style="blue", + padding=(1, 2) + ) + return panel + +if __name__ == "__main__": + main_menu() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..df78ca6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +rich diff --git a/template.py b/template.py new file mode 100644 index 0000000..5c225e4 --- /dev/null +++ b/template.py @@ -0,0 +1,61 @@ +# template.py + +# used for the examples. these imports can be removed later +import os +import time + +class TEMPLATE: + def __init__(self, initial_temp_c=25.0): + # add self.[parameters] here and update method details + self.title = "Template Utility" + self.usage = """This template can be used to define the CLASS + that menu.py will use to generate the utility UI""" + + self.methods = [ + { + "name": "os_info", + "title": "Print OS information", + "description": "Print basic information from the OS" + }, + { + "name": "add_one", + "title": "Number incrementer with error checking", + "description": "Add 1 to a number" + }, + { + "name": "divide_by_zero", + "title": "Divide anything by 0", + "description": "Returns the input divded by 0" + } + ] + + def os_info(self, unused_input=""): + """Print OS information""" + return [ + ["OS:", "Environment Variables:", "Local Time"], # Header row + [f"{os.name}", f"{os.getenv('PATH')}", f"{time.localtime()}"] + ] + + def add_one(self, input): + """Number incrementer with error checking!""" + try: + input_plus_one = float(input) + 1 + except: + input_plus_one = "[red][bold]NAN[/bold][/red]" + return [ + [f"{input} + 1"], # Header row + [f"{input_plus_one}"] + ] + + def divide_by_zero(self, input): + """Divide anything by 0""" + return [ + [f"{input} / 0"], # Header row + ["more than 255"] + ] + +if __name__ == "__main__": + obj = TEMPLATE() + # when not using menu.py, direct CLI calls can be handled here + obj.os_info() + \ No newline at end of file