summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/idlelib/editor.py29
-rw-r--r--Lib/idlelib/idle_test/test_editor.py12
-rwxr-xr-xLib/idlelib/pyshell.py18
-rw-r--r--Lib/idlelib/runscript.py3
-rw-r--r--Lib/test/test_tcl.py5
-rw-r--r--Lib/tkinter/test/test_tkinter/test_misc.py22
-rw-r--r--Lib/tkinter/test/test_ttk/test_widgets.py13
-rw-r--r--Misc/NEWS.d/next/Library/2019-09-29-22-47-37.bpo-13153.0mO9qR.rst4
-rw-r--r--Modules/_tkinter.c375
9 files changed, 240 insertions, 241 deletions
diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py
index b969f8c..adeed74 100644
--- a/Lib/idlelib/editor.py
+++ b/Lib/idlelib/editor.py
@@ -358,21 +358,6 @@ class EditorWindow(object):
Font(text, font=text.cget('font')).measure('0')
self.width = pixel_width // zero_char_width
- def _filename_to_unicode(self, filename):
- """Return filename as BMP unicode so displayable in Tk."""
- # Decode bytes to unicode.
- if isinstance(filename, bytes):
- try:
- filename = filename.decode(self.filesystemencoding)
- except UnicodeDecodeError:
- try:
- filename = filename.decode(self.encoding)
- except UnicodeDecodeError:
- # byte-to-byte conversion
- filename = filename.decode('iso8859-1')
- # Replace non-BMP char with diamond questionmark.
- return re.sub('[\U00010000-\U0010FFFF]', '\ufffd', filename)
-
def new_callback(self, event):
dirname, basename = self.io.defaultfilename()
self.flist.new(dirname)
@@ -963,10 +948,8 @@ class EditorWindow(object):
menu.delete(0, END) # clear, and rebuild:
for i, file_name in enumerate(rf_list):
file_name = file_name.rstrip() # zap \n
- # make unicode string to display non-ASCII chars correctly
- ufile_name = self._filename_to_unicode(file_name)
callback = instance.__recent_file_callback(file_name)
- menu.add_command(label=ulchars[i] + " " + ufile_name,
+ menu.add_command(label=ulchars[i] + " " + file_name,
command=callback,
underline=0)
@@ -1004,16 +987,10 @@ class EditorWindow(object):
def short_title(self):
filename = self.io.filename
- if filename:
- filename = os.path.basename(filename)
- else:
- filename = "untitled"
- # return unicode string to display non-ASCII chars correctly
- return self._filename_to_unicode(filename)
+ return os.path.basename(filename) if filename else "untitled"
def long_title(self):
- # return unicode string to display non-ASCII chars correctly
- return self._filename_to_unicode(self.io.filename or "")
+ return self.io.filename or ""
def center_insert_event(self, event):
self.center()
diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py
index 4af4ff0..240db71 100644
--- a/Lib/idlelib/idle_test/test_editor.py
+++ b/Lib/idlelib/idle_test/test_editor.py
@@ -30,18 +30,6 @@ class EditorWindowTest(unittest.TestCase):
e._close()
-class EditorFunctionTest(unittest.TestCase):
-
- def test_filename_to_unicode(self):
- func = Editor._filename_to_unicode
- class dummy():
- filesystemencoding = 'utf-8'
- pairs = (('abc', 'abc'), ('a\U00011111c', 'a\ufffdc'),
- (b'abc', 'abc'), (b'a\xf0\x91\x84\x91c', 'a\ufffdc'))
- for inp, out in pairs:
- self.assertEqual(func(dummy, inp), out)
-
-
class TestGetLineIndent(unittest.TestCase):
def test_empty_lines(self):
for tabwidth in [1, 2, 4, 6, 8]:
diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py
index 2e4dfad..bc87d24 100755
--- a/Lib/idlelib/pyshell.py
+++ b/Lib/idlelib/pyshell.py
@@ -679,14 +679,6 @@ class ModifiedInterpreter(InteractiveInterpreter):
self.more = 0
# at the moment, InteractiveInterpreter expects str
assert isinstance(source, str)
- #if isinstance(source, str):
- # from idlelib import iomenu
- # try:
- # source = source.encode(iomenu.encoding)
- # except UnicodeError:
- # self.tkconsole.resetoutput()
- # self.write("Unsupported characters in input\n")
- # return
# InteractiveInterpreter.runsource() calls its runcode() method,
# which is overridden (see below)
return InteractiveInterpreter.runsource(self, source, filename)
@@ -1298,16 +1290,6 @@ class PyShell(OutputWindow):
self.set_line_and_column()
def write(self, s, tags=()):
- if isinstance(s, str) and len(s) and max(s) > '\uffff':
- # Tk doesn't support outputting non-BMP characters
- # Let's assume what printed string is not very long,
- # find first non-BMP character and construct informative
- # UnicodeEncodeError exception.
- for start, char in enumerate(s):
- if char > '\uffff':
- break
- raise UnicodeEncodeError("UCS-2", char, start, start+1,
- 'Non-BMP character not supported in Tk')
try:
self.text.mark_gravity("iomark", "right")
count = OutputWindow.write(self, s, tags, "iomark")
diff --git a/Lib/idlelib/runscript.py b/Lib/idlelib/runscript.py
index de73bf8..e99d0d2 100644
--- a/Lib/idlelib/runscript.py
+++ b/Lib/idlelib/runscript.py
@@ -147,8 +147,7 @@ class ScriptBinding:
interp = self.shell.interp
if pyshell.use_subprocess and restart:
interp.restart_subprocess(
- with_cwd=False, filename=
- self.editwin._filename_to_unicode(filename))
+ with_cwd=False, filename=filename)
dirname = os.path.dirname(filename)
argv = [filename]
if self.cli_args:
diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py
index 80f1668..3183ea8 100644
--- a/Lib/test/test_tcl.py
+++ b/Lib/test/test_tcl.py
@@ -429,9 +429,12 @@ class TclTest(unittest.TestCase):
self.assertEqual(passValue(False), False if self.wantobjects else '0')
self.assertEqual(passValue('string'), 'string')
self.assertEqual(passValue('string\u20ac'), 'string\u20ac')
+ self.assertEqual(passValue('string\U0001f4bb'), 'string\U0001f4bb')
self.assertEqual(passValue('str\x00ing'), 'str\x00ing')
self.assertEqual(passValue('str\x00ing\xbd'), 'str\x00ing\xbd')
self.assertEqual(passValue('str\x00ing\u20ac'), 'str\x00ing\u20ac')
+ self.assertEqual(passValue('str\x00ing\U0001f4bb'),
+ 'str\x00ing\U0001f4bb')
self.assertEqual(passValue(b'str\x00ing'),
b'str\x00ing' if self.wantobjects else 'str\x00ing')
self.assertEqual(passValue(b'str\xc0\x80ing'),
@@ -490,6 +493,7 @@ class TclTest(unittest.TestCase):
check('string')
check('string\xbd')
check('string\u20ac')
+ check('string\U0001f4bb')
check('')
check(b'string', 'string')
check(b'string\xe2\x82\xac', 'string\xe2\x82\xac')
@@ -531,6 +535,7 @@ class TclTest(unittest.TestCase):
('a\n b\t\r c\n ', ('a', 'b', 'c')),
(b'a\n b\t\r c\n ', ('a', 'b', 'c')),
('a \u20ac', ('a', '\u20ac')),
+ ('a \U0001f4bb', ('a', '\U0001f4bb')),
(b'a \xe2\x82\xac', ('a', '\u20ac')),
(b'a\xc0\x80b c\xc0\x80d', ('a\x00b', 'c\x00d')),
('a {b c}', ('a', 'b c')),
diff --git a/Lib/tkinter/test/test_tkinter/test_misc.py b/Lib/tkinter/test/test_tkinter/test_misc.py
index 1d1a3c2..236cae0 100644
--- a/Lib/tkinter/test/test_tkinter/test_misc.py
+++ b/Lib/tkinter/test/test_tkinter/test_misc.py
@@ -156,6 +156,28 @@ class MiscTest(AbstractTkTest, unittest.TestCase):
with self.assertRaises(tkinter.TclError):
root.tk.call('after', 'info', idle1)
+ def test_clipboard(self):
+ root = self.root
+ root.clipboard_clear()
+ root.clipboard_append('Ùñî')
+ self.assertEqual(root.clipboard_get(), 'Ùñî')
+ root.clipboard_append('çōđě')
+ self.assertEqual(root.clipboard_get(), 'Ùñîçōđě')
+ root.clipboard_clear()
+ with self.assertRaises(tkinter.TclError):
+ root.clipboard_get()
+
+ def test_clipboard_astral(self):
+ root = self.root
+ root.clipboard_clear()
+ root.clipboard_append('𝔘𝔫𝔦')
+ self.assertEqual(root.clipboard_get(), '𝔘𝔫𝔦')
+ root.clipboard_append('𝔠𝔬𝔡𝔢')
+ self.assertEqual(root.clipboard_get(), '𝔘𝔫𝔦𝔠𝔬𝔡𝔢')
+ root.clipboard_clear()
+ with self.assertRaises(tkinter.TclError):
+ root.clipboard_get()
+
tests_gui = (MiscTest, )
diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py
index 69e4b3f..2598bc6 100644
--- a/Lib/tkinter/test/test_ttk/test_widgets.py
+++ b/Lib/tkinter/test/test_ttk/test_widgets.py
@@ -489,8 +489,7 @@ class ComboboxTest(EntryTest, unittest.TestCase):
expected=('mon', 'tue', 'wed', 'thur'))
self.checkParam(self.combo, 'values', ('mon', 'tue', 'wed', 'thur'))
self.checkParam(self.combo, 'values', (42, 3.14, '', 'any string'))
- self.checkParam(self.combo, 'values', '',
- expected='' if get_tk_patchlevel() < (8, 5, 10) else ())
+ self.checkParam(self.combo, 'values', '')
self.combo['values'] = ['a', 1, 'c']
@@ -1245,12 +1244,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
expected=('mon', 'tue', 'wed', 'thur'))
self.checkParam(self.spin, 'values', ('mon', 'tue', 'wed', 'thur'))
self.checkParam(self.spin, 'values', (42, 3.14, '', 'any string'))
- self.checkParam(
- self.spin,
- 'values',
- '',
- expected='' if get_tk_patchlevel() < (8, 5, 10) else ()
- )
+ self.checkParam(self.spin, 'values', '')
self.spin['values'] = ['a', 1, 'c']
@@ -1308,8 +1302,7 @@ class TreeviewTest(AbstractWidgetTest, unittest.TestCase):
self.checkParam(widget, 'columns', 'a b c',
expected=('a', 'b', 'c'))
self.checkParam(widget, 'columns', ('a', 'b', 'c'))
- self.checkParam(widget, 'columns', (),
- expected='' if get_tk_patchlevel() < (8, 5, 10) else ())
+ self.checkParam(widget, 'columns', '')
def test_displaycolumns(self):
widget = self.create()
diff --git a/Misc/NEWS.d/next/Library/2019-09-29-22-47-37.bpo-13153.0mO9qR.rst b/Misc/NEWS.d/next/Library/2019-09-29-22-47-37.bpo-13153.0mO9qR.rst
new file mode 100644
index 0000000..6f95615
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-09-29-22-47-37.bpo-13153.0mO9qR.rst
@@ -0,0 +1,4 @@
+OS native encoding is now used for converting between Python strings and
+Tcl objects. This allows to display, copy and paste to clipboard emoji and
+other non-BMP characters. Converting strings from Tcl to Python and back
+now never fails (except MemoryError).
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
index 02924d4..b622c15 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -96,6 +96,24 @@ Copyright (C) 1994 Steen Lumholt.
#endif /* HAVE_CREATEFILEHANDLER */
+/* Use OS native encoding for converting between Python strings and
+ Tcl objects.
+ On Windows use UTF-16 (or UTF-32 for 32-bit Tcl_UniChar) with the
+ "surrogatepass" error handler for converting to/from Tcl Unicode objects.
+ On Linux use UTF-8 with the "surrogateescape" error handler for converting
+ to/from Tcl String objects. */
+#ifdef MS_WINDOWS
+#define USE_TCL_UNICODE 1
+#else
+#define USE_TCL_UNICODE 0
+#endif
+
+#if PY_LITTLE_ENDIAN
+#define NATIVE_BYTEORDER -1
+#else
+#define NATIVE_BYTEORDER 1
+#endif
+
#ifdef MS_WINDOWS
#include <conio.h>
#define WAIT_FOR_STDIN
@@ -290,7 +308,6 @@ typedef struct {
} TkappObject;
#define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
-#define Tkapp_Result(v) Tcl_GetStringResult(Tkapp_Interp(v))
#define DEBUG_REFCNT(v) (printf("DEBUG: id=%p, refcnt=%i\n", \
(void *) v, Py_REFCNT(v)))
@@ -311,10 +328,16 @@ static int tk_load_failed = 0;
#endif
+static PyObject *Tkapp_UnicodeResult(TkappObject *);
+
static PyObject *
-Tkinter_Error(PyObject *v)
+Tkinter_Error(TkappObject *self)
{
- PyErr_SetString(Tkinter_TclError, Tkapp_Result(v));
+ PyObject *res = Tkapp_UnicodeResult(self);
+ if (res != NULL) {
+ PyErr_SetObject(Tkinter_TclError, res);
+ Py_DECREF(res);
+ }
return NULL;
}
@@ -368,30 +391,35 @@ static PyObject *
unicodeFromTclStringAndSize(const char *s, Py_ssize_t size)
{
PyObject *r = PyUnicode_DecodeUTF8(s, size, NULL);
- if (!r && PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) {
- /* Tcl encodes null character as \xc0\x80 */
- if (memchr(s, '\xc0', size)) {
- char *buf, *q;
- const char *e = s + size;
- PyErr_Clear();
- q = buf = (char *)PyMem_Malloc(size);
- if (buf == NULL) {
- PyErr_NoMemory();
- return NULL;
- }
- while (s != e) {
- if (s + 1 != e && s[0] == '\xc0' && s[1] == '\x80') {
- *q++ = '\0';
- s += 2;
- }
- else
- *q++ = *s++;
+ if (r != NULL || !PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) {
+ return r;
+ }
+
+ char *buf = NULL;
+ PyErr_Clear();
+ /* Tcl encodes null character as \xc0\x80 */
+ if (memchr(s, '\xc0', size)) {
+ char *q;
+ const char *e = s + size;
+ q = buf = (char *)PyMem_Malloc(size);
+ if (buf == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ while (s != e) {
+ if (s + 1 != e && s[0] == '\xc0' && s[1] == '\x80') {
+ *q++ = '\0';
+ s += 2;
}
- s = buf;
- size = q - s;
- r = PyUnicode_DecodeUTF8(s, size, NULL);
- PyMem_Free(buf);
+ else
+ *q++ = *s++;
}
+ s = buf;
+ size = q - s;
+ }
+ r = PyUnicode_DecodeUTF8(s, size, "surrogateescape");
+ if (buf != NULL) {
+ PyMem_Free(buf);
}
return r;
}
@@ -406,8 +434,21 @@ static PyObject *
unicodeFromTclObj(Tcl_Obj *value)
{
int len;
- char *s = Tcl_GetStringFromObj(value, &len);
+#if USE_TCL_UNICODE
+ int byteorder = NATIVE_BYTEORDER;
+ const Tcl_UniChar *u = Tcl_GetUnicodeFromObj(value, &len);
+ if (sizeof(Tcl_UniChar) == 2)
+ return PyUnicode_DecodeUTF16((const char *)u, len * 2,
+ "surrogatepass", &byteorder);
+ else if (sizeof(Tcl_UniChar) == 4)
+ return PyUnicode_DecodeUTF32((const char *)u, len * 4,
+ "surrogatepass", &byteorder);
+ else
+ Py_UNREACHABLE();
+#else
+ const char *s = Tcl_GetStringFromObj(value, &len);
return unicodeFromTclStringAndSize(s, len);
+#endif
}
@@ -746,7 +787,7 @@ Tkapp_New(const char *screenName, const char *className,
#endif
if (Tcl_AppInit(v->interp) != TCL_OK) {
- PyObject *result = Tkinter_Error((PyObject *)v);
+ PyObject *result = Tkinter_Error(v);
#ifdef TKINTER_PROTECT_LOADTK
if (wantTk) {
const char *_tkinter_tk_failed;
@@ -817,12 +858,6 @@ PyTclObject_dealloc(PyTclObject *self)
Py_DECREF(tp);
}
-static const char *
-PyTclObject_TclString(PyObject *self)
-{
- return Tcl_GetString(((PyTclObject*)self)->value);
-}
-
/* Like _str, but create Unicode if necessary. */
PyDoc_STRVAR(PyTclObject_string__doc__,
"the string representation of this object, either as str or bytes");
@@ -1048,53 +1083,51 @@ AsObj(PyObject *value)
}
if (PyUnicode_Check(value)) {
- void *inbuf;
- Py_ssize_t size;
- int kind;
- Tcl_UniChar *outbuf = NULL;
- Py_ssize_t i;
- size_t allocsize;
-
if (PyUnicode_READY(value) == -1)
return NULL;
- inbuf = PyUnicode_DATA(value);
- size = PyUnicode_GET_LENGTH(value);
- if (size == 0)
- return Tcl_NewUnicodeObj((const void *)"", 0);
+ Py_ssize_t size = PyUnicode_GET_LENGTH(value);
+ if (size == 0) {
+ return Tcl_NewStringObj("", 0);
+ }
if (!CHECK_SIZE(size, sizeof(Tcl_UniChar))) {
PyErr_SetString(PyExc_OverflowError, "string is too long");
return NULL;
}
- kind = PyUnicode_KIND(value);
- if (kind == sizeof(Tcl_UniChar))
- return Tcl_NewUnicodeObj(inbuf, (int)size);
- allocsize = ((size_t)size) * sizeof(Tcl_UniChar);
- outbuf = (Tcl_UniChar*)PyMem_Malloc(allocsize);
- /* Else overflow occurred, and we take the next exit */
- if (!outbuf) {
- PyErr_NoMemory();
- return NULL;
+ if (PyUnicode_IS_ASCII(value)) {
+ return Tcl_NewStringObj((const char *)PyUnicode_DATA(value),
+ (int)size);
}
- for (i = 0; i < size; i++) {
- Py_UCS4 ch = PyUnicode_READ(kind, inbuf, i);
- /* We cannot test for sizeof(Tcl_UniChar) directly,
- so we test for UTF-8 size instead. */
-#if TCL_UTF_MAX == 3
- if (ch >= 0x10000) {
- /* Tcl doesn't do UTF-16, yet. */
- PyErr_Format(Tkinter_TclError,
- "character U+%x is above the range "
- "(U+0000-U+FFFF) allowed by Tcl",
- ch);
- PyMem_Free(outbuf);
- return NULL;
- }
+
+ PyObject *encoded;
+#if USE_TCL_UNICODE
+ if (sizeof(Tcl_UniChar) == 2)
+ encoded = _PyUnicode_EncodeUTF16(value,
+ "surrogatepass", NATIVE_BYTEORDER);
+ else if (sizeof(Tcl_UniChar) == 4)
+ encoded = _PyUnicode_EncodeUTF32(value,
+ "surrogatepass", NATIVE_BYTEORDER);
+ else
+ Py_UNREACHABLE();
+#else
+ encoded = _PyUnicode_AsUTF8String(value, "surrogateescape");
#endif
- outbuf[i] = ch;
+ if (!encoded) {
+ return NULL;
}
- result = Tcl_NewUnicodeObj(outbuf, (int)size);
- PyMem_Free(outbuf);
+ size = PyBytes_GET_SIZE(encoded);
+ if (size > INT_MAX) {
+ Py_DECREF(encoded);
+ PyErr_SetString(PyExc_OverflowError, "string is too long");
+ return NULL;
+ }
+#if USE_TCL_UNICODE
+ result = Tcl_NewUnicodeObj((const Tcl_UniChar *)PyBytes_AS_STRING(encoded),
+ (int)(size / sizeof(Tcl_UniChar)));
+#else
+ result = Tcl_NewStringObj(PyBytes_AS_STRING(encoded), (int)size);
+#endif
+ Py_DECREF(encoded);
return result;
}
@@ -1113,7 +1146,7 @@ AsObj(PyObject *value)
}
static PyObject *
-fromBoolean(PyObject* tkapp, Tcl_Obj *value)
+fromBoolean(TkappObject *tkapp, Tcl_Obj *value)
{
int boolValue;
if (Tcl_GetBooleanFromObj(Tkapp_Interp(tkapp), value, &boolValue) == TCL_ERROR)
@@ -1122,7 +1155,7 @@ fromBoolean(PyObject* tkapp, Tcl_Obj *value)
}
static PyObject*
-fromWideIntObj(PyObject* tkapp, Tcl_Obj *value)
+fromWideIntObj(TkappObject *tkapp, Tcl_Obj *value)
{
Tcl_WideInt wideValue;
if (Tcl_GetWideIntFromObj(Tkapp_Interp(tkapp), value, &wideValue) == TCL_OK) {
@@ -1138,7 +1171,7 @@ fromWideIntObj(PyObject* tkapp, Tcl_Obj *value)
#ifdef HAVE_LIBTOMMAMTH
static PyObject*
-fromBignumObj(PyObject* tkapp, Tcl_Obj *value)
+fromBignumObj(TkappObject *tkapp, Tcl_Obj *value)
{
mp_int bigValue;
unsigned long numBytes;
@@ -1174,32 +1207,31 @@ fromBignumObj(PyObject* tkapp, Tcl_Obj *value)
#endif
static PyObject*
-FromObj(PyObject* tkapp, Tcl_Obj *value)
+FromObj(TkappObject *tkapp, Tcl_Obj *value)
{
PyObject *result = NULL;
- TkappObject *app = (TkappObject*)tkapp;
Tcl_Interp *interp = Tkapp_Interp(tkapp);
if (value->typePtr == NULL) {
- return unicodeFromTclStringAndSize(value->bytes, value->length);
+ return unicodeFromTclObj(value);
}
- if (value->typePtr == app->BooleanType ||
- value->typePtr == app->OldBooleanType) {
+ if (value->typePtr == tkapp->BooleanType ||
+ value->typePtr == tkapp->OldBooleanType) {
return fromBoolean(tkapp, value);
}
- if (value->typePtr == app->ByteArrayType) {
+ if (value->typePtr == tkapp->ByteArrayType) {
int size;
char *data = (char*)Tcl_GetByteArrayFromObj(value, &size);
return PyBytes_FromStringAndSize(data, size);
}
- if (value->typePtr == app->DoubleType) {
+ if (value->typePtr == tkapp->DoubleType) {
return PyFloat_FromDouble(value->internalRep.doubleValue);
}
- if (value->typePtr == app->IntType) {
+ if (value->typePtr == tkapp->IntType) {
long longValue;
if (Tcl_GetLongFromObj(interp, value, &longValue) == TCL_OK)
return PyLong_FromLong(longValue);
@@ -1207,8 +1239,8 @@ FromObj(PyObject* tkapp, Tcl_Obj *value)
fall through to wideInt handling. */
}
- if (value->typePtr == app->IntType ||
- value->typePtr == app->WideIntType) {
+ if (value->typePtr == tkapp->IntType ||
+ value->typePtr == tkapp->WideIntType) {
result = fromWideIntObj(tkapp, value);
if (result != NULL || PyErr_Occurred())
return result;
@@ -1218,14 +1250,14 @@ FromObj(PyObject* tkapp, Tcl_Obj *value)
}
#ifdef HAVE_LIBTOMMAMTH
- if (value->typePtr == app->IntType ||
- value->typePtr == app->WideIntType ||
- value->typePtr == app->BignumType) {
+ if (value->typePtr == tkapp->IntType ||
+ value->typePtr == tkapp->WideIntType ||
+ value->typePtr == tkapp->BignumType) {
return fromBignumObj(tkapp, value);
}
#endif
- if (value->typePtr == app->ListType) {
+ if (value->typePtr == tkapp->ListType) {
int size;
int i, status;
PyObject *elem;
@@ -1253,30 +1285,28 @@ FromObj(PyObject* tkapp, Tcl_Obj *value)
return result;
}
- if (value->typePtr == app->ProcBodyType) {
+ if (value->typePtr == tkapp->ProcBodyType) {
/* fall through: return tcl object. */
}
- if (value->typePtr == app->StringType) {
- return PyUnicode_FromKindAndData(
- sizeof(Tcl_UniChar), Tcl_GetUnicode(value),
- Tcl_GetCharLength(value));
+ if (value->typePtr == tkapp->StringType) {
+ return unicodeFromTclObj(value);
}
#if TK_HEX_VERSION >= 0x08050000
- if (app->BooleanType == NULL &&
+ if (tkapp->BooleanType == NULL &&
strcmp(value->typePtr->name, "booleanString") == 0) {
/* booleanString type is not registered in Tcl */
- app->BooleanType = value->typePtr;
+ tkapp->BooleanType = value->typePtr;
return fromBoolean(tkapp, value);
}
#endif
#ifdef HAVE_LIBTOMMAMTH
- if (app->BignumType == NULL &&
+ if (tkapp->BignumType == NULL &&
strcmp(value->typePtr->name, "bignum") == 0) {
/* bignum type is not registered in Tcl */
- app->BignumType = value->typePtr;
+ tkapp->BignumType = value->typePtr;
return fromBignumObj(tkapp, value);
}
#endif
@@ -1366,19 +1396,28 @@ finally:
return NULL;
}
+/* Convert the results of a command call into a Python string. */
+
+static PyObject *
+Tkapp_UnicodeResult(TkappObject *self)
+{
+ return unicodeFromTclObj(Tcl_GetObjResult(self->interp));
+}
+
+
/* Convert the results of a command call into a Python objects. */
-static PyObject*
-Tkapp_CallResult(TkappObject *self)
+static PyObject *
+Tkapp_ObjectResult(TkappObject *self)
{
PyObject *res = NULL;
Tcl_Obj *value = Tcl_GetObjResult(self->interp);
- if(self->wantobjects) {
+ if (self->wantobjects) {
/* Not sure whether the IncrRef is necessary, but something
may overwrite the interpreter result while we are
converting it. */
Tcl_IncrRefCount(value);
- res = FromObj((PyObject*)self, value);
+ res = FromObj(self, value);
Tcl_DecrRefCount(value);
} else {
res = unicodeFromTclObj(value);
@@ -1410,15 +1449,13 @@ Tkapp_CallProc(Tkapp_CallEvent *e, int flags)
i = Tcl_EvalObjv(e->self->interp, objc, objv, e->flags);
ENTER_PYTHON
if (i == TCL_ERROR) {
- *(e->res) = NULL;
- *(e->exc_type) = NULL;
- *(e->exc_tb) = NULL;
- *(e->exc_value) = PyObject_CallFunction(
- Tkinter_TclError, "s",
- Tcl_GetStringResult(e->self->interp));
+ *(e->res) = Tkinter_Error(e->self);
}
else {
- *(e->res) = Tkapp_CallResult(e->self);
+ *(e->res) = Tkapp_ObjectResult(e->self);
+ }
+ if (*(e->res) == NULL) {
+ PyErr_Fetch(e->exc_type, e->exc_value, e->exc_tb);
}
LEAVE_PYTHON
@@ -1506,9 +1543,9 @@ Tkapp_Call(PyObject *selfptr, PyObject *args)
ENTER_OVERLAP
if (i == TCL_ERROR)
- Tkinter_Error(selfptr);
+ Tkinter_Error(self);
else
- res = Tkapp_CallResult(self);
+ res = Tkapp_ObjectResult(self);
LEAVE_OVERLAP_TCL
@@ -1540,9 +1577,9 @@ _tkinter_tkapp_eval_impl(TkappObject *self, const char *script)
err = Tcl_Eval(Tkapp_Interp(self), script);
ENTER_OVERLAP
if (err == TCL_ERROR)
- res = Tkinter_Error((PyObject *)self);
+ res = Tkinter_Error(self);
else
- res = unicodeFromTclString(Tkapp_Result(self));
+ res = Tkapp_UnicodeResult(self);
LEAVE_OVERLAP_TCL
return res;
}
@@ -1569,9 +1606,9 @@ _tkinter_tkapp_evalfile_impl(TkappObject *self, const char *fileName)
err = Tcl_EvalFile(Tkapp_Interp(self), fileName);
ENTER_OVERLAP
if (err == TCL_ERROR)
- res = Tkinter_Error((PyObject *)self);
+ res = Tkinter_Error(self);
else
- res = unicodeFromTclString(Tkapp_Result(self));
+ res = Tkapp_UnicodeResult(self);
LEAVE_OVERLAP_TCL
return res;
}
@@ -1598,9 +1635,9 @@ _tkinter_tkapp_record_impl(TkappObject *self, const char *script)
err = Tcl_RecordAndEval(Tkapp_Interp(self), script, TCL_NO_EVAL);
ENTER_OVERLAP
if (err == TCL_ERROR)
- res = Tkinter_Error((PyObject *)self);
+ res = Tkinter_Error(self);
else
- res = unicodeFromTclString(Tkapp_Result(self));
+ res = Tkapp_UnicodeResult(self);
LEAVE_OVERLAP_TCL
return res;
}
@@ -1631,13 +1668,13 @@ _tkinter_tkapp_adderrorinfo_impl(TkappObject *self, const char *msg)
/** Tcl Variable **/
-typedef PyObject* (*EventFunc)(PyObject*, PyObject *args, int flags);
+typedef PyObject* (*EventFunc)(TkappObject *, PyObject *, int);
TCL_DECLARE_MUTEX(var_mutex)
typedef struct VarEvent {
Tcl_Event ev; /* must be first */
- PyObject *self;
+ TkappObject *self;
PyObject *args;
int flags;
EventFunc func;
@@ -1692,7 +1729,7 @@ varname_converter(PyObject *in, void *_out)
return 1;
}
if (PyTclObject_Check(in)) {
- *out = PyTclObject_TclString(in);
+ *out = Tcl_GetString(((PyTclObject *)in)->value);
return 1;
}
PyErr_Format(PyExc_TypeError,
@@ -1750,7 +1787,7 @@ var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags)
PyErr_NoMemory();
return NULL;
}
- ev->self = selfptr;
+ ev->self = self;
ev->args = args;
ev->flags = flags;
ev->func = func;
@@ -1770,11 +1807,11 @@ var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags)
return res;
}
/* Tcl is not threaded, or this is the interpreter thread. */
- return func(selfptr, args, flags);
+ return func(self, args, flags);
}
static PyObject *
-SetVar(PyObject *self, PyObject *args, int flags)
+SetVar(TkappObject *self, PyObject *args, int flags)
{
const char *name1, *name2;
PyObject *newValue;
@@ -1843,7 +1880,7 @@ Tkapp_GlobalSetVar(PyObject *self, PyObject *args)
static PyObject *
-GetVar(PyObject *self, PyObject *args, int flags)
+GetVar(TkappObject *self, PyObject *args, int flags)
{
const char *name1, *name2=NULL;
PyObject *res = NULL;
@@ -1858,10 +1895,9 @@ GetVar(PyObject *self, PyObject *args, int flags)
tres = Tcl_GetVar2Ex(Tkapp_Interp(self), name1, name2, flags);
ENTER_OVERLAP
if (tres == NULL) {
- PyErr_SetString(Tkinter_TclError,
- Tcl_GetStringResult(Tkapp_Interp(self)));
+ Tkinter_Error(self);
} else {
- if (((TkappObject*)self)->wantobjects) {
+ if (self->wantobjects) {
res = FromObj(self, tres);
}
else {
@@ -1887,7 +1923,7 @@ Tkapp_GlobalGetVar(PyObject *self, PyObject *args)
static PyObject *
-UnsetVar(PyObject *self, PyObject *args, int flags)
+UnsetVar(TkappObject *self, PyObject *args, int flags)
{
char *name1, *name2=NULL;
int code;
@@ -1959,7 +1995,7 @@ _tkinter_tkapp_getint(TkappObject *self, PyObject *arg)
CHECK_STRING_LENGTH(s);
value = Tcl_NewStringObj(s, -1);
if (value == NULL)
- return Tkinter_Error((PyObject *)self);
+ return Tkinter_Error(self);
}
/* 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).
@@ -1968,14 +2004,14 @@ _tkinter_tkapp_getint(TkappObject *self, PyObject *arg)
value in ranges -2**64..-2**63-1 and 2**63..2**64-1 (on 32-bit platform).
*/
#ifdef HAVE_LIBTOMMAMTH
- result = fromBignumObj((PyObject *)self, value);
+ result = fromBignumObj(self, value);
#else
- result = fromWideIntObj((PyObject *)self, value);
+ result = fromWideIntObj(self, value);
#endif
Tcl_DecrRefCount(value);
if (result != NULL || PyErr_Occurred())
return result;
- return Tkinter_Error((PyObject *)self);
+ return Tkinter_Error(self);
}
/*[clinic input]
@@ -2006,7 +2042,7 @@ _tkinter_tkapp_getdouble(TkappObject *self, PyObject *arg)
if (Tcl_GetDoubleFromObj(Tkapp_Interp(self),
((PyTclObject*)arg)->value,
&v) == TCL_ERROR)
- return Tkinter_Error((PyObject *)self);
+ return Tkinter_Error(self);
return PyFloat_FromDouble(v);
}
@@ -2014,7 +2050,7 @@ _tkinter_tkapp_getdouble(TkappObject *self, PyObject *arg)
return NULL;
CHECK_STRING_LENGTH(s);
if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR)
- return Tkinter_Error((PyObject *)self);
+ return Tkinter_Error(self);
return PyFloat_FromDouble(v);
}
@@ -2041,7 +2077,7 @@ _tkinter_tkapp_getboolean(TkappObject *self, PyObject *arg)
if (Tcl_GetBooleanFromObj(Tkapp_Interp(self),
((PyTclObject*)arg)->value,
&v) == TCL_ERROR)
- return Tkinter_Error((PyObject *)self);
+ return Tkinter_Error(self);
return PyBool_FromLong(v);
}
@@ -2049,7 +2085,7 @@ _tkinter_tkapp_getboolean(TkappObject *self, PyObject *arg)
return NULL;
CHECK_STRING_LENGTH(s);
if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR)
- return Tkinter_Error((PyObject *)self);
+ return Tkinter_Error(self);
return PyBool_FromLong(v);
}
@@ -2075,9 +2111,9 @@ _tkinter_tkapp_exprstring_impl(TkappObject *self, const char *s)
retval = Tcl_ExprString(Tkapp_Interp(self), s);
ENTER_OVERLAP
if (retval == TCL_ERROR)
- res = Tkinter_Error((PyObject *)self);
+ res = Tkinter_Error(self);
else
- res = unicodeFromTclString(Tkapp_Result(self));
+ res = Tkapp_UnicodeResult(self);
LEAVE_OVERLAP_TCL
return res;
}
@@ -2105,7 +2141,7 @@ _tkinter_tkapp_exprlong_impl(TkappObject *self, const char *s)
retval = Tcl_ExprLong(Tkapp_Interp(self), s, &v);
ENTER_OVERLAP
if (retval == TCL_ERROR)
- res = Tkinter_Error((PyObject *)self);
+ res = Tkinter_Error(self);
else
res = PyLong_FromLong(v);
LEAVE_OVERLAP_TCL
@@ -2136,7 +2172,7 @@ _tkinter_tkapp_exprdouble_impl(TkappObject *self, const char *s)
ENTER_OVERLAP
PyFPE_END_PROTECT(retval)
if (retval == TCL_ERROR)
- res = Tkinter_Error((PyObject *)self);
+ res = Tkinter_Error(self);
else
res = PyFloat_FromDouble(v);
LEAVE_OVERLAP_TCL
@@ -2165,7 +2201,7 @@ _tkinter_tkapp_exprboolean_impl(TkappObject *self, const char *s)
retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v);
ENTER_OVERLAP
if (retval == TCL_ERROR)
- res = Tkinter_Error((PyObject *)self);
+ res = Tkinter_Error(self);
else
res = PyLong_FromLong(v);
LEAVE_OVERLAP_TCL
@@ -2198,12 +2234,12 @@ _tkinter_tkapp_splitlist(TkappObject *self, PyObject *arg)
if (Tcl_ListObjGetElements(Tkapp_Interp(self),
((PyTclObject*)arg)->value,
&objc, &objv) == TCL_ERROR) {
- return Tkinter_Error((PyObject *)self);
+ return Tkinter_Error(self);
}
if (!(v = PyTuple_New(objc)))
return NULL;
for (i = 0; i < objc; i++) {
- PyObject *s = FromObj((PyObject*)self, objv[i]);
+ PyObject *s = FromObj(self, objv[i]);
if (!s) {
Py_DECREF(v);
return NULL;
@@ -2231,7 +2267,7 @@ _tkinter_tkapp_splitlist(TkappObject *self, PyObject *arg)
if (Tcl_SplitList(Tkapp_Interp(self), list,
&argc, &argv) == TCL_ERROR) {
PyMem_Free(list);
- return Tkinter_Error((PyObject *)self);
+ return Tkinter_Error(self);
}
if (!(v = PyTuple_New(argc)))
@@ -2275,16 +2311,16 @@ _tkinter_tkapp_split(TkappObject *self, PyObject *arg)
int i;
if (Tcl_ListObjGetElements(Tkapp_Interp(self), value,
&objc, &objv) == TCL_ERROR) {
- return FromObj((PyObject*)self, value);
+ return FromObj(self, value);
}
if (objc == 0)
return PyUnicode_FromString("");
if (objc == 1)
- return FromObj((PyObject*)self, objv[0]);
+ return FromObj(self, objv[0]);
if (!(v = PyTuple_New(objc)))
return NULL;
for (i = 0; i < objc; i++) {
- PyObject *s = FromObj((PyObject*)self, objv[i]);
+ PyObject *s = FromObj(self, objv[i]);
if (!s) {
Py_DECREF(v);
return NULL;
@@ -2331,34 +2367,31 @@ PythonCmd_Error(Tcl_Interp *interp)
* function or method.
*/
static int
-PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[])
+PythonCmd(ClientData clientData, Tcl_Interp *interp,
+ int objc, Tcl_Obj *const objv[])
{
PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData;
- PyObject *func, *arg, *res;
- int i, rv;
+ PyObject *args, *res;
+ int i;
Tcl_Obj *obj_res;
ENTER_PYTHON
- /* TBD: no error checking here since we know, via the
- * Tkapp_CreateCommand() that the client data is a two-tuple
- */
- func = data->func;
-
- /* Create argument list (argv1, ..., argvN) */
- if (!(arg = PyTuple_New(argc - 1)))
+ /* Create argument tuple (objv1, ..., objvN) */
+ if (!(args = PyTuple_New(objc - 1)))
return PythonCmd_Error(interp);
- for (i = 0; i < (argc - 1); i++) {
- PyObject *s = unicodeFromTclString(argv[i + 1]);
+ for (i = 0; i < (objc - 1); i++) {
+ PyObject *s = unicodeFromTclObj(objv[i + 1]);
if (!s) {
- Py_DECREF(arg);
+ Py_DECREF(args);
return PythonCmd_Error(interp);
}
- PyTuple_SET_ITEM(arg, i, s);
+ PyTuple_SET_ITEM(args, i, s);
}
- res = PyObject_Call(func, arg, NULL);
- Py_DECREF(arg);
+
+ res = PyObject_Call(data->func, args, NULL);
+ Py_DECREF(args);
if (res == NULL)
return PythonCmd_Error(interp);
@@ -2368,18 +2401,15 @@ PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[
Py_DECREF(res);
return PythonCmd_Error(interp);
}
- else {
- Tcl_SetObjResult(interp, obj_res);
- rv = TCL_OK;
- }
-
+ Tcl_SetObjResult(interp, obj_res);
Py_DECREF(res);
LEAVE_PYTHON
- return rv;
+ return TCL_OK;
}
+
static void
PythonCmdDelete(ClientData clientData)
{
@@ -2411,7 +2441,7 @@ static int
Tkapp_CommandProc(CommandEvent *ev, int flags)
{
if (ev->create)
- *ev->status = Tcl_CreateCommand(
+ *ev->status = Tcl_CreateObjCommand(
ev->interp, ev->name, PythonCmd,
ev->data, PythonCmdDelete) == NULL;
else
@@ -2477,7 +2507,7 @@ _tkinter_tkapp_createcommand_impl(TkappObject *self, const char *name,
else
{
ENTER_TCL
- err = Tcl_CreateCommand(
+ err = Tcl_CreateObjCommand(
Tkapp_Interp(self), name, PythonCmd,
(ClientData)data, PythonCmdDelete) == NULL;
LEAVE_TCL
@@ -2953,9 +2983,9 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self)
if (err == TCL_ERROR) {
/* This sets an exception, but we cannot return right
away because we need to exit the overlap first. */
- Tkinter_Error((PyObject *)self);
+ Tkinter_Error(self);
} else {
- _tk_exists = Tkapp_Result(self);
+ _tk_exists = Tcl_GetStringResult(Tkapp_Interp(self));
}
LEAVE_OVERLAP_TCL
if (err == TCL_ERROR) {
@@ -2963,8 +2993,7 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self)
}
if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) {
if (Tk_Init(interp) == TCL_ERROR) {
- PyErr_SetString(Tkinter_TclError,
- Tcl_GetStringResult(Tkapp_Interp(self)));
+ Tkinter_Error(self);
#ifdef TKINTER_PROTECT_LOADTK
tk_load_failed = 1;
#endif