how to get ticking timer with dynamic label? - python-2.7

What im trying to do is that whenever cursor is on label it must show the time elapsed since when it is created it does well by subtracting (def on_enter(i)) the value but i want it to be ticking while cursor is still on label.
I tried using after function as newbie i do not understand it well to use on dynamic labels.
any help will be appreciated thx
code:
from Tkinter import *
import datetime
date = datetime.datetime
now = date.now()
master=Tk()
list_label=[]
k=[]
time_var=[]
result=[]
names=[]
def delete(i):
k[i]=max(k)+1
time_var[i]='<deleted>'
list_label[i].pack_forget()
def create():#new func
i=k.index(max(k))
for j in range(i+1,len(k)):
if k[j]==0:
list_label[j].pack_forget()
list_label[i].pack(anchor='w')
time_var[i]=time_now()
for j in range(i+1,len(k)):
if k[j]==0:
list_label[j].pack(anchor='w')
k[i]=0
###########################
def on_enter(i):
list_label[i].configure(text=time_now()-time_var[i])
def on_leave(i):
list_label[i].configure(text=names[i])
def time_now():
now = date.now()
return date(now.year,now.month,now.day,now.hour,now.minute,now.second)
############################
for i in range(11):
lb=Label(text=str(i),anchor=W)
list_label.append(lb)
lb.pack(anchor='w')
lb.bind("<Button-3>",lambda event,i=i:delete(i))
k.append(0)
names.append(str(i))
lb.bind("<Enter>",lambda event,i=i: on_enter(i))
lb.bind("<Leave>",lambda event,i=i: on_leave(i))
time_var.append(time_now())
master.bind("<Control-Key-z>",lambda event: create())
mainloop()

You would use after like this:
###########################
def on_enter(i):
list_label[i].configure(text=time_now()-time_var[i])
list_label[i].timer = list_label[i].after(1000, on_enter, i)
def on_leave(i):
list_label[i].configure(text=names[i])
list_label[i].after_cancel(list_label[i].timer)
However, your approach here is all wrong. You currently have some functions and a list of data. What you should do is make a single object that contains the functions and data together and make a list of those. That way you can write your code for a single Label and just duplicate that. It makes your code a lot simpler partly because you no longer need to keep track of "i". Like this:
import Tkinter as tk
from datetime import datetime
def time_now():
now = datetime.now()
return datetime(now.year,now.month,now.day,now.hour,now.minute,now.second)
class Kiran(tk.Label):
"""A new type of Label that shows the time since creation when the mouse hovers"""
hidden = []
def __init__(self, master=None, **kwargs):
tk.Label.__init__(self, master, **kwargs)
self.name = self['text']
self.time_var = time_now()
self.bind("<Enter>", self.on_enter)
self.bind("<Leave>", self.on_leave)
self.bind("<Button-3>", self.hide)
def on_enter(self, event=None):
self.configure(text=time_now()-self.time_var)
self.timer = self.after(1000, self.on_enter)
def on_leave(self, event=None):
self.after_cancel(self.timer) # cancel the timer
self.configure(text=self.name)
def hide(self, event=None):
self.pack_forget()
self.hidden.append(self) # add this instance to the list of hidden instances
def show(self):
self.time_var = time_now() # reset time
self.pack(anchor='w')
def undo(event=None):
'''if there's any hidden Labels, show one'''
if Kiran.hidden:
Kiran.hidden.pop().show()
def main():
root = tk.Tk()
root.geometry('200x200')
for i in range(11):
lb=Kiran(text=i)
lb.pack(anchor='w')
root.bind("<Control-Key-z>",undo)
root.mainloop()
if __name__ == '__main__':
main()
More notes:
Don't use lambda unless you are forced to; it's known to cause bugs.
Don't use wildcard imports (from module import *), they cause bugs and are against PEP8.
Put everything in functions.
Use long, descriptive names. Single letter names just waste time. Think of names as tiny comments.
Add a lot more comments to your code so that other people don't have to guess what the code is supposed to do.
Try a more beginner oriented forum for questions like this, like learnpython.reddit.com

Related

Defining functions inside of views

