Library of Assembled Shared Sources
PyExportTraits

Detailed Description

Traits to convert between C++ and Python types.

PyExportTraits<T> is a central part of the Lass Python binding system. It defines how to convert between a C++ type T and a corresponding Python object. It also provides type hinting information for Python type annotations.

Client code will not usually use these traits directly, but rather use the functions pyBuildSimpleObject() and pyGetSimpleObject():

TPyObjPtr pyObj( pyBuildSimpleObject(cppValue) );
if (!pyObj)
// error occurred, Python exception set
T cppValue2;
if (pyGetSimpleObject(pyObj.get(), cppValue2) != 0)
// error occurred, Python exception set
PyObjectPtr< PyObject >::Type TPyObjPtr
PyObjectPtr to a PyObject.

A well-defined PyExportTraits<T> specialization provides the following parts, all of which are optional:

template <typename T>
struct PyExportTraits<Spam<T>>
{
constexpr static const char* py_typing = "Spam[T]";
constexpr static const char* py_typing_param = "_Spam[T]";
constexpr static const char* py_typing_preamble = "type _Spam[T] = Spam[T] | T";
static PyObject* build(const Spam<T> &value)
{
// Construct PyObject from value and return new reference.
// Or set Python error and return nullptr on failure.
}
static int get(PyObject* obj, Spam<T>& value)
{
// Extract and set value from obj, and return 0 on success.
// Or set Python error and return -1 on failure.
}
}

Building Python objects from C++ values

The build() method should return a new reference to a Python object that represents the C++ value passed as argument. If the conversion fails, it should set a Python exception and return nullptr.

Its return type must be PyObject*, and it must accept a single argument of type const T&.

If a PyExportTraits<T> specialization does not provide a build() method, then the C++ type cannot be converted to Python. This is only useful for types that can only be used as function parameters, but not as return values or attributes.

Client code will usually not call the build() method directly, but rather use the pyBuildSimpleObject() function, which will call the build() method internally.

Getting C++ values from Python objects

The get() method should extract the C++ value from the Python object passed as argument, and store it in the second argument passed by reference. If the conversion is successful, it should return 0. If the conversion fails, it should set a Python exception and return 1.

The first argument must be of type PyObject*, and the get() shall not eat a reference. In other words, the get() method gets a borrowed reference to the Python object.

The second argument must be of type T&, and the get() method should set this value if conversion is successful.

Note
Some types cannot define a meaningful get() method, such as types that cannot be default-constructed, or types that don't have a well-defined lifetime, such as char* strings. In such cases, the PyExportTraits<T> specialization should not provide a get() method. But that does not mean that these types cannot be used as function parameters. By specializing ArgumentTraits for these types, you can still support them as function parameters, and it may still make sense to define py_typing_param for type hinting. See ArgumentTraits for more details on techniques to support such types as function parameters.

Type Hinting

The three type hinting members are used in combination with lass_stubgen to automatically generate Python stub files (.pyi) that provide type hinting information for Python extension modules that use the Lass binding system.

All three members are of type constexpr static const char*, and are optional:

py_typing

To generate useful type hints, you need to provide at least the py_typing member. This should be a string that describes the type in Python typing syntax. For example, for the C++ type prim::ColorRGBA will always convert to a tuple of 4 floats (r, g, b, a), and can be described as:

template <>
struct PyExportTraits<prim::ColorRGBA>
{
constexpr static const char* py_typing = "tuple[float, float, float, float]";
};

py_typing_param

