summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_unicode.py9
-rw-r--r--Misc/NEWS4
-rw-r--r--Python/ceval.c12
3 files changed, 22 insertions, 3 deletions
diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py
index b1f7c89..f70504c 100644
--- a/Lib/test/test_unicode.py
+++ b/Lib/test/test_unicode.py
@@ -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
diff --git a/Misc/NEWS b/Misc/NEWS
index e21a723..72d96e7 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ What's New in Python 3.7.0 alpha 1?
Core and Builtins
-----------------
+- bpo-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.
@@ -19,6 +22,7 @@ Core and Builtins
- bpo-29347: Fixed possibly dereferencing undefined pointers
when creating weakref objects.
+
- bpo-29463: Add ``docstring`` field to Module, ClassDef, FunctionDef,
and AsyncFunctionDef ast nodes. docstring is not first stmt in their body
anymore. It affects ``co_firstlineno`` and ``co_lnotab`` of code object
diff --git a/Python/ceval.c b/Python/ceval.c
index 81c89df..0a82965 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1354,9 +1354,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);