re.match in AT content calculator not working - python

Working out a few kinks in this code and for some reason my method validation check is not quite working. All I want it to do is to validate that the input from the user ONLY contains letters G, C, A, T before moving onto the method at_calculate which performs the maths on the input sequence. Any help/tips would be appreciated.
import re
from tkinter import *
class AT_content_calculator:
def __init__(self, master):
#initialising various widgets
frame_1 = Frame(master)
frame_1.pack()
self.varoutput_1 = StringVar()
self.label_1 = Label(frame_1, text="Please enter a DNA sequence:")
self.label_1.pack()
self.entry_1 = Entry(frame_1, textvariable=self.dna_sequence)
self.entry_1.pack()
self.output_1 = Label(frame_1, textvariable=self.varoutput_1)
self.output_1.pack()
self.button_1 = Button(frame_1, text="Calculate", command=self.validation_check)
self.button_1.pack()
def dna_sequence(self):
self.dna_sequence = ()
def validation_check(self):
#used to validate that self.dna_sequence only contains letters G, C, A, T
if re.match(r"GCAT", self.dna_sequence):
self.at_calculate()
else:
self.varoutput_1.append = "Invalid DNA sequence. Please enter again."
self.validation_check()
def at_calculate(self):
#used to calculate AT content of string stored in self.dna_sequence
self.dna_sequence = self.entry_1.get()
self.total_bases = len(self.dna_sequence)
self.a_bases = self.dna_sequence.count("A")
self.b_bases = self.dna_sequence.count("T")
self.at_content = "%.2f" % ((self.a_bases + self.b_bases) / self.total_bases)
self.varoutput_1.set("AT content percentage: " + self.at_content)
root = Tk()
root.title("AT content calculator")
root.geometry("320x320")
b = AT_content_calculator(root)
root.mainloop()

If you want to validate the input from the user ONLY contains letters G, C, A, T you need to put the characters within a character class that will match any combinations of this characters :
Note :self.dna_sequence is a function and you can't pass it to match function although its incorrect.you need to return the input value within that function :
def dna_sequence(self):
dna_sequence = self.entry_1.get()
return dna_sequence
and then do :
if re.match(r"[GCAT]+", self.dna_sequence()):
[GCAT]+ will match any combinations of that characters with length 1 or more. if you want that be in length 4 you can use [GCAT]+{4}.
But this also will match duplicated characters. like GGCC.If you don't want such thing you can use set.intersection :
if len(self.dna_sequence())==4 and len(set(GCAT).intersection(self.dna_sequence()))==4:
#do stuff
Or as a better way :
if sorted(self.dna_sequence)==ACGT:
#do stuff

Related

How do I get my code to end a funtion after a button is pressed?

# import engines for code hs (Existing)
import pip
import os
import sys,time,random
import tkinter
from tkinter import *
root = Tk()
# establishes cavas as a object (Existing)
screen = Canvas(root,width = 500, height = 600, background = "light blue")
screen.pack()
# Define some global variable (New)
number = 0
""" funtaion that runs when a button is pressed returning a number
value base on what they choose and then disables the buttons"""
def helloCallBack(num,b1,b2,b3,b4):
How do I make the program recognize the variable global? because they currently it is not working.
global number
number= num
"""if b1 or b2 or b3 or b4 != 0:
b1['state']='disabled'
b2['state']='disabled'
b3['state']='disabled'
b4['state']='disabled'"""
for b in (b1,b2,b3,b4):
if b: b['state'] = 'disabled'
creats up to four buttons based on the value assighned to num value
the opt1-4 values assighned the dialouge to the buttons
def button_maker(num_buttons,opt1,opt2,opt3,opt4):
while True:
master=tkinter.Tk()
master.title("grid() method")
master.geometry("600x150")
if num_opt is equal to 1 create one buttons
if num_buttons == 1:
button1=tkinter.Button(master, text= opt1,command=lambda : helloCallBack(1,button1,0,0,0))
button1.grid(row=1,column=1)
if num_opt is equal to 2 create two buttons
elif num_buttons==2:
button1=tkinter.Button(master, text= opt1,command=lambda : helloCallBack(1,button1,0,0,0))
button1.grid(row=1,column=0)
button2=tkinter.Button(master, text= opt2,command=lambda : helloCallBack(2,button1,button2,0,0))
button2.grid(row=6,column=0)
# if num_opt is equal to 3 create three buttons
elif num_buttons==3:
button1=tkinter.Button(master, text=opt1,command=lambda : helloCallBack(1,button1))
button1.grid(row=1,column=0)
button2=tkinter.Button(master, text=opt2, command=lambda : helloCallBack(2,button1,button2,button3,button4))
button2.grid(row=6,column=0)
button3=tkinter.Button(master, text=opt3,command=lambda : helloCallBack(3,button1,button2,button3,button4))
button3.grid(row=8,column=0)
# if num_opt is 4 or over four buttons will be made
else:
button1=tkinter.Button(master, text=opt1,command=lambda : helloCallBack(1,button1,button2,button3,button4))
button1.grid(row=1,column=0)
button2=tkinter.Button(master, text=opt2,command=lambda :helloCallBack(2,button1,button2,button3,button4))
button2.grid(row=6,column=0)
button3=tkinter.Button(master, text=opt3,command=lambda : helloCallBack(3,button1,button2,button3,button4))
button3.grid(row=8,column=0)
button4=tkinter.Button(master, text=opt4,command=lambda : helloCallBack(4,button1,button2,button3,button4))
button4.grid(row=10,column=0)
root.mainloop()
cuases text to be type out slow
typing_speed = 50 #wpm
def slow_type(t):
for l in t:
sys.stdout.write(l)
sys.stdout.flush()
time.sleep(random.random()*10.0/typing_speed)
print('')
saves a diolouge tree and prints the text out one by one by slow typing it."""
def print_text(my_list):
b=0
space=input("press enter key to continue." )
#key = event.keysym
#print(event.keysym)
for i in my_list:
if space == "":
slow_type(my_list[b])
space=input("")
b=b+1
print_text(["Excellent chioce Mr...","MMM...Mr..."])
#test number value
#print(number)
#test failed
"""creats four buttons on screan when clicked they deactivate and return a number value."""
button_maker(4,str("Tell them your real name!"),"Give them a fake identity ","\"None of your business! \"","\"...\"")
print(number)
# is meant to give different adventures based on what the user chooses
unfortunately, it is not working as the code freezes after the buttons are made.
if number==1:
print(input("Make up a first and last name:"))
# please !!!SAVE ME!!!
In python, global variable must be declared first before it can be used in functions, so you should add a piece of code at the start to declare that:
# import engines for code hs (Existing)
import pip
import os
import sys,time,random
import tkinter
from tkinter import *
root = Tk()
# establishes cavas as a object (Existing)
screen = Canvas(root,width = 500, height = 600, background = "light blue")
screen.pack()
# Define some global variable (New)
number = 0
However, there seem to be typo in the function button_maker() where you have 4 variable p, k, n, l not defined, which returns error.

How can I test a function that is embedded in a method

I recently started doing python. The course I was on ended with an introduction to testing with doctest. I have written a program that uses Tkinter to display widgets and it works :-) . I am using version 3.7. However, testing it is another matter. I can test simple functions and methods, but I hit difficulties when I have a function inside a method. I am pasting below a stripped-down version of what I am trying to achieve. I tried first with doctest and it threw up an error:
"AttributeError: 'function' object has no attribute 'c_square'".
# counter.py
from tkinter import *
import doctest
count = 0
delay = 1000
class MyClass:
def __init__(self, master):
master.geometry("1000x500")
master.resizable(0, 0)
master.title("Display a counter")
frame1 = Frame(master)
frame1.pack()
label1 = Label(frame1, font = ('Courier', 15 , 'bold'))
label1.grid(row = 0, column = 0)
self.my_counter(label1)
label2 = Label(frame1, font = ('Courier', 15 , 'bold'))
label2.grid(row = 0, column = 1)
self.square_of_count(label2)
# This method recursively increments a counter and displays the count.
def my_counter(self, lbl):
def increment_count():
global count
global delay
count += 1
string = str(count)
lbl.config(text = string)
lbl.after(delay, increment_count)
increment_count()
# This method takes the square of the counter and displays the result.
def square_of_count(self, lbl):
def c_square():
global count
squ = count * count
string = str(squ)
lbl.config(text=string)
lbl.after(delay, c_square)
return squ
c_square()
def test_c_square(number):
"""
>>> test_c_square(2)
4
"""
global count
count = number
master = Tk()
frame1 = Frame(master)
label = Label(frame1, font = ('Courier', 15 , 'bold'))
return MyClass.square_of_count.c_square(MyClass.square_of_count.c_square)
def main():
""" # main body commented out for test purposes.
root = Tk()
a = MyClass(root)
root.mainloop()
"""
doctest.testmod(verbose=True)
if __name__ == "__main__":
main()
I am using a separate test function, so that I can initialise my counter.
Then someone suggested that I try unittest, so I wrote this :
import unittest
import counter
class TestCounter(unittest.TestCase):
counter.count = 2
print("count = ", counter.count)
def square_of_count(self):
result = counter.c_square()
self.assertEqual(result, 4)
result = counter.c_square()
self.assertNotEqual(result, 3)
if __name__ == '__main__':
unittest.main()
This runs without throwing up any errors, the purpose of it is to set a value to the variable 'count' and read back the result. But I get the same response whatever value I test for, so I do not believe it is working right. I also tried variations on a theme, but I just got error messages.
Can someone please point out what I am doing wrong, I have looked about various forums and tutorials but have not seen this question asked before.
I would appreciate an answer that is easy to follow, I am asperger / dyslexic and find it difficult to learn new material. A correction with explanation would be most helpful. Thank you.
First of all, avoid this kind of nesting the functions. In your particular case I would highly suggest refactoring of a code in manner of creating some help private methods which you will call from the main ones, or even create whole new utility class:
class Util:
def _init_(self):
self.name = "Utility"
def add_two_numbers(self, first, second):
if(isinstance(first, int) and isinstance(second, int)):
return first+second
class SomeFancyClass:
def __init__(self):
self.util = Util()
self.constant = 4
# This method recursively increments a counter and displays the count.
def my_fancy_math(self, first, second):
return self.constant * self.util.add_two_numbers(first, second)
FancyVar = SomeFancyClass()
print(FancyVar.my_fancy_math(5, 6))
In case you dont want to change your code (for some reason), there is extremely dirty way to access your inner function. Again, a bit stupidly modified example made from your code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# counter.py
from tkinter import *
import doctest
import types
count = 0
delay = 1000
class MyClass:
def __init__(self, smth1):
self.something = smth1
# This method recursively increments a counter and displays the count.
def my_counter(self, lbl):
def increment_count():
global count
global delay
count += 1
string = str(count)
lbl.config(text=string)
lbl.after(delay, increment_count)
increment_count()
# This method takes the square of the counter and displays the result.
def square_of_count(self, lbl):
def test_function1(self, first, second):
return first+second
def c_square():
global count
squ = count * count
string = str(squ)
lbl.config(text=string)
lbl.after(delay, c_square)
return squ
c_square()
def test_function(self, st1):
print(st1)
def test_c_square(number):
global count
count = number
master = Tk()
frame1 = Frame(master)
label = Label(frame1, font=('Courier', 15, 'bold'))
return MyClass.square_of_count.c_square(MyClass.square_of_count.c_square)
def main():
doctest.testmod(verbose=True)
if __name__ == '__main__':
# main()
print('done')
test_function = types.FunctionType(MyClass.square_of_count.__code__.co_consts[1],
{}, None, (), ())
obj = MyClass("Hi")
sum1 = test_function("", 1, 2)
print(sum1)

reccomending, according to the selected listbox value

the code is a bit long, hope you understand it, i have this small app, where i have to implement data from 2 files, and then showing some of the values(of data) in list box. on the other side i have combined the values in nested dictionary. Now i have to recommend movie according the the value i will select from list box. Maybe the code i have written is wrong in some parts, though in the last part, when i have to write the code of recommendation, i have no clue how i have to write the code, i so it will recommend me movie, for further explanation, i will be writing in comments part if needed. (Data&recommendations file: https://www.dropbox.com/sh/b949hapk5lmm94i/AAD29ykbvWq83wZbFpvvqw69a?dl=0)
from Tkinter import *
import tkFileDialog
import csv
from recommendations import *
class STproject:
def __init__(self): #1
self.variableclasses()
self.buttonsnlabels()
self.dictionary()
def variableclasses(self):
self.all_vars = [StringVar() for _ in range(2)]
self.var1 = StringVar()
self.var2 = StringVar()
self.var1.set(0)
self.var2.set(0)
def buttonsnlabels(self):
self.rdbttn=Radiobutton(root,text='user based recommendation',variable = self.var1,value=1,command=lambda:self.dictionary())#, command=lambda :self.selec1())
self.rdbttn.grid(row=0,column=0)
self.rdbttn2=Radiobutton(root,text='movie based recommendation',variable = self.var1,value=2,command=lambda:self.dictionary())#,command=lambda :self.selec1())
self.rdbttn2.grid(row=1,column=0)
self.rdbttn3=Radiobutton(root,text='pearson',variable = self.var2,value=1)#,command=lambda :self.selec2())
self.rdbttn3.grid(row=2,column=0)
self.rdbttn4=Radiobutton(root,text='euclidean',variable = self.var2,value=2)#,command=lambda :self.selec2())
self.rdbttn4.grid(row=3,column=0)
self.ratingbutton=Button(root,text='Upload Rating',command=lambda :self.file(self.all_vars[0]))
self.ratingbutton.grid()
self.ratingbutton=Button(root,text='Upload Movies',command=lambda :self.file(self.all_vars[1]))
self.ratingbutton.grid()
self.lb1 = Listbox(root)
self.lb1.grid(row=0,column=1)
self.lb2 = Listbox(root)
self.lb2.grid(row=0,column=1)
self.lb3 = Listbox(root)
self.lb3.grid(row=0,column=1)
def file(self, v):
result = tkFileDialog.askopenfilename()
if result:
v.set(result)
# self.dictionary()
def dictionary(self):
# self.lb1.delete(END, 0) #clear listbox
# self.lb1.update_idletasks()
if self.var1.get()==1:
self.d = {}
if all(i.get() for i in self.all_vars): #process only if all 2 files are selected
with open(self.all_vars[0].get(),"r") as a, open(self.all_vars[1].get(),"r") as b:
for line1,line2,line3 in zip(csv.reader(a),csv.reader(b),csv.reader(a)):
self.d[line1[0]]={line2[1]:line3[2]}
self.lb1.insert('end',line2[1])
print self.d
else:
self.d = {}
if all(i.get() for i in self.all_vars): #process only if all 2 files are selected
with open(self.all_vars[0].get(),"r") as a, open(self.all_vars[1].get(),"r") as b:
for line1,line2,line3 in zip(csv.reader(a),csv.reader(b),csv.reader(a)):
self.d[line1[0]]={line2[1]:line3[2]}
self.lb1.insert('end', line1[1])
print self.d
def recoms(self):
# selection=self.lb1.curselection()
# print selection
if self.var2.get()==1:
getRecommendations()
else:
pass
root=Tk()
root.title('SteelBox Inc. Calculator')
application=STproject() #2
root.mainloop() #3

python - tkinter grid row not appearing and not passing to function correctly

Two separate issues have come up with my code
First, I can't get the fourth row of my grid to appear, although the fifth appears to be displaying just fine.
Secondly, my passVal function keeps giving me the error:
passVal() takes 1 positional argument but 2 were given
I've tried rearranging things and converting it to a string and nothing seems to work.
I figure there's a chance it's one thing causing the same issue since they're both centered around the same button but I'm not sure.
import tkinter
class AccountCreation:
def __init__(self):
self.main = tkinter.Tk()
self.main.title("Account Creation")
self.topleftLabel = tkinter.Label(text=" ")
self.topleftLabel.grid(row=1,column=1)
self.botrightLabel = tkinter.Label(text=" ")
self.botrightLabel.grid(row=5,column=5)
self.promptLabel = tkinter.Label(text="Create a password with at least nine (9)\n characters that contains at least one digit, \n one uppercase, and one lowercase letter.\n\n")
self.promptLabel.grid(row=2,column=2,columnspan=2)
self.passLabel = tkinter.Label(text="Password:")
self.passLabel.grid(row=3,column=2)
self.passEntry = tkinter.Entry(width = 18, justify='right')
self.passEntry.grid(row=3,column=3)
self.enterButton = tkinter.Button(text="Enter", \
command=self.passVal(self.passEntry.get()))
self.enterButton.grid(row=4,column=2)
self.cancelButton = tkinter.Button(text="Cancel", \
command=self.cancel)
self.cancelButton.grid(row=4,column=3)
tkinter.mainloop()
def passVal(pw):
if len(pw) < 9:
print ("no")
def cancel(self):
self.main.destroy()
my_gui = AccountCreation()
Aside from the indention issues you are having, all methods in a class you need to pass self as the first argument unless you are using special tags that can make it a stand alone function.
Change:
def passVal(pw):
To:
def passVal(self, pw):
You will also need to change the command on you Enter button to use lambda in order to prevent python from calling the passVal method on start up.
Change:
command=self.passVal(self.passEntry.get())
To:
command=lambda: self.passVal(self.passEntry.get())
You don't really need to use a lambda here or even pass the argument of self.passEntry.get(). You can get the value of the entry field in the passVal() method by use self.passEntry.get() instead of pw.
If you change this:
command=lambda: self.passVal(self.passEntry.get())
To this:
command=self.passVal
And this:
def passVal(self, pw):
if len(pw) < 9:
print ("no")
To this:
def passVal(self):
if len(self.passEntry.get()) < 9:
print ("no")
You program will work fine and you can avoid using a lambda in your command.
Note: You do not need to use labels as spacers. You can simple use padx and pady in your grid placement.
Take a look at the below code:
import tkinter
class AccountCreation:
def __init__(self):
self.main = tkinter.Tk()
self.main.title("Account Creation")
self.promptLabel = tkinter.Label(text="Create a password with at least nine (9)\n characters that contains at least one digit, \n one uppercase, and one lowercase letter.\n\n")
self.promptLabel.grid(row=2,column=2,columnspan=2,pady=(10,10))
self.passLabel = tkinter.Label(text="Password:")
self.passLabel.grid(row=3,column=2)
self.passEntry = tkinter.Entry(width = 18, justify='right')
self.passEntry.grid(row=3,column=3)
self.enterButton = tkinter.Button(text="Enter", \
command=self.passVal(self.passEntry.get()))
self.enterButton.grid(row=4,column=2)
self.cancelButton = tkinter.Button(text="Cancel", \
command=self.cancel)
self.cancelButton.grid(row=4,column=3,pady=(10,10))
tkinter.mainloop()
def passVal(self, pw):
if len(pw) < 9:
print ("no")
def cancel(self):
self.main.destroy()
my_gui = AccountCreation()
Notice that simple using pady=(10,10) we have put space at the top and bottom of the widget.

Python Tkinter calculator calculation limit

I'm trying to make a simple calculator that has buttons of numbers 0-9, plus, minus, clear and equals. I have the gui and the functionality of the buttons, but my calculator calculates further than 999. Any ideas?
-I have attempted to stop it calculating further than 999, if you look at line 45-53.
here is my code:
from tkinter import *
class Calculator(Frame):
def frame(this, side):
w = Frame(this)
w.pack(side=side, expand=YES, fill=BOTH)
return w
def button(this, root, side, text, command=None):
w = Button(root, text=text, command=command)
w.pack(side=side, expand=YES, fill=BOTH)
return w
need_clr = False
def digit(self, digit):
if self.need_clr:
self.display.set('')
self.need_clr = False
self.display.set(self.display.get() + digit)
def sign(self):
need_clr = False
cont = self.display.get()
if len(cont) > 0 and cont[0] == '-':
self.display.set(cont[1:])
else:
self.display.set('-' + cont)
def oper(self, op):
self.display.set(self.display.get() + ' ' + op + ' ')
self.need_clr = False
def calc(self):
try:
self.display.set(eval(self.display.get()))
self.need_clr = True
except:
showerror('Operation Error', 'Illegal Operation')
self.display.set('')
self.need_clr = False
def equals(self):
try:
result = eval(self.display.get())
if result >= 1000:
result (calc)
except:
results("ERROR")
display.delete(0, END)
display.insert(0, display)
def __init__(self):
Frame.__init__(self)
self.option_add('*Font', 'Dotum 15')
self.pack(expand=YES, fill=BOTH)
self.master.title('Simple Calculator')
self.display = StringVar()
e = Entry(self, relief=SUNKEN, textvariable=self.display)
e.pack(side=TOP, expand=YES, fill=BOTH)
for key in ("123", "456", "789"):
keyF = self.frame(TOP)
for char in key:
self.button(keyF, LEFT, char,
lambda c=char: self.digit(c))
keyF = self.frame(TOP)
self.button(keyF, LEFT, '0', lambda ch='0': self.digit(ch))
opsF = self.frame(TOP)
for char in "+-=":
if char == '=':
btn = self.button(opsF, LEFT, char, self.calc)
else:
btn = self.button(opsF, LEFT, char,
lambda w=self, s=char: w.oper(s))
clearF = self.frame(BOTTOM)
self.button(clearF, LEFT, 'Clr', lambda w=self.display: w.set(''))
if __name__ == '__main__':
Calculator().mainloop()
Your big problem is that you've tried to fix this in a method called equals that you never call anywhere in your code. So, obviously this won't do anything.
If you look at where your = button is defined, it does this:
opsF = self.frame(TOP)
for char in "+-=":
if char == '=':
btn = self.button(opsF, LEFT, char, self.calc)
So, it calls the calc method. You have to change calc to influence what it does; adding some completely separate method that never gets called anywhere won't help.
If you change this to call self.equals instead of self.calc, that solves this first problem… but of course you'll have a whole new set of problems, because most of the code in equals makes no sense, as Joran Beasley explains. Look at the working code in calc as a model for how to do things in equals.
However, a better design than copying/pasting/editing calc would be to modify it to call some new validate_result method, like this:
def calc(self):
try:
self.display.set(self.validate_result(eval(self.display.get())))
self.need_clr = True
except:
showerror('Operation Error', 'Illegal Operation')
self.display.set('')
self.need_clr = False
Now, you just need to write validate_result as a function that works on numbers and either returns the number (or returns a modified number, if you want) or raises an exception. It doesn't need to duplicate all the work that calc does, it can just let calc do all that stuff. For example:
def validate_result(self, result):
if result >= 1000:
raise ValueError('result too big!')
else:
return result
I assume you are talking about
def equals(self):
try:
result = eval(self.display.get()) # <-- this is some risky business
if result >= 1000: #I think you want to check less than but its not clear, this is greater than or equal
result (calc) #result is a number you cannot do 5(some_argument)
#^^^^^^^^^^^ this line should probably end up as an error message ...
#you probably need an else here to handle if the number is too big
else:
raise ValueError("Value Too Large!!!")
except:
results("ERROR") #not sure what this line is doing ...
display.delete(0, END)
display.insert(0, display)
there are several problems I commented ... perhaps one will solve your issue
but I think really abarnert nailed your problem so I would go with that ...

Categories