Repository: fedora-infra/bodhi

Issue:
TypeError: a bytes-like object is required, not 'str'
The composer has a Python 3 compatibility issue:

```
Traceback (most recent call last):
  File "/usr/lib/python3.7/site-packages/bodhi/server/consumers/masher.py", line 339, in run 
    self.work()
  File "/usr/lib/python3.7/site-packages/bodhi/server/consumers/masher.py", line 410, in work
    self._compose_updates()
  File "/usr/lib/python3.7/site-packages/bodhi/server/consumers/masher.py", line 946, in _compose_updates
    self._wait_for_pungi(pungi_process)
  File "/usr/lib/python3.7/site-packages/bodhi/server/consumers/masher.py", line 1235, in _wait_for_pungi
    for line in out.split('\n'):
TypeError: a bytes-like object is required, not 'str'
```


Discussion:

Resolving patch:
diff --git a/bodhi/server/consumers/masher.py b/bodhi/server/consumers/masher.py
--- a/bodhi/server/consumers/masher.py
+++ b/bodhi/server/consumers/masher.py
@@ -1222,6 +1222,8 @@ def _wait_for_pungi(self, pungi_process):
             return
         self.log.info('Waiting for pungi process to finish')
         out, err = pungi_process.communicate()
+        out = out.decode()
+        err = err.decode()
         self.devnull.close()
         if pungi_process.returncode != 0:
             self.log.error('Pungi exited with exit code %d', pungi_process.returncode)


Test patch:
diff --git a/bodhi/tests/server/consumers/test_masher.py b/bodhi/tests/server/consumers/test_masher.py
--- a/bodhi/tests/server/consumers/test_masher.py
+++ b/bodhi/tests/server/consumers/test_masher.py
@@ -268,7 +268,7 @@ def fake_pungi(*args, **kwargs):
 That was the actual one''' % mash_dir
 
             fake_popen = mock.MagicMock()
-            fake_popen.communicate = lambda: (fake_stdout, 'hello')
+            fake_popen.communicate = lambda: (fake_stdout.encode(), b'hello')
             fake_popen.poll.return_value = None
             fake_popen.returncode = 0
             return fake_popen
@@ -630,11 +630,11 @@ def test_mash_invalid_dir(self, save_state):
             t.release = session.query(Release).filter_by(name=u'F17').one()
             try:
                 fake_popen = mock.MagicMock()
-                fake_stdout = '''Some output
+                fake_stdout = b'''Some output
 Some more output ...... This is not a Compose dir: ....
 Compose dir: /tmp/nonsensical_directory
 That was the actual one'''
-                fake_popen.communicate = lambda: (fake_stdout, 'hello')
+                fake_popen.communicate = lambda: (fake_stdout, b'hello')
                 fake_popen.poll.return_value = None
                 fake_popen.returncode = 0
                 t._startyear = datetime.datetime.utcnow().year
@@ -660,10 +660,10 @@ def test_mash_no_found_dirs(self, save_state):
             t.release = session.query(Release).filter_by(name=u'F17').one()
             try:
                 fake_popen = mock.MagicMock()
-                fake_stdout = '''Some output
+                fake_stdout = b'''Some output
     Some more output ...... This is not a Compose dir: ....
     That was the actual one'''
-                fake_popen.communicate = lambda: (fake_stdout, 'hello')
+                fake_popen.communicate = lambda: (fake_stdout, b'hello')
                 fake_popen.poll.return_value = None
                 fake_popen.returncode = 0
                 t._startyear = datetime.datetime.utcnow().year