Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
ea134da9
Commit
ea134da9
authored
Apr 02, 2015
by
Serhiy Storchaka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #16840: Tkinter now supports 64-bit integers added in Tcl 8.4 and
arbitrary precision integers added in Tcl 8.5.
parent
8e44aa5a
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
248 additions
and
23 deletions
+248
-23
Lib/test/test_tcl.py
Lib/test/test_tcl.py
+39
-7
Misc/NEWS
Misc/NEWS
+3
-0
Modules/_tkinter.c
Modules/_tkinter.c
+206
-16
No files found.
Lib/test/test_tcl.py
View file @
ea134da9
...
...
@@ -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
)
if
tcl_version
>=
(
8
,
4
):
# wideInt was added in Tcl 8.4
integers
+=
(
2
**
31
,
-
2
**
31
-
1
,
2
**
63
-
1
,
-
2
**
63
)
if
tcl_version
>=
(
8
,
5
):
# bignum was added in Tcl 8.5
integers
+=
(
2
**
63
,
-
2
**
63
-
1
,
2
**
1000
,
-
2
**
1000
)
return
integers
def
test_getint
(
self
):
tcl
=
self
.
interp
.
tk
self
.
assertEqual
(
tcl
.
getint
(
' 42 '
),
42
)
for
i
in
self
.
get_integers
():
self
.
assertEqual
(
tcl
.
getint
(
' %d '
%
i
),
i
)
self
.
assertEqual
(
tcl
.
getint
(
' %#o '
%
i
),
i
)
self
.
assertEqual
(
tcl
.
getint
(
' %#x '
%
i
),
i
)
if
tcl_version
<
(
8
,
5
):
# bignum was added in Tcl 8.5
self
.
assertRaises
(
TclError
,
tcl
.
getint
,
str
(
2
**
1000
))
self
.
assertEqual
(
tcl
.
getint
(
42
),
42
)
self
.
assertRaises
(
TypeError
,
tcl
.
getint
)
self
.
assertRaises
(
TypeError
,
tcl
.
getint
,
'42'
,
'10'
)
...
...
@@ -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
\
x00
b'
)
if
tcl_version
>=
(
8
,
5
):
if
tcl_version
>=
(
8
,
5
):
# bignum was added in Tcl 8.5
check
(
'2**64'
,
str
(
2
**
64
))
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
):
if
tcl_version
>=
(
8
,
5
):
# bignum was added in Tcl 8.5
check
(
'2**64'
,
float
(
2
**
64
))
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
):
if
tcl_version
>=
(
8
,
5
):
# bignum was added in Tcl 8.5
self
.
assertRaises
(
TclError
,
tcl
.
exprlong
,
'2**64'
)
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
):
if
tcl_version
>=
(
8
,
5
):
# bignum was added in Tcl 8.5
check
(
'2**64'
,
True
)
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
for
i
in
self
.
get_integers
():
result
=
tcl
.
call
(
'expr'
,
str
(
i
))
if
self
.
wantobjects
:
self
.
assertEqual
(
result
,
i
)
self
.
assertIsInstance
(
result
,
int
)
else
:
self
.
assertEqual
(
result
,
str
(
i
))
self
.
assertIsInstance
(
result
,
str
)
if
tcl_version
<
(
8
,
5
):
# bignum was added in Tcl 8.5
result
=
tcl
.
call
(
'expr'
,
str
(
2
**
1000
))
self
.
assertEqual
(
result
,
str
(
2
**
1000
))
self
.
assertIsInstance
(
result
,
str
)
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
\
x80
ing'
if
self
.
wantobjects
else
'str
\
xc0
\
x80
ing'
)
self
.
assertEqual
(
passValue
(
b'str
\
xbd
ing'
),
b'str
\
xbd
ing'
if
self
.
wantobjects
else
'str
\
xbd
ing'
)
for
i
in
(
0
,
1
,
-
1
,
2
**
31
-
1
,
-
2
**
31
):
for
i
in
self
.
get_integers
(
):
self
.
assertEqual
(
passValue
(
i
),
i
if
self
.
wantobjects
else
str
(
i
))
if
tcl_version
<
(
8
,
5
):
# bignum was added in Tcl 8.5
self
.
assertEqual
(
passValue
(
2
**
1000
),
str
(
2
**
1000
))
for
f
in
(
0.0
,
1.0
,
-
1.0
,
1
/
3
,
sys
.
float_info
.
min
,
sys
.
float_info
.
max
,
-
sys
.
float_info
.
min
,
-
sys
.
float_info
.
max
):
...
...
@@ -473,8 +503,10 @@ class TclTest(unittest.TestCase):
check
(
b'str
\
x00
ing'
,
'str
\
x00
ing'
)
check
(
b'str
\
xc0
\
x80
ing'
,
'str
\
xc0
\
x80
ing'
)
check
(
b'str
\
xc0
\
x80
ing
\
xe2
\
x82
\
xac
'
,
'str
\
xc0
\
x80
ing
\
xe2
\
x82
\
xac
'
)
for
i
in
(
0
,
1
,
-
1
,
2
**
31
-
1
,
-
2
**
31
):
for
i
in
self
.
get_integers
(
):
check
(
i
,
str
(
i
))
if
tcl_version
<
(
8
,
5
):
# bignum was added in Tcl 8.5
check
(
2
**
1000
,
str
(
2
**
1000
))
for
f
in
(
0.0
,
1.0
,
-
1.0
):
check
(
f
,
repr
(
f
))
for
f
in
(
1
/
3.0
,
sys
.
float_info
.
min
,
sys
.
float_info
.
max
,
...
...
Misc/NEWS
View file @
ea134da9
...
...
@@ -24,6 +24,9 @@ Core and Builtins
Library
-------
- Issue #16840: Tkinter now supports 64-bit integers added in Tcl 8.4 and
arbitrary precision integers added in Tcl 8.5.
- Issue #23834: Fix socket.sendto(), use the C Py_ssize_t type to store the
result of sendto() instead of the C int type.
...
...
Modules/_tkinter.c
View file @
ea134da9
...
...
@@ -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 *className,
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
)
{
Tcl_Obj
*
result
;
int
neg
;
PyObject
*
hexstr
;
char
*
hexchars
;
mp_int
bigValue
;
neg
=
Py_SIZE
(
value
)
<
0
;
hexstr
=
_PyLong_Format
(
value
,
16
);
if
(
hexstr
==
NULL
)
return
NULL
;
hexchars
=
PyUnicode_AsUTF8
(
hexstr
);
if
(
hexchars
==
NULL
)
{
Py_DECREF
(
hexstr
);
return
NULL
;
}
hexchars
+=
neg
+
2
;
/* skip sign and "0x" */
mp_init
(
&
bigValue
);
if
(
mp_read_radix
(
&
bigValue
,
hexchars
,
16
)
!=
MP_OKAY
)
{
mp_clear
(
&
bigValue
);
Py_DECREF
(
hexstr
);
PyErr_NoMemory
();
return
NULL
;
}
Py_DECREF
(
hexstr
);
bigValue
.
sign
=
neg
?
MP_NEG
:
MP_ZPOS
;
result
=
Tcl_NewBignumObj
(
&
bigValue
);
mp_clear
(
&
bigValue
);
if
(
result
==
NULL
)
{
PyErr_NoMemory
();
return
NULL
;
}
return
result
;
}
#endif
static
Tcl_Obj
*
AsObj
(
PyObject
*
value
)
{
Tcl_Obj
*
result
;
long
longVal
;
int
overflow
;
if
(
PyBytes_Check
(
value
))
return
Tcl_NewByteArrayObj
((
unsigned
char
*
)
PyBytes_AS_STRING
(
value
),
PyBytes_GET_SIZE
(
value
));
else
if
(
PyBool_Check
(
value
))
if
(
PyBool_Check
(
value
))
return
Tcl_NewBooleanObj
(
PyObject_IsTrue
(
value
));
else
if
(
PyLong_CheckExact
(
value
)
&&
((
longVal
=
PyLong_AsLongAndOverflow
(
value
,
&
overflow
)),
!
overflow
))
{
if
(
PyLong_CheckExact
(
value
))
{
int
overflow
;
long
longValue
;
#ifdef TCL_WIDE_INT_TYPE
Tcl_WideInt
wideValue
;
#endif
longValue
=
PyLong_AsLongAndOverflow
(
value
,
&
overflow
);
if
(
!
overflow
)
{
return
Tcl_NewLongObj
(
longValue
);
}
/* If there is an overflow in the long conversion,
fall through to wideInt handling. */
#ifdef TCL_WIDE_INT_TYPE
if
(
_PyLong_AsByteArray
((
PyLongObject
*
)
value
,
(
unsigned
char
*
)(
void
*
)
&
wideValue
,
sizeof
(
wideValue
),
PY_LITTLE_ENDIAN
,
/* signed */
1
)
==
0
)
{
return
Tcl_NewWideIntObj
(
wideValue
);
}
PyErr_Clear
();
#endif
/* If there is an overflow in the wideInt conversion,
fall through to bignum handling. */
#ifdef HAVE_LIBTOMMAMTH
return
asBignumObj
(
value
);
#endif
/* If there is no wideInt or bignum support,
fall through to default object handling. */
return
Tcl_NewLongObj
(
longVal
);
}
else
if
(
PyFloat_Check
(
value
))
if
(
PyFloat_Check
(
value
))
return
Tcl_NewDoubleObj
(
PyFloat_AS_DOUBLE
(
value
));
else
if
(
PyTuple_Check
(
value
))
{
if
(
PyTuple_Check
(
value
))
{
Tcl_Obj
**
argv
;
Py_ssize_t
size
,
i
;
...
...
@@ -916,7 +989,8 @@ AsObj(PyObject *value)
ckfree
(
FREECAST
argv
);
return
result
;
}
else
if
(
PyUnicode_Check
(
value
))
{
if
(
PyUnicode_Check
(
value
))
{
void
*
inbuf
;
Py_ssize_t
size
;
int
kind
;
...
...
@@ -966,12 +1040,14 @@ AsObj(PyObject *value)
ckfree
(
FREECAST
outbuf
);
return
result
;
}
else
if
(
PyTclObject_Check
(
value
))
{
if
(
PyTclObject_Check
(
value
))
{
Tcl_Obj
*
v
=
((
PyTclObject
*
)
value
)
->
value
;
Tcl_IncrRefCount
(
v
);
return
v
;
}
else
{
{
PyObject
*
v
=
PyObject_Str
(
value
);
if
(
!
v
)
return
0
;
...
...
@@ -990,6 +1066,62 @@ fromBoolean(PyObject* tkapp, Tcl_Obj *value)
return
PyBool_FromLong
(
boolValue
);
}
#ifdef TCL_WIDE_INT_TYPE
static
PyObject
*
fromWideIntObj
(
PyObject
*
tkapp
,
Tcl_Obj
*
value
)
{
Tcl_WideInt
wideValue
;
if
(
Tcl_GetWideIntFromObj
(
Tkapp_Interp
(
tkapp
),
value
,
&
wideValue
)
==
TCL_OK
)
{
#ifdef HAVE_LONG_LONG
if
(
sizeof
(
wideValue
)
<=
SIZEOF_LONG_LONG
)
return
PyLong_FromLongLong
(
wideValue
);
#endif
return
_PyLong_FromByteArray
((
unsigned
char
*
)(
void
*
)
&
wideValue
,
sizeof
(
wideValue
),
PY_LITTLE_ENDIAN
,
/* signed */
1
);
}
return
NULL
;
}
#endif
#ifdef HAVE_LIBTOMMAMTH
static
PyObject
*
fromBignumObj
(
PyObject
*
tkapp
,
Tcl_Obj
*
value
)
{
mp_int
bigValue
;
unsigned
long
numBytes
;
unsigned
char
*
bytes
;
PyObject
*
res
;
if
(
Tcl_GetBignumFromObj
(
Tkapp_Interp
(
tkapp
),
value
,
&
bigValue
)
!=
TCL_OK
)
return
Tkinter_Error
(
tkapp
);
numBytes
=
mp_unsigned_bin_size
(
&
bigValue
);
bytes
=
PyMem_Malloc
(
numBytes
);
if
(
bytes
==
NULL
)
{
mp_clear
(
&
bigValue
);
return
PyErr_NoMemory
();
}
if
(
mp_to_unsigned_bin_n
(
&
bigValue
,
bytes
,
&
numBytes
)
!=
MP_OKAY
)
{
mp_clear
(
&
bigValue
);
PyMem_Free
(
bytes
);
return
PyErr_NoMemory
();
}
res
=
_PyLong_FromByteArray
(
bytes
,
numBytes
,
/* big-endian */
0
,
/* unsigned */
0
);
PyMem_Free
(
bytes
);
if
(
res
!=
NULL
&&
bigValue
.
sign
==
MP_NEG
)
{
PyObject
*
res2
=
PyNumber_Negative
(
res
);
Py_DECREF
(
res
);
res
=
res2
;
}
mp_clear
(
&
bigValue
);
return
res
;
}
#endif
static
PyObject
*
FromObj
(
PyObject
*
tkapp
,
Tcl_Obj
*
value
)
{
...
...
@@ -1017,8 +1149,32 @@ FromObj(PyObject* tkapp, Tcl_Obj *value)
}
if
(
value
->
typePtr
==
app
->
IntType
)
{
return
PyLong_FromLong
(
value
->
internalRep
.
longValue
);
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. */
}
#ifdef TCL_WIDE_INT_TYPE
if
(
value
->
typePtr
==
app
->
IntType
||
value
->
typePtr
==
app
->
WideIntType
)
{
result
=
fromWideIntObj
(
tkapp
,
value
);
if
(
result
!=
NULL
||
PyErr_Occurred
())
return
result
;
Tcl_ResetResult
(
interp
);
/* If there is an error in the wideInt conversion,
fall through to bignum handling. */
}
#endif
#ifdef HAVE_LIBTOMMAMTH
if
(
value
->
typePtr
==
app
->
IntType
||
value
->
typePtr
==
app
->
WideIntType
||
value
->
typePtr
==
app
->
BignumType
)
{
return
fromBignumObj
(
tkapp
,
value
);
}
#endif
if
(
value
->
typePtr
==
app
->
ListType
)
{
int
size
;
...
...
@@ -1067,6 +1223,15 @@ FromObj(PyObject* tkapp, Tcl_Obj *value)
}
#endif
#ifdef HAVE_LIBTOMMAMTH
if
(
app
->
BignumType
==
NULL
&&
strcmp
(
value
->
typePtr
->
name
,
"bignum"
)
==
0
)
{
/* bignum type is not registered in Tcl */
app
->
BignumType
=
value
->
typePtr
;
return
fromBignumObj
(
tkapp
,
value
);
}
#endif
return
newPyTclObject
(
value
);
}
...
...
@@ -1700,7 +1865,12 @@ static PyObject *
Tkapp_GetInt
(
PyObject
*
self
,
PyObject
*
args
)
{
char
*
s
;
int
v
;
#if defined(TCL_WIDE_INT_TYPE) || defined(HAVE_LIBTOMMAMTH)
Tcl_Obj
*
value
;
PyObject
*
result
;
#else
int
intValue
;
#endif
if
(
PyTuple_Size
(
args
)
==
1
)
{
PyObject
*
o
=
PyTuple_GetItem
(
args
,
0
);
...
...
@@ -1712,9 +1882,29 @@ Tkapp_GetInt(PyObject *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"s:getint"
,
&
s
))
return
NULL
;
CHECK_STRING_LENGTH
(
s
);
if
(
Tcl_GetInt
(
Tkapp_Interp
(
self
),
s
,
&
v
)
==
TCL_ERROR
)
#if defined(TCL_WIDE_INT_TYPE) || defined(HAVE_LIBTOMMAMTH)
value
=
Tcl_NewStringObj
(
s
,
-
1
);
if
(
value
==
NULL
)
return
Tkinter_Error
(
self
);
return
Py_BuildValue
(
"i"
,
v
);
/* 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).
Prefer bignum because Tcl_GetWideIntFromObj returns ambiguous result for
value in ranges -2**64..-2**63-1 and 2**63..2**64-1 (on 32-bit platform).
*/
#ifdef HAVE_LIBTOMMAMTH
result
=
fromBignumObj
(
self
,
value
);
#else
result
=
fromWideIntObj
(
self
,
value
);
#endif
Tcl_DecrRefCount
(
value
);
if
(
result
!=
NULL
||
PyErr_Occurred
())
return
result
;
#else
if
(
Tcl_GetInt
(
Tkapp_Interp
(
self
),
s
,
&
intValue
)
==
TCL_OK
)
return
PyLong_FromLong
(
intValue
);
#endif
return
Tkinter_Error
(
self
);
}
static
PyObject
*
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment