How to create and assign a Python variable in C? - python

I've initialized the Python environment by
Py_Initialize();
I have no external Python module imported into the environment and everything works well. But when I need to pass a C string into this environment, I am lost...
I was thinking to add a function in the environment to assign the variable like the following code do.
char *str;
str="\
def assign_var(str):\
global string\
string = str";
PyRun_SimpleString(str);
And then call this function in C and pass the converted C string as the arguments.
I don't think all I mentioned above is a good way solve the problem...
How can I make this work?
Solution:
Finally, here's the solution with Peter Mortensen's help. (Thanks Peter Mortensen!)
As the python environment I've initialized is a pure empty environment(without any imported modules). I use
py_main = PyImport_AddModule("__main__");
to get a hook to the main environment. and then call
PyModule_AddStringConstant(py_main, "string_name", str);
to bring the C string into the python environment.
To verify everything is done, just try:
PyRun_SimpleString("print dir()");
PyRun_SimpleString("print string_name");
and you'll see you "string_name" string appears in the dir() list and make it print by python!

This should do what you want:
char *cStr = "Some text here.";
PyObject *pyStr = Py_BuildValue("s", cStr);
http://docs.python.org/c-api/arg.html#Py_BuildValue
Of course if you're using Python 3 (or use it in the future), there may be situations where you'd want to use "y" instead of "s" and get a bytes object rather than a str.
UPDATE: Woops, I forgot the even easier way of doing it.
PyObject *pyStr = PyString_FromString(cStr);
http://docs.python.org/c-api/string.html#PyString_FromString
(It'd be PyBytes_FromString() in Python 3.)
You might want to take a look at http://docs.python.org/extending/embedding.html for some more information.
Here's something else you might want to try. See
http://docs.python.org/c-api/module.html#PyModule_AddObject
Or possibly
http://docs.python.org/c-api/module.html#PyModule_AddStringConstant
With the former it'd be something like
errorcheck = PyModule_AddObject(embmodule, "str", pyStr);
And with the latter, something like
errorcheck = PyModule_AddStringConstant(embmodule, "str", cStr);

Related

how to use gdb.lookup_type find local type definition

I have a C static function, and a struct type is defined in it. It may look like:
static void do_stuff(parameters...) {
struct example {
uint32_t a;
uint32_t b;
};
}
I tried to use python gdb module to find this type - gdb.lookup_type('struct example'), but I got an error saying that the type is not defined. If I moved this struct definition outside of this static function, then everything would be good. I guess I need to specify the block parameter in the lookup_type function. I tried gdb.selected_frame().block() (and its superblock, static_block, global_block), but it doesn't work for me. I am new to python and gdb module, so I am not sure why a local struct type cannot be found here, even if I passed the local block to lookup_type. Can anyone give me some help about this issue? Thanks!
I figured out a solution by myself, though I am not sure if it is the best one.
I tried to check all symbols in the current frame's block, and I found that the local struct definition can be found in it. The code may look like:
for symbol in gdb.selected_frame().block():
if symbol.type.tag == 'example' and symbol.type.code = gdb.TYPE_CODE_STRUCT:
# do something
Hope this is useful for someone who has the same problem with me.

create a python module with C and Python code

I have a small python module I have created with the Python C API which I call mycore.
I have also created some utility scripts in Python which are related.
How can I put both in the same module namespace? I know I can call Python code from my C code but surely there is an easier way to do that.
Thanks
The obvious way is by making mycore a package. Create a mycore/__init__.py that imports both the C part, typically named something like _mycore, and the Python part:
from _mycore import *
from _mycorepy import *
In the same directory you'd have a _mycore.so and _mycorepy.py.
Another way to mix Python and C code is by invoking PyRun_String on the embedded Python. This might be what you mean by I know I can call Python code from my C code..., but just in case, here is a simple example with the potentially tricky refcounting details:
PyObject *get_factory()
{
PyObject *g, *runret, *factory;
// prepare a dictionary for the module to run in
g = Py_BuildValue("{s:O}", "__builtins__", PyEval_GetBuiltins());
if (!g)
return NULL;
// run Python code in the dictionary -- the code may import modules, etc.
runret = PyRun_String("\
def factory():\n\
return 42\n", Py_file_input, g, NULL);
Py_XDECREF(runret);
if (!runret) {
Py_DECREF(g);
return NULL;
}
Py_DECREF(runret);
// pick the stuff you care about from the dictionary and return it
factory = PyDict_GetItemString(g, "factory");
Py_INCREF(factory);
Py_DECREF(g);
return factory;
}
OK, this worked for me. My circumstances may be different. My C module was built internally and provided to my embedded Python with a call to PyImport_AppendInittab().
But I still had some accompanying Python code that I wanted associated with the same namespace.
So I got it working by naming my C code _mygadget and the Python file mygadget.py. For the first line of mygadget.py I wrote:
from _mygadget import *
This seems to work. I don't know what would happen if I had a Python method and C call with the same name. I am avoiding that at present.

Create object from string repesentation in C API

I am working on a system which is embedding a Python interpreter, and I need to construct a PyObject* given a string from the C API.
I have a const char* representing a dictionary, in the proper format for eval() to work properly from within Python, ie: "{'bar': 42, 'baz': 50}".
Currently, this is being passed into Python as a PyObject* using the Py_Unicode_ api (representing a string), so in my python interpreter, I can successfully write:
foo = eval(myObject.value)
print(foo['bar']) # prints 42
I would like to change this to automatically "eval" the const char* on the C side, and return a PyObject* representing a completed dictionary. How do I go about converting this string into a dictionary in the C API?
There are two basic ways to do this.
The first is to simply call eval the same way you do in Python. The only trick is that you need a handle to the builtins module, because you don't get that for free in the C API. There are a number of ways to do this, but one really easy way is to just import it:
/* or PyEval_GetBuiltins() if you know you're at the interpreter's top level */
PyObject *builtins = PyImport_ImportModule("builtins");
PyObject *eval = PyObject_GetAttrString(builtins, "eval");
PyObject *args = Py_BuildValue("(s)", expression_as_c_string);
PyObject *result = PyObject_Call(eval, args);
(This is untested code, and it at least leaks references, and doesn't check for NULL return if you want to handle exceptions on the C sideā€¦ But it should be enough to get the idea across.)
One nice thing about this is that you can use ast.literal_eval in exactly the same way as eval (which means you get some free validation); just change "builtins" to "ast", and "eval" to "literal_eval". But the real win is that you're doing exactly what eval does in Python, which you already know is exactly what you wanted.
The alternative is to use the compilation APIs. At the really high level, you can just build a Python statement out of "foo = eval(%s)" and PyRun_SimpleString it. Below that, use Py_CompileString to parse and compile the expression (you can also parse and compile in separate steps, but that isn't useful here), then PyEval_EvalCode to evaluate it in the appropriate globals and locals. (If you're not tracking globals yourself, use the interpreter-reflection APIs PyEval_GetLocals and PyEval_GetGlobals.) Note that I'm giving the super-simplified version of each function; often you want to use one of the sibling functions. But you can find them easily in the docs.

Changing C variables from python?

I have an embedded python interpreter in my program. I'd like to export a module with values defined in my program and be able to change them from a python script. e.g.
in c:
int x = 1;
in python:
import embedded
embedded.x = 2
in c:
printf("%d",x);
output:
2
Is this possible or do I have to export functions to change anything in c?
There's no need to export functions, but the easiest way to do this would be to use PyModule_GetDict() with PyDict_GetItemString() to get the value assigned to the x attribute.
If you don't want to actively check the value of a PyObject in your C code, I think you need to export functions to modify the representation in C. I'm no expert, but I don't think there's an automatic mapping.

How to access a Python global variable from C?

I have some global variables in a Python script. Some functions in that script call into C - is it possible to set one of those variables while in C and if so, how?
I appreciate that this isn't a very nice design in the first place, but I need to make a small change to existing code, I don't want to embark on major refactoring of existing scripts.
I'm not a python guru, but I found this question interesting so I googled around. This was the first hit on "python embedding API" - does it help?
If the attributes belong to the global
scope of a module, then you can use
"PyImport_AddModule" to get a handle
to the module object. For example, if
you wanted to get the value of an
integer in the main module named
"foobar", you would do the following:
PyObject *m = PyImport_AddModule("__main__");
PyObject *v = PyObject_GetAttrString(m,"foobar");
int foobar = PyInt_AsLong(v);
Py_DECREF(v);
For anyone coming here from Google, here's the direct method:
PyObject* PyEval_GetGlobals()
https://docs.python.org/2/c-api/reflection.html
https://docs.python.org/3/c-api/reflection.html
The return value is accessed as a dictionary.
I recommend using pyrex to make an extension module you can store the values in in python, and cdef a bunch of functions which can be called from C to return the values there.
Otherwise, much depends on the type of values you're trying to transmit.
Are you willing to modify the API a little bit?
You can make the C function return the new value for the global, and then call it like this:
my_global = my_c_func(...)
If you're using Robin or the Python C API directly, you can pass the globals dictionary as an additional parameter and modify it
If your global is always in the same module, Sherm's solution looks great

Categories

Resources