8000 [3.12] gh-103194: Fix Tkinter’s Tcl value type handling for Tcl 8.7/9… · python/cpython@d4680b9 · GitHub
[go: up one dir, main page]

Skip to content

Commit d4680b9

Browse files
[3.12] gh-103194: Fix Tkinter’s Tcl value type handling for Tcl 8.7/9.0 (GH-103846) (GH-119831)
Some of standard Tcl types were renamed, removed, or no longer registered in Tcl 8.7/9.0. This change fixes automatic conversion of Tcl values to Python values to avoid returning a Tcl_Obj where the primary Python types (int, bool, str, bytes) were returned in older Tcl. (cherry picked from commit 94e9585) Co-authored-by: Christopher Chavez <chrischavez@gmx.us>
1 parent bd0d97c commit d4680b9

File tree

2 files changed

+36
-22
lines changed

2 files changed

+36
-22
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Prepare Tkinter for C API changes in Tcl 8.7/9.0 to avoid
2+
:class:`_tkinter.Tcl_Obj` being unexpectedly returned
3+
instead of :class:`bool`, :class:`str`,
4+
:class:`bytearray`, or :class:`int`.

Modules/_tkinter.c

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ typedef struct {
322322
const Tcl_ObjType *ListType;
323323
const Tcl_ObjType *ProcBodyType;
324324
const Tcl_ObjType *StringType;
325+
const Tcl_ObjType *UTF32StringType;
325326
} TkappObject;
326327

327328
#define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
@@ -592,15 +593,41 @@ Tkapp_New(const char *screenName, const char *className,
592593
}
593594

594595
v->OldBooleanType = Tcl_GetObjType("boolean");
595-
v->BooleanType = Tcl_GetObjType("booleanString");
596-
v->ByteArrayType = Tcl_GetObjType("bytearray");
596+
{
597+
Tcl_Obj *value;
598+
int boolValue;
599+
600+
/* Tcl 8.5 "booleanString" type is not registered
601+
and is renamed to "boolean" in Tcl 9.0.
602+
Based on approach suggested at
603+
https://core.tcl-lang.org/tcl/info/3bb3bcf2da5b */
604+
value = Tcl_NewStringObj("true", -1);
605+
Tcl_GetBooleanFromObj(NULL, value, &boolValue);
606+
v->BooleanType = value->typePtr;
607+
Tcl_DecrRefCount(value);
608+
609+
// "bytearray" type is not registered in Tcl 9.0
610+
value = Tcl_NewByteArrayObj(NULL, 0);
611+
v->ByteArrayType = value->typePtr;
612+
Tcl_DecrRefCount(value);
613+
}
597614
v->DoubleType = Tcl_GetObjType("double");
615+
/* TIP 484 suggests retrieving the "int" type without Tcl_GetObjType("int")
616+
since it is no longer registered in Tcl 9.0. But even though Tcl 8.7
617+
only uses the "wideInt" type on platforms with 32-bit long, it still has
618+
a registered "int" type, which FromObj() should recognize just in case. */
598619
v->IntType = Tcl_GetObjType("int");
620+
if (v->IntType == NULL) {
621+
Tcl_Obj *value = Tcl_NewIntObj(0);
622+
v->IntType = value->typePtr;
623+
Tcl_DecrRefCount(value);
624+
}
599625
v->WideIntType = Tcl_GetObjType("wideInt");
600626
v->BignumType = Tcl_GetObjType("bignum");
601627
v->ListType = Tcl_GetObjType("list");
602628
v->ProcBodyType = Tcl_GetObjType("procbody");
603629
v->StringType = Tcl_GetObjType("string");
630+
v->UTF32StringType = Tcl_GetObjType("utf32string");
604631

605632
/* Delete the 'exit' command, which can screw things up */
606633
Tcl_DeleteCommand(v->interp, "exit");
@@ -1130,14 +1157,6 @@ FromObj(TkappObject *tkapp, Tcl_Obj *value)
11301157
return PyFloat_FromDouble(value->internalRep.doubleValue);
11311158
}
11321159

1133-
if (value->typePtr == tkapp->IntType) {
1134-
long longValue;
1135-
if (Tcl_GetLongFromObj(interp, value, &longValue) == TCL_OK)
1136-
return PyLong_FromLong(longValue);
1137-
/* If there is an error in the long conversion,
1138-
fall through to wideInt handling. */
1139-
}
1140-
11411160
if (value->typePtr == tkapp->IntType ||
11421161
value->typePtr == tkapp->WideIntType) {
11431162
result = fromWideIntObj(tkapp, value);
@@ -1182,21 +1201,12 @@ FromObj(TkappObject *tkapp, Tcl_Obj *value)
11821201
return result;
11831202
}
11841203

1185-
if (value->typePtr == tkapp->ProcBodyType) {
1186-
/* fall through: return tcl object. */
1187-
}
1188-
1189-
if (value->typePtr == tkapp->StringType) {
1204+
if (value->typePtr == tkapp->StringType ||
1205+
value->typePtr == tkapp->UTF32StringType)
1206+
{
11901207
return unicodeFromTclObj(value);
11911208
}
11921209

1193-
if (tkapp->BooleanType == NULL &&
1194-
strcmp(value->typePtr->name, "booleanString") == 0) {
1195-
/* booleanString type is not registered in Tcl */
1196-
tkapp->BooleanType = value->typePtr;
1197-
return fromBoolean(tkapp, value);
1198-
}
1199-
12001210
if (tkapp->BignumType == NULL &&
12011211
strcmp(value->typePtr->name, "bignum") == 0) {
12021212
/* bignum type is not registered in Tcl */

0 commit comments

Comments
 (0)
0