cpython: a6f4d8fa7ab8 (original) (raw)
--- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -133,9 +133,22 @@ class TclTest(unittest.TestCase): tcl = self.interp self.assertRaises(TclError,tcl.unsetvar,'a')
- def get_integers(self):
integers = (0, 1, -1, 2**31-1, -2**31)[](#l1.8)
if tcl_version >= (8, 4): # wideInt was added in Tcl 8.4[](#l1.9)
integers += (2**31, -2**31-1, 2**63-1, -2**63)[](#l1.10)
if tcl_version >= (8, 5): # bignum was added in Tcl 8.5[](#l1.11)
integers += (2**63, -2**63-1, 2**1000, -2**1000)[](#l1.12)
return integers[](#l1.13)
+ def test_getint(self): tcl = self.interp.tk
self.assertEqual(tcl.getint(' 42 '), 42)[](#l1.17)
for i in self.get_integers():[](#l1.18)
self.assertEqual(tcl.getint(' %d ' % i), i)[](#l1.19)
self.assertEqual(tcl.getint(' %#o ' % i), i)[](#l1.20)
self.assertEqual(tcl.getint(' %#x ' % i), i)[](#l1.21)
if tcl_version < (8, 5): # bignum was added in Tcl 8.5[](#l1.22)
self.assertRaises(TclError, tcl.getint, str(2**1000))[](#l1.23) self.assertEqual(tcl.getint(42), 42)[](#l1.24) self.assertRaises(TypeError, tcl.getint)[](#l1.25) self.assertRaises(TypeError, tcl.getint, '42', '10')[](#l1.26)
@@ -270,7 +283,7 @@ class TclTest(unittest.TestCase): check('"a\xbd\u20ac"', 'a\xbd\u20ac') check(r'"a\xbd\u20ac"', 'a\xbd\u20ac') check(r'"a\0b"', 'a\x00b')
if tcl_version >= (8, 5):[](#l1.31)
if tcl_version >= (8, 5): # bignum was added in Tcl 8.5[](#l1.32) check('2**64', str(2**64))[](#l1.33)
def test_exprdouble(self): @@ -302,7 +315,7 @@ class TclTest(unittest.TestCase): check('[string length "a\xbd\u20ac"]', 3.0) check(r'[string length "a\xbd\u20ac"]', 3.0) self.assertRaises(TclError, tcl.exprdouble, '"abc"')
if tcl_version >= (8, 5):[](#l1.40)
if tcl_version >= (8, 5): # bignum was added in Tcl 8.5[](#l1.41) check('2**64', float(2**64))[](#l1.42)
def test_exprlong(self): @@ -334,7 +347,7 @@ class TclTest(unittest.TestCase): check('[string length "a\xbd\u20ac"]', 3) check(r'[string length "a\xbd\u20ac"]', 3) self.assertRaises(TclError, tcl.exprlong, '"abc"')
if tcl_version >= (8, 5):[](#l1.49)
if tcl_version >= (8, 5): # bignum was added in Tcl 8.5[](#l1.50) self.assertRaises(TclError, tcl.exprlong, '2**64')[](#l1.51)
def test_exprboolean(self): @@ -375,7 +388,7 @@ class TclTest(unittest.TestCase): check('[string length "a\xbd\u20ac"]', True) check(r'[string length "a\xbd\u20ac"]', True) self.assertRaises(TclError, tcl.exprboolean, '"abc"')
if tcl_version >= (8, 5):[](#l1.58)
if tcl_version >= (8, 5): # bignum was added in Tcl 8.5[](#l1.59) check('2**64', True)[](#l1.60)
def test_booleans(self): @@ -397,6 +410,21 @@ class TclTest(unittest.TestCase): check('1 < 2', True) check('1 > 2', False)
- def test_expr_bignum(self):
tcl = self.interp[](#l1.68)
for i in self.get_integers():[](#l1.69)
result = tcl.call('expr', str(i))[](#l1.70)
if self.wantobjects:[](#l1.71)
self.assertEqual(result, i)[](#l1.72)
self.assertIsInstance(result, int)[](#l1.73)
else:[](#l1.74)
self.assertEqual(result, str(i))[](#l1.75)
self.assertIsInstance(result, str)[](#l1.76)
if tcl_version < (8, 5): # bignum was added in Tcl 8.5[](#l1.77)
result = tcl.call('expr', str(2**1000))[](#l1.78)
self.assertEqual(result, str(2**1000))[](#l1.79)
self.assertIsInstance(result, str)[](#l1.80)
+ def test_passing_values(self): def passValue(value): return self.interp.call('set', '_', value) @@ -414,8 +442,10 @@ class TclTest(unittest.TestCase): b'str\xc0\x80ing' if self.wantobjects else 'str\xc0\x80ing') self.assertEqual(passValue(b'str\xbding'), b'str\xbding' if self.wantobjects else 'str\xbding')
for i in (0, 1, -1, 2**31-1, -2**31):[](#l1.89)
for i in self.get_integers():[](#l1.90) self.assertEqual(passValue(i), i if self.wantobjects else str(i))[](#l1.91)
if tcl_version < (8, 5): # bignum was added in Tcl 8.5[](#l1.92)
self.assertEqual(passValue(2**1000), str(2**1000))[](#l1.93) for f in (0.0, 1.0, -1.0, 1/3,[](#l1.94) sys.float_info.min, sys.float_info.max,[](#l1.95) -sys.float_info.min, -sys.float_info.max):[](#l1.96)
@@ -473,8 +503,10 @@ class TclTest(unittest.TestCase): check(b'str\x00ing', 'str\x00ing') check(b'str\xc0\x80ing', 'str\xc0\x80ing') check(b'str\xc0\x80ing\xe2\x82\xac', 'str\xc0\x80ing\xe2\x82\xac')
for i in (0, 1, -1, 2**31-1, -2**31):[](#l1.101)
for i in self.get_integers():[](#l1.102) check(i, str(i))[](#l1.103)
if tcl_version < (8, 5): # bignum was added in Tcl 8.5[](#l1.104)
check(2**1000, str(2**1000))[](#l1.105) for f in (0.0, 1.0, -1.0):[](#l1.106) check(f, repr(f))[](#l1.107) for f in (1/3.0, sys.float_info.min, sys.float_info.max,[](#l1.108)
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,9 @@ Core and Builtins Library ------- +- Issue #16840: Tkinter now supports 64-bit integers added in Tcl 8.4 and
- Issue #23834: Fix socket.sendto(), use the C Py_ssize_t type to store the result of sendto() instead of the C int type.
--- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -69,6 +69,11 @@ Copyright (C) 1994 Steen Lumholt. #error "Tk older than 8.3.1 not supported" #endif +#if TK_VERSION_HEX >= 0x08050000 +#define HAVE_LIBTOMMAMTH +#include <tclTomMath.h> +#endif + #if !(defined(MS_WINDOWS) || defined(CYGWIN)) #define HAVE_CREATEFILEHANDLER #endif @@ -247,6 +252,8 @@ typedef struct { const Tcl_ObjType *ByteArrayType; const Tcl_ObjType *DoubleType; const Tcl_ObjType *IntType;
- const Tcl_ObjType *WideIntType;
- const Tcl_ObjType *BignumType; const Tcl_ObjType *ListType; const Tcl_ObjType *ProcBodyType; const Tcl_ObjType *StringType; @@ -583,6 +590,8 @@ Tkapp_New(char *screenName, char *classN v->ByteArrayType = Tcl_GetObjType("bytearray"); v->DoubleType = Tcl_GetObjType("double"); v->IntType = Tcl_GetObjType("int");
- 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"); @@ -875,28 +884,92 @@ static PyType_Spec PyTclObject_Type_spec
#define CHECK_STRING_LENGTH(s) #endif +#ifdef HAVE_LIBTOMMAMTH +static Tcl_Obj* +asBignumObj(PyObject *value) +{
- neg = Py_SIZE(value) < 0;
- hexstr = _PyLong_Format(value, 16);
- if (hexstr == NULL)
return NULL;[](#l3.50)
- hexchars = PyUnicode_AsUTF8(hexstr);
- if (hexchars == NULL) {
Py_DECREF(hexstr);[](#l3.53)
return NULL;[](#l3.54)
- }
- hexchars += neg + 2; /* skip sign and "0x" */
- mp_init(&bigValue);
- if (mp_read_radix(&bigValue, hexchars, 16) != MP_OKAY) {
mp_clear(&bigValue);[](#l3.59)
Py_DECREF(hexstr);[](#l3.60)
PyErr_NoMemory();[](#l3.61)
return NULL;[](#l3.62)
- }
- Py_DECREF(hexstr);
- bigValue.sign = neg ? MP_NEG : MP_ZPOS;
- result = Tcl_NewBignumObj(&bigValue);
- mp_clear(&bigValue);
- if (result == NULL) {
PyErr_NoMemory();[](#l3.69)
return NULL;[](#l3.70)
- }
- return result;
+} +#endif + static Tcl_Obj* AsObj(PyObject *value) { Tcl_Obj *result;
if (PyBytes_Check(value)) return Tcl_NewByteArrayObj((unsigned char *)PyBytes_AS_STRING(value), PyBytes_GET_SIZE(value));
- else if (PyLong_CheckExact(value) &&
((longVal = PyLong_AsLongAndOverflow(value, &overflow)),[](#l3.91)
!overflow)) {[](#l3.92)
Tcl_WideInt wideValue;[](#l3.98)
longValue = PyLong_AsLongAndOverflow(value, &overflow);[](#l3.100)
if (!overflow) {[](#l3.101)
return Tcl_NewLongObj(longValue);[](#l3.102)
}[](#l3.103) /* If there is an overflow in the long conversion,[](#l3.104)
fall through to wideInt handling. */[](#l3.105)
if (_PyLong_AsByteArray((PyLongObject *)value,[](#l3.107)
(unsigned char *)(void *)&wideValue,[](#l3.108)
sizeof(wideValue),[](#l3.109)
PY_LITTLE_ENDIAN,[](#l3.110)
/* signed */ 1) == 0) {[](#l3.111)
return Tcl_NewWideIntObj(wideValue);[](#l3.112)
}[](#l3.113)
PyErr_Clear();[](#l3.114)
/* If there is an overflow in the wideInt conversion,[](#l3.116)
fall through to bignum handling. */[](#l3.117)
return asBignumObj(value);[](#l3.119)
/* If there is no wideInt or bignum support,[](#l3.121) fall through to default object handling. */[](#l3.122)
@@ -916,7 +989,8 @@ AsObj(PyObject *value) ckfree(FREECAST argv); return result; }
@@ -966,12 +1040,14 @@ AsObj(PyObject *value) ckfree(FREECAST outbuf); return result; }
- if (PyTclObject_Check(value)) { Tcl_Obj v = ((PyTclObject)value)->value; Tcl_IncrRefCount(v); return v; }
@@ -990,6 +1066,62 @@ fromBoolean(PyObject* tkapp, Tcl_Obj va return PyBool_FromLong(boolValue); } +#ifdef TCL_WIDE_INT_TYPE +static PyObject +fromWideIntObj(PyObject* tkapp, Tcl_Obj *value) +{
Tcl_WideInt wideValue;[](#l3.170)
if (Tcl_GetWideIntFromObj(Tkapp_Interp(tkapp), value, &wideValue) == TCL_OK) {[](#l3.171)
if (sizeof(wideValue) <= SIZEOF_LONG_LONG)[](#l3.173)
return PyLong_FromLongLong(wideValue);[](#l3.174)
return _PyLong_FromByteArray((unsigned char *)(void *)&wideValue,[](#l3.176)
sizeof(wideValue),[](#l3.177)
PY_LITTLE_ENDIAN,[](#l3.178)
/* signed */ 1);[](#l3.179)
}[](#l3.180)
return NULL;[](#l3.181)
+} +#endif + +#ifdef HAVE_LIBTOMMAMTH +static PyObject* +fromBignumObj(PyObject* tkapp, Tcl_Obj *value) +{
- if (Tcl_GetBignumFromObj(Tkapp_Interp(tkapp), value, &bigValue) != TCL_OK)
return Tkinter_Error(tkapp);[](#l3.195)
- numBytes = mp_unsigned_bin_size(&bigValue);
- bytes = PyMem_Malloc(numBytes);
- if (bytes == NULL) {
mp_clear(&bigValue);[](#l3.199)
return PyErr_NoMemory();[](#l3.200)
- }
- if (mp_to_unsigned_bin_n(&bigValue, bytes,
&numBytes) != MP_OKAY) {[](#l3.203)
mp_clear(&bigValue);[](#l3.204)
PyMem_Free(bytes);[](#l3.205)
return PyErr_NoMemory();[](#l3.206)
- }
- res = _PyLong_FromByteArray(bytes, numBytes,
/* big-endian */ 0,[](#l3.209)
/* unsigned */ 0);[](#l3.210)
- PyMem_Free(bytes);
- if (res != NULL && bigValue.sign == MP_NEG) {
PyObject *res2 = PyNumber_Negative(res);[](#l3.213)
Py_DECREF(res);[](#l3.214)
res = res2;[](#l3.215)
- }
- mp_clear(&bigValue);
- return res;
+} +#endif + static PyObject* FromObj(PyObject* tkapp, Tcl_Obj value) { @@ -1017,9 +1149,33 @@ FromObj(PyObject tkapp, Tcl_Obj *value) } if (value->typePtr == app->IntType) {
return PyLong_FromLong(value->internalRep.longValue);[](#l3.229)
long longValue;[](#l3.230)
if (Tcl_GetLongFromObj(interp, value, &longValue) == TCL_OK)[](#l3.231)
return PyLong_FromLong(longValue);[](#l3.232)
/* If there is an error in the long conversion,[](#l3.233)
} +#ifdef TCL_WIDE_INT_TYPEfall through to wideInt handling. */[](#l3.234)
- if (value->typePtr == app->IntType ||
value->typePtr == app->WideIntType) {[](#l3.239)
result = fromWideIntObj(tkapp, value);[](#l3.240)
if (result != NULL || PyErr_Occurred())[](#l3.241)
return result;[](#l3.242)
Tcl_ResetResult(interp);[](#l3.243)
/* If there is an error in the wideInt conversion,[](#l3.244)
fall through to bignum handling. */[](#l3.245)
- }
+#endif + +#ifdef HAVE_LIBTOMMAMTH
- if (value->typePtr == app->IntType ||
value->typePtr == app->WideIntType ||[](#l3.251)
value->typePtr == app->BignumType) {[](#l3.252)
return fromBignumObj(tkapp, value);[](#l3.253)
- }
+#endif + if (value->typePtr == app->ListType) { int size; int i, status; @@ -1067,6 +1223,15 @@ FromObj(PyObject* tkapp, Tcl_Obj *value) } #endif +#ifdef HAVE_LIBTOMMAMTH
- if (app->BignumType == NULL &&
strcmp(value->typePtr->name, "bignum") == 0) {[](#l3.266)
/* bignum type is not registered in Tcl */[](#l3.267)
app->BignumType = value->typePtr;[](#l3.268)
return fromBignumObj(tkapp, value);[](#l3.269)
- }
+#endif + return newPyTclObject(value); } @@ -1700,7 +1865,12 @@ static PyObject * Tkapp_GetInt(PyObject *self, PyObject *args) { char *s;
+#if defined(TCL_WIDE_INT_TYPE) || defined(HAVE_LIBTOMMAMTH)
+#endif if (PyTuple_Size(args) == 1) { PyObject* o = PyTuple_GetItem(args, 0); @@ -1712,9 +1882,29 @@ Tkapp_GetInt(PyObject *self, PyObject *a if (!PyArg_ParseTuple(args, "s:getint", &s)) return NULL; CHECK_STRING_LENGTH(s);
+#if defined(TCL_WIDE_INT_TYPE) || defined(HAVE_LIBTOMMAMTH)
- /* Don't use Tcl_GetInt() because it returns ambiguous result for value
in ranges -2**32..-2**31-1 and 2**31..2**32-1 (on 32-bit platform).[](#l3.301)
Prefer bignum because Tcl_GetWideIntFromObj returns ambiguous result for[](#l3.303)
value in ranges -2**64..-2**63-1 and 2**63..2**64-1 (on 32-bit platform).[](#l3.304)
*/[](#l3.305)