I am attempting to create a job board website and upon entering a zip code in a form, that zip code is passed to a search_results view (as zip_code). In this view, I need to:
Get the surrounding zip codes (with a certain mile radius)
Get objects in DB that match those zip codes.
I have step one complete and have not implemented step two yet (actual code not that important to question):
from uszipcode import Zipcode, SearchEngine
def search_results(request, zip_code):
zip_codes = []
search = SearchEngine(simple_zipcode=True) # create SearchEngine object
zip_code = search.by_zipcode(zip_code) #create Zipcode object?
latitude = zip_code.lat
longitude = zip_code.lng
result = search.by_coordinates(latitude, longitude, radius = 5, returns = 5)
for item in result:
zip_codes.append(item.zipcode)
# code that will return matching objects
My question is can you define functions inside of a view in Django, like such:
def search_results(request, zip_code):
zip_codes = getSurroundingZipCodes(zip_code)
results = getJobsInArea(zip_codes)
return render(request, 'results.html', {'results: results})
def getSurroundingZipCodes(zip_code):
# logic for this function
def getJobsInArea(zip_codes):
# logic for this function
This is something I haven't seen in any tutorials so I feel like the answer is no, but I'm not sure why?
Yes you can do it. django view here is a function . You can define functions inside function.
That is how decorators work in python. But
why cant we define functions in seperate modules and import them above? Like in a file do
utils.py
def getSurroundingZipCodes(zip_code):
# logic for this function
def getJobsInArea(zip_codes):
# logic for this function
and simply import
from utils import getSurroundingZipCodes,getJobsInArea
this way they will be resuable

making a function staticmethod in python is confusing

Hi I have a GUI written using Tkinter and the code template is as follows. My question is PyCharm gives me warnings on my functions (def func1, def func2) that they are static. To get rid of the warnings I placed #staticmethod above the functions. What does this do and is it necessary?
# Use TKinter for python 2, tkinter for python 3
import Tkinter as Tk
import ctypes
import numpy as np
import os, fnmatch
import tkFont
class MainWindow(Tk.Frame):
def __init__(self, parent):
Tk.Frame.__init__(self,parent)
self.parent = parent
self.parent.title('BandCad')
self.initialize()
#staticmethod
def si_units(self, string):
if string.endswith('M'):
num = float(string.replace('M', 'e6'))
elif string.endswith('K'):
num = float(string.replace('K', 'e3'))
elif string.endswith('k'):
num = float(string.replace('k', 'e3'))
else:
num = float(string)
return num
if __name__ == "__main__":
# main()
root = Tk.Tk()
app = MainWindow(root)
app.mainloop()
You can also turn off that inspection so that PyCharm doesn't warn you. Preferences -> Editor -> Inspections. Note that the inspection appears in the JavaScript section as well as the Python section.
You are right about #staticmethod being confusing. It is not really needed in Python code and in my opinion should almost never by used. Instead, since si_units is not a method, move it out of the class and remove the unused self parameter. (Actually, you should have done that when adding #staticmethod; the posted code will not work right with 'self' left in.)
Unless one has forgotten to use 'self' when it needs to be used, this is (or at least should be) the intent of the PyCharm warning. No confusion, no fiddling with PyCharm settings.
While you are at it, you could condense the function and make it easily extensible to other suffixes by using a dict.
def si_units(string):
d = {'k':'e3', 'K':'e3', 'M':'e6'}
end = string[-1]
if end in d:
string = string[:-1] + d[end]
return float(string)
for f in ('1.5', '1.5k', '1.5K', '1.5M'): print(si_units(f))

Does pdb offer watchpoints? [duplicate]

There is large python project where one attribute of one class just have wrong value in some place.
It should be sqlalchemy.orm.attributes.InstrumentedAttribute, but when I run tests it is constant value, let's say string.
There is some way to run python program in debug mode, and run some check (if variable changed type) after each step throught line of code automatically?
P.S. I know how to log changes of attribute of class instance with help of inspect and property decorator. Possibly here I can use this method with metaclasses...
But sometimes I need more general and powerfull solution...
Thank you.
P.P.S. I need something like there: https://stackoverflow.com/a/7669165/816449, but may be with more explanation of what is going on in that code.
Well, here is a sort of slow approach. It can be modified for watching for local variable change (just by name). Here is how it works: we do sys.settrace and analyse the value of obj.attr each step. The tricky part is that we receive 'line' events (that some line was executed) before line is executed. So, when we notice that obj.attr has changed, we are already on the next line and we can't get the previous line frame (because frames aren't copied for each line, they are modified ). So on each line event I save traceback.format_stack to watcher.prev_st and if on the next call of trace_command value has changed, we print the saved stack trace to file. Saving traceback on each line is quite an expensive operation, so you'd have to set include keyword to a list of your projects directories (or just the root of your project) in order not to watch how other libraries are doing their stuff and waste cpu.
watcher.py
import traceback
class Watcher(object):
def __init__(self, obj=None, attr=None, log_file='log.txt', include=[], enabled=False):
"""
Debugger that watches for changes in object attributes
obj - object to be watched
attr - string, name of attribute
log_file - string, where to write output
include - list of strings, debug files only in these directories.
Set it to path of your project otherwise it will take long time
to run on big libraries import and usage.
"""
self.log_file=log_file
with open(self.log_file, 'wb'): pass
self.prev_st = None
self.include = [incl.replace('\\','/') for incl in include]
if obj:
self.value = getattr(obj, attr)
self.obj = obj
self.attr = attr
self.enabled = enabled # Important, must be last line on __init__.
def __call__(self, *args, **kwargs):
kwargs['enabled'] = True
self.__init__(*args, **kwargs)
def check_condition(self):
tmp = getattr(self.obj, self.attr)
result = tmp != self.value
self.value = tmp
return result
def trace_command(self, frame, event, arg):
if event!='line' or not self.enabled:
return self.trace_command
if self.check_condition():
if self.prev_st:
with open(self.log_file, 'ab') as f:
print >>f, "Value of",self.obj,".",self.attr,"changed!"
print >>f,"###### Line:"
print >>f,''.join(self.prev_st)
if self.include:
fname = frame.f_code.co_filename.replace('\\','/')
to_include = False
for incl in self.include:
if fname.startswith(incl):
to_include = True
break
if not to_include:
return self.trace_command
self.prev_st = traceback.format_stack(frame)
return self.trace_command
import sys
watcher = Watcher()
sys.settrace(watcher.trace_command)
testwatcher.py
from watcher import watcher
import numpy as np
import urllib2
class X(object):
def __init__(self, foo):
self.foo = foo
class Y(object):
def __init__(self, x):
self.xoo = x
def boom(self):
self.xoo.foo = "xoo foo!"
def main():
x = X(50)
watcher(x, 'foo', log_file='log.txt', include =['C:/Users/j/PycharmProjects/hello'])
x.foo = 500
x.goo = 300
y = Y(x)
y.boom()
arr = np.arange(0,100,0.1)
arr = arr**2
for i in xrange(3):
print 'a'
x.foo = i
for i in xrange(1):
i = i+1
main()
There's a very simple way to do this: use watchpoints.
Basically you only need to do
from watchpoints import watch
watch(your_object.attr)
That's it. Whenever the attribute is changed, it will print out the line that changed it and how it's changed. Super easy to use.
It also has more advanced features, for example, you can call pdb when the variable is changed, or use your own callback functions instead of print it to stdout.
A simpler way to watch for an object's attribute change (which can also be a module-level variable or anything accessible with getattr) would be to leverage hunter library, a flexible code tracing toolkit. To detect state changes we need a predicate which can look like the following:
import traceback
class MutationWatcher:
def __init__(self, target, attrs):
self.target = target
self.state = {k: getattr(target, k) for k in attrs}
def __call__(self, event):
result = False
for k, v in self.state.items():
current_value = getattr(self.target, k)
if v != current_value:
result = True
self.state[k] = current_value
print('Value of attribute {} has chaned from {!r} to {!r}'.format(
k, v, current_value))
if result:
traceback.print_stack(event.frame)
return result
Then given a sample code:
class TargetThatChangesWeirdly:
attr_name = 1
def some_nested_function_that_does_the_nasty_mutation(obj):
obj.attr_name = 2
def some_public_api(obj):
some_nested_function_that_does_the_nasty_mutation(obj)
We can instrument it with hunter like:
# or any other entry point that calls the public API of interest
if __name__ == '__main__':
obj = TargetThatChangesWeirdly()
import hunter
watcher = MutationWatcher(obj, ['attr_name'])
hunter.trace(watcher, stdlib=False, action=hunter.CodePrinter)
some_public_api(obj)
Running the module produces:
Value of attribute attr_name has chaned from 1 to 2
File "test.py", line 44, in <module>
some_public_api(obj)
File "test.py", line 10, in some_public_api
some_nested_function_that_does_the_nasty_mutation(obj)
File "test.py", line 6, in some_nested_function_that_does_the_nasty_mutation
obj.attr_name = 2
test.py:6 return obj.attr_name = 2
... return value: None
You can also use other actions that hunter supports. For instance, Debugger which breaks into pdb (debugger on an attribute change).
Try using __setattr__ to override the function that is called when an attribute assignment is attempted. Documentation for __setattr__
You can use the python debugger module (part of the standard library)
To use, just import pdb at the top of your source file:
import pdb
and then set a trace wherever you want to start inspecting the code:
pdb.set_trace()
You can then step through the code with n, and investigate the current state by running python commands.
def __setattr__(self, name, value):
if name=="xxx":
util.output_stack('xxxxx')
super(XXX, self).__setattr__(name, value)
This sample code helped me.

Proper way to pass variables within a tkinter GUI

I am trying to write a simple GUI to plot data from a csv file, which I read into a pandas DataFrame. I am completely new to GUI programming, and I am having a hard time getting my head around event-driven setups like Tkinter.
As a simple exercise, I want to set up a couple of buttons, one to open a file and read in the DataFrame, and another to print out the resulting DataFrame. My first naive attempt didn't work:
import pandas as pd
import tkFileDialog
import Tkinter as tk
def open_events_db():
file_path_string = tkFileDialog.askopenfilename()
eventsdb = pd.read_csv(file_path_string,encoding='utf-8')
return eventsdb
def print_events_db(eventsdb):
print eventsdb
def main():
root=tk.Tk()
eventsdb = tk.Button(text='File Open', command=open_events_db).pack(fill=tk.X)
tk.Button(text='Print DB', command=lambda:print_events_db(eventsdb)).pack(fill=tk.X)
tk.mainloop()
if __name__=="__main__":
main()
I can read in the file fine, and open it, but in hindsight obviously I can't return eventsdb from the file open button and have it as an argument to the print button.
I don't think it's unreasonable to have buttons that operate on that DB, though, so what is the proper way to pass variables around within the GUI?
Functions called from buttons and event handers don't return their data. Instead, they must set global variables or class attributes.
def open_events_db():
global eventsdb
file_path_string = tkFileDialog.askopenfilename()
eventsdb = pd.read_csv(file_path_string,encoding='utf-8')
def print_events_db():
global eventsdb
print eventsdb
...
tk.Button(text='Print DB', command=print_events_db).pack(fill=tk.X)
It's generally considered poor programming to rely on global variables. Since python is an object oriented language, it makes sense to write your app as a class. You would then use instance attributes rather than global variables.
import Tkinter as tk
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
open_button = tk.Button(text='File Open', command=self.open_events_db)
print_button = tk.Button(text='Print DB', command=self.print_events_db)
open_button.pack(fill=tk.X)
print_button.pack(fill=tk.X)
def open_events_db(self):
file_path_string = tkFileDialog.askopenfilename()
self.eventsdb = pd.read_csv(file_path_string,encoding='utf-8')
def print_events_db():
print self.eventsdb
def main():
root=tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
if __name__=="__main__":
main()

python problems with super

Ok so I'm having a bit of a problem with the code below. It works as is but if I try to change the part with the comment about me not being able to get super to work correctly to.
pipeline_class_call = super(Error_Popup,self)
broken_file_w_whats_wrong = pipeline_class_call.whats_wrong_with_file()
or to
broken_file_w_whats_wrong = super(Error_Popup,self).whats_wrong_with_file()
and change
class Error_Popup(QtGui.QDialog):
to
class Error_Popup(QtGui.QDialog,Pipeline_UI):
I get the following error
# TypeError: object of type 'instancemethod' has no len() #
Which normally means that I need to call the method, but doesn't super handle all this for me. Or am I goofing this?
from PySide import QtCore, QtGui
from shiboken import wrapInstance
import pymel.core as pm
import maya.OpenMayaUI as omui
from UI.UI import Pipeline_UI
def something_bad_happened_window():
sbh_pointer = omui.MQtUtil.mainWindow()
return wrapInstance(long(sbh_pointer), QtGui.QWidget)
class Error_Popup(QtGui.QDialog):
def __init__(self,parent=something_bad_happened_window()):
super(Error_Popup,self).__init__(parent)
self.setWindowTitle('Something Bad Happened!')
self.setWindowFlags(QtCore.Qt.Tool)
self.popup_layout()
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.connections()
def popup_layout(self):
self.file_description = QtGui.QListWidget()
#cant seem to get super to work appropriately... booo
pipeline_class_call = Pipeline_UI()
broken_file_w_whats_wrong = pipeline_class_call.whats_wrong_with_file()
for display in range(0,len(broken_file_w_whats_wrong)):
broken_list = QtGui.QListWidgetItem()
if display % 2 == 0:
broken_list.setText(broken_file_w_whats_wrong[display][0])
broken_list.asset = broken_file_w_whats_wrong[display][1]
else:
broken_list.setText(" " + broken_file_w_whats_wrong[display][0])
self.file_description.addItem(broken_file_w_whats_wrong[display])
self.import_button = QtGui.QPushButton('Import Replacement(s)')
error_layout = QtGui.QVBoxLayout()
error_layout.setContentsMargins(2,2,2,2)
error_layout.setSpacing(2)
error_layout.addWidget(self.file_description)
error_layout.addWidget(self.import_button)
error_layout.addStretch()
self.setLayout(error_layout)
def connections(self):
self.import_button.clicked.connect(Error_Popup.make_sphere)
#classmethod
def make_sphere(cls):
pm.polySphere()
def show_window():
ui = Error_Popup()
if __name__ == '__main__':
try:
ui.close()
except:
pass
ui.show()
show_window()
Thanks in advance everyone
Looks to me like it's a problem of using super with multiple inheritance. It picks one of the parents in a certain order to use. For example, super(Error_Popup,self).__init__(parent) only calls one of the parents __init__ methods. You have to manually call all of them.
When calling methods or accessing variables, you have to be specific about which parent you want to use or super will pick for you. See this answer and this answer.