How to control fileviewer.py tkinter application from within another python program

128 views
Skip to first unread message

Mohan R

unread,
Nov 1, 2012, 2:50:24 PM11/1/12
to robotframe...@googlegroups.com
Hi, 

I recently discovered fileviewer.py and I love it. I have been searching for a tail -f equivalent in windows .. and more importantly I was searching for something that I could include with my test repository and launch as part of the test runs. As I have some rudimentary screen capture setup to run with the test runs, this will be great to debug test failures .. as I cannot only see what selenium is doing in the browser but also watch the corresponding debug.log messages to see what keywords are being executed etc.

I did the following in my test runner script:
 
...
from robot import fileviewer
test_proc = Process(target=robot.run, ...)
test_proc.start()
debug_log_viewer = fileviewer.FileViewer(os.path.abspath(os.path.join(output_dir, 'debug.log')))
debug_log_viewer.mainloop()
test_proc.join()
debug_log_viewer._root.quit()
debug_log_viewer._root.destroy()

Things work mostly as expected. The fileviewer is launched with real time updates to debug.log and I have the browser running the tests by the side. 
The problem is after the test execution is complete, I am not able to get back control to my code. 
It seems like debug_log_viewer.mainloop() keeps on executing. When I manually click Quit on the fileviewer GUI, then the control comes back to my script.

I would like to automate this last step of quitting the fileviewer application so that I can have this as part of my Continuous integration process. 
Can someone help me please.

I tried starting the fileviewer in a separate process. But seems like Tkinter apps have a problem of playing nicely with multi processes. I started in a thread, but I don't think I can .terminate() a thread like I can do a process.

I would like to do this programmatically and not have another application (Sikuli ..etc) clicking the GUI quit as a solution.


Thank you,

Mohan Raj Rajamanickam

unread,
Nov 2, 2012, 9:34:28 AM11/2/12
to robotframe...@googlegroups.com
I guess that if I reimplemented fileviewer.py to be a thread (subclass from thread) and had a queue to pass messages (in this case the quit signal) - ref http://effbot.org/zone/tkinter-threads.htm -  it might work - but before I try this, does anyone has experience doing something similar? Is there a good chance that this will work?

--
You received this message because you are subscribed to the Google Groups "robotframework-users" group.
To view this discussion on the web visit https://groups.google.com/d/msg/robotframework-users/-/jyByi_Hx3yYJ.
To post to this group, send email to robotframe...@googlegroups.com.
To unsubscribe from this group, send email to robotframework-u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/robotframework-users?hl=en.



--
Mohan Raj

Kevin O.

unread,
Nov 2, 2012, 3:22:24 PM11/2/12
to robotframe...@googlegroups.com
From what I understand you can't kill a thread in Python like you can in other language (not that that is a good idea anyways). Why not use subprocess to run fileviewer in a different process?  You could use kill() then.

Another approach is to use a listener. We wrote a simple listener for robot that logs to the console.  The console output in a web browser for Jenkins works just like a tail -f.  The logs of course take up more space and it may be more difficult to know what test is running if there is a lot of output.

FYI a more general solution to the missing tail on Windows is to install Cygwin.  Then you get a bunch of handy tools.

Kevin

Mohan Raj Rajamanickam

unread,
Nov 5, 2012, 11:33:43 AM11/5/12
to korm...@gmail.com, robotframe...@googlegroups.com
I tried using subprocess (that was my first choice) .. but tkinter errored. Turns out that Tkinter doesn't play nicely with multi-threading, processing. 

All I need basically now is a way to trigger 'quit' programmatically. I am going to try messaging using Queue or some other similar form of communication. 

Regarding the logs I have a couple of questions, why does the html of the entire page we are testing gets dumped into it from time to time - This makes it very hard to follow what is going on.. I tried disabling screen shots thinking that could be the problem - but it didn't help. How can I disable the html being dumped.

Another question - is there any way we can have time stamped messages in the log - like in the default log.html.


--
You received this message because you are subscribed to the Google Groups "robotframework-users" group.

To post to this group, send email to robotframe...@googlegroups.com.
To unsubscribe from this group, send email to robotframework-u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/robotframework-users?hl=en.



--
Mohan Raj

Mohan R

unread,
Nov 8, 2012, 11:21:48 AM11/8/12
to robotframe...@googlegroups.com, korm...@gmail.com
Here is how I have solved the problem:

changes to fileviewer.py:

from threading import Event
class FileViewer:
    def __init__(self, path=None):
        ....
        self.quit_event = Event()   # instantiating a thread event object to receive quit signals - before calling _update()
        self._update()

    def quit_application(self):
        self.quit_event.set() 

    def _update(self):
        if self.quit_event.is_set():
            self._root.quit()    # might be redundant 
            self._root.destroy()
            return    # without this return we get tkinter errors - I guess it continues to process updates even after destroy()
        .......  # rest of _update()  follows


And here is how I launch the fileviewer along with robot.run() using threads and send a quit event from the robot thread to the file viewer thread after test execution is complete:

from threading import Thread
import robot
from robot.fileviewer import FileViewer

def run_tests(robot_instance, options, debug_log_viewer, test_status):
    ''' Run tests using the given robot instance and send a quit signal to the debug log file viewer. '''
    test_status.append(robot_instance.run(r'.', # find tests in current directory
                                          **options))
    debug_log_viewer.quit_application()  # since test execution is done, set quit event so that the debug log viewer application can quit


if __name__ == '__main__':
                ..... 
                                        test_status = [] 
                kwargs={'debugfile' : 'debug.log',
                        'outputdir' : output_dir,
                 .....
                       }
                debug_log_viewer = FileViewer(path=os.path.abspath(os.path.join(output_dir, 'debug.log')))
                debug_log_viewer_proc = Thread(target=debug_log_viewer.mainloop)
                test_proc = Thread(target=run_tests, args=(robot, kwargs, debug_log_viewer, test_status))
                test_proc.start()
                debug_log_viewer_proc.start()
                test_proc.join()
                debug_log_viewer_proc.join()
                return all(test_status)


I had to move away from using multiprocessing.Process() to multithreading.Thread() to execute robot.run() because Tkinter doesn't mix well with multiprocessing (I got errors while multiprocessing was trying to pickle objects). 

Are you guys interested in this patch to fileviewer.py? With this patch, the fileviewer.py can still work as before as a standalone app, but additionally can be controlled from another program. 
Reply all
Reply to author
Forward
0 new messages