Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

embedding interactive python interpreter

170 views
Skip to first unread message

Eric Frederich

unread,
Mar 25, 2011, 12:02:16 PM3/25/11
to pytho...@python.org
I am able to embed the interactive Python interpreter in my C program
except that when the interpreter exits, my entire program exits.

#include <stdio.h>
#include <Python.h>

int main(int argc, char *argv[]){
printf("line %d\n", __LINE__);
Py_Initialize();
printf("line %d\n", __LINE__);
Py_Main(argc, argv);
printf("line %d\n", __LINE__);
Py_Finalize();
printf("line %d\n", __LINE__);
return 0;
}

When I run the resulting binary I get the following....

$ ./embedded_python
line 5
line 7
Python 2.7.1 (r271:86832, Mar 25 2011, 11:56:07)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print 'hi'
hi
>>> exit()


I never see line 9 or 11 printed.
I need to embed python in an application that needs to do some cleanup
at the end so I need that code to execute.
What am I doing wrong?

Is there something else I should call besides "exit()" from within the
interpreter?
Is there something other than Py_Main that I should be calling?

Thanks,
~Eric

Eric Frederich

unread,
Mar 25, 2011, 1:37:27 PM3/25/11
to pytho...@python.org
So.... I found that if I type ctrl-d then the other lines will print.

It must be a bug then that the exit() function doesn't do the same thing.
The documentation says "The return value will be the integer passed to
the sys.exit() function" but clearly nothing is returned since the
call to Py_Main exits rather than returning (even when calling
sys.exit instead of just exit).

In the mean time is there a way to redefine the exit function in
Python to do the same behavior as "ctrl-d?"
I realize that in doing that (if its even possible) still won't
provide a way to pass a value back from the interpreter via sys.exit.

Thanks,
~Eric

MRAB

unread,
Mar 25, 2011, 1:47:02 PM3/25/11
to pytho...@python.org
On 25/03/2011 17:37, Eric Frederich wrote:
> So.... I found that if I type ctrl-d then the other lines will print.
>
> It must be a bug then that the exit() function doesn't do the same thing.
> The documentation says "The return value will be the integer passed to
> the sys.exit() function" but clearly nothing is returned since the
> call to Py_Main exits rather than returning (even when calling
> sys.exit instead of just exit).
>
> In the mean time is there a way to redefine the exit function in
> Python to do the same behavior as "ctrl-d?"
> I realize that in doing that (if its even possible) still won't
> provide a way to pass a value back from the interpreter via sys.exit.
>
You could flush stdout after each print or turn off buffering on stdout
with:

setvbuf(stdout, NULL, _IONBF, 0);

Eric Frederich

unread,
Mar 25, 2011, 2:22:12 PM3/25/11
to pytho...@python.org
Added a fflush(stdout) after each printf and, as I expected....still
only the first 2 prints.

> --
> http://mail.python.org/mailman/listinfo/python-list
>

Mark Hammond

unread,
Mar 27, 2011, 3:10:47 AM3/27/11
to Eric Frederich, pytho...@python.org
On 26/03/2011 4:37 AM, Eric Frederich wrote:
> So.... I found that if I type ctrl-d then the other lines will print.

I think ctrl-d just causes sys.stdin to see EOF, so things just "fall
out" as you desire. exit() will winf up causing the C exit() function
after finalizing, hence the behaviour you see.

> In the mean time is there a way to redefine the exit function in
> Python to do the same behavior as "ctrl-d?"

You can just patch exit in builtins with your own function although I'm
not sure how you would terminate the builtin REPL - another alternative
may be to look into the code/console modules where you may be able to
arrange for more control over the REPL.

Cheers,

Mark

Eric Frederich

unread,
Mar 27, 2011, 9:33:00 AM3/27/11
to Mark Hammond, pytho...@python.org
This is behavior contradicts the documentation which says the value
passed to sys.exit will be returned from Py_Main.
Py_Main doesn't return anything, it just exits.
This is a bug.

Jerry Hill

unread,
Mar 27, 2011, 1:55:23 PM3/27/11
to pytho...@python.org
On Sun, Mar 27, 2011 at 9:33 AM, Eric Frederich
<eric.fr...@gmail.com> wrote:
> This is behavior contradicts the documentation which says the value
> passed to sys.exit will be returned from Py_Main.
> Py_Main doesn't return anything, it just exits.
> This is a bug.

Are you sure that calling the builtin exit() function is the same as
calling sys.exit()?

You keep talking about the documentation for sys.exit(), but that's
not the function you're calling. I played around in the interactive
interpreter a bit, and the two functions do seem to behave a bit
differently from each other. I can't seem to find any detailed
documentation for the builtin exit() function though, so I'm not sure
exactly what the differences are.

