Using integers with dictionary to create text menu (Switch/Case alternative) - function

I am working my way through the book Core Python Programming. Exercise 2_11 instructed to build a menu system that had allowed users to select and option which would run an earlier simple program. the menu system would stay open until the user selected the option to quit. Here is my first working program.
programList = {1:"menu system",
2:"for loop count 0 to 10",
3:"positive or negative",
4:"print a string, one character at a time",
5:"sum of a fixed tuple",
"x":"quit()",
"menu":"refresh the menu"}
import os
for x in programList:
print(x,":",programList[x])
while True:
selection = input("select a program: ")
if selection == "1":
os.startfile("cpp2_11.py")
elif selection == "2":
os.startfile("cpp2_5b.py")
elif selection == "3":
os.startfile("cpp2_6.py")
elif selection == "4":
os.startfile("cpp2_7.py")
elif selection == "5":
os.startfile("cpp2_8.py")
elif selection == "menu":
for x in range(8): print(" ")
for x in programList:print(x,":",programList[x])
elif selection == "X":
break
elif selection == "x":
break
else:
print("not sure what you want")
input()
quit()
This version worked fine, but I wanted to use the a dictionary as a case/switch statement to clean up the ugly if/elif/else lines.
Now I'm stuck. I'm using Eclipse with PyDev and my new code is throwing an error:
Duplicated signature:!!
Here's a copy of my current code:
import os
def '1'():
os.startfile("cpp2_11.py")
def '2'():
os.startfile("cpp2_5b.py")
def '3'():
os.startfile("cpp2_6.py")
def '4'():
os.startfile("cpp2_7.py")
def '5'():
os.startfile("cpp2_8.py")
def 'm'():
for x in range(8): print(" ")
for x in actions:print(x,":",actions[x])
def 'x'():
quit()
def errhandler():
else:
print("not sure what you want")
actions = {1:"menu system",
2:"for loop count 0 to 10",
3:"positive or negative",
4:"print a string, one character at a time",
5:"sum of a fixed tuple",
"X":"quit()",
"menu":"refresh the menu"}
for x in actions:
print(x,":",actions[x])
selectedaction = input("please select an option from the list")
while True:
actions.get(selectedaction,errhandler)()
input()
quit()
I'm pretty sure that my current problem (the error codes) are related to the way I'm trying to use the os.startfile() in the functions. Maybe I'm way off. Any help is appreciated.
EDIT: I am changing the title to make it more useful for future reference. After a helpful comment from Ryan pointing out the simple error in function naming, I was able to piece together a script that works. sort of...Here it is:
import os
def menu_system():
os.startfile("cpp2_11alt.py")
def loopCount_zero_to_ten():
os.startfile("cpp2_5b.py")
def positive_or_negative():
os.startfile("cpp2_6.py")
def print_a_string_one_character_at_a_time():
os.startfile("cpp2_7.py")
def sum_of_a_tuples_values():
os.startfile("cpp2_8.py")
def refresh_the_menu():
for x in range(4): print(" ")
for y in actions:print(y,":",actions[y])
for z in range(2): print(" ")
def exit_the_program():
quit()
def errhandler():
print("not sure what you want")
actions = {'1':menu_system,
'2':loopCount_zero_to_ten,
'3':positive_or_negative,
'4':print_a_string_one_character_at_a_time,
'5':sum_of_a_tuples_values,
'x':exit_the_program,
'm':refresh_the_menu}
for item in actions:
print(item,":",actions[item])
for z in range(2): print(" ")
selectedaction = input("please select an option from the list: ")
while True:
actions.get(selectedaction,errhandler)()
selectedaction = input("please select an option from the list: ")
quit()
There were many problems with the second attempt. I was referencing the dictionary key instead of the value when calling functions. I also had some bugs in the way the menu printed and handled input values. Now all I need to do is figure out how to get the dictionary values to print without all of the extra information:
This is the output when I print the menu:
2 : <function loopCount_zero_to_ten at 0x027FDA08>
3 : <function positive_or_negative at 0x027FD810>
1 : <function menu_system at 0x027FD978>
4 : <function print_a_string_one_character_at_a_time at 0x027FD930>
5 : <function sum_of_a_tuples_values at 0x027FD780>
x : <function exit_the_program at 0x027FD858>
m : <function refresh_the_menu at 0x027FD7C8>
AND how to get the menu to print in numeric order.
Once again, any help is appreciated.

