Question
I'm trying to run a python application but keep getting the following error: File /Users/Holly/Documents/UMUC/SDEV300/lab2.py, line 286, in ui.mainloop() AttributeError: 'UI' object has no attribute
I'm trying to run a python application but keep getting the following error:
File "/Users/Holly/Documents/UMUC/SDEV300/lab2.py", line 286, in
ui.mainloop()
AttributeError: 'UI' object has no attribute 'mainloop'
Here are the sections giving me trouble:
def mainloop(self) -> None:
"""Run the program."""
print("Welcome to the", colored("Really Purposeful Program (RPP):", "red"))
while not self.stop:
self._print_main_menu()
uin = input(">>> ")
while not self._validate_menu_input(uin):
print("I didn't understand that! ")
self._print_main_menu()
uin = input(">>> ")
self._run(uin)
self.stop = self._continue_msg()
self.exit()
if __name__ == "__main__":
ui = UI()
try:
ui.mainloop()
except KeyboardInterrupt:
ui.exit()
When I change the attribute to a different method, such as ui._print_main_menu, the error message goes away but the program ends without printing or taking input.
Essentially, I'm not sure how I should code the main method. The application is supposed to create a menu-driven Python program with options like generating a password and doing different math computations.
Here's the full code:
# pylint: disable=too-few-public-methods, unsubscriptable-object, no-self-use, ungrouped-imports
try:
import colorama
from termcolor import colored
except ImportError:
import subprocess
subprocess.call(["pip", "install", "-U", "colorama", "termcolor"])
finally:
import colorama
from termcolor import colored
import sys
import re
import math
import string
import datetime
import secrets
from functools import partial
from typing import Any, Callable, Dict, List, Optional, Tuple
# init color terminal output
colorama.init()
class Utility:
"""Class for utilities"""
"""Utilities are software programs that add functionality to your computer or help your computer perform better"""
@classmethod
def get_int(cls, message: str) -> int:
"print message and get an integer"
uin = input(message)
while not all(ltr.isdigit() for ltr in uin):
print("Please enter a whole number.")
uin = input(message)
return int(uin)
@classmethod
def get_float(cls, message: str) -> float:
"print message and get a float"
uin = input(message)
while not all(ltr.isdigit() or ltr == "." for ltr in uin):
print("Please enter a valid integer.")
uin = input(message)
return float(uin)
@classmethod
def get_valid(cls, message: str, validator: Callable) -> str:
"print message and verify input with validator()"
uin = input(message)
while not validator(uin):
print("Please try again.")
uin = input(message)
return uin
@classmethod
def password(cls, length: int, makeup: str) -> None:
"""A. Generate secure password"""
inds = {"1": "lower", "2": "upper", "3": "numbers", "4": "symbols"}
types = {
"lower": string.ascii_lowercase,
"upper": string.ascii_uppercase,
"numbers": string.digits,
"symbols": "".join(
letter
for letter in string.printable
if not letter
in string.ascii_letters + string.digits + string.whitespace
),
}
# generate a string for secrets to choose from
choices = "".join(types[inds[num]] for num in makeup)
# print out that password
print()
print(colored("Secure password: ", "green"), end="")
print(
colored("".join(secrets.choice(choices) for _ in range(length)), "blue"),
end=" ",
)
@classmethod
def percentage(cls, num: int, denom: int, prec: int) -> None:
"""B. Calculate and Format a Percentage"""
"""Calculate the percentage of `num/denom` to `prec` digits of precision."""
print()
print(
colored("Percentage:", "green"),
colored(f"{num/denom : .0{prec}%}", "blue"),
end=" ",
)
@classmethod
def days(cls) -> None:
"""C. How many days from today until July 4, 2025?"""
"""Get the number of days until July 4, 2025"""
print()
print(
colored(
f"{(datetime.datetime(2025, 7, 4) - datetime.datetime.today()).days}",
"blue",
),
colored("days until", "green"),
colored("July 4, 2025", "red"),
end=" ",
)
@classmethod
def triangle(cls, side_b: int, side_c: int, angle_a: int, prec: int = 3) -> None:
"""D. Use the Law of Cosines to calculate the leg of a triangle."""
"""
On a triangle with angles A, B, C, input two of
the sides and the angle between them to return
the third side.
"""
answer = math.sqrt(
side_b ** 2 + side_c ** 2 - (2 * side_b * side_c * math.cos(angle_a))
)
print()
print(
colored("Side a:", "green"),
colored(f"{answer : .0{prec}}", "blue"), end=" ",
)
@classmethod
def cylinder(cls, radius: int, height: int, prec: int = 3) -> None:
"""E.. Calculate the volume of a Right Circular Cylinder"""
"""Calculate the volume of a cylinder based on a supplied radius and height"""
print()
print(
colored("Volume of the cylinder:", "green"),
colored(f"{(math.pi * (radius ** 2)) * height : ,.0{prec}f}", "blue"),
end=" ",
)
class UI:
"""User interface class"""
def __init__(self) -> None:
self.stop: bool = False # flag for self.mainloop()
# self.needs is a dict of:
# {
# menu selection :
# [(input message, validator func), ...]
# }
# that self._run collects and uses with the appropriate
# utility from the _Utilities class.
self.needs: Dict[str, List[Tuple[str, Callable]]] = {
"1": [
("How long should the password be?", Utility.get_int),
(
(
"What should the makeup of the password be?"
" (ex: 123 for lower, upper, and nums)"
" 1 - lower case letters"
" 2 - upper case letters"
" 3 - numbers"
" 4 - symbols"
),
partial(
Utility.get_valid,
validator=lambda msg: all(ltr in "1234" for ltr in msg),
),
),
],
"2": [
("What is the numerator?", Utility.get_int),
("What is the denominator?", Utility.get_int),
("Calculate to how many decimal places?", Utility.get_int),
],
"3": [("", print)],
"4": [
(
(
"In the triangle:"
" angle A /| "
" / | "
" / | side c"
" side b / | "
" / | "
" / | "
" -------- "
" side a"
),
print,
),
("What is the length of side b?", Utility.get_int),
("What is the length of side c?", Utility.get_int),
("What is the measure of angle A (in degrees)?", Utility.get_float),
],
"5": [
("What is the radius of the base?", Utility.get_int),
("What is the height of the cylnder?", Utility.get_int),
],
}
# self.run is a dict that contains
# { menu selection : utility function }
# the utility function is what self._run
# feeds the collected arguments to.
self.functions = {
"1": Utility.password,
"2": Utility.percentage,
"3": Utility.days,
"4": Utility.triangle,
"5": Utility.cylinder,
}
def _print_main_menu(self) -> None:
"""See function name"""
print(
"""
Options:
1 - Generate a password
2 - Calculate a percentage
3 - How many days until July 4, 2025
4 - Find the missing side of a triangle
5 - Calculate the volume of a cylinder
6 - Exit
"""
)
def _validate_menu_input(self, m_choice: str) -> bool:
"""Validate menu input"""
# remove spaces and dots
u_str = re.sub('[\s\.]+', '', m_choice)
if u_str == "6" or not u_str:
print("Are you sure? (y/n)")
yes_no = input(">>> ")
if yes_no.lower().startswith("y"):
self.exit()
return False
if len(u_str) > 1 or not u_str in "".join([str(i) for i in range(1, 6)]):
return False
return True
def exit(self) -> None:
"Prints thank you message, cleans up terminal, and exits"
self.stop = True # useless but makes pylint stop yelling
print()
print(colored("Thank you!", "red", "on_blue"))
print(
colored("Thanks for using the", "blue")
+ colored(" Really Purposeful Program (RPP)", "red")
+ "!"
)
colorama.deinit()
sys.exit()
def _run(self, num: str) -> Optional[Any]:
"""
Collects arguments based on messages and validation functions in
self.needs. Feeds collected args to the function in self.functions
that corresponds to the user supplied selection from the menu.
"""
args = [] # collected arguments
for msg, func in self.needs.get(
num
): # grabs message and validator from self.needs
args.append(func(msg + " >>> ")) # appends the arg from the validator
# runs the corresponding function using the collected args
self.functions[num](*[arg for arg in args if arg])
def _continue_msg(self) -> bool:
"Prints continue message"
print("Continue? (y/n)")
yes_no = input(">>> ")
if yes_no.lower().startswith("y"):
return False
return True
def mainloop(self) -> None:
"""Run the program."""
print("Welcome to the", colored("Really Purposeful Program (RPP):", "red"))
while not self.stop:
self._print_main_menu()
uin = input(">>> ")
while not self._validate_menu_input(uin):
print("I didn't understand that! ")
self._print_main_menu()
uin = input(">>> ")
self._run(uin)
self.stop = self._continue_msg()
self.exit()
if __name__ == "__main__":
ui = UI()
try:
ui.mainloop()
except KeyboardInterrupt:
ui.exit()
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started