Generator Customization

Because robotpy-build’s code generation is intended to be a semi-automated process (except for simple C++ code), a rich set of per-{class/function/parameter} configuration options can be specified in per-file YAML configurations.

Additionally, some headers are too complex for the autogenerator to completely process, so when this occurs you must manually specify required information in the YAML file.

Most files generated by robotpy-build are customizable.

Note

robotpy-build is designed for the RobotPy project and may contain defaults that aren’t appropriate for all projects. If you find that you need more customization, file an issue on github and let’s talk about it!

Location of customization file

In your pyproject.toml, you can specify either a single YAML file with customizations, or you can specify a directory that robotpy-build will search for YAML files.

Single file:

[tool.robotpy-build.wrappers."PACKAGENAME"]
generation_data = "gen/data.yml"

Multiple files:

[tool.robotpy-build.wrappers."PACKAGENAME"]
generation_data = "gen"

When a directory is specified, pybind11 will search for YAML files in the directory based on the header filename. In the above example, customization data for header.h could be specified in gen/header.yml.

Autogeneration

The default values for these YAML files can be generated via the robotpy-build command line tool:

robotpy-build create-gen --write

This can be a good way to get the boilerplate out of the way when you need to provide customizations.

Reference

The following strctures describe the dictionaries that are read from the YAML file. The toplevel structure is HooksDataYaml.

class robotpy_build.hooks_datacfg.BufferData
len: str

Name of the C++ length parameter. An out-only parameter, it will be set to the size of the python buffer, and will be returned so the caller can determine how many bytes were written

Type

str

minsz: Optional[int] = None

If specified, the minimum size of the python buffer

Type

Optional[int]

src: str

Name of C++ parameter that the buffer will use

Type

str

type: robotpy_build.hooks_datacfg.BufferType

Indicates what type of python buffer is required

Type

BufferType

class robotpy_build.hooks_datacfg.BufferType(value)

An enumeration.

IN = 'in'

The buffer must indicate that it is readable (such as bytes, or bytearray)

INOUT = 'inout'

The buffer must indicate that it readable or writeable (such as a bytearray)

OUT = 'out'

The buffer must indicate that it is writeable (such as a bytearray)

class robotpy_build.hooks_datacfg.ClassData
attributes: Dict[str, robotpy_build.hooks_datacfg.PropData] = {}
Type

Dict[str, PropData]

base_qualnames: Dict[str, str] = {}

Specify fully qualified names for the bases

Type

Dict[str, str]

constants: List[str] = []

Extra constexpr to insert into the trampoline and wrapping scopes

Type

List[str]

doc: Optional[str] = None

Docstring for the class

Type

Optional[str]

enums: Dict[str, robotpy_build.hooks_datacfg.EnumData] = {}
Type

Dict[str, EnumData]

force_depends: List[str] = []

If there are circular dependencies, this will help you resolve them manually. TODO: make it so we don’t need this

Type

List[str]

force_no_default_constructor: bool = False
Type

bool

force_no_trampoline: bool = False
Type

bool

force_type_casters: List[str] = []

Use this to bring in type casters for a particular type that may have been hidden (for example, with a typedef or definition in another file), instead of explicitly including the header. This should be the full namespace of the type.

Type

List[str]

ignore: bool = False
Type

bool

ignored_bases: List[str] = []
Type

List[str]

is_polymorphic: bool = False
Type

bool

methods: Dict[str, robotpy_build.hooks_datacfg.FunctionData] = {}
Type

Dict[str, FunctionData]

nodelete: bool = False

If the object shouldn’t be deleted by pybind11, use this. Disables implicit constructors.

Type

bool

rename: Optional[str] = None

Set the python name of the class to this

Type

Optional[str]

shared_ptr: bool = True

If the type was created as a shared_ptr (such as via std::make_shared) then pybind11 needs to be informed of this.

https://github.com/pybind/pybind11/issues/1215

One way you can tell we messed this up is if there’s a double-free error and the stack trace involves a unique_ptr destructor

Type

bool

subpackage: Optional[str] = None

If specified, put the class in a sub.pack.age. Ignored for functions attached to a class. When template parameters are used, must define subpackage on template instances instead

Type

Optional[str]

template_inline_code: str = ''

If this is a template class, the specified C++ code is inserted into the template definition

Type

str

template_params: Optional[List[str]] = None

If this is a template class, a list of the parameters if it can’t be autodetected (currently can’t autodetect). If there is no space in the parameter, then it is assumed to be a ‘typename’, otherwise the parameter is split by space and the first item is the type and the second parameter is the name (useful for integral templates)

Type

Optional[List[str]]

