summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-10-16 20:18:24 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-10-16 20:18:24 (GMT)
commitc993315b188b08b6d78248522f6d0ed31d52f939 (patch)
tree3fd0205ab57b86f588c32a378186c3569ad1d9ed
parentdfefc06fe01fdab0171a368c642ecaf352540627 (diff)
downloadcpython-c993315b188b08b6d78248522f6d0ed31d52f939.zip
cpython-c993315b188b08b6d78248522f6d0ed31d52f939.tar.gz
cpython-c993315b188b08b6d78248522f6d0ed31d52f939.tar.bz2
SF bug [#468061] __str__ ignored in str subclass.
object.c, PyObject_Str: Don't try to optimize anything except exact string objects here; in particular, let str subclasses go thru tp_str, same as non-str objects. This allows overrides of tp_str to take effect. stringobject.c: + string_print (str's tp_print): If the argument isn't an exact string object, get one from PyObject_Str. + string_str (str's tp_str): Make a genuine-string copy of the object if it's of a proper str subclass type. str() applied to a str subclass that doesn't override __str__ ends up here. test_descr.py: New str_of_str_subclass() test.
-rw-r--r--Lib/test/test_descr.py31
-rw-r--r--Objects/object.c6
-rw-r--r--Objects/stringobject.c23
3 files changed, 52 insertions, 8 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index a15e7a0..c9235c8 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -2298,6 +2298,36 @@ def buffer_inherit():
except TypeError:
pass
+def str_of_str_subclass():
+ import binascii
+ import cStringIO
+
+ if verbose:
+ print "Testing __str__ defined in subclass of str ..."
+
+ class octetstring(str):
+ def __str__(self):
+ return binascii.b2a_hex(self)
+ def __repr__(self):
+ return self + " repr"
+
+ o = octetstring('A')
+ vereq(type(o), octetstring)
+ vereq(type(str(o)), str)
+ vereq(type(repr(o)), str)
+ vereq(ord(o), 0x41)
+ vereq(str(o), '41')
+ vereq(repr(o), 'A repr')
+ vereq(o.__str__(), '41')
+ vereq(o.__repr__(), 'A repr')
+
+ capture = cStringIO.StringIO()
+ # Calling str() or not exercises different internal paths.
+ print >> capture, o
+ print >> capture, str(o)
+ vereq(capture.getvalue(), '41\n41\n')
+ capture.close()
+
def test_main():
class_docstrings()
lists()
@@ -2346,6 +2376,7 @@ def test_main():
binopoverride()
subclasspropagation()
buffer_inherit()
+ str_of_str_subclass()
if verbose: print "All OK"
if __name__ == "__main__":
diff --git a/Objects/object.c b/Objects/object.c
index be8eb07..af0c0bb 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -261,12 +261,6 @@ PyObject_Str(PyObject *v)
Py_INCREF(v);
return v;
}
- if (PyString_Check(v)) {
- /* For a string subtype that's not a string, return a true
- string with the same string data. */
- PyStringObject *s = (PyStringObject *)v;
- return PyString_FromStringAndSize(s->ob_sval, s->ob_size);
- }
if (v->ob_type->tp_str == NULL)
return PyObject_Repr(v);
diff --git a/Objects/stringobject.c b/Objects/stringobject.c
index aea31ac..0a3155e 100644
--- a/Objects/stringobject.c
+++ b/Objects/stringobject.c
@@ -566,7 +566,18 @@ string_print(PyStringObject *op, FILE *fp, int flags)
int i;
char c;
int quote;
+
/* XXX Ought to check for interrupts when writing long strings */
+ if (! PyString_CheckExact(op)) {
+ int ret;
+ /* A str subclass may have its own __str__ method. */
+ op = (PyStringObject *) PyObject_Str((PyObject *)op);
+ if (op == NULL)
+ return -1;
+ ret = string_print(op, fp, flags);
+ Py_DECREF(op);
+ return ret;
+ }
if (flags & Py_PRINT_RAW) {
fwrite(op->ob_sval, 1, (int) op->ob_size, fp);
return 0;
@@ -651,8 +662,16 @@ string_repr(register PyStringObject *op)
static PyObject *
string_str(PyObject *s)
{
- Py_INCREF(s);
- return s;
+ assert(PyString_Check(s));
+ if (PyString_CheckExact(s)) {
+ Py_INCREF(s);
+ return s;
+ }
+ else {
+ /* Subtype -- return genuine string with the same value. */
+ PyStringObject *t = (PyStringObject *) s;
+ return PyString_FromStringAndSize(t->ob_sval, t->ob_size);
+ }
}
static int