lib

pythoninterpreter.cpp

00001 /***************************************************************************
00002  * pythoninterpreter.cpp
00003  * This file is part of the KDE project
00004  * copyright (C)2004-2005 by Sebastian Sauer (mail@dipe.org)
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Library General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2 of the License, or (at your option) any later version.
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  * You should have received a copy of the GNU Library General Public License
00015  * along with this program; see the file COPYING.  If not, write to
00016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018  ***************************************************************************/
00019 
00020 #include "pythoninterpreter.h"
00021 #include "pythonscript.h"
00022 #include "pythonmodule.h"
00023 #include "pythonsecurity.h"
00024 //#include "pythonextension.h"
00025 #include "../api/variant.h"
00026 
00027 #include <kglobal.h>
00028 #include <kstandarddirs.h>
00029 
00030 #if defined(Q_WS_WIN)
00031   #define PYPATHDELIMITER ";"
00032 #else
00033   #define PYPATHDELIMITER ":"
00034 #endif
00035 
00036 extern "C"
00037 {
00047     void* krossinterpreter(Kross::Api::InterpreterInfo* info)
00048     {
00049         try {
00050             return new Kross::Python::PythonInterpreter(info);
00051         }
00052         catch(Kross::Api::Exception::Ptr e) {
00053             Kross::krosswarning("krossinterpreter(Kross::Api::InterpreterInfo* info): Unhandled exception.");
00054         }
00055         return 0;
00056     }
00057 }
00058 
00059 using namespace Kross::Python;
00060 
00061 namespace Kross { namespace Python {
00062 
00064     class PythonInterpreterPrivate
00065     {
00066         public:
00067 
00069             PythonModule* mainmodule;
00070 
00072             PythonSecurity* security;
00073     };
00074 
00075 }}
00076 
00077 PythonInterpreter::PythonInterpreter(Kross::Api::InterpreterInfo* info)
00078     : Kross::Api::Interpreter(info)
00079     , d(new PythonInterpreterPrivate())
00080 {
00081     // Initialize the python interpreter.
00082     initialize();
00083 
00084     // Set name of the program.
00085     Py_SetProgramName(const_cast<char*>("Kross"));
00086 
00087     /*
00088     // Set arguments.
00089     //char* comm[0];
00090     const char* comm = const_cast<char*>("kross"); // name.
00091     PySys_SetArgv(1, comm);
00092     */
00093 
00094     // In the python sys.path are all module-directories are
00095     // listed in.
00096     QString path;
00097 
00098     // First import the sys-module to remember it's sys.path
00099     // list in our path QString.
00100     Py::Module sysmod( PyImport_ImportModule("sys"), true );
00101     Py::Dict sysmoddict = sysmod.getDict();
00102     Py::Object syspath = sysmoddict.getItem("path");
00103     if(syspath.isList()) {
00104         Py::List syspathlist = syspath;
00105         for(Py::List::iterator it = syspathlist.begin(); it != syspathlist.end(); ++it)
00106             if( (*it).isString() )
00107                 path.append( QString(Py::String(*it).as_string().c_str()) + PYPATHDELIMITER );
00108     }
00109     else
00110         path = Py_GetPath();
00111 
00112     // Determinate additional module-paths we like to add.
00113     // First add the global Kross modules-path.
00114     QStringList krossdirs = KGlobal::dirs()->findDirs("data", "kross/python");
00115     for(QStringList::Iterator krossit = krossdirs.begin(); krossit != krossdirs.end(); ++krossit)
00116         path.append(*krossit + PYPATHDELIMITER);
00117     // Then add the application modules-path.
00118     QStringList appdirs = KGlobal::dirs()->findDirs("appdata", "kross/python");
00119     for(QStringList::Iterator appit = appdirs.begin(); appit != appdirs.end(); ++appit)
00120         path.append(*appit + PYPATHDELIMITER);
00121 
00122     // Set the extended sys.path.
00123     PySys_SetPath( (char*) path.latin1() );
00124 
00125     krossdebug(QString("Python ProgramName: %1").arg(Py_GetProgramName()));
00126     krossdebug(QString("Python ProgramFullPath: %1").arg(Py_GetProgramFullPath()));
00127     krossdebug(QString("Python Version: %1").arg(Py_GetVersion()));
00128     krossdebug(QString("Python Platform: %1").arg(Py_GetPlatform()));
00129     krossdebug(QString("Python Prefix: %1").arg(Py_GetPrefix()));
00130     krossdebug(QString("Python ExecPrefix: %1").arg(Py_GetExecPrefix()));
00131     krossdebug(QString("Python Path: %1").arg(Py_GetPath()));
00132     krossdebug(QString("Python System Path: %1").arg(path));
00133 
00134     // Initialize the main module.
00135     d->mainmodule = new PythonModule(this);
00136 
00137     // The main dictonary.
00138     Py::Dict moduledict = d->mainmodule->getDict();
00139     //TODO moduledict["KrossPythonVersion"] = Py::Int(KROSS_PYTHON_VERSION);
00140 
00141     // Prepare the interpreter.
00142     QString s =
00143         "import sys\n"
00144         //"sys.setdefaultencoding('latin-1')\n"
00145 
00146         // Dirty hack to get sys.argv defined. Needed for e.g. TKinter.
00147         "sys.argv = ['']\n"
00148 
00149         // On the try to read something from stdin always return an empty
00150         // string. That way such reads don't block our script.
00151         "import cStringIO\n"
00152         "sys.stdin = cStringIO.StringIO()\n"
00153 
00154         // Class to redirect something. We use this class e.g. to redirect
00155         // <stdout> and <stderr> to a c++ event.
00156         "class Redirect:\n"
00157         "  def __init__(self, target):\n"
00158         "    self.target = target\n"
00159         "  def write(self, s):\n"
00160         "    self.target.call(s)\n"
00161 
00162         // Wrap builtin __import__ method. All import requests are
00163         // first redirected to our PythonModule.import method and
00164         // if the call returns None, then we call the original
00165         // python import mechanism.
00166         "import __builtin__\n"
00167         "import __main__\n"
00168         "class Importer:\n"
00169         "    def __init__(self):\n"
00170         "        self.realImporter = __builtin__.__import__\n"
00171         "        __builtin__.__import__ = self._import\n"
00172         "    def _import(self, name, globals=None, locals=None, fromlist=[]):\n"
00173         "        mod = __main__._import(name, globals, locals, fromlist)\n"
00174         "        if mod != None: return mod\n"
00175         "        return self.realImporter(name, globals, locals, fromlist)\n"
00176         "Importer()\n"
00177         ;
00178 
00179     PyObject* pyrun = PyRun_String(s.latin1(), Py_file_input, moduledict.ptr(), moduledict.ptr());
00180     if(! pyrun) {
00181         Py::Object errobj = Py::value(Py::Exception()); // get last error
00182         throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(QString("Failed to prepare the __main__ module: %1").arg(errobj.as_string().c_str())) );
00183     }
00184     Py_XDECREF(pyrun); // free the reference.
00185 
00186     // Initialize the RestrictedPython module.
00187     d->security = new PythonSecurity(this);
00188 }
00189 
00190 PythonInterpreter::~PythonInterpreter()
00191 {
00192     // Free the zope security module.
00193     delete d->security; d->security = 0;
00194     // Free the main module.
00195     delete d->mainmodule; d->mainmodule = 0;
00196     // Finalize the python interpreter.
00197     finalize();
00198     // Delete the private d-pointer.
00199     delete d;
00200 }
00201 
00202 void PythonInterpreter::initialize()
00203 {
00204     // Initialize python.
00205     Py_Initialize();
00206 
00207     /* Not needed cause we use the >= Python 2.3 GIL-mechanism.
00208     PyThreadState* d->globalthreadstate, d->threadstate;
00209     // First we have to initialize threading if python supports it.
00210     PyEval_InitThreads();
00211     // The main thread. We don't use it later.
00212     d->globalthreadstate = PyThreadState_Swap(NULL);
00213     d->globalthreadstate = PyEval_SaveThread();
00214     // We use an own sub-interpreter for each thread.
00215     d->threadstate = Py_NewInterpreter();
00216     // Note that this application has multiple threads.
00217     // It maintains a separate interp (sub-interpreter) for each thread.
00218     PyThreadState_Swap(d->threadstate);
00219     // Work done, release the lock.
00220     PyEval_ReleaseLock();
00221     */
00222 }
00223 
00224 void PythonInterpreter::finalize()
00225 {
00226     /* Not needed cause we use the >= Python 2.3 GIL-mechanism.
00227     // Lock threads.
00228     PyEval_AcquireLock();
00229     // Free the used thread.
00230     PyEval_ReleaseThread(d->threadstate);
00231     // Set back to rememberd main thread.
00232     PyThreadState_Swap(d->globalthreadstate);
00233     // Work done, unlock.
00234     PyEval_ReleaseLock();
00235     */
00236 
00237     // Finalize python.
00238     Py_Finalize();
00239 }
00240 
00241 Kross::Api::Script* PythonInterpreter::createScript(Kross::Api::ScriptContainer* scriptcontainer)
00242 {
00243     return new PythonScript(this, scriptcontainer);
00244 }
00245 
00246 PythonModule* PythonInterpreter::mainModule()
00247 {
00248     return d->mainmodule;
00249 }
00250 
00251 PythonSecurity* PythonInterpreter::securityModule()
00252 {
00253     return d->security;
00254 }
00255 
KDE Home | KDE Accessibility Home | Description of Access Keys