mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	Change the %s format specifier for str objects so that it returns a
unicode instance if the argument is not an instance of basestring and calling __str__ on the argument returns a unicode instance.
This commit is contained in:
		
							parent
							
								
									ba7d95e215
								
							
						
					
					
						commit
						cf52c07843
					
				
					 5 changed files with 42 additions and 17 deletions
				
			
		| 
						 | 
				
			
			@ -371,6 +371,7 @@ PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *);
 | 
			
		|||
PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
 | 
			
		||||
PyAPI_FUNC(void) _PyObject_Dump(PyObject *);
 | 
			
		||||
PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *);
 | 
			
		||||
PyAPI_FUNC(PyObject *) _PyObject_Str(PyObject *);
 | 
			
		||||
PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *);
 | 
			
		||||
#ifdef Py_USING_UNICODE
 | 
			
		||||
PyAPI_FUNC(PyObject *) PyObject_Unicode(PyObject *);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -388,6 +388,10 @@ def test_formatting(self):
 | 
			
		|||
        self.assertEqual('%i %*.*s' % (10, 5,3,u'abc',), u'10   abc')
 | 
			
		||||
        self.assertEqual('%i%s %*.*s' % (10, 3, 5, 3, u'abc',), u'103   abc')
 | 
			
		||||
        self.assertEqual('%c' % u'a', u'a')
 | 
			
		||||
        class Wrapper:
 | 
			
		||||
            def __str__(self):
 | 
			
		||||
                return u'\u1234'
 | 
			
		||||
        self.assertEqual('%s' % Wrapper(), u'\u1234')
 | 
			
		||||
 | 
			
		||||
    def test_constructor(self):
 | 
			
		||||
        # unicode(obj) tests (this maps to PyObject_Unicode() at C level)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -118,6 +118,10 @@ Core and builtins
 | 
			
		|||
  positions.  It once again reports a syntax error if a future
 | 
			
		||||
  statement occurs after anything other than a doc string.
 | 
			
		||||
 | 
			
		||||
- Change the %s format specifier for str objects so that it returns a
 | 
			
		||||
  unicode instance if the argument is not an instance of basestring and
 | 
			
		||||
  calling __str__ on the argument returns a unicode instance.
 | 
			
		||||
 | 
			
		||||
Extension Modules
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -331,22 +331,48 @@ PyObject_Repr(PyObject *v)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
PyObject *
 | 
			
		||||
PyObject_Str(PyObject *v)
 | 
			
		||||
_PyObject_Str(PyObject *v)
 | 
			
		||||
{
 | 
			
		||||
	PyObject *res;
 | 
			
		||||
 | 
			
		||||
	int type_ok;
 | 
			
		||||
	if (v == NULL)
 | 
			
		||||
		return PyString_FromString("<NULL>");
 | 
			
		||||
	if (PyString_CheckExact(v)) {
 | 
			
		||||
		Py_INCREF(v);
 | 
			
		||||
		return v;
 | 
			
		||||
	}
 | 
			
		||||
#ifdef Py_USING_UNICODE
 | 
			
		||||
	if (PyUnicode_CheckExact(v)) {
 | 
			
		||||
		Py_INCREF(v);
 | 
			
		||||
		return v;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	if (v->ob_type->tp_str == NULL)
 | 
			
		||||
		return PyObject_Repr(v);
 | 
			
		||||
 | 
			
		||||
	res = (*v->ob_type->tp_str)(v);
 | 
			
		||||
	if (res == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	type_ok = PyString_Check(res);
 | 
			
		||||
#ifdef Py_USING_UNICODE
 | 
			
		||||
	type_ok = type_ok || PyUnicode_Check(res);
 | 
			
		||||
#endif
 | 
			
		||||
	if (!type_ok) {
 | 
			
		||||
		PyErr_Format(PyExc_TypeError,
 | 
			
		||||
			     "__str__ returned non-string (type %.200s)",
 | 
			
		||||
			     res->ob_type->tp_name);
 | 
			
		||||
		Py_DECREF(res);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PyObject *
 | 
			
		||||
PyObject_Str(PyObject *v)
 | 
			
		||||
{
 | 
			
		||||
	PyObject *res = _PyObject_Str(v);
 | 
			
		||||
	if (res == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
#ifdef Py_USING_UNICODE
 | 
			
		||||
	if (PyUnicode_Check(res)) {
 | 
			
		||||
		PyObject* str;
 | 
			
		||||
| 
						 | 
				
			
			@ -358,13 +384,7 @@ PyObject_Str(PyObject *v)
 | 
			
		|||
		    	return NULL;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	if (!PyString_Check(res)) {
 | 
			
		||||
		PyErr_Format(PyExc_TypeError,
 | 
			
		||||
			     "__str__ returned non-string (type %.200s)",
 | 
			
		||||
			     res->ob_type->tp_name);
 | 
			
		||||
		Py_DECREF(res);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	assert(PyString_Check(res));
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3853,7 +3853,6 @@ formatchar(char *buf, size_t buflen, PyObject *v)
 | 
			
		|||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...)
 | 
			
		||||
 | 
			
		||||
   FORMATBUFLEN is the length of the buffer in which the floats, ints, &
 | 
			
		||||
| 
						 | 
				
			
			@ -4079,7 +4078,9 @@ PyString_Format(PyObject *format, PyObject *args)
 | 
			
		|||
				break;
 | 
			
		||||
			case 's':
 | 
			
		||||
#ifdef Py_USING_UNICODE
 | 
			
		||||
				if (PyUnicode_Check(v)) {
 | 
			
		||||
				temp = _PyObject_Str(v);
 | 
			
		||||
				if (temp != NULL && PyUnicode_Check(temp)) {
 | 
			
		||||
					Py_DECREF(temp);
 | 
			
		||||
					fmt = fmt_start;
 | 
			
		||||
					argidx = argidx_start;
 | 
			
		||||
					goto unicode;
 | 
			
		||||
| 
						 | 
				
			
			@ -4087,16 +4088,11 @@ PyString_Format(PyObject *format, PyObject *args)
 | 
			
		|||
#endif
 | 
			
		||||
				/* Fall through */
 | 
			
		||||
			case 'r':
 | 
			
		||||
				if (c == 's')
 | 
			
		||||
					temp = PyObject_Str(v);
 | 
			
		||||
				else
 | 
			
		||||
				if (c == 'r')
 | 
			
		||||
					temp = PyObject_Repr(v);
 | 
			
		||||
				if (temp == NULL)
 | 
			
		||||
					goto error;
 | 
			
		||||
				if (!PyString_Check(temp)) {
 | 
			
		||||
					/* XXX Note: this should never happen,
 | 
			
		||||
					   since PyObject_Repr() and
 | 
			
		||||
					   PyObject_Str() assure this */
 | 
			
		||||
					PyErr_SetString(PyExc_TypeError,
 | 
			
		||||
					  "%s argument has non-string str()");
 | 
			
		||||
					Py_DECREF(temp);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue