Index: Python/bltinmodule.c =================================================================== --- Python/bltinmodule.c (revision 62536) +++ Python/bltinmodule.c (working copy) @@ -1136,22 +1136,29 @@ { PyNumberMethods *nb; PyObject *res; - - if ((nb = v->ob_type->tp_as_number) == NULL || - nb->nb_hex == NULL) { - PyErr_SetString(PyExc_TypeError, - "hex() argument can't be converted to hex"); - return NULL; + + nb = Py_TYPE(v)->tp_as_number; + + if (nb != NULL && nb->nb_hex != NULL) { + if (PyErr_WarnPy3k("In 3.x, hex() converts " + "the result of __index__ to hexidecimal.", + 1) < 0) + return NULL; + res = (*nb->nb_hex)(v); + if (res && !PyString_Check(res)) { + PyErr_Format(PyExc_TypeError, + "__hex__ returned non-string (type %.200s)", + res->ob_type->tp_name); + Py_DECREF(res); + return NULL; + } + return res; } - res = (*nb->nb_hex)(v); - if (res && !PyString_Check(res)) { - PyErr_Format(PyExc_TypeError, - "__hex__ returned non-string (type %.200s)", - res->ob_type->tp_name); - Py_DECREF(res); - return NULL; - } - return res; + else if (PyIndex_Check(v)) + return PyNumber_ToBase(v, 16); + PyErr_SetString(PyExc_TypeError, + "hex() argument can't be converted to hex"); + return NULL; } PyDoc_STRVAR(hex_doc, @@ -1411,6 +1418,9 @@ "oct() argument can't be converted to oct"); return NULL; } + if (PyErr_WarnPy3k("In 3.x, oct() converts the result of __index__ to octal; " + "Use future_builtins.oct for this behavior.", 1) < 0) + return NULL; res = (*nb->nb_oct)(v); if (res && !PyString_Check(res)) { PyErr_Format(PyExc_TypeError, Index: Lib/test/test_py3kwarn.py =================================================================== --- Lib/test/test_py3kwarn.py (revision 62534) +++ Lib/test/test_py3kwarn.py (working copy) @@ -123,7 +123,20 @@ with catch_warning() as w: self.assertWarning(buffer('a'), w, expected) + def test_hex_and_oct(self): + class Spam(object): + def __hex__(self): return "0x17" + def __oct__(self): return "07" + expected = 'In 3.x, oct() converts the result of __index__ to octal; ' \ + 'Use future_builtins.oct for this behavior.' + with catch_warning() as w: + self.assertWarning(oct(Spam()), w, expected) + expected = 'In 3.x, hex() converts the result of __index__ to hexidecimal.' + with catch_warning() as w: + self.assertWarning(hex(Spam()), w, expected) + + def test_main(): run_unittest(TestPy3KWarnings) Index: Lib/test/test_builtin.py =================================================================== --- Lib/test/test_builtin.py (revision 62534) +++ Lib/test/test_builtin.py (working copy) @@ -770,6 +770,10 @@ self.assertEqual(hex(-16L), '-0x10L') self.assertRaises(TypeError, hex, {}) + class Spam(object): + def __index__(self): return 23 + self.assertEqual(hex(Spam()), "0x17") + def test_id(self): id(None) id(1)