mirror of https://github.com/python/cpython
gh-101830: Fix Tcl_Obj to string conversion (GH-120884)
Accessing the Tkinter object's string representation no longer converts the underlying Tcl object to a string on Windows.
This commit is contained in:
parent
18b6ca9660
commit
f4ddaa3967
|
@ -51,7 +51,7 @@ class TclTest(unittest.TestCase):
|
||||||
|
|
||||||
def test_eval_surrogates_in_result(self):
|
def test_eval_surrogates_in_result(self):
|
||||||
tcl = self.interp
|
tcl = self.interp
|
||||||
self.assertIn(tcl.eval(r'set a "<\ud83d\udcbb>"'), '<\U0001f4bb>')
|
self.assertEqual(tcl.eval(r'set a "<\ud83d\udcbb>"'), '<\U0001f4bb>')
|
||||||
|
|
||||||
def testEvalException(self):
|
def testEvalException(self):
|
||||||
tcl = self.interp
|
tcl = self.interp
|
||||||
|
@ -61,6 +61,13 @@ class TclTest(unittest.TestCase):
|
||||||
tcl = self.interp
|
tcl = self.interp
|
||||||
self.assertRaises(TclError,tcl.eval,'this is wrong')
|
self.assertRaises(TclError,tcl.eval,'this is wrong')
|
||||||
|
|
||||||
|
def test_eval_returns_tcl_obj(self):
|
||||||
|
tcl = self.interp.tk
|
||||||
|
tcl.eval(r'set a "\u20ac \ud83d\udcbb \0 \udcab"; regexp -about $a')
|
||||||
|
a = tcl.eval('set a')
|
||||||
|
expected = '\u20ac \U0001f4bb \0 \udced\udcb2\udcab'
|
||||||
|
self.assertEqual(a, expected)
|
||||||
|
|
||||||
def testCall(self):
|
def testCall(self):
|
||||||
tcl = self.interp
|
tcl = self.interp
|
||||||
tcl.call('set','a','1')
|
tcl.call('set','a','1')
|
||||||
|
@ -74,6 +81,18 @@ class TclTest(unittest.TestCase):
|
||||||
tcl = self.interp
|
tcl = self.interp
|
||||||
self.assertRaises(TclError,tcl.call,'this','is','wrong')
|
self.assertRaises(TclError,tcl.call,'this','is','wrong')
|
||||||
|
|
||||||
|
def test_call_returns_tcl_obj(self):
|
||||||
|
tcl = self.interp.tk
|
||||||
|
tcl.eval(r'set a "\u20ac \ud83d\udcbb \0 \udcab"; regexp -about $a')
|
||||||
|
a = tcl.call('set', 'a')
|
||||||
|
expected = '\u20ac \U0001f4bb \0 \udced\udcb2\udcab'
|
||||||
|
if self.wantobjects:
|
||||||
|
self.assertEqual(str(a), expected)
|
||||||
|
self.assertEqual(a.string, expected)
|
||||||
|
self.assertEqual(a.typename, 'regexp')
|
||||||
|
else:
|
||||||
|
self.assertEqual(a, expected)
|
||||||
|
|
||||||
def testSetVar(self):
|
def testSetVar(self):
|
||||||
tcl = self.interp
|
tcl = self.interp
|
||||||
tcl.setvar('a','1')
|
tcl.setvar('a','1')
|
||||||
|
@ -102,6 +121,18 @@ class TclTest(unittest.TestCase):
|
||||||
tcl = self.interp
|
tcl = self.interp
|
||||||
self.assertRaises(TclError,tcl.getvar,'a(1)')
|
self.assertRaises(TclError,tcl.getvar,'a(1)')
|
||||||
|
|
||||||
|
def test_getvar_returns_tcl_obj(self):
|
||||||
|
tcl = self.interp.tk
|
||||||
|
tcl.eval(r'set a "\u20ac \ud83d\udcbb \0 \udcab"; regexp -about $a')
|
||||||
|
a = tcl.getvar('a')
|
||||||
|
expected = '\u20ac \U0001f4bb \0 \udced\udcb2\udcab'
|
||||||
|
if self.wantobjects:
|
||||||
|
self.assertEqual(str(a), expected)
|
||||||
|
self.assertEqual(a.string, expected)
|
||||||
|
self.assertEqual(a.typename, 'regexp')
|
||||||
|
else:
|
||||||
|
self.assertEqual(a, expected)
|
||||||
|
|
||||||
def testUnsetVar(self):
|
def testUnsetVar(self):
|
||||||
tcl = self.interp
|
tcl = self.interp
|
||||||
tcl.setvar('a',1)
|
tcl.setvar('a',1)
|
||||||
|
@ -549,6 +580,24 @@ class TclTest(unittest.TestCase):
|
||||||
'1 2 {3 4} {5 6} {}',
|
'1 2 {3 4} {5 6} {}',
|
||||||
(1, (2,), (3, 4), '5 6', ''))
|
(1, (2,), (3, 4), '5 6', ''))
|
||||||
|
|
||||||
|
def test_passing_tcl_obj(self):
|
||||||
|
tcl = self.interp.tk
|
||||||
|
a = None
|
||||||
|
def testfunc(arg):
|
||||||
|
nonlocal a
|
||||||
|
a = arg
|
||||||
|
self.interp.createcommand('testfunc', testfunc)
|
||||||
|
self.addCleanup(self.interp.tk.deletecommand, 'testfunc')
|
||||||
|
tcl.eval(r'set a "\u20ac \ud83d\udcbb \0 \udcab"; regexp -about $a')
|
||||||
|
tcl.eval(r'testfunc $a')
|
||||||
|
expected = '\u20ac \U0001f4bb \0 \udced\udcb2\udcab'
|
||||||
|
if self.wantobjects >= 2:
|
||||||
|
self.assertEqual(str(a), expected)
|
||||||
|
self.assertEqual(a.string, expected)
|
||||||
|
self.assertEqual(a.typename, 'regexp')
|
||||||
|
else:
|
||||||
|
self.assertEqual(a, expected)
|
||||||
|
|
||||||
def test_splitlist(self):
|
def test_splitlist(self):
|
||||||
splitlist = self.interp.tk.splitlist
|
splitlist = self.interp.tk.splitlist
|
||||||
call = self.interp.tk.call
|
call = self.interp.tk.call
|
||||||
|
@ -673,6 +722,7 @@ class TclTest(unittest.TestCase):
|
||||||
support.check_disallow_instantiation(self, _tkinter.TkttType)
|
support.check_disallow_instantiation(self, _tkinter.TkttType)
|
||||||
support.check_disallow_instantiation(self, _tkinter.TkappType)
|
support.check_disallow_instantiation(self, _tkinter.TkappType)
|
||||||
|
|
||||||
|
|
||||||
class BigmemTclTest(unittest.TestCase):
|
class BigmemTclTest(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Accessing the :mod:`tkinter` object's string representation no longer converts
|
||||||
|
the underlying Tcl object to a string on Windows.
|
|
@ -493,24 +493,28 @@ unicodeFromTclString(const char *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
unicodeFromTclObj(Tcl_Obj *value)
|
unicodeFromTclObj(TkappObject *tkapp, Tcl_Obj *value)
|
||||||
{
|
{
|
||||||
Tcl_Size len;
|
Tcl_Size len;
|
||||||
#if USE_TCL_UNICODE
|
#if USE_TCL_UNICODE
|
||||||
int byteorder = NATIVE_BYTEORDER;
|
if (value->typePtr != NULL && tkapp != NULL &&
|
||||||
const Tcl_UniChar *u = Tcl_GetUnicodeFromObj(value, &len);
|
(value->typePtr == tkapp->StringType ||
|
||||||
if (sizeof(Tcl_UniChar) == 2)
|
value->typePtr == tkapp->UTF32StringType))
|
||||||
return PyUnicode_DecodeUTF16((const char *)u, len * 2,
|
{
|
||||||
"surrogatepass", &byteorder);
|
int byteorder = NATIVE_BYTEORDER;
|
||||||
else if (sizeof(Tcl_UniChar) == 4)
|
const Tcl_UniChar *u = Tcl_GetUnicodeFromObj(value, &len);
|
||||||
return PyUnicode_DecodeUTF32((const char *)u, len * 4,
|
if (sizeof(Tcl_UniChar) == 2)
|
||||||
"surrogatepass", &byteorder);
|
return PyUnicode_DecodeUTF16((const char *)u, len * 2,
|
||||||
else
|
"surrogatepass", &byteorder);
|
||||||
Py_UNREACHABLE();
|
else if (sizeof(Tcl_UniChar) == 4)
|
||||||
#else
|
return PyUnicode_DecodeUTF32((const char *)u, len * 4,
|
||||||
|
"surrogatepass", &byteorder);
|
||||||
|
else
|
||||||
|
Py_UNREACHABLE();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
const char *s = Tcl_GetStringFromObj(value, &len);
|
const char *s = Tcl_GetStringFromObj(value, &len);
|
||||||
return unicodeFromTclStringAndSize(s, len);
|
return unicodeFromTclStringAndSize(s, len);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@ -793,7 +797,7 @@ PyTclObject_string(PyObject *_self, void *ignored)
|
||||||
{
|
{
|
||||||
PyTclObject *self = (PyTclObject *)_self;
|
PyTclObject *self = (PyTclObject *)_self;
|
||||||
if (!self->string) {
|
if (!self->string) {
|
||||||
self->string = unicodeFromTclObj(self->value);
|
self->string = unicodeFromTclObj(NULL, self->value);
|
||||||
if (!self->string)
|
if (!self->string)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -808,7 +812,7 @@ PyTclObject_str(PyObject *_self)
|
||||||
return Py_NewRef(self->string);
|
return Py_NewRef(self->string);
|
||||||
}
|
}
|
||||||
/* XXX Could cache result if it is non-ASCII. */
|
/* XXX Could cache result if it is non-ASCII. */
|
||||||
return unicodeFromTclObj(self->value);
|
return unicodeFromTclObj(NULL, self->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -1143,7 +1147,7 @@ FromObj(TkappObject *tkapp, Tcl_Obj *value)
|
||||||
Tcl_Interp *interp = Tkapp_Interp(tkapp);
|
Tcl_Interp *interp = Tkapp_Interp(tkapp);
|
||||||
|
|
||||||
if (value->typePtr == NULL) {
|
if (value->typePtr == NULL) {
|
||||||
return unicodeFromTclObj(value);
|
return unicodeFromTclObj(tkapp, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value->typePtr == tkapp->BooleanType ||
|
if (value->typePtr == tkapp->BooleanType ||
|
||||||
|
@ -1208,7 +1212,7 @@ FromObj(TkappObject *tkapp, Tcl_Obj *value)
|
||||||
if (value->typePtr == tkapp->StringType ||
|
if (value->typePtr == tkapp->StringType ||
|
||||||
value->typePtr == tkapp->UTF32StringType)
|
value->typePtr == tkapp->UTF32StringType)
|
||||||
{
|
{
|
||||||
return unicodeFromTclObj(value);
|
return unicodeFromTclObj(tkapp, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tkapp->BignumType == NULL &&
|
if (tkapp->BignumType == NULL &&
|
||||||
|
@ -1308,7 +1312,7 @@ finally:
|
||||||
static PyObject *
|
static PyObject *
|
||||||
Tkapp_UnicodeResult(TkappObject *self)
|
Tkapp_UnicodeResult(TkappObject *self)
|
||||||
{
|
{
|
||||||
return unicodeFromTclObj(Tcl_GetObjResult(self->interp));
|
return unicodeFromTclObj(self, Tcl_GetObjResult(self->interp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1327,7 +1331,7 @@ Tkapp_ObjectResult(TkappObject *self)
|
||||||
res = FromObj(self, value);
|
res = FromObj(self, value);
|
||||||
Tcl_DecrRefCount(value);
|
Tcl_DecrRefCount(value);
|
||||||
} else {
|
} else {
|
||||||
res = unicodeFromTclObj(value);
|
res = unicodeFromTclObj(self, value);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -1860,7 +1864,7 @@ GetVar(TkappObject *self, PyObject *args, int flags)
|
||||||
res = FromObj(self, tres);
|
res = FromObj(self, tres);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res = unicodeFromTclObj(tres);
|
res = unicodeFromTclObj(self, tres);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LEAVE_OVERLAP_TCL
|
LEAVE_OVERLAP_TCL
|
||||||
|
@ -2307,7 +2311,7 @@ PythonCmd(ClientData clientData, Tcl_Interp *interp,
|
||||||
|
|
||||||
for (i = 0; i < (objc - 1); i++) {
|
for (i = 0; i < (objc - 1); i++) {
|
||||||
PyObject *s = objargs ? FromObj(data->self, objv[i + 1])
|
PyObject *s = objargs ? FromObj(data->self, objv[i + 1])
|
||||||
: unicodeFromTclObj(objv[i + 1]);
|
: unicodeFromTclObj(data->self, objv[i + 1]);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
Py_DECREF(args);
|
Py_DECREF(args);
|
||||||
return PythonCmd_Error(interp);
|
return PythonCmd_Error(interp);
|
||||||
|
|
Loading…
Reference in New Issue