typealias: List[str] = []

Extra ‘using’ directives to insert into the trampoline and the wrapping scope

Type

List[str]

classmethod validate_attributes(value)
classmethod validate_enums(value)
classmethod validate_methods(value)
class robotpy_build.hooks_datacfg.EnumData
doc: Optional[str] = None

Set your own docstring for the enum

Type

Optional[str]

ignore: bool = False

If set to True, this property is not made available to python

Type

bool

rename: Optional[str] = None

Set the python name of this enum to the specified string

Type

Optional[str]

subpackage: Optional[str] = None

If specified, put the enum in a sub.pack.age (ignored for enums that are part of classes)

Type

Optional[str]

value_prefix: Optional[str] = None
Type

Optional[str]

values: Dict[str, robotpy_build.hooks_datacfg.EnumValue] = {}
Type

Dict[str, EnumValue]

class robotpy_build.hooks_datacfg.EnumValue
doc: Optional[str] = None

Docstring for the enum value

Type

Optional[str]

ignore: bool = False

If set to True, this property is not made available to python

Type

bool

rename: Optional[str] = None

Set the python name of this enum value to the specified string

Type

Optional[str]

class robotpy_build.hooks_datacfg.FunctionData

Customize the way the autogenerator binds a function.

functions:
  # for non-overloaded functions, just specify the name + customizations
  name_of_non_overloaded_fn:
    # add customizations for function here

  # For overloaded functions, specify the name, but each overload
  # separately
  my_overloaded_fn:
    overloads:
      int, int:
        # customizations for `my_overloaded_fn(int, int)`
      int, int, int:
        # customizations for `my_overloaded_fn(int, int, int)`
buffers: List[robotpy_build.hooks_datacfg.BufferData] = []
Type

List[BufferData]

cpp_code: Optional[str] = None

Use this code instead of the generated code

Type

Optional[str]

doc: Optional[str] = None

Docstring for the function

Type

Optional[str]

ifdef: Optional[str] = None

Generate this in an #ifdef

Type

Optional[str]

ifndef: Optional[str] = None

Generate this in an #ifndef

Type

Optional[str]

ignore: bool = False

If True, don’t wrap this

Type

bool

ignore_pure: bool = False

If True, don’t wrap this, but provide a pure virtual implementation

Type

bool

internal: bool = False

If True, prepends an underscore to the python name

Type

bool

keepalive: Optional[List[Tuple[int, int]]] = None

Adds py::keep_alive<x,y> to the function. Overrides automatic keepalive support, which retains references passed to constructors. https://pybind11.readthedocs.io/en/stable/advanced/functions.html#keep-alive

Type

Optional[List[Tuple[int, int]]]

no_release_gil: Optional[bool] = None

By default, robotpy-build will release the GIL whenever a wrapped function is called.

Type

Optional[bool]

overloads: Dict[str, robotpy_build.hooks_datacfg.FunctionData] = {}
Type

Dict[str, FunctionData]

param_override: Dict[str, robotpy_build.hooks_datacfg.ParamData] = {}

Mechanism to override individual parameters

Type

Dict[str, ParamData]

rename: Optional[str] = None

Use this to set the name of the function as exposed to python

Type

Optional[str]

return_value_policy: robotpy_build.hooks_datacfg.ReturnValuePolicy = 'automatic'

https://pybind11.readthedocs.io/en/stable/advanced/functions.html#return-value-policies

Type

ReturnValuePolicy

subpackage: Optional[str] = None

If specified, put the function in a sub.pack.age

Type

Optional[str]

template_impls: Optional[List[List[str]]] = None

If this is a function template, this is a list of instantiations that you wish to provide. This is a list of lists, where the inner list is the template parameters for that function

Type

Optional[List[List[str]]]

classmethod validate_overloads(value)
virtual_xform: Optional[str] = None

Specify a transformation lambda to be used when this virtual function is called from C++. This inline code should be a lambda that has the same arguments as the original C++ virtual function, except the first argument will be a py::function with the python overload

cpp_code should also be specified for this to be useful

For example, to transform a function that takes an iostream into a function that returns a string:

cpp_code: |
  [](MyClass* self) {
    return "string";
  }
virtual_xform: |
  [](py::function fn, MyClass* self, std::iostream &is) {
     std::string d = py::cast(fn());
     is << d;
  }
Type

Optional[str]

class robotpy_build.hooks_datacfg.HooksDataYaml

Format of the file in [tool.robotpy-build.wrappers.”PACKAGENAME”] generation_data

attributes: Dict[str, robotpy_build.hooks_datacfg.PropData] = {}

Key is the attribute (variable) name

attributes:
  my_variable:
    # customizations here, see PropData
Type

Dict[str, PropData]

classes: Dict[str, robotpy_build.hooks_datacfg.ClassData] = {}

Key is the class name

classes:
  CLASSNAME:
    # customizations here, see ClassData
Type

Dict[str, ClassData]

enums: Dict[str, robotpy_build.hooks_datacfg.EnumData] = {}

Key is the enum name, for enums at global scope

enums:
  MyEnum:
    # customizations here, see EnumData
Type

Dict[str, EnumData]

extra_includes: List[str] = []

Adds #include <FILENAME> directives to the top of the autogenerated C++ file, after autodetected include dependencies are inserted.

Type

List[str]

extra_includes_first: List[str] = []

Adds #include <FILENAME> directives after robotpy_build.h is included, but before any autodetected include dependencies. Only use this when dealing with broken headers.

Type

List[str]

functions: Dict[str, robotpy_build.hooks_datacfg.FunctionData] = {}

Key is the function name

functions:
  fn_name:
    # customizations here, see FunctionData
Type

Dict[str, FunctionData]

inline_code: Optional[str] = None

Specify raw C++ code that will be inserted at the end of the autogenerated file, inside a function. This is useful for extending your classes or providing other customizations. The following C++ variables are available:

  • m is the py::module instance

  • cls_CLASSNAME are py::class instances

  • … lots of other things too

To see the full list, run a build and look at the generated code at build/*/gensrc/**/*.cpp

Recommend that you use the YAML multiline syntax to specify it:

inline_code: |
  cls_CLASSNAME.def("get42", []() { return 42; });
Type

Optional[str]

strip_prefixes: List[str] = []
Type

List[str]

templates: Dict[str, robotpy_build.hooks_datacfg.TemplateData] = {}

Instantiates a template. Key is the name to give to the Python type.

templates:
  ClassName:
    # customizations here, see TemplateData
Type

Dict[str, TemplateData]

classmethod validate_attributes(value)
classmethod validate_classes(value)
classmethod validate_enums(value)
classmethod validate_functions(value)
class robotpy_build.hooks_datacfg.ParamData

Various ways to modify parameters

array_size: Optional[int] = None

Force an array size

Type

Optional[int]

default: Optional[str] = None

Default value for parameter

Type

Optional[str]

force_out: bool = False

Force this to be an ‘out’ parameter

See also

Out parameters

Type

bool

ignore: bool = False

Ignore this parameter

Type

bool

name: Optional[str] = None

Set parameter name to this

Type

Optional[str]

x_type: Optional[str] = None

Change C++ type emitted

Type

Optional[str]

class robotpy_build.hooks_datacfg.PropAccess(value)

An enumeration.

AUTOMATIC = 'auto'

Determine read/read-write automatically:

  • If a struct/union, default to readwrite

  • If a class, default to readwrite if a basic type that isn’t a reference, otherwise default to readonly

READONLY = 'readonly'

Allow python users access to the value, but ensure it can’t change. This is useful for properties that are defined directly in the class

READWRITE = 'readwrite'

Allows python users to read/write the value

class robotpy_build.hooks_datacfg.PropData
access: robotpy_build.hooks_datacfg.PropAccess = 'auto'

Python code access to this property

Type

PropAccess

doc: Optional[str] = None

Docstring for the property (only available on class properties)

Type

Optional[str]

ignore: bool = False

If set to True, this property is not made available to python

Type

bool

rename: Optional[str]

Set the python name of this property to the specified string

Type

Optional[str]

class robotpy_build.hooks_datacfg.ReturnValuePolicy(value)

See pybind11 documentation for what each of these values mean.

AUTOMATIC = 'automatic'
AUTOMATIC_REFERENCE = 'automatic_reference'
COPY = 'copy'
MOVE = 'move'
REFERENCE = 'reference'
REFERENCE_INTERNAL = 'reference_internal'
TAKE_OWNERSHIP = 'take_ownership'
class robotpy_build.hooks_datacfg.TemplateData

Instantiates a template as a python type. To customize the class, add it to the classes key and specify the template type.

Code to be wrapped:

template <typename T>
class MyClass {};

To bind MyClass<int> as the python class MyIntClass, add this to your YAML:

classes:
  MyClass:
    template_params:
    - T

templates:
  MyIntClass:
    qualname: MyClass
    params:
    - int
params: List[str]

Template parameters to use

Type

List[str]

qualname: str

Fully qualified name of instantiated class

Type

str

subpackage: Optional[str] = None

If specified, put the template instantiation in a sub.pack.age

Type

Optional[str]