PyQt5 is QTimer running in separate thread and is it blocking? - pyqt5

I'm having an app which uses a database. I want to set a timer to launch a function which will modify the db periodically. But I want to be sure that it is blocking, so no read-write operations with db until this function would finish.
My QTimer is in the GUI thread, so as far as I understand, it's slot will block main thread. Am I right?
class AppLauncher(QtWidgets.QMainWindow, AppWindow.Ui_MainWindow):
def __init__(self, parent=None):
super(AppLauncher, self).__init__(parent)
self.setupUi(self)
flags = QtCore.Qt.WindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint)
self.setWindowFlags(flags)
self.setWindowState(QtCore.Qt.WindowFullScreen)
self.fooTimer = QTimer(self)
self.fooTimer.timeout.connect(self.foo)
def foo(self):
pass
def main():
app = QApplication(sys.argv)
form = AppLauncher()
form.show()
app.exec_()
if __name__ == '__main__':
main()

QTimer is always running in the thread it was created and started, but that doesn't matter, as it wouldn't change the resulting behavior of the timeout connected functions even if it was executed in another thread.
What always matters is the thread in which the slot/function is, and as long as foo is a member of an instance that is in the same thread of any other function you want to "block", it will work as expected, preventing execution of anything else until it returns.

Related

How can I run two threads in python using their own commands in a Telegram bot

I want to run two threads in python using their own commands from a Telegram bot. How do I do that exactly?
I am using telegram.ext module
Here is a working example which is self explanatory. I wrote two command functions. each function has a thread function defined inside it. Then I created a thread object with arguments passed. finally started the threads.
import time
from telegram.ext import *
import threading
BOT_TOKEN = '***INSERT YOUR BOT ID HERE***.'
def start(update: Updater, context: CallbackContext):
update.message.reply_text('Start command going to start the thread 1 now')
def thread1(update: Updater, context: CallbackContext):
while True:
update.message.reply_text('I am from thread 1. going to sleep now.')
time.sleep(2)
t1 = threading.Thread(target=thread1,args=(update,context))
t1.start()
def run(update: Updater, context: CallbackContext):
update.message.reply_text('run command is going to start the thread 2 now')
def thread2(update: Updater, context: CallbackContext):
while True:
update.message.reply_text('I am from thread 2. going to sleep now')
time.sleep(5)
t2 = threading.Thread(target=thread2,args=(update,context))
t2.start()
def main() -> None:
print('bot started..')
updater = Updater(BOT_TOKEN)
dispatcher = updater.dispatcher
dispatcher.add_handler(CommandHandler('start', start))
dispatcher.add_handler(CommandHandler('run', run))
updater.start_polling()
updater.idle()
if __name__ == '__main__':
main()

How to create this coroutines in kotlin?

I am trying to print Hello in between World 4 from this code.
import kotlinx.coroutines.*
import java.util.*
fun main() = runBlocking <Unit> {
launch { //COR-1
var now = Date().time
val c= timeConusmingFunct(now) //may be some IO work
print(" World $c") //once done lets process it
}
launch{ //COR-2
print(" in between")
}
print("Hello ")
}
suspend fun timeConusmingFunct(now: Long): Int{
while(Date().time-now <4000){
//a way to block the thread
}
return 4
}
My understanding is that when main thread execute it will face COR-1 and move onto next COR-2 and then move to final print("Hello"). As COR-1 will take some time (~4s) and the time consuming funct is marked suspend [which indicates that it will take some time].
The call should have gone to COR-2.
However it prints : Hello World 4 in between
Why this happens, and how do I make my code work as intended Hello in between World 4 with help of coroutine ?
You need this minimal change to your spin-waiting loop:
while (Date().time - now < 4000) {
yield()
}
The concurrency in coroutines is cooperative, suspension happens when the code explicitly asks for it. Normally it happens transparently because you call a suspendable function, but in your case you must add it in since you aren't otherwise calling any suspendable functions.
what if I had some Image processing in that timeConsumingcode to do. It will block the main thread. I want it to be handled by co routine.
Image processing is a CPU-bound task and, since it's not a task that must be pinned to the GUI thread, you are better off handing it over to a thread pool. The most convenient way to do it is to write
withContext(Dispatchers.Default) {
processImage(img)
}
This way your coroutine, that otherwise runs on the main GUI thread, will temporarily jump over to the thread pool to do the long task, and then move back to the GUI thread to go on. While it's running on the thread pool, the GUI thread will be able to serve other GUI events and keep your UI live.

Combining trio and flask

