Benjamin Peterson avatar Benjamin Peterson committed 09176d0

properly lookup the __format__ special method

Comments (0)

Files changed (2)

Lib/test/test_descr.py

         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
             ("__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):

Objects/abstract.c

 PyObject *
 PyObject_Format(PyObject* obj, PyObject *format_spec)
 {
-    static PyObject * str__format__ = NULL;
     PyObject *empty = NULL;
     PyObject *result = NULL;
 #ifdef Py_USING_UNICODE
     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);
     /* 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,
             }
 
             /* 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;
             }
     } 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)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.