1

This script creates a progress bar when copying a folder. I need to figure out how to make the copyObjFile function complete before the script continues (and displays the "Done!" message). However, the "Done!" message is currently being displayed before the copy operation completes. How can I make it wait?

import sys
import os
import subprocess
from PySide2 import QtGui, QtCore, QtWidgets

class FileCopyProgress(QtWidgets.QWidget):
   def __init__(self, src=None, dest=None):
      super(FileCopyProgress, self).__init__()
      self.src = src
      self.dest = dest
      self.build_ui()

   def build_ui(self):
      hbox = QtWidgets.QVBoxLayout()
      self.pb = QtWidgets.QProgressBar()
      self.pb.setMinimum(0)
      self.pb.setMaximum(100)
      self.pb.setValue(0)

      hbox.addWidget(self.pb)
      self.setLayout(hbox)
      self.setWindowTitle('File copy')

      self.auto_start_timer = QtCore.QTimer()
      self.auto_start_timer.timeout.connect(lambda: self.copyfileobj(src=self.src, dst=self.dest, callback_progress=self.progress, callback_copydone=self.copydone))
      self.auto_start_timer.start(2000)
      self.show()

   def progress(self, curr, tot):
      percentage = int((float(curr) / float(tot)) * 100)
      self.pb.setValue(percentage)
      app = QtWidgets.QApplication.instance()
      app.processEvents()

   def copydone(self):
      self.pb.setValue(100)
      self.close()

   def copyfileobj(self, src, dst, callback_progress, callback_copydone, length=8*1024):
      numFiles_total = 0
      for root, dirs, files in os.walk(src):
         numFiles_total += len(files)
      self.auto_start_timer.stop()
      # COPY FILE
      p = subprocess.Popen(['robocopy', src, dst, '/E', '/MT:16'], shell=True, stdout=subprocess.PIPE)
      numFiles_curr = 0
      while True:
         line = p.stdout.readline()
         if not line:
            break
         myLine = line.strip()
         if '%' in myLine:
            numFiles_curr += 1
            print('Progress: ' + str(numFiles_curr) + '/' + str(numFiles_total))
            callback_progress(curr=numFiles_curr, tot=numFiles_total)
         sys.stdout.flush()
      callback_copydone()

class Window(QtWidgets.QDialog):
   def __init__(self):
      super(Window, self).__init__()
      self.initUI()

   def initUI(self):
      vlayout_base = QtWidgets.QVBoxLayout()
      self.setLayout(vlayout_base)
      button = QtWidgets.QPushButton('Copy File')
      button.clicked.connect(self.doStuff)
      vlayout_base.addWidget(button)

   def doStuff(self):
      self.copyFile()
      self.messageDialog('Done!', 'message')

   def copyFile(self):
      source = r'/Users/asdf/Downloads'
      destination = r'/Users/asdf/Temp'
      ex = FileCopyProgress(src=source, dest=destination)

   def messageDialog(self, msgText, windowTitle=None):
      # SHOW MESSAGE BOX
      msgBox = QtWidgets.QMessageBox()
      msgBox.setModal = True
      if windowTitle:
         msgBox.setWindowTitle(windowTitle)
      msgBox.setText(msgText)
      msgBox.exec_()

def main():
   app = QtWidgets.QApplication(sys.argv)
   w = Window()
   w.show()
   sys.exit(app.exec_())

if __name__ == '__main__':
   main()
Dominique
  • 16,450
  • 15
  • 56
  • 112
Dogger
  • 39
  • 5

1 Answers1

0

It looks like you are missing a wait:

# in: copyfileobj definition

p = subprocess.Popen(['robocopy', src, dst, '/E', '/MT:16'], shell=True, stdout=subprocess.PIPE)

status = p.wait()
Alexander L. Hayes
  • 3,892
  • 4
  • 13
  • 34
  • `shell=True` is wrong for several reasons here. It might work on Windows still, but it's nevertheless [wrong and wasteful.](https://stackoverflow.com/questions/3172470/actual-meaning-of-shell-true-in-subprocess) – tripleee Dec 21 '20 at 10:38