diff -r be22ffb4fdf1 Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst Fri Dec 20 13:25:53 2013 -0600 +++ b/Doc/reference/datamodel.rst Sat Dec 28 11:46:46 2013 -0800 @@ -2077,20 +2077,26 @@ left undefined. :func:`int`, :func:`float` and :func:`round`. Should return a value of the appropriate type. .. method:: object.__index__(self) Called to implement :func:`operator.index`. Also called whenever Python needs an integer object (such as in slicing, or in the built-in :func:`bin`, :func:`hex` and :func:`oct` functions). Must return an integer. + .. note:: + + When :meth:`__index__` is defined, :meth:`__int__` should also be defined, + and both shuld return the same value, in order to have a coherent integer + type class. + .. _context-managers: With Statement Context Managers ------------------------------- A :dfn:`context manager` is an object that defines the runtime context to be established when executing a :keyword:`with` statement. The context manager handles the entry into, and the exit from, the desired runtime context for the execution of the block of code. Context managers are normally invoked using the diff -r be22ffb4fdf1 Lib/test/test_unicode.py --- a/Lib/test/test_unicode.py Fri Dec 20 13:25:53 2013 -0600 +++ b/Lib/test/test_unicode.py Sat Dec 28 11:46:46 2013 -0800 @@ -1119,20 +1119,49 @@ class UnicodeTest(string_tests.CommonTes INF = float('inf') self.assertEqual('%f' % NAN, 'nan') self.assertEqual('%F' % NAN, 'NAN') self.assertEqual('%f' % INF, 'inf') self.assertEqual('%F' % INF, 'INF') # PEP 393 self.assertEqual('%.1s' % "a\xe9\u20ac", 'a') self.assertEqual('%.2s' % "a\xe9\u20ac", 'a\xe9') + #issue 19995 + class PsuedoInt: + def __init__(self, value): + self.value = int(value) + def __int__(self): + return self.value + def __index__(self): + return self.value + class PsuedoFlaot: + def __init__(self, value): + self.value = float(value) + def __int__(self): + return int(self.value) + pi = PsuedoFlaot(3.1415) + lucky = PsuedoInt(109) + self.assertEquals('%x' % 42, '2a') + self.assertEquals('%X' % 15, 'F') + self.assertEquals('%o' % 9, '11') + self.assertEquals('%c' % 109, 'm') + self.assertEquals('%x' % lucky, '6d') + self.assertEquals('%X' % lucky, '6D') + self.assertEquals('%o' % lucky, '155') + self.assertEquals('%c' % lucky, 'm') + self.assertRaises(TypeError, '%x'.__mod__, pi) + self.assertRaises(TypeError, '%x'.__mod__, 3.14) + self.assertRaises(TypeError, '%X'.__mod__, 2.11) + self.assertRaises(TypeError, '%o'.__mod__, 1.79) + self.assertRaises(TypeError, '%c'.__mod__, pi) + def test_formatting_with_enum(self): # issue18780 import enum class Float(float, enum.Enum): PI = 3.1415926 class Int(enum.IntEnum): IDES = 15 class Str(str, enum.Enum): ABC = 'abc' # Testing Unicode formatting strings... diff -r be22ffb4fdf1 Objects/unicodeobject.c --- a/Objects/unicodeobject.c Fri Dec 20 13:25:53 2013 -0600 +++ b/Objects/unicodeobject.c Sat Dec 28 11:46:46 2013 -0800 @@ -14008,42 +14008,51 @@ formatlong(PyObject *val, struct unicode Py_DECREF(result); result = unicode; } else if (len != PyUnicode_GET_LENGTH(result)) { if (PyUnicode_Resize(&result, len) < 0) Py_CLEAR(result); } return result; } -/* Format an integer. +/* Format an integer or a float as an integer. * Return 1 if the number has been formatted into the writer, * 0 if the number has been formatted into *p_output * -1 and raise an exception on error */ static int mainformatlong(PyObject *v, struct unicode_format_arg_t *arg, PyObject **p_output, _PyUnicodeWriter *writer) { PyObject *iobj, *res; char type = (char)arg->ch; if (!PyNumber_Check(v)) goto wrongtype; if (!PyLong_Check(v)) { - iobj = PyNumber_Long(v); - if (iobj == NULL) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - goto wrongtype; - return -1; + if (type == 'o' || type == 'x' || type == 'X') { + iobj = PyNumber_Index(v); + if (iobj == NULL) { + return -1; + } + Py_INCREF(iobj); + } + else { + iobj = PyNumber_Long(v); + if (iobj == NULL ) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + goto wrongtype; + return -1; + } } assert(PyLong_Check(iobj)); } else { iobj = v; Py_INCREF(iobj); } if (PyLong_CheckExact(v) && arg->width == -1 && arg->prec == -1 @@ -14099,22 +14108,31 @@ static Py_UCS4 formatchar(PyObject *v) { /* presume that the buffer is at least 3 characters long */ if (PyUnicode_Check(v)) { if (PyUnicode_GET_LENGTH(v) == 1) { return PyUnicode_READ_CHAR(v, 0); } goto onError; } else { + PyObject *iobj; + long x; + /* make sure number is a type of integer */ + if (!PyLong_Check(v)) { + iobj = PyNumber_Index(v); + if (iobj == NULL) { + goto onError; + } + v = iobj; + } /* Integer input truncated to a character */ - long x; x = PyLong_AsLong(v); if (x == -1 && PyErr_Occurred()) goto onError; if (x < 0 || x > MAX_UNICODE) { PyErr_SetString(PyExc_OverflowError, "%c arg not in range(0x110000)"); return (Py_UCS4) -1; } @@ -14302,21 +14320,22 @@ unicode_format_arg_parse(struct unicode_ return -1; } return 0; #undef FORMAT_READ } /* Format one argument. Supported conversion specifiers: - "s", "r", "a": any type - - "i", "d", "u", "o", "x", "X": int + - "i", "d", "u": int or float + - "o", "x", "X": int - "e", "E", "f", "F", "g", "G": float - "c": int or str (1 character) When possible, the output is written directly into the Unicode writer (ctx->writer). A string is created when padding is required. Return 0 if the argument has been formatted into *p_str, 1 if the argument has been written into ctx->writer, -1 on error. */ static int