Merge tag 'v3.9.0a3'

Python 3.9.0a3
diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst
index 8394304..515bdd0 100644
--- a/Doc/library/unittest.mock.rst
+++ b/Doc/library/unittest.mock.rst
@@ -1401,7 +1401,8 @@
     "as"; very useful if :func:`patch` is creating a mock object for you.
 
     :func:`patch` takes arbitrary keyword arguments. These will be passed to
-    the :class:`Mock` (or *new_callable*) on construction.
+    :class:`AsyncMock` if the patched object is asynchronous, to
+    :class:`MagicMock` otherwise or to *new_callable* if specified.
 
     ``patch.dict(...)``, ``patch.multiple(...)`` and ``patch.object(...)`` are
     available for alternate use-cases.
diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt
index 708292e..eda7c27 100644
--- a/Lib/idlelib/NEWS.txt
+++ b/Lib/idlelib/NEWS.txt
@@ -3,7 +3,9 @@
 ======================================
 
 
-bpo-39050: Make Settings dialog Help button work again.
+bpo-39388: Settings dialog Cancel button cancels pending changes.
+
+bpo-39050: Settings dialog Help button again displays help text.
 
 bpo-32989: Add tests for editor newline_and_indent_event method.
 Remove unneeded arguments and dead code from pyparse
diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py
index 0e007b5..2f95c9c 100644
--- a/Lib/idlelib/configdialog.py
+++ b/Lib/idlelib/configdialog.py
@@ -191,6 +191,7 @@
         Methods:
             destroy: inherited
         """
+        changes.clear()
         self.destroy()
 
     def destroy(self):
diff --git a/Lib/idlelib/idle_test/test_configdialog.py b/Lib/idlelib/idle_test/test_configdialog.py
index 7c575d0..817a3521 100644
--- a/Lib/idlelib/idle_test/test_configdialog.py
+++ b/Lib/idlelib/idle_test/test_configdialog.py
@@ -47,17 +47,24 @@
     root.destroy()
     root = dialog = None
 
-class ConfigDialogTest(unittest.TestCase):
 
-    def test_help(self):
+class DialogTest(unittest.TestCase):
+
+    @mock.patch(__name__+'.dialog.destroy', new_callable=Func)
+    def test_cancel(self, destroy):
+        changes['main']['something'] = 1
+        dialog.cancel()
+        self.assertEqual(changes['main'], {})
+        self.assertEqual(destroy.called, 1)
+
+    @mock.patch('idlelib.configdialog.view_text', new_callable=Func)
+    def test_help(self, view):
         dialog.note.select(dialog.keyspage)
-        saved = configdialog.view_text
-        view = configdialog.view_text = Func()
         dialog.help()
         s = view.kwds['contents']
-        self.assertTrue(s.startswith('When you click'))
-        self.assertTrue(s.endswith('a different name.\n'))
-        configdialog.view_text = saved
+        self.assertTrue(s.startswith('When you click') and
+                        s.endswith('a different name.\n'))
+
 
 class FontPageTest(unittest.TestCase):
     """Test that font widgets enable users to make font changes.
diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
index 92b596f..a97542a 100644
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -46,6 +46,8 @@
 def _is_async_obj(obj):
     if _is_instance_mock(obj) and not isinstance(obj, AsyncMock):
         return False
+    if hasattr(obj, '__func__'):
+        obj = getattr(obj, '__func__')
     return asyncio.iscoroutinefunction(obj) or inspect.isawaitable(obj)
 
 
@@ -1728,7 +1730,8 @@
     "as"; very useful if `patch` is creating a mock object for you.
 
     `patch` takes arbitrary keyword arguments. These will be passed to
-    the `Mock` (or `new_callable`) on construction.
+    `AsyncMock` if the patched object is asynchronous, to `MagicMock`
+    otherwise or to `new_callable` if specified.
 
     `patch.dict(...)`, `patch.multiple(...)` and `patch.object(...)` are
     available for alternate use-cases.
diff --git a/Lib/unittest/test/testmock/testasync.py b/Lib/unittest/test/testmock/testasync.py
index 73d31a2..43b8749 100644
--- a/Lib/unittest/test/testmock/testasync.py
+++ b/Lib/unittest/test/testmock/testasync.py
@@ -19,6 +19,15 @@
     def normal_method(self):
         pass
 
+    @classmethod
+    async def async_class_method(cls):
+        pass
+
+    @staticmethod
+    async def async_static_method():
+        pass
+
+
 class AwaitableClass:
     def __await__(self):
         yield
@@ -71,6 +80,20 @@
 
         test_async()
 
+    def test_is_AsyncMock_patch_staticmethod(self):
+        @patch.object(AsyncClass, 'async_static_method')
+        def test_async(mock_method):
+            self.assertIsInstance(mock_method, AsyncMock)
+
+        test_async()
+
+    def test_is_AsyncMock_patch_classmethod(self):
+        @patch.object(AsyncClass, 'async_class_method')
+        def test_async(mock_method):
+            self.assertIsInstance(mock_method, AsyncMock)
+
+        test_async()
+
     def test_async_def_patch(self):
         @patch(f"{__name__}.async_func", return_value=1)
         @patch(f"{__name__}.async_func_args", return_value=2)
diff --git a/Misc/NEWS.d/next/IDLE/2020-01-25-02-26-45.bpo-39388.x4TQNh.rst b/Misc/NEWS.d/next/IDLE/2020-01-25-02-26-45.bpo-39388.x4TQNh.rst
new file mode 100644
index 0000000..42bbfb1
--- /dev/null
+++ b/Misc/NEWS.d/next/IDLE/2020-01-25-02-26-45.bpo-39388.x4TQNh.rst
@@ -0,0 +1 @@
+IDLE Settings Cancel button now cancels pending changes
diff --git a/Misc/NEWS.d/next/Library/2020-01-24-13-24-35.bpo-39082.qKgrq_.rst b/Misc/NEWS.d/next/Library/2020-01-24-13-24-35.bpo-39082.qKgrq_.rst
new file mode 100644
index 0000000..52c4ee1
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-01-24-13-24-35.bpo-39082.qKgrq_.rst
@@ -0,0 +1 @@
+Allow AsyncMock to correctly patch static/class methods