Anteara
Anteara

Reputation: 759

How to kill a requests Request object that is in progress

Edit: The main part of this question before this revision/update was how to terminate a QThread. That has been solved, the question is being revised to How to kill a requests rest object that is in progress.

http://docs.python-requests.org/en/v0.10.4/user/advanced/#asynchronous-requests It appears using an Asynchronous Request still blocks - the user can't cancel the post while its in progress.

Basically this is the functionality that is needed: When the user presses Stop Uploading, the uploading must stop instantly, I can stop the thread using stop() however it is only checked if it should stop once the loop has looped over again.

So basically, it should be possible to use an asynchronous request that would let me check if it should be cancelled during the request, however, I don't know how.

Any suggestions? The previous part of the post is still relevant so it's below.
Please note that the initial question of how to terminate a QThread has been solved, and as such the code below isn't too important, it's just for context, the thing I need help with now is what I just described.




I've been writing a program, it's a photo uploader, I've made a thread in which I upload the files. I can't figure out how to exit the thread. I've tried suggestions i've read from here:

1) I've tried a bool flag, wrapping it both around the method and the for statement that does the work.

2) I've use a 'with' and then tried to set an exception.

I want to be able to cancel uploading, preferably quickly. I've read a lot that it's always recommended to "clean up" the thread before terminating it, I honestly don't know what 'clean it up' means. But, I think I should be able to just kill the thread - since all it's doing is sending the binary data of an image to the TUMBLR api. It shouldn't matter if the request is cancelled early, because It will just cancel the upload in the api too.

Anyway, here is my thread:

class WorkThread(QtCore.QThread):
    def __init__(self):
        QtCore.QThread.__init__(self)
        global w
        w = WorkThread
    def __del__(slf):
        self.wait()        
    def run(self):
        url = 'https://www.tumblr.com/api/write'
        files = os.listdir(directory)
        for file in files:
            file_path = os.path.join(directory + '\\' + file)
            file_path = str(file_path)
            if file_path[-3:] in ['bmp', 'gif', 'jpg', 'png', 'thm', 'tif', 'yuv']:
                self.emit(QtCore.SIGNAL('update(QString)'), "Uploading %s ..." % file_path)
                print smart_str(password)
                data = {'email': email, 'password': password, 'type': 'photo'}
                with open(file_path, 'rb') as photo:
                    r = requests.post(url, data=data, files={'data': photo})
                print r.content
        self.emit(QtCore.SIGNAL('update(QString)'), 'All finished! Go check out your stuff on tumblr :)\n')
        return

This is how im calling it.

def upload(self):
    self.doneBox.clear()

    self.workThread = WorkThread()
    self.connect( self.workThread, QtCore.SIGNAL("update(QString)"), self.startUploading )
    self.workThread.start()

Can anyone suggest in a way that I can terminate the thread quickly and quietly? OR if you think that's not good, a way to stop it safely.

HOWEVER, If I do not kill it instantly, and it goes through the for loop again in the run() method, It will upload the photo that it was uploading WHEN the user presses "Stop Uploading". I wouldn't want it to do that, I'd prefer to have it stop uploading the current photo the second the user presses "Stop Uploading".

Thanks.

Upvotes: 5

Views: 5366

Answers (2)

jdi
jdi

Reputation: 92647

I'm not sure what you are doing with that global w; w = WorkThread but it seems pointless since you aren't doing anything with it.

In your __init__() you want a flag:

def __init__(self):
    ...
    self._isRunning = False

In your run() method you just check for this flag and exit when needed:

def run(self):
    self._isRunning = True
    while True:
        if not self._isRunning:
            # clean up or close anything here
            return
        # do rest of work

And maybe add a simple convenience method:

def stop(self):
    self._isRunning = False
    self.wait()

When documentation refers to cleaning up they are talking about closing down resources that you may have opened, undoing things that might be partially started, or anything else that you might want to signal or handle before just killing the thread object. In the case of your uploader, you want to check if the thread should exit before you start each upload process. This will give you the chance to stop the thread and have it exit before it continues with another bit of work.

Upvotes: 1

Blender
Blender

Reputation: 298532

Try terminating it:

self.workThread.terminate()

Just be careful while doing this. Since you are performing a network operation, you can't stop it, but usually you do this:

# Logic...

if self.running:
  # Continue logic...

You set self.running from outside of the thread.

Upvotes: 0

Related Questions