Python 3.9.x | Cannot 'return' variable with user entry validation - function

I'm having problems getting my code to 'return' one of the option strings correctly.
If the user inputs one of the string options correctly the first time through, then the 'return' value comes back perfectly fine when going through the 'while' to 'if/elif' statements. No problem.
However, if the user DOES NOT input the data correctly the first time through, I'm trying to catch that with my final 'else' statement and then begin the function again. However, the second/third/ect time through, even if the user inputs a valid selection, the 'return' type is None and the value returned is None.
So, my user validation is missing something. Any thoughts?
#Global variable initialization
mainSelection = str(None)
#Santa's Christmas Card List Main Menu function
def XmasMainMenu(mainSelection):
print('')
print('How may the elves be of service today?')
print('')
print('\"PRINT\" - Print out the Christmas card list from the database.')
print('\"ADD\" - Add nice recipients information to the Christmas card list.')
print('\"SEARCH\" - Search the database for information.')
print('\"DELETE\" - Remove naughty recipients from the Christmas card list. ')
print('\"EXIT\" - Exit the program without any printing or changes to the database.')
print('')
mainSelection = input('Please enter your selection: ')
mainSelection = mainSelection.lower()
print(type(mainSelection), mainSelection)
#Selection return value
while mainSelection != None:
if mainSelection == 'print':
print('|| Will print out the Xmas Card List ||')
return mainSelection
elif mainSelection == 'add':
print('|| Will prompt user to add information to the DB ||')
return mainSelection
elif mainSelection == 'search':
print('|| Will prompt user to search the information in the DB ||')
return mainSelection
elif mainSelection == 'delete':
print('|| Will prompt the user to delete recipients from the DB ||')
return mainSelection
elif mainSelection == 'exit':
print('|| Will exit the user from the program with no changes')
return mainSelection
elif mainSelection == 'drop table':
print('|| Will call the XmasTableDrop function ||')
return mainSelection
else:
print('')
print('Input Error: Please enter a valid selection above!')
print('Try again...')
print('')
print(type(mainSelection), mainSelection)
break
XmasMainMenu(mainSelection)
Program Launch
User input correct, 'return' value is correct
1st user input invalid. Error message is received, the function starts over again. 2nd user input valid --> however, the 'return' type is None and the value is None (this is what I need to fix, but cannot figure out).

This is a typical "new programmer" mistake. Do not call a function within the function itself unless you know what recursion is and how it works. When a called function returns it returns to the function that called it. What happens is:
XmasMainMenu is called from the top-level script.
...user enters an incorrect value...
XmasMainMenu calls XmasMainMenu again.
...user enters a correct value....
XmasMainMenu (2nd call) returns to XmasMainMenu (1st call)
The return value is not assigned to anything, so is lost.
Now at the end of the function with no return, so returns default None.
top-level script receives None.
Instead, wrap your code in a while True: and break when you get a correct value, then return that (pseudo-code):
def XmasMainMenu():
while True:
print menu # this could be outside while if you don't want to re-print menu.
selection = input()
if selection valid:
break # exit while loop
else:
prompt user to enter valid input.
return selection

Related

dash error loading dependencies when adding a editable table

I'm trying to add an editable table in my dash app and use the edited data in the following step.
First, I have a callback that is triggered by a button, receives a file, the function processes the file and the output is the editable table and a json data. The table is showing on the screen.
Then, I want the user to do the necessary changes in the table and click on another button.
The click will trigger another callback that should receive the edited data from the table + the json data from the previous callback and as output, another json data.
However, when I test the function, I get "error loading dependencies".
I'm using a very old version of dash 0.43 and at the moment I can't update (many functions were deprecated and I can't change them all now).
#dash_application.callback(
[Output('journey-data-store-raw', 'data'),
Output('new-lable-table', 'children'), #this goes to a div in the layout file
Output('source-table-updated', 'data')],
[Input('parser-process', 'n_clicks')],
[State('upload-data', 'contents'),
State('upload-data', 'filename'),
State('decimal-selection', 'value')]
)
def source_data(_, content, name, decimal_selection):
"""Show the sources to allow the user to edit it"""
if name:
clean_data = get_clean_data(content, name, decimal_selection)
clean_data.to_csv('clean_data_test.csv')
return df_to_json(clean_data), dash_table.DataTable(**get_sources(clean_data)), json.dumps({'updated': True})
else:
print('deu ruim')
raise dash.exceptions.PreventUpdate
#dash_application.callback(
[Output('journey-data-store', 'data'),
Output('color-store', 'data')],
[Input('run-analysis', 'n_clicks')],
[State('sources-table', 'data'),
State('journey-data-store-raw', 'data')]
)
def store_data(_, new_table, raw_data):
"""Stores the datafile and colors in a Store object"""
i = 0
for row in new_table:
if row['new source labels'] != '':
i = 1
break
if i > 0:
# call function to "parser file"
# colors = get_colors(new_data)
# return df_to_json(clean_data), json.dumps(colors)
# the return is only a test, I'd develop the function later I just wanna test and make
# the call back work
return raw_data, json.dumps(get_colors(df_from_json(raw_data)))
else:
return raw_data, json.dumps(get_colors(df_from_json(raw_data)))
I tried to exclude the button and the sources-table of the callback, so it would trigger when the first callback is finished (journey-data-store-raw is available). But is not happening either.
i tried to run in a private window.

How can I assign an output to a function call in python?

