]> granicus.if.org Git - python/commitdiff
bpo-28598: Support __rmod__ for RHS subclasses of str in % string formatting operatio...
authorMartijn Pieters <github.com@zopatista.com>
Mon, 27 Feb 2017 16:08:01 +0000 (16:08 +0000)
committerBerker Peksag <berker.peksag@gmail.com>
Mon, 27 Feb 2017 16:08:01 +0000 (19:08 +0300)
Lib/test/test_unicode.py
Misc/NEWS
Python/ceval.c

index 86ebd45e7b031daf9b15709e5fc4d6cd15888ad1..2844bc5540c38b3ae6fb9b67741d37e658493b80 100644 (file)
@@ -1448,6 +1448,15 @@ class UnicodeTest(string_tests.CommonTest,
         with self.assertRaises(ValueError):
             result = format_string % 2.34
 
+    def test_issue28598_strsubclass_rhs(self):
+        # A subclass of str with an __rmod__ method should be able to hook
+        # into the % operator
+        class SubclassedStr(str):
+            def __rmod__(self, other):
+                return 'Success, self.__rmod__({!r}) was called'.format(other)
+        self.assertEqual('lhs %% %r' % SubclassedStr('rhs'),
+                         "Success, self.__rmod__('lhs %% %r') was called")
+
     @support.cpython_only
     def test_formatting_huge_precision_c_limits(self):
         from _testcapi import INT_MAX
index 7ec6b1291a3d2de903e827bebb8831c827634fc3..fe420b62f231ddce1399922cd1cdabc8d38d7283 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ What's New in Python 3.6.1 release candidate 1?
 Core and Builtins
 -----------------
 
+- Issue #28598: Support __rmod__ for subclasses of str being called before
+  str.__mod__.  Patch by Martijn Pieters.
+
 - bpo-29607: Fix stack_effect computation for CALL_FUNCTION_EX.
   Patch by Matthieu Dartiailh.
 
index d5172b9631f43d79f39c4b187151d0bf191f5f65..c9e9c327f31401f4f43ec67721507010d9f8d60b 100644 (file)
@@ -1409,9 +1409,15 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
         TARGET(BINARY_MODULO) {
             PyObject *divisor = POP();
             PyObject *dividend = TOP();
-            PyObject *res = PyUnicode_CheckExact(dividend) ?
-                PyUnicode_Format(dividend, divisor) :
-                PyNumber_Remainder(dividend, divisor);
+            PyObject *res;
+            if (PyUnicode_CheckExact(dividend) && (
+                  !PyUnicode_Check(divisor) || PyUnicode_CheckExact(divisor))) {
+              // fast path; string formatting, but not if the RHS is a str subclass
+              // (see issue28598)
+              res = PyUnicode_Format(dividend, divisor);
+            } else {
+              res = PyNumber_Remainder(dividend, divisor);
+            }
             Py_DECREF(divisor);
             Py_DECREF(dividend);
             SET_TOP(res);