Branch merge
diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst
index 922bcf4..9477133 100644
--- a/Doc/library/codecs.rst
+++ b/Doc/library/codecs.rst
@@ -839,7 +839,7 @@
 characters: UTF-8. UTF-8 is an 8-bit encoding, which means there are no issues
 with byte order in UTF-8. Each byte in a UTF-8 byte sequence consists of two
 parts: Marker bits (the most significant bits) and payload bits. The marker bits
-are a sequence of zero to six 1 bits followed by a 0 bit. Unicode characters are
+are a sequence of zero to four ``1`` bits followed by a ``0`` bit. Unicode characters are
 encoded like this (with x being payload bits, which when concatenated give the
 Unicode character):
 
@@ -852,12 +852,7 @@
 +-----------------------------------+----------------------------------------------+
 | ``U-00000800`` ... ``U-0000FFFF`` | 1110xxxx 10xxxxxx 10xxxxxx                   |
 +-----------------------------------+----------------------------------------------+
-| ``U-00010000`` ... ``U-001FFFFF`` | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx          |
-+-----------------------------------+----------------------------------------------+
-| ``U-00200000`` ... ``U-03FFFFFF`` | 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
-+-----------------------------------+----------------------------------------------+
-| ``U-04000000`` ... ``U-7FFFFFFF`` | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
-|                                   | 10xxxxxx                                     |
+| ``U-00010000`` ... ``U-0010FFFF`` | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx          |
 +-----------------------------------+----------------------------------------------+
 
 The least significant bit of the Unicode character is the rightmost x bit.
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
index d8ab8b7..5737755 100644
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -29,11 +29,6 @@
   objects, and result in an object of the same type, if a path or file name is
   returned.
 
-.. note::
-
-   If not separately noted, all functions that claim "Availability: Unix" are
-   supported on Mac OS X, which builds on a Unix core.
-
 * An "Availability: Unix" note means that this function is commonly found on
   Unix systems.  It does not make any claims about its existence on a specific
   operating system.
diff --git a/Include/descrobject.h b/Include/descrobject.h
index f715fe1..646b3cc 100644
--- a/Include/descrobject.h
+++ b/Include/descrobject.h
@@ -77,6 +77,7 @@
 PyAPI_DATA(PyTypeObject) PyMethodDescr_Type;
 PyAPI_DATA(PyTypeObject) PyWrapperDescr_Type;
 PyAPI_DATA(PyTypeObject) PyDictProxy_Type;
+PyAPI_DATA(PyTypeObject) _PyMethodWrapper_Type;
 
 PyAPI_FUNC(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *);
 PyAPI_FUNC(PyObject *) PyDescr_NewClassMethod(PyTypeObject *, PyMethodDef *);
diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py
index dcce2eb..da74729 100644
--- a/Lib/idlelib/PyShell.py
+++ b/Lib/idlelib/PyShell.py
@@ -1,16 +1,17 @@
 #! /usr/bin/env python3
 
+import getopt
 import os
 import os.path
-import sys
-import getopt
 import re
 import socket
-import time
+import subprocess
+import sys
 import threading
+import time
+import tokenize
 import traceback
 import types
-import subprocess
 
 import linecache
 from code import InteractiveInterpreter
@@ -201,18 +202,18 @@
         breaks = self.breakpoints
         filename = self.io.filename
         try:
-            lines = open(self.breakpointPath,"r").readlines()
+            with open(self.breakpointPath, "r") as fp:
+                lines = fp.readlines()
         except IOError:
             lines = []
-        new_file = open(self.breakpointPath,"w")
-        for line in lines:
-            if not line.startswith(filename + '='):
-                new_file.write(line)
-        self.update_breakpoints()
-        breaks = self.breakpoints
-        if breaks:
-            new_file.write(filename + '=' + str(breaks) + '\n')
-        new_file.close()
+        with open(self.breakpointPath, "w") as new_file:
+            for line in lines:
+                if not line.startswith(filename + '='):
+                    new_file.write(line)
+            self.update_breakpoints()
+            breaks = self.breakpoints
+            if breaks:
+                new_file.write(filename + '=' + str(breaks) + '\n')
 
     def restore_file_breaks(self):
         self.text.update()   # this enables setting "BREAK" tags to be visible
@@ -220,7 +221,8 @@
         if filename is None:
             return
         if os.path.isfile(self.breakpointPath):
-            lines = open(self.breakpointPath,"r").readlines()
+            with open(self.breakpointPath, "r") as fp:
+                lines = fp.readlines()
             for line in lines:
                 if line.startswith(filename + '='):
                     breakpoint_linenumbers = eval(line[len(filename)+1:])