I know I can't necessarily assign values to function call, so how would I assign an output to that function call? I've built a function that checks if a location (row,col) is valid in puzzle(list). I built another function that returns the value at that location. I am now building a third function that calls those two functions to set a value at a specific location, if that value was initially none. If the value was able to be set, it needs to return True. If the value was not None, it doesn't need to be set and it should return false.
For example:
set_location([[1]], 1, (0,0)) → False
set_location([[None]], 1, (0,0)) → True # puzzle is now [[1]]
My code is the following:
def is_valid_location(loc,puzzle):
x,y=loc
return x in range(len(puzzle[0])) and y in range(len(puzzle))
def get_value_at_location(puzzle,loc):
val_loc=puzzle[loc[0]][loc[1]]
return val_loc
def set_location(puzzle,value,loc):
if is_valid_location(loc,puzzle)== True:
if get_value_at_location(puzzle,loc) != None:
return False
else:
if get_value_at_location(puzzle,loc) == None:
get_value_at_location(puzzle,loc)= value
return True
Obviously the problem is this line:
get_value_at_location(puzzle,loc)= value
But I'm not sure how else to do it. Any suggestions?
Would your solution be:
value = get_value_at_location(puzzle,loc)

Function does not deliver the desired values in python

I am trying to use both functions below:
def func1():
print('blahblah')
func2()
def func2():
check = 0
while check < 1:
first = input('Integer or pass ')
if first == 'pass':
first = 0
func1()
break
else:
first = int(first)
second = input('Integer or pass')
if second == 'pass':
second = 0
func1()
break
else:
second = int(second)
third = input('Integer or pass' )
if third == 'pass':
third = 0
func1()
break
else:
third = int(third)
check = 1
return first, second, third
The func2 returns None instead of the inputs when once "pass" was entered. What am I doing wrong?
edit: the results should be 3 integers, no matter how many times 'pass' was entered.
After changing the indentation I get following error: UnboundLocalError: local variable 'second' referenced before assignment (in case I start with pass)
For clarifcation: func2 asks for input, if input is "pass" then func1 is called.
After the print func1 calls func2 again . This repeats until 3 integers are input. Their valus shall be returned in th end.
Your indentation is wrong. You need to move the last statement return first, second, third one tab before.

How to call a function with less arguments that is set (Python 3)

I am making a terminal emulator in Python 3. The commands are being stored in functions, like:
def rd(os_vartmp, os_vartmp2):
if os_vartmp == None:
print('rd [path] [-S]')
print('Delete a folder')
else:
if os.path.isfile(os_vartmp) == True:
if os_vartmp2 == '-S': print('a')
else:
print(ERR5)
a = input('Command: ')
The terminal works like this:
Asks user for input
Splits the input
Uses the first part of input to search a function in locals
If there is one, uses the rest part of input as argument
Calls the function
The thing here is, when i call the function 'rd' with, for example, 'rd "boot.py" -S' it works just fine. But if i need to call it like this: rd "boot.py", it throws me a error about 1 argument given when 2 are required. Is there a fix for that?
You can make an argument optional by assigning a value in the method definition. For example:
def Add(x=0, y=0):
return x+y
If you input only one value, y will default to 0. If I wanted to give y a value but have x fall back on it's default value I could do Add(y=10). I hope this helped!
Have you tried this?
def rd(os_vartmp, os_vartmp2="-S"):
Instead of trying to get null value, which would require rd("boot.py",null), you can ser default value and then you can do rd("boot.py").
Hope it works.

stop recursion from 'deepest' reccursion in python 3

I am trying to stop errors happening in my code when an invalid input is entered by the user. Here is a simplified example that demonstrates my problem.
def foo():
try:
a = int(input('1,2,3 or 4'))
except (ValueError, UnboundLocalError):
print ('invalid input')
print ('')
print ('Try 1,2,3 or 4')
foo()
if a == 3:
print ('done')
When I input an intiger the function runs perfectly. When I input a string into the a = int(input()) part it runs foo() again. However, when I then input 3 it prints done' but goes on to give as many ValueError's as times I made an incorrect inputs followed by an UnboundLocalError.I think this is because im running the function over and over inside itself so it then has to 'come out' of this. Is there a better way to re run the function without using recursion? I am new to programming.
Put the last two lines inside the try..except block.
def foo():
try:
a = int(input('1,2,3 or 4'))
if a == 3:
print ('done')
except (ValueError, UnboundLocalError):
print ('invalid input')
print ('')
print ('Try 1,2,3 or 4')
foo()
And you'd better use while loop to avoid increasing the recursion depth:
def foo():
while True:
try:
a = int(input('1,2,3 or 4'))
if a == 3:
print ('done')
break
except (ValueError, UnboundLocalError):
print ('invalid input')
print ('')
print ('Try 1,2,3 or 4')
The issue you're having is that you don't exit the function when you recurse in your exception handler. One solution would be to return foo() when you recurse, but this is still going to be awkward (Python doesn't do tail call optimization, so this will build up a big stack of calls waiting to be returned from, if you keep entering invalid values). A better solution is to use a loop:
a=None:
while a is None:
try:
a = int(input('1,2,3 or 4'))
except ValueError:
print ('invalid input')
print ('')
print ('Try 1,2,3 or 4')
# you could do more validation here, and set `a` back to `None` if it is invalid
if a == 3:
print("done")
The while loop will keep on asking for input until an acceptable value is provided by the user. No recursion is needed.
Pull the try and except block outside of your recursive function This way you don't enter multiple different trys. Then when your recursive function throws an error, it'll go all the way back up it that one any only try block that you have.