initial commit of the Python utility menu

This commit is contained in:
2024-09-28 14:33:49 -06:00
commit ea2176b77c
11 changed files with 194 additions and 0 deletions

39
README.md Normal file
View File

@@ -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

BIN
__pycache__/desktop.ini Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
desktop.ini Normal file

Binary file not shown.

93
menu.py Normal file
View File

@@ -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()

1
requirements.txt Normal file
View File

@@ -0,0 +1 @@
rich

61
template.py Normal file
View File

@@ -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()