.. _gendata: Generator Customization ======================= Because semiwrap'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 semiwrap are customizable. .. note:: semiwrap 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 ------------------------------ By default customization files are located in the ``semiwrap`` directory. The name of the YAML file is the ``key`` in the extension module headers table: .. code-block:: toml [tool.semiwrap.extension_modules."PACKAGE.NAME".headers] # yaml file is `semiwrap/demo.yml` demo = "include/demo.h" Autogeneration -------------- The default values for these YAML files should be generated via the semiwrap command line tool: .. code-block:: sh semiwrap update-yaml --write This can be a good way to get the boilerplate out of the way when you need to provide customizations. Manual pybind11 APIs -------------------- You can write your own custom .cpp files and add them to the python extensions generated by semiwrap. In your ``meson.build`` after you include the generated ``semiwrap`` subdir, add files to ``NAME_sources``. .. code-block:: meson subdir('semiwrap') my_module_sources += files( 'src/my_module/main.cpp', ) Name transforms --------------- Generated Python names for functions, methods, attributes/properties, enum values, and function/method parameters can be configured with ``name_transform``. Explicit ``rename`` entries are final and are not transformed. Explicit ``param_override`` ``name`` entries are also final and are not transformed. Precedence is: #. YAML ``name_transform`` #. ``[tool.semiwrap.extension_modules."pkg.name"].name_transform`` #. ``[tool.semiwrap].name_transform`` #. built-in ``default`` behavior ``name_transform`` may be a string or a mapping. String form applies to all transformable kinds, including enum values: .. code-block:: yaml name_transform: snake_case Mapping form can configure each kind separately: .. code-block:: yaml name_transform: default: snake_case method: camelCase attribute: none enum_value: PascalCase parameter: snake_case Mapping keys are ``default``, ``function``, ``method``, ``attribute``, ``enum_value``, ``parameter``, and ``known_words``. The ``known_words`` key is a list of strings; the other keys are transform specs. Missing kind-specific keys use ``default``. Mapping values merge across precedence levels, so a YAML file can override only one kind while preserving project-level settings. A string value applies to every kind at that precedence level. Built-in transform names are: * ``none``: passes the C++ name directly through without changing case. * ``default``: function and method names lowercase the first character unless the first two characters are uppercase, while attribute, enum value, and parameter names are unchanged. * ``camelCase``: converts names to lower camel case, such as ``GetFoo`` or ``get_foo`` becoming ``getFoo``. * ``snake_case``: converts names to lowercase words separated by underscores, such as ``GetFoo`` or ``getFoo`` becoming ``get_foo``. * ``PascalCase``: converts names to upper camel case, such as ``getFoo`` or ``get_foo`` becoming ``GetFoo``. * ``kCamelCase``: converts names to ``k`` followed by upper camel case, such as ``getFoo`` or ``get_foo`` becoming ``kGetFoo``. When transforming from names like ``kGetFoo``, the leading ``k`` prefix is ignored by built-in case splitting. * ``CAPS_CASE``: converts names to uppercase words separated by underscores, such as ``GetFoo`` or ``getFoo`` becoming ``GET_FOO``. You may also specify a python function to perform custom transform logic. Custom transforms use ``custom: package.name:function`` and receive ``(name: str, kind: str)`` where kind is ``function``, ``method``, ``attribute``, ``enum_value``, or ``parameter``. Enum value transforms run after semiwrap's existing enum value prefix stripping. ``rename`` on an enum value remains exact and is not transformed. Parameter transforms apply to generated Python argument names used in ``py::arg``. They do not change C++ local variable names or the C++ parameter names used as ``param_override`` keys. ``param_override`` ``name`` values remain exact and are not transformed. Known word splitting ~~~~~~~~~~~~~~~~~~~~ Built-in case transforms can split names using a case-sensitive list of known words. Configure project defaults in ``pyproject.toml`` with the ``known_words`` key under ``[tool.semiwrap.name_transform]``: .. code-block:: toml [tool.semiwrap.name_transform] default = "snake_case" known_words = ["KiB", "mDNS"] A YAML file can replace the project known word list for one header with a top-level ``known_words`` key: .. code-block:: yaml name_transform: snake_case known_words: [KiB, mDNS] When a YAML file omits ``known_words``, it uses the project known word list. When a YAML file specifies ``known_words: []``, it uses no known words for that header. Known word matching is case-sensitive and prefers the longest configured known word at each position. For example, with ``KiB`` configured, ``GetKiBValue`` becomes ``get_kib_value`` under ``snake_case`` instead of ``get_ki_b_value``. Reference --------- The following structures describe the dictionaries that are read from the YAML files. The toplevel structure is :class:`.AutowrapConfigYaml`. .. autoclass:: semiwrap.name_transform.NameTransformConfig :members: .. automodule:: semiwrap.config.autowrap_yml :members: