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.


    Threads and ui.delay

    Pythonista
    1
    1
    993
    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

      There's some problem with the implementation of ui.delay or my understanding of it. The code below (gist here) experiments with repeated background URL requests and running a counter at the same time. Requests use concurrent.futures, and the counter ui.delay.

      1. If I run only the requests, they run fine.
      2. If I run only the ui.delayed counter, it runs fine.
      3. If I run both, Pythonista 3 crashes, often after only a few dozen iterations.
      4. If I only print the request results and do not touch the UI framework at all, it still crashes.
      5. If I replace the counter with @JonB's drop-in async function, both the requests and the counter run fine.

      While I can avoid using ui.delay in my code, I would not want to be vulnerable to third-party use. Any advice how I can make my background code more robust?

      Thanks.

      Code:

      from requests_futures.sessions import FuturesSession
      from concurrent.futures import *
      import re
      import ui
      import requests
      
      class SyncBackend (object):
        URL = 'http://tycho.usno.navy.mil/cgi-bin/timer.pl'
        RE_TIME = re.compile('<BR>(.*?)\t.*Universal Time')
        
        def __init__(self, time_callback):
          self.executor = ThreadPoolExecutor(max_workers=1)
          self.time = ''
          self.cb = time_callback
          self.running = True
          self.run_one()
          
        def run_one(self):
          self.future = self.executor.submit(self.worker)
          self.future.add_done_callback(self.callback)
          
        def worker(self):
          resp =  requests.get(self.URL)
          return self.RE_TIME.search(resp.text).group(1)
          
        def callback(self, future_state):
          try:
            self.time = future_state.result()
            self.cb(self.time)
          except Exception as e:
            print(e)
          if self.running:
            self.run_one()
          
        def cancel(self):
          self.running = False
      
      class TestView(ui.View):
        
        def __init__(self):
          self.create_layout()
          
          self.request_counter = 0
          self.sync = SyncBackend(self.callback)
          
          self.counter = 0
          ui.delay(self.increment_counter, 0.05)
          
        def increment_counter(self):
          self.counter += 1
          self.counter_label.text = str(self.counter)
      
          ui.delay(self.increment_counter, 0.05)
      
        def callback(self, new_time):
          self.request_counter += 1
          self.time_label.text = str(self.request_counter) + ' - ' + new_time
      
        def will_close(self):
          self.sync.cancel()
      
        def create_layout(self):
          self.background_color = 'white'
          self.counter_label = ui.Label()
          self.time_label = ui.Label()
          self.counter_label.width = self.time_label.width = 300
          self.counter_label.height = self.time_label.height = 200
          self.counter_label.center = (self.width * 0.5, self.height * 0.3)
          self.time_label.center = (self.width * 0.5, self.height * 0.6)
          self.counter_label.flex = self.time_label.flex = 'LRTB'
          self.counter_label.text_color = self.time_label.text_color = 'black'
          self.counter_label.text = self.time_label.text = 'Start'
          self.add_subview(self.counter_label)
          self.add_subview(self.time_label)
      
      v = TestView()
      v.present('sheet')
      
      1 Reply Last reply Reply Quote 0
      • First post
        Last post
      Powered by NodeBB Forums | Contributors