diff -r 8676e436c0f0 Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py Wed May 21 17:12:21 2014 +0300 +++ b/Lib/test/test_tcl.py Thu May 22 17:32:01 2014 +0300 @@ -133,6 +133,47 @@ tcl = self.interp self.assertRaises(TclError,tcl.unsetvar,'a') + def test_getint(self): + tcl = self.interp.tk + self.assertEqual(tcl.getint(' 42 '), 42) + self.assertEqual(tcl.getint(42), 42) + self.assertRaises(TypeError, tcl.getint) + self.assertRaises(TypeError, tcl.getint, '42', '10') + self.assertRaises(TypeError, tcl.getint, b'42') + self.assertRaises(TypeError, tcl.getint, 42.0) + self.assertRaises(TclError, tcl.getint, 'a') + self.assertRaises((ValueError, TclError), tcl.getint, '42\0') + self.assertRaises((UnicodeEncodeError, ValueError, TclError), + tcl.getint, '42\ud800') + + def test_getdouble(self): + tcl = self.interp.tk + self.assertEqual(tcl.getdouble(' 42 '), 42.0) + self.assertEqual(tcl.getdouble(' 42.5 '), 42.5) + self.assertEqual(tcl.getdouble(42.5), 42.5) + self.assertRaises(TypeError, tcl.getdouble) + self.assertRaises(TypeError, tcl.getdouble, '42.5', '10') + self.assertRaises(TypeError, tcl.getdouble, b'42.5') + self.assertRaises(TypeError, tcl.getdouble, 42) + self.assertRaises(TclError, tcl.getdouble, 'a') + self.assertRaises((ValueError, TclError), tcl.getdouble, '42.5\0') + self.assertRaises((UnicodeEncodeError, ValueError, TclError), + tcl.getdouble, '42.5\ud800') + + def test_getboolean(self): + tcl = self.interp.tk + self.assertIs(tcl.getboolean('on'), True) + self.assertIs(tcl.getboolean('1'), True) + self.assertEqual(tcl.getboolean(42), 42) + self.assertRaises(TypeError, tcl.getboolean) + self.assertRaises(TypeError, tcl.getboolean, 'on', '1') + self.assertRaises(TypeError, tcl.getboolean, b'on') + self.assertRaises(TypeError, tcl.getboolean, 1.0) + self.assertRaises(TclError, tcl.getboolean, 'a') + self.assertRaises((ValueError, TclError), tcl.getboolean, 'on\0') + self.assertRaises((UnicodeEncodeError, ValueError, TclError), + tcl.getboolean, 'on\ud800') + def testEvalFile(self): tcl = self.interp with open(support.TESTFN, 'w') as f: diff -r 8676e436c0f0 Modules/_tkinter.c --- a/Modules/_tkinter.c Wed May 21 17:12:21 2014 +0300 +++ b/Modules/_tkinter.c Thu May 22 17:32:01 2014 +0300 @@ -881,6 +881,78 @@ }; +static const char * +bytesAsShortString(PyObject *arg) +{ + const char *s; + if (PyBytes_Size(arg) > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "bytes object is too long"); + return NULL; + } + s = PyBytes_AsString(arg); + if (strlen(s) != PyBytes_Size(arg)) { + PyErr_SetString(PyExc_ValueError, "null byte in bytes object"); + return NULL; + } + return s; +} + +static const char * +unicodeAsShortString(PyObject *arg) +{ + Py_ssize_t size; + const char *s = PyUnicode_AsUTF8AndSize(arg, &size); + if (s == NULL) + return NULL; + if (size > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "string is too long"); + return NULL; + } + if (strlen(s) != size) { + PyErr_SetString(PyExc_ValueError, "null character in string"); + return NULL; + } + return s; +} + +static int +short_string_converter(PyObject *in, void *_out) +{ + const char *s; + const char **out = (const char**)_out; + if (PyUnicode_Check(in)) { + s = unicodeAsShortString(in); + if (s == NULL) + return 0; + *out = s; + return 1; + } + PyErr_Format(PyExc_TypeError, + "must be str, not %.50s", in->ob_type->tp_name); + return 0; +} + +static int +short_zstring_converter(PyObject *in, void *_out) +{ + const char *s; + const char **out = (const char**)_out; + if (in == Py_None) { + *out = NULL; + return 1; + } + if (PyUnicode_Check(in)) { + s = unicodeAsShortString(in); + if (s == NULL) + return 0; + *out = s; + return 1; + } + PyErr_Format(PyExc_TypeError, + "must be str or None, not %.50s", in->ob_type->tp_name); + return 0; +} + static Tcl_Obj* AsObj(PyObject *value) { @@ -1300,7 +1372,7 @@ PyObject *res = NULL; int err; - if (!PyArg_ParseTuple(args, "s:eval", &script)) + if (!PyArg_ParseTuple(args, "O&:eval", short_string_converter, &script)) return NULL; CHECK_TCL_APPARTMENT; @@ -1323,7 +1395,8 @@ PyObject *res = NULL; int err; - if (!PyArg_ParseTuple(args, "s:evalfile", &fileName)) + if (!PyArg_ParseTuple(args, "O&:evalfile", + short_string_converter, &fileName)) return NULL; CHECK_TCL_APPARTMENT; @@ -1346,7 +1419,7 @@ PyObject *res = NULL; int err; - if (!PyArg_ParseTuple(args, "s", &script)) + if (!PyArg_ParseTuple(args, "O&:record", short_string_converter, &script)) return NULL; CHECK_TCL_APPARTMENT; @@ -1367,7 +1440,8 @@ { char *msg; - if (!PyArg_ParseTuple(args, "s:adderrorinfo", &msg)) + if (!PyArg_ParseTuple(args, "O&:adderrorinfo", + short_string_converter, &msg)) return NULL; CHECK_TCL_APPARTMENT; @@ -1403,35 +1477,19 @@ static int varname_converter(PyObject *in, void *_out) { - char *s; - char **out = (char**)_out; + const char *s; + const char **out = (const char**)_out; if (PyBytes_Check(in)) { - if (PyBytes_Size(in) > INT_MAX) { - PyErr_SetString(PyExc_OverflowError, "bytes object is too long"); + s = bytesAsShortString(in); + if (s == NULL) return 0; - } - s = PyBytes_AsString(in); - if (strlen(s) != PyBytes_Size(in)) { - PyErr_SetString(PyExc_ValueError, "null byte in bytes object"); - return 0; - } *out = s; return 1; } if (PyUnicode_Check(in)) { - Py_ssize_t size; - s = PyUnicode_AsUTF8AndSize(in, &size); - if (s == NULL) { + s = unicodeAsShortString(in); + if (s == NULL) return 0; - } - if (size > INT_MAX) { - PyErr_SetString(PyExc_OverflowError, "string is too long"); - return 0; - } - if (strlen(s) != size) { - PyErr_SetString(PyExc_ValueError, "null character in string"); - return 0; - } *out = s; return 1; } @@ -1549,8 +1607,9 @@ LEAVE_OVERLAP_TCL break; case 3: - if (!PyArg_ParseTuple(args, "ssO:setvar", - &name1, &name2, &newValue)) + if (!PyArg_ParseTuple(args, "O&O&O:setvar", + short_string_converter, &name1, + short_string_converter, &name2, &newValue)) return NULL; /* XXX must hold tcl lock already??? */ newval = AsObj(newValue); @@ -1593,8 +1652,9 @@ PyObject *res = NULL; Tcl_Obj *tres; - if (!PyArg_ParseTuple(args, "O&|s:getvar", - varname_converter, &name1, &name2)) + if (!PyArg_ParseTuple(args, "O&|O&:getvar", + varname_converter, &name1, + short_string_converter, &name2)) return NULL; ENTER_TCL @@ -1636,7 +1696,9 @@ int code; PyObject *res = NULL; - if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2)) + if (!PyArg_ParseTuple(args, "O&|O&:unsetvar", + short_string_converter, &name1, + short_string_converter, &name2)) return NULL; ENTER_TCL @@ -1672,61 +1734,79 @@ static PyObject * Tkapp_GetInt(PyObject *self, PyObject *args) { - char *s; - int v; - - if (PyTuple_Size(args) == 1) { - PyObject* o = PyTuple_GetItem(args, 0); - if (PyLong_Check(o)) { - Py_INCREF(o); - return o; - } + PyObject *arg; + + if (!PyArg_ParseTuple(args, "O:getint", &arg)) + return NULL; + if (PyLong_Check(arg)) { + Py_INCREF(arg); + return arg; } - if (!PyArg_ParseTuple(args, "s:getint", &s)) - return NULL; - if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR) + if (PyUnicode_Check(arg)) { + int intVal; + const char *s = unicodeAsShortString(arg); + if (s == NULL) + return NULL; + if (Tcl_GetInt(Tkapp_Interp(self), s, &intVal) == TCL_OK) + return PyLong_FromLong(intVal); return Tkinter_Error(self); - return Py_BuildValue("i", v); + } + PyErr_Format(PyExc_TypeError, + "must be int or str, not %.50s", + arg->ob_type->tp_name); + return NULL; } static PyObject * Tkapp_GetDouble(PyObject *self, PyObject *args) { - char *s; - double v; - - if (PyTuple_Size(args) == 1) { - PyObject *o = PyTuple_GetItem(args, 0); - if (PyFloat_Check(o)) { - Py_INCREF(o); - return o; - } + PyObject *arg; + + if (!PyArg_ParseTuple(args, "O:getdouble", &arg)) + return NULL; + if (PyFloat_Check(arg)) { + Py_INCREF(arg); + return arg; } - if (!PyArg_ParseTuple(args, "s:getdouble", &s)) - return NULL; - if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR) + if (PyUnicode_Check(arg)) { + double doubleVal; + const char *s = unicodeAsShortString(arg); + if (s == NULL) + return NULL; + if (Tcl_GetDouble(Tkapp_Interp(self), s, &doubleVal) == TCL_OK) + return PyFloat_FromDouble(doubleVal); return Tkinter_Error(self); - return Py_BuildValue("d", v); + } + PyErr_Format(PyExc_TypeError, + "must be double or str, not %.50s", + arg->ob_type->tp_name); + return NULL; } static PyObject * Tkapp_GetBoolean(PyObject *self, PyObject *args) { - char *s; - int v; - - if (PyTuple_Size(args) == 1) { - PyObject *o = PyTuple_GetItem(args, 0); - if (PyLong_Check(o)) { - Py_INCREF(o); - return o; - } + PyObject *arg; + + if (!PyArg_ParseTuple(args, "O:getboolean", &arg)) + return NULL; + if (PyLong_Check(arg)) { + Py_INCREF(arg); + return arg; } - if (!PyArg_ParseTuple(args, "s:getboolean", &s)) - return NULL; - if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR) + if (PyUnicode_Check(arg)) { + int intVal; + const char *s = unicodeAsShortString(arg); + if (s == NULL) + return NULL; + if (Tcl_GetBoolean(Tkapp_Interp(self), s, &intVal) == TCL_OK) + return PyBool_FromLong(intVal); return Tkinter_Error(self); - return PyBool_FromLong(v); + } + PyErr_Format(PyExc_TypeError, + "must be int or str, not %.50s", + arg->ob_type->tp_name); + return NULL; } static PyObject * @@ -1736,7 +1816,7 @@ PyObject *res = NULL; int retval; - if (!PyArg_ParseTuple(args, "s:exprstring", &s)) + if (!PyArg_ParseTuple(args, "O&:exprstring", short_string_converter, &s)) return NULL; CHECK_TCL_APPARTMENT; @@ -1760,7 +1840,7 @@ int retval; long v; - if (!PyArg_ParseTuple(args, "s:exprlong", &s)) + if (!PyArg_ParseTuple(args, "O&:exprlong", short_string_converter, &s)) return NULL; CHECK_TCL_APPARTMENT; @@ -1784,7 +1864,7 @@ double v; int retval; - if (!PyArg_ParseTuple(args, "s:exprdouble", &s)) + if (!PyArg_ParseTuple(args, "O&:exprdouble", short_string_converter, &s)) return NULL; CHECK_TCL_APPARTMENT; PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0) @@ -1808,7 +1888,7 @@ int retval; int v; - if (!PyArg_ParseTuple(args, "s:exprboolean", &s)) + if (!PyArg_ParseTuple(args, "O&:exprboolean", short_string_converter, &s)) return NULL; CHECK_TCL_APPARTMENT; ENTER_TCL @@ -2055,7 +2135,8 @@ PyObject *func; int err; - if (!PyArg_ParseTuple(args, "sO:createcommand", &cmdName, &func)) + if (!PyArg_ParseTuple(args, "O&O:createcommand", + short_string_converter, &cmdName, &func)) return NULL; if (!PyCallable_Check(func)) { PyErr_SetString(PyExc_TypeError, "command not callable"); @@ -2116,7 +2197,8 @@ char *cmdName; int err; - if (!PyArg_ParseTuple(args, "s:deletecommand", &cmdName)) + if (!PyArg_ParseTuple(args, "O&:deletecommand", + short_string_converter, &cmdName)) return NULL; #ifdef WITH_THREAD @@ -2784,10 +2866,12 @@ className = "Tk"; - if (!PyArg_ParseTuple(args, "|zssiiiiz:create", - &screenName, &baseName, &className, - &interactive, &wantobjects, &wantTk, - &sync, &use)) + if (!PyArg_ParseTuple(args, "|O&O&O&iiiiO&:create", + short_zstring_converter, &screenName, + short_string_converter, &baseName, + short_string_converter, &className, + &interactive, &wantobjects, &wantTk, &sync, + short_zstring_converter, &use)) return NULL; return (PyObject *) Tkapp_New(screenName, className,