Allow alphabet characters to be the only inputs into entrybox tkinter - python

#Want this code but to only allow str (alphabet)
def is_type_int(*args):
item = var2.get()
try:
item_type = type(int(item))
if item_type == type(int(1)):
#Had too have any action here so just made a print do nothing
print
except:
IDEntry.delete(0, tk.END)
var2 = tk.StringVar()
var2.trace("w", is_type_int)

So, the first option I was thinking about it to compare the type to str instead of int. But this solution would not always work because it depends on how the argument is passed.
I'd try to use regex instead, use a simple function to check if there is any number in the input text as below:
import re
def numberInText(input_string):
# Using regex, look for a number in the string
if (re.search("[0-9]",input_string)):
return True
# if no number is found, return False
return False
test_with_number = "TEST 123"
print(numberInText(test_with_number))
test_without_number = "TEST"
print(numberInText(test_without_number))

Related

Are you able in Python to name functions as numbers such as 1 2 3 4 etc

I would like to call functions from the items in my option_list using the first character(index*) in their name which would be 1 or 2
problem is functions don't like being called numbers even if I put "1" or "2"
how would I go about this?
def main():
print(option_list := ["1.data", "2.stratified sampling"])
user_select = input("Type your selection!..\n").lower()
for value in option_list:
if user_select == value[0]:
eval(value)
# functions for specification
def 1():
print("data")
main()
An option would be to create a dictionary that links the number to your function:
dictionary = {
1: data,
2: stratified_sampling
}
Then, you can call it accessing that dictionary and the number:
dictionary[index]()
The whole program woud look like something like this:
def data():
print("data")
def stratified_sampling():
print("stratified sampling")
dictionary = {
1: data,
2: stratified_sampling
}
selection = int(input("Select the option\n"))
if selection in dictionary.keys():
dictionary[selection]()
You can simply add some characters in front of your function and pretty sure you'll still achieve what you want, though not sure what it is
def main():
print(option_list := ["1.data", "2.stratified sampling"])
user_select = input("Type your selection!..\n").lower()
for value in option_list:
if user_select == value[0]:
eval(f"func{value[0]}()")
# functions for specification
def func1():
print("data")
Define your functions with useful names:
def data():
print("data")
def hello():
print("hello")
def say_something():
print("something")
You can put the functions into a list:
functions = [data, hello, say_something]
When asking the user to choose a function, print out all of their names:
print([f.__name__ for f in functions])
Ask for the index of the function they want to use:
i = int(input("Type the index of the function you want\n"))
Then call that function:
functions[i]()
Putting them in a list may be better than a dictionary if you are only numbering them since indexing is inherent to a list.

click custom option prompt function

I have noticed that prompt using click accepts inputs with trailing spaces
ftp_server = click.prompt("FTP Server")
Is there a way to use a custom return function like this to reject trailing spaces?
def custom_prompt(value):
if value.strip():
return True
else:
return False
ftp_server = click.prompt("FTP Server", custom_prompt)
I have already used this:
while not ftp_server.strip():
ftp_server = click.prompt("FTP Server")
But I'm looking for a better way because I don't want to use a while loop each time I use prompt.
To reject invalid user input, you can use the value_proc parameter to click.prompt. A validator to reject input with trailing spaces could look like:
Prompt Validator
import click
def validate_no_trailing_space(value):
if value != value.rstrip():
raise click.UsageError("Trailing space is invalid!")
return value
ftp_server = click.prompt("FTP Server",
value_proc=validate_no_trailing_space)
Trim Spaces
You might also consider a validator which trims leading and trailing spaces but reject spaces in the name:
def validate_no_internal_space(value):
value = value.strip()
if ' ' in value:
raise click.UsageError("Spaces are not valid here!")
return value

Object is not iterable when replacing word called by function

How do I get otherImages to return the string in it so that I can replace a word within it when called from 'narrow' method?
def otherImages(self):
self.wfile.write(bytes("<div id='menu_button'><a href='/narrow'><img src='../images/menu_button.png'></a></div>", "utf8"))
#^word I want to replace
def contentList(self, skip_name=''): # All content methods in list
methods = [self.title, self.containerDIV, self.heading, self.stopSection, self.offlineSection, self.onlineSection, self.endDIV, self.otherImages]
for m in methods:
if m.__name__ != skip_name:
m()
def narrow(self):
try:
self.reply()
self.contentList('onlineSection') # removed onlineSection
for words in self.otherImages():
words.replace("narrow", "index")
self.otherImages doesn't return anything! When a function does not return an explicit value in python, it returns None. You cannot iterate over None.
Here are the changes I made which solves my problem. It allows me to edit the string when called from the 'narrow' method.
def otherImages(self):
return["<div id='menu_button'><a href='/narrow'><img src='../images/menu_button.png'></a></div>"]
def narrow(self):
try:
self.reply()
self.contentList('onlineSection') # removed onlineSectionv
for words in self.otherImages():
words = words.replace("/narrow", "/")
self.wfile.write(bytes(words, "utf8"))
return

Tkinter: restrict entry data to float

