Issue #4387: binascii now refuses to accept str as binary input.
diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py
index 9639d30..8857e42 100644
--- a/Lib/email/test/test_email.py
+++ b/Lib/email/test/test_email.py
@@ -2279,7 +2279,7 @@
         eq(charsets[0], 'utf-8')
         charset = Charset(charsets[0])
         eq(charset.get_body_encoding(), 'base64')
-        msg.set_payload('hello world', charset=charset)
+        msg.set_payload(b'hello world', charset=charset)
         eq(msg.get_payload(), 'aGVsbG8gd29ybGQ=\n')
         eq(msg.get_payload(decode=True), b'hello world')
         eq(msg['content-transfer-encoding'], 'base64')
@@ -2539,7 +2539,7 @@
     def test_len(self):
         eq = self.assertEqual
         eq(base64mime.header_length('hello'),
-           len(base64mime.body_encode('hello', eol='')))
+           len(base64mime.body_encode(b'hello', eol='')))
         for size in range(15):
             if   size == 0 : bsize = 0
             elif size <= 3 : bsize = 4
@@ -2556,19 +2556,19 @@
 
     def test_encode(self):
         eq = self.assertEqual
-        eq(base64mime.body_encode(''), '')
-        eq(base64mime.body_encode('hello'), 'aGVsbG8=\n')
+        eq(base64mime.body_encode(b''), b'')
+        eq(base64mime.body_encode(b'hello'), 'aGVsbG8=\n')
         # Test the binary flag
-        eq(base64mime.body_encode('hello\n'), 'aGVsbG8K\n')
+        eq(base64mime.body_encode(b'hello\n'), 'aGVsbG8K\n')
         # Test the maxlinelen arg
