Python Forum

Full Version: menu while loop
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
Hello! I have a problem with the code below.
If I remove the 2 lines below from the code, the code enters the loop.
If I leave it when I use option 1 for products and enter the products menu it also shows me the main menu (I marked with ---> the outp that I want to disappear)
products = ['product_id', 'name', 'producer','category','price', 'stock']
clients = ['cnp', 'last_name', 'first_name', 'age']

def menu():
    print("[1] Products")
    print("[2] Clients")
    print("[3] Display")
    print('[4] Report')
    print("[0] Exit the program.")


def products():
    #Adăugarea/ Ștergerea/ Actualizarea unui nou produs
    print("[1] Add new product")
    print("[2] Product update")
    print("[3] Delete product")
    print('[4] Go back to main page')
    print("[0] Exit the program.")

def clients():
    #Adăugarea/ Ștergerea/ Actualizarea unui nou client
    print("[1] Add new client")
    print("[2] Client update")
    print("[3] Delete client")
    print('[4] Go back to main page')
    print("[0] Exit the program.")


def display():
    #Afișarea listei de produse/ clienți
    #Afișarea unui client/ produs specific
    print("[1] Search list of: ")
    print("[2] Search a: ")
    print('[4] Go back to main page')
    print("[0] Exit the program.")

def reports():
    #Media de varsta a clientilor
    #Prețul mediu al produselor
    print("[1] Average age of clients: ")
    print("[2] The average price of the products ")
    print('[4] Return to the main menu')
    print("[0] Exit the program.")

def option3():
    print("Optiunea 3!")

menu()
option = int(input("Enter your option: "))

while option != 0:
    if option == 1:
        products()

    elif option == 2:
        clients()

    elif option == 3:
        display()

    elif option == 4:
        reports()

    else:
        print("Invalid option.")
    
    menu()                                -------->>>> this 2 line
    option = int(input("Enter your option: "))
    # sa nu intre in bucla

print("E gata!")
Output:
[1] Products [2] Clients [3] Display [4] Report [0] Exit the program. Enter your option: 1 [1] Add new product [2] Product update [3] Delete product [4] Go back to main page [0] Exit the program. [1] Products --->>> this output [2] Clients [3] Display [4] Report [0] Exit the program. ---> until here Enter your option:
You're headed for trouble. If you keep going like that you will have to create a differentif/eliflist for every menu. Let's organize a little differently. In this code we have oneoperate_menufunction that accepts a tuple of two lists. One list is the options to display for the menu and the other is a list of the command associated with those options. You can change the command that any menu item calls by changing the command in the command list. I've included adummy_functionas a place holder for the commands that you will be using.
Please let me know if you need any further help with this. Smile
products = ['product_id', 'name', 'producer','category','price', 'stock']
clients = ['cnp', 'last_name', 'first_name', 'age']

def operate_menu (menu_tuple) :
	acceptable_options = {'1': 0, '2': 1, '3': 2, '4': 3, '0': 4}
	display_list = menu_tuple [0]
	command_list = menu_tuple [1]
	while True :
		print ('\n----------------------')
		for item in display_list :
			print (item)
		option = input ('Enter your option: ')
		if option in acceptable_options :
			exec (command_list [acceptable_options [option]])
		else :
			print (f'\n{option} is not an acceptable option.')

def exit_the_program () :
	print("\n\nFinished!")
	exit () 

def dummy_function () :
	print ('\nThis is just a place holder function.\n')

products_menu = ((
	"[1] Add new product",
	"[2] Product update",
	"[3] Delete product",
	'[4] Go back to main page',
	"[0] Exit the program."),
	('dummy_function ()',
	'dummy_function ()',
	'dummy_function ()',
	'operate_menu (main_menu)',
	'exit_the_program ()'))
 
clients_menu = ((
	"[1] Add new client",
	"[2] Client update",
	"[3] Delete client",
	'[4] Go back to main page',
	"[0] Exit the program."),
	('dummy_function ()',
	'dummy_function ()',
	'dummy_function ()',
	'operate_menu (main_menu)',
	'exit_the_program ()'))

display_menu = ((
	"[1] Search list of: ",
	"[2] Search a: ",
	"[3] No operation.",
	'[4] Go back to main page',
	"[0] Exit the program."),
	('dummy_function ()',
	'dummy_function ()',
	'dummy_function ()',
	'operate_menu (main_menu)',
	'exit_the_program ()'))

reports_menu = ((
	"[1] Average age of clients: ",
	"[2] The average price of the products ",
	"[3] No operation.",
	'[4] Return to the main menu',
	"[0] Exit the program."),
	('dummy_function ()',
	'dummy_function ()',
	'dummy_function ()',
	'operate_menu (main_menu)',
	'exit_the_program ()'))

