No, it can't be done this way, because shutil.copy
doesn't have any means of providing progress.
But you can write your own copy function (or even fork the code from shutil
--notice that it's one of the modules that includes a link to the source at the top, meaning it's meant to be as useful for sample code as for just using as-is). Your function can, e.g., take a progress callback function as an extra argument and calls it after each buffer (or each N buffers, or each N bytes, or each N seconds). Something like:
def copy(src, dst, progress):
# ...
for something:
progress(bytes_so_far, bytes_total)
# ...
progress(bytes_total, bytes_total)
Now, that callback is still going to be called in the background thread, not the main thread. With most GUI frameworks, that means it can't directly touch any GUI widgets. But most GUI frameworks have a way to post a message to the main thread's event loop from a background thread, so just make the callback do that. With Qt you do this with signals and slots, exactly the same way you do within the main thread; there's lots of great tutorials out there if you don't know how.
Alternatively, you could do it the way you suggested: have the main thread signal the background thread (e.g., by posting on a queue.Queue
or triggering an Event
or Condition
) and have your copy
function check for that signal every time through the loop and respond. But that seems both more complicated and less responsive.
One more thing: Qt has its own threading library, and you may want to use it instead of Python's native one, because you can attach a slot directly to QThread
object and make that your callback. I'm not sure, but Qt might even have its own file-copy-with-progress methods in there somewhere; they try to wrap up everything that might be at all different between platforms and vaguely related to GUIs.