Repository: dmwm/wmcore
Issue: [py2py3] problem with strings and base64 when contacting couchdb

**Impact of the bug**
All WMCore

**Describe the bug**
When working on #10502, after providing the fix in #10504 I get this error [1]. Alan already pointed me to [his approach](https://github.com/amaltaro/couchapp/commit/2d7084d6716c665bb3c17736eda1784e51210a2e) when dealing with a similar issue.



**How to reproduce it**

Run the following unittest
```bash
python3 setup.py test --buildBotMode=true --reallyDeleteMyDatabaseAfterEveryTest=true --testCertainPath=test/python/WMCore_t/WMBS_t/JobSplitting_t/EventBased_t.py
```
In a py3 environment with #10504 applied

**Expected behavior**
We should not get such a failure

**Additional context and error message**

[1]

```plaintext
======================================================================
ERROR: _testACDCProduction_v1_
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/dmwm/unittestdeploy/wmagent/1.4.9.pre3/sw/slc7_amd64_gcc630/external/python3/3.8.2-comp/lib/python3.8/base64.py", line 510, in _input_type_check
    m = memoryview(s)
TypeError: memoryview: a bytes-like object is required, not 'str'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/dmwm/wmcore_unittest/WMCore/test/python/WMCore_t/WMBS_t/JobSplitting_t/EventBased_t.py", line 46, in setUp
    self.testInit.setupCouch(self.couchDBName, "GroupUser", "ACDC")
  File "/home/dmwm/wmcore_unittest/WMCore/src/python/WMQuality/TestInitCouchApp.py", line 103, in setupCouch
    self.couch = CouchAppTestHarness(dbName)
  File "/home/dmwm/wmcore_unittest/WMCore/src/python/WMQuality/TestInitCouchApp.py", line 44, in __init__
    self.couchServer = CouchServer(self.couchUrl)
  File "/home/dmwm/wmcore_unittest/WMCore/src/python/WMCore/Database/CMSCouch.py", line 946, in __init__
    CouchDBRequests.__init__(self, url=dburl, usePYCurl=usePYCurl, ckey=ckey, cert=cert, capath=capath)
  File "/home/dmwm/wmcore_unittest/WMCore/src/python/WMCore/Database/CMSCouch.py", line 96, in __init__
    JSONRequests.__init__(self, url,
  File "/home/dmwm/wmcore_unittest/WMCore/src/python/WMCore/Services/Requests.py", line 542, in __init__
    Requests.__init__(self, url, idict)
  File "/home/dmwm/wmcore_unittest/WMCore/src/python/Utils/PortForward.py", line 69, in portMangle
    return callFunc(callObj, url, *args, **kwargs)
  File "/home/dmwm/wmcore_unittest/WMCore/src/python/WMCore/Services/Requests.py", line 92, in __init__
    self.addBasicAuth(urlComponent['username'], urlComponent['password'])
  File "/home/dmwm/wmcore_unittest/WMCore/src/python/WMCore/Services/Requests.py", line 413, in addBasicAuth
    auth_string = "Basic %s" % base64.encodestring('%s:%s' % (
  File "/home/dmwm/unittestdeploy/wmagent/1.4.9.pre3/sw/slc7_amd64_gcc630/external/python3/3.8.2-comp/lib/python3.8/base64.py", line 540, in encodestring
    return encodebytes(s)
  File "/home/dmwm/unittestdeploy/wmagent/1.4.9.pre3/sw/slc7_amd64_gcc630/external/python3/3.8.2-comp/lib/python3.8/base64.py", line 527, in encodebytes
    _input_type_check(s)
  File "/home/dmwm/unittestdeploy/wmagent/1.4.9.pre3/sw/slc7_amd64_gcc630/external/python3/3.8.2-comp/lib/python3.8/base64.py", line 513, in _input_type_check
    raise TypeError(msg) from err
TypeError: expected bytes-like object, not str
```


Changed files:
src/python/WMCore/Services/Requests.py

diff --git a/src/python/WMCore/Services/Requests.py b/src/python/WMCore/Services/Requests.py
index 794ef10d4..0d1f3d7ac 100644
--- a/src/python/WMCore/Services/Requests.py
+++ b/src/python/WMCore/Services/Requests.py
@@ -35,6 +35,7 @@ from http.client import HTTPException
 from json import JSONEncoder, JSONDecoder
 
 from Utils.CertTools import getKeyCertFromEnv, getCAPathFromEnv
+from Utils.Utilities import encodeUnicodeToBytes, decodeBytesToUnicode
 from WMCore.Algorithms import Permissions
 from WMCore.Lexicon import sanitizeURL
 from WMCore.WMException import WMException
@@ -410,8 +411,16 @@ class Requests(dict):
 
     def addBasicAuth(self, username, password):
         """Add basic auth headers to request"""
-        auth_string = "Basic %s" % base64.encodestring('%s:%s' % (
+        ## TODO: base64.encodestring is deprecated
+        # https://docs.python.org/3.8/library/base64.html#base64.encodestring
+        # change to base64.encodebytes after we drop python2
+        username = encodeUnicodeToBytes(username)
+        password = encodeUnicodeToBytes(password)
+        encodedauth = base64.encodestring(b'%s:%s' % (
             username, password)).strip()
+        if sys.version_info[0] == 3:
+            encodedauth = decodeBytesToUnicode(encodedauth)
+        auth_string = "Basic %s" % encodedauth
         self.additionalHeaders["Authorization"] = auth_string
 
     def getKeyCert(self):
@@ -559,6 +568,8 @@ class JSONRequests(Requests):
         if data:
             decoder = JSONDecoder()
             thunker = JSONThunker()
+            if sys.version_info[0] == 3:
+                data = decodeBytesToUnicode(data)
             data = decoder.decode(data)
             unthunked = thunker.unthunk(data)
             return unthunked