PyQT Threadin kills my memory - multithreading

The following block of code is part of the class Dataview(QWidget), which is called in main.py. It creates 3 tables; bids, asks and history and automaticly fetches data from various exchanges via API.
The application works, but when viewing in Task Manager my memory usage keeps getting bigger and bigger - which I think is due to way I run these threads. What am I doing wrong here?
EDIT:
MAIN.PY
import sys
from PyQt4 import QtCore, QtGui, Qt
from datetime import datetime
import time
import thread
from apis import API_Bitstamp_usd
class Dataview(QtGui.QFrame):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setFixedSize(152,730)
self.setStyleSheet('background: #444;background-color: QLinearGradient(x1:0, y1:0,x2:0, y2:1,stop:1 #212121,stop:0.4 #343434/*,stop:0.2 #343434,stop:0.1 #ffaa00*/);margin-bottom:-1px;padding-bottom:1px;')
self.setup_table_asks()
self.setup_table_bids()
self.setup_table_hist()
self.setup_label()
self.start_threads()
def setup_table_asks(self):
self.table_asks = QtGui.QTableWidget(self)
self.table_asks.setGeometry(10,30,132,180)
self.table_asks.setStyleSheet('color: lightblue; background: #444;background-color: QLinearGradient(x1:0, y1:0,x2:0, y2:1,stop:1 #212121,stop:0.4 #343434/*,stop:0.2 #343434,stop:0.1 #ffaa00*/);margin-bottom:-1px;padding-bottom:1px;')
self.table_asks.setFrameShadow(QtGui.QFrame.Raised)
self.table_asks.horizontalHeader().hide()
self.table_asks.verticalHeader().hide()
self.table_asks.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.table_asks.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.table_asks.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.table_asks.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
self.table_asks.setShowGrid(False)
self.table_asks.setRowCount(300)
self.table_asks.setColumnCount(3)
self.table_asks.setColumnWidth(0,50)
self.table_asks.setColumnWidth(1,40)
self.table_asks.setColumnWidth(2,40)
self.table_asks.setCursor(QtCore.Qt.SizeVerCursor)
self.table_asks.scrollToBottom()
def setup_table_bids(self):
self.table_bids = QtGui.QTableWidget(self)
self.table_bids.setGeometry(10,230,132,180)
self.table_bids.setStyleSheet('color: lightblue; background: #444;background-color: QLinearGradient(x1:0, y1:0,x2:0, y2:1,stop:1 #212121,stop:0.4 #343434/*,stop:0.2 #343434,stop:0.1 #ffaa00*/);margin-bottom:-1px;padding-bottom:1px;')
self.table_bids.setFrameShadow(QtGui.QFrame.Raised)
self.table_bids.horizontalHeader().hide()
self.table_bids.verticalHeader().hide()
self.table_bids.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.table_bids.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.table_bids.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.table_bids.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
self.table_bids.setShowGrid(False)
self.table_bids.setRowCount(300)
self.table_bids.setColumnCount(3)
self.table_bids.setColumnWidth(0,50)
self.table_bids.setColumnWidth(1,40)
self.table_bids.setColumnWidth(2,40)
self.table_bids.setCursor(QtCore.Qt.SizeVerCursor)
def setup_table_hist(self):
self.table_hist = QtGui.QTableWidget(self)
self.table_hist.setGeometry(10,414,132,206)
self.table_hist.setStyleSheet('color: lightblue;background: #444;background-color: QLinearGradient(x1:0, y1:0,x2:0, y2:1,stop:1 #212121,stop:0.4 #343434/*,stop:0.2 #343434,stop:0.1 #ffaa00*/);margin-bottom:-1px;padding-bottom:1px;')
self.table_hist.setFrameShadow(QtGui.QFrame.Raised)
self.table_hist.horizontalHeader().hide()
self.table_hist.verticalHeader().hide()
self.table_hist.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.table_hist.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.table_hist.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.table_hist.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
self.table_hist.setShowGrid(False)
self.table_hist.setRowCount(150)
self.table_hist.setColumnCount(3)
self.table_hist.setColumnWidth(0,45)
self.table_hist.setColumnWidth(1,45)
self.table_hist.setColumnWidth(2,40)
self.table_hist.setCursor(QtCore.Qt.SizeVerCursor)
def setup_label(self):
self.label = QtGui.QLabel(self)
self.label.setGeometry(10,210,132,20)
self.label.setFrameShadow(QtGui.QFrame.Sunken)
self.label.setText('last_price')
self.label.setStyleSheet('color: lightblue;background: #444;background-color: QLinearGradient(x1:0, y1:0,x2:0, y2:1,stop:1 #212121,stop:0.4 #343434/*,stop:0.2 #343434,stop:0.1 #ffaa00*/);margin-bottom:-1px;padding-bottom:1px;')
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.title = QtGui.QLabel(self)
self.title.setGeometry(10,10,132,20)
self.title.setStyleSheet('color: silver;background: #444;background-color: QLinearGradient(x1:0, y1:0,x2:0, y2:1,stop:1 #212121,stop:0.4 #343434/*,stop:0.2 #343434,stop:0.1 #ffaa00*/);margin-bottom:-1px;padding-bottom:1px;')
self.title.setText('Bitstamp')
self.title.setAlignment(QtCore.Qt.AlignCenter)
def start_threads(self):
thread.start_new_thread(self.fill_table_bids, ())
thread.start_new_thread(self.fill_table_asks, ())
thread.start_new_thread(self.fill_table_hist, ())
def fill_table_bids(self):
while True:
ticker = API_Bitstamp_usd()
x = ticker.get_depth()
bids = x[0]
row = 0
depth = 0
for i in bids:
price = i[0]
qty = i[1]
depth = format(float(depth) + float(qty), '.1f')
self.table_bids.setRowHeight(row, 12)
tw = QtGui.QTableWidgetItem(str(price))
self.table_bids.setItem(row,0,tw)
tw = QtGui.QTableWidgetItem(str(qty))
tw.setTextAlignment(5)
self.table_bids.setItem(row,1,tw)
tw = QtGui.QTableWidgetItem(str(depth))
tw.setTextAlignment(5)
self.table_bids.setItem(row,2,tw)
row = row + 1
time.sleep(2)
def fill_table_asks(self):
while True:
ticker = API_Bitstamp_usd()
x = ticker.get_depth()
asks = x[1]
row = 0
depth = 0
for i in asks[:300]:
depth = depth + float(i[1])
for i in reversed(asks[:300]):
price, qty = i[0], i[1]
depth = format(float(depth) - float(qty), '.1f')
self.table_asks.setRowHeight(row, 12)
tw = QtGui.QTableWidgetItem(str(price))
self.table_asks.setItem(row,0,tw)
tw = QtGui.QTableWidgetItem(str(qty))
tw.setTextAlignment(5)
self.table_asks.setItem(row,1,tw)
if depth > 0:
tw = QtGui.QTableWidgetItem(str(depth))
tw.setTextAlignment(5)
self.table_asks.setItem(row,2,tw)
row = row + 1
time.sleep(2)
def fill_table_hist(self):
while True:
ticker = API_Bitstamp_usd()
x = ticker.get_history()
row = 0
for i in x:
timestamp = datetime.fromtimestamp(float(i[0])).strftime('%H:%M:%S')
price = i[1]
qty = i[2]
type = i[3]
self.table_hist.setRowHeight(row, 12)
tw = QtGui.QTableWidgetItem(str(timestamp))
self.table_hist.setItem(row,0,tw)
tw = QtGui.QTableWidgetItem(str(price))
tw.setTextAlignment(5)
self.table_hist.setItem(row,1,tw)
tw = QtGui.QTableWidgetItem(str(qty))
tw.setTextAlignment(5)
if type == 'sell':
tw.setTextColor(QtGui.QColor('red'))
else:
tw.setTextColor(QtGui.QColor('green'))
self.table_hist.setItem(row,2,tw)
row = row + 1
self.label.setText(str(x[0][1]))
time.sleep(2)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = Dataview()
myapp.show()
sys.exit(app.exec_())
APIS.PY
import urllib2
import json
class API_Bitstamp_usd:
def __init__(self):
self.url = 'https://www.bitstamp.net/api/'
def get_depth(self):
try:
url = self.url + 'order_book/'
json_obj = urllib2.urlopen(url)
data = json.load(json_obj)
asks_, bids_ = [], []
for i in data['bids']:
price, qty = format(float(i[0]), '.2f'), format(float(i[1]), '.2f')
bids_.append([float(price), float(qty)])
for i in data['asks']:
price, qty = format(float(i[0]), '.2f'), format(float(i[1]), '.2f')
asks_.append([float(price), float(qty)])
return bids_, asks_
except:
pass
def get_history(self):
try:
url = self.url + 'transactions/'
json_obj = urllib2.urlopen(url)
data = json.load(json_obj)
history_ = []
for i in data:
timestamp, price, amount, type = i['date'], format(float(i['price']), '.3f'), format(float(i['amount']), '.2f'), ''
history_.append([timestamp, float(price), float(amount), type])
return history_
except:
pass

Related

Open multiple windows per time interval, using same long function, receiving different data with Python and PySimpleGui

I'm making a system that receives a list of login data (username and password), then opens each user and password in a window, consuming the same function that I receive as user and password parameters.
Below is a reduced example of what I'm doing.
from multiprocessing.dummy import Process
import PySimpleGUI as sg
from time import sleep
import threading
import concurrent.futures
from concurrent.futures import ThreadPoolExecutor
import multiprocessing as mp
from multiprocessing import Process
import os, json
from datetime import datetime, timezone
import time
import random
HOME = './Dados'
def current_location(self):
geometry = self.TKroot.geometry()
location = geometry[geometry.find('+') + 1:].split('+')
x, y = int(location[0]), int(location[1])
return(x, y+-30)
sg.Window.current_location = current_location
def function_thread(usuario, senha):
global window
window['output'].print(f'Login {usuario} e {senha}')
for i in range(5):
#print(f'Tarefas no perfil {usuario}')
#window['output'].update(str('Tarefas no perfil {usuario}'))
time.sleep(random.randint(1,2))
horaatual = datetime.today().strftime('[%H:%M:%S:%f] - ')
window['output'].print(horaatual+': Tarefas: '+ str(i))
#sleep(2)
#window.write_event_value('output', i)
#window.write_event_value('output', usuario)
window['output'].print(f'Completado {usuario}')
#sleep(1)
x=-7
y=515
def abrir_abas():
global x,y, usuario_insta, senha_insta
window2 = None
cont = 0
#list_user = [('perfil1','senha1'),('perfil2', 'senha2'),('perfil3', 'senha3'),('perfil4', 'senha4'),('perfil5','senha5'),('perfil6', 'senha6'),('perfil7', 'senha7'),('perfil8', 'senha8')]
'''
executor = concurrent.futures.ProcessPoolExecutor(8)
futures = [executor.submit(function_thread(group[0],group[1])for group in list_user)]
concurrent.futures.wait(futures)
'''
with open(os.path.join(HOME, f'Config/abas.txt'), 'r') as f:
abas = f.readlines()
lista_conta = []
for index_lista in range(len(abas)):
abas[index_lista] = abas[index_lista].rstrip('\n')
if abas[index_lista] != '' or None:
lista_conta.append(abas[index_lista])
#with concurrent.futures.ProcessPoolExecutor() as executor:
for i_lista_conta in range(len(lista_conta)):
qtd_lista_conta = int(len(lista_conta)/2)
if i_lista_conta % 2 == 0:
usuario = lista_conta[i_lista_conta].split(' ')
usuario_insta = usuario[0]
senha_insta = usuario[1]
#self.output(usuario_insta, senha_insta)
titulo = 'TAB '+usuario_insta
window2 = output(usuario_insta, senha_insta, loc=(x,y))
window2.TKroot.title(titulo)
t1 = threading.Thread(target=function_thread(usuario_insta, senha_insta), daemon=True)
t1.start()
y=y+-30
y=y
cont = cont + 1
'''
processos = []
for i_lista_conta in range(len(lista_conta)):
qtd_lista_conta = int(len(lista_conta)/2)
if i_lista_conta % 2 == 0:
usuario_insta = lista_conta[i_lista_conta]
senha_insta = lista_conta[i_lista_conta+1]
#self.output(usuario_insta, senha_insta)
titulo = 'TAB '+usuario_insta
window2 = output(loc=(x,y))
window2.TKroot.title(titulo)
#threading.Thread(target=self.thread_acao(usuario_insta, senha_insta), daemon=True).start()
p = Process(target=function_thread(usuario_insta, senha_insta))
p.start()
processos.append(p)
y=y+-30
y=y
cont = cont + 1
'''
#for process in processos:
# process.join()
'''
for i in list_user:
titulo = 'TAB '+i[0]
#with concurrent.futures.ProcessPoolExecutor() as executor:
# window2 = executor.map(output(loc=(x,y)))
window2 = output(loc=(x,y))
window2.TKroot.title(titulo)
#with concurrent.futures.ProcessPoolExecutor() as executor:
# executor.map(function_thread(i[0],i[1]))
#threading.Thread(target=function_thread(i[0],i[1]), daemon=True).start()
Process(target=function_thread(i[0],i[1])).start()
y=y+-30
y=y
cont = cont + 1
sleep(2)
'''
def output(login, senha, loc=(-7, 515))->sg.Window:
global window
voltar = 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF8WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDggNzkuMTY0MDM2LCAyMDE5LzA4LzEzLTAxOjA2OjU3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMCAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIwLTAzLTAzVDA5OjUwOjM0LTAzOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMC0wNS0wMlQxNzo1Nzo0Mi0wMzowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyMC0wNS0wMlQxNzo1Nzo0Mi0wMzowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo0MGZlY2VlMS0yYmE4LTI4NGQtYTk4NC0zYjQxNTIxNzA1ZGQiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDo2MmQ1MzYwYi0zMTQ5LTI2NDAtYWZhMC03YzdiNjkzNDFkY2YiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowZDY2MTNmZi0wMGIzLWMzNDQtYTgzOS1jMTUwZTc4ZGZlODEiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjBkNjYxM2ZmLTAwYjMtYzM0NC1hODM5LWMxNTBlNzhkZmU4MSIgc3RFdnQ6d2hlbj0iMjAyMC0wMy0wM1QwOTo1MDozNC0wMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIxLjAgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MGZlY2VlMS0yYmE4LTI4NGQtYTk4NC0zYjQxNTIxNzA1ZGQiIHN0RXZ0OndoZW49IjIwMjAtMDUtMDJUMTc6NTc6NDItMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4wIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4M/LCOAAABD0lEQVQ4y43SMSvFURjH8XPvVchCScpwB2VRykIpG7u7KLeMZGGQd6BMXoDZwAtQUgaTkZKNRalPSgYZrAbn1On0v/f+Tz2d0/P0fM/z/J4nIBTWyN5rOMU5zrCD4RhrIvRKHsEFXmLiIU5wjycsJUioqCDgCtcYrYgd+D/zZQWteO/FX3J/I5acKjzGTVULAXfYiu+hHi2O4w0LZWAy/j5XIWhpl+iUgGk8YLYGYAJjVYDHmoCQNGhmApaAVpp3P0BuJSAMqiRgFSvRMRM1SCIuYr0fJKCDTyzHNX3GFNr4wG6+ur1a2MY7urjFBl5x1C85FzFBvvGFn7iyoa6IaQqb+MV+4a81hSRSe1BSbn+7uNbAq7k3vAAAAABJRU5ErkJggg=='
pause = 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAABYlAAAWJQFJUiTwAAAGvmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDggNzkuMTY0MDM2LCAyMDE5LzA4LzEzLTAxOjA2OjU3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMCAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIwLTA1LTAyVDE3OjQ4OjI0LTAzOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMC0wNS0wM1QxMTowNjo0NC0wMzowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyMC0wNS0wM1QxMTowNjo0NC0wMzowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo0ODFlYzZjZS1jYTNhLWIxNDgtYjlmYy0yZmZmYjVhNzI3ZTEiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDo1NmE4ZDEzNC0wNmIzLWVkNGMtOWYwYi1kMjk4YmU1YTlmYzAiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZmQ2MzhkYy05YzYyLTFjNGUtYjg2Ny03ZDNmOTdlMmE5YTgiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjRmZDYzOGRjLTljNjItMWM0ZS1iODY3LTdkM2Y5N2UyYTlhOCIgc3RFdnQ6d2hlbj0iMjAyMC0wNS0wMlQxNzo0ODoyNC0wMzowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIxLjAgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo0N2MwYWRlMy02NmVjLWVjNDEtYjE1YS0zNmI2ZmZmOGEzNWYiIHN0RXZ0OndoZW49IjIwMjAtMDUtMDJUMTc6NTI6MTYtMDM6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMS4wIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NDgxZWM2Y2UtY2EzYS1iMTQ4LWI5ZmMtMmZmZmI1YTcyN2UxIiBzdEV2dDp3aGVuPSIyMDIwLTA1LTAzVDExOjA2OjQ0LTAzOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgMjEuMCAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+sKbvRwAAAWBJREFUOI3t1L2KFFEQBeCvZ8afBZENFmEEBU0MxGQfQBE00jfYh9DUFxBBQzMx8A00MlVMDQVRFARxXDN1BWfH6W2DPpe5jLA7xnqS+1NV51Rfuk4zmUwE6ziR/R5G+IFJznJ3CkfwK+c5PmE6Ho+NLHAW59CF4BC+YgffkrOBTRzFLDltYu+L4nrInuNYFGuhO7iV4ge4XuW0GOItLmF7hDEuhGwLr1I8x31cDvEaLuIR7uWzZxG4jdOFUJQ6vMDHqrsPOJN9F4I3ES04mXUOg7zXHpq8UY3jJTGEbe5qbFRxA/ujOyD+R85BhH+N/4T/ImGzQs2+/+ZAP9xlBD8vxXdwuBIrDlSj1AxZOEbxuy29cwxzv2lhXcXSruC13sKmuFZ3PtKbQasf+LtL6jPcyH6Kh7iJq0t5j/GuEP7EFzzBd+ymmzVs42WKWjzD+XS3m44bPM3zaLpulflfHb8BEgRaa6It0wUAAAAASUVORK5CYII='
col_v = sg.Column(
[
[sg.Button(image_data=pause, size=(None,20), key='Executar',button_color=(sg.theme_background_color(), sg.theme_background_color()), border_width=0)],
[sg.Text('')],
[sg.Button(image_data=voltar, key='voltar',tooltip="Voltar",button_color=(sg.theme_background_color(), sg.theme_background_color()), border_width=0)],
], k='c_v', visible=True)
main_layout =[
#[sg.Titlebar(title = texto, key = 'titulo')],
[sg.StatusBar('O Rei Dos BOTs',justification='center', font='Arial 12')],
[col_v,sg.Multiline(size=(20,2),expand_x=True, expand_y=True, key='output')],
[sg.StatusBar('INICIANDO', k='status+', auto_size_text=True, justification='center', font=('Arial', 12, 'bold'), text_color='#FFFFFF', background_color=None, s=(None, 1))],
]
window = sg.Window('ABA', size=(253,181), finalize=True, location=loc, background_color=None, auto_size_text=True, font='Arial 7', resizable=True, auto_size_buttons=False,right_click_menu = False, margins=(1, 1)).Layout(main_layout).Finalize()
#with concurrent.futures.ProcessPoolExecutor() as executor:
# executor.map(function_thread(login, senha))
return window
def main_output():
global window, usuario_insta, senha_insta
sg.theme('Topanga')
layout = [ [sg.Text('Janela')],
[sg.Text(size=(10,1), key='-OUT-')],
[sg.Button('Executar'), sg.Button('Sair')],
[sg.StatusBar('INICIANDO', k='status', auto_size_text=True, justification='center', font='Arial 12', text_color='#FFFFFF', background_color=None, s=(None, 1))],
]
window = sg.Window('Janela principal', layout, size=(253,181), use_default_focus=False,finalize=True, use_custom_titlebar=False, no_titlebar=False)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED or event == 'Sair':
break
if event == 'Executar':
window.hide()
#with ThreadPoolExecutor() as executor:
# executor.map(abrir_abas())
#threading.Thread(target=abrir_abas(), daemon=True).start()
abrir_abas()
#threading.Thread(target=abrir_abas(), args=(window,), daemon=False).start()
#with concurrent.futures.ProcessPoolExecutor() as executor:
# executor.map(abrir_abas())
if event == 'Ok':
print('Completado')
if event == 'voltar':
print('Voltar')
window.close()
#threading.Thread(target=main_output(), args=(window,), daemon=True).start()
main_output()
I can only do this by opening the first window and waiting for the function to complete and then opening the second window and so on.
The function is looping and can take more than 24 hours.

