ARTICLE

Download Files Async With Gio And Python

by | Mon 15 Mar 2010

Recently I [asked for some help on how to download a file without blocking the GUI](https://archivedblog.jonobacon.com/2010/03/15/downloading-large-files-async-with-gio/). Thanks to everyone who contributed their expertise in the post comments: I now have my program working great.

I wanted to now share my conclusions so that others can benefit from them too. To do this I am going to first explain how this works, and secondly I have created a Python Snippet and added it to the [Python Snippets library](https://wiki.ubuntu.com/PythonSnippets) so there is a great working example you folks can play with. You can use Acire to load the snippet and play with it. This is the first `gio` snippet, and I hope there will be many more. 🙂

The goal I set out with was to download a file without freezing the GUI. This was somewhat inspired from [a recent Shot Of Jaq](https://shotofjaq.org/2010/03/going-async/) shot that we did on async programming, and I used this app as a good example to play with. Typically I had downloaded files the manual way and this had blocked my GUI hard, but I was aware that this is exactly what `gio`, part of the GNOME platform is here to solve.

The way async basically works is that you kick off an operation and then you wait for confirmation of the result before you proceed. It is the opposite of procedural programming: you don’t kick off an operation and in the next line process it. When you do things the async way, you start an operation and then tell it what callback should be called when it is complete. It feels very event-driven: kind of how you connect a handler to a signal in a widget so that when that signal is generated, the handler is called.

When I started playing with this the docs insinuated that `read_async()` and `read_finish()` were what I needed to use. I started off with code that looked a little like this:

def download_latest_shot(self):
audiourl = “https://….the url to the Ogg file….”

self.shot_stream = gio.File(audiourl)
self.shot_stream.read_async(self.download_latest_shot_complete)

It then calls this callback:

def download_latest_shot_complete(self, gdaemonfile, result):
f = self.shot_stream.read_finish(result).read()

outputfile = open(“/home/jono/Desktop/shot.ogg”,”w”)
outputfile.writelines(f)

After some helpful notes from the GNOME community, it turned out that what I really needed to use was `load_contents_async()` to download the full content of the file (`read_async()` merely kicks off a read operation) and `load_contents_finish()` as the callback that is called when it is complete. This worked great for me.

As such, here is the snippet which I have added to the [Python Snippets library](https://wiki.ubuntu.com/PythonSnippets) which downloads the Ubuntu HTML index page, shows it in a GUI without blocking it and writes it to the disk:

#!/usr/bin/env python
#
# [SNIPPET_NAME: Download a file asynchronously]
# [SNIPPET_CATEGORIES: GIO]
# [SNIPPET_DESCRIPTION: Download a file async (useful for not blocking the GUI)]
# [SNIPPET_AUTHOR: Jono Bacon ]
# [SNIPPET_LICENSE: GPL]

import gio, gtk, os

# Downloading a file in an async way is a great way of not blocking a GUI. This snippet will show a simple GUI and
# download the main HTML file from ubuntu.com without blocking the GUI. You will see the dialog appear with no content
# and when the content has downloaded, the GUI will be refreshed. This snippet also writes the content to the home
# directory as pythonsnippetexample-ubuntuwebsite.html.

# To download in an async way you kick off the download and when it is complete, another callback is called to process
# it (namely, display it in the window and write it to the disk). This separation means you can download large files and
# not block the GUI if needed.

class Example(object):
def download_file(self, data, url):
“””Download the file using gio”””

# create a gio stream and download the URL passed to the method
self.stream = gio.File(url)

# there are two methods of downloading content: load_contents_async and read_async. Here we use load_contents_async as it
# downloads the full contents of the file, which is what we want. We pass it a method to be called when the download has
# complete: in this case, self.download_file_complete
self.stream.load_contents_async(self.download_file_complete)

def download_file_complete(self, gdaemonfile, result):
“””Method called after the file has downloaded”””

# the result from the download is actually a tuple with three elements. The first element is the actual content
# so let’s grab that
content = self.stream.load_contents_finish(result)[0]

# update the label with the content
label.set_text(content)

# let’s now save the content to the user’s home directory
outputfile = open(os.path.expanduser(‘~’) + “/pythonsnippetexample-ubuntuwebsite.html”,”w”)
outputfile.write(content)

ex = Example()

dial = gtk.Dialog()
label = gtk.Label()
dial.action_area.pack_start(label)
label.show_all()
label.connect(‘realize’, ex.download_file, “https://www.ubuntu.com”)
dial.run()

I am still pretty new to this, and I am sure there is plenty that can be improved in the snippet, so feel free [submit a merge request](https://wiki.ubuntu.com/PythonSnippets) if you would like to improve it. Hope this helps!

An invitation-only accelerator that develops industry-leading community engagement and growth via personalized training, coaching, and accountability...all tailored to your company's needs.

Want to read some more?

Happy Holidays

Happy Holidays

Just a quick note to wish all of you a happy, restful, and peaceful holidays, however and whoever you spend it with. Take care, folks, and I look forward to seeing you in 2015!

The Impact of One Person

The Impact of One Person

I am 35 years old and *people* never cease to surprise me. My trip home from Los Angeles today was a good example of this. It was a tortuous affair that should have been a quick hop from LA to Oakland, popping on BArt, and then getting home for a cup of tea and an...

Feedback Requested: Great Examples of Community

Feedback Requested: Great Examples of Community

Folks, I need to ask for some help. Like many, I have some go-to examples of great communities. This includes Wikipedia, OpenStreetmap, Ubuntu, Debian, Linux, and others. Many of these are software related, many of them are Open Source. I would like to ask your...

Ubuntu Governance Reboot: Five Proposals

Ubuntu Governance Reboot: Five Proposals

Sorry, this is *long*, but hang in there. A little while back I wrote [a blog post](https://archivedblog.jonobacon.com/2014/11/14/ubuntu-governance-reboot/) that seemed to inspire some people and ruffle the feathers of some others. It was designed as a...

Ubuntu Governance: Reboot?

Ubuntu Governance: Reboot?

For many years Ubuntu has had a comprehensive governance structure. At the top of the tree are the Community Council (community policy) and the Technical Board (technical policy). Below those boards are sub-councils such as the IRC, Forum, and LoCo councils, and...

Dealing With Disrespect: The Video

Dealing With Disrespect: The Video

A while back I wrote and released a free e-book called [Dealing With Disrespect](https://www.dealingwithdisrespect.com/). It is a book that provides a short, simple to read, free guide for handling personalized, mean-spirited, disrespectful, and in some cases,...