One of the greatest strengths of KDE is undoubtedly the asynchronous and network-transparent I/O access, employed by the so-called “I/O” slaves, part of the KIO class. If you are developing an application that requires file or network access, those classes make things incredibly simple to do, and they don’t freeze your GUI when you are in the middle of a process.

In this post I’ll show how to use KIO to retrieve files from network resources using PyKDE4. The whole example is also available in the kdeexamples module.

Our first step is to create a simple UI to show how KIO works. It will be a text edit along with two buttons to retrieve and clear items. Here’s how it looks in Designer (the ui file and its compiled Python version are available at the above link):

Once this is done, we turn our attention to code. We start customary imports:

#!/usr/bin/env python import sys import PyQt4.QtCore as QtCore import PyQt4.QtGui as QtGui import PyKDE4.kdecore as kdecore import PyKDE4.kdeui as kdeui from PyKDE4.kio import KIO

These will provide for everything we need. Then we set up our widget:

from ui_textbrowser import Ui_Form class TextArea ( QtGui . QWidget , Ui_Form ): """Example class used to show how KIO works.""" def __init__ ( self , parent = None ): super ( TextArea , self ) . __init__ ( parent ) self . setupUi ( self ) self . downloadButton . clicked . connect ( self . start_download ) self . clearButton . clicked . connect ( self . textWidget . clear )

Nothing strange in the initializer here. We simply make two connections, one to the clear() slot of the clear button, and the other to start the KIO process, that is the retrieval of the index from www.kde.org. Let’s take a look at the start_download slot:

def start_download ( self ): kdeui . KMessageBox . information ( self . parent (), "Now data will be retrieved from " "www.kde.org using KIO" ) # KIO wants KUrls data_url = kdecore . KUrl ( "http://www.kde.org" ) retrieve_job = KIO . storedGet ( data_url , KIO . NoReload , KIO . HideProgressInfo ) retrieve_job . result . connect ( self . handle_download )

What do we do here? We show a KMessageBox, just for informational purposes. Once this is done, we prepare the actual KIO job. KIO wants KUrls so we first of all wrap the URL we want to download from in that. Then we create the actual job: in this case it’s KIO.storedGet, that is we retrieve the data in full from our URL and store it in a QByteArray. This is a common use case, but you have to keep in mind that for large files this may be impractical. In such a case, we would be better off using KIO.get followed by a connection to the “data” signal, to get the data in chunks.

A KIO job can have many flags: here we set to remove the progress information, so that you won’t get a notification in the Plasma notifier. For small operations, this should be always present. For longer downloads, it’s likely not a good idea. More information are available in the KIO namespace page (C++ version).

As a last step, we connect the result signal (emitted when the job is complete) to a slot to handle the download. This is what makes KIO useful, because it’s asynchronous, so you can perform long downloads without blocking the user interface of your program

Lastly, we see the “handle_download” slot:

def handle_download ( self , job ): # Bail out in case of errors if job . error (): return print "This slot has been called. The job has finished its operation." data = job . data () self . textWidget . setPlainText ( QtCore . QString ( data ))

This slot’s signature include a KJob instance, that is what we’ll use to get the data. In fact, using the data() function we can obtain the QByteArray containing what we have retrieved. Then, in this case we simply use setPlainText to put the downloaded data into the text edit.

What if something goes wrong? We can check for errors if job.error() returns True: in that case we can perform recovery, or simply tell our user that something went wrong. Especially with networked resources, this should always be present in your code.

So that’s all for now. As you can see, it was pretty simple, and also very effective.