Git Product home page Git Product logo

cpp-pybind11-playground's Introduction

pybind11 as a scripting engine

This tutorial explains in 14 steps how to use pybind11 for creating a Python scripting engine for a Qt application.

It first explains how to create a module that can be imported in Python, continues by prosenting different aspects of running inside of a C++ (Qt) application a Python script that can access (and modify) the status of the main application.

Each step contains code that can be individually compiled, run, and – of course – modified.

You should probably go through each step in the order presented below, since the commands are (briefly) introduced only once.

Getting pybind11

There are three ways for getting pybind11:

  • Embedding it in your project as a Git submodule.
  • Installing pybind11 through your package manager (or downloading binaries that are installed in the system path).
    • In 2023, in Debian Testing you need to install pybind11-dev and python3-pybind11.
  • Compiling pybind11 in a separate directory.

The samples in this repositories use a pre-compiled version of pybind11. If you're not getting pybind11 from your distribution repositories:

  • get the code from github
  • compile it:
    • mkdir build && cd build
    • cmake -D CMAKE_INSTALL_PREFIX=/the/prefix/where/you/install/pybind11 -D PYBIND11_TEST=OFF ..
    • make install

The pybind11 authors prefer adding pybind11 as a git sub-project: you can of course follow their instruction and adapt the CMakeLists.txt files in this repository.

The development environment

You need:

  • a development environment for C++ (g++ or clang; cmake, ...)
  • the Python bindings (libpython3-dev, python-cxx-dev, ...)

Our first example directly uses the compiler, all other examples will need a modern version of cmake being installed (pybind11 needs cmake 3.4)

Sample projects

  • add/: create a module providing a C++ add function that can be add two numbers.
  • add-cmake: the first example with CMake (all further examples use CMake).
  • classes/: let Python use C++ classes.
  • eval-file/: C++ evaluates a Python script in an external files that modifies the state of a C++ variable.
  • eval-set-object/: Create two objects of type Foo and pass them by value or by reference to a Python script (defined as a string in the C++ code)
  • eval-set-object-module/: Create a .so module for the Foo type, load it in the Python interpreter and let the Python script access it.
  • eval-file-pyqt5/: The C++ code runs an external Python script that shows a PyQt5 alert.
  • eval-file-pyqt5-set-value/: Setting a C++ value from a PyQt5 input dialog.
  • ...

Links

Notes

alternatives

  • cppy is an automatic Python-C++ bindings generator designed for large scale programs in high performance computing that use modern C++.

todo

  • adapt all CMakeLists.txt files to require Python 3.7. (eval-set-object-module does somehow require it)
  • use pyside2 on top of pyqt5
  • can python use the c++ qt widgets (add an entry to the menus, add keyboard shortcuts); can we have callbacks back to python code from the c++ app?
  • in the qt5-pyqt example there is a "visibility" warning.
  • Try to add a menu entry from pyqt5
  • Try with PySide2

Document all directories:

  • add
  • add-cmake
  • classes
  • eval-file
  • eval-set-object
  • eval-set-object-module
  • eval-file-pyqt5
  • eval-file-pyqt5-set-value
  • scripter-api
  • scripter-class
  • scripter-class-in-class
  • scripting
  • scripting-pyqt5
  • qt5-pyqt5

open questions:

  • how to pass sys.argv to the QApplication() in eval-file-pyqt5/python/pyqt5.py

cpp-pybind11-playground's People

Contributors

ale-ditoy avatar aoloe avatar galou avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

cpp-pybind11-playground's Issues

Reference-counting pointers

I am opening this issue to discuss how to use pointers in the Python scripter. The problem I see is that scribus uses raw pointers internally, so the wrapper has to use those as well (of course this involves risky things, such as objects being deleted while the scriper is active). There is no way to use managed pointers (shared_ptr and similar, also including unique_ptr) when some parts of the code don't use them.

So the way is either to start using shared_ptr inside scribus (that would be my idea, but it is a huge change for the whole code), they integrate beautifully with python reference counting. This is high-performance computing code https://woodem.org/ using shared_ptr and is entirely scriptable in python. The advantage is that Python can go as deep into the internal structures as desired.

Another options is that the scripter will use raw pointers (perhaps wrapped in lightweight wrapperss) and assume that the underlying document will never change while the script is running, so that none of the pointers becomes stale, leading to Python crashing.

access DocumentAPI / Document in ScripterAPI / Sample

when running

https://github.com/aoloe/cpp-pybind11-playground/blob/master/scripter-api/python/set-bar.py

print(Sample.a)
document = Sample.document
print(document.a)

i get this error message:

terminate called after throwing an instance of 'pybind11::error_already_set'
  what():  TypeError: Unable to convert function return value to a Python type! The signature was
        (self: scripterapi.Sample) -> ScripterAPI::Document

At:
  ../python/set-bar.py(7): <module>

the offending line is document = Sample.document.

the Sample and the Document classes for the API are defined here:

https://github.com/aoloe/cpp-pybind11-playground/tree/master/scripter-api/src/scripterAPI

Imports not working in functions, classes

Dear developers,
I am new in pybind11 and I encountered following simple problem: consider the example "eval-file" - if I change the script "set-the-y.py" as follows:

import sys

def print_version():
	print(sys.version)

print_version()

set_the_answer(y - 1)

I got an error in function 'print_version'

NameError: name 'sys' is not defined

This is very strange for me, please can anybody explain me what is wrong? How to make the code above operational?
Thank you in advance for your replies! Susnicek

Typo in classes example

The description for getName member function is placed out of the def invocation:

.def("getName", &Dog::getName), "Getting the dog's name";

However the compiler ignores that description and the example works:

[ 50%] Building CXX object CMakeFiles/pet.dir/src/main.cpp.o
classes/src/main.cpp:38:37: warning: expression result unused [-Wunused-value]
    .def("getName", &Dog::getName), "Getting the dog's name";
                                    ^~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
[100%] Linking CXX shared module pet.cpython-39-darwin.so
[100%] Built target pet

sharing the document between the c++ application, the API and the python script

  • the c++ application might or not have an open document.
  • if there is an open document, it's shared with the API.
  • the API can modify the document.
  • while the script is running, the C++ application is not allowed to modify the document(s).
  • (eventually, trough the API it should be possible to change the current document to any other open document)
  • through the API, it should be possible to open documents / create new documents.
  • (eventually, the document will be left open when the script is finished)

in https://github.com/aoloe/cpp-pybind11-playground/tree/master/scripter-api i have a Sample::Document which is the document in the Sample C++ application and a ScripterAPI::Document which will be used to create the module for Python.

i'm now looking for a good (modern) way of managing the sharing of the Sample::Document...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.