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

When you use `'%s' % SubClassOfStr()`, where `SubClassOfStr.__rmod__` exists, the reverse operation is ignored as normally such string formatting operations use the `PyUnicode_Format()` fast path. This patch tests for subclasses of `str` first and picks the slow path in that case.

Patch by Martijn Pieters.
This commit is contained in:
Martijn Pieters 2017-02-23 13:38:04 +00:00 committed by Serhiy Storchaka
parent 2771304357
commit d7e64337ef
3 changed files with 22 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.7.0 alpha 1?
Core and Builtins 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. - bpo-29607: Fix stack_effect computation for CALL_FUNCTION_EX.
Patch by Matthieu Dartiailh. Patch by Matthieu Dartiailh.
@ -19,6 +22,7 @@ Core and Builtins
- bpo-29347: Fixed possibly dereferencing undefined pointers - bpo-29347: Fixed possibly dereferencing undefined pointers
when creating weakref objects. when creating weakref objects.
- bpo-29463: Add ``docstring`` field to Module, ClassDef, FunctionDef, - bpo-29463: Add ``docstring`` field to Module, ClassDef, FunctionDef,
and AsyncFunctionDef ast nodes. docstring is not first stmt in their body and AsyncFunctionDef ast nodes. docstring is not first stmt in their body
anymore. It affects ``co_firstlineno`` and ``co_lnotab`` of code object anymore. It affects ``co_firstlineno`` and ``co_lnotab`` of code object

View file

@ -1354,9 +1354,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);