Merge tag 'v3.8.0a2'

Python 3.8.0a2
diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst
index 4e55c1a..0ced5a5 100644
--- a/Doc/c-api/dict.rst
+++ b/Doc/c-api/dict.rst
@@ -119,7 +119,7 @@
    To get error reporting use :c:func:`PyDict_GetItemWithError()` instead.
 
 
-.. c:function:: PyObject* PyDict_SetDefault(PyObject *p, PyObject *key, PyObject *default)
+.. c:function:: PyObject* PyDict_SetDefault(PyObject *p, PyObject *key, PyObject *defaultobj)
 
    This is the same as the Python-level :meth:`dict.setdefault`.  If present, it
    returns the value corresponding to *key* from the dictionary *p*.  If the key
diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst
index 5b1f386..8093f4b 100644
--- a/Doc/c-api/long.rst
+++ b/Doc/c-api/long.rst
@@ -131,20 +131,28 @@
       single: OverflowError (built-in exception)
 
    Return a C :c:type:`long` representation of *obj*.  If *obj* is not an
-   instance of :c:type:`PyLongObject`, first call its :meth:`__int__` method
-   (if present) to convert it to a :c:type:`PyLongObject`.
+   instance of :c:type:`PyLongObject`, first call its :meth:`__index__` or
+   :meth:`__int__` method (if present) to convert it to a
+   :c:type:`PyLongObject`.
 
    Raise :exc:`OverflowError` if the value of *obj* is out of range for a
    :c:type:`long`.
 
    Returns ``-1`` on error.  Use :c:func:`PyErr_Occurred` to disambiguate.
 
+   .. versionchanged:: 3.8
+      Use :meth:`__index__` if available.
+
+   .. deprecated:: 3.8
+      Using :meth:`__int__` is deprecated.
+
 
 .. c:function:: long PyLong_AsLongAndOverflow(PyObject *obj, int *overflow)
 
    Return a C :c:type:`long` representation of *obj*.  If *obj* is not an
-   instance of :c:type:`PyLongObject`, first call its :meth:`__int__` method
-   (if present) to convert it to a :c:type:`PyLongObject`.
+   instance of :c:type:`PyLongObject`, first call its :meth:`__index__` or
+   :meth:`__int__` method (if present) to convert it to a
+   :c:type:`PyLongObject`.
 
    If the value of *obj* is greater than :const:`LONG_MAX` or less than
    :const:`LONG_MIN`, set *\*overflow* to ``1`` or ``-1``, respectively, and
@@ -153,6 +161,12 @@
 
    Returns ``-1`` on error.  Use :c:func:`PyErr_Occurred` to disambiguate.
 
+   .. versionchanged:: 3.8
+      Use :meth:`__index__` if available.
+
+   .. deprecated:: 3.8
+      Using :meth:`__int__` is deprecated.
+
 
 .. c:function:: long long PyLong_AsLongLong(PyObject *obj)
 
@@ -160,20 +174,28 @@
       single: OverflowError (built-in exception)
 
    Return a C :c:type:`long long` representation of *obj*.  If *obj* is not an
-   instance of :c:type:`PyLongObject`, first call its :meth:`__int__` method
-   (if present) to convert it to a :c:type:`PyLongObject`.
+   instance of :c:type:`PyLongObject`, first call its :meth:`__index__` or
+   :meth:`__int__` method (if present) to convert it to a
+   :c:type:`PyLongObject`.
 
    Raise :exc:`OverflowError` if the value of *obj* is out of range for a
    :c:type:`long`.
 
    Returns ``-1`` on error.  Use :c:func:`PyErr_Occurred` to disambiguate.
 
+   .. versionchanged:: 3.8
+      Use :meth:`__index__` if available.
+
+   .. deprecated:: 3.8
+      Using :meth:`__int__` is deprecated.
+
 
 .. c:function:: long long PyLong_AsLongLongAndOverflow(PyObject *obj, int *overflow)
 
    Return a C :c:type:`long long` representation of *obj*.  If *obj* is not an
-   instance of :c:type:`PyLongObject`, first call its :meth:`__int__` method
-   (if present) to convert it to a :c:type:`PyLongObject`.
+   instance of :c:type:`PyLongObject`, first call its :meth:`__index__` or
+   :meth:`__int__` method (if present) to convert it to a
+   :c:type:`PyLongObject`.
 
    If the value of *obj* is greater than :const:`PY_LLONG_MAX` or less than
    :const:`PY_LLONG_MIN`, set *\*overflow* to ``1`` or ``-1``, respectively,
@@ -184,6 +206,12 @@
 
    .. versionadded:: 3.2
 
+   .. versionchanged:: 3.8
+      Use :meth:`__index__` if available.
+
+   .. deprecated:: 3.8
+      Using :meth:`__int__` is deprecated.
+
 
 .. c:function:: Py_ssize_t PyLong_AsSsize_t(PyObject *pylong)
 
@@ -253,26 +281,40 @@
 .. c:function:: unsigned long PyLong_AsUnsignedLongMask(PyObject *obj)
 
    Return a C :c:type:`unsigned long` representation of *obj*.  If *obj*
-   is not an instance of :c:type:`PyLongObject`, first call its :meth:`__int__`
-   method (if present) to convert it to a :c:type:`PyLongObject`.
+   is not an instance of :c:type:`PyLongObject`, first call its
+   :meth:`__index__` or :meth:`__int__` method (if present) to convert
+   it to a :c:type:`PyLongObject`.
 
    If the value of *obj* is out of range for an :c:type:`unsigned long`,
    return the reduction of that value modulo ``ULONG_MAX + 1``.
 
    Returns ``-1`` on error.  Use :c:func:`PyErr_Occurred` to disambiguate.
 
+   .. versionchanged:: 3.8
+      Use :meth:`__index__` if available.
+
+   .. deprecated:: 3.8
+      Using :meth:`__int__` is deprecated.
+
 
 .. c:function:: unsigned long long PyLong_AsUnsignedLongLongMask(PyObject *obj)
 
    Return a C :c:type:`unsigned long long` representation of *obj*.  If *obj*
-   is not an instance of :c:type:`PyLongObject`, first call its :meth:`__int__`
-   method (if present) to convert it to a :c:type:`PyLongObject`.
+   is not an instance of :c:type:`PyLongObject`, first call its
+   :meth:`__index__` or :meth:`__int__` method (if present) to convert
+   it to a :c:type:`PyLongObject`.
 
    If the value of *obj* is out of range for an :c:type:`unsigned long long`,
    return the reduction of that value modulo ``PY_ULLONG_MAX + 1``.
 
    Returns ``-1`` on error.  Use :c:func:`PyErr_Occurred` to disambiguate.
 
+   .. versionchanged:: 3.8
+      Use :meth:`__index__` if available.
+
+   .. deprecated:: 3.8
+      Using :meth:`__int__` is deprecated.
+
 
 .. c:function:: double PyLong_AsDouble(PyObject *pylong)
 
diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst
index 296b21c..9fb220b 100644
--- a/Doc/c-api/number.rst
+++ b/Doc/c-api/number.rst
@@ -11,6 +11,9 @@
    Returns ``1`` if the object *o* provides numeric protocols, and false otherwise.
    This function always succeeds.
 
+   .. versionchanged:: 3.8
+      Returns ``1`` if *o* is an index integer.
+
 
 .. c:function:: PyObject* PyNumber_Add(PyObject *o1, PyObject *o2)
 
diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst
index 047812e..7bc00ff 100644
--- a/Doc/faq/programming.rst
+++ b/Doc/faq/programming.rst
@@ -1317,9 +1317,6 @@
 that final assignment still results in an error, because tuples are immutable.
 
 
-Dictionaries
-============
-
 I want to do a complicated sort: can you do a Schwartzian Transform in Python?
 ------------------------------------------------------------------------------
 
diff --git a/Doc/library/re.rst b/Doc/library/re.rst
index b512830..4ac5dee 100644
--- a/Doc/library/re.rst
+++ b/Doc/library/re.rst
@@ -573,7 +573,8 @@
 only inside character classes.)
 
 ``'\u'``, ``'\U'``, and ``'\N'`` escape sequences are only recognized in Unicode
-patterns.  In bytes patterns they are errors.
+patterns.  In bytes patterns they are errors.  Unknown escapes of ASCII
+letters are reserved for future use and treated as errors.
 
 Octal escapes are included in a limited form.  If the first digit is a 0, or if
 there are three octal digits, it is considered an octal escape. Otherwise, it is
@@ -850,7 +851,9 @@
    *string* is returned unchanged.  *repl* can be a string or a function; if it is
    a string, any backslash escapes in it are processed.  That is, ``\n`` is
    converted to a single newline character, ``\r`` is converted to a carriage return, and
-   so forth.  Unknown escapes such as ``\&`` are left alone.  Backreferences, such
+   so forth.  Unknown escapes of ASCII letters are reserved for future use and
+   treated as errors.  Other unknown escapes such as ``\&`` are left alone.
+   Backreferences, such
    as ``\6``, are replaced with the substring matched by group 6 in the pattern.
    For example::
 
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index 68a4457..154fd66 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -458,6 +458,17 @@
 
   (Contributed by Antoine Pitrou in :issue:`32430`.)
 
+* Functions that convert Python number to C integer like
+  :c:func:`PyLong_AsLong` and argument parsing functions like
+  :c:func:`PyArg_ParseTuple` with integer converting format units like ``'i'``
+  will now use the :meth:`~object.__index__` special method instead of
+  :meth:`~object.__int__`, if available.  The deprecation warning will be
+  emitted for objects with the ``__int__()`` method but without the
+  ``__index__()`` method (like :class:`~decimal.Decimal` and
+  :class:`~fractions.Fraction`).  :c:func:`PyNumber_Check` will now return
+  ``1`` for objects implementing ``__index__()``.
+  (Contributed by Serhiy Storchaka in :issue:`36048`.)
+
 
 Deprecated
 ==========
@@ -508,6 +519,15 @@
 * The :meth:`~threading.Thread.isAlive()` method of :class:`threading.Thread` has been deprecated.
   (Contributed by Dong-hee Na in :issue:`35283`.)
 
+* Many builtin and extension functions that take integer arguments will
+  now emit a deprecation warning for :class:`~decimal.Decimal`\ s,
+  :class:`~fractions.Fraction`\ s and any other objects that can be converted
+  to integers only with a loss (e.g. that have the :meth:`~object.__int__`
+  method but do not have the :meth:`~object.__index__` method).  In future
+  version they will be errors.
+  (Contributed by Serhiy Storchaka in :issue:`36048`.)
+
+
 API and Feature Removals
 ========================
 
diff --git a/Include/cpython/dictobject.h b/Include/cpython/dictobject.h
index 4c7457c..64c012a 100644
--- a/Include/cpython/dictobject.h
+++ b/Include/cpython/dictobject.h
@@ -35,6 +35,7 @@
                                        Py_hash_t hash);
 PyAPI_FUNC(PyObject *) _PyDict_GetItemIdWithError(PyObject *dp,
                                                   struct _Py_Identifier *key);
+PyAPI_FUNC(PyObject *) _PyDict_GetItemStringWithError(PyObject *, const char *);
 PyAPI_FUNC(PyObject *) PyDict_SetDefault(
     PyObject *mp, PyObject *key, PyObject *defaultobj);
 PyAPI_FUNC(int) _PyDict_SetItem_KnownHash(PyObject *mp, PyObject *key,
diff --git a/Include/internal/pycore_tupleobject.h b/Include/internal/pycore_tupleobject.h
index fdd7414..d0c5b62 100644
--- a/Include/internal/pycore_tupleobject.h
+++ b/Include/internal/pycore_tupleobject.h
@@ -11,6 +11,7 @@
 #include "tupleobject.h"
 
 #define _PyTuple_ITEMS(op) (_PyTuple_CAST(op)->ob_item)
+PyAPI_FUNC(PyObject *) _PyTuple_FromArray(PyObject *const *, Py_ssize_t);
 
 #ifdef __cplusplus
 }
diff --git a/Include/longobject.h b/Include/longobject.h
index 82c06c9..b696f54 100644
--- a/Include/longobject.h
+++ b/Include/longobject.h
@@ -177,7 +177,17 @@
    nb_int slot is not available or the result of the call to nb_int
    returns something not of type int.
 */
-PyAPI_FUNC(PyLongObject *)_PyLong_FromNbInt(PyObject *);
+PyAPI_FUNC(PyObject *) _PyLong_FromNbInt(PyObject *);
+
+/* Convert the given object to a PyLongObject using the nb_index or
+   nb_int slots, if available (the latter is deprecated).
+   Raise TypeError if either nb_index and nb_int slots are not
+   available or the result of the call to nb_index or nb_int
+   returns something not of type int.
+   Should be replaced with PyNumber_Index after the end of the
+   deprecation period.
+*/
+PyAPI_FUNC(PyObject *) _PyLong_FromNbIndexOrNbInt(PyObject *);
 
 /* _PyLong_Format: Convert the long to a string object with given base,
    appending a base prefix of 0[box] if base is 2, 8 or 16. */
diff --git a/Lib/ctypes/test/test_numbers.py b/Lib/ctypes/test/test_numbers.py
index 09eef90..c6d843b 100644
--- a/Lib/ctypes/test/test_numbers.py
+++ b/Lib/ctypes/test/test_numbers.py
@@ -124,12 +124,18 @@
         class IntLike(object):
             def __int__(self):
                 return 2
-        i = IntLike()
+        d = IntLike()
+        class IndexLike(object):
+            def __index__(self):
+                return 2
+        i = IndexLike()
         # integers cannot be constructed from floats,
         # but from integer-like objects
         for t in signed_types + unsigned_types:
             self.assertRaises(TypeError, t, 3.14)
             self.assertRaises(TypeError, t, f)
+            with self.assertWarns(DeprecationWarning):
+                self.assertEqual(t(d).value, 2)
             self.assertEqual(t(i).value, 2)
 
     def test_sizes(self):