main_menu = ((
	"[1] Products",
	"[2] Clients",
	"[3] Display",
	'[4] Report',
	"[0] Exit the program."),
	('operate_menu (products_menu)',
	'operate_menu (clients_menu)',
	'operate_menu (display_menu)',
	'operate_menu (report_menu)',
	'exit_the_program ()'))
 

operate_menu (main_menu)
It is not a good idea to reinvent the wheel!

Seems to me, you need a database. I would use MySQL for this.

Python can interact with MySQL via the module pymysql.

json files are mini databases. They are a way of saving and passing on data, if MySQL seems difficult.

The code below will make a json file of all your products and product details.

You can change it to make a json file for your clients.

Then all you need is to read up on how to selectively display json file data.

Personally, I think you need a class for your products and clients.

I never use classes for my simple stuff, so I don't know much about them.

There is a guy here, deanhystad, he seems to be quite an expert on classes.

Maybe he can show you how to do this with classes.

def myApp():
    # Step 1
    # get the module
    import json
    
    # collect data
    # this is a list of things we need to know about each product
    # need some kind of check to keep 'product_id' unique
    collect_data = ['product_id', 'name', 'producer','category','price', 'stock']

    # save the information we collect in the list: product_data

    product_data = []

    # a function to collect our data
    # this function returns a dictionary with product data
    # this dictionary is saved in the list: product_data

    def get_product_data():
        product_dict = {}
        for info in collect_data:            
            product_dict[info] = input(f'Please enter the {info}: ')   
        return product_dict

    replies = ['yes', 'no']
    reply = 'X'
    # still need a way to keep the product ids unique!!
    while not reply in replies:    
        print('Do you want to enter a product?')
        reply = input('Enter yes to continue, enter no to stop ')
        if reply == 'yes':
            answers = get_product_data()
            product_data.append(answers)
            reply = 'maybe'
        elif reply == 'no':
            break

    # Step 2        
    # use a DICTIONARY COMPREHENSION to make  the list: product_data into a dictionary
    product_data_dict = {i:product_data[i] for i in range(len(product_data))}

    # look at product_data_dict

    for item in product_data_dict.items():
            print(json.dumps(item, indent = 4, sort_keys=True))

    # Step 3   
    # save user_data_dict as a .json file
    # USE YOUR PATH

    mypath = '/home/pedro/temp/product_data_json.json'
    # open 'a' in case the file already exists
    with open(mypath, 'a') as json_file:
      json.dump(product_data_dict, json_file)
    
    # Step 4
    # open the file you just saved in mypath
    # USE YOUR PATH

    with open(mypath) as f:
      data = json.load(f)

    print('data is ' + str(len(data)) + ' entries long')

    # look at the content of '/home/pedro/winter2020/20PY/json/user_data_json.json'

    for item in data.items():
        print(json.dumps(item, indent = 4, sort_keys=True))

    """
    You can open and append to this json file any time
    Make another json file for clients
    Then read up on how to display the contents of a json file

    """
If write menu function like this it will make more sense,this is how i usually do it when using menu with functions,can also call a class.
Now always fall back to the menu(loop) where can do other task or Quit out.
def solve_1():
    answer = int(input('What is 2 + 2? '))
    if answer == 4:
        print('Correct')
    else:
        print('Wrong,try again')

def prod(data):
    for item in data[0]:
        print(item)
    input('Press enter to retun to menu\n')

def func_data():
    products = ['product_id', 'name', 'producer','category','price', 'stock']
    clients = ['cnp', 'last_name', 'first_name', 'age']
    return products, clients

def menu():
    while True:
        print('(1) Solve something')
        print('(2) Show products list')
        print('(Q) Quit')
        choice = input('Enter your choice: ').lower()
        if choice == '1':
            solve_1()
        elif choice == '2':
            data =  func_data()
            prod(data)
        elif choice == 'q':
            return
        else:
            print(f'Not a correct choice: <{choice}>,try again')

if __name__ == '__main__':
    menu()
I suggest to insert the various menus in a collection (here a dictionary named 'menus'). This allows to refer to them more easily, add more of them etc.

Another useful feature is a registering system to register actions to do when the user makes a choice. Try to play with the following extensible code outline to see if you like it
import re

class Menu:
    def __init__(self, name, value):
        self.name = name
        self.value = value
        self.options = [s[1:-1] for s in re.findall(r'\[[^\]]*\]', value)]
        
    def __str__(self):
        return(self.value)

menus = {}

menus['main'] = Menu('main', """\
[1] Products
[2] Clients
[3] Display
[4] Report
[0] Exit the program.""")
 
menus['products'] = Menu('products', """\
[1] Add new product
[2] Product update
[3] Delete product
[4] Go back to main page
[0] Exit the program.""")
 
