[despammed] Re: redirect sys.stdout to C++ ?
Bengt Richter
bokr at oz.net
Sun Dec 29 06:09:25 EST 2002
On Sat, 28 Dec 2002 19:43:21 +0100, =?ISO-8859-1?Q?Andr=E9_Jonsson?= <tatsujin at despammed.com> wrote:
>Bengt Richter wrote:
>
>>>I should probably make clear that I don't use an actual "interactive shell", I just
>>>feed an entered string into the PyRun_SimpleString() API call, thus the normal
>> ^^^^^^^^^^^^^^ entered where & how? If it is in the same interpreter,
>> perhaps a similar thing could happen.
>>
>> Need more context to understand your problem. Can you reduce it to a minimal example
>> showing how "entered strings" are entered and wind up being passed to PyRunSimpleString()?
>
>Ok, I'm developing this C++ application that embeds Python. In this application there
^^^^^^^^^^^^^^^-- do you refer to this C++ every time you say
"application" below?
>is a prompt, completely self-made, that is meant to accept one-liners of Python
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
?? printf("Enter one-liner: "); fgets(line, 128, stdin); // or such ??
>"code" as input. The strings input there are passed directly to PyRun_SimpleString().
>
>To this embedded Python interpreter I've also added a module of my own that makes
^^^^^^^^^^^^^^^^^^ written in C++ or Python?
I'm guessing python.
>calls to some static functions in the application. One of these are a logging
^-C++?
>facility (or merely a 'print'-command inside my application).
^-sounds like python. ^-C++??
>
>Now, the thing is that I want all stdout/err output from any script that is run by
>the python interpreter, including -but not limited to- the prompt, to be output
If you are using printf/fgets, those are determining the prompt/input line, so I assume
you will have to log those from C++ before calling PyRun_SimpleString.
>through the logging-function in the imported module (python code can also be executed
>from anywhere inside the application code (using PyRun_SimpleString()). To accomplish
^--this must be C++ ;-)
>this I've made a redirection of sys.stdout and sys.stderr to call my own callback on
^-C++?
>any output to make the output visible inside my application.
^--C++?h
>
>Without this all output from the code the interpreter runs will be output to the
>application's stdout, which is of course not what I want.
>
>Maybe that clears it up... Thanks for trying to help!
>
Yes, though I forgot to ask what platform & what version of Python. Going by your
header, it would be some Linux variant and Python version.
The following is on NT3 with Python 2.2.2 and MSVC++6.0, guessing what you've done:
====< andrejonsson.c >==============================================================
/* andrejonsson.c */
#include <stdio.h>
#include <Python.h>
#include <string.h>
FILE * logfile = NULL;
int
logwrite(char* tag, char* line){
int ntag, nline;
if (logfile==NULL) return 0;
ntag = strlen(tag); nline = strlen(line);
if (ntag != fwrite(tag, 1, ntag, logfile) ||
2 != fwrite(": ", 1, 2, logfile) ||
nline != fwrite(line, 1, nline, logfile)
){
return 1; /*error*/
}
fflush(logfile);
return 0;
}
static PyObject *
andre_log(PyObject *self, PyObject *args)
{
char *s_tag, *s_line;
int n_tag, n_line, err;
if (!PyArg_ParseTuple(args, "ss:andrelog", &s_tag, &s_line))
return NULL;
Py_BEGIN_ALLOW_THREADS
err = logwrite(s_tag, s_line);
Py_END_ALLOW_THREADS
if (err) {
PyErr_SetFromErrno(PyExc_IOError);
clearerr(logfile);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyMethodDef andreMethods[] = {
{"andre_log", (PyCFunction)andre_log, METH_VARARGS,
"andre_log(tag, line) writes same to log file if specified as -log lfile"},
{NULL, NULL, 0, NULL}
};
int
main(int argc, char *argv[])
{
char *prompt = "Enter Python line: ";
char line[128];
if (argc>2 && !strcmp(argv[1],"-log")){
if (!strcmp(argv[2], "stdout")){
logfile = stdout;
} else if (!strcmp(argv[2], "stderr")){
logfile = stderr;
} else {
logfile = fopen(argv[2],"a");
}
}
Py_Initialize();
Py_InitModule("andreApp", andreMethods);
for (line[0]='\0'; strcmp(line,"q\n");){
printf(prompt);
if (fgets(line, 128, stdin) == NULL){
printf( "fgets error\n" );
break;
} else {
logwrite("prompt",prompt); logwrite("entered",line);
if(!strcmp(line,"q\n")) break;
PyRun_SimpleString(line);
}
}
Py_Finalize();
if (logfile) fclose(logfile);
return 0;
}
====================================================================================
compiled thus:
--
[ 2:40] C:\pywk\embed>cl -ID:\Python22\include andrejonsson.c -link /LIBPATH:D:\Python22\libs
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.
andrejonsson.c
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
/out:andrejonsson.exe
/LIBPATH:D:\Python22\libs
andrejonsson.obj
--
The above program prompts "on its own" and reads a line, and feeds it to
PyRun_SimpleString as I think you meant.
It also accepts a log file as a command line argument after -log, and it
presents an importable module interface called andreApp, which has a andre_log method
that takes two string args (a prefix and data).
You said there was a separate module (I thought python) which did overriding of stdout
and stderr. I modified your code a tiny bit and called it redirect.py:
====< redirect.py >==================================================================
# redirect.py
import andreApp # a module interface created by C application
class Logger:
def __init__(self, source):
self.source=source
self.buf = []
def write(self, data):
self.buf.append(data)
if data.endswith('\n'):
andreApp.andre_log(self.source, ''.join(self.buf))
self.buf = []
import sys
sys.stdout = Logger('stdout')
sys.stderr = Logger('stderr')
=====================================================================================
This just does the redirection on import. Not nicely reversible or anything, but this
is just test stuff.
Ok, now we will run andrejonsson.exe:
--
[ 2:57] C:\pywk\embed>dir log.txt
Volume in drive C is System
Volume Serial Number is 14CF-C4B9
Directory of C:\pywk\embed
File Not Found
[ 2:58] C:\pywk\embed>andrejonsson -log log.txt
Enter Python line: import andreApp
Enter Python line: import redirect
Enter Python line: print dir()
Enter Python line: 1/0
Enter Python line: import sys
Enter Python line: print sys.modules.keys()
Enter Python line: for k,v in sys.modules.items(): print '%15s %s' %(k,v)
Enter Python line: '----------------------------------'
Enter Python line: andreApp.andre_log('prefix', 'message fragment w/o newline, ')
Enter Python line: andreApp.andre_log('prefix', 'and same prefix with newline.\n')
Enter Python line: print 'should be stdout'
Enter Python line: print >> sys.stderr, 'should be stderr'
Enter Python line: print >> sys.stdout, 'should be stdout again'
Enter Python line: raise ValueError, 'A value error message'
Enter Python line: print '1'
Enter Python line: print '1'
Enter Python line: q
--
And the resulting log.txt was:
--
prompt: Enter Python line: entered: import andreApp
prompt: Enter Python line: entered: import redirect
prompt: Enter Python line: entered: print dir()
stdout: ['__builtins__', '__doc__', '__name__', 'andreApp', 'redirect']
prompt: Enter Python line: entered: 1/0
stderr: Traceback (most recent call last):
stderr: File "<string>", line 1, in ?
stderr: ZeroDivisionError: integer division or modulo by zero
prompt: Enter Python line: entered: import sys
prompt: Enter Python line: entered: print sys.modules.keys()
stdout: ['redirect', 'stat', '__future__', 'copy_reg', 'os', 'signal', 'site', '__builtin__', 'UserDict', 'sys', 'ntpath', 'andreApp', '__main__', 'exceptions', 'types', 'nt', 'os.path']
prompt: Enter Python line: entered: for k,v in sys.modules.items(): print '%15s %s' %(k,v)
stdout: redirect <module 'redirect' from 'C:\pywk\embed\redirect.pyc'>
stdout: stat <module 'stat' from 'D:\Python22\Lib\stat.pyc'>
stdout: __future__ <module '__future__' from 'D:\Python22\Lib\__future__.pyc'>
stdout: copy_reg <module 'copy_reg' from 'D:\Python22\Lib\copy_reg.pyc'>
stdout: os <module 'os' from 'D:\Python22\Lib\os.pyc'>
stdout: signal <module 'signal' (built-in)>
stdout: site <module 'site' from 'D:\Python22\Lib\site.pyc'>
stdout: __builtin__ <module '__builtin__' (built-in)>
stdout: UserDict <module 'UserDict' from 'D:\Python22\Lib\UserDict.pyc'>
stdout: sys <module 'sys' (built-in)>
stdout: ntpath <module 'ntpath' from 'D:\Python22\Lib\ntpath.pyc'>
stdout: andreApp <module 'andreApp' (built-in)>
stdout: __main__ <module '__main__' (built-in)>
stdout: exceptions <module 'exceptions' (built-in)>
stdout: types <module 'types' from 'D:\Python22\Lib\types.pyc'>
stdout: nt <module 'nt' (built-in)>
stdout: os.path <module 'ntpath' from 'D:\Python22\Lib\ntpath.pyc'>
prompt: Enter Python line: entered: '----------------------------------'
prompt: Enter Python line: entered: andreApp.andre_log('prefix', 'message fragment w/o newline, ')
prefix: message fragment w/o newline, prompt: Enter Python line: entered: andreApp.andre_log('prefix', 'and same prefix with newline.\n')
prefix: and same prefix with newline.
prompt: Enter Python line: entered: print 'should be stdout'
stdout: should be stdout
prompt: Enter Python line: entered: print >> sys.stderr, 'should be stderr'
stderr: should be stderr
prompt: Enter Python line: entered: print >> sys.stdout, 'should be stdout again'
stdout: should be stdout again
prompt: Enter Python line: entered: raise ValueError, 'A value error message'
stderr: Traceback (most recent call last):
stderr: File "<string>", line 1, in ?
stderr: ValueError: A value error message
prompt: Enter Python line: entered: print '1'
stdout: 1
prompt: Enter Python line: entered: print '1'
stdout: 1
prompt: Enter Python line: entered: q
--
It seems to be working. So what did I do differently from what you did?
Maybe the fflush in logwrite?
Regards,
Bengt Richter
More information about the Python-list
mailing list