bpo-28598: Support __rmod__ for RHS subclasses of str in % string formatting operations (#95)

This commit is contained in:
Martijn Pieters 2017-02-27 16:08:01 +00:00 committed by Berker Peksag
parent 046041e23b
commit 53039ad381
3 changed files with 21 additions and 3 deletions

View file

@ -1448,6 +1448,15 @@ class UnicodeTest(string_tests.CommonTest,
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
result = format_string % 2.34 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 @support.cpython_only
def test_formatting_huge_precision_c_limits(self): def test_formatting_huge_precision_c_limits(self):
from _testcapi import INT_MAX from _testcapi import INT_MAX

View file

@ -10,6 +10,9 @@ What's New in Python 3.6.1 release candidate 1?
Core and Builtins 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. - bpo-29607: Fix stack_effect computation for CALL_FUNCTION_EX.
Patch by Matthieu Dartiailh. Patch by Matthieu Dartiailh.

View file

@ -1409,9 +1409,15 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
TARGET(BINARY_MODULO) { TARGET(BINARY_MODULO) {
PyObject *divisor = POP(); PyObject *divisor = POP();
PyObject *dividend = TOP(); PyObject *dividend = TOP();
PyObject *res = PyUnicode_CheckExact(dividend) ? PyObject *res;
PyUnicode_Format(dividend, divisor) : if (PyUnicode_CheckExact(dividend) && (
PyNumber_Remainder(dividend, divisor); !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(divisor);
Py_DECREF(dividend); Py_DECREF(dividend);
SET_TOP(res); SET_TOP(res);