menus['clients'] = Menu('clients', """\
[1] Add new client
[2] Client update
[3] Delete client
[4] Go back to main page
[0] Exit the program.""")
 
 
menus['display'] = Menu('display', """\
[1] Search list of: 
[2] Search a: 
[4] Go back to main page
[0] Exit the program.""")
 
menus['reports'] = Menu('reports', """\
[1] Average age of clients: 
[2] The average price of the products 
[4] Return to the main menu
[0] Exit the program.""")

def ask_option(menu):
    while True:
        print(menu)
        opt = input('Please select an option: ')
        if opt in menu.options:
            try:
                return int(opt)
            except ValueError:
                return opt
        else:
            print(f'Invalid option, please choose one of {menu.options}')
            
registered = {}

def register(name, opt):
    def decorator(func):
        registered[(name, opt)] = func
        return func
    return decorator

@register('main', 1)
def main_choose_products(menu, opt):
    return menus['products']

@register('main', 2)
def main_choose_clients(menu, opt):
    return menus['clients']

@register('main', 3)
def main_choose_display(menu, opt):
    return menus['display']

@register('main', 4)
def main_choose_reports(menu, opt):
    return menus['reports']

@register('main', 0)
@register('products', 0)
@register('clients', 0)
@register('display', 0)
@register('reports', 0)
def all_choose_exit(menu, opt):
    return None

if __name__ == '__main__':
    menu = menus['main']
    while menu:
        opt = ask_option(menu)
        func = registered.get((menu.name, opt), None)
        if func:
            menu = func(menu, opt)
        else:
            menu = menus['main']
Here is another version using a class and a dictionary. I personally like this one best.
def dummy_function () :
	print ('\nThe dummy function has run.')

def say_goodbye () :
	print ('\nBye for now.')
	exit ()

class Menu_Tree :
	def __init__ (self) :
		self.all_menus = {
			'main_menu' : {
				"[1] Products": 'products_menu',
				"[2] Clients": 'clients_menu',
				"[3] Display": 'display_menu',
				'[4] Report': 'report_menu',
				"[0] Exit the program.": say_goodbye},
			'products_menu' : {
				"[1] Add new product": dummy_function,
				"[2] Product update": dummy_function,
				"[3] Delete product": dummy_function,
				'[4] Go back to main page': 'main_menu',
				"[0] Exit the program.": say_goodbye},
			'clients_menu' : {
				"[1] Add new client": dummy_function,
				"[2] Client update": dummy_function,
				"[3] Delete client": dummy_function,
				'[4] Go back to main page': 'main_menu',
				"[0] Exit the program.": say_goodbye},
			'display_menu' : {
				"[1] Search list of: ": dummy_function,
				"[2] Search a: ": dummy_function,
				'[4] Go back to main page': 'main_menu',
				"[0] Exit the program.": say_goodbye},
			'report_menu' : {
				"[1] Average age of clients: ": dummy_function,
				"[2] The average price of the products ": dummy_function,
				'[4] Return to the main menu': 'main_menu',
				"[0] Exit the program.": say_goodbye}}

		self.run_menus (self.all_menus ['main_menu'])

	def run_menus (self, menu) :
		look_up_table = {label [1: 2]: label for label in menu}
		print ('\n==============================')
		for label in menu :
			print ('     ', label)
		while True :
			menu_choice = input ('Enter your selection: ')
			if menu_choice != '' and menu_choice in look_up_table :
				command = menu [look_up_table [menu_choice]]
				if type (command) == str :
					self.run_menus (self.all_menus [command])
				else :
					command ()
					self.run_menus (self.all_menus ['main_menu'])
			else :
				print (f'     "{menu_choice}" is not a valid entry.')

Menu_Tree ()
@BashBedlam With very little work, you could make Menu_Tree.run_menus() non recursive. Also add the possibility that after command(), the menu to run is not the main_menu.
(Dec-20-2021, 07:09 AM)Gribouillis Wrote: [ -> ]@BashBedlam With very little work, you could make Menu_Tree.run_menus() non recursive. Also add the possibility that after command(), the menu to run is not the main_menu.
This would be my best shot at that Cool
def dummy_function () :
	print ('\n   The dummy function has finished running.')

def say_goodbye () :
	print ('\nBye for now.')
	exit ()

class Menu_Tree :
	def __init__ (self) :
		self.all_menus = {
			'main_menu' : {
				"[1] Products": 'products_menu',
				"[2] Clients": 'clients_menu',
				"[3] Display": 'display_menu',
				'[4] Report': 'report_menu',
				"[0] Exit the program.": say_goodbye},
			'products_menu' : {
				"[1] Add new product": dummy_function,
				"[2] Product update": dummy_function,
				"[3] Delete product": dummy_function,
				'[4] Go back to main page': 'main_menu',
				"[0] Exit the program.": say_goodbye},
			'clients_menu' : {
				"[1] Add new client": dummy_function,
				"[2] Client update": dummy_function,
				"[3] Delete client": dummy_function,
				'[4] Go back to main page': 'main_menu',
				"[0] Exit the program.": say_goodbye},
			'display_menu' : {
				"[1] Search list of: ": dummy_function,
				"[2] Search a: ": dummy_function,
				'[4] Go back to main page': 'main_menu',
				"[0] Exit the program.": say_goodbye},
			'report_menu' : {
				"[1] Average age of clients: ": dummy_function,
				"[2] The average price of the products ": dummy_function,
				'[4] Return to the main menu': 'main_menu',
				"[0] Exit the program.": say_goodbye}}

		self.run_the_current_command ('main_menu')

	def run_the_current_command (self, command) :
		if type (command) == str :
			self.current_menu = command
			command = self.run_the_menus (self.all_menus [command])
		else :
			command ()
			self.run_the_menus (self.all_menus [self.current_menu])

	def run_the_menus (self, menu) :
		look_up_table = {label [1: 2]: label for label in menu}

		print ('\n   ==============================')
		for label in menu :
			print ('     ', label)

		still_selecting = True
		while  still_selecting :
			menu_choice = input ('   Enter your selection: ')
			if menu_choice != '' and menu_choice in look_up_table :
				still_selecting = False
				command = menu [look_up_table [menu_choice]]
			else :
				print (f'     "{menu_choice}" is not a valid entry.')

		self.run_the_current_command (command)

if __name__ == '__main__' :
	Menu_Tree ()
(Dec-18-2021, 03:56 AM)Pedroski55 Wrote: [ -> ]It is not a good idea to reinvent the wheel!

Seems to me, you need a database. I would use MySQL for this.

Python can interact with MySQL via the module pymysql.

json files are mini databases. They are a way of saving and passing on data, if MySQL seems difficult.

The code below will make a json file of all your products and product details.

You can change it to make a json file for your clients.

Then all you need is to read up on how to selectively display json file data.

Personally, I think you need a class for your products and clients.

I never use classes for my simple stuff, so I don't know much about them.

There is a guy here, deanhystad, he seems to be quite an expert on classes.

Maybe he can show you how to do this with classes.

def myApp():
    # Step 1
    # get the module
    import json
    
    # collect data
    # this is a list of things we need to know about each product
    # need some kind of check to keep 'product_id' unique
    collect_data = ['product_id', 'name', 'producer','category','price', 'stock']

    # save the information we collect in the list: product_data

    product_data = []

    # a function to collect our data
    # this function returns a dictionary with product data
    # this dictionary is saved in the list: product_data

    def get_product_data():
        product_dict = {}
        for info in collect_data:            
            product_dict[info] = input(f'Please enter the {info}: ')   
        return product_dict

    replies = ['yes', 'no']
    reply = 'X'
    # still need a way to keep the product ids unique!!
    while not reply in replies:    
        print('Do you want to enter a product?')
        reply = input('Enter yes to continue, enter no to stop ')
        if reply == 'yes':
            answers = get_product_data()
            product_data.append(answers)
            reply = 'maybe'
        elif reply == 'no':
            break

    # Step 2        
    # use a DICTIONARY COMPREHENSION to make  the list: product_data into a dictionary
    product_data_dict = {i:product_data[i] for i in range(len(product_data))}

    # look at product_data_dict

    for item in product_data_dict.items():
            print(json.dumps(item, indent = 4, sort_keys=True))

    # Step 3   
    # save user_data_dict as a .json file
    # USE YOUR PATH

    mypath = '/home/pedro/temp/product_data_json.json'
    # open 'a' in case the file already exists
    with open(mypath, 'a') as json_file:
      json.dump(product_data_dict, json_file)
    
    # Step 4
    # open the file you just saved in mypath
    # USE YOUR PATH

    with open(mypath) as f:
      data = json.load(f)

    print('data is ' + str(len(data)) + ' entries long')

    # look at the content of '/home/pedro/winter2020/20PY/json/user_data_json.json'

    for item in data.items():
        print(json.dumps(item, indent = 4, sort_keys=True))

    """
    You can open and append to this json file any time
    Make another json file for clients
    Then read up on how to display the contents of a json file

    """

I try to save the dictionary in a json file in the folder called project but I automatically create another file in the main folder and add the information there. I tried 3 methods and the same thing happens with everything
    if name == 'products':
        m = 'D:\python visio\proiect\clients.json'
        #m = 'D:\python visio\proiect\clients.json'
        #m = 'proiect\products.json
        with open(m, 'w') as f:
            json.dump(answer, f)

    
FIXED
Sorry, I don't know what you mean by "same thing happens". For the code snippet above, can you tell us what the computer does (output or error) and what you expect to happen instead?

Is the folder in the middle supposed to be named "proiect" instead of "project"?
Pages: 1 2