~showard314/ubuntu/natty/qtiplot/Python2.7_fix

« back to all changes in this revision

Viewing changes to qtiplot/src/PythonScript.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Gudjon I. Gudjonsson
  • Date: 2007-03-25 12:06:27 UTC
  • Revision ID: james.westby@ubuntu.com-20070325120627-5pvdufddr7i0r74x
Tags: upstream-0.9~rc2
ImportĀ upstreamĀ versionĀ 0.9~rc2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
        File                 : PythonScript.cpp
 
3
        Project              : QtiPlot
 
4
--------------------------------------------------------------------
 
5
        Copyright            : (C) 2006 by Knut Franke
 
6
        Email (use @ for *)  : knut.franke*gmx.de
 
7
        Description          : Execute Python code from within QtiPlot
 
8
 
 
9
 ***************************************************************************/
 
10
 
 
11
/***************************************************************************
 
12
 *                                                                         *
 
13
 *  This program is free software; you can redistribute it and/or modify   *
 
14
 *  it under the terms of the GNU General Public License as published by   *
 
15
 *  the Free Software Foundation; either version 2 of the License, or      *
 
16
 *  (at your option) any later version.                                    *
 
17
 *                                                                         *
 
18
 *  This program is distributed in the hope that it will be useful,        *
 
19
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 
20
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 
21
 *  GNU General Public License for more details.                           *
 
22
 *                                                                         *
 
23
 *   You should have received a copy of the GNU General Public License     *
 
24
 *   along with this program; if not, write to the Free Software           *
 
25
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
 
26
 *   Boston, MA  02110-1301  USA                                           *
 
27
 *                                                                         *
 
28
 ***************************************************************************/
 
29
// get rid of a compiler warning
 
30
#ifdef _POSIX_C_SOURCE
 
31
#undef _POSIX_C_SOURCE
 
32
#endif
 
33
#include <Python.h>
 
34
 
 
35
#include "PythonScript.h"
 
36
#include "PythonScripting.h"
 
37
#include "ApplicationWindow.h"
 
38
 
 
39
#include <QObject>
 
40
#include <QVariant>
 
41
 
 
42
PythonScript::PythonScript(PythonScripting *env, const QString &code, QObject *context, const QString &name)
 
43
: Script(env, code, context, name)
 
44
{
 
45
        PyCode = NULL;
 
46
        localDict = PyDict_New();
 
47
        setQObject(Context, "self");
 
48
}
 
49
 
 
50
PythonScript::~PythonScript()
 
51
{
 
52
        Py_DECREF(localDict);
 
53
        Py_XDECREF(PyCode);
 
54
}
 
55
 
 
56
void PythonScript::setContext(QObject *context)
 
57
{
 
58
        Script::setContext(context);
 
59
        setQObject(Context, "self");
 
60
}
 
61
 
 
62
bool PythonScript::compile(bool for_eval)
 
