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 AutowrapConfigYaml
.
- class robotpy_build.config.autowrap_yml.AutowrapConfigYaml
Format of the file in [tool.robotpy-build.wrappers.”PACKAGENAME”] generation_data
-
attributes:
Dict
[str
,PropData
] = {} Key is the attribute (variable) name
attributes: my_variable: # customizations here, see PropData
-
classes:
Dict
[str
,ClassData
] = {} Key is the class name
classes: CLASSNAME: # customizations here, see ClassData
-
defaults:
Defaults
= FieldInfo(default=PydanticUndefined, default_factory=<class 'robotpy_build.config.autowrap_yml.Defaults'>, extra={})
-
encoding:
str
= 'utf-8-sig' Encoding to use when opening this header file
-
enums:
Dict
[str
,EnumData
] = {} Key is the enum name, for enums at global scope
enums: MyEnum: # customizations here, see EnumData
-
extra_includes:
List
[str
] = [] Adds
#include <FILENAME>
directives to the top of the autogenerated C++ file, after autodetected include dependencies are inserted.
-
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.
- classmethod from_file(fname)
- Return type:
-
functions:
Dict
[str
,FunctionData
] = {} Key is the function name
functions: fn_name: # customizations here, see 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 thepy::module
instancecls_CLASSNAME
arepy::class
instances… lots of other things too
The trampoline class (useful for accessing protected items) is available at
{CLASSNAME}_Trampoline
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; });
-
strip_prefixes:
List
[str
] = []
-
templates:
Dict
[str
,TemplateData
] = {} Instantiates a template. Key is the name to give to the Python type.
templates: ClassName: # customizations here, see TemplateData
-
typealias:
List
[str
] = [] Extra ‘using’ directives to insert into the trampoline and the wrapping scope
- classmethod validate_attributes(value)
- classmethod validate_classes(value)
- classmethod validate_enums(value)
- classmethod validate_functions(value)
-
attributes:
- class robotpy_build.config.autowrap_yml.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
-
minsz:
Optional
[int
] = None If specified, the minimum size of the python buffer
-
src:
str
Name of C++ parameter that the buffer will use
-
type:
BufferType
Indicates what type of python buffer is required
-
len:
- class robotpy_build.config.autowrap_yml.BufferType(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
- 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.config.autowrap_yml.ClassData
-
-
base_qualnames:
Dict
[str
,str
] = {} Specify fully qualified names for the bases. If the base has a template parameter, you must include it. Only needed if it can’t be automatically detected directly from the text.
-
constants:
List
[str
] = [] Fully-qualified pre-existing constant that will be inserted into the trampoline and wrapping scopes as a constexpr
-
doc:
Optional
[str
] = None Docstring for the class
-
doc_append:
Optional
[str
] = None Text to append to the (autoconverted) docstring
-
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
-
force_multiple_inheritance:
bool
= False pybind11 will detect multiple inheritance automatically if a class directly derives from multiple classes. However, If the class derives from classes that participate in multiple inheritance, pybind11 won’t detect it automatically, so this flag is needed.
-
force_no_default_constructor:
bool
= False
-
force_no_trampoline:
bool
= False
-
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.
-
ignore:
bool
= False
-
ignored_bases:
List
[str
] = [] List of bases to ignore. Name must include any template specializations.
-
inline_code:
Optional
[str
] = None This will insert code right before the semicolon ending the class py definition. You can use this to easily insert additional custom functions without using the global inline_code mechanism.
-
is_polymorphic:
Optional
[bool
] = None
-
methods:
Dict
[str
,FunctionData
] = {}
-
nodelete:
bool
= False If the object shouldn’t be deleted by pybind11, use this. Disables implicit constructors.
-
rename:
Optional
[str
] = None Set the python name of the class to this
This is deprecated and has no effect
-
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
-
template_inline_code:
str
= '' If this is a template class, the specified C++ code is inserted into the template definition
-
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)
-
trampoline_inline_code:
Optional
[str
] = None If this class has an associated trampoline, add this code inline at the bottom of the trampoline class. This is rarely useful.
-
typealias:
List
[str
] = [] Extra ‘using’ directives to insert into the trampoline and the wrapping scope
- classmethod validate_attributes(value)
- classmethod validate_enums(value)
- classmethod validate_methods(value)
-
base_qualnames:
- class robotpy_build.config.autowrap_yml.Defaults
Defaults to apply to everything
-
ignore:
bool
= False Set this to True to ignore functions/enums/classes at namespace scope by default if they aren’t present in the YAML
-
report_ignored_missing:
bool
= True If False and default ignore is True, don’t report missing items
-
ignore:
- class robotpy_build.config.autowrap_yml.EnumData
-
arithmetic:
bool
= False Tell pybind11 to create an enumeration that also supports rudimentary arithmetic and bit-level operations like comparisons, and, or, xor, negation, etc.
-
doc:
Optional
[str
] = None Set your own docstring for the enum
-
doc_append:
Optional
[str
] = None Text to append to the (autoconverted) docstring
-
ignore:
bool
= False If set to True, this property is not made available to python
-
inline_code:
Optional
[str
] = None This will insert code right before the semicolon ending the enum py definition. You can use this to easily insert additional custom values without using the global inline_code mechanism.
-
rename:
Optional
[str
] = None Set the python name of this enum to the specified string
-
subpackage:
Optional
[str
] = None If specified, put the enum in a sub.pack.age (ignored for enums that are part of classes)
-
value_prefix:
Optional
[str
] = None Remove this prefix from autogenerated enum value name
-
arithmetic:
- class robotpy_build.config.autowrap_yml.EnumValue
-
doc:
Optional
[str
] = None Docstring for the enum value
-
doc_append:
Optional
[str
] = None Text to append to the (autoconverted) docstring
-
ignore:
bool
= False If set to True, this property is not made available to python
-
rename:
Optional
[str
] = None Set the python name of this enum value to the specified string
-
doc:
- class robotpy_build.config.autowrap_yml.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
[BufferData
] = []
-
cpp_code:
Optional
[str
] = None Use this code instead of the generated code
-
disable_none:
Optional
[bool
] = None Disallow implicit conversions from None for all parameters. See also
disable_none
in ParamData.
-
doc:
Optional
[str
] = None Docstring for the function, will attempt to convert Doxygen docs if omitted
-
doc_append:
Optional
[str
] = None Text to append to the (autoconverted) docstring for the function
-
ifdef:
Optional
[str
] = None Generate this in an #ifdef
-
ifndef:
Optional
[str
] = None Generate this in an #ifndef
-
ignore:
bool
= False If True, don’t wrap this
-
ignore_pure:
bool
= False If True, don’t wrap this, but provide a pure virtual implementation
-
ignore_py:
bool
= False Most of the time, you will want to specify
ignore
instead.If True, don’t expose this function to python. If a trampoline is supposed to be generated, it will still be generated. You will likely want to use
trampoline_cpp_code
if you specify this.
-
internal:
bool
= False If True, prepends an underscore to the python name
-
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
-
no_release_gil:
Optional
[bool
] = None By default, robotpy-build will release the GIL whenever a wrapped function is called.
-
overloads:
Dict
[str
,FunctionData
] = {}
-
rename:
Optional
[str
] = None Use this to set the name of the function as exposed to python
-
return_value_policy:
ReturnValuePolicy
= 'automatic' https://pybind11.readthedocs.io/en/stable/advanced/functions.html#return-value-policies
-
subpackage:
Optional
[str
] = None If specified, put the function in a sub.pack.age
-
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
-
trampoline_cpp_code:
Optional
[str
] = None Specify custom C++ code for the virtual function trampoline
- classmethod validate_overloads(value)
- classmethod validate_virtual_xform(v, values)
-
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; }
-
buffers:
- class robotpy_build.config.autowrap_yml.ParamData
Various ways to modify parameters
-
array_size:
Optional
[int
] = None Force an array size
-
default:
Optional
[str
] = None Default value for parameter
-
disable_none:
Optional
[bool
] = None Disallow implicit conversions from None. This defaults to True for built in types and types that are obviously std::function (does not handle all cases, in which case this should be explicitly specified)
-
disable_type_caster_default_cast:
bool
= False Disables a default cast caused by
default_arg_cast
-
force_out:
bool
= False Force this to be an ‘out’ parameter
See also
-
ignore:
bool
= False Ignore this parameter
-
name:
Optional
[str
] = None Set parameter name to this
-
no_default:
Optional
[bool
] = False Disable default value
-
x_type:
Optional
[str
] = None Change C++ type emitted
-
array_size:
- class robotpy_build.config.autowrap_yml.PropAccess(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
- 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.config.autowrap_yml.PropData
-
access:
PropAccess
= 'auto' Python code access to this property
-
doc:
Optional
[str
] = None Docstring for the property (only available on class properties)
-
doc_append:
Optional
[str
] = None Text to append to the (autoconverted) docstring
-
ignore:
bool
= False If set to True, this property is not made available to python
-
rename:
Optional
[str
] = None Set the python name of this property to the specified string
-
access:
- class robotpy_build.config.autowrap_yml.ReturnValuePolicy(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
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.config.autowrap_yml.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 classMyIntClass
, add this to your YAML:classes: MyClass: template_params: - T templates: MyIntClass: qualname: MyClass params: - int
-
doc:
Optional
[str
] = None Set the docstring for the template instance
-
doc_append:
Optional
[str
] = None Text to append to the (autoconverted) docstring for the template instance
-
params:
List
[str
] Template parameters to use
-
qualname:
str
Fully qualified name of instantiated class
-
subpackage:
Optional
[str
] = None If specified, put the template instantiation in a sub.pack.age
-
doc: