Repository: SFDO-Tooling/CumulusCI
Pull request #3428 (2022-11-08 01:42:22)

Start the process of deprecating Python 2 OrgConfigs
This code was not covered by tests and claims to be only related to Python 2. Let's see if we can delete it. If nobody reports the warning to the CCI team in the next several months, we can delete it. If they do, it will inform our work on deprecating Pickle in favour of JSON (which would not support binary data, by default).



Patch:
diff --git a/cumulusci/core/keychain/encrypted_file_project_keychain.py b/cumulusci/core/keychain/encrypted_file_project_keychain.py
index 0bb0cad9a..0f951250e 100644
--- a/cumulusci/core/keychain/encrypted_file_project_keychain.py
+++ b/cumulusci/core/keychain/encrypted_file_project_keychain.py
@@ -144,20 +144,36 @@ class EncryptedFileProjectKeychain(BaseProjectKeychain):
                     ]
                 )
                 raise KeychainKeyNotFound(message) from e
-            # Convert bytes created in Python 2
-            config_dict = {}
-            for k, v in unpickled.items():
-                if isinstance(k, bytes):
-                    k = k.decode("utf-8")
-                if isinstance(v, bytes):
-                    v = v.decode("utf-8")
-                config_dict[k] = v
+
+        config_dict = self.cleanup_Python_2_configs(unpickled)
 
         args = [config_dict]
         if extra:
             args += extra
         return self._construct_config(config_class, args)
 
+    def cleanup_Python_2_configs(self, unpickled):
+        # Convert bytes created in Python 2
+        config_dict = {}
+
+        # After a few months, we can clean up this code if nobody reports
+        # warnings.
+        message = (
+            "Unexpected bytes found in config.\n"
+            "Please inform the CumulusCI team.\n"
+            "Future versions of CumulusCI may break your config."
+        )
+        for k, v in unpickled.items():
+            if isinstance(k, bytes):
+                self.logger.warning(message)
+                k = k.decode("utf-8")
+            if isinstance(v, bytes):
+                self.logger.warning(message)
+                v = v.decode("utf-8")
+            config_dict[k] = v
+
+        return config_dict
+
     def _construct_config(self, config_class, args):
         config = args[0]
         if config.get("scratch"):


Test patch:
diff --git a/cumulusci/core/keychain/tests/test_encrypted_file_project_keychain.py b/cumulusci/core/keychain/tests/test_encrypted_file_project_keychain.py
index 73a7c2809..d91a5f199 100644
--- a/cumulusci/core/keychain/tests/test_encrypted_file_project_keychain.py
+++ b/cumulusci/core/keychain/tests/test_encrypted_file_project_keychain.py
@@ -905,6 +905,15 @@ class TestEncryptedFileProjectKeychain:
         assert config.__class__ == BaseConfig
         assert config.config == {}
 
+    def test_decrypt_config__Python_2_warning(self, keychain, caplog):
+        config = keychain.cleanup_Python_2_configs({"a": "b"})
+        assert config == {"a": "b"}
+        assert len(caplog.records) == 0
+
+        config = keychain.cleanup_Python_2_configs({"a": b"b", b"c": "d"})
+        assert config == {"a": "b", "c": "d"}
+        assert len(caplog.records) == 2
+
     def test_decrypt_config__wrong_key(self, keychain, org_config):
         keychain.set_org(org_config, False)
         keychain.key = "x" * 16