Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Run an async web server along with PyQt5
QtWS25 Last Chance

Run an async web server along with PyQt5

Scheduled Pinned Locked Moved Unsolved Qt for Python
8 Posts 4 Posters 3.0k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Offline
    R Offline
    rhx9
    wrote on 23 Nov 2021, 18:33 last edited by
    #1

    Hello,
    I'm trying to run an async web server like Sanic along side my PyQt5 app, but the web server api requires that i run a function .run which runs an event loop, and i'm having trouble running it along side the PyQt5 event loop:

    I tried to run it inside a Qthread but even then it makes the app freeze because the .run function never returns until the app is closed.

    My example Qthread class:

    
    class api_server(qtc.QObject):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.api = Sanic(name='test')
            self.api.add_route(self.test, "/")
    
        def run(self):
            
            self.api.run(host="0.0.0.0", port=8080)
     
        async def test(self,request):
            return json({"hello": "world"})
    

    Then in my main qtw.QMainWindow init method I'm doing the following:

    self._api_server_thread = qtc.QThread()
    self._api_server = api.api_server()
    self._api_server_thread.started.connect(self._api_server.run)
    self._api_server.moveToThread(self._api_server_thread)
    self._api_server_thread.start()
    

    Regards

    E 1 Reply Last reply 23 Nov 2021, 20:15
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote on 23 Nov 2021, 18:37 last edited by
      #2

      Hi,

      Why do you need a full blown web server as part of your GUI application ?

      That said you may have to consider using the Python subprocess module rather than multithreading.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      R 1 Reply Last reply 23 Nov 2021, 19:01
      0
      • S SGaist
        23 Nov 2021, 18:37

        Hi,

        Why do you need a full blown web server as part of your GUI application ?

        That said you may have to consider using the Python subprocess module rather than multithreading.

        R Offline
        R Offline
        rhx9
        wrote on 23 Nov 2021, 19:01 last edited by rhx9
        #3

        @SGaist said in Run an async web server along with PyQt5:

        Hi,

        Why do you need a full blown web server as part of your GUI application ?

        To provide an api for another app running on a different machine and since my gui app is already connected the sqlite database i want to run the server from the same code to keep resource usage to a minimum

        That said you may have to consider using the Python subprocess module rather than multithreading.

        That means i need to run the server from a different python file which means i can't reference the server from inside my app code.

        There was a proposed qt component a couple of years ago which would have been perfect for my use case, sadly it was never merged upstream

        Regards

        1 Reply Last reply
        0
        • S Offline
          S Offline
          SGaist
          Lifetime Qt Champion
          wrote on 23 Nov 2021, 19:12 last edited by
          #4

          That doesn't answer my question about the why.

          Understanding the why may help found how.

          From memory QHttpServer is a separate module. If you really want it in Python, you can create the necessary bindings yourself.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          R 1 Reply Last reply 23 Nov 2021, 19:18
          0
          • S SGaist
            23 Nov 2021, 19:12

            That doesn't answer my question about the why.

            Understanding the why may help found how.

            From memory QHttpServer is a separate module. If you really want it in Python, you can create the necessary bindings yourself.

            R Offline
            R Offline
            rhx9
            wrote on 23 Nov 2021, 19:18 last edited by
            #5

            @SGaist said in Run an async web server along with PyQt5:

            That doesn't answer my question about the why.

            Understanding the why may help found how.

            The gui app is connected to an SQLITE database, along side the main app function, it should also provide an api that can be called from a different machine, this api can be used to control the main app(provide records from the database, delete, insert as well as running functions that changes the Widget appearance which is why i need the server to be called from my pyqt app code

            From memory QHttpServer is a separate module. If you really want it in Python, you can create the necessary bindings yourself.

            That would be too much of a hassle and i have no prior experience in that space

            Regards

            1 Reply Last reply
            0
            • S Offline
              S Offline
              SGaist
              Lifetime Qt Champion
              wrote on 23 Nov 2021, 19:27 last edited by
              #6

              In that case, I would suggest to have these two cleanly separated and have your GUI connect to the API server as well for example through a local socket.

              They can both connect to the same database if required. Establish a protocol for whatever needs to be changed in your GUI based on what is called your API server.

              This has the added advantage that your GUI can crash without killing the server and vice-versa.

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              0
              • R rhx9
                23 Nov 2021, 18:33

                Hello,
                I'm trying to run an async web server like Sanic along side my PyQt5 app, but the web server api requires that i run a function .run which runs an event loop, and i'm having trouble running it along side the PyQt5 event loop:

                I tried to run it inside a Qthread but even then it makes the app freeze because the .run function never returns until the app is closed.

                My example Qthread class:

                
                class api_server(qtc.QObject):
                    def __init__(self, *args, **kwargs):
                        super().__init__(*args, **kwargs)
                        self.api = Sanic(name='test')
                        self.api.add_route(self.test, "/")
                
                    def run(self):
                        
                        self.api.run(host="0.0.0.0", port=8080)
                 
                    async def test(self,request):
                        return json({"hello": "world"})
                

                Then in my main qtw.QMainWindow init method I'm doing the following:

                self._api_server_thread = qtc.QThread()
                self._api_server = api.api_server()
                self._api_server_thread.started.connect(self._api_server.run)
                self._api_server.moveToThread(self._api_server_thread)
                self._api_server_thread.start()
                

                Regards

                E Offline
                E Offline
                eyllanesc
                wrote on 23 Nov 2021, 20:15 last edited by
                #7

                @rhx9 A simple solution is to use qasync:

                # https://github.com/sanic-org/sanic/blob/main/examples/run_async.py
                import asyncio
                from signal import signal, SIGINT
                import sys
                
                from sanic import Sanic
                from sanic.response import json
                
                from PyQt5.QtCore import QDateTime, Qt, QTimer
                from PyQt5.QtWidgets import QApplication, QLabel
                
                import qasync
                
                
                app = Sanic(__name__)
                
                
                @app.route("/")
                async def test(request):
                    return json({"hello": "world"})
                
                
                def main():
                    qtapp = QApplication(sys.argv)
                    loop = qasync.QEventLoop(qtapp)
                    asyncio.set_event_loop(loop)
                
                    w = QLabel(alignment=Qt.AlignmentFlag.AlignCenter)
                    w.resize(640, 480)
                    w.show()
                
                    def handle_timeout():
                        w.setText(QDateTime.currentDateTime().toString())
                
                    timer = QTimer()
                    timer.setInterval(1000)
                    timer.timeout.connect(handle_timeout)
                    timer.start()
                    handle_timeout()
                
                    server = app.create_server(host="0.0.0.0", port=8000, return_asyncio_server=True)
                    loop = asyncio.get_event_loop()
                    task = asyncio.ensure_future(server)
                    server = loop.run_until_complete(task)
                    loop.run_until_complete(server.startup())
                    signal(SIGINT, lambda s, f: loop.stop())
                
                    try:
                        loop.run_forever()
                    finally:
                        loop.stop()
                
                
                if __name__ == "__main__":
                    main()
                

                If you want me to help you develop some work then you can write to my email: e.yllanescucho@gmal.com.

                A 1 Reply Last reply 19 Dec 2022, 09:25
                2
                • E eyllanesc
                  23 Nov 2021, 20:15

                  @rhx9 A simple solution is to use qasync:

                  # https://github.com/sanic-org/sanic/blob/main/examples/run_async.py
                  import asyncio
                  from signal import signal, SIGINT
                  import sys
                  
                  from sanic import Sanic
                  from sanic.response import json
                  
                  from PyQt5.QtCore import QDateTime, Qt, QTimer
                  from PyQt5.QtWidgets import QApplication, QLabel
                  
                  import qasync
                  
                  
                  app = Sanic(__name__)
                  
                  
                  @app.route("/")
                  async def test(request):
                      return json({"hello": "world"})
                  
                  
                  def main():
                      qtapp = QApplication(sys.argv)
                      loop = qasync.QEventLoop(qtapp)
                      asyncio.set_event_loop(loop)
                  
                      w = QLabel(alignment=Qt.AlignmentFlag.AlignCenter)
                      w.resize(640, 480)
                      w.show()
                  
                      def handle_timeout():
                          w.setText(QDateTime.currentDateTime().toString())
                  
                      timer = QTimer()
                      timer.setInterval(1000)
                      timer.timeout.connect(handle_timeout)
                      timer.start()
                      handle_timeout()
                  
                      server = app.create_server(host="0.0.0.0", port=8000, return_asyncio_server=True)
                      loop = asyncio.get_event_loop()
                      task = asyncio.ensure_future(server)
                      server = loop.run_until_complete(task)
                      loop.run_until_complete(server.startup())
                      signal(SIGINT, lambda s, f: loop.stop())
                  
                      try:
                          loop.run_forever()
                      finally:
                          loop.stop()
                  
                  
                  if __name__ == "__main__":
                      main()
                  
                  A Offline
                  A Offline
                  allenZ
                  wrote on 19 Dec 2022, 09:25 last edited by
                  #8

                  @eyllanesc qasync is awesome, i use it to embed a asyncio tcp server with my qml application.
                  yet it did not support python 3.11 for right now as this issue described, does qasync has a substitude which work with python 3.11?
                  i also noticed that asyncio example is in discussion mentioned in 08. December 2022 development notes, yet i can not find any official asyncio example until now

                  1 Reply Last reply
                  0

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved