Skip to content

Commit 94e9585

Browse files
authored
gh-103194: Fix Tkinter’s Tcl value type handling for Tcl 8.7/9.0 (GH-103846)
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.
1 parent b278c72 commit 94e9585

File tree

2 files changed

+36
-18
lines changed

2 files changed

+36
-18
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 & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ typedef struct {
318318
const Tcl_ObjType *BignumType;
319319
const Tcl_ObjType *ListType;
320320
const Tcl_ObjType *StringType;
321+
const Tcl_ObjType *UTF32StringType;
321322
} TkappObject;
322323

323324
#define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
@@ -588,14 +589,40 @@ Tkapp_New(const char *screenName, const char *className,
588589
}
589590

590591
v->OldBooleanType = Tcl_GetObjType("boolean");
591-
v->BooleanType = Tcl_GetObjType("booleanString");
592-
v->ByteArrayType = Tcl_GetObjType("bytearray");
592+
{
593+
Tcl_Obj *value;
594+
int boolValue;
595+
596+
/* Tcl 8.5 "booleanString" type is not registered
597+
and is renamed to "boolean" in Tcl 9.0.
598+
Based on approach suggested at
599+
https://core.tcl-lang.org/tcl/info/3bb3bcf2da5b */
600+
value = Tcl_NewStringObj("true", -1);
601+
Tcl_GetBooleanFromObj(NULL, value, &boolValue);
602+
v->BooleanType = value->typePtr;
603+
Tcl_DecrRefCount(value);
604+
605+
// "bytearray" type is not registered in Tcl 9.0
606+
value = Tcl_NewByteArrayObj(NULL, 0);
607+
v->ByteArrayType = value->typePtr;
608+
Tcl_DecrRefCount(value);
609+
}
593610
v->DoubleType = Tcl_GetObjType("double");
611+
/* TIP 484 suggests retrieving the "int" type without Tcl_GetObjType("int")
612+
since it is no longer registered in Tcl 9.0. But even though Tcl 8.7
613+
only uses the "wideInt" type on platforms with 32-bit long, it still has
614+
a registered "int" type, which FromObj() should recognize just in case. */
594615
v->IntType = Tcl_GetObjType("int");
616+
if (v->IntType == NULL) {
617+
Tcl_Obj *value = Tcl_NewIntObj(0);
618+
v->IntType = value->typePtr;
619+
Tcl_DecrRefCount(value);
620+
}
595621
v->WideIntType = Tcl_GetObjType("wideInt");
596622
v->BignumType = Tcl_GetObjType("bignum");
597623
v->ListType = Tcl_GetObjType("list");
598624
v->StringType = Tcl_GetObjType("string");
625+
v->UTF32StringType = Tcl_GetObjType("utf32string");
599626

600627
/* Delete the 'exit' command, which can screw things up */
601628
Tcl_DeleteCommand(v->interp, "exit");
@@ -1124,14 +1151,6 @@ FromObj(TkappObject *tkapp, Tcl_Obj *value)
11241151
return PyFloat_FromDouble(value->internalRep.doubleValue);
11251152
}
11261153

1127-
if (value->typePtr == tkapp->IntType) {
1128-
long longValue;
1129-
if (Tcl_GetLongFromObj(interp, value, &longValue) == TCL_OK)
1130-
return PyLong_FromLong(longValue);
1131-
/* If there is an error in the long conversion,
1132-
fall through to wideInt handling. */
1133-
}
1134-
11351154
if (value->typePtr == tkapp->IntType ||
11361155
value->typePtr == tkapp->WideIntType) {
11371156
result = fromWideIntObj(tkapp, value);
@@ -1176,17 +1195,12 @@ FromObj(TkappObject *tkapp, Tcl_Obj *value)
11761195
return result;
11771196
}
11781197

1179-
if (value->typePtr == tkapp->StringType) {
1198+
if (value->typePtr == tkapp->StringType ||
1199+
value->typePtr == tkapp->UTF32StringType)
1200+
{
11801201
return unicodeFromTclObj(value);
11811202
}
11821203

1183-
if (tkapp->BooleanType == NULL &&
1184-
strcmp(value->typePtr->name, "booleanString") == 0) {
1185-
/* booleanString type is not registered in Tcl */
1186-
tkapp->BooleanType = value->typePtr;
1187-
return fromBoolean(tkapp, value);
1188-
}
1189-
11901204
if (tkapp->BignumType == NULL &&
11911205
strcmp(value->typePtr->name, "bignum") == 0) {
11921206
/* bignum type is not registered in Tcl */

0 commit comments

Comments
 (0)