diff -r 33a39dfc239e Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py Mon May 19 00:12:00 2014 -0400 +++ b/Lib/test/test_tcl.py Thu May 22 17:59:01 2014 +0300 @@ -127,6 +127,42 @@ 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(u' 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, 42L) + self.assertRaises(TypeError, tcl.getint, 42.0) + self.assertRaises(TclError, tcl.getint, 'a') + self.assertRaises((ValueError, TclError), tcl.getint, '42\0') + + 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(u'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, 42) + self.assertRaises(TclError, tcl.getdouble, 'a') + self.assertRaises((ValueError, TclError), tcl.getdouble, '42.5\0') + + def test_getboolean(self): + tcl = self.interp.tk + self.assertIs(tcl.getboolean('on'), True) + self.assertIs(tcl.getboolean(u'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, 1.0) + self.assertRaises(TclError, tcl.getboolean, 'a') + self.assertRaises((ValueError, TclError), tcl.getboolean, 'on\0') + def testEvalFile(self): tcl = self.interp filename = "testEvalFile.tcl" diff -r 33a39dfc239e Modules/_tkinter.c --- a/Modules/_tkinter.c Mon May 19 00:12:00 2014 -0400 +++ b/Modules/_tkinter.c Thu May 22 17:59:01 2014 +0300 @@ -1021,6 +1021,65 @@ 0, /*tp_is_gc*/ }; +static const char * +stringAsShortString(PyObject *arg) +{ + const char *s; + if (PyUnicode_Check(arg)) { + arg = _PyUnicode_AsDefaultEncodedString(arg, NULL); + if (arg == NULL) + return NULL; + } + if (PyString_Size(arg) > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "string is too long"); + return NULL; + } + s = PyString_AsString(arg); + if (strlen(s) != PyString_Size(arg)) { + 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 (PyString_Check(in) || PyUnicode_Check(in)) { + s = stringAsShortString(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 (PyString_Check(in) || PyUnicode_Check(in)) { + s = stringAsShortString(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) { @@ -1483,7 +1542,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; @@ -1529,7 +1588,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; @@ -1553,7 +1613,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; @@ -1574,7 +1634,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; @@ -1611,18 +1672,12 @@ static int varname_converter(PyObject *in, void *_out) { - char *s; - char **out = (char**)_out; - if (PyString_Check(in)) { - if (PyString_Size(in) > INT_MAX) { - PyErr_SetString(PyExc_OverflowError, "string is too long"); + const char *s; + const char **out = (const char**)_out; + if (PyString_Check(in) || PyUnicode_Check(in)) { + s = stringAsShortString(in); + if (s == NULL) return 0; - } - s = PyString_AsString(in); - if (strlen(s) != PyString_Size(in)) { - PyErr_SetString(PyExc_ValueError, "null character in string"); - return 0; - } *out = s; return 1; } @@ -1740,8 +1795,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); @@ -1784,8 +1840,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 @@ -1828,7 +1885,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 @@ -1863,61 +1922,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 (PyInt_Check(o)) { - Py_INCREF(o); - return o; - } + PyObject *arg; + + if (!PyArg_ParseTuple(args, "O:getint", &arg)) + return NULL; + if (PyInt_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 (PyString_Check(arg) || PyUnicode_Check(arg)) { + int intVal; + const char *s = stringAsShortString(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 (PyString_Check(arg) || PyUnicode_Check(arg)) { + double doubleVal; + const char *s = stringAsShortString(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 (PyInt_Check(o)) { - Py_INCREF(o); - return o; - } + PyObject *arg; + + if (!PyArg_ParseTuple(args, "O:getboolean", &arg)) + return NULL; + if (PyInt_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 (PyString_Check(arg) || PyUnicode_Check(arg)) { + int intVal; + const char *s = stringAsShortString(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 * @@ -1927,7 +2004,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; @@ -1951,7 +2028,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; @@ -1975,7 +2052,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) @@ -1999,7 +2076,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 @@ -2257,7 +2334,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"); @@ -2320,7 +2398,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 @@ -3125,10 +3204,12 @@ baseName = Py_GetProgramName(); 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, baseName, className,