Python 3 TypeError: 'int' object is not callable, but what is the fault here?

currently I am leraning Python 3 and I am facing here the following problem within my blackjack card game code.
The output is the result of the player.points() function, I was testing it outside of the written code and it worked well like that, so I dont get it where the Error Message comes from, any hints or ideas?
```
from IPython.display import clear_output
import time
import random
import emoji
class Player():
def __init__(self, account,name):
self.name = name
self.account = account
self.betbox = 0
self.cards = [[]]
self.points = 0
self.status = True # True -> Player, False -> Spectator
def bet(self,bet):
self.betbox = int(bet)
self.account -= int(bet)
def get_card(self, card, deck_of_cards=0):
self.cards[deck_of_cards].append(card)
def points(self):
for i,cards in enumerate(self.cards):
for card in self.cards[i]:
print(card)
def __str__(self):
player_string = ""
name_string = "Player: "+ str(self.name)
cards_string = ""
account_string = "Account: "+ str(self.account)
betbox_string = "Betbox: "+ str(self.betbox)
points_string = "points to be calculated"
for i,deck_of_cards in enumerate(self.cards):
for j,card in enumerate(deck_of_cards):
cards_string += str(self.cards[i][j]) +" "
return "\n\n"+ name_string +"\n"+ cards_string +"\n"+ account_string +"\n"+ betbox_string +"\n"+ points_string
class Dealer(Player):
def __init__(self,account,name):
Player.__init__(self, account,name)
self.stack = []
def __str__(self):
player_string = ""
name_string = "Dealer: "+ str(self.name)
cards_string = ""
account_string = "Account: "+ str(self.account)
betbox_string = "Betbox: "+ str(self.betbox)
points_string = "points to be calculated"
for i,deck_of_cards in enumerate(self.cards):
for j,card in enumerate(deck_of_cards):
cards_string += str(self.cards[i][j]) +" "
return "\n\n"+ name_string +"\n"+ cards_string +"\n"+ account_string +"\n"+ betbox_string +"\n"+ points_string
def new_stack_of_cards(self):
value=["2","3","4","5","6","7","8","9","10","Jack","Queen","King","Ace"]
color=[emoji.emojize(':heart_suit:'), emoji.emojize(':spade_suit:'), emoji.emojize(':club_suit:'), emoji.emojize(':diamond_suit:')]
i = 0
while i < 4:
for v in value:
for c in color:
self.stack.append(Card())
self.stack[-1].new(v,c)
i += 1
random.shuffle(self.stack)
def card(self):
return self.stack.pop()
class Table():
def __init__(self):
self.table = []
def initialize(self):
input_string = ""
name_strings = []
while True:
input_string = input()
if input_string == "q":
break
name_strings.append(input_string)
return name_strings
def view(self):
table = ""
for player in self.table:
table += str(player)
time.sleep(5)
clear_output()
print(table)
class Card():
def __init__(self):
self.value = "2"
self.color = emoji.emojize(':heart_suit:')
def new(self, value, color):
self.value = value
self.color = color
def __str__(self):
return str(self.color) + str(self.value)
blackjack = Table()
dealer = Dealer(1000000,"d")
dealer.new_stack_of_cards()
name_strings = blackjack.initialize()
for i,player in enumerate(name_strings):
blackjack.table.append(Player(10000,name_strings[i]))
blackjack.table.append(dealer)
for player in blackjack.table[:-1]:
player.bet(input())
for player in blackjack.table:
player.get_card(dealer.card())
blackjack.view()
for player in blackjack.table[:-1]:
player.get_card(dealer.card())
blackjack.view()
for player in blackjack.table:
player.points()
output:
Player: 1
♥10 ♥2
Account: 9999
Betbox: 1
points to be calculated
Player: 2
♣10 ♣Jack
Account: 9998
Betbox: 2
points to be calculated
Dealer: d
♥Ace
Account: 1000000
Betbox: 0
points to be calculated
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-8-1a19c3780b6f> in <module>
25
26 for player in blackjack.table:
---> 27 player.points()
28
29
TypeError: 'int' object is not callable
In your Player class, points is an integer, and cannot be called. I see that the method points has been commented out.
for player in blackjack.table:
player.points()
From this code, it looks like you want to call the method points, but you are instead trying to call an integer stored in the points attribute.
Uncomment the method, and change the name of either the method or the attribute.

Not getting the Multithreaading to work for GTK 3 python

I am trying to get the themes from the gnome-look.org and trying to create widgets by scraping the website.
I wanted to show the window first while updating the GtkWidgets necessary in the background via another Thread.
Here is my code
[code]
#!/usr/bin/python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GdkPixbuf
import requests
import sys
import gi
import shutil
from bs4 import BeautifulSoup
import dryscrape
import json
import urllib.parse
import concurrent.futures
import threading
class ReadGnomeLook:
def format_bytes(self, size):
# 2**10 = 1024
power = 2**10
n = 0
power_labels = {0 : '', 1: 'KB', 2: 'MB', 3: 'GB'}
while size > power:
size /= power
n += 1
return str("{:.2f}".format(size)) +' ' + str(power_labels[n])
def getDownloadLinks(self, childURL):
#childURL = "https://www.gnome-look.org/s/Gnome/p/1519633"
childURL = childURL+"#files-panel"
session = dryscrape.Session()
session.set_attribute('auto_load_images', False)
session.visit(childURL)
response = session.body()
soup = BeautifulSoup(response, features='lxml')
downloadlink = []
allscripts = soup.find_all('script', {"src":False})
for each_script in range(len(allscripts)):
content = str(allscripts[each_script]).split("var")
for indx in content:
if 'filesJson' in str(indx):
content = indx.replace('filesJson = ','').replace(';','')
content = json.loads(content)
links = []
for each_item in content:
if each_item['active'] == '1':
links.append({'name':each_item['name'],'type':each_item['type'],'size':format_bytes(int(each_item['size'])),'md5sum':each_item['md5sum'],'title':each_item['title'],'description':each_item['description'],'url':urllib.parse.unquote(each_item['url'])})
for each in links:
downloadlink.append(each)
return downloadlink
def readWebpage(self, URL):
myProducts = []
baseURL="https://www.gnome-look.org"
#URL = "https://www.gnome-look.org/browse/cat/132/order/latest/"
session = dryscrape.Session()
session.set_header('Host','www.gnome-look.org')
session.visit(URL)
response = session.body()
soup = BeautifulSoup(response, features='lxml')
#print(soup)
#soup.find(class="product-browse-item-info")
mydivs = soup.find_all("div", {"class": "product-browse-item picture"})
for mydiv in mydivs:
myProducts.append([
{'name' : mydiv.div.a.findAll("div",{"class":"product-browse-item-info"})[0].h2.text},
{'category' : mydiv.div.a.findAll("div",{"class":"product-browse-item-info"})[0].findAll("span")[0].text},
{'author' : mydiv.div.a.findAll("div",{"class":"product-browse-item-info"})[0].findAll("span")[1].b.text},
{'img' : mydiv.div.a.div.img['src']},
{'href' : mydiv.div.a['href']}
])
productCatalog = []
for elements in myProducts:
productCatalog.append([
{
'Name':elements[0]['name'],
'Category': elements[1]['category'],
'Author': elements[2]['author'],
'Image': elements[3]['img'],
'Link': baseURL + elements[4]['href'],
#'DownloadLinks': getDownloadLinks(baseURL + elements[4]['href'])
}
])
return productCatalog
class AppicationWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Themes Manager")
# Main Application Window
# self.set_title("Themes Manager v1.0")
#self.set_default_size(400, 400)
self.set_position(Gtk.WindowPosition.CENTER)
self.connect("destroy",Gtk.main_quit)
# Create Image and Title Grid
#self.image = self.getImageFromWeb('https://media.wired.com/photos/592697678d4ebc5ab806acf7/master/w_2560%2Cc_limit/GooglePlay.jpg')
#self.image.set_from_file("android-download.png")
#image.set_size(200,200)
print("Before 1st Show all")
self.show_all()
z = threading.Thread(target=self.doProcessing(),daemon=True)
z.start()
print("Started Z thread")
def doProcessing(self):
# Grid for Full Icon Themes
self.gridfulliconthemes = Gtk.FlowBox(valign = Gtk.Align.START)
self.gridfulliconthemesscroll = Gtk.ScrolledWindow(hexpand=True, vexpand=True) # Create scroll window
self.gridfulliconthemesscroll.add(self.gridfulliconthemes) # Adds the TreeView to the scroll container
self.getProductCatalog()
## Start
self.URLs = []
self.labels = []
self.images = []
self.threads = []
for each_item in self.productCatalog:
image = Gtk.Image()
image.new_from_file('/tmp/82682596e6c89475b2f21221d5dc61927887.png')
self.images.append(image)
self.labels.append(Gtk.Label("loading"))
for each_item in range(0,len(self.productCatalog)):
#print(each_item[0]['Name'])
self.URLs.append(self.productCatalog[each_item][0]['Image'])
vertical_box = Gtk.Box()
vertical_box.set_homogeneous(True)
vertical_items = Gtk.FlowBox(valign = Gtk.Align.START)
vertical_items.set_max_children_per_line(1)
label = Gtk.Label()
label.set_text(self.productCatalog[each_item][0]['Name'])
label.set_line_wrap(True)
label.set_max_width_chars(10)
label.set_hexpand(True)
self.labels.append(label)
#image = Gtk.Image()
#self.images.append(image)
vertical_items.add(self.images[each_item])
vertical_items.add(self.labels[each_item])
vertical_box.add(vertical_items)
vertical_box.connect("button-press-event", self.do_anything)
self.gridfulliconthemes.add(vertical_box)
## End
# Create Notebook to add to the Window
self.notebook = Gtk.Notebook()
self.add(self.notebook)
self.fullicontheme = Gtk.Label()
self.fullicontheme.set_text("Full Icon Themes")
self.gtkthemes = Gtk.Label()
self.gtkthemes.set_text("Gtk 3/4 Themes")
self.gnomeshellthemes = Gtk.Label()
self.gnomeshellthemes.set_text("Gnome Shell Themes")
self.fulliconthemepage = Gtk.Label()
self.fulliconthemepage.set_text("Full Icon Themes Page")
self.gtkthemespage = Gtk.Label()
self.gtkthemespage.set_text("GTK themes Page")
self.gnomeshellthemespage = Gtk.Label()
self.gnomeshellthemespage.set_text("Gnome Shell Themes Page")
#notebook.append_page(fullicontheme, Gtk.Label("Icon Page"))
self.notebook.append_page(self.gridfulliconthemesscroll, self.fulliconthemepage)
self.notebook.append_page(self.gtkthemes, self.gtkthemespage)
self.notebook.append_page(self.gnomeshellthemes, self.gnomeshellthemespage)
self.notebook.set_tab_reorderable(self.gridfulliconthemesscroll, True)
#self.add(hb)
#self.show_all()
#threadtemp = threading.Thread(target=self.getImageFromWeb(each_item[0]['Image']))
#self.threads.append(threadtemp)
#self.getAllImages()
x = threading.Thread(target=self.getAllImages(),daemon=True)
x.start()
self.show_all()
def getProductCatalog(self):
# Download Links from GnomeLook.org
URL = "https://www.gnome-look.org/s/Gnome/browse/cat/132/page/2/ord/latest/"
readgnomelook = ReadGnomeLook()
self.productCatalog = readgnomelook.readWebpage(URL)
#print(json.dumps(productCatalog, sort_keys=False, indent=4))
def getAllImages(self):
for i in range(0,len(self.productCatalog)):
#self.images.append(self.getImageFromWeb(self.productCatalog[i][0]['Image']))
#self.images[i] = self.getImageFromWeb(self.productCatalog[i][0]['Image'],self.images[i])
with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
future = executor.submit(self.getImageFromWeb, self.productCatalog[i][0]['Image'], self.images[i])
# #self.images.append(future.result())
self.images[i]= future.result()
# #print(type(self.images[i]))
def do_anything(self):
print("clicked on box")
def getImageFromWeb(self, URL,image):
filename = '/tmp/'+URL.split("/")[-1]
try:
f = open(filename)
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
filename=filename,
width=100,
height=100,
preserve_aspect_ratio=False)
Gtk.Image.set_from_pixbuf(image, pixbuf)
#image.set_from_file(filename)
#print("Got the image : " + filename)
#del r
return image
except IOError:
#print("File not accessible")
r = requests.get(URL,stream=True)
if r.status_code == 200:
with open(filename,'wb') as f:
r.raw.decode_content = True
shutil.copyfileobj(r.raw, f)
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
filename=filename,
width=200,
height=200,
preserve_aspect_ratio=False)
Gtk.Image.set_from_pixbuf(image, pixbuf)
#image.set_from_file(filename)
#print("Got the image : " + filename)
return image
else:
#print("Failed to get the image : " + filename)
return None
del r
window = AppicationWindow()
#window.connect("destroy",Gtk.main_quit)
#window.show_all()
Gtk.main()
[/code]
Code works fine. But in below code, the thread doProcessing() is getting completed and then I am seeing the "Started Z thread"
print("Before 1st Show all")
self.show_all()
z = threading.Thread(target=self.doProcessing(),daemon=True)
z.start()
print("Started Z thread")
As I see, doProcessing should start in background and "Started Z thread" should be printed immediately but that's not happening.
Am I missing anything here ? Any help is appreciated.
Thanks, Debasish
z = threading.Thread(target=self.doProcessing(),daemon=True)
threading.Thread wants a function not the result of a function, thus try:
z = threading.Thread(target=self.doProcessing,daemon=True)

how to store in a list or dictionary the date from Gtk.Calendar.get_date() and a text from Gtk.TextBuffer for that date in python

I am trying to create a calendar app in python.As for now I have manage to create the Gtk.window, a Gtk.Notebook with two pages (page1 month calendar, page 2 week calendar) added to the Gtk.window.I have used Gtk.Calendar for month and from signal 'day-selected' I used a function to get_date().Also I used a Gtk.TextView with Gtk.TextBuffer to input text (as a note).
First question : how to connect the date with the input text and store it in a list or dictionary so i can save it later to a file.
Second:I have activate details with self.calendar.set_property("show-details", True) and defined a function self.calendar.set_detail_func(self.cal_entry) for details.
def cal_entry(self, calendar, year, month, date):
if self.textbuffer is not None:
self.calendar.mark_day(self.day)
How to mark the days with notes(text in Gtk.TextBuffer) because the above function does not work correctly.
Below is a snippet of the code:
class Window(Gtk.ApplicationWindow):
def __init__(self, app):
super(Window, self).__init__(title="Live Calendar", application=app)
self.set_default_size(-1, 400)
self.set_resizable(False)
self.set_border_width(10)
self.create_notebook()
self.entry()
self.refresh_icon()
def refresh_icon(self):
#refreshing the icon of the app
print(get_filename())
subject_lines = read_file(subject)
index = [i for i in range(len(subject_lines)) \
if subject_lines[i].startswith("Icon=")][0]
subject_lines[index] = "Icon=" + get_filename() + "\n"
write_file(subject, subject_lines)
self.set_icon_from_file(get_filename())
timer = threading.Timer(60, self.refresh_icon)
timer.start()
def create_notebook(self):
# Open Buttton
self.openbutton = Gtk.Button("Open")
self.openbutton.set_tooltip_text("Open Notes")
self.openbutton.connect("clicked", self.on_open_clicked)
# Save Button
self.savebutton = Gtk.Button("Save")
self.savebutton.set_tooltip_text("Save Notes")
self.savebutton.connect("clicked", self.on_save_clicked)
# Header
self.header = Gtk.HeaderBar(title="Live Calendar")
self.header.set_property("show_close_button", True)
self.header.pack_start(self.openbutton)
self.header.pack_start(self.savebutton)
self.set_titlebar(self.header)
#page1 month calendar
self.page1 = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
self.calendar = Gtk.Calendar()
self.calendar.set_property("show-week-numbers", True)
self.calendar.set_detail_height_rows(2)
self.calendar.set_detail_width_chars(2)
self.calendar.set_property("show-details", True)
self.calendar.set_detail_func(self.cal_entry)
self.__connect_signals()
self.page1.add(self.calendar)
#note taking
self.sw = Gtk.ScrolledWindow()
self.sw.set_hexpand(True)
self.sw.set_vexpand(True)
self.textview = Gtk.TextView()
self.textview.set_editable(True)
self.textview.set_wrap_mode(Gtk.WrapMode.WORD_CHAR)
self.textbuffer = self.textview.get_buffer()
self.sw.add(self.textview)
self.page1.pack_start(self.sw, True, True, 0)
#page2 week calendar
......a lot of code.......
#create notebook
self.notebook = Gtk.Notebook()
self.notebook.set_tab_pos(0)
self.notebook.append_page(self.page1, Gtk.Label('Month'))
self.notebook.append_page(self.page2, Gtk.Label('Week'))
self.add(self.notebook)
def __connect_signals(self):
self.day_selected_handle = self.calendar.connect('day-selected', self.entry)
def entry(self, *args):
self.page1.remove(self.label)
self.year, self.month, self.day = self.calendar.get_date()
self.month = self.month + 1
self.entrydate = datetime.date(self.year, self.month, self.day)
self.notedate = self.entrydate.strftime("%d/%m/%y")
self.text = self.entrydate.strftime("%d/%m/%y write your notes here...")
self.label = Gtk.Label(self.text)
self.page1.pack_start(self.label, False, False, 0)
self.show_all()
def cal_entry(self, calendar, year, month, date):
if self.textbuffer is not None:
self.calendar.mark_day(self.day)
#save into file
def on_save_clicked(self, widget):
dialog = Gtk.FileChooserDialog("Save file", self,
Gtk.FileChooserAction.SAVE,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
response = dialog.run()
if response == Gtk.ResponseType.OK:
save_file = dialog.get_filename()
start_iter = self.textbuffer.get_start_iter()
end_iter = self.textbuffer.get_end_iter()
text = self.textbuffer.get_text(start_iter, end_iter, True)
with open(save_file, 'w') as f:
f.write(text)
elif response == Gtk.ResponseType.CANCEL:
dialog.destroy()
dialog.destroy()
# open and read the file
def on_open_clicked(self, widget):
dialog = Gtk.FileChooserDialog("Please choose a file", self,
Gtk.FileChooserAction.OPEN,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
filter_text = Gtk.FileFilter()
filter_text.set_name("Text files")
filter_text.add_mime_type("text/plain")
dialog.add_filter(filter_text)
response = dialog.run()
if response == Gtk.ResponseType.OK:
selected_file = dialog.get_filename()
with open(selected_file, 'r') as f:
data = f.read()
self.textbuffer.set_text(data)
elif response == Gtk.ResponseType.CANCEL:
dialog.destroy()
dialog.destroy()
def quitApp(self, par):
app.quit()
class Application(Gtk.Application):
def __init__(self):
super(Application, self).__init__()
def do_activate(self):
self.win = Window(self)
self.win.show_all()
def do_startup(self):
Gtk.Application.do_startup(self)
app = Application()
app.run(sys.argv)
Any help will be appriciated.
Thanks in advance
For the first question: Depends, but probably a dictionary indexed by a triple for y/m/d
d = dict()
d[(2019, 10, 1)] = "your notes..."
Second question: The way details work is that cal_entry(self, calendar, year, month, day) must return a string to be displayed below the day, in the calendar. So you have to get the text from the dictionary above. You can do that with:
def cal_entry(self, calendar, year, month, day):
self.calendar.mark_day(day)
return dict.get((year, month, day))
Maybe this sample code can help:
#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class NotePopover(Gtk.Popover):
def __init__(self, app):
Gtk.Popover.__init__(self)
self.set_size_request(200, 300)
grid = Gtk.Grid()
grid.set_orientation(Gtk.Orientation.VERTICAL)
scrolled_window = Gtk.ScrolledWindow()
self.text_view = Gtk.TextView()
scrolled_window.add(self.text_view)
grid.add(scrolled_window)
button = Gtk.Button(label='Add')
grid.add(button)
grid.show_all()
self.add(grid)
scrolled_window.set_vexpand(True)
scrolled_window.set_hexpand(True)
button.connect('clicked', self.on_button_clicked)
self.app = app
def do_popup(self):
self.popup()
def on_button_clicked(self, widget):
year = app.win.calendar.get_property('year')
month = app.win.calendar.get_property('month')
day = app.win.calendar.get_property('day')
start_iter = self.text_view.get_buffer().get_start_iter()
end_iter = self.text_view.get_buffer().get_end_iter()
app.notes_dict[(year, month, day)] = self.text_view.get_buffer().get_text(start_iter, end_iter, True)
app.win.do_update()
self.text_view.get_buffer().set_text("")
self.popdown()
class Window(Gtk.Window):
def __init__(self, app):
Gtk.Window.__init__(self)
self.set_title('Test GtkCalendar')
self.set_default_size(400, 300)
header_bar = Gtk.HeaderBar()
header_bar.set_show_close_button(True)
self.set_titlebar(header_bar)
button = Gtk.Button(label="Add note")
button.get_style_context().add_class('suggested-action')
button.connect('clicked', self.on_button_clicked)
header_bar.pack_start(button)
grid = Gtk.Grid()
grid.set_orientation(Gtk.Orientation.VERTICAL)
self.calendar = Gtk.Calendar()
scrolled_window = Gtk.ScrolledWindow()
self.text_view = Gtk.TextView()
self.add(grid)
grid.add(self.calendar)
grid.add(scrolled_window)
scrolled_window.add(self.text_view)
self.calendar.set_hexpand(True)
self.calendar.set_halign(Gtk.Align.CENTER)
scrolled_window.set_vexpand(True)
scrolled_window.set_hexpand(True)
self.popover = NotePopover(app)
self.popover.set_relative_to(button)
self.connect('destroy', Gtk.main_quit)
self.calendar.connect('day-selected', self.calendar_changed)
self.calendar.connect('month-changed', self.calendar_changed)
self.show_all()
self.app = app
def on_button_clicked(self, widget):
self.popover.do_popup()
def calendar_changed(self, widget):
self.do_update()
def do_update(self):
year = app.win.calendar.get_property('year')
month = app.win.calendar.get_property('month')
day = app.win.calendar.get_property('day')
text = app.notes_dict.get((year, month, day))
if text is not None:
self.text_view.get_buffer().set_text(text)
else:
self.text_view.get_buffer().set_text("")
class Application:
def __init__(self):
self.notes_dict = dict()
self.win = Window(self)
if __name__ == '__main__':
app = Application()
Gtk.main()

How to use QThread in both gui and non-gui application in Python?

I am writing a fuzzy search application which finds words in text even if words have mistakes. I wrote gui form but it freezed because of heavy calculation. So I created class inherited from QThread and emitted signals from it to gui so that progress bar started to work and gui form wasn't freezed anymore. BUT I should also create console version of this application where I don't need gui form but I need methods that written in class inherited from QThread. But it's impossible without using PyQT library which strange to use in console version. So I don't know how to solve this problem. My teacher recommended to use threading but I didn't find how to emit signals from Thread class as I colud do in QThread.
That's a QThread class
import text_methods
from PyQt5.QtCore import pyqtSignal, QThread
class FuzzySearch(QThread):
sig_words_count = pyqtSignal(int)
sig_step = pyqtSignal(int)
sig_done = pyqtSignal(bool)
sig_insertions = pyqtSignal(str)
sig_insertions_indexes = pyqtSignal(list)
def __init__(self, text, words, case_sensitive):
super().__init__()
self.text = text
self.words = words
self.case_sensitive = case_sensitive
self.insertions_indexes = {}
self.text_dict = {}
def run(self):
self.get_insertions_info(self.text, self.words)
def find_insertions_of_word(self, word, word_number):
word_insertions = {}
for textword in self.text_dict.keys():
if text_methods.is_optimal_distance(word, textword):
word_insertions[textword] = self.text_dict[textword]
for index in self.text_dict[textword]:
self.insertions_indexes[index] = index + len(textword)
self.sig_step.emit(word_number)
return word_insertions
'''Get information about insertions of words in the text'''
def find_insertions(self, text, words):
word_number = 1
insertions = {}
self.text_dict = text_methods.transform_text_to_dict(text, self.case_sensitive)
words_list = text_methods.transform_words_to_list(words, self.case_sensitive)
self.sig_words_count.emit(len(words_list))
for word in words_list:
print(word_number)
insertions[word] = self.find_insertions_of_word(word, word_number)
word_number += 1
self.insertions_indexes = sorted(self.insertions_indexes.items())
return insertions
'''Get information about insertions of words in the text in special format'''
def get_insertions_info(self, text, words):
insertions = self.find_insertions(text, words)
insertions_info = ''
for word in insertions.keys():
insertions_info += 'Вы искали слово "' + word + '"\n'
if len(insertions[word]) == 0:
insertions_info += ' По этому запросу не было найдено слов\n'
else:
insertions_info += ' По этому запросу были найдены слова:\n'
for textword in insertions[word].keys():
insertions_info += ' "' + textword + '" на позициях: '
insertions_info += ", ".join([str(i) for i in insertions[word][textword]])
insertions_info += '\n'
self.sig_done.emit(True)
self.sig_insertions.emit(insertions_info)
self.sig_insertions_indexes.emit(self.insertions_indexes)
self.quit()
As you see there are a lot of emitted signals that I transfer to gui module where they connect to slots in class FindButton in method find_insertions:
from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QApplication, QWidget,\
QLabel, QPushButton, QTextEdit, QFileDialog,\
QMessageBox, QProgressBar, QCheckBox
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
from fuzzysearch import FuzzySearch
import sys
class OpenButton(QPushButton):
def __init__(self, name, font, textedit):
super().__init__(name, font=font)
self.textedit = textedit
self.clicked.connect(self.open_dialog)
def open_dialog(self):
fname = QFileDialog.getOpenFileName(self, 'Open file', '/home')
if fname[0]:
with open(fname[0], 'r') as f:
data = f.read()
self.textedit.setText(data)
class FindButton(QPushButton):
def __init__(self, name, font, text, words, result, window):
super().__init__(name, font=font)
self.window = window
self.textedit = text
self.wordsedit = words
self.resultedit = result
self.checkbox = window.case_sensitive_checkbox
self.clicked.connect(self.find_insertions)
def find_insertions(self):
text = self.textedit.toPlainText()
words = self.wordsedit.toPlainText()
if text == '':
QMessageBox.information(self, 'Нет текста',
'Текст не был введен. \nВведите текст.')
elif words == '':
QMessageBox.information(self, 'Нет слов',
'Слова не были введены. \nВведите слова через запятую.')
else:
self.setDisabled(True)
self.text_editor = TextEditor(text, self.textedit)
self.fuzzy_search = FuzzySearch(text, words, self.checkbox.checkState())
self.fuzzy_search.sig_words_count.connect(self.window.progress_bar.setMaximum)
self.fuzzy_search.sig_step.connect(self.window.progress_bar.setValue)
self.fuzzy_search.sig_done.connect(self.setEnabled)
self.fuzzy_search.sig_insertions.connect(self.resultedit.setText)
self.fuzzy_search.sig_insertions_indexes.connect(self.text_editor.mark)
self.fuzzy_search.start()
class TextEditor:
def __init__(self, text, textedit):
self.text = text
self.textedit = textedit
def mark(self, to_mark):
self.textedit.clear()
current_index = 0
for item in to_mark:
self.write_not_marked_text(self.text[current_index:item[0]])
self.write_marked_text(self.text[item[0]:item[1]])
current_index = item[1]
self.write_not_marked_text(self.text[current_index:])
def write_not_marked_text(self, text):
font = QFont("Times", 10)
font.setItalic(False)
font.setBold(False)
self.textedit.setCurrentFont(font)
self.textedit.setTextColor(Qt.black)
self.textedit.insertPlainText(text)
def write_marked_text(self, text):
font = QFont("Times", 10)
font.setItalic(True)
font.setBold(True)
self.textedit.setCurrentFont(font)
self.textedit.setTextColor(Qt.red)
self.textedit.insertPlainText(text)
class Window(QWidget):
def __init__(self, font):
super().__init__()
self.standard_font = font
self.text_edit_font = QFont("Times", 10)
text_label = QLabel("Введите или откройте текст",
font=self.standard_font)
words_label = QLabel("Введите или откройте слова (через запятую)",
font=self.standard_font)
result_label = QLabel("Результат",
font=self.standard_font)
text_edit = QTextEdit(font=self.text_edit_font)
words_edit = QTextEdit(font=self.text_edit_font)
result_edit = QTextEdit(font=self.text_edit_font)
self.case_sensitive_checkbox = QCheckBox('Учитывать регистр')
self.case_sensitive_checkbox.setFont(self.standard_font)
self.progress_bar = QProgressBar()
self.progress_bar.setValue(0)
open_btn1 = OpenButton("Открыть", self.standard_font, text_edit)
open_btn2 = OpenButton("Открыть", self.standard_font, words_edit)
find_btn = FindButton("Найти слова в тексте", self.standard_font,
text_edit, words_edit, result_edit, self)
text_label_box = QHBoxLayout()
text_label_box.addWidget(text_label, alignment=Qt.AlignLeft)
text_label_box.addWidget(open_btn1, alignment=Qt.AlignRight)
words_label_box = QHBoxLayout()
words_label_box.addWidget(words_label, alignment=Qt.AlignLeft)
words_label_box.addWidget(open_btn2, alignment=Qt.AlignRight)
words_box = QVBoxLayout()
words_box.addLayout(words_label_box)
words_box.addWidget(words_edit)
result_box = QVBoxLayout()
result_box.addWidget(result_label, alignment=Qt.AlignLeft)
result_box.addWidget(result_edit)
bottom_box = QHBoxLayout()
bottom_box.addLayout(words_box)
bottom_box.addLayout(result_box)
find_and_progress_box = QHBoxLayout()
find_and_progress_box.addWidget(find_btn, alignment=Qt.AlignLeft)
find_and_progress_box.addWidget(self.case_sensitive_checkbox)
find_and_progress_box.addWidget(self.progress_bar)
main_box = QVBoxLayout()
main_box.addLayout(text_label_box)
main_box.addWidget(text_edit)
main_box.addLayout(bottom_box)
main_box.addLayout(find_and_progress_box)
self.setLayout(main_box)
self.setGeometry(300, 300, 1100, 700)
self.setWindowTitle('Нечеткий поиск')
self.show()
def start_application():
app = QApplication(sys.argv)
w = Window(QFont("Times", 12))
sys.exit(app.exec_())
And it works perfectly. But it will not work in console version because without QEventLoop QThread will not work:
import fuzzysearch
class ConsoleVersion():
def __init__(self, text, words):
self.text = text
self.words = words
def search_words_in_text(self):
with self.text:
with self.words:
self.f = fuzzysearch.FuzzySearch(self.text.read(), self.words.read(), False)
self.f.sig_insertions.connect(self.get_insertions)
self.f.start()
def get_insertions(self, insertions):
print(insertions)
and in main file I wrote parsing arguments and choise between two versions
import argparse
import gui
import console_version
def parse_args():
parser = argparse.ArgumentParser(description='Fuzzy search in text')
parser.add_argument('-g', '--graphics', help='graphical version', action='store_true')
parser.add_argument('-c', '--console', help='console version', nargs=2, type=argparse.FileType('r'), metavar=('TEXTFILE', 'WORDSFILE'))
return parser.parse_args()
if __name__ == '__main__':
args = parse_args()
if args.graphics:
gui.start_application()
if args.console:
cv = console_version.ConsoleVersion(args.console[0], args.console[1])
cv.search_words_in_text()
and module text_methods:
from re import split, sub
def transform_text_to_dict(text, case_sensitive):
text_dict = {}
index = 0
if case_sensitive:
splitted_text = split("[^'а-яА-ЯA-Za-z0-9_-]", text)
else:
splitted_text = split("[^'а-яА-ЯA-Za-z0-9_-]", text.lower())
for element in splitted_text:
if element not in text_dict:
text_dict[element] = []
text_dict[element].append(index)
index += len(element) + 1
return text_dict
def transform_words_to_list(words, case_sensitive):
words = sub("^\s+|\n|\r|\s+$", '', words)
if case_sensitive:
return split(' *, *', words)
else:
return split(' *, *', words.lower())
'''Damerau-Levenstein'''
def find_distance(word1: str, word2: str):
len1, len2 = len(word1), len(word2)
if len1 > len2:
word1, word2 = word2, word1
len1, len2 = len2, len1
current_row = range(len1 + 1)
previous_row = range(len1 + 1)
pre_previous_row = range(len1 + 1)
for i in range(1, len2 + 1):
if i == 1:
previous_row, current_row = current_row, [i] + [0] * len1
else:
pre_previous_row, previous_row, current_row = previous_row, current_row, [i] + [0] * len1
for j in range(1, len1 + 1):
add = previous_row[j] + 1
delete = current_row[j - 1] + 1
change = previous_row[j - 1]
if word1[j - 1] != word2[i - 1]:
change += 1
if word1[j - 1] == word2[i - 2] and word1[j - 2] == word2[i - 1]:
transpose = pre_previous_row[j - 2] + 1
current_row[j] = min(add, delete, change, transpose)
else:
current_row[j] = min(add, delete, change)
return current_row[len1]
def is_optimal_distance(word1 : str, word2 : str):
distance = find_distance(word1, word2)
l = min(len(word1), len(word2))
return distance <= l // 4
so what can you advise me?
Qt so that to handle the tasks always needs a loop that is created internally for it one must construct an object of the type QCoreApplication, QGuiApplication or QApplication, this needs it for example for this case for QThread that is not a thread but a thread handler for that is monitoring the state of the thread, if you do not place the application is closed immediately since the run method is not executed in the main thread.
if args.console:
app = QCoreApplication(sys.argv)
cv = console_version.ConsoleVersion(args.console[0], args.console[1])
cv.search_words_in_text()
sys.exit(app.exec_())

Resources