@@ -571,7 +573,8 @@
     def execfile(self, filename, source=None):
         "Execute an existing file"
         if source is None:
-            source = open(filename, "r").read()
+            with tokenize.open(filename) as fp:
+                source = fp.read()
         try:
             code = compile(source, filename, "exec")
         except (OverflowError, SyntaxError):
diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py
index 90972b5..915e56e 100644
--- a/Lib/idlelib/ScriptBinding.py
+++ b/Lib/idlelib/ScriptBinding.py
@@ -67,25 +67,20 @@
 
     def tabnanny(self, filename):
         # XXX: tabnanny should work on binary files as well
-        with open(filename, 'r', encoding='iso-8859-1') as f:
-            two_lines = f.readline() + f.readline()
-        encoding = IOBinding.coding_spec(two_lines)
-        if not encoding:
-            encoding = 'utf-8'
-        f = open(filename, 'r', encoding=encoding)
-        try:
-            tabnanny.process_tokens(tokenize.generate_tokens(f.readline))
-        except tokenize.TokenError as msg:
-            msgtxt, (lineno, start) = msg
-            self.editwin.gotoline(lineno)
-            self.errorbox("Tabnanny Tokenizing Error",
-                          "Token Error: %s" % msgtxt)
-            return False
-        except tabnanny.NannyNag as nag:
-            # The error messages from tabnanny are too confusing...
-            self.editwin.gotoline(nag.get_lineno())
-            self.errorbox("Tab/space error", indent_message)
-            return False
+        with tokenize.open(filename) as f:
+            try:
+                tabnanny.process_tokens(tokenize.generate_tokens(f.readline))
+            except tokenize.TokenError as msg:
+                msgtxt, (lineno, start) = msg
+                self.editwin.gotoline(lineno)
+                self.errorbox("Tabnanny Tokenizing Error",
+                              "Token Error: %s" % msgtxt)
+                return False
+            except tabnanny.NannyNag as nag:
+                # The error messages from tabnanny are too confusing...
+                self.editwin.gotoline(nag.get_lineno())
+                self.errorbox("Tab/space error", indent_message)
+                return False
         return True
 
     def checksyntax(self, filename):
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index d3c0062..0a7ddd4 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -5,6 +5,7 @@
 import unittest
 import pickle
 import weakref
+import errno
 
 from test.support import (TESTFN, unlink, run_unittest, captured_output,
                           gc_collect, cpython_only)
@@ -849,6 +850,13 @@
             self.fail("RuntimeError not raised")
         self.assertEqual(wr(), None)
 
+    def test_errno_ENOTDIR(self):
+        # Issue #12802: "not a directory" errors are ENOTDIR even on Windows
+        with self.assertRaises(OSError) as cm:
+            os.listdir(__file__)
+        self.assertEqual(cm.exception.errno, errno.ENOTDIR, cm.exception)
+
+
 def test_main():
     run_unittest(ExceptionTests)
 
diff --git a/Misc/NEWS b/Misc/NEWS
index a562d29..c74cb55 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,12 @@
 Core and Builtins
 -----------------
 
+- Issue #12802: the Windows error ERROR_DIRECTORY (numbered 267) is now
+  mapped to POSIX errno ENOTDIR (previously EINVAL).
+
+- Accept bytes for the AST string type. This is temporary until a proper fix in
+  3.3.
+
 - Issue #9200: The str.is* methods now work with strings that contain non-BMP
   characters even in narrow Unicode builds.
 
@@ -22,6 +28,8 @@
 Library
 -------
 
+- Issue #12636: IDLE reads the coding cookie when executing a Python script.
+
 - Issue #10946: The distutils commands bdist_dumb, bdist_wininst and bdist_msi
   now respect a --skip-build option given to bdist.
 
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index 93daefd..a786bae 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -846,16 +846,13 @@
 /* This has no reason to be in this file except that adding new files is a
    bit of a pain */
 
-/* forward */
-static PyTypeObject wrappertype;
-
 typedef struct {
     PyObject_HEAD
     PyWrapperDescrObject *descr;
     PyObject *self;
 } wrapperobject;
 
-#define Wrapper_Check(v) (Py_TYPE(v) == &wrappertype)
+#define Wrapper_Check(v) (Py_TYPE(v) == &_PyMethodWrapper_Type)
 
 static void
 wrapper_dealloc(wrapperobject *wp)