63
{
 
64
        // Support for the convenient col() and cell() functions.
 
65
        // This can't be done anywhere else, because we need access to the local
 
66
        // variables self, i and j.
 
67
        if(Context->inherits("Table")) {
 
68
                // A bit of a hack, but we need either IndexError or len() from __builtins__.
 
69
                PyDict_SetItemString(localDict, "__builtins__",
 
70
                                PyDict_GetItemString(env()->globalDict(), "__builtins__"));
 
71
                PyObject *ret = PyRun_String(
 
72
                                "def col(c,*arg):\n"
 
73
                                "\ttry: return self.cell(c,arg[0])\n"
 
74
                                "\texcept(IndexError): return self.cell(c,i)\n"
 
75
                                "def cell(c,r):\n"
 
76
                                "\treturn self.cell(c,r)",
 
77
                                Py_file_input, localDict, localDict);
 
78
                if (ret)
 
79
                        Py_DECREF(ret);
 
80
                else
 
81
                        PyErr_Print();
 
82
        } else if(Context->inherits("Matrix")) {
 
83
                // A bit of a hack, but we need either IndexError or len() from __builtins__.
 
84
                PyDict_SetItemString(localDict, "__builtins__",
 
85
                                PyDict_GetItemString(env()->globalDict(), "__builtins__"));
 
86
                PyObject *ret = PyRun_String(
 
87
                                "def cell(*arg):\n"
 
88
                                "\ttry: return self.cell(arg[0],arg[1])\n"
 
89
                                "\texcept(IndexError): return self.cell(i,j)\n",
 
90
                                Py_file_input, localDict, localDict);
 
91
                if (ret)
 
92
                        Py_DECREF(ret);
 
93
                else
 
94
                        PyErr_Print();
 
95
        }
 
96
        bool success=false;
 
97
        Py_XDECREF(PyCode);
 
98
        // Simplest case: Code is a single expression
 
99
        PyCode = Py_CompileString(Code.ascii(), Name, Py_eval_input);
 
100
        if (PyCode) {
 
101
                success = true;
 
102
        } else if (for_eval) {
 
103
                // Code contains statements (or errors) and we want to get a return
 
104
                // value from it.
 
105
                // So we wrap the code into a function definition,
 
106
                // execute that (as Py_file_input) and store the function object in PyCode.
 
107
                // See http://mail.python.org/pipermail/python-list/2001-June/046940.html
 
108
                // for why there isn't an easier way to do this in Python.
 
109
                PyErr_Clear(); // silently ignore errors
 
110
                PyObject *key, *value;
 
111
#if PY_VERSION_HEX >= 0x02050000
 
112
                Py_ssize_t i=0;
 
113
#else
 
114
                int i=0;
 
115
#endif
 
116
                QString signature = "";
 
117
                while(PyDict_Next(localDict, &i, &key, &value))
 
118
                        signature.append(PyString_AsString(key)).append(",");
 
119
                signature.truncate(signature.length()-1);
 
120
                QString fdef = "def __doit__("+signature+"):\n";
 
121
                fdef.append(Code);
 
122
                fdef.replace('\n',"\n\t");
 
123
                PyCode = Py_CompileString(fdef, Name, Py_file_input);
 
124
                if (PyCode)
 
125
                {
 
126
                        PyObject *tmp = PyDict_New();
 
127
                        Py_XDECREF(PyEval_EvalCode((PyCodeObject*)PyCode, env()->globalDict(), tmp));
 
128
                        Py_DECREF(PyCode);
 
129
                        PyCode = PyDict_GetItemString(tmp,"__doit__");
 
130
                        Py_XINCREF(PyCode);
 
131
                        Py_DECREF(tmp);
 
132
                }
 
133
                success = PyCode != NULL;
 
134
        } else {
 
135
                // Code contains statements (or errors), but we do not need to get
 
136
                // a return value.
 
137
                PyErr_Clear(); // silently ignore errors
 
138
                PyCode = Py_CompileString(Code.ascii(), Name, Py_file_input);
 
139
                success = PyCode != NULL;
 
140
        }
 
141
        if (!success)
 
142
        {
 
143
                compiled = compileErr;
 
144
                emit_error(env()->errorMsg(), 0);
 
145
        } else
 
146
                compiled = isCompiled;
 
147
        return success;
 
148
}
 
149
 
 
150
QVariant PythonScript::eval()
 
151
{
 
152
        if (!isFunction) compiled = notCompiled;
 
153
        if (compiled != isCompiled && !compile(true))
 
154
                return QVariant();
 
155
        PyObject *pyret;
 
156
        beginStdoutRedirect();
 
157
        if (PyCallable_Check(PyCode))
 
158
        {
 
159
                PyObject *empty_tuple = PyTuple_New(0);
 
160
                pyret = PyObject_Call(PyCode, empty_tuple, localDict);
 
161
                Py_DECREF(empty_tuple);
 
162
        } else
 
163
                pyret = PyEval_EvalCode((PyCodeObject*)PyCode, env()->globalDict(), localDict);
 
164
        endStdoutRedirect();
 
165
        if (!pyret)
 
166
        {
 
167
                emit_error(env()->errorMsg(), 0);
 
168
                return QVariant();
 
169
        }
 
170
 
 
171
        QVariant qret = QVariant();
 
172
        /* None */
 
173
        if (pyret == Py_None)
 
174
                qret = QVariant("");
 
175
        /* numeric types */
 
176
        else if (PyFloat_Check(pyret))
 
177
                qret = QVariant(PyFloat_AS_DOUBLE(pyret));
 
178
        else if (PyInt_Check(pyret))
 
179
                qret = QVariant((qlonglong)PyInt_AS_LONG(pyret));
 
180
        else if (PyLong_Check(pyret))
 
181
                qret = QVariant((qlonglong)PyLong_AsLongLong(pyret));
 
182
        else if (PyNumber_Check(pyret))
 
183
        {
 
184
                PyObject *number = PyNumber_Float(pyret);
 
185
                if (number)
 
186
                {
 
187
                        qret = QVariant(PyFloat_AS_DOUBLE(number));
 
188
                        Py_DECREF(number);
 
189
                }
 
190
                /* bool */
 
191
        } else if (PyBool_Check(pyret))
 
192
                qret = QVariant(pyret==Py_True, 0);
 
193
        // could handle advanced types (such as PyList->QValueList) here if needed
 
194
        /* fallback: try to convert to (unicode) string */
 
195
        if(!qret.isValid()) {
 
196
                PyObject *pystring = PyObject_Unicode(pyret);
 
197
                if (pystring) {
 
198
                        PyObject *asUTF8 = PyUnicode_EncodeUTF8(PyUnicode_AS_UNICODE(pystring), PyUnicode_GET_DATA_SIZE(pystring), 0);
 
199
                        Py_DECREF(pystring);
 
200
                        if (asUTF8) {
 
201
                                qret = QVariant(QString::fromUtf8(PyString_AS_STRING(asUTF8)));
 
202
                                Py_DECREF(asUTF8);
 
203
                        } else if (pystring = PyObject_Str(pyret)) {
 
204
                                qret = QVariant(QString(PyString_AS_STRING(pystring)));
 
205
                                Py_DECREF(pystring);
 
206
                        }
 
207
                }
 
208
        }
 
209
 
 
210
        Py_DECREF(pyret);
 
211
        if (PyErr_Occurred()) {
 
212
                emit_error(env()->errorMsg(), 0);
 
213
                return QVariant();
 
214
        } else
 
215
                return qret;
 
216
}
 
