]> granicus.if.org Git - python/commitdiff
Issue 1742669. Now %d accepts very big float numbers.
authorFacundo Batista <facundobatista@gmail.com>
Sun, 24 Feb 2008 03:17:21 +0000 (03:17 +0000)
committerFacundo Batista <facundobatista@gmail.com>
Sun, 24 Feb 2008 03:17:21 +0000 (03:17 +0000)
Thanks Gabriel Genellina.

Lib/test/string_tests.py
Lib/test/test_format.py
Objects/stringobject.c
Objects/unicodeobject.c

index cefdcacfec6abc06312e30bc24ba1681f29d7ed0..4e2b37eca00a9571a187ad687262fd4b9befd252 100644 (file)
@@ -1033,7 +1033,14 @@ class MixinStrUnicodeUserStringTest:
             # unicode raises ValueError, str raises OverflowError
             self.checkraises((ValueError, OverflowError), '%c', '__mod__', ordinal)
 
+        longvalue = sys.maxint + 10L
+        slongvalue = str(longvalue)
+        if slongvalue[-1] in ("L","l"): slongvalue = slongvalue[:-1]
         self.checkequal(' 42', '%3ld', '__mod__', 42)
+        self.checkequal('42', '%d', '__mod__', 42L)
+        self.checkequal('42', '%d', '__mod__', 42.0)
+        self.checkequal(slongvalue, '%d', '__mod__', longvalue)
+        self.checkcall('%d', '__mod__', float(longvalue))
         self.checkequal('0042.00', '%07.2f', '__mod__', 42)
         self.checkequal('0042.00', '%07.2F', '__mod__', 42)
 
@@ -1043,6 +1050,8 @@ class MixinStrUnicodeUserStringTest:
         self.checkraises(TypeError, '%c', '__mod__', (None,))
         self.checkraises(ValueError, '%(foo', '__mod__', {})
         self.checkraises(TypeError, '%(foo)s %(bar)s', '__mod__', ('foo', 42))
+        self.checkraises(TypeError, '%d', '__mod__', "42") # not numeric
+        self.checkraises(TypeError, '%d', '__mod__', (42+0j)) # no int/long conversion provided
 
         # argument names with properly nested brackets are supported
         self.checkequal('bar', '%((foo))s', '__mod__', {'(foo)': 'bar'})
index c4cfa11935478dcd70b765e605375bfe89d1c784..76b9fd43f20a41356146019046e748dcb3d1ce31 100644 (file)
@@ -11,7 +11,7 @@ maxsize = MAX_Py_ssize_t
 overflowok = 1
 overflowrequired = 0
 
-def testformat(formatstr, args, output=None):
+def testformat(formatstr, args, output=None, limit=None):
     if verbose:
         if output:
             print "%s %% %s =? %s ..." %\
@@ -31,7 +31,18 @@ def testformat(formatstr, args, output=None):
                 print 'no'
             print "overflow expected on %s %% %s" % \
                   (repr(formatstr), repr(args))
-        elif output and result != output:
+        elif output and limit is None and result != output:
+            if verbose:
+                print 'no'
+            print "%s %% %s == %s != %s" % \
+                  (repr(formatstr), repr(args), repr(result), repr(output))
+        # when 'limit' is specified, it determines how many characters
+        # must match exactly; lengths must always match.
+        # ex: limit=5, '12345678' matches '12345___'
+        # (mainly for floating point format tests for which an exact match
+        # can't be guaranteed due to rounding and representation errors)
+        elif output and limit is not None and (
+                len(result)!=len(output) or result[:limit]!=output[:limit]):
             if verbose:
                 print 'no'
             print "%s %% %s == %s != %s" % \
@@ -98,6 +109,7 @@ testboth("%.2d", big, "123456789012345678901234567890")
 testboth("%.30d", big, "123456789012345678901234567890")
 testboth("%.31d", big, "0123456789012345678901234567890")
 testboth("%32.31d", big, " 0123456789012345678901234567890")
+testboth("%d", float(big), "123456________________________", 6)
 
 big = 0x1234567890abcdef12345L  # 21 hex digits
 testboth("%x", big, "1234567890abcdef12345")
