Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > calling Pyrex results from C

Reply
Thread Tools

calling Pyrex results from C

 
 
Kyler Laird
Guest
Posts: n/a
 
      01-20-2004
I need to submit C/C++ code for a class. (It's not a programming
class. The choice of language is inertial. I think that it mostly
serves to distract students from the course subject.) I'm fairly
fluent with C but it hurts to think about writing in C when Python
is *so* much more appropriate for these operations.

I'd like to keep my sanity and satisfy the course requirements by
programming in Python and converting the code to C. It looks like
a few people have scratched this itch already, but of the
translators I found, most of them (Python2C, P2C, PyFront) seem to
be dead. Pyrex, however, appears to be well-maintained and is even
available as a Debian package.
http://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/

I realize that the goal of Pyrex is to create a module that can be
called from Python. For my need of calling the result from C, the
other utilities are probably more appropriate but I think that
Pyrex could be useful to me for less contrived situations than this
so it's worthwhile to learn more about it.


http://www.cosc.canterbury.ac.nz/~gr...ngWithExternal

You can also use public declarations to make C functions
and variables defined in a Pyrex module available to
external C code. The need for this is expected to be less
frequent, but you might want to do it, for example, if you
are embedding Python in another application as a scripting
language. Just as a Pyrex module can be used as a bridge to
allow Python code to call C code, it can also be used to
allow C code to call Python code.

[...]

You can make C variables and functions defined in a Pyrex
module accessible to external C code (or another Pyrex
module) using the public keyword

I've discovered that as long as everything in the code is cdef-ed,
I can call Pyrex code from my C code. If, however, I so much as
mention anything Pythonish, it segfaults during execution.

For example, this is fine.
cdef public int foo():
cdef int i
i = 123

return(i)

And this results in a segfault.
cdef public int foo():
cdef int i
i = 123
j = 5

return(i)

This means that I can't, for example, make a function that takes a
filename (string), uses PIL to do a bunch of operations, and
returns a string.

Any suggestions (besides "suck it up and do it all in C")?

Thank you.

--kyler
 
Reply With Quote
 
 
 
 
=?iso-8859-1?Q?Fran=E7ois?= Pinard
Guest
Posts: n/a
 
      01-20-2004
[Kyler Laird]

> I realize that the goal of Pyrex is to create a module that can be
> called from Python.


Or vice-versa. I found Pyrex useful for calling Python modules from
within C programs which were not Python-aware to start with. You may
even write wholly Pyrex programs.

> I've discovered that as long as everything in the code is cdef-ed,
> I can call Pyrex code from my C code. If, however, I so much as
> mention anything Pythonish, it segfaults during execution.


There is some magic needed to establish Python context, not much.
Hoping that it will help, here is a template I use when generating
Pyrex main programs. `%(module)s' shall be replaced by the Pyrex module
name, as Pyrex needs to initialise itself. When Python calls Pyrex,
initialisation occurs automatically at `import' time, but when C
initially calls Pyrex, initialisation should be explicitly launched.



cdef extern void Py_Initialize()
cdef extern void Py_Finalize()
cdef extern void init%(module)s()

cdef extern int main(int argc, char **argv):
cdef int index, status
Py_Initialize()
init%(module)s()
import sys
try:
arguments = []
for index from 0 <= index < argc:
arguments.append(argv[index])
sys.argv = arguments
result = main_application()
raise SystemExit, result or 0
except SystemExit, result:
result = str(result)
try:
status = int(result)
except ValueError:
if not result.endswith('\n'):
result = result + '\n'
sys.stderr.write(result)
status = 1
except:
import traceback
traceback.print_exc()
status = 1
Py_Finalize()
return status


--
François Pinard http://www.iro.umontreal.ca/~pinard

 
Reply With Quote
 
 
 
 
John J. Lee
Guest
Posts: n/a
 
      01-20-2004
Kyler Laird <(E-Mail Removed)> writes:
[...]
> This means that I can't, for example, make a function that takes a
> filename (string), uses PIL to do a bunch of operations, and
> returns a string.


I don't see why you shouldn't be able to write a module in Pyrex, then
use standard embedding techniques to embed Python and then call your
module with a few C API calls. Or do the same, but also write a Pyrex
cdef function to wrap it all up, so you can just call that as a "plain
old" C function instead of those final few C API calls (you'll still
need other embedding calls, of course, to initialise Python, etc.).

Try the pyrex mailing list if you're stuck.

