5

I have a python plugin targeting QGIS 1.8 that uses QgsNetworkAccessManager and QNetworkRequest to issue a GetCapabilities request to WMS servers.

With 1.8 everything was working fine. Now we are porting this plugin to QGIS 2.x (tested on 2.6 and 2.7 of 16/02/2015) and have found that some errors are being displayed.

As far as our python code can tell everything is working as expected, however 20 seconds after a network request is initiated a "Network request ... timed out" message is displayed in the messages log and in a banner at the top of the map pane.


I have created a minimal example that can be copy/pasted into the python console:

from datetime import datetime
from PyQt4.QtCore import SIGNAL, QUrl
from PyQt4.QtNetwork import QNetworkAccessManager, QNetworkRequest

def request_download():
    global reply
    manager = QgsNetworkAccessManager.instance()
    url = QUrl("http://www.example.net")
    request = QNetworkRequest(url)
    print "Download start time: {}".format(datetime.now())
    reply = manager.createRequest(QNetworkAccessManager.GetOperation, request)
    reply.connect(reply, SIGNAL("finished()"), handle_download)

def handle_download():
    global reply
    print "Download finish time: {}".format(datetime.now())
    print "Finished: {}".format(reply.isFinished())
    print "Bytes received: {}".format(len(reply.readAll()))

request_download()

# python console:
#   Download start time: 2015-02-23 15:24:39.887000
#   Download finish time: 2015-02-23 15:24:41.077000
#   Finished: True
#   Bytes received: 1270
# 
# message log:
#   2015-02-23T15:25:01    1    Network request http://www.example.com timed out

As this example shows the download appears to succeed:

  1. The finish() signal is emitted.
  2. The reply.isFinished() method returns True.
  3. The reply.readAll() method returns the correct data.

However the time out error message is displayed :

  1. Prominently on a yellow banner at the top of the map pane.
  2. Under the Network tab on the Log Messages panel.

How do I perform a download without triggering this error?

1
  • I approached this problem month ago... I remember there wheren't solution other than popping out the message from QgsMessageBar, because the timeout was sent from a part of the qgis.core. Now I don't remember why and in what conditions there where that message (I should re-read the qgis code). I don't know if it is changed in master. Please file a issue if it can be considered an error. Commented Feb 23, 2015 at 12:38

1 Answer 1

6

If you are fine with a solution that uses QNetworkAccessManager from Qt (instead of the manager from QGIS libs), you can do it this way:

from datetime import datetime
from PyQt4.QtCore import QUrl
from PyQt4.QtNetwork import QNetworkAccessManager, QNetworkRequest

def request_download(manager):
    url = QUrl("http://www.geotux.tuxfamily.org")
    request = QNetworkRequest(url)
    print "Download start time: {}".format(datetime.now())
    manager.get( request )

def handle_download(reply):
    print "Download finish time: {}".format(datetime.now())
    print "Finished: {}".format(reply.isFinished())
    print "Bytes received: {}".format(len(reply.readAll()))

manager = QNetworkAccessManager()
manager.finished.connect( handle_download )
request_download(manager)

As you can see, you don't need to use global variables.


BTW, I couldn't use your code from a QGIS Python console, it threw this error: RuntimeError: no access to protected functions or signals for objects not created from Python

6
  • 1
    Thanks, looks good I will try it out at work in the morning. Commented Feb 23, 2015 at 14:53
  • The RuntimeError surprises me, what OS and qgis version are you using? Commented Feb 23, 2015 at 14:58
  • Yes, first time I see it. QGIS v.2.8 on a GNU/Linux (Mint). Commented Feb 23, 2015 at 15:06
  • Thanks, that works great. One gotcha I will warn readers about is that it is important that the QNetworkAccessManager instance has a lifetime that spans the duration of the network transaction. Commented Feb 24, 2015 at 2:31
  • 1
    I don't think that's a good idea, because you're performing an asynchronous request and you must wait until you get a response. If you write some code after the call to request_download, it will be executed right away, without waiting for the response. You would need things like this rohieb.wordpress.com/2010/07/08/… if you really need the request/response to be synchronous. Commented Jun 10, 2016 at 12:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.