@@ -135,6 +147,7 @@ testboth("%#+27.23X", big, " +0X001234567890ABCDEF12345")
 testboth("%#+027.23X", big, "+0X0001234567890ABCDEF12345")
 # same, except no 0 flag
 testboth("%#+27.23X", big, " +0X001234567890ABCDEF12345")
+testboth("%x", float(big), "123456_______________", 6)
 
 big = 012345670123456701234567012345670L  # 32 octal digits
 testboth("%o", big, "12345670123456701234567012345670")
@@ -175,16 +188,19 @@ testboth("%#.32o", big, "012345670123456701234567012345670")
 testboth("%034.33o", big, "0012345670123456701234567012345670")
 # base marker shouldn't change that
 testboth("%0#34.33o", big, "0012345670123456701234567012345670")
+testboth("%o", float(big), "123456__________________________", 6)
 
 # Some small ints, in both Python int and long flavors).
 testboth("%d", 42, "42")
 testboth("%d", -42, "-42")
 testboth("%d", 42L, "42")
 testboth("%d", -42L, "-42")
+testboth("%d", 42.0, "42")
 testboth("%#x", 1, "0x1")
 testboth("%#x", 1L, "0x1")
 testboth("%#X", 1, "0X1")
 testboth("%#X", 1L, "0X1")
+testboth("%#x", 1.0, "0x1")
 testboth("%#o", 1, "01")
 testboth("%#o", 1L, "01")
 testboth("%#o", 0, "0")
@@ -202,11 +218,13 @@ testboth("%x", 0x42, "42")
 testboth("%x", -0x42, "-42")
 testboth("%x", 0x42L, "42")
 testboth("%x", -0x42L, "-42")
+testboth("%x", float(0x42), "42")
 
 testboth("%o", 042, "42")
 testboth("%o", -042, "-42")
 testboth("%o", 042L, "42")
 testboth("%o", -042L, "-42")
+testboth("%o", float(042), "42")
 
 # Test exception for unknown format characters
 if verbose:
@@ -235,7 +253,7 @@ if have_unicode:
     test_exc(unicode('abc %\u3000','raw-unicode-escape'), 1, ValueError,
              "unsupported format character '?' (0x3000) at index 5")
 
-test_exc('%d', '1', TypeError, "int argument required, not str")
+test_exc('%d', '1', TypeError, "%d format: a number is required, not str")
 test_exc('%g', '1', TypeError, "float argument required, not str")
 test_exc('no format', '1', TypeError,
          "not all arguments converted during string formatting")
index 392da93a90902deb335a4c57be96613ce88a2368..314ec426287f993f86a2183984d176edf576bacf 100644 (file)
@@ -4585,6 +4585,7 @@ PyString_Format(PyObject *format, PyObject *args)
                        int prec = -1;
                        int c = '\0';
                        int fill;
+                       int isnumok;
                        PyObject *v = NULL;
                        PyObject *temp = NULL;
                        char *pbuf;
@@ -4786,23 +4787,52 @@ PyString_Format(PyObject *format, PyObject *args)
                        case 'X':
                                if (c == 'i')
                                        c = 'd';