I'd very definitely check to make sure you aren't going to get marked
down for being a smartass, though (even if you're generating C that
doesn't depend on Python at all, it might still be unreadable).


> Any suggestions (besides "suck it up and do it all in C")?


I think I'd do it in C, regardless of whether or not it's allowable to
use Pyrex.


John
 
Reply With Quote
 
Kyler Laird
Guest
Posts: n/a
 
      01-20-2004
On Tue, Jan 20, 2004 at 12:27:33PM -0500, Fran?ois Pinard wrote:

> There is some magic needed to establish Python context, not much.
> Hoping that it will help, here is a template I use when generating
> Pyrex main programs.


Paul started me on this path and you've given me exactly what I need to
keep going.

Thank you!

--kyler


 
Reply With Quote
 
Kyler Laird
Guest
Posts: n/a
 
      01-21-2004
Paul Prescod graciously responded to my plea for help by gently asking
if I had initialized Python. Doh! I had gotten lazy and assumed that
Pyrex would take care of such details. (How could it?!)

Initializing the interpreter seems to have the simple test case I made
working smoothly. Now it's on to bigger and better things...

Pyrex is *so* cool.

Thank you, Paul!

--kyler
 
Reply With Quote
 
=?iso-8859-1?Q?Fran=E7ois?= Pinard
Guest
Posts: n/a
 
      01-21-2004
[Kyler Laird]
> On Tue, Jan 20, 2004 at 12:27:33PM -0500, Fran?ois Pinard wrote:


> > There is some magic needed to establish Python context, not much.
> > Hoping that it will help, here is a template I use when generating
> > Pyrex main programs.


> Paul started me on this path and you've given me exactly what I need to
> keep going.


Good.

There is also some linking magic, which differs from system to system,
it might be documented in the Python Embedding API, I'm not sure. If
you do not stumble on the proper recipe, I'll share what I use on Linux.
Just ask if you want me to go search into some of my Makefiles .

--
François Pinard http://www.iro.umontreal.ca/~pinard

 
Reply With Quote
 
Kyler Laird
Guest
Posts: n/a
 
      01-21-2004
The help I've gotten in this thread has enabled me to complete my
assignment...well, at least I can generate C code that spits out
the answer.

I'd like to factor out more of the Python so that my handwritten
C code can do more of the high-level operations. I'm having some
difficulties passing data between my C and the Pyrex code.

One of the first things I thought I'd build is a helper function
to return a string representation of an object. I thought that
this would be fairly straightforward. Unfortunately it segfaults
when called with some Python objects.

Pyrex:
cdef public image_file_open(char* image_filename):
return(Image.open(image_filename))

cdef public image_size(image_PIL):
return(Image.size)

cdef public char* string(x):
s = str(x)
return(s)

my C:
void *im, *im_size;
im = image_file_open(input_filename);
im_size = image_size(im);
printf("im=%s\n", string(im));
printf("im_size=%s\n", string(im_size));

The first call to string() succeeds but the second one fails. I
suspect that I've expected too much of Pyrex again. Do I need to
allocate memory, manipulate reference counts or something like
that?

It's difficult for me to get back to thinking in terms of
passing around data in C ways. I almost forgot what a boon
tuples have been. (Perhaps I need to code in assembly for
awhile to get back in that frame of mind.) Someday I might try
to pass structures between C and Pyrex. I'm slowly getting
comfortable with Pyrex but I can see how my code can get *much*
cleaner once I understand more of its capabilities.

Thank you.

--kyler
 
Reply With Quote
 
Paul Prescod
Guest
Posts: n/a
 
      01-21-2004
Kyler Laird wrote:

>
> Pyrex:
> cdef public image_file_open(char* image_filename):
> return(Image.open(image_filename))
>
> cdef public image_size(image_PIL):
> return(Image.size)
>
> cdef public char* string(x):
> s = str(x)
> return(s)
>
> my C:
> void *im, *im_size;
> im = image_file_open(input_filename);
> im_size = image_size(im);
> printf("im=%s\n", string(im));
> printf("im_size=%s\n", string(im_size));
>
> The first call to string() succeeds but the second one fails. I
> suspect that I've expected too much of Pyrex again. Do I need to
> allocate memory, manipulate reference counts or something like
> that?


First, I'd suggest that "integer" is a perfectly good type in both C and
Pyrex so you shouldn't pass around Python objects representing integers.

Second, you aren't checking the return codes of your functions and C has
no exception handling, tracebacks, etc. image_size is probably returning
0 because it is probably throwing an exception because you are asking
for the size attribute of the Image class rather than the image_PIL object.

You actually would have gotten a Pyrex error on your console if your
function were defined to return "int" or "void" because Pyrex would KNOW
that there's no way you are doing exception handling so it would try to
compensate by printing exceptions to the console. But I wouldn't depend
on that feature because it doesn't help for functions that really should
return objects. Better to check your return values.

Once I fix the Image/Image_PIL error your code runs okay on my computer.
But you are walking on thin ice and may just be lucky. It is simply
not possible to work with strings generated at runtime in C without
worrying about memory allocation sometime. In this case I have the
strong suspicion that the string() function is either creating and
destroying a string object and then returning you a pointer to the dead
object's internal memory buffer (bad news!) or simply losing a reference
to the (still living) string object: still not a good thing. Eyeballing
the code I believe the former is the issue. You could check for sure by
adding some printf's to the generated code to look at __pyx_v_s->ob_refcnt.

Why not let Python do the "print" rather than using "printf".

Paul Prescod



 
Reply With Quote
 
Kyler Laird
Guest
Posts: n/a
 
      01-21-2004
On Wed, Jan 21, 2004 at 08:23:53AM -0800, Paul Prescod wrote:

> First, I'd suggest that "integer" is a perfectly good type in both C and
> Pyrex so you shouldn't pass around Python objects representing integers.


That would be my inclination too if I just had an integer to pass.
Are you suggesting that I should pass tuples of integers as pointers
to (an array of) integers?

> Second, you aren't checking the return codes of your functions and C has
> no exception handling, tracebacks, etc. image_size is probably returning
> 0 because it is probably throwing an exception because you are asking
> for the size attribute of the Image class rather than the image_PIL object.


I'm trying to keep my examples simple so that it's easy to pick out the
mistakes.

> Once I fix the Image/Image_PIL error your code runs okay on my computer.


Grrr...yup, that does it. Dumb mistake - the result of pulling code
out of various places and gluing it together without checks.

> But you are walking on thin ice and may just be lucky. It is simply
> not possible to work with strings generated at runtime in C without
> worrying about memory allocation sometime. In this case I have the
> strong suspicion that the string() function is either creating and
> destroying a string object and then returning you a pointer to the dead
> object's internal memory buffer (bad news!) or simply losing a reference
> to the (still living) string object: still not a good thing. Eyeballing
> the code I believe the former is the issue. You could check for sure by
> adding some printf's to the generated code to look at __pyx_v_s->ob_refcnt.


I feared this was a problem. I'll play with it.

> Why not let Python do the "print" rather than using "printf".


Printing is not always my final goal.

Thank you.

--kyler


 
Reply With Quote
 
Kyler Laird
Guest
Posts: n/a
 
      02-04-2004
Paul Prescod <(E-Mail Removed)> writes:

> 1. How is your teacher going to react when you hand in obfuscated-ish
> C code that depends on the whole Python interpreter _and_ PIL?


Shhh...don't tell anyone.
Grades for ECE661 as of Wed Feb 4 15:01:35 2004
Name hw1 hw2
---- ----- -----
Maximums: 100.0 100.0
Laird, Kyler 100.0 100.0
Class Average: 93.8 86.6
Class Standard Deviation: 20.1 24.3

This is Computer Vision, not Introduction to Pointers and Memory Allocation.
Pyrex frees me to concentrate on the course material.

(And I *need* to concentrate on the course material. I'm in a class full of
incredibly smart people with a lot more background in the subject. Pyrex
helps me keep up with them. So does only taking one class and investing
ridiculous amounts of time on the homework.)

Thanks again for helping me avoid C.

Now to write some "thinning" code...

--kyler
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: [Pyrex] pyrex functions to replace a method (Re: replace a method Greg Ewing Python 2 06-29-2006 05:25 PM
Re: [Pyrex] Allocating an array.array of a specific length in pyrex Chris Lambacher Python 0 06-08-2005 06:56 PM
calling virtual function results in calling function of base class... Andreas Lagemann C++ 8 01-10-2005 11:03 PM
calling virtual function results in calling function of base class ... tiwy C++ 0 01-09-2005 11:17 PM
Re: Pyrex without Python (was Re: calling Pyrex results from C) =?iso-8859-1?Q?Fran=E7ois?= Pinard Python 3 01-21-2004 01:53 PM



Advertisments