From 07c71365244ce496042566d94bdd469f7d3b1bf6 Mon Sep 17 00:00:00 2001
From: Mark Dickinson <dickinsm@gmail.com>
Date: Sun, 27 Jan 2013 10:17:52 +0000
Subject: [PATCH] Issue #16772: in int(x, base), non-integer bases must have an
 __index__ method.

---
 Doc/library/functions.rst |  6 ++++++
 Lib/test/test_int.py      | 17 +++++++++++++++++
 Misc/NEWS                 |  4 ++++
 Objects/longobject.c      |  5 -----
 4 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
index c52dc06b30..64b46a3a5b 100644
--- a/Doc/library/functions.rst
+++ b/Doc/library/functions.rst
@@ -665,6 +665,12 @@ are always available.  They are listed here in alphabetical order.
 
    The integer type is described in :ref:`typesnumeric`.
 
+   .. versionchanged:: 3.4
+      If *base* is not an instance of :class:`int` and the *base* object has a
+      :meth:`base.__index__ <object.__index__>` method, that method is called
+      to obtain an integer for the base.  Previous versions used
+      :meth:`base.__int__ <object.__int__>` instead of :meth:`base.__index__
+      <object.__index__>`.
 
 .. function:: isinstance(object, classinfo)
 
diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py
index 09b9a7785b..afc91699a9 100644
--- a/Lib/test/test_int.py
+++ b/Lib/test/test_int.py
@@ -260,6 +260,23 @@ class IntTestCases(unittest.TestCase):
         with self.assertRaises(TypeError):
             int('0', 5.0)
 
+    def test_int_base_indexable(self):
+        class MyIndexable(object):
+            def __init__(self, value):
+                self.value = value
+            def __index__(self):
+                return self.value
+
+        # Check out of range bases.
+        for base in 2**100, -2**100, 1, 37:
+            with self.assertRaises(ValueError):
+                int('43', base)
+
+        # Check in-range bases.
+        self.assertEqual(int('101', base=MyIndexable(2)), 5)
+        self.assertEqual(int('101', base=MyIndexable(10)), 101)
+        self.assertEqual(int('101', base=MyIndexable(36)), 1 + 36**2)
+
     def test_non_numeric_input_types(self):
         # Test possible non-numeric types for the argument x, including
         # subclasses of the explicitly documented accepted types.
diff --git a/Misc/NEWS b/Misc/NEWS
index 01842ce5c2..d2f15b383d 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,10 @@ What's New in Python 3.4.0 Alpha 1?
 Core and Builtins
 -----------------
 
+- Issue #16772: The base argument to the int constructor no longer accepts
+  floats, or other non-integer objects with an __int__ method.  Objects
+  with an __index__ method are now accepted.
+
 - Issue #10156: In the interpreter's initialization phase, unicode globals
   are now initialized dynamically as needed.
 
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 1a82b1c67a..bec0a78008 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -4283,11 +4283,6 @@ long_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     }
     if (obase == NULL)
         return PyNumber_Long(x);
-    if (!PyLong_Check(obase)) {
-        PyErr_SetString(PyExc_TypeError,
-                        "int() base must be an integer.");
-        return NULL;
-    }
 
     base = PyNumber_AsSsize_t(obase, NULL);
     if (base == -1 && PyErr_Occurred())
-- 
2.40.0