gh-91217: deprecate uu (GH-92009)



Automerge-Triggered-By: GH:brettcannon
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index aa0a51b..b2b9874 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -1071,6 +1071,7 @@
   * :mod:`spwd`
   * :mod:`sunau`
   * :mod:`telnetlib`
+  * :mod:`uu`
 
   (Contributed by Brett Cannon in :issue:`47061` and Victor Stinner in
   :gh:`68966`.)
diff --git a/Lib/email/message.py b/Lib/email/message.py
index 6752ce0..65fda50 100644
--- a/Lib/email/message.py
+++ b/Lib/email/message.py
@@ -6,8 +6,8 @@
 
 __all__ = ['Message', 'EmailMessage']
 
+import binascii
 import re
-import uu
 import quopri
 from io import BytesIO, StringIO
 
@@ -35,7 +35,7 @@ def _splitparam(param):
     if not sep:
         return a.strip(), None
     return a.strip(), b.strip()
-
+
 def _formatparam(param, value=None, quote=True):
     """Convenience function to format and return a key=value pair.
 
@@ -101,7 +101,37 @@ def _unquotevalue(value):
         return utils.unquote(value)
 
 
-
+def _decode_uu(encoded):
+    """Decode uuencoded data."""
+    decoded_lines = []
+    encoded_lines_iter = iter(encoded.splitlines())
+    for line in encoded_lines_iter:
+        if line.startswith(b"begin "):
+            mode, _, path = line.removeprefix(b"begin ").partition(b" ")
+            try:
+                int(mode, base=8)
+            except ValueError:
+                continue
+            else:
+                break
+    else:
+        raise ValueError("`begin` line not found")
+    for line in encoded_lines_iter:
+        if not line:
+            raise ValueError("Truncated input")
+        elif line.strip(b' \t\r\n\f') == b'end':
+            break
+        try:
+            decoded_line = binascii.a2b_uu(line)
+        except binascii.Error:
+            # Workaround for broken uuencoders by /Fredrik Lundh
+            nbytes = (((line[0]-32) & 63) * 4 + 5) // 3
+            decoded_line = binascii.a2b_uu(line[:nbytes])
+        decoded_lines.append(decoded_line)
+
+    return b''.join(decoded_lines)
+
+
 class Message:
     """Basic message object.
 
@@ -288,13 +318,10 @@ def get_payload(self, i=None, decode=False):
                 self.policy.handle_defect(self, defect)
             return value
         elif cte in ('x-uuencode', 'uuencode', 'uue', 'x-uue'):
-            in_file = BytesIO(bpayload)
-            out_file = BytesIO()
             try:
-                uu.decode(in_file, out_file, quiet=True)
-                return out_file.getvalue()
-            except uu.Error:
-                # Some decoding problem
+                return _decode_uu(bpayload)
+            except ValueError:
+                # Some decoding problem.
                 return bpayload
         if isinstance(payload, str):
             return bpayload
diff --git a/Lib/test/test_uu.py b/Lib/test/test_uu.py
index 753b31e..316a04a 100644
--- a/Lib/test/test_uu.py
+++ b/Lib/test/test_uu.py
@@ -4,12 +4,13 @@
 """
 
 import unittest
-from test.support import os_helper
+from test.support import os_helper, warnings_helper
+
+uu = warnings_helper.import_deprecated("uu")
 
 import os
 import stat
 import sys
-import uu
 import io
 
 plaintext = b"The symbols on top of your keyboard are !@#$%^&*()_+|~\n"
diff --git a/Lib/uu.py b/Lib/uu.py
index 9f1f37f..6f8805d 100755
--- a/Lib/uu.py
+++ b/Lib/uu.py
@@ -33,6 +33,9 @@
 import binascii
 import os
 import sys
+import warnings
+
+warnings._deprecated(__name__, remove=(3, 13))
 
 __all__ = ["Error", "encode", "decode"]
 
diff --git a/Misc/NEWS.d/next/Library/2022-04-21-21-04-08.gh-issue-91217.BZVEki.rst b/Misc/NEWS.d/next/Library/2022-04-21-21-04-08.gh-issue-91217.BZVEki.rst
new file mode 100644
index 0000000..ef5b5c2
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-04-21-21-04-08.gh-issue-91217.BZVEki.rst
@@ -0,0 +1 @@
+Deprecate the uu module.