I finally found a solution to the problem of sorting a dictionary and printing the function names as a string. In the last part of the edited question (3rd code section), I had the fixed code for the question that started this post: how to use integers in a dictionary to create a menu - with the intention of creating a switch/case style alternative and avoiding the ugly if/elif/else problems in the first code section.
Here's the final version of the working code:
import os
def menu_system():
os.startfile("cpp2_11alt.py")
def loopCount_zero_to_ten():
os.startfile("cpp2_5b.py")
def positive_or_negative():
os.startfile("cpp2_6.py")
def print_a_string_one_character_at_a_time():
os.startfile("cpp2_7.py")
def sum_of_a_tuples_values():
os.startfile("cpp2_8.py")
def refresh_the_menu():
for x in range(4): print(" ")
for key in sorted(actions):
print (key, '=>', actions[key].__name__)
for z in range(2): print(" ")
def exit_the_program():
quit()
def errhandler():
print("not sure what you want")
actions = {'1':menu_system,
'2':loopCount_zero_to_ten,
'3':positive_or_negative,
'4':print_a_string_one_character_at_a_time,
'5':sum_of_a_tuples_values,
'x':exit_the_program,
'm':refresh_the_menu}
for key in sorted(actions):
print (key, '=>', actions[key].__name__)
selectedaction = input("please select an option from the list: ")
while True:
actions.get(selectedaction,errhandler)()
selectedaction = input("please select an option from the list: ")
quit()
adding the .__name__ method allowed me to print the function names as a string.
Using the for loop:
for key in sorted(actions):
print (key, '=>', actions[key].__name__)
created the ability to sort the dictionary.

Related

Function to PDF using FPDF error: "Not enough horizontal space to render a single character"

