mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
b278c723d7
commit
94e9585e99
|
@ -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`.
|
|
@ -318,6 +318,7 @@ typedef struct {
|
||||||
const Tcl_ObjType *BignumType;
|
const Tcl_ObjType *BignumType;
|
||||||
const Tcl_ObjType *ListType;
|
const Tcl_ObjType *ListType;
|
||||||
const Tcl_ObjType *StringType;
|
const Tcl_ObjType *StringType;
|
||||||
|
const Tcl_ObjType *UTF32StringType;
|
||||||
} TkappObject;
|
} TkappObject;
|
||||||
|
|
||||||
#define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
|
#define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
|
||||||
|
@ -588,14 +589,40 @@ Tkapp_New(const char *screenName, const char *className,
|
||||||
}
|
}
|
||||||
|
|
||||||
v->OldBooleanType = Tcl_GetObjType("boolean");
|
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");
|
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");
|
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->WideIntType = Tcl_GetObjType("wideInt");
|
||||||
v->BignumType = Tcl_GetObjType("bignum");
|
v->BignumType = Tcl_GetObjType("bignum");
|
||||||
v->ListType = Tcl_GetObjType("list");
|
v->ListType = Tcl_GetObjType("list");
|
||||||
v->StringType = Tcl_GetObjType("string");
|
v->StringType = Tcl_GetObjType("string");
|
||||||
|
v->UTF32StringType = Tcl_GetObjType("utf32string");
|
||||||
|
|
||||||
/* Delete the 'exit' command, which can screw things up */
|
/* Delete the 'exit' command, which can screw things up */
|
||||||
Tcl_DeleteCommand(v->interp, "exit");
|
Tcl_DeleteCommand(v->interp, "exit");
|
||||||
|
@ -1124,14 +1151,6 @@ FromObj(TkappObject *tkapp, Tcl_Obj *value)
|
||||||
return PyFloat_FromDouble(value->internalRep.doubleValue);
|
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 ||
|
if (value->typePtr == tkapp->IntType ||
|
||||||
value->typePtr == tkapp->WideIntType) {
|
value->typePtr == tkapp->WideIntType) {
|
||||||
result = fromWideIntObj(tkapp, value);
|
result = fromWideIntObj(tkapp, value);
|
||||||
|
@ -1176,17 +1195,12 @@ FromObj(TkappObject *tkapp, Tcl_Obj *value)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value->typePtr == tkapp->StringType) {
|
if (value->typePtr == tkapp->StringType ||
|
||||||
|
value->typePtr == tkapp->UTF32StringType)
|
||||||
|
{
|
||||||
return unicodeFromTclObj(value);
|
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 &&
|
if (tkapp->BignumType == NULL &&
|
||||||
strcmp(value->typePtr->name, "bignum") == 0) {
|
strcmp(value->typePtr->name, "bignum") == 0) {
|
||||||
/* bignum type is not registered in Tcl */
|
/* bignum type is not registered in Tcl */
|
||||||
|
|
Loading…
Reference in New Issue