OT : Python embedding in wxWindows C++ (w/ hint for your Ctrl-C problem)

I'm testing to see if it's possible to embed python in a wxWindows c++ program as a simple interpreter. The interpreter will have a *very* simple idle like interface and I will add functions to hook in the c++ data structures. But, alas I have some problems and questions and after digging through python/wxPython/(anything I could find including both python and this newgroup) I can't find suitable answers.

1) I need to redirect stdout, stderr, and stdin. stdout/err are easy to do and I create events. The stdin, seems far more tricky. In fact I don't believe that wxPython does this? PyCrust does it on a python level, but don't you need to do it at the c++ level too?

The Ctrl-C problem that people have mentioned is probably because you don't call PyOS_FiniInterrupts() which stops python from "stealing" stdin. I'm guessing what happens is that ctrl-c kills the python interpreter and then your wxPython app crashes the next time it tries to use it.

Here is some simple code to redirect the stdio and setup python to use these instead, "wxstdio" uses the function below this python code (the stdout function is not shown).

PyRun_SimpleString("import wxstdio\n"
                    "sys.oldstdin = sys.stdin\n"
                    "sys.oldstdout = sys.stdout\n"
                    "sys.oldstderr = sys.stderr\n"

                    "class StdioRedir:\n"
                    " def write(self, text):\n"
                    " wxstdio.stdout(text)\n"
                    " def write(self, s, tags=(), mark='insert'):\n"
                    " wxstdio.stdout(s)\n"
                    " def writelines(self, l):\n"
                    " map(self.write, l)\n"
                    " def read(self, length = None):\n"
                    " return wxstdio.stdin()\n"
                    " def readline(self, length = None):\n"
                    " return wxstdio.stdin()\n"
                    " def readlines(self, length = None):\n"
                    " return wxstdio.stdin()\n"
                    " def __del__(self):\n" // restore stdio
                    " sys.stdin = sys.oldstdin\n"
                    " sys.stdout = sys.oldstdout\n"
                    " sys.stderr = sys.oldstderr\n"

                    // redirect stdio to the class
                    "sys.stdin = StdioRedir()\n"
                    "sys.stdout = StdioRedir()\n"
                    "sys.stderr = StdioRedir()\n");

This is my c function for stdin, I know it's nonsense, but what can I do? I'd like to send it real keycodes, for example ctrl-c and stuff mapped from a textctrl's OnChar...

static PyObject *pyStdin(PyObject *WXUNUSED(self), PyObject* args)
{
     //printf("My stdin!!!\n"); fflush(stdout);
     wxString msg;
     // this merely searches for an instance of the wxPythonInterpreter class that has a matching PyThreadState

     wxPythonInterpreter *pI = wxPythonInterpreter::FindInterpreter(PyThreadState_Get());
     if (pI)
     {
         // m_stdinString gets filled from a textctrl
         msg = pI->m_stdinString;
         pI->m_stdinString.Clear();
     }

     return PyString_FromString(msg.c_str());
}

ps. the embedded.cpp sample should proabably have
"sys.stdout = sys.stderr = output\n\"
instead of
"sys.stdin = sys.stderr = output\n\"

2) Lets say someone types while(1) : print "hi". I need to stop that gracefully, but I don't see anyway to get a hook into python. Some languages have methods to pause/break the interpreter and the also have callbacks that can be setup to be called every n number of instructions. This would be useful since I'd like to run python in a wxThread and I need to check TestDestroy(). Python doesn't seem to have either of these unless I'm mistaken. This seems like a serious problem since it would be easy enough to "take out" a program with a trivial mistake in a python script. You can try that code in PyCrust and after a few seconds it segfaults. The segfault I assume is from the textctrl overflowing (which is easy to solve), but before that happens you cannot stop it.

Anyway, maybe I'm neurotic since nobody else (code from python newsgroups and others) seems to care about runaway python programs embedded into a c program.

I would appreciate any insight, Thanks.
John Labenski

John Labenski wrote:

The Ctrl-C problem that people have mentioned is probably because you don't call PyOS_FiniInterrupts() which stops python from "stealing" stdin.

Yes that does seem to help, but it has nothing to do with stdin. It just restores any signal handlers that Python may have hooked, such as the SIGINT in the case of Ctrl-C/

This is my c function for stdin, I know it's nonsense, but what can I do? I'd like to send it real keycodes, for example ctrl-c and stuff mapped from a textctrl's OnChar...

sys.stdin has nothing to do with raw keycodes. It is simply a file object that returns some characters when it's read method is called. It just happens that the default stdin file is hooked to the consol and so when you type the characters are fed from the console to the app's stdin file. (More or less...)

One way to do it is to have the characters from the textctrl pushed into a buffer object, and then the object you create to replace sys.stdin should just pull from that buffer when the read method is called.

2) Lets say someone types while(1) : print "hi". I need to stop that gracefully, but I don't see anyway to get a hook into python. Some languages have methods to pause/break the interpreter and the also have callbacks that can be setup to be called every n number of instructions. This would be useful since I'd like to run python in a wxThread and I need to check TestDestroy(). Python doesn't seem to have either of these unless I'm mistaken.

See the docs for sys.settrace. I don't think we've got it PyCrust yet although Patrick was working on it a couple weeks ago. Maybe he can chime in here and let us know what he figured out.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!