@@ -1021,7 +1018,7 @@
     return 0;
 }
 
-static PyTypeObject wrappertype = {
+PyTypeObject _PyMethodWrapper_Type = {
     PyVarObject_HEAD_INIT(&PyType_Type, 0)
     "method-wrapper",                           /* tp_name */
     sizeof(wrapperobject),                      /* tp_basicsize */
@@ -1070,7 +1067,7 @@
     assert(_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
                                     (PyObject *)PyDescr_TYPE(descr)));
 
-    wp = PyObject_GC_New(wrapperobject, &wrappertype);
+    wp = PyObject_GC_New(wrapperobject, &_PyMethodWrapper_Type);
     if (wp != NULL) {
         Py_INCREF(descr);
         wp->descr = descr;
diff --git a/Objects/object.c b/Objects/object.c
index 3240bc3..694e7e7 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -1625,6 +1625,9 @@
     if (PyType_Ready(&PyWrapperDescr_Type) < 0)
         Py_FatalError("Can't initialize wrapper type");
 
+    if (PyType_Ready(&_PyMethodWrapper_Type) < 0)
+        Py_FatalError("Can't initialize method wrapper type");
+
     if (PyType_Ready(&PyEllipsis_Type) < 0)
         Py_FatalError("Can't initialize ellipsis type");
 
diff --git a/PC/errmap.h b/PC/errmap.h
index d225aa4..8dde31c 100644
--- a/PC/errmap.h
+++ b/PC/errmap.h
@@ -72,6 +72,7 @@
         case 202: return 8;
         case 206: return 2;
         case 215: return 11;
+        case 267: return 20;
         case 1816: return 12;
         default: return EINVAL;
     }
diff --git a/PC/generrmap.c b/PC/generrmap.c
index bf1081b..0323cd4 100644
--- a/PC/generrmap.c
+++ b/PC/generrmap.c
@@ -1,3 +1,6 @@
+#include <windows.h>
+#include <fcntl.h>
+#include <io.h>
 #include <stdio.h>
 #include <errno.h>
 
@@ -6,15 +9,21 @@
 int main()
 {
     int i;
+    _setmode(fileno(stdout), O_BINARY);
     printf("/* Generated file. Do not edit. */\n");
     printf("int winerror_to_errno(int winerror)\n");
-    printf("{\n\tswitch(winerror) {\n");
+    printf("{\n    switch(winerror) {\n");
     for(i=1; i < 65000; i++) {
         _dosmaperr(i);
-        if (errno == EINVAL)
-            continue;
-        printf("\t\tcase %d: return %d;\n", i, errno);
+        if (errno == EINVAL) {
+            /* Issue #12802 */
+            if (i == ERROR_DIRECTORY)
+                errno = ENOTDIR;
+            else
+                continue;
+        }
+        printf("        case %d: return %d;\n", i, errno);
     }
-    printf("\t\tdefault: return EINVAL;\n");
-    printf("\t}\n}\n");
+    printf("        default: return EINVAL;\n");
+    printf("    }\n}\n");
 }
diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py
index 8a7f8ae..249e18d 100755
--- a/Parser/asdl_c.py
+++ b/Parser/asdl_c.py
@@ -805,7 +805,7 @@
 
 static int obj2ast_string(PyObject* obj, PyObject** out, PyArena* arena)
 {
-    if (!PyUnicode_CheckExact(obj)) {
+    if (!PyUnicode_CheckExact(obj) && !PyBytes_CheckExact(obj)) {
         PyErr_SetString(PyExc_TypeError, "AST string must be of type str");
         return 1;
     }
diff --git a/Python/Python-ast.c b/Python/Python-ast.c
index 8ba06ff..89c07cd 100644
--- a/Python/Python-ast.c
+++ b/Python/Python-ast.c
@@ -611,7 +611,7 @@
 
 static int obj2ast_string(PyObject* obj, PyObject** out, PyArena* arena)
 {
-    if (!PyUnicode_CheckExact(obj)) {
+    if (!PyUnicode_CheckExact(obj) && !PyBytes_CheckExact(obj)) {
         PyErr_SetString(PyExc_TypeError, "AST string must be of type str");
         return 1;
     }
diff --git a/Python/import.c b/Python/import.c
index 23752ee..93defef 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -2349,7 +2349,9 @@
 {
     PyObject *result;
     PyObject *modules;
+#ifdef WITH_THREAD
     long me;
+#endif
 
     /* Try to get the module from sys.modules[name] */
     modules = PyImport_GetModuleDict();