pthom / litgen

litgen: a pybind11 automatic generator for humans who like nice code and API documentation. Also a C++ transformer tool
https://pthom.github.io/litgen
GNU General Public License v3.0
36 stars 3 forks source link

C++ unions #9

Open renautomation opened 2 months ago

renautomation commented 2 months ago

Hello, I have code like this: typedef union u_signalValue_t { float flt; int32_t i32; double dbl; int64_t i64; } signalValue_t; I already overcame the issue related to the usage of "typedef", by pre-processing the code, as suggested here: https://github.com/pthom/litgen/issues/7

So, my pre-processed code is now: union signalValue_t { float flt; int32_t i32; double dbl; int64_t i64; };

however, it seems the the union type is not processed by litgen: I see all other types in the pybind11 C++ code, like enums, classes, structs, etc. except this union.

Any suggestion?

pthom commented 2 months ago

Union types are very, very, C/C++ specific.

There is no such thing as unions in Python: object and base types will always occupy different memory locations.

Solutions:

1/ Either you write a wrapper And use it in the API you want to publish.


class MySignal 
{
  int as_int();
   ...
private:
   signalValue_t xxx;

};

2/ And/or you write a custom caster And give it appropriate methods.

https://pybind11.readthedocs.io/en/stable/advanced/cast/custom.html

pthom commented 2 months ago

https://chat.openai.com/share/cac0564c-376c-4e90-89f9-0c6f7734263a

renautomation commented 1 month ago

Hi, I used the wrapper approach suggested above by ChatGPT. Now, I'm trying to add the original union type in the exclude options, but I don't find the proper option. I only found: fn_exclude_by_nameregex class_exclude_by_name__regex member_exclude_by_nameregex but of course they don't work because I don't have neither a function nor a class, I have a union. The problem is that, if I don't exclude it, in the generated code, in the bindings related to the functions and classes that use my union, I find stuff like: ..., py::arg("value") = signalValue_t(), ... (in pybind11_module.cpp) ...value: signalValue_t ... (in init.pyi)

the build process works, but then when I go to Python: `>>> from MyPythonBindings import Traceback (most recent call last): File "", line 1, in File "/My/Path/init.py", line 1, in from MyPythonBindings._MyPythonBindings import # type: ignore # noqa: F403 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ImportError: arg(): could not convert default argument into a Python object (type not registered yet?). #define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more information.

`

pthom commented 1 month ago

https://github.com/pthom/litgen/blob/226992d4e30be298963fa96e52254e2e45af6477/src/litgen/options.py#L110C1-L118C46


    # Exclude certain functions and methods by a regex on any of their parameter type and/or return type
    # (those should be decorated type)
    # For example:
    #     options.fn_exclude_by_param_type__regex = "^char\s*$|^unsigned\s+char$|Callback$"
    # would exclude all functions having params of type "char *", "unsigned char", "xxxCallback"
    #
    # Note: this is distinct from `fn_params_exclude_types__regex` which removes params
    # from the function signature, but not the function itself.
    fn_exclude_by_param_type__regex: str = ""
renautomation commented 1 month ago

ok, I was doing confusion before on what I really needed... I didn't need to exclude the "union" (also because it was already excluded by litgen by default, in fact I opened the issue exactly for this reason.

So, now I found the way to expose union types, and I resume the procedure for eventual future users:

Now the bindings are correctly generaed and the wrapped union works s expected. Thanks a lot for your support, @pthom