Remove native popen() and fdopen(), replacing them with subprocess calls.
Fix a path to an assert in fileio_read().
Some misc tweaks.
diff --git a/Lib/io.py b/Lib/io.py
index 9cbc11c..222197e 100644
--- a/Lib/io.py
+++ b/Lib/io.py
@@ -120,6 +120,8 @@
                  (appending and "a" or "") +
                  (updating and "+" or ""))
     if buffering is None:
+        buffering = -1
+    if buffering < 0:
         buffering = DEFAULT_BUFFER_SIZE
         # XXX Should default to line buffering if os.isatty(raw.fileno())
         try:
@@ -446,8 +448,8 @@
     implementation, but wrap one.
     """
 
-    def read(self, n: int = -1) -> bytes:
-        """read(n: int = -1) -> bytes.  Read and return up to n bytes.
+    def read(self, n: int = None) -> bytes:
+        """read(n: int = None) -> bytes.  Read and return up to n bytes.
 
         If the argument is omitted, None, or negative, reads and
         returns all data until EOF.
@@ -717,6 +719,8 @@
         self._write_buf = b""
 
     def write(self, b):
+        if not isinstance(b, bytes):
+            b = bytes(b)
         # XXX we can implement some more tricks to try and avoid partial writes
         if len(self._write_buf) > self.buffer_size:
             # We're full, so let's pre-flush the buffer
diff --git a/Lib/os.py b/Lib/os.py
index 5ddf07c..0ced882 100644
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -696,3 +696,41 @@
             bs += read(_urandomfd, n - len(bs))
         close(_urandomfd)
         return bs
+
+# Supply os.popen()
+def popen(cmd, mode="r", buffering=None):
+    if not isinstance(cmd, basestring):
+        raise TypeError("invalid cmd type (%s, expected string)" % type(cmd))
+    if mode not in ("r", "w"):
+        raise ValueError("invalid mode %r" % mode)
+    import subprocess, io
+    if mode == "r":
+        proc = subprocess.Popen(cmd,
+                                shell=True,
+                                stdout=subprocess.PIPE,
+                                bufsize=buffering)
+        return _wrap_close(io.TextIOWrapper(proc.stdout), proc)
+    else:
+        proc = subprocess.Popen(cmd,
+                                shell=True,
+                                stdin=subprocess.PIPE,
+                                bufsize=buffering)
+        return _wrap_close(io.TextIOWrapper(proc.stdin), proc)
+
+# Helper for popen() -- a proxy for a file whose close waits for the process
+class _wrap_close:
+    def __init__(self, stream, proc):
+        self._stream = stream
+        self._proc = proc
+    def close(self):
+        self._stream.close()
+        return self._proc.wait() << 8  # Shift left to match old behavior
+    def __getattr__(self, name):
+        return getattr(self._stream, name)
+
+# Supply os.fdopen() (used by subprocess!)
+def fdopen(fd, mode="r", buffering=-1):
+    if not isinstance(fd, int):
+        raise TypeError("invalid fd type (%s, expected integer)" % type(fd))
+    import io
+    return io.open(fd, mode, buffering)
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index 2d02df6..fe64cc0 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -246,11 +246,11 @@
 try:
     retcode = call("mycmd" + " myarg", shell=True)
     if retcode < 0:
-        print >>sys.stderr, "Child was terminated by signal", -retcode
+        print("Child was terminated by signal", -retcode, file=sys.stderr)
     else:
-        print >>sys.stderr, "Child returned", retcode
-except OSError, e:
-    print >>sys.stderr, "Execution failed:", e
+        print("Child returned", retcode, file=sys.stderr)
+except OSError as e:
+    print("Execution failed:", e, file=sys.stderr)
 
 
 Replacing os.spawn*
@@ -539,6 +539,8 @@
                 os.close(errread)
                 errread = None
 
+        if bufsize == 0:
+            bufsize = 1  # Nearly unbuffered (XXX for now)
         if p2cwrite is not None:
             self.stdin = os.fdopen(p2cwrite, 'wb', bufsize)
         if c2pread is not None:
@@ -1007,6 +1009,7 @@
             if data:
                 os.waitpid(self.pid, 0)
                 child_exception = pickle.loads(data)
+                print("exc:", child_exception)
                 raise child_exception
 
 
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index d1c0f68..c98d61f 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -478,7 +478,7 @@
             [ '\r\n', input_lines ],
         ]
 
-        encodings = ('utf-8', 'bz2')
+        encodings = ('utf-8', 'latin-1')
 
         # Try a range of pad sizes to test the case where \r is the last
         # character in TextIOWrapper._pending_line.
diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py
index f8b5bdf..8c2eb23 100644
--- a/Lib/test/test_tempfile.py
+++ b/Lib/test/test_tempfile.py
@@ -730,7 +730,7 @@
         write("a" * 35)
         write("b" * 35)
         seek(0, 0)
-        self.failUnless(read(70) == 'a'*35 + 'b'*35)
+        self.assertEqual(read(70), 'a'*35 + 'b'*35)
 
 test_classes.append(test_SpooledTemporaryFile)