Skip to content

Commit

Permalink
[3.12] pythongh-103194: Fix Tkinter’s Tcl value type handling for Tcl…
Browse files Browse the repository at this point in the history
… 8.7/9.0 (pythonGH-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.
(cherry picked from commit 94e9585)

Co-authored-by: Christopher Chavez <chrischavez@gmx.us>
  • Loading branch information
chrstphrchvz authored and serhiy-storchaka committed May 31, 2024
1 parent bd0d97c commit 503d6b4
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Prepare Tkinter for C API changes in Tcl 8.7/9.0 to avoid
:class:`_tkinter.Tcl_Obj` being unexpectedly returned
instead of :class:`bool`, :class:`str`,
:class:`bytearray`, or :class:`int`.
54 changes: 32 additions & 22 deletions Modules/_tkinter.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ typedef struct {
const Tcl_ObjType *ListType;
const Tcl_ObjType *ProcBodyType;
const Tcl_ObjType *StringType;
const Tcl_ObjType *UTF32StringType;
} TkappObject;

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

v->OldBooleanType = Tcl_GetObjType("boolean");
v->BooleanType = Tcl_GetObjType("booleanString");
v->ByteArrayType = Tcl_GetObjType("bytearray");
{
Tcl_Obj *value;
int boolValue;

/* Tcl 8.5 "booleanString" type is not registered
and is renamed to "boolean" in Tcl 9.0.
Based on approach suggested at
https://core.tcl-lang.org/tcl/info/3bb3bcf2da5b */
value = Tcl_NewStringObj("true", -1);
Tcl_GetBooleanFromObj(NULL, value, &boolValue);
v->BooleanType = value->typePtr;
Tcl_DecrRefCount(value);

// "bytearray" type is not registered in Tcl 9.0
value = Tcl_NewByteArrayObj(NULL, 0);
v->ByteArrayType = value->typePtr;
Tcl_DecrRefCount(value);
}
v->DoubleType = Tcl_GetObjType("double");
/* TIP 484 suggests retrieving the "int" type without Tcl_GetObjType("int")
since it is no longer registered in Tcl 9.0. But even though Tcl 8.7
only uses the "wideInt" type on platforms with 32-bit long, it still has
a registered "int" type, which FromObj() should recognize just in case. */
v->IntType = Tcl_GetObjType("int");
if (v->IntType == NULL) {
Tcl_Obj *value = Tcl_NewIntObj(0);
v->IntType = value->typePtr;
Tcl_DecrRefCount(value);
}
v->WideIntType = Tcl_GetObjType("wideInt");
v->BignumType = Tcl_GetObjType("bignum");
v->ListType = Tcl_GetObjType("list");
v->ProcBodyType = Tcl_GetObjType("procbody");
v->StringType = Tcl_GetObjType("string");
v->UTF32StringType = Tcl_GetObjType("utf32string");

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

if (value->typePtr == tkapp->IntType) {
long longValue;
if (Tcl_GetLongFromObj(interp, value, &longValue) == TCL_OK)
return PyLong_FromLong(longValue);
/* If there is an error in the long conversion,
fall through to wideInt handling. */
}

if (value->typePtr == tkapp->IntType ||
value->typePtr == tkapp->WideIntType) {
result = fromWideIntObj(tkapp, value);
Expand Down Expand Up @@ -1182,21 +1201,12 @@ FromObj(TkappObject *tkapp, Tcl_Obj *value)
return result;
}

if (value->typePtr == tkapp->ProcBodyType) {
/* fall through: return tcl object. */
}

if (value->typePtr == tkapp->StringType) {
if (value->typePtr == tkapp->StringType ||
value->typePtr == tkapp->UTF32StringType)
{
return unicodeFromTclObj(value);
}

if (tkapp->BooleanType == NULL &&
strcmp(value->typePtr->name, "booleanString") == 0) {
/* booleanString type is not registered in Tcl */
tkapp->BooleanType = value->typePtr;
return fromBoolean(tkapp, value);
}

if (tkapp->BignumType == NULL &&
strcmp(value->typePtr->name, "bignum") == 0) {
/* bignum type is not registered in Tcl */
Expand Down

0 comments on commit 503d6b4

Please sign in to comment.