[PATCH 12/21] lookaside: Add a progress callback

Mathieu Bridon bochecha at fedoraproject.org
Wed May 6 11:53:08 UTC 2015


From: Mathieu Bridon <bochecha at daitauha.fr>

Due to the way pycurl handles progress callback, this handles both
upload and download progress.

However, we only use it for download at the moment.
---
 src/pyrpkg/lookaside.py | 24 +++++++++++++++
 test/test_lookaside.py  | 81 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)

diff --git a/src/pyrpkg/lookaside.py b/src/pyrpkg/lookaside.py
index 1108fcf..8badc73 100644
--- a/src/pyrpkg/lookaside.py
+++ b/src/pyrpkg/lookaside.py
@@ -43,6 +43,24 @@ class CGILookasideCache(object):
 
         self.download_path = '%(name)s/%(filename)s/%(hash)s/%(filename)s'
 
+    def print_progress(self, to_download, downloaded, to_upload, uploaded):
+        if to_download > 0:
+            done = downloaded / to_download
+
+        elif to_upload > 0:
+            done = uploaded / to_upload
+
+        else:
+            return
+
+        done_chars = int(done * 72)
+        remain_chars = 72 - done_chars
+        done = int(done * 1000) / 10.0
+
+        p = "\r%s%s %s%%" % ("#" * done_chars, " " * remain_chars, done)
+        sys.stdout.write(p)
+        sys.stdout.flush()
+
     def hash_file(self, filename, hashtype=None):
         """Compute the hash of a file
 
@@ -117,6 +135,8 @@ class CGILookasideCache(object):
             c = pycurl.Curl()
             c.setopt(pycurl.URL, url)
             c.setopt(pycurl.HTTPHEADER, ['Pragma:'])
+            c.setopt(pycurl.NOPROGRESS, False)
+            c.setopt(pycurl.PROGRESSFUNCTION, self.print_progress)
             c.setopt(pycurl.OPT_FILETIME, True)
             c.setopt(pycurl.WRITEDATA, f)
 
@@ -131,6 +151,10 @@ class CGILookasideCache(object):
             finally:
                 c.close()
 
+        # Get back a new line, after displaying the download progress
+        sys.stdout.write('\n')
+        sys.stdout.flush()
+
         if status != 200:
             raise DownloadError('Server returned status code %d' % status)
 
diff --git a/test/test_lookaside.py b/test/test_lookaside.py
index 89a34cd..7fe1743 100644
--- a/test/test_lookaside.py
+++ b/test/test_lookaside.py
@@ -186,3 +186,84 @@ class CGILookasideCacheTestCase(unittest.TestCase):
         lc = CGILookasideCache('sha512', 'http://example.com', '_')
         self.assertRaises(DownloadError, lc.download, 'pyrpkg',
                           'pyrpkg-0.0.tar.xz', hash, outfile)
+
+    @mock.patch('pyrpkg.lookaside.sys.stdout')
+    def test_print_download_progress(self, mock_stdout):
+        def mock_write(msg):
+            written_lines.append(msg)
+
+        written_lines = []
+        expected_lines = [
+            '\r##################                                                       25.0%',  # nopep8
+            '\r####################################                                     50.0%',  # nopep8
+            '\r######################################################                   75.0%',  # nopep8
+            '\r######################################################################## 100.0%',  # nopep8
+            ]
+
+        mock_stdout.write.side_effect = mock_write
+
+        lc = CGILookasideCache('_', '_', '_')
+        lc.print_progress(2000.0, 500.0, 0.0, 0.0)
+        self.assertEqual(mock_stdout.write.call_count, 1)
+        self.assertEqual(len(written_lines), 1)
+
+        lc.print_progress(2000.0, 1000.0, 0.0, 0.0)
+        self.assertEqual(mock_stdout.write.call_count, 2)
+        self.assertEqual(len(written_lines), 2)
+
+        lc.print_progress(2000.0, 1500.0, 0.0, 0.0)
+        self.assertEqual(mock_stdout.write.call_count, 3)
+        self.assertEqual(len(written_lines), 3)
+
+        lc.print_progress(2000.0, 2000.0, 0.0, 0.0)
+        self.assertEqual(mock_stdout.write.call_count, 4)
+        self.assertEqual(len(written_lines), 4)
+
+        self.assertEqual(written_lines, expected_lines)
+
+    @mock.patch('pyrpkg.lookaside.sys.stdout')
+    def test_print_upload_progress(self, mock_stdout):
+        def mock_write(msg):
+            written_lines.append(msg)
+
+        written_lines = []
+        expected_lines = [
+            '\r##################                                                       25.0%',  # nopep8
+            '\r####################################                                     50.0%',  # nopep8
+            '\r######################################################                   75.0%',  # nopep8
+            '\r######################################################################## 100.0%',  # nopep8
+            ]
+
+        mock_stdout.write.side_effect = mock_write
+
+        lc = CGILookasideCache('_', '_', '_')
+        lc.print_progress(0.0, 0.0, 2000.0, 500.0)
+        self.assertEqual(mock_stdout.write.call_count, 1)
+        self.assertEqual(len(written_lines), 1)
+
+        lc.print_progress(0.0, 0.0, 2000.0, 1000.0)
+        self.assertEqual(mock_stdout.write.call_count, 2)
+        self.assertEqual(len(written_lines), 2)
+
+        lc.print_progress(0.0, 0.0, 2000.0, 1500.0)
+        self.assertEqual(mock_stdout.write.call_count, 3)
+        self.assertEqual(len(written_lines), 3)
+
+        lc.print_progress(0.0, 0.0, 2000.0, 2000.0)
+        self.assertEqual(mock_stdout.write.call_count, 4)
+        self.assertEqual(len(written_lines), 4)
+
+        self.assertEqual(written_lines, expected_lines)
+
+    @mock.patch('pyrpkg.lookaside.sys.stdout')
+    def test_print_no_progress(self, mock_stdout):
+        def mock_write(msg):
+            written_lines.append(msg)
+
+        written_lines = []
+
+        mock_stdout.write.side_effect = mock_write
+
+        lc = CGILookasideCache('_', '_', '_')
+        lc.print_progress(0.0, 0.0, 0.0, 0.0)
+        self.assertEqual(len(written_lines), 0)
-- 
2.1.0



More information about the rel-eng mailing list