Reply
Thread Tools
Posts: 6 | Thanked: 4 times | Joined on Oct 2008
#1
Hi guys, I think this is my first post on internettablettalk. I hope you can help me with a development issue I'm having.

I'm developing a home applet in python for the n810, (using notepad on windows and testing on the tablet). I don't have access to a scratchbox installation.

It's a slideshow plugin that grabs a photo list (xml) from a site, and then retrieves the photos from flickr.

I managed to make everything work, but as i'm using urllib, it freezes the ui until it's done retrieving the xml and the files.

So, I'm trying to use threads instead, and that's were everything falls apart. If I call urllib.urlopen from within a thread, it just doesn't work, no error, no freezing, nothing, it just stops working. The main thread continues as normal, but the thread stops when urlopen is called.

If I call urlopen from anywhere else in the main thread, it works fine.
If I remove urlopen from the thread code, it works fine (though obviously I can't retrieve the xml, so it's useless.

If I run the plugin code from the commandline, it all works (creates the thread, receives the xml file).
If I change the code to use gtk.Window instead of hildondesktop.HomeItem, it runs fine in the tablet and in windows.

So, the thread stopping at urlopen happens only when the code runs as a normal home plugin.

Here's a simplified version of the code. The problem is at _startthread (it outputs "in thread" to a gtk label, but "done thread" never appears).

Code:
import gtk
import hildondesktop
import os
import gobject

import threading,thread

gtk.gdk.threads_init()

import urllib

FB_URL = 'http://somesite.com/getphotolist.php'

class FbSlideshow(hildondesktop.HomeItem):
	def __init__(self):
		hildondesktop.HomeItem.__init__(self)
		#here i do other things like creating the UI, adding a label, etc
		self.do_get_poto()
	def do_get_photo(self):
		self.set_label( 'start thread')
		threading.Thread(target=self._startthread).start()
	def _startthread(self):
		self.set_label('in thread')
		url = FB_URL
		f=urllib.urlopen(url)
		self.set_label('done thread')
def hd_plugin_get_objects():
		plugin=FbSlideshow()
		return [plugin]
Do you have any idea of why is this happening? Is there another method I can use to retrieve the file without freezing the ui?

I'd really appreciate your help, I spent all day yesterday trying to find a solution, but got nothing.

Last edited by azrasta; 2008-11-01 at 22:02.
 
Posts: 6 | Thanked: 4 times | Joined on Oct 2008
#2
well, i made some progress. I changed the code a bit, but still didn't work.

But I was lucky to find out something just by chance.

I think openurl never times out, that's why there's no error to report.

The other thing is that it seems that eventhough the device is connected via wifi, I think the connection goes idle.

Somehow, calling openurl in the main thread makes the connection alive again, but if it's called in a thread, it stays dead.

Now, what I found is that if I click on the wireless status icon several times, the code manages to grab the xml after a few seconds. So I'm guessing the wireless applet does something (a system call?) to check for the status or the network or something, and that makes everything else work.

I guess this has to do with dbus, but I have no idea about it, so I'll keep searching :P
 
pycage's Avatar
Posts: 3,404 | Thanked: 4,474 times | Joined on Oct 2005 @ Germany
#3
You must not access self.set_label or any other GTK stuff while running in a thread. You can surround such calls with gtk.threads_enter() and gtk.threads_leave() to use them in a thread, but have to be very very careful, because PyGTK + threads is an evil mix that deadlocks all too easily. My advice: never ever use threads in PyGTK unless absolutely necessary. Async IO via gobject means is usually the better choice with PyGTK.
 
Posts: 6 | Thanked: 4 times | Joined on Oct 2008
#4
thanks for the info pycage. Yeah, I noticed that if I removed the applet before the thread was complete, the thread stayed alive (so I was rebooting the tablet several times to clean everything).

those set_label calls are not necessary, I was using them for debugging only.

Anyway, I reflashed the tablet, just in case, and did some changes. I noticed that when cairoclock was on the desktop, my applet was more responsive, so that other applet is doing something (I think it's the call queue_draw() ). Anyway, my previous theory (wifi turning idle) seems to be incorrect, I think that actually what's going on is that the hildon desktop needs to notice some activity to stay alive. I did some test by pressing buttons like crazy, maximizing and minimizing apps, and that helped the urlopen calls to finish (of course, this is not too scientific).

Anyway, after reflashing the tablet, it looks like the applet is working better, but it takes 2 minutes to retrieve an xml and 5 small images, which only takes like 8 seconds (with my connection) if i run something similar in the commandline.

I can remove the set_label calls, but the problem still remains that urlopen seems unresponsive inside a thread.

Now, you mention async io via gobject.
I found two possible functions for that: gobject.spawn_async and gobject.io_add_watch
Were you referring to that or something else (I'm new to python and gtk, so not sure if those are the ones).
spawn_async would complicate things a bit, as it's about starting a new process/script

io_add_watch makes more sense, however, the problem is that urllib.urlopen is a synchronous call. The pygtk faq mentions that io_add_watch can obseve the urllib.urlopen return object, however, I couldn't make it work and I couldn't find any examples. As soon as I call urlopen, the ui freezes until it gets the file, so there seems no way to use it with io_add_watch unless...I combine it with a thread, which would beat the purpose of using gobject asynchronously, right?

I might be completely wrong, so please, if you know of any examples or further documentation about how I could get a file asynchronously, I'd appreciate it.
 
Posts: 605 | Thanked: 137 times | Joined on Nov 2005 @ La Rochelle, France
#5
Wouldn't GnomeVFS be the anwer to your quest ?
I think it can handle asynchronous IO.
I hope there is some python binding for GnomeVFS ...

Last edited by fredoll; 2008-11-02 at 18:50.
 

The Following 2 Users Say Thank You to fredoll For This Useful Post:
Posts: 6 | Thanked: 4 times | Joined on Oct 2008
#6
you're awesome fredoll
gnomevfs worked nicely. I'll have to cleanup everything and fix bugs, but it did its work, thanks!

I used the example here: http://cs1.mcm.edu/tutorial/doc/gnom...-gnomevfs/vfs/ (async-xfer.py ) but to use it in maemo, it is imported like this:

import gnome.gnomevfs as gnomevfs

Anyway, thanks a lot, I'll update this thread with the fixed code soon
 

The Following 3 Users Say Thank You to azrasta For This Useful Post:
Posts: 105 | Thanked: 48 times | Joined on Aug 2008
#7
azrasta, will you update your code in the first post so that it will work with GnomeVFS? I would greatly appreciate it.
 
Munk's Avatar
Posts: 229 | Thanked: 108 times | Joined on Oct 2007 @ Sacramento, California
#8
I'm brand new to Python and this is related as I can find during my searches. But, does anyone know how to make a python program automatically connect to the web or at least bring up the connection program?

In other words, my Python program could be sitting there and once an hour I want it to connect to my wifi connection or bluetooth phone to retrieve a small amount of data and then disconnect.

Any ideas?
 
Posts: 6 | Thanked: 4 times | Joined on Oct 2008
#9
MattZTexasu, I will, but right now it's a mess due to so many tests and changes I did to it, so I first have to clean it up (work is first though, so I need some time to update it :P )

Munk, I think you can use the conic module to do what you want
https://garage.maemo.org/svn/pymaemo...est_connect.py

though this thread hear says it doesn't work: http://www.gossamer-threads.com/list...velopers/42285
 

The Following User Says Thank You to azrasta For This Useful Post:
Reply


 
Forum Jump


All times are GMT. The time now is 11:56.