I am in need of a function that retricts the input of the user to numeric values.
I've been looking for an answer but the one I've found does not allow for '-', '+' and ','(comma).
Here's the code for the validation method:
def __init__(self, master1):
self.panel2 = tk.Frame(master1)
self.panel2.grid()
vcmd = (master1.register(self.validate),
'%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')
self.text1 = tk.Entry(self.panel2, validate = 'key', validatecommand = vcmd)
self.text1.grid()
self.text1.focus()
def validate(self, action, index, value_if_allowed,
prior_value, text, validation_type, trigger_type, widget_name):
# action=1 -> insert
if(action=='1'):
if text in '0123456789,-+':
try:
float(value_if_allowed)
return True
except ValueError:
return False
else:
return False
else:
return True
Again, this only seems to work with numbers, but restricts commas and plus and minus signs, which is not intended.
How could this be fixed?
The right tool is definitely the re module.
Here is a regular expression that should do the job:
(\+|\-)?\d+(,\d+)?$
Let's break it down:
(\+|\-)?\d+(,\d+)?$
\+|\- Starts with a + or a -...
( )? ... but not necessarily
\d+ Contains a repetition of at least one digits
,\d+ Is followed by a comma and at least one digits...
( )? ... but not necessarily
$ Stops here: nothing follows the trailing digits
Now, your validate function only has to return True if the input matches that regex, and False if it does not.
def validate(string):
result = re.match(r"(\+|\-)?\d+(,\d+)?$", string)
return result is not None
Some tests:
# Valid inputs
>>> validate("123")
True
>>> validate("123,2")
True
>>> validate("+123,2")
True
>>> validate("-123,2")
True
# Invalid inputs
>>> validate("123,")
False
>>> validate("123,2,")
False
>>> validate("+123,2,")
False
>>> validate("hello")
False
Edit
I understand now that you want to check in real-time if the input is valid.
So here is an example of what you can do:
import tkinter as tk
import re
def validate(string):
regex = re.compile(r"(\+|\-)?[0-9,]*$")
result = regex.match(string)
return (string == ""
or (string.count('+') <= 1
and string.count('-') <= 1
and string.count(',') <= 1
and result is not None
and result.group(0) != ""))
def on_validate(P):
return validate(P)
root = tk.Tk()
entry = tk.Entry(root, validate="key")
vcmd = (entry.register(on_validate), '%P')
entry.config(validatecommand=vcmd)
entry.pack()
root.mainloop()
The validate function now checks more or less the same thing, but more loosely.
Then if the regex results in a match, some additional checks are performed:
Allow the input to be empty;
Prevent the input to have more than one '+'/'-', and more than one ',';
Ignore a match against the empty string, because the pattern allows it, so "a" would result in a match but we don't want it.
The command is registered, and works with the '%P' parameter, that corresponds to the string if the input were accepted.
Please not however that forcing the input to be always correct is somewhat harsh, and might be counter-intuitive.
A more commonly used approach is to update a string next to the entry, and have the user know when their input is valid or invalid.

Python string assignment issue!

So I'm fairly new to Python but I have absolutely no idea why this strong oldUser is changing to current user after I make the parse call. Any help would be greatly appreciated.
while a < 20:
f = urllib.urlopen("SITE")
a = a+1
for i, line in enumerate(f):
if i == 187:
print line
myparser.parse(line)
if fCheck == 1:
result = oldUser[0] is oldUser[1]
print oldUser[0]
print oldUser[1]
else:
result = user is oldUser
fCheck = 1
print result
user = myparser.get_descriptions(firstCheck)
firstCheck = 1
print user
if result:
print "SAME"
array[index+1] = array[index+1] +0
else:
oldUser = user
elif i > 200:
break
myparser.reset()
I don't understand why result doesn't work either... I print out both values and when they're the same it's telling me they're not equal... Also, why does myparser.parse(line) turn oldUser into a size 2 array? Thanks!
** Here's the definition for myparse...
class MyParser(sgmllib.SGMLParser):
"A simple parser class."
def parse(self, s):
"Parse the given string 's'."
self.feed(s)
self.close()
def __init__(self, verbose=0):
"Initialise an object, passing 'verbose' to the superclass."
sgmllib.SGMLParser.__init__(self, verbose)
self.divs = []
self.descriptions = []
self.inside_div_element = 0
def start_div(self, attributes):
"Process a hyperlink and its 'attributes'."
for name, value in attributes:
if name == "id":
self.divs.append(value)
self.inside_div_element = 1
def end_div(self):
"Record the end of a hyperlink."
self.inside_div_element = 0
def handle_data(self, data):
"Handle the textual 'data'."
if self.inside_div_element:
self.descriptions.append(data)
def get_div(self):
"Return the list of hyperlinks."
return self.divs
def get_descriptions(self, check):
"Return a list of descriptions."
if check == 1:
self.descriptions.pop(0)
return self.descriptions
Don’t compare strings with is. That checks if they’re the same object, not two copies of the same string. See:
>>> string = raw_input()
hello
>>> string is 'hello'
False
>>> string == 'hello'
True
Also, the definition of myparser would be useful.
I'm not quite sure what your code is doing, but I suspect you want to use == instead of is. Using is compares object identity, which is not the same as string equality. Two different string objects may contain the same sequence of characters.
result = oldUser[0] == oldUser[1]
If you're curious, for more information on the behaviour of the is operator see Python “is” operator behaves unexpectedly with integers.

Categories