217
 
 
218
bool PythonScript::exec()
 
219
{
 
220
        if (isFunction) compiled = notCompiled;
 
221
        if (compiled != Script::isCompiled && !compile(false))
 
222
                return false;
 
223
        PyObject *pyret;
 
224
        beginStdoutRedirect();
 
225
        if (PyCallable_Check(PyCode))
 
226
        {
 
227
                PyObject *empty_tuple = PyTuple_New(0);
 
228
                if (!empty_tuple) {
 
229
                        emit_error(env()->errorMsg(), 0);
 
230
                        return false;
 
231
                }
 
232
                pyret = PyObject_Call(PyCode,empty_tuple,localDict);
 
233
                Py_DECREF(empty_tuple);
 
234
        } else
 
235
                pyret = PyEval_EvalCode((PyCodeObject*)PyCode, env()->globalDict(), localDict);
 
236
        endStdoutRedirect();
 
237
        if (pyret) {
 
238
                Py_DECREF(pyret);
 
239
                return true;
 
240
        }
 
241
        emit_error(env()->errorMsg(), 0);
 
242
        return false;
 
243
}
 
244
 
 
245
void PythonScript::beginStdoutRedirect()
 
246
{
 
247
        stdoutSave = PyDict_GetItemString(env()->sysDict(), "stdout");
 
248
        Py_XINCREF(stdoutSave);
 
249
        stderrSave = PyDict_GetItemString(env()->sysDict(), "stderr");
 
250
        Py_XINCREF(stderrSave);
 
251
        env()->setQObject(this, "stdout", env()->sysDict());
 
252
        env()->setQObject(this, "stderr", env()->sysDict());
 
253
}
 
254
 
 
255
void PythonScript::endStdoutRedirect()
 
256
{
 
257
        PyDict_SetItemString(env()->sysDict(), "stdout", stdoutSave);
 
258
        Py_XDECREF(stdoutSave);
 
259
        PyDict_SetItemString(env()->sysDict(), "stderr", stderrSave);
 
260
        Py_XDECREF(stderrSave);
 
261
}
 
262
 
 
263
bool PythonScript::setQObject(QObject *val, const char *name)
 
264
{
 
265
        if (!PyDict_Contains(localDict, PyString_FromString(name)))
 
266
                compiled = notCompiled;
 
267
        return env()->setQObject(val, name, localDict);
 
268
}
 
269
 
 
270
bool PythonScript::setInt(int val, const char *name)
 
271
{
 
272
        if (!PyDict_Contains(localDict, PyString_FromString(name)))
 
273
                compiled = notCompiled;
 
274
        return env()->setInt(val, name, localDict);
 
275
}
 
276
 
 
277
bool PythonScript::setDouble(double val, const char *name)
 
278
{
 
279
        if (!PyDict_Contains(localDict, PyString_FromString(name)))
 
280
                compiled = notCompiled;
 
281
        return env()->setDouble(val, name, localDict);
 
282
}
 
283