I'm trying to make an HTTP API that can create and destroy concurrent tasks that open TCP connections to remote servers streaming ~15-second data. I'll have to figure out how to handle the data later. For now I just print it.
In the example below, I can create multiple TCP connections by navigating to http://192.168.1.1:5000/addconnection.
Questions:
1) Is this approach reasonable? I think Flask may be creating a new thread for each /addconnection request. I'm not sure what performance limits I'll hit doing that.
2) Is it possible to keep track of each connection? I'd like to implement /listconnections and /removeconnections.
3) Is there a more Pythonic way to do this? I've read a little about Celery, but I don't really understand it very well yet. Perhaps there are other already existing tools for handling similar problems.
import trio
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
#app.route("/addconnection")
def addconnection():
async def receiver(client_stream):
print("Receiver: started!")
while True:
data = await client_stream.receive_some(16800)
print("Received Data: {}".format(data))
async def parent():
async with trio.open_nursery() as nursery:
client_stream = await trio.open_tcp_stream('192.168.1.1', 1234)
nursery.start_soon(receiver, client_stream)
trio.run(parent)
1) You will create a new event loop for each /addconnection request which will block the Flask runtime. This will likely limit you to a single request per thread.
2) Yes, in the simplest case you can store them in a global set, see connections below.
3) I'm the author of Quart-Trio, which I think is a better way. Quart is the Flask API re-implemented with async/await (which solves most of 1)). Quart-Trio is an extension to use Trio rather than asyncio for Quart.
Roughly (and I've not tested this) your code becomes,
import trio
from quart_trio import QuartTrio
connections = set()
app = QuartTrio(__name__)
#app.route("/")
async def hello():
return "Hello World!"
#app.route("/addconnection")
async def addconnection():
async def receiver(client_stream):
print("Receiver: started!")
while True:
data = await client_stream.receive_some(16800)
print("Received Data: {}".format(data))
async def parent():
async with trio.open_nursery() as nursery:
client_stream = await trio.open_tcp_stream('192.168.1.1', 1234)
connections.add(client_stream)
nursery.start_soon(receiver, client_stream)
connections.remove(client_stream)
app.nursery.start_soon(parent)
return "Connection Created"
if __name__ == "__main__":
# Allows this to run and serve via python script.py
# For production use `hypercorn -k trio script:app`
app.run()
Where you have async def receiver(client_stream): I would put an await await trio.sleep(0.029) between each loop iteration to give the rest of the program a chance to run. You can increase the sleep time according to how busy you want the function to be. But if you execute that loop your app is likely to freeze. Also cancellation blocks should be used so you are not stuck reading data forever.

How to make python apscheduler trigger a function inside a class instance

I have a class which has BaseScheduler as an attribute, nothing fancy, no frameworks etc.
class MyClass(object):
def __init__(self, ...):
...
self.Scheduler = BackgroundScheduler()
...
Later on I define methods that a) schedule jobs based on a schedule definition passed as kwargs, and b) handle the jobs when they are triggered:
def _schedule_Events(self, *args, **kwargs):
try:
Schedule_Def = kwargs.copy()
Schedule_Def['func'] = self._handle_scheduled_Event
job = self.Scheduler.add_job(**Schedule_Def)
self.Scheduled_Events.append(job)
except Exception as e:
self.Logger.exception('%s: exception in schedule_Events, details: %s' %(self.Name, e))
def _handle_scheduled_Event(self, Event_Action):
""" Callback function for scheduled jobs """
try:
.... do stuff ....
However, adding jobs with _schedule_Events fails with:
File "/usr/local/lib/python3.4/dist-packages/apscheduler/util.py", line 381, in check_callable_args
', '.join(unsatisfied_args))
ValueError: The following arguments have not been supplied: Event_Action
The reason is apparently that the 'func' argument must be globally callable, ie. not within a class instance scope. I also don't see how using a 'textual reference' as described in the documentation will help.
If I replace the 'func' callable with a function defined at the module level then it works, but I need to make it call a method within my instance object. Any ideas how to make this work ? Custom trigger ? Wrapping APS Scheduler inside another class and pass the callback ? Other ideas ?
Many thanks in advance.

QtWebKit QApplication call twice

I am calling a scraping class from Flask and the second time I instantiate a new Webkit() class (QApplication), it exits my Flask app.
How can I re-run a Qt GUI app multiple times and have it contained so it does not shut down the "outer" app?
Further clarification, Qt is event drive and calling QApplication.quit() closes not only the event loop but Python as well. Not calling quit() though never continues executing the rest of the code.
class Webkit():
...
def __run(self, url, method, dict=None):
self.qapp = QApplication(sys.argv) # FAIL here the 2nd time round
req = QNetworkRequest()
req.setUrl(QUrl(url))
self.qweb = QWebView()
self.qweb.setPage(self.Page())
self.qweb.loadFinished.connect(self.finished_loading)
self.qweb.load(req)
self.qapp.exec_()
def finished_loading(self):
self.qapp.quit()
The only (hacky!) solution so far is for me is to add this to the WebKit() class:
if __name__ == '__main__':
....
and then parse the result from the Flask app with this:
return os.popen('python webkit.py').read()