Issue #1602: Windows console doesn't input or print Unicode (PEP 528)
Closes #17602: Adds a readline implementation for the Windows console
diff --git a/Lib/io.py b/Lib/io.py
index e03db97..968ee50 100644
--- a/Lib/io.py
+++ b/Lib/io.py
@@ -90,3 +90,10 @@
 for klass in (StringIO, TextIOWrapper):
     TextIOBase.register(klass)
 del klass
+
+try:
+    from _io import _WindowsConsoleIO
+except ImportError:
+    pass
+else:
+    RawIOBase.register(_WindowsConsoleIO)
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index b504cf7..95c7482 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -1518,7 +1518,7 @@
     singles = ["fchdir", "dup", "fdopen", "fdatasync", "fstat",
                "fstatvfs", "fsync", "tcgetpgrp", "ttyname"]
     #singles.append("close")
-    #We omit close because it doesn'r raise an exception on some platforms
+    #We omit close because it doesn't raise an exception on some platforms
     def get_single(f):
         def helper(self):
             if  hasattr(os, f):
diff --git a/Lib/test/test_winconsoleio.py b/Lib/test/test_winconsoleio.py
new file mode 100644
index 0000000..9e932fe
--- /dev/null
+++ b/Lib/test/test_winconsoleio.py
@@ -0,0 +1,72 @@
+'''Tests for WindowsConsoleIO
+
+Unfortunately, most testing requires interactive use, since we have no
+API to read back from a real console, and this class is only for use
+with real consoles.
+
+Instead, we validate that basic functionality such as opening, closing
+and in particular fileno() work, but are forced to leave real testing
+to real people with real keyborads.
+'''
+
+import io
+import unittest
+import sys
+
+if sys.platform != 'win32':
+    raise unittest.SkipTest("test only relevant on win32")
+
+ConIO = io._WindowsConsoleIO
+
+class WindowsConsoleIOTests(unittest.TestCase):
+    def test_abc(self):
+        self.assertTrue(issubclass(ConIO, io.RawIOBase))
+        self.assertFalse(issubclass(ConIO, io.BufferedIOBase))
+        self.assertFalse(issubclass(ConIO, io.TextIOBase))
+
+    def test_open_fd(self):
+        f = ConIO(0)
+        self.assertTrue(f.readable())
+        self.assertFalse(f.writable())
+        self.assertEqual(0, f.fileno())
+        f.close()   # multiple close should not crash
+        f.close()
+
+        f = ConIO(1, 'w')
+        self.assertFalse(f.readable())
+        self.assertTrue(f.writable())
+        self.assertEqual(1, f.fileno())
+        f.close()
+        f.close()
+
+        f = ConIO(2, 'w')
+        self.assertFalse(f.readable())
+        self.assertTrue(f.writable())
+        self.assertEqual(2, f.fileno())
+        f.close()
+        f.close()
+
+    def test_open_name(self):
+        f = ConIO("CON")
+        self.assertTrue(f.readable())
+        self.assertFalse(f.writable())
+        self.assertIsNotNone(f.fileno())
+        f.close()   # multiple close should not crash
+        f.close()
+
+        f = ConIO('CONIN$')
+        self.assertTrue(f.readable())
+        self.assertFalse(f.writable())
+        self.assertIsNotNone(f.fileno())
+        f.close()
+        f.close()
+
+        f = ConIO('CONOUT$', 'w')
+        self.assertFalse(f.readable())
+        self.assertTrue(f.writable())
+        self.assertIsNotNone(f.fileno())
+        f.close()
+        f.close()
+
+if __name__ == "__main__":
+    unittest.main()