When py_typing_param is provided, it will be used instead of py_typing when the type is used as a function parameter. This is useful for types that can be converted from additional types when used as a parameter. For example, prim::ColorRGBA will always convert to a tuple of 4 floats (r, g, b, a) when returned from a function, but it will also accept (r, g, b), a tuple of 3 floats without the alpha channel(r, g, b)` as argument:

template <>
struct PyExportTraits<prim::ColorRGBA>
{
constexpr static const char* py_typing = "tuple[float, float, float, float]";
constexpr static const char* py_typing_param = "tuple[float, float, float, float] | tuple[float, float, float]";
};

py_typing_preamble

py_typing_preamble can be used to provide additional Python code that needs to be added to the generated stub files to support the type hinting. This can be used to define type aliases to make the type hints more readable. For example, for prim::ColorRGBA, we define two aliases _RGBA and _RGB to make the type hints more readable. The preamble can consist of multiple lines, separated by newline characters. Each type alias will be of the form type _Name = ...:

template <>
struct PyExportTraits<prim::ColorRGBA>
{
constexpr static const char* py_typing = "_RGBA";
constexpr static const char* py_typing_param = "_RGBA | _RGB";
constexpr static const char* py_typing_preamble =
"type _RGBA = tuple[float, float, float, float]\n"
"type _RGB = tuple[float, float, float]";
};

The preamble can also be used to include necessary imports. For example, std::filesystem::path is mapped to pathlib.Path in Python, so the pathlib module needs to be imported. And as parameter, it also accepts str and bytes, or anything that implements the os.PathLike for which the StrOrBytesPath type alias from the _typeshed module is used:

template <>
struct PyExportTraits<std::filesystem::path>
{
constexpr static const char* py_typing = "pathlib.Path";
constexpr static const char* py_typing_param = "StrOrBytesPath";
constexpr static const char* py_typing_preamble = "import pathlib\nfrom _typeshed import StrOrBytesPath";
};
Note
Type-aliases should start with an underscore to indicate they are private and not really part of the module API. They only exist for the purpose of type hinting and checking. Attempting to import them at runtime will result in a failure, unless you hide the code in a if TYPE_CHECKING: block. See https://docs.python.org/3/library/typing.html#typing.TYPE_CHECKING
It is also your responsibility to ensure that the type aliases do not conflict with any other names in the module or in the Python standard library.
The preamble can only contain type aliases and imports.

Partial Specializations

If a PyExportTraits is partially specialized, such as for template classes, then the template parameters can be used in the py_typing and py_typing_param members. They will be substituted with the corresponding Python type hints of the template parameters. For example: for the C++ type std::pair<T, U> translates to a Python tuple of two elements, and is described as:

template <typename T, typename U>
struct PyExportTraits<std::pair<T, U>>
{
constexpr static const char* py_typing = "tuple[T, U]";
};

When substituing template parameters in the context of function parameters, then py_typing_param is used if the template argument defines it, even if the top-level PyExportTraits specialization only defines py_typing. For example, std::pair<T, U> only defines py_typing, but float defines the alias _Float as py_typing_param. So a function taking std::pair<float, float> as a parameter would have the following type hint:

def func(param: tuple[_Float, _Float]) -> None:
...

But sometimes, you really want to substitute the template parameters by their py_typing type, even in the context of function parameters. In that case, you can add an exlamation mark ! after the template parameter name as special syntax to indicate that you always want to replace it by its py_typing type.

One example where this is useful is callable types, such as std::function<R(T, U)>. What you're really saying when a function takes a std::function<R(T, U)> as parameter, is that it takes a callable that accepts two parameters of type T and U, and that you will call that callable from C++, you are providing the arguments of type T and U from C++ to Python, similar like returning values from a normal function. So in this case, you want the types of the T and U arguments to be substituted by their py_typing type, not their py_typing_param type. So you would define the PyExportTraits specialization as:

template <typename R, typename T, typename U>
struct PyExportTraits<std::function<R(T, U)>>
{
constexpr static const char* py_typing = "Callable[[T!, U!], R!]";
};

Data Structures

struct  lass::python::PyExportTraitsCallback< CallbackType, PyCallbackImplType, ExportTraits >
 Helper class to implement PyExportTraits for Callback types. More...
 
struct  lass::python::PyExportTraits< util::Callback0 >
 Bidirectional mapping between util::Callback0 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::Callback1< P1 > >
 Bidirectional mapping between util::Callback1 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::Callback2< P1, P2 > >
 Bidirectional mapping between util::Callback2 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::Callback3< P1, P2, P3 > >
 Bidirectional mapping between util::Callback3 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::Callback4< P1, P2, P3, P4 > >
 Bidirectional mapping between util::Callback4 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::Callback5< P1, P2, P3, P4, P5 > >
 Bidirectional mapping between util::Callback5 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::Callback6< P1, P2, P3, P4, P5, P6 > >
 Bidirectional mapping between util::Callback6 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::Callback7< P1, P2, P3, P4, P5, P6, P7 > >
 Bidirectional mapping between util::Callback7 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::Callback8< P1, P2, P3, P4, P5, P6, P7, P8 > >
 Bidirectional mapping between util::Callback8 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::Callback9< P1, P2, P3, P4, P5, P6, P7, P8, P9 > >
 Bidirectional mapping between util::Callback9 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::Callback10< P1, P2, P3, P4, P5, P6, P7, P8, P9, P10 > >
 Bidirectional mapping between util::Callback10 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::Callback11< P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11 > >
 Bidirectional mapping between util::Callback11 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::Callback12< P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12 > >
 Bidirectional mapping between util::Callback12 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::Callback13< P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13 > >
 Bidirectional mapping between util::Callback13 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::Callback14< P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14 > >
 Bidirectional mapping between util::Callback14 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::Callback15< P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15 > >
 Bidirectional mapping between util::Callback15 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR0< R > >
 Bidirectional mapping between util::CallbackR0 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR1< R, P1 > >
 Bidirectional mapping between util::CallbackR1 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR2< R, P1, P2 > >
 Bidirectional mapping between util::CallbackR2 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR3< R, P1, P2, P3 > >
 Bidirectional mapping between util::CallbackR3 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR4< R, P1, P2, P3, P4 > >
 Bidirectional mapping between util::CallbackR4 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR5< R, P1, P2, P3, P4, P5 > >
 Bidirectional mapping between util::CallbackR5 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR6< R, P1, P2, P3, P4, P5, P6 > >
 Bidirectional mapping between util::CallbackR6 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR7< R, P1, P2, P3, P4, P5, P6, P7 > >
 Bidirectional mapping between util::CallbackR7 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR8< R, P1, P2, P3, P4, P5, P6, P7, P8 > >
 Bidirectional mapping between util::CallbackR8 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR9< R, P1, P2, P3, P4, P5, P6, P7, P8, P9 > >
 Bidirectional mapping between util::CallbackR9 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR10< R, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10 > >
 Bidirectional mapping between util::CallbackR10 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR11< R, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11 > >
 Bidirectional mapping between util::CallbackR11 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR12< R, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12 > >
 Bidirectional mapping between util::CallbackR12 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR13< R, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13 > >
 Bidirectional mapping between util::CallbackR13 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR14< R, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14 > >
 Bidirectional mapping between util::CallbackR14 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< util::CallbackR15< R, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15 > >
 Bidirectional mapping between util::CallbackR15 and a Python callable object. More...
 
struct  lass::python::PyExportTraits< T >
 by copy, general case assumes shadow type or PyObjectPlus based type. More...
 
struct  lass::python::PyExportTraits< const T >
 constant objects can only be build. More...
 
struct  lass::python::PyExportTraits< util::SharedPtr< T, S, C > >
 SharedPtr assumes shadow types or PyObjectPlus types. More...
 
struct  lass::python::PyExportTraits< TPyObjPtr >
 A shared PyObject pointer is mapped to Any in Python. More...
 
struct  lass::python::PyExportTraits< std::unique_ptr< T, Deleter > >
 std::unique_ptr assumes shadow types More...
 
struct  lass::python::PyExportTraits< std::shared_ptr< T > >
 std::shared_ptr assumes shadow types. More...
 
struct  lass::python::PyExportTraitsNoNone< T >
 Helper class to create PyExportTraits for NoNone wrapped types. More...
 
struct  lass::python::PyExportTraits< NoNone< T * > >
 NoNone<T*> type-hints as T and refuses None as value. More...
 
struct  lass::python::PyExportTraits< NoNone< util::SharedPtr< T, S, C > > >
 Type-hints NoNone<util::SharedPtr<T>> as T and refuses None as value. More...
 
struct  lass::python::PyExportTraits< NoNone< std::shared_ptr< T > > >
 NoNone<std::shared_ptr<T>> type-hints as T and refuses None as value. More...
 
struct  lass::python::PyExportTraitsMaybeNone< T >
 Helper class to create PyExportTraits for MaybeNone wrapped types. More...
 
struct  lass::python::PyExportTraits< MaybeNone< T * > >
 MaybeNone<T*> type-hints a type as T | MaybeNone More...
 
struct  lass::python::PyExportTraits< MaybeNone< util::SharedPtr< T, S, C > > >
 MaybeNone<util::SharedPtr<T>> type-hints a type as T | MaybeNone More...
 
struct  lass::python::PyExportTraits< MaybeNone< std::shared_ptr< T > > >
 MaybeNone<std::shared_ptr<T>> type-hints a type as T | MaybeNone More...
 
struct  lass::python::PyExportTraits< Self< T > >
 Self<T> type-hints as Self. More...
 
struct  lass::python::PyExportTraitsSigned< Integer >
 Helper class to create PyExportTraits for signed integers. More...
 
struct  lass::python::PyExportTraits< signed char >
 signed char is mapped to Python int More...
 
struct  lass::python::PyExportTraits< signed short >
 signed short is mapped to Python int More...
 
struct  lass::python::PyExportTraits< signed int >
 signed int is mapped to Python int More...
 
struct  lass::python::PyExportTraits< signed long >
 signed long is mapped to Python int More...
 
struct  lass::python::PyExportTraitsUnsigned< Integer >
 Helper class to create PyExportTraits for unsigned integers. More...
 
struct  lass::python::PyExportTraits< unsigned char >
 unsigned char is mapped to Python int More...
 
struct  lass::python::PyExportTraits< unsigned short >
 unsigned short is mapped to Python int More...
 
struct  lass::python::PyExportTraits< unsigned int >
 unsigned int is mapped to Python int More...
 
struct  lass::python::PyExportTraits< unsigned long >
 unsigned long is mapped to Python int More...
 
struct  lass::python::PyExportTraitsFloat< Float >
 Helper class to create PyExportTraits for floating point numbers. More...
 
struct  lass::python::PyExportTraits< float >
 float is mapped to Python float type, which is a C double. More...
 
struct  lass::python::PyExportTraits< double >
 double is mapped to Python float type, which is also a C double. More...
 
struct  lass::python::PyExportTraits< long double >
 long double is mapped to Python float type, which is a C double. More...
 
struct  lass::python::PyExportTraits< std::complex< T > >
 std::complex<T> is always mapped to Python complex type. More...
 
struct  lass::python::PyExportTraits< std::basic_string_view< T > >
 std::basic_string_view<T> is mapped to Python str More...
 
struct  lass::python::PyExportTraits< const char16_t * >
 UTF-16 const char16_t* string is mapped to Python str | None, as it can be null. More...
 
struct  lass::python::PyExportTraits< std::u16string >
 UTF-16 std::u16string is mapped to str More...
 
struct  lass::python::PyExportTraits< const char32_t * >
 UTF-32 const char32_t* string is mapped to Python str | None, as it can be null. More...
 
struct  lass::python::PyExportTraits< std::u32string >
 UTF-32 std::u32string is mapped to str More...
 
struct  lass::python::PyExportTraits< std::chrono::duration< Rep, Period > >
 std::chrono::duration is mapped on datetime.timedelta by copy. More...
 
struct  lass::python::PyExportTraits< std::chrono::time_point< std::chrono::system_clock > >
 std::chrono::time_point<std::chrono::system_clock> is mapped on a timezone-unaware datetime.datetime instance by copy, in local time. More...
 
struct  lass::python::PyExportTraits< std::chrono::utc_clock::time_point >
 std::chrono::utc_clock::time_point is mapped on a timezone-aware datetime.datetime instance by copy, in UTC. More...
 
struct  lass::python::PyExportTraits< std::chrono::gps_clock::time_point >
 std::chrono::gps_clock::time_point is mapped on a timezone-aware datetime.datetime instance by copy, in UTC. More...
 
struct  lass::python::PyExportTraits< std::chrono::tai_clock::time_point >
 std::chrono::tai_clock::time_point is mapped on a timezone-aware datetime.datetime instance by copy, in UTC. More...
 
struct  lass::python::PyExportTraits< std::chrono::file_clock::time_point >
 std::chrono::file_clock::time_point is mapped on a timezone-aware datetime.datetime instance by copy, in UTC. More...
 
struct  lass::python::PyExportTraits< std::chrono::year_month_day >
 std::chrono::year_month_day is mapped on a datetime.date instance by copy. More...
 
struct  lass::python::PyExportTraits< std::function< R(Args...)> >
 Bidirectional wrapper between Callable objects and std::function. More...
 
struct  lass::python::PyExportTraits< std::optional< T > >
 Uses None to represent a std::optional without value. More...
 
struct  lass::python::PyExportTraits< MaybeNone< std::optional< T > > >
 MaybeNone<std::optional<T>> type-hints a type as T | MaybeNone More...
 
struct  lass::python::PyExportTraits< prim::Vector2D< T > >
 Maps prim::Vector2D<T> to a Python tuple of two elements of type T. More...
 
struct  lass::python::PyExportTraits< prim::Vector3D< T > >
 Maps prim::Vector3D<T> to a Python tuple of three elements of type T. More...
 
struct  lass::python::PyExportTraits< prim::Vector4D< T > >
 Maps prim::Vector4D<T> to a Python tuple of four elements of type T. More...
 
struct  lass::python::PyExportTraits< prim::Point2D< T > >
 Maps prim::Point2D<T> to a Python tuple of two elements of type T. More...
 
struct  lass::python::PyExportTraits< prim::Point3D< T > >
 Maps prim::Point3D<T> to a Python tuple of three elements of type T. More...
 
struct  lass::python::PyExportTraits< prim::Aabb2D< T, MMP > >
 Maps prim::Aabb2D<T> to a Python tuple of two tuples of two elements of type T. More...
 
struct  lass::python::PyExportTraits< prim::Aabb3D< T, MMP > >
 Maps prim::Aabb3D<T> to a Python tuple of two tuples of three elements of type T. More...
 
struct  lass::python::PyExportTraits< prim::LineSegment2D< T, PP > >
 Maps prim::LineSegment2D<T> to a Python tuple of two tuples of two elements of type T. More...
 
struct  lass::python::PyExportTraits< prim::LineSegment3D< T, PP > >
 Maps prim::LineSegment3D<T> to a Python tuple of two tuples of three elements of type T. More...
 
struct  lass::python::PyExportTraits< prim::Transformation2D< T > >
 Maps prim::Transformation2D<T> to a Python tuple of three tuples of three elements of type T. More...
 
struct  lass::python::PyExportTraits< prim::Transformation3D< T > >
 Maps prim::Transformation3D<T> to a Python tuple of four tuples of four elements of type T. More...
 
struct  lass::python::PyExportTraits< prim::SimplePolygon2D< T, DP > >
 Maps prim::SimplePolygon2D<T> to a Python sequence of tuples of two elements of type T. More...
 
struct  lass::python::PyExportTraits< prim::SimplePolygon3D< T, DP > >
 Maps prim::SimplePolygon3D<T> to a Python sequence of tuples of three elements of type T. More...
 
struct  lass::python::PyExportTraits< prim::XY >
 Maps prim::XY to a Python string literal "x" or "y". More...
 
struct  lass::python::PyExportTraits< prim::XYZ >
 Maps prim::XYZ to a Python string literal "x", "y" or "z". More...
 
struct  lass::python::PyExportTraits< prim::XYZW >
 Maps prim::XYZW to a Python string literal "x", "y", "z" or "w". More...
 
struct  lass::python::PyExportTraits< prim::ColorRGBA >
 Maps prim::ColorRGBA to a Python tuple of four elements of type float. More...
 
struct  lass::python::PyExportTraits< prim::IndexTriangle >
 Maps prim::IndexTriangle to a Python tuple of three index vertices. More...
 
struct  lass::python::PyExportTraits< std::pair< T1, T2 > >
 std::pair translates to a tuple by copy. More...
 
struct  lass::python::PyExportTraits< std::tuple< T... > >
 std::tuple translates to a tuple by copy. More...
 
struct  lass::python::PyExportTraits< PyIteratorRange * >
 Passes a PyIteratorRange to Python. More...
 
struct  lass::python::PyExportTraits< ContainerRangeView< SelfType, ValueType > >
 Builds a PyIteratorRange from a ContainerRangeView. More...
 
struct  lass::python::PyExportTraits< MemberRangeView< SelfType, ValueType, GetIterator > >
 Builds a PyIteratorRange from a MemberRangeView. More...
 
struct  lass::python::PyExportTraits< FreeRangeView< SelfType, ValueType, GetIterator > >
 Builds a PyIteratorRange from a FreeRangeView. More...
 
struct  lass::python::PyExportTraits< IndexedRangeView< SelfType, ValueType, SizeType, AtMethod, SizeMethod > >
 Builds a PyIteratorRange from a IndexedRangeView. More...
 
struct  lass::python::PyExportTraits< FreeIndexedRangeView< SelfType, ValueType, SizeType, AtFunc, SizeFunc > >
 Builds a PyIteratorRange from a FreeIndexedRangeView. More...
 
struct  lass::python::PyExportTraitsEnum< EnumType, IntegerType >
 Helper to specialise PyExportTraits for enumerations. More...