A little more digging reveals that the builtin exit() function is
getting set up by site.py, and it does more than sys.exit() does.
Particularly, in 3.1 it tries to close stdin then raises SystemExit().
Does that maybe explain the behavior you're seeing? I didn't go
digging in 2.7, which appears to be what you're using, but I think you
need to explore the differences between sys.exit() and the builtin
exit() functions.

--
Jerry

Message has been deleted

Eric Frederich

unread,
Mar 27, 2011, 2:28:13 PM3/27/11
to Jerry Hill, pytho...@python.org
I'm not talking about the documentation for sys.exit()
I'm talking about the documentation for Py_Main(int argc, char **argv)

http://docs.python.org/c-api/veryhigh.html?highlight=py_main#Py_Main

This C function never returns anything whether in the interpreter I
type "exit(123)" or "sys.exit(123)".
I cannot call any of my C cleanup code because of this.

> --
> http://mail.python.org/mailman/listinfo/python-list
>

eryksun ()

unread,
Mar 27, 2011, 5:59:42 PM3/27/11
to pytho...@python.org, Eric Frederich
On Friday, March 25, 2011 12:02:16 PM UTC-4, Eric Frederich wrote:
>
> Is there something else I should call besides "exit()" from within the
> interpreter?
> Is there something other than Py_Main that I should be calling?

Does PyRun_InteractiveLoop also have this problem?

Message has been deleted
Message has been deleted

Mark Hammond

unread,
Mar 27, 2011, 6:21:27 PM3/27/11
to Eric Frederich, pytho...@python.org
On 28/03/2011 5:28 AM, Eric Frederich wrote:
> I'm not talking about the documentation for sys.exit()
> I'm talking about the documentation for Py_Main(int argc, char **argv)
>
> http://docs.python.org/c-api/veryhigh.html?highlight=py_main#Py_Main
>
> This C function never returns anything whether in the interpreter I
> type "exit(123)" or "sys.exit(123)".
> I cannot call any of my C cleanup code because of this.

I think there is a bug in that documentation - the paragraph:

Note that if an otherwise unhandled SystemError is raised, this
function will not return 1, but exit the process, as long as
Py_InspectFlag is not set.

Looks like it should refer to SystemExit, not SystemError. If you check
out pythonrun.c in handle_system_exit, you will note the behaviour
described above is exactly what is implemented for SystemExit.

See also http://bugs.python.org/issue6498

HTH,

Mark.

Eric Frederich

unread,
Mar 27, 2011, 11:06:47 PM3/27/11
to comp.lan...@googlegroups.com, pytho...@python.org, eryksun ()
I'm not sure that I know how to run this function in such a way that
it gives me an interactive session.
I passed in stdin as the first parameter and NULL as the second and
I'd get seg faults when running exit() or even imnport sys.

I don't want to pass a file. I want to run some C code, start an
interactive session, then run some more C code once the session is
over, but I cannot find a way to start an interactive Python session
within C that won't exit pre-maturely before I have a chance to run my
cleanup code in C.

eryksun ()

unread,
Mar 27, 2011, 11:47:34 PM3/27/11
to Eric Frederich
On Sunday, March 27, 2011 11:06:47 PM UTC-4, Eric Frederich wrote:
> I'm not sure that I know how to run this function in such a way that
> it gives me an interactive session.
> I passed in stdin as the first parameter and NULL as the second and
> I'd get seg faults when running exit() or even imnport sys.

Passing NULL as the 2nd parameter causes the segfault. Do this instead:

FILE* fp = stdin;
char *filename = "Embedded";
PyRun_InteractiveLoop(fp, filename);

See here regarding the segfault:

http://bugs.python.org/issue5121

Mark Hammond

unread,
Mar 28, 2011, 8:36:34 PM3/28/11
to Eric Frederich, pytho...@python.org
On 28/03/2011 2:06 PM, Eric Frederich wrote:
> I'm not sure that I know how to run this function in such a way that
> it gives me an interactive session.
> I passed in stdin as the first parameter and NULL as the second and
> I'd get seg faults when running exit() or even imnport sys.
>
> I don't want to pass a file. I want to run some C code, start an
> interactive session, then run some more C code once the session is
> over, but I cannot find a way to start an interactive Python session
> within C that won't exit pre-maturely before I have a chance to run my
> cleanup code in C.

Instead of calling Py_Main, arrange for the following code to be executed:

import code
try:
code.interact()
except SystemExit:
pass
print "Done!"

If you save that as a script and run it, you will see that when you call
quit() or use Ctrl+D, the "Done!" is printed (so the exception is
caught) and things will return normally (albeit without any return code
that may have been specified in the SystemExit exception). If you
arrange to call that code in your app (either by importing it as a
module of even by calling PyRun_SimpleString) things should work as you
need.

HTH,

Mark

0 new messages