Forum Archive

Console output from ui

charmaex

I wrote a script that is controlled via an ui and outputs what it does through the console.

My problem is that it doesn't output the data in realtime.
My code works like the following example.
The time.sleep(5) is just some time consuming task.
I would like to have an output like this

a
b
waiting 5 seconds
c
d

Instead the output is

a
waiting 5 seconds
b
c
d

# coding: utf-8

import ui, time, tempfile

ui_file = '[{"selected" : false,"frame" : "{{0, 0}, {240, 240}}","class" : "View","nodes" : [{"selected" : true,"frame" : "{{75, 49}, {80, 32}}","class" : "Button","nodes" : [],"attributes" : {"action" : "button","frame" : "{{80, 104}, {80, 32}}","title" : "Button","class" : "Button","uuid" : "269E121F-FCD6-478B-B6CD-2F2C2D3E2ED8","font_size" : 15,"name" : "button1"}}],"attributes" : {"enabled" : true,"background_color" : "RGBA(1.000000,1.000000,1.000000,1.000000)","tint_color" : "RGBA(0.000000,0.478000,1.000000,1.000000)","border_color" : "RGBA(0.000000,0.000000,0.000000,1.000000)","flex" : ""}}]'

def button(sender):
    print 'b'
    time.sleep(5)
    print 'c'

open('Test_abcd.pyui', 'w').write(ui_file)

print 'a'
v = ui.load_view('Test_abcd')
v.present('sheet')
v.wait_modal()
print 'd'
ccc

Try replacing time.sleep(5) with ui.delay(None, 5)... I am not sure if it will do the right thing or not.

If not, you could create a function called print_c() that does print('c') and then do ui.delay(print_c, 5).

charmaex

Thanks for your reply.

Maybe my example was a bit to simple.

time.sleep(5) is a placeholder for downloading files (which takes some time).
print c indicates, that the download is finished. So this should follow the sleep.
My problem is that the b isn't printed before the download starts.

If I only run button() everything works fine. Running button() via the ui prints b and c at the same time (after 5 secs).
I want it to print b, work, print c.

JonB

The typical way you handle long running callbacks is to use the ui.in_background decorator. Remember, a button action needs to exit wuickly, or the ui appears frozen.

However, that does not work with wait_modal -- not sure if that is a bug or a documentation quirk. Basically, wait_modal seems to use the same single background thread, so anything backgrounded gets run after the dialog is closed.

The solution is to use ui.delay to launch another function containing your slow process.

def button(sender):
   print 'b'
   def other():
        time.sleep(5) # call to some time consuming task
        print 'c'
   ui.delay(other,0.01) #easy way to launch a new thread

Another option would be to use this run_async decorator on you action, which actually runs the function a background thread, as opposed to queuing it up..

def run_async(func):
   from threading import Thread
   from functools import wraps

   @wraps(func)
   def async_func(*args, **kwargs):
      func_hl = Thread(target = func, args = args, kwargs = kwargs)
      func_hl.start()
      return func_hl

   return async_func
ccc

@JonB gave better advise than I did...

import ui
def download():
    print('download')
print('a')
ui.delay(download, 0.02)
print('b')
charmaex

Thank you all for your help.

After some fumbling around I decided to close the UI and then start the action.
This was the easiest way without having to change much code :)