First my class and class-function code:
class Dataframe1:
def __init__(self, Date, Email, Name)
self.Date = Date
self.Email = Email
self.Name = Name
def FunctionDF1(self):
if self.Date != "":
pdf.multi_cell(0, 5, "Date: {a}".format(a= self.Date))
elif self.Date == "":
pass
else:
pdf.multi_cell(0, 5, "Error")
if self.Name !="":
pdf.multi_cell(0 , 5, "/nName{a}".format(a= self.Name))
elif self.Name == "":
pass
else:
pdf.multi_cell(0 , 5, "/nError")
if self.Email !="":
pdf.multi_cell(0 , 5, "/nEmail{a}".format(a= self.Email))
elif self.Email == "":
pass
else:
pdf.multi_cell(0, 5, "/nError")
This gives no errors.
When I try to call it later, to write a PDF it does give errors.
i=1
while i< End1:
Data1 = Dataframe1(dataframe[0][i], dataframe[1][i], dataframe[2][i])
class PDF(FPDF):
def header(self):
# Logo
%cd /content/drive/MyDrive/Code/Intake
self.image('image.png', 100, 8, 33, 33)
self.set_font('Arial', '', 15)
self.cell(80)
#line break
self.ln(20)
# Page footer
def footer(self):
self.set_y(-15)
# Arial italic 8
self.set_font('Arial', 'I', 8)
# Page number
#self.cell(0, 5, u'Page ' + str(self.page_no()) + '/{nb}', 'C')
# Go to the folder with NOTO_SANS and import it.
%cd /content/drive/MyDrive/code/
pdf = PDF(format = "letter")
pdf.alias_nb_pages()
pdf.add_page()
#pdf.add_font('Noto_Sans', fname=r"Noto_Sans", uni=True)
base_Noto_path = '/content/drive/MyDrive/code/Noto_Sans'
pdf.add_font('Noto', '', os.path.join(base_Noto_path, 'NotoSans-Regular.ttf'))
pdf.add_font('Noto', 'B', os.path.join(base_Noto_path, 'NotoSans-Bold.ttf'))
pdf.set_font('Noto', '', 12)
pdf.multi_cell(0, 5, u'\n\n')
pdf.multi_cell(0, 5, u'Please contact Toll Free: \nor our International Texting Message number is: \nPlease email us \nThank you! \n \n')
#Not outputting the right stuff.
Data1.FunctionDF1()
i = i+1
%cd /content/drive/MyDrive/code/Intake
pdf.output('Initial_Intake_{A}_{B}.pdf'.format(A=Data1.Name, B=i))
The error is occurring on the line
Data1.FunctionDF1()
FPDFException: Not enough horizontal space to render a single character
Some difficulties encountered included formatting.
Other difficulties were getting it to output properly. Currently, all of the PDF outputs show the correct naming format, and show the manually added multi_cells but DO NOT show the function called multi_cells.
I was trying to output the function into the built pdf using fpdf.multi_cell() to write all the patient's data (unless blank) on a new line. I used a while i<End1: to loop through the patients and write their individual data on a different PDF.
def FunctionDF1(self):
if self.Date != "":
print("Date: {a}".format(a= self.Date))
elif self.Date == "":
pass
else:
print("Error")
if self.Name !="":
print("/nName{a}".format(a= self.Name))
elif self.Name == "":
pass
else:
print("/nError")
if self.Email !="":
print("/nEmail{a}".format(a= self.Email))
elif self.Email == "":
pass
else:
print("/nError")
I tried print() as shown above instead of multi_cell in the function. It worked to display the correct information, but it showed all patient data at once when called.
The trick I'm not understanding is how do I write ONLY one patient's data to the corresponding intake form PDF.
I wonder if there are better tools than a while loop for this.
I found that my main error was that I needed to specify
pdf.multi_cell(100,5,"Text")
When the width was no longer 0, the code did not throw an error anymore.
This did have the side effect of giving odd spacing to the PDF.

Creating a menu, adding the input to a list or csv file and display

I am trying to create a programme that allows me to add, remove, amend and display details. I have created a general class and an additional class, that allowed me to hold an empty list and add/remove details.
I am now struggling with my menu and how to add further details and display these. Can anyone help, please?
from AircraftInspection_2 import AircraftInspection_2
from RoutineInspection import RoutineInspection
inspection = RoutineInspection()
end_of_add_String = "X to return to main menu\n"
def display_inspection_inventory():
#if inspection.number_of_aircrafts == 0
#return
print (f'{"SN":>3} {"TN":<7} {"AFhrs":<7} {"Zone":<3} {"Corrosion":<3} {"Component":<8} {"Fault":<8} {"Actionalbe":<5}')
for count aircraft in enumerate(inspection.aircrafts):
print(f'{count + 1:>3} {aircraft.Serial_Number:>3} {aircraft.Tail_No:<7} {aircraft.AF_hrs:<7} {aircraft.Zone:<3} {aircraft.Corrosion:<3} {aircraft.Component:<8} {aircraft.Fault:<8} {aircraft.Actionable:<5}')
def menu_options():
print("Menu: ")
print("Key A - Add details.")
print("Key R - Remove details.")
print("Key C - Change details.")
print("Key D - Display details.")
print("Key X - Exit the programme")
print(" ")
menu_options()
def menu_choice():
letters = {"a", "r", "c", "d", "x"}
select = input()
while any(letter in letters for letter in select) and len(select) == 1:
pass
return select
#menu_choice()
def add_aircraft():
aircraft = get_aircraft_details()
try:
routineinspection.add(aircraft)
except ValueError as e:
print(f"{str(e)}")
def get_aircraft_details():
Tail_No = input("Please enter tailnumber: ")
AF_hours = int(input("Enter airframe hours: "))
Zone = input("Enter inspected zone: ")
Corrosion = int(input("Enter corrosion level: "))
Component = input("Enter inspected component: ")
Fault = input("Enter type of fault: ")
Actionable = bool(input("Enter 1 if actionable, 0 if not: "))
aircraft = Aircraft(Tail_No = Tail_No, AF_hours = AF_hours, Zone = Zone, Corrosion = Corrosion, Component = Component, Fault = Fault, Actionable = Actionable)
return aircraft
def remove_aircraft():
routineinspection.remove(aircraft)
while True:
display_inspection_inventory()
menu_options()
menu_choice()
option = menu_choice().upper()
if option == "A":
add_aircraft()
elif option == "R":
remove_aircraft()
#elif option =="C":
#amend_aircraft()
elif option == "X":
confirm = input("Do you want to quit the programme, y or n?").lower()
if confirm == "y":
break
else:
pass
print("See you again soon.")