-                               if (PyLong_Check(v)) {
-                                       int ilen;
-                                       temp = _PyString_FormatLong(v, flags,
-                                               prec, c, &pbuf, &ilen);
-                                       len = ilen;
-                                       if (!temp)
-                                               goto error;
-                                       sign = 1;
+                               isnumok = 0;
+                               if (PyNumber_Check(v)) {
+                                       PyObject *iobj=NULL;
+
+                                       if (PyInt_Check(v) || (PyLong_Check(v))) {
+                                               iobj = v;
+                                               Py_INCREF(iobj);
+                                       }
+                                       else {
+                                               iobj = PyNumber_Int(v);
+                                               if (iobj==NULL) iobj = PyNumber_Long(v);
+                                       }
+                                       if (iobj!=NULL) {
+                                               if (PyInt_Check(iobj)) {
+                                                       isnumok = 1;
+                                                       pbuf = formatbuf;
+                                                       len = formatint(pbuf,
+                                                                       sizeof(formatbuf),
+                                                                       flags, prec, c, iobj);
+                                                       Py_DECREF(iobj);
+                                                       if (len < 0)
+                                                               goto error;
+                                                       sign = 1;
+                                               }
+                                               else if (PyLong_Check(iobj)) {
+                                                       int ilen;
+                                                       
+                                                       isnumok = 1;
+                                                       temp = _PyString_FormatLong(iobj, flags,
+                                                               prec, c, &pbuf, &ilen);
+                                                       Py_DECREF(iobj);
+                                                       len = ilen;
+                                                       if (!temp)
+                                                               goto error;
+                                                       sign = 1;
+                                               }
+                                               else {
+                                                       Py_DECREF(iobj);
+                                               }
+                                       }
                                }
-                               else {
-                                       pbuf = formatbuf;
-                                       len = formatint(pbuf,
-                                                       sizeof(formatbuf),
-                                                       flags, prec, c, v);
-                                       if (len < 0)
-                                               goto error;
-                                       sign = 1;
+                               if (!isnumok) {
+                                       PyErr_Format(PyExc_TypeError, 
+                                           "%%%c format: a number is required, "
+                                           "not %.200s", c, Py_TYPE(v)->tp_name);
+                                       goto error;
                                }
                                if (flags & F_ZERO)
                                        fill = '0';
index 0dca976ab4fafca03bd7ac0ed17e1c1f873985b2..0470ef4bc5bfd7109a30ea8fcdff0679cd9b118d 100644 (file)
@@ -8334,6 +8334,7 @@ PyObject *PyUnicode_Format(PyObject *format,
            int prec = -1;
            Py_UNICODE c = '\0';
            Py_UNICODE fill;
+           int isnumok;
            PyObject *v = NULL;
            PyObject *temp = NULL;
            Py_UNICODE *pbuf;
@@ -8546,21 +8547,49 @@ PyObject *PyUnicode_Format(PyObject *format,
            case 'X':
                if (c == 'i')
                    c = 'd';
-               if (PyLong_Check(v)) {
-                   temp = formatlong(v, flags, prec, c);
-                   if (!temp)
-                       goto onError;
-                   pbuf = PyUnicode_AS_UNICODE(temp);
-                   len = PyUnicode_GET_SIZE(temp);
-                   sign = 1;
+               isnumok = 0;
+               if (PyNumber_Check(v)) {
+                       PyObject *iobj=NULL;
+
+                       if (PyInt_Check(v) || (PyLong_Check(v))) {
+                               iobj = v;
+                               Py_INCREF(iobj);
+                       }
+                       else {
+                               iobj = PyNumber_Int(v);
+                               if (iobj==NULL) iobj = PyNumber_Long(v);
+                       }
+                       if (iobj!=NULL) {
+                               if (PyInt_Check(iobj)) {
+                                       isnumok = 1;
+                                       pbuf = formatbuf;
+                                       len = formatint(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE),
+                                                   flags, prec, c, iobj);
+                                       Py_DECREF(iobj);
+                                       if (len < 0)
+                                           goto onError;
+                                       sign = 1;
+                               } 
+                               else if (PyLong_Check(iobj)) {
+                                       isnumok = 1;
+                                       temp = formatlong(iobj, flags, prec, c);
+                                       Py_DECREF(iobj);
+                                       if (!temp)
+                                           goto onError;
+                                       pbuf = PyUnicode_AS_UNICODE(temp);
+                                       len = PyUnicode_GET_SIZE(temp);
+                                       sign = 1;
+                               }
+                               else {
+                                       Py_DECREF(iobj);
+                               }
+                       }
                }
-               else {
-                   pbuf = formatbuf;
-                   len = formatint(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE),
-                                   flags, prec, c, v);
-                   if (len < 0)
+               if (!isnumok) {
+                       PyErr_Format(PyExc_TypeError, 
+                           "%%%c format: a number is required, "
+                           "not %.200s", c, Py_TYPE(v)->tp_name);
                        goto onError;
-                   sign = 1;
                }
                if (flags & F_ZERO)
                    fill = '0';