Converting a C++ String Class to a Python String - python

I have a C++ class that is able to output strings in normal ASCII or wide format. I want to get the output in Python as a string. I am using SWIG (version 3.0.4) and have read the SWIG documentation. I believe I need to use the typemap construct to achieve my goal. I have written the following:
%typemap(out) my_namespace::MyString *
{
$result = PyString_AsString($1);
}
with no success. When I try to access a C++ string from Python, I get the following output:
<Swig Object of type 'MyString *' at 0x02B6FC68>
Obviously, I'm doing something wrong. Can anyone point me in the right direction? Thanks in advance.

I use pyboost for C++/python interfaces and is amazing and easy to do that. If you can, I recommend it. A simply std::string is automatically mapped to python string. In your case, may be any solution is to define a
__str __
method for the object or directly pass a char* (I see that in swig docs but I never followed this way).

It turns out the correct solution was:
%typemap(out) my_namespace::MyString &
{
$result = PyString_FromFormat($1->c_str());
}
Not very intuitive, but it works.

Related

using nlohmann::json with cppyy?

Is it possible to pass a python dict into a function expecting a nlohmann::json (nlohmann/json) object via cppyy? This question has to have come up by now, but I wasn't able to find anything on it.
Minimal example to reproduce (without regard to performance/safety, pls forgive):
test-json.h
#include <iostream>
#include <nlohmann/json.hpp>
using nlohmann::json;
void print_name_and_age(json j) {
std::cout << j["name"] << "\n"
<< j["age"] << "\n";
}
test-cppyy.py
import cppyy
cppyy.include('test-json.h')
from cppyy.gbl import print_name_and_age
some_dict = {
"name": "alfred",
"age": 25
}
print_name_and_age(some_dict)
runs into
print_name_and_age(some_dict)
NotImplementedError: void ::print_name_and_age(nlohmann::json j) =>
NotImplementedError: could not convert argument 1 (this method cannot (yet) be called)
I would like to be able to pass a python dict into the C++ function, and receive it as a nlohmann::json object. I presume I would need to write some custom converter for this?
Design requirement/background (optional)
I have a reinforcement learning environment class (written in C++) that needs to accept some configuration to initialize it (in its constructor). Everything's all fine passing a nlohmann::json object into the constructor while in the C++ domain, but I have a Python wrapper around the class too, written with cppyy that provides similar functionality to the C++ interface.
Uptill now, because of the aforementioned issue, I've been forced to receive a const std::map<std::string, float>& in the constructor instead of a nlohmann::json, which is what a python dict containing only str -> float mappings easily gets converted to by cppyy. But this obviously limits my input json files to only contain floats as values (my usecase requires having strings as keys but strings, ints, floats and bools as values in the JSON file). I can ofcourse write some pre-processing code to encode my heterogenous python dict into a homogenous str->float mapping on the python front (and do the same for C++) but I'd like a cleaner solution, if possible.
Could anyone please help me achieve passing a python dict into the cppyy-imported C++ function and have it converted into a nlohmann::json object in the C++ function? If this requires forking cppyy to add extra converter code/too much trouble I presume I would need to use a std::map<std::string, std::any / variant> alternative? I haven't worked alot with std::any/variant, would like to ask if this would even be possible - python dict to map<string, any> - if this is the best alternative to a custom converter - in terms of performance / clean elegant code.
Environment:
Python 3.9.13
C++17 ( I believe cppyy-2.4.0 doesn't support C++20 yet, I don't have any constraint on the C++ standard)
cppyy==2.3.1
cppyy-backend==1.14.8
cppyy-cling==6.25.3
cppyythonizations==1.2.1
MacOS Monterey, Apple M1
This has been answered at GitHub: Conversion from python dict into nlohmann::json

Using SWIG typemaps to generate overloaded Python wrapper

I am using SWIG to generate Python bindings for a library (lets call it Spam) that is written in C++. The library internally defines its own Vector datatype, defined in the Spam::Vector class.
Consider the following functions to be wrapped:
void ham(Spam::Vector &vec_in, Spam::Vector &vec_out);
void eggs(Spam::Vector &vec_in, double arg2, double result);
I would like to be able to call these functions using Python lists AND NumPy arrays as inputs (instead of having to create a Spam::Vector object in Python and then populate it using the associated C++ methods - it is very unpythonic).
How would I go about writing the SWIG typemap to achieve this? Also, is there a way to incorporate/leverage numpy.i for this purpose?
The right way to do this is with a custom typemap. Precisely what this will look like depends a lot on the type Spam::Vector itself. In general though you can do this with something like:
%typemap(in) {
// Maybe you'd rather check for iterable here, with this check after numpy?
if (PyList_Check($input)) {
$1 = ... // Code to iterate over a list and prepare a Spam::Vector
}
else if (PyType_IsSubtype($input->ob_type, NumpyType)) {
$1 = ... // Code to convert from numpy input
}
else {
// code to raise an error
}
}
There are various hacks that might be possible in other more specific circumstances, but this is the general solution.