-        eq(base64mime.body_encode('xxxx ' * 20, maxlinelen=40), """\
+        eq(base64mime.body_encode(b'xxxx ' * 20, maxlinelen=40), """\
 eHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg
 eHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg
 eHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg
 eHh4eCB4eHh4IA==
 """)
         # Test the eol argument
-        eq(base64mime.body_encode('xxxx ' * 20, maxlinelen=40, eol='\r\n'),
+        eq(base64mime.body_encode(b'xxxx ' * 20, maxlinelen=40, eol='\r\n'),
            """\
 eHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg\r
 eHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHgg\r
@@ -2734,7 +2734,7 @@
         eq('hello w=F6rld', c.body_encode('hello w\xf6rld'))
         # Try a charset with Base64 body encoding
         c = Charset('utf-8')
-        eq('aGVsbG8gd29ybGQ=\n', c.body_encode('hello world'))
+        eq('aGVsbG8gd29ybGQ=\n', c.body_encode(b'hello world'))
         # Try a charset with None body encoding
         c = Charset('us-ascii')
         eq('hello world', c.body_encode('hello world'))
diff --git a/Lib/test/test_binascii.py b/Lib/test/test_binascii.py
index 76a76b2..d4ab6bf 100755
--- a/Lib/test/test_binascii.py
+++ b/Lib/test/test_binascii.py
@@ -121,7 +121,7 @@
         self.assertRaises(binascii.Error, binascii.a2b_hex, t[:-1])
         self.assertRaises(binascii.Error, binascii.a2b_hex, t[:-1] + b'q')
 
-        self.assertEqual(binascii.hexlify('a'), b'61')
+        self.assertEqual(binascii.hexlify(b'a'), b'61')
 
     def test_qp(self):
         # A test for SF bug 534347 (segfaults without the proper fix)
@@ -166,7 +166,15 @@
                 f(b'')
             except SystemError as err:
                 self.fail("%s(b'') raises SystemError: %s" % (n, err))
-        binascii.crc_hqx('', 0)
+        binascii.crc_hqx(b'', 0)
+
+    def test_no_binary_strings(self):
+        # b2a_ must not accept strings
+        for f in (binascii.b2a_uu, binascii.b2a_base64,
+                  binascii.b2a_hqx, binascii.b2a_qp,
+                  binascii.hexlify, binascii.rlecode_hqx,
+                  binascii.crc_hqx, binascii.crc32):
+            self.assertRaises(TypeError, f, "test")
 
 def test_main():
     support.run_unittest(BinASCIITest)
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index fa3e0c3..1020740 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -3097,22 +3097,14 @@
         import binascii
         # SF bug [#470040] ParseTuple t# vs subclasses.
 
-        class MyStr(str):
+        class MyBytes(bytes):
             pass
-        base = 'abc'
-        m = MyStr(base)
+        base = b'abc'
+        m = MyBytes(base)
         # b2a_hex uses the buffer interface to get its argument's value, via
         # PyArg_ParseTuple 't#' code.
         self.assertEqual(binascii.b2a_hex(m), binascii.b2a_hex(base))
 
-        # It's not clear that unicode will continue to support the character
-        # buffer interface, and this test will fail if that's taken away.
-        class MyUni(str):
-            pass
-        base = 'abc'
-        m = MyUni(base)
-        self.assertEqual(binascii.b2a_hex(m), binascii.b2a_hex(base))
-
         class MyInt(int):
             pass
         m = MyInt(42)
@@ -3129,7 +3121,7 @@
 
         class octetstring(str):
             def __str__(self):
-                return binascii.b2a_hex(self).decode("ascii")
+                return binascii.b2a_hex(self.encode('ascii')).decode("ascii")
             def __repr__(self):
                 return self + " repr"
 
diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py
index f52aa5e..99c8dda 100644
--- a/Lib/test/test_zlib.py
+++ b/Lib/test/test_zlib.py
@@ -48,11 +48,11 @@
         self.assertEqual(zlib.adler32('spam'), 72286642)
 
     def test_same_as_binascii_crc32(self):
-        foo = 'abcdefghijklmnop'
+        foo = b'abcdefghijklmnop'
         crc = 2486878355
         self.assertEqual(binascii.crc32(foo), crc)
         self.assertEqual(zlib.crc32(foo), crc)
-        self.assertEqual(binascii.crc32('spam'), zlib.crc32('spam'))
+        self.assertEqual(binascii.crc32(b'spam'), zlib.crc32(b'spam'))
 
 
 
diff --git a/Misc/NEWS b/Misc/NEWS
index 723c71f..a8565c9 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -24,6 +24,8 @@
 Library
 -------
 
+- Issue #4387: binascii now refuses to accept str as binary input.
+
 - Issue #4073: Add 2to3 support to build_scripts, refactor that support
   in build_py.
 
diff --git a/Modules/binascii.c b/Modules/binascii.c
index c6e0362..52bd6dc 100644
--- a/Modules/binascii.c
+++ b/Modules/binascii.c
@@ -282,7 +282,7 @@
 	PyObject *rv;
 	Py_ssize_t bin_len;
 
-	if ( !PyArg_ParseTuple(args, "s*:b2a_uu", &pbin) )
+	if ( !PyArg_ParseTuple(args, "y*:b2a_uu", &pbin) )
 		return NULL;
 	bin_data = pbin.buf;
 	bin_len = pbin.len;
@@ -478,7 +478,7 @@
 	PyObject *rv;
 	Py_ssize_t bin_len;
 
-	if ( !PyArg_ParseTuple(args, "s*:b2a_base64", &pbuf) )
+	if ( !PyArg_ParseTuple(args, "y*:b2a_base64", &pbuf) )
 		return NULL;
 	bin_data = pbuf.buf;
 	bin_len = pbuf.len;
@@ -618,7 +618,7 @@
 	unsigned char ch;
 	Py_ssize_t in, inend, len;
 
-	if ( !PyArg_ParseTuple(args, "s*:rlecode_hqx", &pbuf) )
+	if ( !PyArg_ParseTuple(args, "y*:rlecode_hqx", &pbuf) )
 		return NULL;
 	in_data = pbuf.buf;
 	len = pbuf.len;
@@ -684,7 +684,7 @@
 	PyObject *rv;
 	Py_ssize_t len;
 
-	if ( !PyArg_ParseTuple(args, "s*:b2a_hqx", &pbin) )
+	if ( !PyArg_ParseTuple(args, "y*:b2a_hqx", &pbin) )
 		return NULL;
 	bin_data = pbin.buf;
 	len = pbin.len;
@@ -856,7 +856,7 @@
 	unsigned int crc;
 	Py_ssize_t len;
 
-	if ( !PyArg_ParseTuple(args, "s*i:crc_hqx", &pin, &crc) )
+	if ( !PyArg_ParseTuple(args, "y*i:crc_hqx", &pin, &crc) )
 		return NULL;
 	bin_data = pin.buf;
 	len = pin.len;
@@ -883,7 +883,7 @@
     Py_ssize_t len;
     int signed_val;
 
-    if (!PyArg_ParseTuple(args, "s*|I:crc32", &pbuf, &crc32val))
+    if (!PyArg_ParseTuple(args, "y*|I:crc32", &pbuf, &crc32val))
         return NULL;
     buf = (Byte*)pbuf.buf;
     len = pbuf.len;
@@ -1047,7 +1047,7 @@
 	char* retbuf;
 	Py_ssize_t i, j;
 
-	if (!PyArg_ParseTuple(args, "s*:b2a_hex", &parg))
+	if (!PyArg_ParseTuple(args, "y*:b2a_hex", &parg))
 		return NULL;
 	argbuf = parg.buf;
 	arglen = parg.len;
@@ -1300,7 +1300,7 @@
 	int crlf = 0;
 	unsigned char *p;
 
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s*|iii", kwlist, &pdata,
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*|iii", kwlist, &pdata,
 	      &quotetabs, &istext, &header))
 		return NULL;
 	data = pdata.buf;