omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    UI and aiohttp

    Pythonista
    1
    2
    2194
    Loading More Posts
    • 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.
    • mikael
      mikael last edited by

      Some beta snuck in built-in support for aiohttp, which looks like an answer to my old question: how to have a UI app with background http requests, without resorting to threads?

      Below a proof of concept which:

      • Runs a counter with ui.View.update
      • Has a button you can click(!)
      • Fetches HTML content in the background
      • Closes cleanly on UI exit

      It works, but it seems a bit complex.

      Also available as a gist.

      import aiohttp, asyncio, async_timeout
      import ui
      
      class AsyncUIView(ui.View):
        def __init__(self, *args, poll_interval=0.5, **kwargs):
          super().__init__(*args, **kwargs)
          self.running = True
          self.poll_interval = poll_interval
          self.loop = asyncio.get_event_loop_policy().new_event_loop()
          self.task = None
          self._session = aiohttp.ClientSession(loop=self.loop)
          
        def start_loop(self):
          self.loop.run_until_complete(self._runner())
        
        def will_close(self):
          self.running = False
          self._session.close()
          
        async def _runner(self):
          while self.running:
            if self.task:
              task = self.task
              self.task = None
              await task()
            task = self.loop.create_task(asyncio.sleep(self.poll_interval))
            await task
            
        async def get(self, url):
          with async_timeout.timeout(10):
            async with self._session.get(url) as response:
              return await response.text()
        
      if __name__ == '__main__':
        
        class CounterButton(ui.View):
          def __init__(self, controller, webview, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.controller = controller
            self.webview = webview
            self.counter = 0
            self.btn = btn = ui.Button(flex='WH', frame=self.bounds, tint_color=(.77, .22, .03), action=self.do_fetch)
            self.add_subview(btn)
            self.update_interval = 0.5
          
          def update(self):
            self.counter += 1
            self.btn.title = f'#{self.counter} - Click me'
            
          def do_fetch(self, sender):
            self.webview.load_html('<span style="font-size: xx-large;">Loading...</span>')
            self.controller.task = self.load_the_page
            
          async def load_the_page(self):
            html = await self.controller.get('http://python.org')
            self.webview.load_html(html)
          
        v = AsyncUIView()
        v.present('full_screen')
        
        w = ui.WebView(frame=v.bounds)
        v.add_subview(w)
        
        b = CounterButton(v, w, frame=v.bounds)
        v.add_subview(b)
        
        v.start_loop()
      
      1 Reply Last reply Reply Quote 1
      • mikael
        mikael last edited by

        This version is a bit more sensible, in that it uses create_task to create any number of concurrent http or other async tasks, as demonstrated by loading two different pages in parallel.

        This still has the custom "run_forever" implementation (see below), because I could not get the regular run_forever to exit cleanly in Pythonista. Other samples work fine, but when combined with Pythonista UI, the script never exits - views close but the end script button is inactive, and script cannot be launched again without restarting Pythonista.

        async def _runner(self):
          while self.running:
            await self._loop.create_task(asyncio.sleep(0.5))
        
        1 Reply Last reply Reply Quote 0
        • First post
          Last post
        Powered by NodeBB Forums | Contributors