diff --git a/Lib/datetime.py b/Lib/datetime.py
index 89c32c0..85bfa48 100644
--- a/Lib/datetime.py
+++ b/Lib/datetime.py
@@ -379,19 +379,34 @@
 def _check_int_field(value):
     if isinstance(value, int):
         return value
-    if not isinstance(value, float):
-        try:
-            value = value.__int__()
-        except AttributeError:
-            pass
-        else:
-            if isinstance(value, int):
-                return value
+    if isinstance(value, float):
+        raise TypeError('integer argument expected, got float')
+    try:
+        value = value.__index__()
+    except AttributeError:
+        pass
+    else:
+        if not isinstance(value, int):
+            raise TypeError('__index__ returned non-int (type %s)' %
+                            type(value).__name__)
+        return value
+    orig = value
+    try:
+        value = value.__int__()
+    except AttributeError:
+        pass
+    else:
+        if not isinstance(value, int):
             raise TypeError('__int__ returned non-int (type %s)' %
                             type(value).__name__)
-        raise TypeError('an integer is required (got type %s)' %
-                        type(value).__name__)
-    raise TypeError('integer argument expected, got float')
+        import warnings
+        warnings.warn("an integer is required (got type %s)"  %
+                      type(orig).__name__,
+                      DeprecationWarning,
+                      stacklevel=2)
+        return value
+    raise TypeError('an integer is required (got type %s)' %
+                    type(value).__name__)
 
 def _check_date_fields(year, month, day):
     year = _check_int_field(year)
diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py
index 958b336..715f0ea 100644
--- a/Lib/test/datetimetester.py
+++ b/Lib/test/datetimetester.py
@@ -4918,8 +4918,9 @@
         for xx in [decimal.Decimal(10),
                    decimal.Decimal('10.9'),
                    Number(10)]:
-            self.assertEqual(datetime(10, 10, 10, 10, 10, 10, 10),
-                             datetime(xx, xx, xx, xx, xx, xx, xx))
+            with self.assertWarns(DeprecationWarning):
+                self.assertEqual(datetime(10, 10, 10, 10, 10, 10, 10),
+                                 datetime(xx, xx, xx, xx, xx, xx, xx))
 
         with self.assertRaisesRegex(TypeError, '^an integer is required '
                                               r'\(got type str\)$'):
@@ -4927,7 +4928,7 @@
 
         f10 = Number(10.9)
         with self.assertRaisesRegex(TypeError, '^__int__ returned non-int '
-                                              r'\(type float\)$'):
+                                               r'\(type float\)$'):
             datetime(10, 10, f10)
 
         class Float(float):
diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py
index 7f402f8..2399980 100644
--- a/Lib/test/test_array.py
+++ b/Lib/test/test_array.py
@@ -1242,6 +1242,8 @@
 class Intable:
     def __init__(self, num):
         self._num = num
+    def __index__(self):
+        return self._num
     def __int__(self):
         return self._num
     def __sub__(self, other):
diff --git a/Lib/test/test_getargs2.py b/Lib/test/test_getargs2.py
index d9bcb1d..07e2d15 100644
--- a/Lib/test/test_getargs2.py
+++ b/Lib/test/test_getargs2.py
@@ -53,6 +53,27 @@
 LLONG_MIN = -2**63
 ULLONG_MAX = 2**64-1
 
+class Index:
+    def __index__(self):
+        return 99
+
+class IndexIntSubclass(int):
+    def __index__(self):
+        return 99
+
+class BadIndex:
+    def __index__(self):
+        return 1.0
+
+class BadIndex2:
+    def __index__(self):
+        return True
+
+class BadIndex3(int):
+    def __index__(self):
+        return True
+
+
 class Int:
     def __int__(self):
         return 99
@@ -134,7 +155,14 @@
         from _testcapi import getargs_b
         # b returns 'unsigned char', and does range checking (0 ... UCHAR_MAX)
         self.assertRaises(TypeError, getargs_b, 3.14)
-        self.assertEqual(99, getargs_b(Int()))
+        self.assertEqual(99, getargs_b(Index()))
+        self.assertEqual(0, getargs_b(IndexIntSubclass()))
+        self.assertRaises(TypeError, getargs_b, BadIndex())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_b(BadIndex2()))
+        self.assertEqual(0, getargs_b(BadIndex3()))
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(99, getargs_b(Int()))
         self.assertEqual(0, getargs_b(IntSubclass()))
         self.assertRaises(TypeError, getargs_b, BadInt())
         with self.assertWarns(DeprecationWarning):
@@ -153,7 +181,14 @@
         from _testcapi import getargs_B
         # B returns 'unsigned char', no range checking
         self.assertRaises(TypeError, getargs_B, 3.14)
-        self.assertEqual(99, getargs_B(Int()))
+        self.assertEqual(99, getargs_B(Index()))
+        self.assertEqual(0, getargs_B(IndexIntSubclass()))
+        self.assertRaises(TypeError, getargs_B, BadIndex())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_B(BadIndex2()))
+        self.assertEqual(0, getargs_B(BadIndex3()))
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(99, getargs_B(Int()))
         self.assertEqual(0, getargs_B(IntSubclass()))
         self.assertRaises(TypeError, getargs_B, BadInt())
         with self.assertWarns(DeprecationWarning):
@@ -172,7 +207,14 @@
         from _testcapi import getargs_H
         # H returns 'unsigned short', no range checking
         self.assertRaises(TypeError, getargs_H, 3.14)
-        self.assertEqual(99, getargs_H(Int()))
+        self.assertEqual(99, getargs_H(Index()))
+        self.assertEqual(0, getargs_H(IndexIntSubclass()))
+        self.assertRaises(TypeError, getargs_H, BadIndex())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_H(BadIndex2()))
+        self.assertEqual(0, getargs_H(BadIndex3()))
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(99, getargs_H(Int()))
         self.assertEqual(0, getargs_H(IntSubclass()))
         self.assertRaises(TypeError, getargs_H, BadInt())
         with self.assertWarns(DeprecationWarning):
@@ -192,7 +234,14 @@
         from _testcapi import getargs_I
         # I returns 'unsigned int', no range checking
         self.assertRaises(TypeError, getargs_I, 3.14)
-        self.assertEqual(99, getargs_I(Int()))
+        self.assertEqual(99, getargs_I(Index()))
+        self.assertEqual(0, getargs_I(IndexIntSubclass()))
+        self.assertRaises(TypeError, getargs_I, BadIndex())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_I(BadIndex2()))
+        self.assertEqual(0, getargs_I(BadIndex3()))
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(99, getargs_I(Int()))
         self.assertEqual(0, getargs_I(IntSubclass()))
         self.assertRaises(TypeError, getargs_I, BadInt())
         with self.assertWarns(DeprecationWarning):
@@ -213,6 +262,11 @@
         # k returns 'unsigned long', no range checking
         # it does not accept float, or instances with __int__
         self.assertRaises(TypeError, getargs_k, 3.14)
+        self.assertRaises(TypeError, getargs_k, Index())
+        self.assertEqual(0, getargs_k(IndexIntSubclass()))
+        self.assertRaises(TypeError, getargs_k, BadIndex())
+        self.assertRaises(TypeError, getargs_k, BadIndex2())
+        self.assertEqual(0, getargs_k(BadIndex3()))
         self.assertRaises(TypeError, getargs_k, Int())
         self.assertEqual(0, getargs_k(IntSubclass()))
         self.assertRaises(TypeError, getargs_k, BadInt())
@@ -233,7 +287,14 @@
         from _testcapi import getargs_h
         # h returns 'short', and does range checking (SHRT_MIN ... SHRT_MAX)
         self.assertRaises(TypeError, getargs_h, 3.14)
-        self.assertEqual(99, getargs_h(Int()))
+        self.assertEqual(99, getargs_h(Index()))
+        self.assertEqual(0, getargs_h(IndexIntSubclass()))
+        self.assertRaises(TypeError, getargs_h, BadIndex())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_h(BadIndex2()))
+        self.assertEqual(0, getargs_h(BadIndex3()))
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(99, getargs_h(Int()))
         self.assertEqual(0, getargs_h(IntSubclass()))
         self.assertRaises(TypeError, getargs_h, BadInt())
         with self.assertWarns(DeprecationWarning):
@@ -252,7 +313,14 @@
         from _testcapi import getargs_i
         # i returns 'int', and does range checking (INT_MIN ... INT_MAX)
         self.assertRaises(TypeError, getargs_i, 3.14)
-        self.assertEqual(99, getargs_i(Int()))
+        self.assertEqual(99, getargs_i(Index()))
+        self.assertEqual(0, getargs_i(IndexIntSubclass()))
+        self.assertRaises(TypeError, getargs_i, BadIndex())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_i(BadIndex2()))
+        self.assertEqual(0, getargs_i(BadIndex3()))
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(99, getargs_i(Int()))
         self.assertEqual(0, getargs_i(IntSubclass()))
         self.assertRaises(TypeError, getargs_i, BadInt())
         with self.assertWarns(DeprecationWarning):
@@ -271,7 +339,14 @@
         from _testcapi import getargs_l
         # l returns 'long', and does range checking (LONG_MIN ... LONG_MAX)
         self.assertRaises(TypeError, getargs_l, 3.14)
-        self.assertEqual(99, getargs_l(Int()))
+        self.assertEqual(99, getargs_l(Index()))
+        self.assertEqual(0, getargs_l(IndexIntSubclass()))
+        self.assertRaises(TypeError, getargs_l, BadIndex())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_l(BadIndex2()))
+        self.assertEqual(0, getargs_l(BadIndex3()))
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(99, getargs_l(Int()))
         self.assertEqual(0, getargs_l(IntSubclass()))
         self.assertRaises(TypeError, getargs_l, BadInt())
         with self.assertWarns(DeprecationWarning):
@@ -291,6 +366,12 @@
         # n returns 'Py_ssize_t', and does range checking
         # (PY_SSIZE_T_MIN ... PY_SSIZE_T_MAX)
         self.assertRaises(TypeError, getargs_n, 3.14)
+        self.assertEqual(99, getargs_n(Index()))
+        self.assertEqual(0, getargs_n(IndexIntSubclass()))
+        self.assertRaises(TypeError, getargs_n, BadIndex())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_n(BadIndex2()))
+        self.assertEqual(0, getargs_n(BadIndex3()))
         self.assertRaises(TypeError, getargs_n, Int())
         self.assertEqual(0, getargs_n(IntSubclass()))
         self.assertRaises(TypeError, getargs_n, BadInt())
@@ -313,7 +394,14 @@
         # ... LLONG_MAX)
         self.assertRaises(TypeError, getargs_L, 3.14)
         self.assertRaises(TypeError, getargs_L, "Hello")
-        self.assertEqual(99, getargs_L(Int()))
+        self.assertEqual(99, getargs_L(Index()))
+        self.assertEqual(0, getargs_L(IndexIntSubclass()))
+        self.assertRaises(TypeError, getargs_L, BadIndex())
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(1, getargs_L(BadIndex2()))
+        self.assertEqual(0, getargs_L(BadIndex3()))
+        with self.assertWarns(DeprecationWarning):
+            self.assertEqual(99, getargs_L(Int()))
         self.assertEqual(0, getargs_L(IntSubclass()))
         self.assertRaises(TypeError, getargs_L, BadInt())
         with self.assertWarns(DeprecationWarning):
@@ -332,6 +420,11 @@
         from _testcapi import getargs_K
         # K return 'unsigned long long', no range checking
         self.assertRaises(TypeError, getargs_K, 3.14)
+        self.assertRaises(TypeError, getargs_K, Index())
+        self.assertEqual(0, getargs_K(IndexIntSubclass()))
+        self.assertRaises(TypeError, getargs_K, BadIndex())
+        self.assertRaises(TypeError, getargs_K, BadIndex2())
+        self.assertEqual(0, getargs_K(BadIndex3()))
         self.assertRaises(TypeError, getargs_K, Int())
         self.assertEqual(0, getargs_K(IntSubclass()))
         self.assertRaises(TypeError, getargs_K, BadInt())
diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py
index c048b71..307ca36 100644
--- a/Lib/test/test_int.py
+++ b/Lib/test/test_int.py
@@ -385,7 +385,8 @@
                 class TruncReturnsNonInt(base):
                     def __trunc__(self):
                         return Integral()
-                self.assertEqual(int(TruncReturnsNonInt()), 42)
+                with self.assertWarns(DeprecationWarning):
+                    self.assertEqual(int(TruncReturnsNonInt()), 42)
 
                 class NonIntegral(trunc_result_base):
                     def __trunc__(self):
diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py
index bf5d64c..f828b4c 100644
--- a/Lib/test/test_zlib.py
+++ b/Lib/test/test_zlib.py
@@ -914,7 +914,7 @@
 
 
 class CustomInt:
-    def __int__(self):
+    def __index__(self):
         return 100
 
 
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-02-20-08-51-04.bpo-36048.I3LJt9.rst b/Misc/NEWS.d/next/Core and Builtins/2019-02-20-08-51-04.bpo-36048.I3LJt9.rst
new file mode 100644
index 0000000..d032e84
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-02-20-08-51-04.bpo-36048.I3LJt9.rst
@@ -0,0 +1,4 @@
+The :meth:`~object.__index__` special method will be used instead of
+:meth:`~object.__int__` for implicit conversion of Python numbers to C
+integers.  Using the ``__int__()`` method in implicit conversions has been
+deprecated.
diff --git a/Modules/_csv.c b/Modules/_csv.c
index 6c00974..d86f63e 100644
--- a/Modules/_csv.c
+++ b/Modules/_csv.c
@@ -132,7 +132,7 @@
 {
     PyObject *dialect_obj;
 
-    dialect_obj = PyDict_GetItem(_csvstate_global->dialects, name_obj);
+    dialect_obj = PyDict_GetItemWithError(_csvstate_global->dialects, name_obj);
     if (dialect_obj == NULL) {
         if (!PyErr_Occurred())
             PyErr_Format(_csvstate_global->error_obj, "unknown dialect");
@@ -1434,8 +1434,12 @@
 static PyObject *
 csv_unregister_dialect(PyObject *module, PyObject *name_obj)
 {
-    if (PyDict_DelItem(_csvstate_global->dialects, name_obj) < 0)
-        return PyErr_Format(_csvstate_global->error_obj, "unknown dialect");
+    if (PyDict_DelItem(_csvstate_global->dialects, name_obj) < 0) {
+        if (PyErr_ExceptionMatches(PyExc_KeyError)) {
+            PyErr_Format(_csvstate_global->error_obj, "unknown dialect");
+        }
+        return NULL;
+    }
     Py_RETURN_NONE;
 }
 
diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c
index b1a9629..1e58cd0 100644
--- a/Modules/_elementtree.c
+++ b/Modules/_elementtree.c
@@ -339,7 +339,7 @@
     if (attrib_str == NULL) {
         return NULL;
     }
-    PyObject *attrib = PyDict_GetItem(kwds, attrib_str);
+    PyObject *attrib = PyDict_GetItemWithError(kwds, attrib_str);
 
     if (attrib) {
         /* If attrib was found in kwds, copy its value and remove it from
@@ -356,7 +356,8 @@
             Py_DECREF(attrib);
             attrib = NULL;
         }
-    } else {
+    }
+    else if (!PyErr_Occurred()) {
         attrib = PyDict_New();
     }
 
@@ -1393,9 +1394,13 @@
     if (!self->extra || self->extra->attrib == Py_None)
         value = default_value;
     else {
-        value = PyDict_GetItem(self->extra->attrib, key);
-        if (!value)
+        value = PyDict_GetItemWithError(self->extra->attrib, key);
+        if (!value) {
+            if (PyErr_Occurred()) {
+                return NULL;
+            }
             value = default_value;
+        }
     }
 
     Py_INCREF(value);
@@ -2848,11 +2853,12 @@
     if (!key)
         return NULL;
 
-    value = PyDict_GetItem(self->names, key);
+    value = PyDict_GetItemWithError(self->names, key);
 
     if (value) {
         Py_INCREF(value);
-    } else {
+    }
+    else if (!PyErr_Occurred()) {
         /* new name.  convert to universal name, and decode as
            necessary */
 
@@ -2974,7 +2980,7 @@
     if (!key)
         return;
 
-    value = PyDict_GetItem(self->entity, key);
+    value = PyDict_GetItemWithError(self->entity, key);
 
     if (value) {
         if (TreeBuilder_CheckExact(self->target))
diff --git a/Modules/_json.c b/Modules/_json.c
index 53e1e88..94a7c0d 100644
--- a/Modules/_json.c
+++ b/Modules/_json.c
@@ -746,12 +746,15 @@
             key = scanstring_unicode(pystr, idx + 1, s->strict, &next_idx);
             if (key == NULL)
                 goto bail;
-            memokey = PyDict_GetItem(s->memo, key);
+            memokey = PyDict_GetItemWithError(s->memo, key);
             if (memokey != NULL) {
                 Py_INCREF(memokey);
                 Py_DECREF(key);
                 key = memokey;
             }
+            else if (PyErr_Occurred()) {
+                goto bail;
+            }
             else {
                 if (PyDict_SetItem(s->memo, key, key) < 0)
                     goto bail;
diff --git a/Modules/_sre.c b/Modules/_sre.c
index 21c41b5..5cea756 100644
--- a/Modules/_sre.c
+++ b/Modules/_sre.c
@@ -1899,15 +1899,7 @@
     void* ptr;
     Py_ssize_t i, j;
 
-    if (index < 0 || index >= self->groups) {
-        /* raise IndexError if we were given a bad group number */
-        PyErr_SetString(
-            PyExc_IndexError,
-            "no such group"
-            );
-        return NULL;
-    }
-
+    assert(0 <= index && index < self->groups);
     index *= 2;
 
     if (self->string == Py_None || self->mark[index] < 0) {
@@ -1940,17 +1932,25 @@
         return 0;
 
     if (PyIndex_Check(index)) {
-        return PyNumber_AsSsize_t(index, NULL);
+        i = PyNumber_AsSsize_t(index, NULL);
     }
+    else {
+        i = -1;
 
-    i = -1;
-
-    if (self->pattern->groupindex) {
-        index = PyDict_GetItem(self->pattern->groupindex, index);
-        if (index && PyLong_Check(index)) {
-            i = PyLong_AsSsize_t(index);
+        if (self->pattern->groupindex) {
+            index = PyDict_GetItemWithError(self->pattern->groupindex, index);
+            if (index && PyLong_Check(index)) {
+                i = PyLong_AsSsize_t(index);
+            }
         }
     }
+    if (i < 0 || i >= self->groups) {
+        /* raise IndexError if we were given a bad group number */
+        if (!PyErr_Occurred()) {
+            PyErr_SetString(PyExc_IndexError, "no such group");
+        }
+        return -1;
+    }
 
     return i;
 }
@@ -1958,7 +1958,13 @@
 static PyObject*
 match_getslice(MatchObject* self, PyObject* index, PyObject* def)
 {
-    return match_getslice_by_index(self, match_getindex(self, index), def);
+    Py_ssize_t i = match_getindex(self, index);
+
+    if (i < 0) {
+        return NULL;
+    }
+
+    return match_getslice_by_index(self, i, def);
 }
 
 /*[clinic input]
@@ -2114,11 +2120,7 @@
 {
     Py_ssize_t index = match_getindex(self, group);
 
-    if (index < 0 || index >= self->groups) {
-        PyErr_SetString(
-            PyExc_IndexError,
-            "no such group"
-            );
+    if (index < 0) {
         return -1;
     }
 
@@ -2141,11 +2143,7 @@
 {
     Py_ssize_t index = match_getindex(self, group);
 
-    if (index < 0 || index >= self->groups) {
-        PyErr_SetString(
-            PyExc_IndexError,
-            "no such group"
-            );
+    if (index < 0) {
         return -1;
     }
 
@@ -2195,11 +2193,7 @@
 {
     Py_ssize_t index = match_getindex(self, group);
 
-    if (index < 0 || index >= self->groups) {
-        PyErr_SetString(
-            PyExc_IndexError,
-            "no such group"
-            );
+    if (index < 0) {
         return NULL;
     }
 
diff --git a/Modules/_struct.c b/Modules/_struct.c
index 5954c13..90839b2 100644
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -2088,12 +2088,15 @@
             return 0;
     }
 
-    s_object = PyDict_GetItem(cache, fmt);
+    s_object = PyDict_GetItemWithError(cache, fmt);
     if (s_object != NULL) {
         Py_INCREF(s_object);
         *ptr = (PyStructObject *)s_object;
         return Py_CLEANUP_SUPPORTED;
     }
+    else if (PyErr_Occurred()) {
+        return 0;
+    }
 
     s_object = PyObject_CallFunctionObjArgs((PyObject *)(&PyStructType), fmt, NULL);
     if (s_object != NULL) {
diff --git a/Modules/_testmultiphase.c b/Modules/_testmultiphase.c
index c6dfc2f..db5bb7d 100644
--- a/Modules/_testmultiphase.c
+++ b/Modules/_testmultiphase.c
@@ -53,11 +53,14 @@
 Example_getattro(ExampleObject *self, PyObject *name)
 {
     if (self->x_attr != NULL) {
-        PyObject *v = PyDict_GetItem(self->x_attr, name);
+        PyObject *v = PyDict_GetItemWithError(self->x_attr, name);
         if (v != NULL) {
             Py_INCREF(v);
             return v;
         }
+        else if (PyErr_Occurred()) {
+            return NULL;
+        }
     }
     return PyObject_GenericGetAttr((PyObject *)self, name);
 }
@@ -72,7 +75,7 @@
     }
     if (v == NULL) {
         int rv = PyDict_DelItemString(self->x_attr, name);
-        if (rv < 0)
+        if (rv < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
             PyErr_SetString(PyExc_AttributeError,
                 "delete non-existing Example attribute");
         return rv;
diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c
index aacce69..73babaf 100644
--- a/Modules/_threadmodule.c
+++ b/Modules/_threadmodule.c
@@ -814,8 +814,11 @@
         return NULL;
     }
 
-    dummy = PyDict_GetItem(tdict, self->key);
+    dummy = PyDict_GetItemWithError(tdict, self->key);
     if (dummy == NULL) {
+        if (PyErr_Occurred()) {
+            return NULL;
+        }
         ldict = _local_create_dummy(self);
         if (ldict == NULL)
             return NULL;
@@ -931,14 +934,17 @@
             (PyObject *)self, name, ldict, 0);
 
     /* Optimization: just look in dict ourselves */
-    value = PyDict_GetItem(ldict, name);
-    if (value == NULL)
-        /* Fall back on generic to get __class__ and __dict__ */
-        return _PyObject_GenericGetAttrWithDict(
-            (PyObject *)self, name, ldict, 0);
-
-    Py_INCREF(value);
-    return value;
+    value = PyDict_GetItemWithError(ldict, name);
+    if (value != NULL) {
+        Py_INCREF(value);
+        return value;
+    }
+    else if (PyErr_Occurred()) {
+        return NULL;
+    }
+    /* Fall back on generic to get __class__ and __dict__ */
+    return _PyObject_GenericGetAttrWithDict(
+        (PyObject *)self, name, ldict, 0);
 }
 
 /* Called when a dummy is destroyed. */
@@ -958,7 +964,7 @@
     self = (localobject *) obj;
     if (self->dummies != NULL) {
         PyObject *ldict;
-        ldict = PyDict_GetItem(self->dummies, dummyweakref);
+        ldict = PyDict_GetItemWithError(self->dummies, dummyweakref);
         if (ldict != NULL) {
             PyDict_DelItem(self->dummies, dummyweakref);
         }
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index f5f461b..a5ba27c 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -340,7 +340,7 @@
                         "array item must be integer");
         return NULL;
     }
-    return (PyObject *)_PyLong_FromNbInt(v);
+    return _PyLong_FromNbIndexOrNbInt(v);
 }
 
 static int
diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c
index 581ae2c..536f7fa 100644
--- a/Modules/itertoolsmodule.c
+++ b/Modules/itertoolsmodule.c
@@ -1,6 +1,7 @@
 
 #define PY_SSIZE_T_CLEAN
 #include "Python.h"
+#include "pycore_tupleobject.h"
 #include "structmember.h"
 
 /* Itertools module written and maintained
@@ -2239,15 +2240,10 @@
         /* Copy the previous result tuple or re-use it if available */
         if (Py_REFCNT(result) > 1) {
             PyObject *old_result = result;
-            result = PyTuple_New(npools);
+            result = _PyTuple_FromArray(_PyTuple_ITEMS(old_result), npools);
             if (result == NULL)
                 goto empty;
             lz->result = result;
-            for (i=0; i < npools; i++) {
-                elem = PyTuple_GET_ITEM(old_result, i);
-                Py_INCREF(elem);
-                PyTuple_SET_ITEM(result, i, elem);
-            }
             Py_DECREF(old_result);
         }
         /* Now, we've got the only copy so we can update it in-place */
@@ -2569,15 +2565,10 @@
         /* Copy the previous result tuple or re-use it if available */
         if (Py_REFCNT(result) > 1) {
             PyObject *old_result = result;
-            result = PyTuple_New(r);
+            result = _PyTuple_FromArray(_PyTuple_ITEMS(old_result), r);
             if (result == NULL)
                 goto empty;
             co->result = result;
-            for (i=0; i<r ; i++) {
-                elem = PyTuple_GET_ITEM(old_result, i);
-                Py_INCREF(elem);
-                PyTuple_SET_ITEM(result, i, elem);
-            }
             Py_DECREF(old_result);
         }
         /* Now, we've got the only copy so we can update it in-place
@@ -2910,15 +2901,10 @@
         /* Copy the previous result tuple or re-use it if available */
         if (Py_REFCNT(result) > 1) {
             PyObject *old_result = result;
-            result = PyTuple_New(r);
+            result = _PyTuple_FromArray(_PyTuple_ITEMS(old_result), r);
             if (result == NULL)
                 goto empty;
             co->result = result;
-            for (i=0; i<r ; i++) {
-                elem = PyTuple_GET_ITEM(old_result, i);
-                Py_INCREF(elem);
-                PyTuple_SET_ITEM(result, i, elem);
-            }
             Py_DECREF(old_result);
         }
         /* Now, we've got the only copy so we can update it in-place CPython's
@@ -3258,15 +3244,10 @@
         /* Copy the previous result tuple or re-use it if available */
         if (Py_REFCNT(result) > 1) {
             PyObject *old_result = result;
-            result = PyTuple_New(r);
+            result = _PyTuple_FromArray(_PyTuple_ITEMS(old_result), r);
             if (result == NULL)
                 goto empty;
             po->result = result;
-            for (i=0; i<r ; i++) {
-                elem = PyTuple_GET_ITEM(old_result, i);
-                Py_INCREF(elem);
-                PyTuple_SET_ITEM(result, i, elem);
-            }
             Py_DECREF(old_result);
         }
         /* Now, we've got the only copy so we can update it in-place */
@@ -4418,6 +4399,7 @@
 static PyObject *
 zip_longest_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
+    _Py_IDENTIFIER(fillvalue);
     ziplongestobject *lz;
     Py_ssize_t i;
     PyObject *ittuple;  /* tuple of iterators */
@@ -4426,10 +4408,15 @@
     Py_ssize_t tuplesize;
 
     if (kwds != NULL && PyDict_CheckExact(kwds) && PyDict_GET_SIZE(kwds) > 0) {
-        fillvalue = PyDict_GetItemString(kwds, "fillvalue");
-        if (fillvalue == NULL || PyDict_GET_SIZE(kwds) > 1) {
-            PyErr_SetString(PyExc_TypeError,
-                "zip_longest() got an unexpected keyword argument");
+        fillvalue = NULL;
+        if (PyDict_GET_SIZE(kwds) == 1) {
+            fillvalue = _PyDict_GetItemIdWithError(kwds, &PyId_fillvalue);
+        }
+        if (fillvalue == NULL) {
+            if (!PyErr_Occurred()) {
+                PyErr_SetString(PyExc_TypeError,
+                    "zip_longest() got an unexpected keyword argument");
+            }
             return NULL;
         }
     }
diff --git a/Modules/main.c b/Modules/main.c
index a062991..f6e7889 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -508,10 +508,14 @@
 static int
 pymain_sys_path_add_path0(PyInterpreterState *interp, PyObject *path0)
 {
+    _Py_IDENTIFIER(path);
     PyObject *sys_path;
     PyObject *sysdict = interp->sysdict;
     if (sysdict != NULL) {
-        sys_path = PyDict_GetItemString(sysdict, "path");
+        sys_path = _PyDict_GetItemIdWithError(sysdict, &PyId_path);
+        if (sys_path == NULL && PyErr_Occurred()) {
+            goto error;
+        }
     }
     else {
         sys_path = NULL;
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 05afe9e..540ee9d 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -9837,6 +9837,9 @@
      */
     if (PyDict_DelItem(posix_putenv_garbage, name)) {
         /* really not much we can do; just leak */
+        if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
+            return NULL;
+        }
         PyErr_Clear();
     }
     Py_RETURN_NONE;
diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c
index 9384081..2e8be37 100644
--- a/Modules/pyexpat.c
+++ b/Modules/pyexpat.c
@@ -226,10 +226,13 @@
         return result;
     if (!self->intern)
         return result;
-    value = PyDict_GetItem(self->intern, result);
+    value = PyDict_GetItemWithError(self->intern, result);
     if (!value) {
-        if (PyDict_SetItem(self->intern, result, result) == 0)
+        if (!PyErr_Occurred() &&
+            PyDict_SetItem(self->intern, result, result) == 0)
+        {
             return result;
+        }
         else {
             Py_DECREF(result);
             return NULL;
@@ -1604,13 +1607,18 @@
         hi->getset.set = (setter)xmlparse_handler_setter;
         hi->getset.closure = &handler_info[i];
 
-        PyObject *descr;
-        if (PyDict_GetItemString(Xmlparsetype.tp_dict, hi->name))
-            continue;
-        descr = PyDescr_NewGetSet(&Xmlparsetype, &hi->getset);
-
+        PyObject *descr = PyDescr_NewGetSet(&Xmlparsetype, &hi->getset);
         if (descr == NULL)
             return -1;
+
+        if (PyDict_GetItemWithError(Xmlparsetype.tp_dict, PyDescr_NAME(descr))) {
+            Py_DECREF(descr);
+            continue;
+        }
+        else if (PyErr_Occurred()) {
+            Py_DECREF(descr);
+            return -1;
+        }
         if (PyDict_SetItem(Xmlparsetype.tp_dict, PyDescr_NAME(descr), descr) < 0) {
             Py_DECREF(descr);
             return -1;
@@ -1682,8 +1690,8 @@
         Py_DECREF(m);
         return NULL;
     }
-    errors_module = PyDict_GetItem(d, errmod_name);
-    if (errors_module == NULL) {
+    errors_module = PyDict_GetItemWithError(d, errmod_name);
+    if (errors_module == NULL && !PyErr_Occurred()) {
         errors_module = PyModule_New(MODULE_NAME ".errors");
         if (errors_module != NULL) {
             _PyImport_SetModule(errmod_name, errors_module);
@@ -1692,8 +1700,8 @@
         }
     }
     Py_DECREF(errmod_name);
-    model_module = PyDict_GetItem(d, modelmod_name);
-    if (model_module == NULL) {
+    model_module = PyDict_GetItemWithError(d, modelmod_name);
+    if (model_module == NULL && !PyErr_Occurred()) {
         model_module = PyModule_New(MODULE_NAME ".model");
         if (model_module != NULL) {
             _PyImport_SetModule(modelmod_name, model_module);
diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c
index 7f62ab1..88130a1 100644
--- a/Modules/selectmodule.c
+++ b/Modules/selectmodule.c
@@ -499,9 +499,11 @@
     key = PyLong_FromLong(fd);
     if (key == NULL)
         return NULL;
-    if (PyDict_GetItem(self->dict, key) == NULL) {
-        errno = ENOENT;
-        PyErr_SetFromErrno(PyExc_OSError);
+    if (PyDict_GetItemWithError(self->dict, key) == NULL) {
+        if (!PyErr_Occurred()) {
+            errno = ENOENT;
+            PyErr_SetFromErrno(PyExc_OSError);
+        }
         Py_DECREF(key);
         return NULL;
     }
diff --git a/Modules/xxlimited.c b/Modules/xxlimited.c
index 5586989..190f993 100644
--- a/Modules/xxlimited.c
+++ b/Modules/xxlimited.c
@@ -78,11 +78,14 @@
 Xxo_getattro(XxoObject *self, PyObject *name)
 {
     if (self->x_attr != NULL) {
-        PyObject *v = PyDict_GetItem(self->x_attr, name);
+        PyObject *v = PyDict_GetItemWithError(self->x_attr, name);
         if (v != NULL) {
             Py_INCREF(v);
             return v;
         }
+        else if (PyErr_Occurred()) {
+            return NULL;
+        }
     }
     return PyObject_GenericGetAttr((PyObject *)self, name);
 }
@@ -97,7 +100,7 @@
     }
     if (v == NULL) {
         int rv = PyDict_DelItemString(self->x_attr, name);
-        if (rv < 0)
+        if (rv < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
             PyErr_SetString(PyExc_AttributeError,
                 "delete non-existing Xxo attribute");
         return rv;
diff --git a/Modules/xxmodule.c b/Modules/xxmodule.c
index c0564ea..d546901 100644
--- a/Modules/xxmodule.c
+++ b/Modules/xxmodule.c
@@ -66,11 +66,14 @@
 Xxo_getattro(XxoObject *self, PyObject *name)
 {
     if (self->x_attr != NULL) {
-        PyObject *v = PyDict_GetItem(self->x_attr, name);
+        PyObject *v = PyDict_GetItemWithError(self->x_attr, name);
         if (v != NULL) {
             Py_INCREF(v);
             return v;
         }
+        else if (PyErr_Occurred()) {
+            return NULL;
+        }
     }
     return PyObject_GenericGetAttr((PyObject *)self, name);
 }
@@ -85,7 +88,7 @@
     }
     if (v == NULL) {
         int rv = PyDict_DelItemString(self->x_attr, name);
-        if (rv < 0)
+        if (rv < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
             PyErr_SetString(PyExc_AttributeError,
                 "delete non-existing Xxo attribute");
         return rv;
diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c
index 00bbe21..5778dbb 100644
--- a/Modules/zlibmodule.c
+++ b/Modules/zlibmodule.c
@@ -291,7 +291,9 @@
     PyObject *long_obj;
     Py_ssize_t val;
 
-    long_obj = (PyObject *)_PyLong_FromNbInt(obj);
+    /* XXX Should be replaced with PyNumber_AsSsize_t after the end of the
+       deprecation period. */
+    long_obj = _PyLong_FromNbIndexOrNbInt(obj);
     if (long_obj == NULL) {
         return 0;
     }
diff --git a/Objects/abstract.c b/Objects/abstract.c
index 0565ba3..68d06ed 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -759,8 +759,9 @@
 PyNumber_Check(PyObject *o)
 {
     return o && o->ob_type->tp_as_number &&
-           (o->ob_type->tp_as_number->nb_int ||
-        o->ob_type->tp_as_number->nb_float);
+           (o->ob_type->tp_as_number->nb_index ||
+            o->ob_type->tp_as_number->nb_int ||
+            o->ob_type->tp_as_number->nb_float);
 }
 
 /* Binary operators */
@@ -1366,7 +1367,7 @@
     }
     m = o->ob_type->tp_as_number;
     if (m && m->nb_int) { /* This should include subclasses of int */
-        result = (PyObject *)_PyLong_FromNbInt(o);
+        result = _PyLong_FromNbInt(o);
         if (result != NULL && !PyLong_CheckExact(result)) {
             Py_SETREF(result, _PyLong_Copy((PyLongObject *)result));
         }
@@ -1386,7 +1387,7 @@
         /* __trunc__ is specified to return an Integral type,
            but int() needs to return an int. */
         m = result->ob_type->tp_as_number;
-        if (m == NULL || m->nb_int == NULL) {
+        if (m == NULL || (m->nb_index == NULL && m->nb_int == NULL)) {
             PyErr_Format(
                 PyExc_TypeError,
                 "__trunc__ returned non-Integral (type %.200s)",
@@ -1394,7 +1395,7 @@
             Py_DECREF(result);
             return NULL;
         }
-        Py_SETREF(result, (PyObject *)_PyLong_FromNbInt(result));
+        Py_SETREF(result, _PyLong_FromNbIndexOrNbInt(result));
         if (result != NULL && !PyLong_CheckExact(result)) {
             Py_SETREF(result, _PyLong_Copy((PyLongObject *)result));
         }
diff --git a/Objects/call.c b/Objects/call.c
index be8e90d..3250f8a 100644
--- a/Objects/call.c
+++ b/Objects/call.c
@@ -1276,20 +1276,7 @@
 _Py_NO_INLINE PyObject *
 _PyStack_AsTuple(PyObject *const *stack, Py_ssize_t nargs)
 {
-    PyObject *args;
-    Py_ssize_t i;
-
-    args = PyTuple_New(nargs);
-    if (args == NULL) {
-        return NULL;
-    }
-
-    for (i=0; i < nargs; i++) {
-        PyObject *item = stack[i];
-        Py_INCREF(item);
-        PyTuple_SET_ITEM(args, i, item);
-    }
-    return args;
+    return _PyTuple_FromArray(stack, nargs);
 }
 
 
@@ -1297,24 +1284,11 @@
 _PyStack_AsTupleSlice(PyObject *const *stack, Py_ssize_t nargs,
                       Py_ssize_t start, Py_ssize_t end)
 {
-    PyObject *args;
-    Py_ssize_t i;
-
     assert(0 <= start);
     assert(end <= nargs);
     assert(start <= end);
 
-    args = PyTuple_New(end - start);
-    if (args == NULL) {
-        return NULL;
-    }
-
-    for (i=start; i < end; i++) {
-        PyObject *item = stack[i];
-        Py_INCREF(item);
-        PyTuple_SET_ITEM(args, i - start, item);
-    }
-    return args;
+    return _PyTuple_FromArray(stack + start, end - start);
 }
 
 
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index a871636..83cadda 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1419,6 +1419,19 @@
     return PyDict_GetItemWithError(dp, kv);
 }
 
+PyObject *
+_PyDict_GetItemStringWithError(PyObject *v, const char *key)
+{
+    PyObject *kv, *rv;
+    kv = PyUnicode_FromString(key);
+    if (kv == NULL) {
+        return NULL;
+    }
+    rv = PyDict_GetItemWithError(v, kv);
+    Py_DECREF(kv);
+    return rv;
+}
+
 /* Fast version of global value lookup (LOAD_GLOBAL).
  * Lookup in globals, then builtins.
  *
@@ -2358,14 +2371,21 @@
         value = PySequence_Fast_GET_ITEM(fast, 1);
         Py_INCREF(key);
         Py_INCREF(value);
-        if (override || PyDict_GetItem(d, key) == NULL) {
-            int status = PyDict_SetItem(d, key, value);
-            if (status < 0) {
+        if (override) {
+            if (PyDict_SetItem(d, key, value) < 0) {
                 Py_DECREF(key);
                 Py_DECREF(value);
                 goto Fail;
             }
         }
+        else if (PyDict_GetItemWithError(d, key) == NULL) {
+            if (PyErr_Occurred() || PyDict_SetItem(d, key, value) < 0) {
+                Py_DECREF(key);
+                Py_DECREF(value);
+                goto Fail;
+            }
+        }
+
         Py_DECREF(key);
         Py_DECREF(value);
         Py_DECREF(fast);
@@ -2489,15 +2509,22 @@
             return -1;
 
         for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) {
-            if (override != 1 && PyDict_GetItem(a, key) != NULL) {
-                if (override != 0) {
-                    _PyErr_SetKeyError(key);
+            if (override != 1) {
+                if (PyDict_GetItemWithError(a, key) != NULL) {
+                    if (override != 0) {
+                        _PyErr_SetKeyError(key);
+                        Py_DECREF(key);
+                        Py_DECREF(iter);
+                        return -1;
+                    }
+                    Py_DECREF(key);
+                    continue;
+                }
+                else if (PyErr_Occurred()) {
                     Py_DECREF(key);
                     Py_DECREF(iter);
                     return -1;
                 }
-                Py_DECREF(key);
-                continue;
             }
             value = PyObject_GetItem(b, key);
             if (value == NULL) {
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
index 75ede1c..ad2a54a 100644
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -975,7 +975,7 @@
         if (myerrno && PyLong_Check(myerrno) &&
             errnomap && (PyObject *) type == PyExc_OSError) {
             PyObject *newtype;
-            newtype = PyDict_GetItem(errnomap, myerrno);
+            newtype = PyDict_GetItemWithError(errnomap, myerrno);
             if (newtype) {
                 assert(PyType_Check(newtype));
                 type = (PyTypeObject *) newtype;
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 8488b96..b668465 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -613,7 +613,7 @@
     }
 #endif
     if (back == NULL || back->f_globals != globals) {
-        builtins = _PyDict_GetItemId(globals, &PyId___builtins__);
+        builtins = _PyDict_GetItemIdWithError(globals, &PyId___builtins__);
         if (builtins) {
             if (PyModule_Check(builtins)) {
                 builtins = PyModule_GetDict(builtins);
@@ -621,6 +621,9 @@
             }
         }
         if (builtins == NULL) {
+            if (PyErr_Occurred()) {
+                return NULL;
+            }
             /* No builtins!              Make up a minimal one
                Give them 'None', at least. */
             builtins = PyDict_New();
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index 4fab358..e8e2d2e 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -54,11 +54,15 @@
 
     /* __module__: If module name is in globals, use it.
        Otherwise, use None. */
-    module = PyDict_GetItem(globals, __name__);
+    module = PyDict_GetItemWithError(globals, __name__);
     if (module) {
         Py_INCREF(module);
         op->func_module = module;
     }
+    else if (PyErr_Occurred()) {
+        Py_DECREF(op);
+        return NULL;
+    }
     if (qualname)
         op->func_qualname = qualname;
     else
diff --git a/Objects/listobject.c b/Objects/listobject.c
index cbd6e81..b6524e8 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -3,6 +3,7 @@
 #include "Python.h"
 #include "pycore_object.h"
 #include "pycore_pystate.h"
+#include "pycore_tupleobject.h"
 #include "pycore_accu.h"
 
 #ifdef STDC_HEADERS
@@ -2501,26 +2502,11 @@
 PyObject *
 PyList_AsTuple(PyObject *v)
 {
-    PyObject *w;
-    PyObject **p, **q;
-    Py_ssize_t n;
     if (v == NULL || !PyList_Check(v)) {
         PyErr_BadInternalCall();
         return NULL;
     }
-    n = Py_SIZE(v);
-    w = PyTuple_New(n);
-    if (w == NULL)
-        return NULL;
-    p = ((PyTupleObject *)w)->ob_item;
-    q = ((PyListObject *)v)->ob_item;
-    while (--n >= 0) {
-        Py_INCREF(*q);
-        *p = *q;
-        p++;
-        q++;
-    }
-    return w;
+    return _PyTuple_FromArray(((PyListObject *)v)->ob_item, Py_SIZE(v));
 }
 
 /*[clinic input]
diff --git a/Objects/longobject.c b/Objects/longobject.c
index d7b01ce..1e3445c 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -140,7 +140,7 @@
    nb_int slot is not available or the result of the call to nb_int
    returns something not of type int.
 */
-PyLongObject *
+PyObject *
 _PyLong_FromNbInt(PyObject *integral)
 {
     PyNumberMethods *nb;
@@ -149,7 +149,7 @@
     /* Fast path for the case that we already have an int. */
     if (PyLong_CheckExact(integral)) {
         Py_INCREF(integral);
-        return (PyLongObject *)integral;
+        return integral;
     }
 
     nb = Py_TYPE(integral)->tp_as_number;
@@ -164,7 +164,7 @@
        of exact type int. */
     result = nb->nb_int(integral);
     if (!result || PyLong_CheckExact(result))
-        return (PyLongObject *)result;
+        return result;
     if (!PyLong_Check(result)) {
         PyErr_Format(PyExc_TypeError,
                      "__int__ returned non-int (type %.200s)",
@@ -181,7 +181,74 @@
         Py_DECREF(result);
         return NULL;
     }
-    return (PyLongObject *)result;
+    return result;
+}
+
+/* Convert the given object to a PyLongObject using the nb_index or
+   nb_int slots, if available (the latter is deprecated).
+   Raise TypeError if either nb_index and nb_int slots are not
+   available or the result of the call to nb_index or nb_int
+   returns something not of type int.
+   Should be replaced with PyNumber_Index after the end of the
+   deprecation period.
+*/
+PyObject *
+_PyLong_FromNbIndexOrNbInt(PyObject *integral)
+{
+    PyNumberMethods *nb;
+    PyObject *result;
+
+    /* Fast path for the case that we already have an int. */
+    if (PyLong_CheckExact(integral)) {
+        Py_INCREF(integral);
+        return integral;
+    }
+
+    nb = Py_TYPE(integral)->tp_as_number;
+    if (nb == NULL || (nb->nb_index == NULL && nb->nb_int == NULL)) {
+        PyErr_Format(PyExc_TypeError,
+                     "an integer is required (got type %.200s)",
+                     Py_TYPE(integral)->tp_name);
+        return NULL;
+    }
+
+    if (nb->nb_index) {
+    /* Convert using the nb_index slot, which should return something
+       of exact type int. */
+        result = nb->nb_index(integral);
+        if (!result || PyLong_CheckExact(result))
+            return result;
+        if (!PyLong_Check(result)) {
+            PyErr_Format(PyExc_TypeError,
+                         "__index__ returned non-int (type %.200s)",
+                         result->ob_type->tp_name);
+            Py_DECREF(result);
+            return NULL;
+        }
+        /* Issue #17576: warn if 'result' not of exact type int. */
+        if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
+                "__index__ returned non-int (type %.200s).  "
+                "The ability to return an instance of a strict subclass of int "
+                "is deprecated, and may be removed in a future version of Python.",
+                result->ob_type->tp_name))
+        {
+            Py_DECREF(result);
+            return NULL;
+        }
+        return result;
+    }
+
+    result = _PyLong_FromNbInt(integral);
+    if (result && PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
+            "an integer is required (got type %.200s).  "
+            "Implicit conversion to integers using __int__ is deprecated, "
+            "and may be removed in a future version of Python.",
+            Py_TYPE(integral)->tp_name))
+    {
+        Py_DECREF(result);
+        return NULL;
+    }
+    return result;
 }
 
 
@@ -420,7 +487,7 @@
         v = (PyLongObject *)vv;
     }
     else {
-        v = _PyLong_FromNbInt(vv);
+        v = (PyLongObject *)_PyLong_FromNbIndexOrNbInt(vv);
         if (v == NULL)
             return -1;
         do_decref = 1;
@@ -700,7 +767,7 @@
         return _PyLong_AsUnsignedLongMask(op);
     }
 
-    lo = _PyLong_FromNbInt(op);
+    lo = (PyLongObject *)_PyLong_FromNbIndexOrNbInt(op);
     if (lo == NULL)
         return (unsigned long)-1;
 
@@ -1229,7 +1296,7 @@
         v = (PyLongObject *)vv;
     }
     else {
-        v = _PyLong_FromNbInt(vv);
+        v = (PyLongObject *)_PyLong_FromNbIndexOrNbInt(vv);
         if (v == NULL)
             return -1;
         do_decref = 1;
@@ -1344,7 +1411,7 @@
         return _PyLong_AsUnsignedLongLongMask(op);
     }
 
-    lo = _PyLong_FromNbInt(op);
+    lo = (PyLongObject *)_PyLong_FromNbIndexOrNbInt(op);
     if (lo == NULL)
         return (unsigned long long)-1;
 
@@ -1384,7 +1451,7 @@
         v = (PyLongObject *)vv;
     }
     else {
-        v = _PyLong_FromNbInt(vv);
+        v = (PyLongObject *)_PyLong_FromNbIndexOrNbInt(vv);
         if (v == NULL)
             return -1;
         do_decref = 1;
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c
index fca8521..9d65332 100644
--- a/Objects/moduleobject.c
+++ b/Objects/moduleobject.c
@@ -792,16 +792,17 @@
 module_dir(PyObject *self, PyObject *args)
 {
     _Py_IDENTIFIER(__dict__);
+    _Py_IDENTIFIER(__dir__);
     PyObject *result = NULL;
     PyObject *dict = _PyObject_GetAttrId(self, &PyId___dict__);
 
     if (dict != NULL) {
         if (PyDict_Check(dict)) {
-            PyObject *dirfunc = PyDict_GetItemString(dict, "__dir__");
+            PyObject *dirfunc = _PyDict_GetItemIdWithError(dict, &PyId___dir__);
             if (dirfunc) {
                 result = _PyObject_CallNoArg(dirfunc);
             }
-            else {
+            else if (!PyErr_Occurred()) {
                 result = PyDict_Keys(dict);
             }
         }
diff --git a/Objects/namespaceobject.c b/Objects/namespaceobject.c
index 2acf809..aba3ff7 100644
--- a/Objects/namespaceobject.c
+++ b/Objects/namespaceobject.c
@@ -102,9 +102,9 @@
         if (PyUnicode_Check(key) && PyUnicode_GET_LENGTH(key) > 0) {
             PyObject *value, *item;
 
-            value = PyDict_GetItem(d, key);
+            value = PyDict_GetItemWithError(d, key);
             if (value != NULL) {
-                item = PyUnicode_FromFormat("%S=%R", key, value);
+                item = PyUnicode_FromFormat("%U=%R", key, value);
                 if (item == NULL) {
                     loop_error = 1;
                 }
@@ -113,6 +113,9 @@
                     Py_DECREF(item);
                 }
             }
+            else if (PyErr_Occurred()) {
+                loop_error = 1;
+            }
         }
 
         Py_DECREF(key);
diff --git a/Objects/object.c b/Objects/object.c
index 044342f..cf5264b 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -1144,7 +1144,7 @@
     dictptr = _PyObject_GetDictPtr(obj);
     if (dictptr != NULL && (dict = *dictptr) != NULL) {
         Py_INCREF(dict);
-        attr = PyDict_GetItem(dict, name);
+        attr = PyDict_GetItemWithError(dict, name);
         if (attr != NULL) {
             Py_INCREF(attr);
             *method = attr;
@@ -1152,7 +1152,13 @@
             Py_XDECREF(descr);
             return 0;
         }
-        Py_DECREF(dict);
+        else {
+            Py_DECREF(dict);
+            if (PyErr_Occurred()) {
+                Py_XDECREF(descr);
+                return 0;
+            }
+        }
     }
 
     if (meth_found) {
@@ -1249,13 +1255,23 @@
     }
     if (dict != NULL) {
         Py_INCREF(dict);
-        res = PyDict_GetItem(dict, name);
+        res = PyDict_GetItemWithError(dict, name);
         if (res != NULL) {
             Py_INCREF(res);
             Py_DECREF(dict);
             goto done;
         }
-        Py_DECREF(dict);
+        else {
+            Py_DECREF(dict);
+            if (PyErr_Occurred()) {
+                if (suppress && PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                    PyErr_Clear();
+                }
+                else {
+                    goto done;
+                }
+            }
+        }
     }
 
     if (f != NULL) {
@@ -1943,8 +1959,11 @@
        early on startup. */
     if (dict == NULL)
         return 0;
-    list = _PyDict_GetItemId(dict, &PyId_Py_Repr);
+    list = _PyDict_GetItemIdWithError(dict, &PyId_Py_Repr);
     if (list == NULL) {
+        if (PyErr_Occurred()) {
+            return -1;
+        }
         list = PyList_New(0);
         if (list == NULL)
             return -1;
@@ -1976,7 +1995,7 @@
     if (dict == NULL)
         goto finally;
 
-    list = _PyDict_GetItemId(dict, &PyId_Py_Repr);
+    list = _PyDict_GetItemIdWithError(dict, &PyId_Py_Repr);
     if (list == NULL || !PyList_Check(list))
         goto finally;
 
diff --git a/Objects/structseq.c b/Objects/structseq.c
index cf94155..56b06c7 100644
--- a/Objects/structseq.c
+++ b/Objects/structseq.c
@@ -2,6 +2,7 @@
    and posixmodule for example uses. */
 
 #include "Python.h"
+#include "pycore_tupleobject.h"
 #include "structmember.h"
 
 static const char visible_length_key[] = "n_sequence_fields";
@@ -250,7 +251,7 @@
     n_fields = REAL_SIZE(self);
     n_visible_fields = VISIBLE_SIZE(self);
     n_unnamed_fields = UNNAMED_FIELDS(self);
-    tup = PyTuple_New(n_visible_fields);
+    tup = _PyTuple_FromArray(self->ob_item, n_visible_fields);
     if (!tup)
         goto error;
 
@@ -258,12 +259,7 @@
     if (!dict)
         goto error;
 
-    for (i = 0; i < n_visible_fields; i++) {
-        Py_INCREF(self->ob_item[i]);
-        PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
-    }
-
-    for (; i < n_fields; i++) {
+    for (i = n_visible_fields; i < n_fields; i++) {
         const char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name;
         if (PyDict_SetItemString(dict, n, self->ob_item[i]) < 0)
             goto error;
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index 9cf3f3d..75d2bf9 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -419,14 +419,26 @@
     return a->ob_item[i];
 }
 
+PyObject *
+_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n)
+{
+    PyTupleObject *tuple = (PyTupleObject *)PyTuple_New(n);
+    if (tuple == NULL) {
+        return NULL;
+    }
+    PyObject **dst = tuple->ob_item;
+    for (Py_ssize_t i = 0; i < n; i++) {
+        PyObject *item = src[i];
+        Py_INCREF(item);
+        dst[i] = item;
+    }
+    return (PyObject *)tuple;
+}
+
 static PyObject *
 tupleslice(PyTupleObject *a, Py_ssize_t ilow,
            Py_ssize_t ihigh)
 {
-    PyTupleObject *np;
-    PyObject **src, **dest;
-    Py_ssize_t i;
-    Py_ssize_t len;
     if (ilow < 0)
         ilow = 0;
     if (ihigh > Py_SIZE(a))
@@ -437,18 +449,7 @@
         Py_INCREF(a);
         return (PyObject *)a;
     }
-    len = ihigh - ilow;
-    np = (PyTupleObject *)PyTuple_New(len);
-    if (np == NULL)
-        return NULL;
-    src = a->ob_item + ilow;
-    dest = np->ob_item;
-    for (i = 0; i < len; i++) {
-        PyObject *v = src[i];
-        Py_INCREF(v);
-        dest[i] = v;
-    }
-    return (PyObject *)np;
+    return _PyTuple_FromArray(a->ob_item + ilow, ihigh - ilow);
 }
 
 PyObject *
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 4234726..e559c64 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -491,9 +491,11 @@
     PyObject *mod;
 
     if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
-        mod = _PyDict_GetItemId(type->tp_dict, &PyId___module__);
+        mod = _PyDict_GetItemIdWithError(type->tp_dict, &PyId___module__);
         if (mod == NULL) {
-            PyErr_Format(PyExc_AttributeError, "__module__");
+            if (!PyErr_Occurred()) {
+                PyErr_Format(PyExc_AttributeError, "__module__");
+            }
             return NULL;
         }
         Py_INCREF(mod);
@@ -532,11 +534,13 @@
     /* type itself has an __abstractmethods__ descriptor (this). Don't return
        that. */
     if (type != &PyType_Type)
-        mod = _PyDict_GetItemId(type->tp_dict, &PyId___abstractmethods__);
+        mod = _PyDict_GetItemIdWithError(type->tp_dict, &PyId___abstractmethods__);
     if (!mod) {
-        PyObject *message = _PyUnicode_FromId(&PyId___abstractmethods__);
-        if (message)
-            PyErr_SetObject(PyExc_AttributeError, message);
+        if (!PyErr_Occurred()) {
+            PyObject *message = _PyUnicode_FromId(&PyId___abstractmethods__);
+            if (message)
+                PyErr_SetObject(PyExc_AttributeError, message);
+        }
         return NULL;
     }
     Py_INCREF(mod);
@@ -808,10 +812,12 @@
     if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) && type->tp_doc != NULL) {
         return _PyType_GetDocFromInternalDoc(type->tp_name, type->tp_doc);
     }
-    result = _PyDict_GetItemId(type->tp_dict, &PyId___doc__);
+    result = _PyDict_GetItemIdWithError(type->tp_dict, &PyId___doc__);
     if (result == NULL) {
-        result = Py_None;
-        Py_INCREF(result);
+        if (!PyErr_Occurred()) {
+            result = Py_None;
+            Py_INCREF(result);
+        }
     }
     else if (Py_TYPE(result)->tp_descr_get) {
         result = Py_TYPE(result)->tp_descr_get(result, NULL,
@@ -2452,13 +2458,16 @@
         goto error;
 
     /* Check for a __slots__ sequence variable in dict, and count it */
-    slots = _PyDict_GetItemId(dict, &PyId___slots__);
+    slots = _PyDict_GetItemIdWithError(dict, &PyId___slots__);
     nslots = 0;
     add_dict = 0;
     add_weak = 0;
     may_add_dict = base->tp_dictoffset == 0;
     may_add_weak = base->tp_weaklistoffset == 0 && base->tp_itemsize == 0;
     if (slots == NULL) {
+        if (PyErr_Occurred()) {
+            goto error;
+        }
         if (may_add_dict) {
             add_dict++;
         }
@@ -2535,7 +2544,7 @@
                 goto error;
             }
             PyList_SET_ITEM(newslots, j, tmp);
-            if (PyDict_GetItem(dict, tmp)) {
+            if (PyDict_GetItemWithError(dict, tmp)) {
                 /* CPython inserts __qualname__ and __classcell__ (when needed)
                    into the namespace when creating a class.  They will be deleted
                    below so won't act as class variables. */
@@ -2548,6 +2557,10 @@
                     goto error;
                 }
             }
+            else if (PyErr_Occurred()) {
+                Py_DECREF(newslots);
+                goto error;
+            }
             j++;
         }
         assert(j == nslots - add_dict - add_weak);
@@ -2632,22 +2645,28 @@
     type->tp_dict = dict;
 
     /* Set __module__ in the dict */
-    if (_PyDict_GetItemId(dict, &PyId___module__) == NULL) {
+    if (_PyDict_GetItemIdWithError(dict, &PyId___module__) == NULL) {
+        if (PyErr_Occurred()) {
+            goto error;
+        }
         tmp = PyEval_GetGlobals();
         if (tmp != NULL) {
-            tmp = _PyDict_GetItemId(tmp, &PyId___name__);
+            tmp = _PyDict_GetItemIdWithError(tmp, &PyId___name__);
             if (tmp != NULL) {
                 if (_PyDict_SetItemId(dict, &PyId___module__,
                                       tmp) < 0)
                     goto error;
             }
+            else if (PyErr_Occurred()) {
+                goto error;
+            }
         }
     }
 
     /* Set ht_qualname to dict['__qualname__'] if available, else to
        __name__.  The __qualname__ accessor will look for ht_qualname.
     */
-    qualname = _PyDict_GetItemId(dict, &PyId___qualname__);
+    qualname = _PyDict_GetItemIdWithError(dict, &PyId___qualname__);
     if (qualname != NULL) {
         if (!PyUnicode_Check(qualname)) {
             PyErr_Format(PyExc_TypeError,
@@ -2656,6 +2675,9 @@
             goto error;
         }
     }
+    else if (PyErr_Occurred()) {
+        goto error;
+    }
     et->ht_qualname = qualname ? qualname : et->ht_name;
     Py_INCREF(et->ht_qualname);
     if (qualname != NULL && _PyDict_DelItemId(dict, &PyId___qualname__) < 0)
@@ -2666,7 +2688,7 @@
        if that fails, it will still look into __dict__.
     */
     {
-        PyObject *doc = _PyDict_GetItemId(dict, &PyId___doc__);
+        PyObject *doc = _PyDict_GetItemIdWithError(dict, &PyId___doc__);
         if (doc != NULL && PyUnicode_Check(doc)) {
             Py_ssize_t len;
             const char *doc_str;
@@ -2685,11 +2707,14 @@
             memcpy(tp_doc, doc_str, len + 1);
             type->tp_doc = tp_doc;
         }
+        else if (doc == NULL && PyErr_Occurred()) {
+            goto error;
+        }
     }
 
     /* Special-case __new__: if it's a plain function,
        make it a static function */
-    tmp = _PyDict_GetItemId(dict, &PyId___new__);
+    tmp = _PyDict_GetItemIdWithError(dict, &PyId___new__);
     if (tmp != NULL && PyFunction_Check(tmp)) {
         tmp = PyStaticMethod_New(tmp);
         if (tmp == NULL)
@@ -2700,10 +2725,13 @@
         }
         Py_DECREF(tmp);
     }
+    else if (tmp == NULL && PyErr_Occurred()) {
+        goto error;
+    }
 
     /* Special-case __init_subclass__ and __class_getitem__:
        if they are plain functions, make them classmethods */
-    tmp = _PyDict_GetItemId(dict, &PyId___init_subclass__);
+    tmp = _PyDict_GetItemIdWithError(dict, &PyId___init_subclass__);
     if (tmp != NULL && PyFunction_Check(tmp)) {
         tmp = PyClassMethod_New(tmp);
         if (tmp == NULL)
@@ -2714,8 +2742,11 @@
         }
         Py_DECREF(tmp);
     }
+    else if (tmp == NULL && PyErr_Occurred()) {
+        goto error;
+    }
 
-    tmp = _PyDict_GetItemId(dict, &PyId___class_getitem__);
+    tmp = _PyDict_GetItemIdWithError(dict, &PyId___class_getitem__);
     if (tmp != NULL && PyFunction_Check(tmp)) {
         tmp = PyClassMethod_New(tmp);
         if (tmp == NULL)
@@ -2726,6 +2757,9 @@
         }
         Py_DECREF(tmp);
     }
+    else if (tmp == NULL && PyErr_Occurred()) {
+        goto error;
+    }
 
     /* Add descriptors for custom slots from __slots__, or for __dict__ */
     mp = PyHeapType_GET_MEMBERS(et);
@@ -2797,7 +2831,7 @@
         type->tp_free = PyObject_Del;
 
     /* store type in class' cell if one is supplied */
-    cell = _PyDict_GetItemId(dict, &PyId___classcell__);
+    cell = _PyDict_GetItemIdWithError(dict, &PyId___classcell__);
     if (cell != NULL) {
         /* At least one method requires a reference to its defining class */
         if (!PyCell_Check(cell)) {
@@ -2807,8 +2841,12 @@
             goto error;
         }
         PyCell_Set(cell, (PyObject *) type);
-        _PyDict_DelItemId(dict, &PyId___classcell__);
-        PyErr_Clear();
+        if (_PyDict_DelItemId(dict, &PyId___classcell__) < 0) {
+            goto error;
+        }
+    }
+    else if (PyErr_Occurred()) {
+        goto error;
     }
 
     /* Initialize the rest */
@@ -3741,47 +3779,41 @@
     }
 
     if (type->tp_flags & Py_TPFLAGS_IS_ABSTRACT) {
-        PyObject *abstract_methods = NULL;
-        PyObject *builtins;
-        PyObject *sorted;
-        PyObject *sorted_methods = NULL;
-        PyObject *joined = NULL;
+        PyObject *abstract_methods;
+        PyObject *sorted_methods;
+        PyObject *joined;
         PyObject *comma;
         _Py_static_string(comma_id, ", ");
-        _Py_IDENTIFIER(sorted);
 
         /* Compute ", ".join(sorted(type.__abstractmethods__))
            into joined. */
         abstract_methods = type_abstractmethods(type, NULL);
         if (abstract_methods == NULL)
-            goto error;
-        builtins = PyEval_GetBuiltins();
-        if (builtins == NULL)
-            goto error;
-        sorted = _PyDict_GetItemId(builtins, &PyId_sorted);
-        if (sorted == NULL)
-            goto error;
-        sorted_methods = PyObject_CallFunctionObjArgs(sorted,
-                                                      abstract_methods,
-                                                      NULL);
+            return NULL;
+        sorted_methods = PySequence_List(abstract_methods);
+        Py_DECREF(abstract_methods);
         if (sorted_methods == NULL)
-            goto error;
+            return NULL;
+        if (PyList_Sort(sorted_methods)) {
+            Py_DECREF(sorted_methods);
+            return NULL;
+        }
         comma = _PyUnicode_FromId(&comma_id);
-        if (comma == NULL)
-            goto error;
+        if (comma == NULL) {
+            Py_DECREF(sorted_methods);
+            return NULL;
+        }
         joined = PyUnicode_Join(comma, sorted_methods);
+        Py_DECREF(sorted_methods);
         if (joined == NULL)
-            goto error;
+            return NULL;
 
         PyErr_Format(PyExc_TypeError,
                      "Can't instantiate abstract class %s "
                      "with abstract methods %U",
                      type->tp_name,
                      joined);
-    error:
-        Py_XDECREF(joined);
-        Py_XDECREF(sorted_methods);
-        Py_XDECREF(abstract_methods);
+        Py_DECREF(joined);
         return NULL;
     }
     return type->tp_alloc(type, 0);
@@ -4610,14 +4642,12 @@
     if (objreduce == NULL) {
         objreduce = _PyDict_GetItemId(PyBaseObject_Type.tp_dict,
                                       &PyId___reduce__);
-        if (objreduce == NULL)
-            return NULL;
     }
 
-    reduce = _PyObject_GetAttrId(self, &PyId___reduce__);
-    if (reduce == NULL)
-        PyErr_Clear();
-    else {
+    if (_PyObject_LookupAttrId(self, &PyId___reduce__, &reduce) < 0) {
+        return NULL;
+    }
+    if (reduce != NULL) {
         PyObject *cls, *clsreduce;
         int override;
 
@@ -4829,14 +4859,12 @@
 add_methods(PyTypeObject *type, PyMethodDef *meth)
 {
     PyObject *dict = type->tp_dict;
+    PyObject *name;
 
     for (; meth->ml_name != NULL; meth++) {
         PyObject *descr;
         int err;
         int isdescr = 1;
-        if (PyDict_GetItemString(dict, meth->ml_name) &&
-            !(meth->ml_flags & METH_COEXIST))
-                continue;
         if (meth->ml_flags & METH_CLASS) {
             if (meth->ml_flags & METH_STATIC) {
                 PyErr_SetString(PyExc_ValueError,
@@ -4846,7 +4874,7 @@
             descr = PyDescr_NewClassMethod(type, meth);
         }
         else if (meth->ml_flags & METH_STATIC) {
-          PyObject *cfunc = PyCFunction_NewEx(meth, (PyObject*)type, NULL);
+            PyObject *cfunc = PyCFunction_NewEx(meth, (PyObject*)type, NULL);
             if (cfunc == NULL)
                 return -1;
             descr = PyStaticMethod_New(cfunc);
@@ -4858,11 +4886,36 @@
         }
         if (descr == NULL)
             return -1;
+
         if (isdescr) {
-            err = PyDict_SetItem(dict, PyDescr_NAME(descr), descr);
+            name = PyDescr_NAME(descr);
         }
         else {
-            err = PyDict_SetItemString(dict, meth->ml_name, descr);
+            name = PyUnicode_FromString(meth->ml_name);
+            if (name == NULL) {
+                Py_DECREF(descr);
+                return -1;
+            }
+        }
+
+        if (!(meth->ml_flags & METH_COEXIST)) {
+            if (PyDict_GetItemWithError(dict, name)) {
+                if (!isdescr) {
+                    Py_DECREF(name);
+                }
+                Py_DECREF(descr);
+                continue;
+            }
+            else if (PyErr_Occurred()) {
+                if (!isdescr) {
+                    Py_DECREF(name);
+                }
+                return -1;
+            }
+        }
+        err = PyDict_SetItem(dict, name, descr);
+        if (!isdescr) {
+            Py_DECREF(name);
         }
         Py_DECREF(descr);
         if (err < 0)
@@ -4877,12 +4930,18 @@
     PyObject *dict = type->tp_dict;
 
     for (; memb->name != NULL; memb++) {
-        PyObject *descr;
-        if (PyDict_GetItemString(dict, memb->name))
-            continue;
-        descr = PyDescr_NewMember(type, memb);
+        PyObject *descr = PyDescr_NewMember(type, memb);
         if (descr == NULL)
             return -1;
+
+        if (PyDict_GetItemWithError(dict, PyDescr_NAME(descr))) {
+            Py_DECREF(descr);
+            continue;
+        }
+        else if (PyErr_Occurred()) {
+            Py_DECREF(descr);
+            return -1;
+        }
         if (PyDict_SetItem(dict, PyDescr_NAME(descr), descr) < 0) {
             Py_DECREF(descr);
             return -1;
@@ -4898,13 +4957,17 @@
     PyObject *dict = type->tp_dict;
 
     for (; gsp->name != NULL; gsp++) {
-        PyObject *descr;
-        if (PyDict_GetItemString(dict, gsp->name))
-            continue;
-        descr = PyDescr_NewGetSet(type, gsp);
-
+        PyObject *descr = PyDescr_NewGetSet(type, gsp);
         if (descr == NULL)
             return -1;
+
+        if (PyDict_GetItemWithError(dict, PyDescr_NAME(descr))) {
+            continue;
+        }
+        else if (PyErr_Occurred()) {
+            Py_DECREF(descr);
+            return -1;
+        }
         if (PyDict_SetItem(dict, PyDescr_NAME(descr), descr) < 0) {
             Py_DECREF(descr);
             return -1;
@@ -5309,7 +5372,10 @@
     /* if the type dictionary doesn't contain a __doc__, set it from
        the tp_doc slot.
      */
-    if (_PyDict_GetItemId(type->tp_dict, &PyId___doc__) == NULL) {
+    if (_PyDict_GetItemIdWithError(type->tp_dict, &PyId___doc__) == NULL) {
+        if (PyErr_Occurred()) {
+            goto error;
+        }
         if (type->tp_doc != NULL) {
             const char *old_doc = _PyType_DocWithoutSignature(type->tp_name,
                 type->tp_doc);
@@ -5335,9 +5401,12 @@
        This signals that __hash__ is not inherited.
      */
     if (type->tp_hash == NULL) {
-        if (_PyDict_GetItemId(type->tp_dict, &PyId___hash__) == NULL) {
-            if (_PyDict_SetItemId(type->tp_dict, &PyId___hash__, Py_None) < 0)
+        if (_PyDict_GetItemIdWithError(type->tp_dict, &PyId___hash__) == NULL) {
+            if (PyErr_Occurred() ||
+               _PyDict_SetItemId(type->tp_dict, &PyId___hash__, Py_None) < 0)
+            {
                 goto error;
+            }
             type->tp_hash = PyObject_HashNotImplemented;
         }
     }
@@ -5988,8 +6057,10 @@
 {
     PyObject *func;
 
-    if (_PyDict_GetItemId(type->tp_dict, &PyId___new__) != NULL)
+    if (_PyDict_GetItemIdWithError(type->tp_dict, &PyId___new__) != NULL)
         return 0;
+    if (PyErr_Occurred())
+        return -1;
     func = PyCFunction_NewEx(tp_new_methoddef, (PyObject *)type, NULL);
     if (func == NULL)
         return -1;
@@ -7414,9 +7485,14 @@
         assert(PyType_Check(subclass));
         /* Avoid recursing down into unaffected classes */
         dict = subclass->tp_dict;
-        if (dict != NULL && PyDict_Check(dict) &&
-            PyDict_GetItem(dict, name) != NULL)
-            continue;
+        if (dict != NULL && PyDict_Check(dict)) {
+            if (PyDict_GetItemWithError(dict, name) != NULL) {
+                continue;
+            }
+            if (PyErr_Occurred()) {
+                return -1;
+            }
+        }
         if (update_subclasses(subclass, name, callback, data) < 0)
             return -1;
     }
@@ -7468,8 +7544,11 @@
         ptr = slotptr(type, p->offset);
         if (!ptr || !*ptr)
             continue;
-        if (PyDict_GetItem(dict, p->name_strobj))
+        if (PyDict_GetItemWithError(dict, p->name_strobj))
             continue;
+        if (PyErr_Occurred()) {
+            return -1;
+        }
         if (*ptr == (void *)PyObject_HashNotImplemented) {
             /* Classes may prevent the inheritance of the tp_hash
                slot by storing PyObject_HashNotImplemented in it. Make it
@@ -7579,7 +7658,7 @@
         goto skip;
 
     /* keep a strong reference to mro because starttype->tp_mro can be
-       replaced during PyDict_GetItem(dict, name)  */
+       replaced during PyDict_GetItemWithError(dict, name)  */
     Py_INCREF(mro);
     do {
         PyObject *res, *tmp, *dict;
@@ -7591,7 +7670,7 @@
         dict = ((PyTypeObject *)tmp)->tp_dict;
         assert(dict != NULL && PyDict_Check(dict));
 
-        res = PyDict_GetItem(dict, name);
+        res = PyDict_GetItemWithError(dict, name);
         if (res != NULL) {
             Py_INCREF(res);
 
@@ -7609,6 +7688,9 @@
             Py_DECREF(mro);
             return res;
         }
+        else if (PyErr_Occurred()) {
+            return NULL;
+        }
 
         i++;
     } while (i < n);
diff --git a/Python/_warnings.c b/Python/_warnings.c
index 7eedd13..33b4615 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -252,7 +252,7 @@
     if (key == NULL)
         return -1;
 
-    version_obj = _PyDict_GetItemId(registry, &PyId_version);
+    version_obj = _PyDict_GetItemIdWithError(registry, &PyId_version);
     if (version_obj == NULL
         || !PyLong_CheckExact(version_obj)
         || PyLong_AsLong(version_obj) != _PyRuntime.warnings.filters_version)
@@ -271,12 +271,15 @@
         Py_DECREF(version_obj);
     }
     else {
-        already_warned = PyDict_GetItem(registry, key);
+        already_warned = PyDict_GetItemWithError(registry, key);
         if (already_warned != NULL) {
             int rc = PyObject_IsTrue(already_warned);
             if (rc != 0)
                 return rc;
         }
+        else if (PyErr_Occurred()) {
+            return -1;
+        }
     }
 
     /* This warning wasn't found in the registry, set it. */
@@ -672,6 +675,8 @@
 setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
               PyObject **module, PyObject **registry)
 {
+    _Py_IDENTIFIER(__warningregistry__);
+    _Py_IDENTIFIER(__name__);
     PyObject *globals;
 
     /* Setup globals, filename and lineno. */
@@ -706,15 +711,18 @@
     /* Setup registry. */
     assert(globals != NULL);
     assert(PyDict_Check(globals));
-    *registry = PyDict_GetItemString(globals, "__warningregistry__");
+    *registry = _PyDict_GetItemIdWithError(globals, &PyId___warningregistry__);
     if (*registry == NULL) {
         int rc;
 
+        if (PyErr_Occurred()) {
+            return 0;
+        }
         *registry = PyDict_New();
         if (*registry == NULL)
             return 0;
 
-         rc = PyDict_SetItemString(globals, "__warningregistry__", *registry);
+         rc = _PyDict_SetItemId(globals, &PyId___warningregistry__, *registry);
          if (rc < 0)
             goto handle_error;
     }
@@ -722,10 +730,13 @@
         Py_INCREF(*registry);
 
     /* Setup module. */
-    *module = PyDict_GetItemString(globals, "__name__");
+    *module = _PyDict_GetItemIdWithError(globals, &PyId___name__);
     if (*module == Py_None || (*module != NULL && PyUnicode_Check(*module))) {
         Py_INCREF(*module);
     }
+    else if (PyErr_Occurred()) {
+        goto handle_error;
+    }
     else {
         *module = PyUnicode_FromString("<string>");
         if (*module == NULL)
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index f9b901f..eebdc5b 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -142,7 +142,7 @@
             return NULL;
         }
 
-        meta = _PyDict_GetItemId(mkw, &PyId_metaclass);
+        meta = _PyDict_GetItemIdWithError(mkw, &PyId_metaclass);
         if (meta != NULL) {
             Py_INCREF(meta);
             if (_PyDict_DelItemId(mkw, &PyId_metaclass) < 0) {
@@ -154,6 +154,11 @@
             /* metaclass is explicitly given, check if it's indeed a class */
             isclass = PyType_Check(meta);
         }
+        else if (PyErr_Occurred()) {
+            Py_DECREF(mkw);
+            Py_DECREF(bases);
+            return NULL;
+        }
     }
     if (meta == NULL) {
         /* if there are no bases, use type: */
@@ -956,11 +961,14 @@
         return NULL;
     }
 
-    if (_PyDict_GetItemId(globals, &PyId___builtins__) == NULL) {
+    if (_PyDict_GetItemIdWithError(globals, &PyId___builtins__) == NULL) {
         if (_PyDict_SetItemId(globals, &PyId___builtins__,
                               PyEval_GetBuiltins()) != 0)
             return NULL;
     }
+    else if (PyErr_Occurred()) {
+        return NULL;
+    }
 
     if (PyCode_Check(source)) {
         if (PyCode_GetNumFree((PyCodeObject *)source) > 0) {
@@ -1036,11 +1044,14 @@
             locals->ob_type->tp_name);
         return NULL;
     }
-    if (_PyDict_GetItemId(globals, &PyId___builtins__) == NULL) {
+    if (_PyDict_GetItemIdWithError(globals, &PyId___builtins__) == NULL) {
         if (_PyDict_SetItemId(globals, &PyId___builtins__,
                               PyEval_GetBuiltins()) != 0)
             return NULL;
     }
+    else if (PyErr_Occurred()) {
+        return NULL;
+    }
 
     if (PyCode_Check(source)) {
         if (PyCode_GetNumFree((PyCodeObject *)source) > 0) {
diff --git a/Python/ceval.c b/Python/ceval.c
index 4e139ce..68c1617 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -2090,10 +2090,12 @@
 
             PyObject *bc;
             if (PyDict_CheckExact(f->f_builtins)) {
-                bc = _PyDict_GetItemId(f->f_builtins, &PyId___build_class__);
+                bc = _PyDict_GetItemIdWithError(f->f_builtins, &PyId___build_class__);
                 if (bc == NULL) {
-                    PyErr_SetString(PyExc_NameError,
-                                    "__build_class__ not found");
+                    if (!PyErr_Occurred()) {
+                        PyErr_SetString(PyExc_NameError,
+                                        "__build_class__ not found");
+                    }
                     goto error;
                 }
                 Py_INCREF(bc);
@@ -2241,8 +2243,10 @@
             int err;
             err = PyDict_DelItem(f->f_globals, name);
             if (err != 0) {
-                format_exc_check_arg(
-                    PyExc_NameError, NAME_ERROR_MSG, name);
+                if (PyErr_ExceptionMatches(PyExc_KeyError)) {
+                    format_exc_check_arg(
+                        PyExc_NameError, NAME_ERROR_MSG, name);
+                }
                 goto error;
             }
             DISPATCH();
@@ -2258,8 +2262,13 @@
                 goto error;
             }
             if (PyDict_CheckExact(locals)) {
-                v = PyDict_GetItem(locals, name);
-                Py_XINCREF(v);
+                v = PyDict_GetItemWithError(locals, name);
+                if (v != NULL) {
+                    Py_INCREF(v);
+                }
+                else if (PyErr_Occurred()) {
+                    goto error;
+                }
             }
             else {
                 v = PyObject_GetItem(locals, name);
@@ -2270,15 +2279,22 @@
                 }
             }
             if (v == NULL) {
-                v = PyDict_GetItem(f->f_globals, name);
-                Py_XINCREF(v);
-                if (v == NULL) {
+                v = PyDict_GetItemWithError(f->f_globals, name);
+                if (v != NULL) {
+                    Py_INCREF(v);
+                }
+                else if (PyErr_Occurred()) {
+                    goto error;
+                }
+                else {
                     if (PyDict_CheckExact(f->f_builtins)) {
-                        v = PyDict_GetItem(f->f_builtins, name);
+                        v = PyDict_GetItemWithError(f->f_builtins, name);
                         if (v == NULL) {
-                            format_exc_check_arg(
+                            if (!PyErr_Occurred()) {
+                                format_exc_check_arg(
                                         PyExc_NameError,
                                         NAME_ERROR_MSG, name);
+                            }
                             goto error;
                         }
                         Py_INCREF(v);
@@ -2386,8 +2402,13 @@
             assert(idx >= 0 && idx < PyTuple_GET_SIZE(co->co_freevars));
             name = PyTuple_GET_ITEM(co->co_freevars, idx);
             if (PyDict_CheckExact(locals)) {
-                value = PyDict_GetItem(locals, name);
-                Py_XINCREF(value);
+                value = PyDict_GetItemWithError(locals, name);
+                if (value != NULL) {
+                    Py_INCREF(value);
+                }
+                else if (PyErr_Occurred()) {
+                    goto error;
+                }
             }
             else {
                 value = PyObject_GetItem(locals, name);
@@ -2591,9 +2612,12 @@
             }
             /* check if __annotations__ in locals()... */
             if (PyDict_CheckExact(f->f_locals)) {
-                ann_dict = _PyDict_GetItemId(f->f_locals,
+                ann_dict = _PyDict_GetItemIdWithError(f->f_locals,
                                              &PyId___annotations__);
                 if (ann_dict == NULL) {
+                    if (PyErr_Occurred()) {
+                        goto error;
+                    }
                     /* ...if not, create a new one */
                     ann_dict = PyDict_New();
                     if (ann_dict == NULL) {
@@ -3807,16 +3831,11 @@
 
     /* Pack other positional arguments into the *args argument */
     if (co->co_flags & CO_VARARGS) {
-        u = PyTuple_New(argcount - n);
+        u = _PyTuple_FromArray(args + n, argcount - n);
         if (u == NULL) {
             goto fail;
         }
         SETLOCAL(total_args, u);
-        for (i = n; i < argcount; i++) {
-            x = args[i];
-            Py_INCREF(x);
-            PyTuple_SET_ITEM(u, i-n, x);
-        }
     }
 
     /* Handle keyword arguments passed as two strided arrays */
@@ -3921,12 +3940,15 @@
                 continue;
             name = PyTuple_GET_ITEM(co->co_varnames, i);
             if (kwdefs != NULL) {
-                PyObject *def = PyDict_GetItem(kwdefs, name);
+                PyObject *def = PyDict_GetItemWithError(kwdefs, name);
                 if (def) {
                     Py_INCREF(def);
                     SETLOCAL(i, def);
                     continue;
                 }
+                else if (PyErr_Occurred()) {
+                    goto fail;
+                }
             }
             missing++;
         }
@@ -4861,9 +4883,11 @@
     PyObject *import_func, *res;
     PyObject* stack[5];
 
-    import_func = _PyDict_GetItemId(f->f_builtins, &PyId___import__);
+    import_func = _PyDict_GetItemIdWithError(f->f_builtins, &PyId___import__);
     if (import_func == NULL) {
-        PyErr_SetString(PyExc_ImportError, "__import__ not found");
+        if (!PyErr_Occurred()) {
+            PyErr_SetString(PyExc_ImportError, "__import__ not found");
+        }
         return NULL;
     }
 
@@ -5207,10 +5231,13 @@
             PyObject *names = f->f_code->co_names;
             PyObject *name = GETITEM(names, oparg);
             PyObject *locals = f->f_locals;
-            if (locals && PyDict_CheckExact(locals) &&
-                PyDict_GetItem(locals, name) == v) {
-                if (PyDict_DelItem(locals, name) != 0) {
-                    PyErr_Clear();
+            if (locals && PyDict_CheckExact(locals)) {
+                PyObject *w = PyDict_GetItemWithError(locals, name);
+                if ((w == v && PyDict_DelItem(locals, name) != 0) ||
+                    (w == NULL && PyErr_Occurred()))
+                {
+                    Py_DECREF(v);
+                    return NULL;
                 }
             }
             break;
diff --git a/Python/codecs.c b/Python/codecs.c
index ff2142d..d4b34f8 100644
--- a/Python/codecs.c
+++ b/Python/codecs.c
@@ -120,12 +120,16 @@
     PyUnicode_InternInPlace(&v);
 
     /* First, try to lookup the name in the registry dictionary */
-    result = PyDict_GetItem(interp->codec_search_cache, v);
+    result = PyDict_GetItemWithError(interp->codec_search_cache, v);
     if (result != NULL) {
         Py_INCREF(result);
         Py_DECREF(v);
         return result;
     }
+    else if (PyErr_Occurred()) {
+        Py_DECREF(v);
+        return NULL;
+    }
 
     /* Next, scan the search functions in order of registration */
     args = PyTuple_New(1);
@@ -648,11 +652,13 @@
 
     if (name==NULL)
         name = "strict";
-    handler = PyDict_GetItemString(interp->codec_error_registry, name);
-    if (!handler)
-        PyErr_Format(PyExc_LookupError, "unknown error handler name '%.400s'", name);
-    else
+    handler = _PyDict_GetItemStringWithError(interp->codec_error_registry, name);
+    if (handler) {
         Py_INCREF(handler);
+    }
+    else if (!PyErr_Occurred()) {
+        PyErr_Format(PyExc_LookupError, "unknown error handler name '%.400s'", name);
+    }
     return handler;
 }
 
diff --git a/Python/errors.c b/Python/errors.c
index febe971..b8af1df 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -858,6 +858,7 @@
 PyObject *
 PyErr_NewException(const char *name, PyObject *base, PyObject *dict)
 {
+    _Py_IDENTIFIER(__module__);
     const char *dot;
     PyObject *modulename = NULL;
     PyObject *classname = NULL;
@@ -877,12 +878,15 @@
         if (dict == NULL)
             goto failure;
     }
-    if (PyDict_GetItemString(dict, "__module__") == NULL) {
+    if (_PyDict_GetItemIdWithError(dict, &PyId___module__) == NULL) {
+        if (PyErr_Occurred()) {
+            goto failure;
+        }
         modulename = PyUnicode_FromStringAndSize(name,
                                              (Py_ssize_t)(dot-name));
         if (modulename == NULL)
             goto failure;
-        if (PyDict_SetItemString(dict, "__module__", modulename) != 0)
+        if (_PyDict_SetItemId(dict, &PyId___module__, modulename) != 0)
             goto failure;
     }
     if (PyTuple_Check(base)) {
diff --git a/Python/getargs.c b/Python/getargs.c
index c491169..ba1a9d4 100644
--- a/Python/getargs.c
+++ b/Python/getargs.c
@@ -650,7 +650,9 @@
 #define CONV_UNICODE "(unicode conversion error)"
 
 /* Explicitly check for float arguments when integers are expected.
-   Return 1 for error, 0 if ok. */
+   Return 1 for error, 0 if ok.
+   XXX Should be removed after the end of the deprecation period in
+   _PyLong_FromNbIndexOrNbInt. */
 static int
 float_argument_error(PyObject *arg)
 {
@@ -1761,9 +1763,13 @@
                 current_arg = PyTuple_GET_ITEM(args, i);
             }
             else if (nkwargs && i >= pos) {
-                current_arg = PyDict_GetItemString(kwargs, kwlist[i]);
-                if (current_arg)
+                current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]);
+                if (current_arg) {
                     --nkwargs;
+                }
+                else if (PyErr_Occurred()) {
+                    return cleanreturn(0, &freelist);
+                }
             }
             else {
                 current_arg = NULL;
@@ -1842,7 +1848,7 @@
         Py_ssize_t j;
         /* make sure there are no arguments given by name and position */
         for (i = pos; i < nargs; i++) {
-            current_arg = PyDict_GetItemString(kwargs, kwlist[i]);
+            current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]);
             if (current_arg) {
                 /* arg present in tuple and in dict */
                 PyErr_Format(PyExc_TypeError,
@@ -1853,6 +1859,9 @@
                              kwlist[i], i+1);
                 return cleanreturn(0, &freelist);
             }
+            else if (PyErr_Occurred()) {
+                return cleanreturn(0, &freelist);
+            }
         }
         /* make sure there are no extraneous keyword arguments */
         j = 0;
@@ -2014,13 +2023,10 @@
 }
 
 static PyObject*
-find_keyword(PyObject *kwargs, PyObject *kwnames, PyObject *const *kwstack, PyObject *key)
+find_keyword(PyObject *kwnames, PyObject *const *kwstack, PyObject *key)
 {
     Py_ssize_t i, nkwargs;
 
-    if (kwargs != NULL) {
-        return PyDict_GetItem(kwargs, key);
-    }
     nkwargs = PyTuple_GET_SIZE(kwnames);
     for (i=0; i < nkwargs; i++) {
         PyObject *kwname = PyTuple_GET_ITEM(kwnames, i);
@@ -2155,9 +2161,18 @@
         }
         else if (nkwargs && i >= pos) {
             keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
-            current_arg = find_keyword(kwargs, kwnames, kwstack, keyword);
-            if (current_arg)
+            if (kwargs != NULL) {
+                current_arg = PyDict_GetItemWithError(kwargs, keyword);
+                if (!current_arg && PyErr_Occurred()) {
+                    return cleanreturn(0, &freelist);
+                }
+            }
+            else {
+                current_arg = find_keyword(kwnames, kwstack, keyword);
+            }
+            if (current_arg) {
                 --nkwargs;
+            }
         }
         else {
             current_arg = NULL;
@@ -2218,7 +2233,15 @@
         /* make sure there are no arguments given by name and position */
         for (i = pos; i < nargs; i++) {
             keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
-            current_arg = find_keyword(kwargs, kwnames, kwstack, keyword);
+            if (kwargs != NULL) {
+                current_arg = PyDict_GetItemWithError(kwargs, keyword);
+                if (!current_arg && PyErr_Occurred()) {
+                    return cleanreturn(0, &freelist);
+                }
+            }
+            else {
+                current_arg = find_keyword(kwnames, kwstack, keyword);
+            }
             if (current_arg) {
                 /* arg present in tuple and in dict */
                 PyErr_Format(PyExc_TypeError,
diff --git a/Python/import.c b/Python/import.c
index 344f199..898321a 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -431,9 +431,13 @@
     for (p = sys_files; *p != NULL; p+=2) {
         if (Py_VerboseFlag)
             PySys_WriteStderr("# restore sys.%s\n", *p);
-        value = PyDict_GetItemString(interp->sysdict, *(p+1));
-        if (value == NULL)
+        value = _PyDict_GetItemStringWithError(interp->sysdict, *(p+1));
+        if (value == NULL) {
+            if (PyErr_Occurred()) {
+                PyErr_WriteUnraisable(NULL);
+            }
             value = Py_None;
+        }
         if (PyDict_SetItemString(interp->sysdict, *p, value) < 0) {
             PyErr_WriteUnraisable(NULL);
         }
@@ -718,7 +722,7 @@
     key = PyTuple_Pack(2, filename, name);
     if (key == NULL)
         return NULL;
-    def = (PyModuleDef *)PyDict_GetItem(extensions, key);
+    def = (PyModuleDef *)PyDict_GetItemWithError(extensions, key);
     Py_DECREF(key);
     if (def == NULL)
         return NULL;
@@ -927,6 +931,7 @@
 static PyObject *
 module_dict_for_exec(PyObject *name)
 {
+    _Py_IDENTIFIER(__builtins__);
     PyObject *m, *d = NULL;
 
     m = PyImport_AddModuleObject(name);
@@ -935,9 +940,11 @@
     /* If the module is being reloaded, we get the old module back
        and re-use its dict to exec the new code. */
     d = PyModule_GetDict(m);
-    if (PyDict_GetItemString(d, "__builtins__") == NULL) {
-        if (PyDict_SetItemString(d, "__builtins__",
-                                 PyEval_GetBuiltins()) != 0) {
+    if (_PyDict_GetItemIdWithError(d, &PyId___builtins__) == NULL) {
+        if (PyErr_Occurred() ||
+            _PyDict_SetItemId(d, &PyId___builtins__,
+                              PyEval_GetBuiltins()) != 0)
+        {
             remove_module(name);
             return NULL;
         }
@@ -1107,8 +1114,8 @@
     if (nhooks < 0)
         return NULL; /* Shouldn't happen */
 
-    importer = PyDict_GetItem(path_importer_cache, p);
-    if (importer != NULL)
+    importer = PyDict_GetItemWithError(path_importer_cache, p);
+    if (importer != NULL || PyErr_Occurred())
         return importer;
 
     /* set path_importer_cache[p] to None to avoid recursion */
@@ -1496,11 +1503,17 @@
         PyErr_SetString(PyExc_TypeError, "globals must be a dict");
         goto error;
     }
-    package = _PyDict_GetItemId(globals, &PyId___package__);
+    package = _PyDict_GetItemIdWithError(globals, &PyId___package__);
     if (package == Py_None) {
         package = NULL;
     }
-    spec = _PyDict_GetItemId(globals, &PyId___spec__);
+    else if (package == NULL && PyErr_Occurred()) {
+        goto error;
+    }
+    spec = _PyDict_GetItemIdWithError(globals, &PyId___spec__);
+    if (spec == NULL && PyErr_Occurred()) {
+        goto error;
+    }
 
     if (package != NULL) {
         Py_INCREF(package);
@@ -1546,9 +1559,11 @@
             goto error;
         }
 
-        package = _PyDict_GetItemId(globals, &PyId___name__);
+        package = _PyDict_GetItemIdWithError(globals, &PyId___name__);
         if (package == NULL) {
-            PyErr_SetString(PyExc_KeyError, "'__name__' not in globals");
+            if (!PyErr_Occurred()) {
+                PyErr_SetString(PyExc_KeyError, "'__name__' not in globals");
+            }
             goto error;
         }
 
@@ -1558,10 +1573,10 @@
             goto error;
         }
 
-        if (_PyDict_GetItemId(globals, &PyId___path__) == NULL) {
+        if (_PyDict_GetItemIdWithError(globals, &PyId___path__) == NULL) {
             Py_ssize_t dot;
 
-            if (PyUnicode_READY(package) < 0) {
+            if (PyErr_Occurred() || PyUnicode_READY(package) < 0) {
                 goto error;
             }
 
diff --git a/Python/symtable.c b/Python/symtable.c
index cade304..6e2df2f 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -359,12 +359,12 @@
     k = PyLong_FromVoidPtr(key);
     if (k == NULL)
         return NULL;
-    v = PyDict_GetItem(st->st_blocks, k);
+    v = PyDict_GetItemWithError(st->st_blocks, k);
     if (v) {
         assert(PySTEntry_Check(v));
         Py_INCREF(v);
     }
-    else {
+    else if (!PyErr_Occurred()) {
         PyErr_SetString(PyExc_KeyError,
                         "unknown symbol table entry");
     }
@@ -637,7 +637,7 @@
     }
 
     while ((name = PyIter_Next(itr))) {
-        v = PyDict_GetItem(symbols, name);
+        v = PyDict_GetItemWithError(symbols, name);
 
         /* Handle symbol that already exists in this scope */
         if (v) {
@@ -662,6 +662,9 @@
             Py_DECREF(name);
             continue;
         }
+        else if (PyErr_Occurred()) {
+            goto error;
+        }
         /* Handle global symbol */
         if (bound && !PySet_Contains(bound, name)) {
             Py_DECREF(name);
@@ -991,7 +994,7 @@
     if (!mangled)
         return 0;
     dict = ste->ste_symbols;
-    if ((o = PyDict_GetItem(dict, mangled))) {
+    if ((o = PyDict_GetItemWithError(dict, mangled))) {
         val = PyLong_AS_LONG(o);
         if ((flag & DEF_PARAM) && (val & DEF_PARAM)) {
             /* Is it better to use 'mangled' or 'name' here? */
@@ -1002,8 +1005,13 @@
             goto error;
         }
         val |= flag;
-    } else
+    }
+    else if (PyErr_Occurred()) {
+        goto error;
+    }
+    else {
         val = flag;
+    }
     o = PyLong_FromLong(val);
     if (o == NULL)
         goto error;
diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
index f4f0017..0e7ce96 100755
--- a/Tools/clinic/clinic.py
+++ b/Tools/clinic/clinic.py
@@ -2602,6 +2602,8 @@
 
     def parse_arg(self, argname, argnum):
         if self.format_unit == 'i':
+            # XXX PyFloat_Check can be removed after the end of the
+            # deprecation in _PyLong_FromNbIndexOrNbInt.
             return """
                 if (PyFloat_Check({argname})) {{{{
                     PyErr_SetString(PyExc_TypeError,