Using PyObject_IsInstance

My application embeds python by dynamically loading it. I need to obtain the values from the dictionary of the script being executed.
pFnPyDict_GetItemString *pFGetItemString = NULL;
pFGetItemString = (pFnPyDict_GetItemString *)::GetProcAddress(hModulePython, PyDict_GetItemString);
if (pFGetItemString)
{
PyObject *pGet = pFGetItemString(pLocals, pVar);
if (pGet)
{
//The following code will not work as PyInt_Check is a macro
pFnPyInt_Check *pIsInt = (pFnPyInt_Check *)::GetProcAddress(hModulePython, "PyInt_Check");
if (PyInt_Check(get))
{
}
// There fore i am using PyObject_IsInstance
pFnPyObject_IsInstance *pFIsInstance = (pFnPyObject_IsInstance*)::GetProcAddress(hModulePython, "PyObject_IsInstance");
if (pFIsInstance)
{
int i = pFIsInstance(pGet, (PyObject*)&PyInt_Type); ----> the problem is here. This call fails.
}
}
}
How do I specify the second parameter to PyObject_IsInstance? Here i want to check if the value in pGet is of type int.
Do you only want to check for ints? If so you're better off using PyInt_Check instead.
Additional: Some advice, that you didn't ask for but which might help you. :) Are you using C or C++. If it's the later, consider using Boost.Python instead of the Python C API — it will make things a lot easier. Exposing functions and classes is trivial with Boost.
Surely the correct approach here is to include the header file and use PyInt_Check().
I assume that you have not included the Python C API header file because you don't want to use implicit linking. But you are making life hard for yourself by trying to work without the header file. Just because you include the header file, doesn't mean that the DLL functions will be implicitly linked to your program. This will only happen if you actually call some of the functions in the DLL.
If you want to be 100% sure that you don't implicitly link to the DLL then simply ensure that you don't link the .lib file.

How to define a C struct which contain a struct inside a Ctype python

Hi
I am learning python and using ctype to embedd 'C' in python. My query is-
How to use C stru which again calling a stru inside into cytpe/python.
typedef struct {
struct *i, *j;
BOOLEAN z;
} foo;
It's not entirely clear from your question, but it looks like you're trying to define a struct that contains a pointer to the same type. It's not immediately obvious how you would accomplish this in python, but you basically define your Structure, and then define the _fields_ attribute afterwards.
The ctype docs on python.org have a perfectly on-point example of doing exactly this.
There's also good documentation there on working with structs in general, including nesting one struct type within another, which works a little more obviously.

How to find the number of parameters to a Python function from C?

I'm using the Python C API to call Python functions from my application. I'd like to present a list of functions that could be called and would like to be able to limit this list to just the ones with the expected number of parameters.
I'm happy that I can walk the dictionary to extract a list of functions and use PyCallable_Check to find out if they're callable, but I'm not sure how I can find out how many parameters each function is expecting?
I've found one technique involving Boost::Python, but would rather not add that for what (I hope!) will be a minor addition.
Thanks :)
Okay, so in the end I've discovered how to do it. User-defined Python functions have a member called func_code (in Python 3.0+ it's __code__), which itself has a member co_argcount, which is presumably what Boost::Python extracts in the example given by Christophe.
The code I'm using looks like this (it's heavily based on a documentation example of how to walk a Python dictionary):
PyObject *key, *value;
int pos = 0;
while(PyDict_Next(pyDictionary, &pos, &key, &value)) {
if(PyCallable_Check(value)) {
PyObject* fc = PyObject_GetAttrString(value, "func_code");
if(fc) {
PyObject* ac = PyObject_GetAttrString(fc, "co_argcount");
if(ac) {
const int count = PyInt_AsLong(ac);
// we now have the argument count, do something with this function
Py_DECREF(ac);
}
Py_DECREF(fc);
}
}
}
Thanks anyway - that thread did indeed lead me in the right direction :)
Maybe this is helpful? (not tested, there could be relevant pieces of information along this thread)...
Your C code can call inspect.getargspec just like any Python code would (e.g. via PyObject_CallMethod or other equivalent ways) and get all the scoop about the signature of each function or other callable that it may care about.

Categories