Tkinter Not Opening Window

I am creating a program that allows a user to make a custom dice, but when I open a GUI window with a button that calls the backend dice roll logic, it breaks. In other words, the window doesn't open, and the code just runs in the terminal. It doesn't happen when the button is clicked like I want it to, instead when I run the code, it doesn't open any GUI window and the code executes in the terminal. The code works without the GUI, and if i take out the dice button callback, the GUI works but together it doesn't.
Any help is appreciated!
import random
import tkinter as tk
def dice_roll():
dice = []
x = 0
# used to check if the input is a whole number, if it isn't, you get a message
while True:
while x == 0:
try:
SIDE_AMT = int(input("How many sides would you like? (min is 2, max is infinite): ")) # amt is amount
x = 1
except ValueError:
print("Sorry it has to be a whole number.")
if SIDE_AMT > 1:
for side in range(SIDE_AMT):
print(f"What would you like side {side + 1} to be?:")
dice.append(str(input()))
break
else:
print("You can't have a dice with one side!")
x = 0
# roll function
def roll():
dice_side = random.choice(dice)
print(f"I choose {dice_side}!")
roll_num = 0
while True:
if roll_num == 0:
spin_it = str(input("Type 'roll' if you would like to roll the dice: "))
if spin_it == "roll":
roll()
else:
print("Sorry, you have to type roll correctly.")
roll_num += 1
elif roll_num == 1:
while True:
spin_it = str(input("Type 'roll' if you would like to roll the dice again!: "))
if spin_it == "roll":
roll()
else:
print("Sorry, you have to type roll correctly.")
if __name__ == '__main__':
gui = tk.Tk()
gui.title("Dice Roll")
gui.geometry("1912x1090")
gui.configure(bg='#a2a2a1', borderwidth=5,
relief="raised")
# title
title = tk.Label(gui, text='Unique Dice', font=("Times
New Roman", 52))
title.configure(bg='#a2a2a1', fg='#195190',
borderwidth=3, relief='raised')
# make a dice?
dice = tk.Button(gui,
text="Yes!",
fg="red",
command=dice_roll())
no_dice = tk.Button(gui,
text="No",
fg="red",
command=quit)
# frame = tk.Frame(gui, height=200, width=200)
# frame['borderwidth'] = 10
# frame['relief'] = 'sunken'
# frame.pack()
dice.pack()
no_dice.pack()
title.pack()
gui.mainloop()
you may want to do something like this:
import tkinter as tk
from random import choice
root = tk.Tk()
root.geometry('400x600')
root.resizable(False, False)
root.config(bg='light blue')
dice_numbers = [1, 2, 3, 4, 5, 6]
rolled_nums = []
def roll():
if len(rolled_nums):
rolled_nums[0].pack_forget()
rolled_nums.pop(0)
chosen_number = choice(dice_numbers)
text = tk.Label(root, text=f'{chosen_number}',
font='arial 500 bold', bg='light blue')
text.pack()
rolled_nums.append(text)
button = tk.Button(root, text='Roll Dice!', font='arial 20 bold', relief='raised', width='300',
bg='dark red', fg='black', command=lambda: roll())
button.pack()
root.mainloop()
fell free to adjust this code and if you have questions -> ask

how can i make the input work with my parameters?

I have started a python class and my book does not seem to help me.
My professor has a program that bombards my code with different inputs and if any of the inputs do not work then my code is "wrong". I have done many days worth of editing and am at a complete loss. I have the code working if someone puts and input of an actual number. But where my code fails the test is if input is "miles_to_laps(26)" it errors out.
I have tried changing the input to int(input()) but that does not fix the issue. I've gone through changing variables and even changing the input method but still am at a loss. I have already tried contacting my teacher but 6 days of no response and 3 days of being late i feel like I'm just going no where.
user_miles = int(input())
def miles_to_laps(user_miles):
x = user_miles
y = 4
x2 = x * y
result = print('%0.2f' % float(x2))
return result
miles_to_laps(user_miles)
my code works for real number inputs but my professor is wanting inputs like
miles_to_laps(26) and miles_to_laps(13) to create the same outputs.
For the wierd input functionality you can try:
import re
def parse_function_text(s):
try:
return re.search("miles_to_laps\((.+)\)", s)[1]
except TypeError:
return None
def accept_input(user_input):
desugar = parse_function_text(user_input)
if desugar is not None:
user_input = desugar
try:
return float(user_input)
except ValueError:
raise ValueError("Cannot process input %s" % user_input)
assert accept_input("miles_to_laps(3.5)") == 3.5
I'm trying to keep all the pedantism aside, but what kind of CS/programming teaching is that?
Areas of concern:
separate user input from rest of code
separate output formatting from function output
the code inside miles_to_laps is excessive
Now here is the code to try:
LAPS_PER_MILE = 4
# the only calculation, "pure" function
def miles_to_laps(miles):
return LAPS_PER_MILE * miles
# sorting out valid vs invalid input, "interface"
def accept_input(user_input):
try:
return float(user_input)
except ValueError:
raise ValueError("Cannot process input %s" % user_input)
if __name__ == "__main__":
# running the program
laps = miles_to_laps(accept_input(input()))
print ('%0.2f' % laps)
Hope this is not too overwhelming.
Update: second attempt
MILE = 1609.34 # meters per mile
LAP = 400 # track lap
LAPS_PER_MILE = MILE/LAP
def miles_to_laps(miles):
return LAPS_PER_MILE * miles
def laps_coerced(laps):
return '%0.2f' % laps
def accept_input(user_input):
try:
return float(user_input)
except ValueError:
raise ValueError("Cannot process input %s" % user_input)
def main(user_input_str):
miles = accept_input(user_input_str)
laps = miles_to_laps(miles)
print (laps_coerced(laps))
if __name__ == "__main__":
main(input())

changing a defineded function name depending on n term used

def usersdecision(n):
if option == n:
calculation.format(n)()
Is there a way to get calculation to become calculation + the value of n then (),
so if n=1 calculation would become calculation1().
Here is an inelegant way of doing it. Pass in a list, see how long it is and use the length to call different routines
import sys
def userd(*n):
if (len(n) == 1):
return calc1(n[0])
if (len(n) == 2):
return calc2(n[0],n[1])
if (len(n) > 2):
warn("bad input",n)
sys.exit(1)
def calc1(x):
return x*2
def calc2(x,x2):
return x**x2
assert userd(1) == 2
assert userd(2,3) == 8
print "it works"