Python3 tkinter label value - json

I need some help, I trying to update the etcprice label value after I push the button and after every 5 seconds, in terminal works, but in tk window not. I stucked here :( please, help me.
I tried to setup the "price" to "StringVar()" but in that case I got a lot of errors.
Many thanks
import urllib.request
from urllib.request import *
import json
import six
from tkinter import *
import tkinter as tk
import threading
price = '0'
def timer():
threading.Timer(5.0, timer).start()
currentPrice()
def currentPrice():
url = 'https://api.cryptowat.ch/markets/bitfinex/ethusd/price'
json_obj = urllib.request.urlopen(url)
data = json.load(json_obj)
for item, v in six.iteritems(data['result']):
# print("ETC: $", v)
price = str(v)
# print(type(etcar))
print(price)
return price
def windows():
root = Tk()
root.geometry("500x200")
kryptoname = Label(root, text="ETC price: ")
kryptoname.grid(column=0, row=0)
etcprice = Label(root, textvariable=price)
etcprice.grid(column=1, row=0)
updatebtn = Button(root, text="update", command=timer)
updatebtn.grid(column=0, row=1)
root.mainloop()
windows()
The solution was: I created a new String variable called “b” and I changed the etcprice Label variable to this.
After I added this b.set(price) in currentPrice() def: and is working.

The price variable is a global - if you're trying to change it, you need to do so explicitly:
def currentPrice():
global price
url = 'https://api.cryptowat.ch/markets/bitfinex/ethusd/price'
json_obj = urllib.request.urlopen(url)
data = json.load(json_obj)
for item, v in six.iteritems(data['result']):
# print("ETC: $", v)
price = str(v)
# print(type(etcar))
print(price)
return price
otherwise, Python will 'mirror' it as a local variable inside the function, and not modify the global.
It's not a good idea to keep on launching more and more threads each time you click the button - so:
updatebtn = Button(root, text="update", command=currentPrice)
probably makes more sense.
You don't need to use threads here, just to call functions 'in the background'. You can use tkinter's own .after function instead to delay caling functions. (it uses milliseconds, not float second values, btw)
def timer(delay_ms, root, func):
func()
root.after(delay_ms, timer, root, func)
might be a helpful kind of function.
Then before you launch your mainloop, or whenever you want the getting to start, call it once:
timer(5000, root, currentPrice)
If you want the currentPrice function to run in a separate thread, and so not block your main GUI thread if there is network lag, for instance, then you can use threads more like this:
Thread(target=currentPrice, daemon=True).start()
which will run it in a daemon-thread - which will automatically get killed if you close the program, or ctrl-c it, or whatever. So you could put that line in a getCurrentPriceBG or similar function.

Related

Count the number of people having a property bounded by two numbers

The following code goes over the 10 pages of JSON returned by GET request to the URL.
and checks how many records satisfy the condition that bloodPressureDiastole is between the specified limits. It does the job, but I was wondering if there was a better or cleaner way to achieve this in python
import urllib.request
import urllib.parse
import json
baseUrl = 'https://jsonmock.hackerrank.com/api/medical_records?page='
count = 0
for i in range(1, 11):
url = baseUrl+str(i)
f = urllib.request.urlopen(url)
response = f.read().decode('utf-8')
response = json.loads(response)
lowerlimit = 110
upperlimit = 120
for elem in response['data']:
bd = elem['vitals']['bloodPressureDiastole']
if bd >= lowerlimit and bd <= upperlimit:
count = count+1
print(count)
There is no access through fields to json content because you get dict object from json.loads (see translation scheme here). It realises access via __getitem__ method (dict[key]) instead of __getattr__ (object.field) as keys may be any hashible objects not only strings. Moreover, even strings cannot serve as fields if they starts with digits or are the same with built-in dictionary methods.
Despite this, you can define your own custom class realising desired behavior with acceptable key names. json.loads has an argument object_hook wherein you may put any callable object (function or class) that take a dict as the sole argument (not only the resulted one but every one in json recursively) & return something as the result. If your jsons match some template, you can define a class with predefined fields for the json content & even with methods in order to get a robust Python-object, a part of your domain logic.
For instance, let's realise the access through fields. I get json content from response.json method from requests but it has the same arguments as in json package. Comments in code contain remarks about how to make your code more pythonic.
from collections import Counter
from requests import get
class CustomJSON(dict):
def __getattr__(self, key):
return self[key]
def __setattr__(self, key, value):
self[key] = value
LOWER_LIMIT = 110 # Constants should be in uppercase.
UPPER_LIMIT = 120
base_url = 'https://jsonmock.hackerrank.com/api/medical_records'
# It is better use special tools for handling URLs
# in order to evade possible exceptions in the future.
# By the way, your option could look clearer with f-strings
# that can put values from variables (not only) in-place:
# url = f'https://jsonmock.hackerrank.com/api/medical_records?page={i}'
counter = Counter(normal_pressure=0)
# It might be left as it was. This option is useful
# in case of additional counting any other information.
for page_number in range(1, 11):
records = get(
base_url, data={"page": page_number}
).json(object_hook=CustomJSON)
# Python has a pile of libraries for handling url requests & responses.
# urllib is a standard library rewritten from scratch for Python 3.
# However, there is a more featured (connection pooling, redirections, proxi,
# SSL verification &c.) & convenient third-party
# (this is the only disadvantage) library: urllib3.
# Based on it, requests provides an easier, more convenient & friendlier way
# to work with url-requests. So I highly recommend using it
# unless you are aiming for complex connections & url-processing.
for elem in records.data:
if LOWER_LIMIT <= elem.vitals.bloodPressureDiastole <= UPPER_LIMIT:
counter["normal_pressure"] += 1
print(counter)

How to receive data from buildin function of another class in another module

I am programming a case manager (administration system). To build it constructively, I program in separate modules to keep an overview. Some modules contain a class-object where I build an small search engine including its own functions. The main program is the case form itself. Obviously, when the search engine finds an entry, it should fill in the case form. I am able to call the search engine (and the search engine works to), however I don't know how to return the results back to the main program/case form/module.
To give you a picture, I have added a image of the GUI, so you can see the case form and the search engine (which is a different module and class (inheriting tk.Toplevel)
The relevant code (case_form/main program):
import ReferenceSearch as rs #Own module
def search_ref(self):
#Function to call search engine
search_engine = rs.ReferenceSearch(self, self.csv_file.get(), self.references_list)
#Reveive data from search_engine and show it in case_form
self.title_var.set(search_engine) #DOES NOT WORK BECAUSE search_engine IS THE ACTUAL ENGINE NOT THE
DATA returned from its buildin function
Relevant code in ReferenceSearch module:
class ReferenceSearch(tk.Toplevel):
def __init__(self, parent, csv_file,references_list=[]):
super().__init__()
self.parent = parent
self.csv_file = csv_file
self.references_list = references_list
self.ref_search_entry = ttk.Entry(self.search_frame)
self.search_but = tk.Button(self.search_frame,
text=" Search ",
command=lambda:self.search_for_ref(self.ref_search_entry.get())
def search_for_ref(self, reference, csv_file="Cases.csv"):
#Function to read specific entry by reference
if reference in self.references_list:
with open(csv_file, "r", newline="") as file:
reader = csv.DictReader(file, delimiter="|")
for entry in reader:
if reference == entry["Reference"]:
data = entry["Title"] #By example
return data
How do I receive the data from the buildin function of the ReferenceSearch class and use it in the main module the case_form?
Keep in mind that the ReferenceSearch module is calling this function when the search button is pressed (and not the case_form module). However, the data is needed in the case_form module.
Change the ReferenceSearch module contents to:
class ReferenceSearch(tk.Toplevel):
def __init__(self, parent, csv_file,references_list=[]):
super().__init__()
self.data = ""
self.parent = parent
self.csv_file = csv_file
self.references_list = references_list
self.ref_search_entry = ttk.Entry(self.search_frame)
self.search_but = tk.Button(self.search_frame,
text=" Search ",
command=lambda:self.search_for_ref(self.ref_search_entry.get())
def search_for_ref(self, reference, csv_file="Cases.csv"):
#Function to read specific entry by reference
if reference in self.references_list:
with open(csv_file, "r", newline="") as file:
reader = csv.DictReader(file, delimiter="|")
for entry in reader:
if reference == entry["Reference"]:
data = entry["Title"] #By example
self.parent.title_var.set(data)
and case_form contents to:
import ReferenceSearch as rs
def search_ref(self):
#Function to call search engine
search_engine = rs.ReferenceSearch(self, self.csv_file.get(), self.references_list)

Tkinter calling functions within a class

Hi I am having trouble calling functions in tkinter
Here is the code
class Demo(tk.Frame):
def ShowOption(self):
print(self.v1.get())
def __init__(self,controller):
tk.Frame.__init__(self,width=800, height=600)
f = Frame(self)
optionList = ('A', 'B','C')
self.v1 = tk.StringVar()
self.v1.set(optionList[0])
Opt1 = tk.OptionMenu(f, self.v1, *optionList,command = self.ShowOption)
Opt1.grid(row=2,column=2,sticky='w')
f.place(relx = 0.5,rely=0.5,anchor='c')
The problem I have is if I use this method it states the function takes 1 postional argument and none were given but if I use
Opt1 = tk.OptionMenu(f, self.v1, *optionList,command = self.ShowOption() )
The function runs straight away when the class is created.
Any help greatly appreciated.
Callback for the command option of OptionMenu expects an argument which is the selected item.
So either you use lambda to skip the argument:
command=lambda v: self.ShowOption()
Or redefine ShowOption() to accept an argument:
def ShowOption(self, value):
...
do this
command = lambda : self.ShowOption()

save list to CSV - python

I try to save my output as csv using the "import csv" and only get errors. Any reason why?
Since I can not make it run will it also notify if the file already exists?
Thanks a lot
from tkinter import *
from tkinter.filedialog import asksaveasfilename
from tkinter import ttk
import csv
def data():
...
output= <class 'list'> #just an example
...
def savefile():
name= asksaveasfilename()
create = csv.writer(open(name, "wb"))
create.writerow(output)
for x in output:
create.writerow(x)
root = Tk()
Mframe = ttk.Frame(root)
Mframe.grid(column=0, row=0, sticky=(N, W, E, S))
bSave=ttk.Button(Mframe, text='Save File', command=savefile)
bSave.grid(column=1, row=0)
root.mainloop()
You are opening the file, but not closing it. A good practise is to use a with statement make sure you close it. By the way, I don't know how is the output list, but if it isn't a list of lists, it makes more sense to me to call writerow once.
Besides, make sure this list is also a global variable, otherwise it won't be available within the scope of savefile. However, global variables are not a very good solution, so consider to pass it as an argument to savefile or use a class to hold all this data:
def savefile():
name = asksaveasfilename()
with open(name, 'w', newline='') as csvfile:
create = csv.writer(csvfile)
create.writerow(output)

Django equivalent of SqlAlchemy's literal_column

Trying to port some SqlAlchemy to Django and I've got this tricky little bit:
version = Column(
BIGINT,
default=literal_column(
'UNIX_TIMESTAMP() * 1000000 + MICROSECOND(CURRENT_TIMESTAMP)'
),
nullable=False)
What's the best option for porting the literal_column bit to Django? Best idea I've got so far is a function to set as the default that executes the same raw sql, but I'm not sure if there's an easier way? My google-foo is failing me there.
Edit: the reason we need to use a timestamp created by mysql is that we are measuring how out of date something is (so we need to actually know time) and we want, for correctness, to have only one time-stamping authority (so that we don't introduce error using python functions that look at system times, which could be different across servers).
At present I've got:
def get_current_timestamp(self):
cursor = connection.cursor()
cursor.execute("SELECT UNIX_TIMESTAMP() * 1000000 + MICROSECOND(CURRENT_TIMESTAMP)")
row = cursor.fetchone()
return row
version = models.BigIntegerField(default=get_current_timestamp)
which, at this point, sounds like my best/only option.
If you don't care about having a central time authority:
import time
version = models.BigIntegerField(
default = lambda: int(time.time()*1000000) )
To bend the database to your will:
from django.db.models.expressions import ExpressionNode
class NowInt(ExpressionNode):
""" Pass this in the same manner you would pass Count or F objects """
def __init__(self):
super(Now, self).__init__(None, None, False)
def evaluate(self, evaluator, qn, connection):
return '(UNIX_TIMESTAMP() * 1000000 + MICROSECOND(CURRENT_TIMESTAMP))', []
### Model
version = models.BigIntegerField(default=NowInt())
because expression nodes are not callables, the expression will be evaluated database side.