]> granicus.if.org Git - python/commitdiff
properly lookup the __format__ special method
authorBenjamin Peterson <benjamin@python.org>
Sat, 5 Jun 2010 00:32:50 +0000 (00:32 +0000)
committerBenjamin Peterson <benjamin@python.org>
Sat, 5 Jun 2010 00:32:50 +0000 (00:32 +0000)
Lib/test/test_descr.py
Objects/abstract.c

index d450eed585f9f74489547a25cc76554e81683633..2fdd62fc4fded590bcc7e3769e51bd4b2d349386 100644 (file)
@@ -1697,6 +1697,8 @@ order (MRO) for bases """
         def some_number(self_, key):
             self.assertEqual(key, "hi")
             return 4
+        def format_impl(self, spec):
+            return "hello"
 
         # It would be nice to have every special method tested here, but I'm
         # only listing the ones I can remember outside of typeobject.c, since it
@@ -1715,6 +1717,7 @@ order (MRO) for bases """
             ("__enter__", run_context, iden, set(), {"__exit__" : swallow}),
             ("__exit__", run_context, swallow, set(), {"__enter__" : iden}),
             ("__complex__", complex, complex_num, set(), {}),
+            ("__format__", format, format_impl, set(), {}),
             ]
 
         class Checker(object):
index 761e035da3ca66a5f8b183120383548f170c4e59..898becd24580e6eedddc6680dad92063f2bdda4d 100644 (file)
@@ -723,7 +723,6 @@ PyBuffer_Release(Py_buffer *view)
 PyObject *
 PyObject_Format(PyObject* obj, PyObject *format_spec)
 {
-    static PyObject * str__format__ = NULL;
     PyObject *empty = NULL;
     PyObject *result = NULL;
 #ifdef Py_USING_UNICODE
@@ -731,14 +730,6 @@ PyObject_Format(PyObject* obj, PyObject *format_spec)
     int result_is_unicode;
 #endif
 
-    /* Initialize cached value */
-    if (str__format__ == NULL) {
-        /* Initialize static variable needed by _PyType_Lookup */
-        str__format__ = PyString_InternFromString("__format__");
-        if (str__format__ == NULL)
-            goto done;
-    }
-
     /* If no format_spec is provided, use an empty string */
     if (format_spec == NULL) {
         empty = PyString_FromStringAndSize(NULL, 0);
@@ -769,8 +760,7 @@ PyObject_Format(PyObject* obj, PyObject *format_spec)
     /* Check for a __format__ method and call it. */
     if (PyInstance_Check(obj)) {
         /* We're an instance of a classic class */
-        PyObject *bound_method = PyObject_GetAttr(obj,
-                                                  str__format__);
+        PyObject *bound_method = PyObject_GetAttrString(obj, "__format__");
         if (bound_method != NULL) {
             result = PyObject_CallFunctionObjArgs(bound_method,
                                                   format_spec,
@@ -820,8 +810,7 @@ PyObject_Format(PyObject* obj, PyObject *format_spec)
             }
 
             /* Then call str.__format__ on that result */
-            format_method = PyObject_GetAttr(self_as_str,
-                                             str__format__);
+            format_method = PyObject_GetAttrString(self_as_str, "__format__");
             if (format_method == NULL) {
                 goto done1;
             }
@@ -837,20 +826,21 @@ done1:
     } else {
         /* Not an instance of a classic class, use the code
            from py3k */
+        static PyObject *format_cache;
 
         /* Find the (unbound!) __format__ method (a borrowed
            reference) */
-        PyObject *method = _PyType_Lookup(Py_TYPE(obj),
-                                          str__format__);
+        PyObject *method = _PyObject_LookupSpecial(obj, "__format__",
+                                                   &format_cache);
         if (method == NULL) {
-            PyErr_Format(PyExc_TypeError,
-                         "Type %.100s doesn't define __format__",
-                         Py_TYPE(obj)->tp_name);
+            if (!PyErr_Occurred())
+                PyErr_Format(PyExc_TypeError,
+                             "Type %.100s doesn't define __format__",
+                             Py_TYPE(obj)->tp_name);
             goto done;
         }
-        /* And call it, binding it to the value */
-        result = PyObject_CallFunctionObjArgs(method, obj,
-                                              format_spec, NULL);
+        /* And call it. */
+        result = PyObject_CallFunctionObjArgs(method, format_spec, NULL);
     }
 
     if (result == NULL)