Similar validation functions don't work - python

First of all, sorry for not using OOP, I just decided to avoid complexity for such a small program.
So here's my program (basically, it's an Entry widget that allows a text that only consists of integers whose maximum length is 5):
from tkinter import *
root = Tk()
root.title("Entry Validation")
root.geometry("300x100")
def validation_function(text):
if len(text) <= 5:
try:
text = int(text)
return True
except:
return False
else:
return False
vcmd = root.register(validation_function)
entry = Entry(root, validate='key', validatecommand=(vcmd, "%P"))
entry.pack()
It works normal. But when I make a little change in the body of the validation function, it doesn't work:
def validation_function(text):
try:
text = int(text)
if len(text) <= 5:
return True
else:
return False
except:
return False
I feel the problem is here:
except:
return False
Probably the max length part doesn't go well with try-except... However:
def validation_function(text):
try:
if len(text) <= 5:
return True
else:
return False
except:
return False
works correctly. But there is only the max length part, I also want it to allow only integers. I've done it in the first example, but my question is: why doesn't it work when I change the places of the max length part with the only integers part?

text is an int ... you cannot call len(int) ... it will raise an exception
try this
def validation_function(text):
try:
int(text)
except:
return False
if len(text) <= 5:
return True
return False

Related

validation of tkinter entry widget [duplicate]

This question already has answers here:
Interactively validating Entry widget content in tkinter
(10 answers)
Closed 3 years ago.
I have an entry field in my tkinter GUI app. entry should only accept numbers including decimal points. I used a function to validate the entry. The problem is, it is not accepting decimal point(.) if there is a digit in front of it. (example 25.3 wont accept). if there is a point in the beginning, it is not accepting any number after that. Could anyone help me with this problem. and any suggestion to limit the maximum value in the entry field to 1000?
import tkinter as tk
def acceptNumber(inp):
if inp.isdigit():
return True
elif inp is "":
return True
elif inp is ".":
return True
else:
return False
win = tk.Tk()
reg = win.register(acceptNumber)
entryHere =tk.Entry(win)
entryHere.place(x=400, y=200)
entryHere.config(validate="key", validatecommand =(reg, '%P'))
win.mainloop()
This accepts valid decimal numbers not greater than 1000:
def acceptNumber(inp):
try:
return True if inp == '' else float(inp) <= 1000
except:
return False
>>> s='1234'
>>> s.isdigit()
True
>>> sdot = '1234.'
>>> sdot.isdigit()
False
Isn't this your problem. isdigit() means digits only.

Homework, Python 3: Changing a Variable Type From Within a Function

For part of an assignment I need to return variables from one function as a string. I then need to take those variables and put them through another function, finally returning those same variables as integers. I hope this isn't too vague. This seems like something that would have been easy enough to find on my own, but it's been about an hour of searching.
startHour and startMinute are the variables I would like to convert.
Here are the functions in question:
hoursList = []
minutesList = []
listSize = 0
def createList(listSize): #WORKING
while listSize < 24:
hoursList.append(listSize)
listSize += 1
while listSize < 84:
minutesList.append(listSize - 24)
listSize += 1
createList(listSize)
def collectUserInputTime(): #WORKING
startHour, startMinute = input("Enter the time the call starts in 24-hour rotation:\n").split(":")
return startHour, startMinute
def validateUserInputTime(startHour, startMinute): #NEED TO CHANGE STRING TO INT
if int(startHour) in hoursList and int(startMinute) in minutesList:
#print("PASS")
return True, int(startHour), int(startMinute)
else:
print("FAIL")
return False
startHour, startMinute = collectUserInputTime()
validateUserInputTime(startHour, startMinute)
I also tried:
return startHours = int(startHour), startMinute = int(startMinute)
How shall I proceed? Thanks.
Your code correctly returns integer values from validateUserInputTime:
return True, int(startHour), int(startMinute)
But when you call the function, you ignore those return values:
validateUserInputTime(startHour, startMinute)
… so it doesn't matter that they're correct; you aren't doing anything with them.
If you then try to print(type(startHour)), it will still be str, because it's still a name for the same value it's always been.
If you want to assign those return values to your variables, you need an assignment statement:
success, startHour, startMinute = validateUserInputTime(startHour, startMinute)
And now, print(type(startHour)) will show int.
However, this is a very weird interface for a function. If it succeeds, you return True plus two values; if it fails, you return False plus nothing else. So, for invalid times, that assignment is going to raise a TypeError: 'bool' object is not iterable.
You could fix this by returning three values even in the failure case:
return False, int(startHour), int(startMinute)
Or, maybe more simply, just use a single return:
success = int(startHour) in hoursList and int(startMinute) in minutesList
if not success:
print("FAIL")
return success, int(startHour), int(startMinute)
it is getting converted just you can't figure it out your function validateUserInputTime() is returning values in integer format just you are not displaying it using print statement
use this code:
hoursList = []
minutesList = []
listSize = 0
def createList(listSize): #WORKING
while listSize < 24:
hoursList.append(listSize)
listSize += 1
while listSize < 84:
minutesList.append(listSize - 24)
listSize += 1
createList(listSize)
def collectUserInputTime(): #WORKING
startHour, startMinute = input("Enter the time the call starts in 24-hour rotation:\n").split(":")
return startHour, startMinute
def validateUserInputTime(startHour, startMinute):
if int(startHour) in hoursList and int(startMinute) in minutesList:
#print("PASS")
return True, int(startHour), int(startMinute)
else:
print("FAIL")
return False
startHour, startMinute = collectUserInputTime()
print(validateUserInputTime(startHour, startMinute))

How to return a boolean value and print a message in python

for example, I want to return a Boolean value False and print a message ("It did not pass the test") at same time in python, how to do that?
Are you looking for this?
def this_returns_false(<arguments>):
"""
Do stuff here
"""
return False
if not this_returns_false(<args>): # not accesses the function for False statement now
print "It did not pass the test"
a possible shorthand:
print "It did not pass the test" if not this_returns_false else ""
OP's code:
def password_check(password):
upper_letter = str.upper(lower_letter)
if ((count_digit(password) == 0) or (count_Lletter(password) == 0) or (count_Uletter(password) == 0)):
return False and print("it did not pass the test")
Edit after OP's code:
def password_check(password):
upper_letter = str.upper(lower_letter)
if (not count_digit(password)) or (not count_Lletter(password)) or (not count_Uletter(password)):
# not is the same as !
print("it did not pass the test")
return False
The print statement is executed before the return statement here btw.

Appending to a file, then reading from it into a list, then re-appending to it and overwriting certain parts

I want to be able to have a program whereby the user can input a paragraph/sentence/word/character whatever and have that stored in a list e.g. in list[0]. Then I want them to be able to write another bit of text and have that stored in e.g. list[1]. Then at any time I want the user to be able to read that from the list by choosing which segment they want to read from e.g. reading "hello" from list[0] whilst in list[1] "hi" is stored. Then when the user exits the program I want the list to be written to an external file. Then, at next start up, the program should read the file contents and store it again in the list so that the user can add more bits of text or read the current bits. When the list is saved to a file it should append new or changed parts but overwrite parts that are the same so as not to have duplicates. I have attempted this without much success. I am to be honest not sure if it is possible. I have browsed similar forums and have found that hasn't helped much so here it is.
My code so far:
import os
import time
import csv
global write_list
global f1_contents
write_list = []
def write():
os.system("cls")
user_story = input("Enter your text: \n")
write_list.append(user_story)
def read():
os.system("cls")
user_select_needs = True
while user_select_needs == True:
user_select = input("Enter the list section to read from or type exit: \n")
if user_select == "exit":
user_select_needs = False
try:
int(user_select)
select = user_select
select = int(select)
try:
print(write_list[select])
user_select_needs = False
enter = input("Press enter:")
except:
print("There is not stored data on that section!")
except ValueError:
print("That is not a valid section!")
def exit():
os.system("cls")
max_num_needs = True
while max_num_needs == True:
set_max_num = input("Set the storage: \n")
try:
int(set_max_num)
max_num = set_max_num
max_num = int(max_num)
max_num_needs = False
except:
print("It must be an integer!")
for i in range(0, max_num):
f = open("Saves.txt", "a")
f.write(write_list[i])
f.close()
os._exit(1)
def main():
store_num_needs = True
while store_num_needs == True:
set_store_num = input("State the current storage amount: \n")
try:
int(set_store_num)
store_num = set_store_num
store_num = int(store_num)
store_num_needs = False
except:
print("It must be an integer!")
try:
f1 = open("Saves.txt", "r")
for i in range(0, store_num+1):
i, = f1.split("#")
f1.close()
except:
print("--------Loading-------")
time.sleep(1)
while True:
os.system("cls")
user_choice = ""
print("Main Menu" + "\n" + "---------")
print("1) Write")
print("2) Read")
print("3) Exit")
while user_choice not in ["1", "2", "3"]:
user_choice = input("Pick 1, 2 or 3 \n")
if user_choice == "1":
write()
elif user_choice == "2":
read()
else:
exit()
if __name__ == "__main__":
main()
It might be too complicated to understand in which case just ask me in comments- otherwise general tips would be nice aswell.
Thanks in advance
A quick point of correction:
global is only required if you're defining a global variable inside a non-global context. In other words, anything defined at the default indentation level, will be accessible by everything else defined below it. For example:
def set_global():
x = 1
def use_global():
x += 1
set_global()
try:
use_global()
except Exception as e:
# `use_global` doesn't know
# about what `set_global` did
print("ERROR: " + str(e))
# to resolve this we can set `x` to a
# default value in a global context:
x = 1
# or, if it were required, we
# could create a global variable
def make_global():
global x
make_global()
# either will work fine
set_global()
use_global()
print(x) # prints 2
Now to the actual question:
I haven't read through the block of code you wrote (probably best to trim it down to just the relevant bits in the future), but this should solve the problem as I understand it, and you described it.
import os
import sys
user_text = []
# login the user somehow
user_file = 'saves.txt'
def writelines(f, lines):
"""Write lines to file with new line characters"""
f.writelines('\n'.join(lines))
def readlines(f):
"""Get lines from file split on new line characters"""
text = f.read()
return text.split('\n') if text else []
class _Choice(object):
"""Class that is equivalent to a set of choices
Example:
>>> class YesObj(Choice):
>>> options = ('y', 'yes')
>>> Yes = YesObj()
>>> assert Yes == 'yes'
>>> assert Yes == 'y'
>>> # assertions evaluate to True
Override the `options` attribute to make use
"""
allowed = ()
def __eq__(self, other):
try:
s = str(other)
except:
raise TypeError("Cannot compare with non-string")
else:
return s.lower() in self.allowed
def _choice_repr(choices):
allowed = []
for c in choices:
if isinstance(c, _Choice):
allowed.extend(c.allowed)
else:
allowed.append(c)
if len(allowed) > 2:
s = ', '.join([repr(c) for c in allowed[:-1]])
s += ', or %s' % repr(allowed[-1])
elif len(allowed) == 1:
s = '%s or %s' % allowed
else:
s = '%s' % allowed[0]
return s
def _choice_sentinel(name, allowed):
"""Creates a sentinel for comparing options"""
return type(name, (_Choice,), {'allowed': list(allowed)})()
Quit = _choice_sentinel('Quit', ('q', 'quit'))
Yes = _choice_sentinel('Yes', ('y', 'yes'))
No = _choice_sentinel('No', ('n', 'no'))
def readline_generator(f):
"""Generate a file's lines one at a time"""
t = f.readline()
# while the line isn't empty
while bool(t):
yield t
t = f.readline()
def read_from_cache():
"""Overwrite `user_text` with file content"""
if not os.path.isfile(user_file):
open(user_file, 'w').close()
globals()['user_text'] = []
else:
with open(user_file, 'r') as f:
lines = readlines(f)
# replace vs extend user text
for i, t in enumerate(lines):
if i == len(user_text):
user_text.extend(lines[i:])
else:
user_text[i] = t
def write_to_cache():
"""Overwrite cache after the first line disagrees with current text
If modifications have been made near the end of the file, this will
be more efficient than a blindly overwriting the cache."""
with open(user_file, 'r+') as f:
i = -1
last_pos = f.tell()
# enumerate is a generator, not complete list
for i, t in enumerate(readline_generator(f)):
if user_text[i] != t:
# rewind to the line before
# this diff was encountered
f.seek(last_pos)
# set the index back one in
# order to catch the change
i -= 1
break
last_pos = f.tell()
# then cut off remainder of file
f.truncate()
# recall that i is the index of the diff
# replace the rest of it with new
# (and potentially old) content
writelines(f, user_text[i+1:])
def blind_write_to_cache():
"""Blindly overwrite the cache with current text"""
with open(user_file, 'w') as f:
writelines(f, user_text)
def overwrite_user_text(i, text, save=False):
"""Overwrite a line of text
If `save` is True, then these changes are cached
"""
try:
user_text[i] = text
except IndexError:
raise IndexError("No text exists on line %r" % (i+1))
if save:
write_to_cache()
def user_input():
"""Get a new line from the user"""
return raw_input("input text: ")
def user_choice(msg, choices):
if len(choices) == 0:
raise ValueError("No choices were given")
ans = raw_input(msg)
if ans not in choices:
print("Invalid Response: '%s'" % ans)
m = "Respond with %s: " % _choice_repr(choices)
return user_choice(m, choices)
else:
return ans
def user_appends():
"""User adds a new line"""
user_text.append(user_input())
def user_reads(*args, **kwargs):
"""Print a set of lines for the user
Selects text via `user_text[slice(*args)]`
Use 'print_init' in kwargs to choose how
many lines are printed out before user must
scroll by pressing enter, or quit with 'q'."""
print_init = kwargs.get('print_init', 4)
sliced = user_text[slice(*args)]
if not isinstance(sliced, list):
sliced = [sliced]
for i, l in enumerate(sliced):
if i < print_init:
print(l)
sys.stdout.flush()
elif user_choice(l, ['', Quit]) == Quit:
break
def user_changes(i=None, save=False):
"""User changes a preexisting line"""
attempt = True
while i is None and attempt:
# get the line the user wants to change
i_text = raw_input("Line to be changed: ")
try:
# make user input an index
i = int(i_text)
except:
# check if they want to try again
c = user_choice("Bad input - '%s' is not an "
"integer. Try again? " % i_text, (Yes, No))
attempt = (c == Yes)
if attempt:
# user gave a valid integer for indexing
try:
user_reads(i-1)
overwrite_user_text(i-1, user_input(), save)
except Exception as e:
print("ERROR: %s" % e)
if user_choice("Try again? ", (Yes, No)):
user_changes(i, save)
# stores whatever text is already on
# file to `user_text` before use
read_from_cache()

Understanding True/False evaluations in the context of Python dictionaries

I am working through the EdEx 6.00.2x course online and am struggling with one portion of my code:
newResistances = copy.deepcopy(self.resistances)
for drugs in self.resistances:
resistancePicker = random.random()
if self.resistances[drugs] == True:
if resistancePicker < self.mutProb:
print self.mutProb
newResistances[drugs] = False
elif self.resistances[drugs] == False:
if resistancePicker < self.mutProb:
print self.mutProb
newResistances[drugs] = True
print newResistances
return ResistantVirus(self.maxBirthProb, self.clearProb, newResistances, self.mutProb)
self.resistances is a dictionary containing drug name keys, and True or False values {'a':True,'b':True}. My problem is that only the first element of the dictionary seems to be evaluated and changed in the newResistances dictionary. Please let me know if this question is too vague/needs more context.
This is because your return is the wrong location. If you move it to line up with the for, you will see the code iterate through all keys.
I have also updated the code to remove constructs like if predicate==True since you could just do if predicate: instead.
Here's how the code should look:
for drugs in self.resistances:
resistancePicker = random.random()
if self.resistances[drugs]:
if resistancePicker < self.mutProb:
print self.mutProb
newResistances[drugs] = False
elif not self.resistances[drugs]: # or else:
if resistancePicker < self.mutProb:
print self.mutProb
newResistances[drugs] = True
print newResistances
return ResistantVirus(self.maxBirthProb, self.clearProb, newResistances, self.mutProb)

Categories