pybind / pybind/pybind11

Enhancement: allow method definition with python code by an augmenting meta class

Open
#1,074 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
18k
Forks
2.3k
Avg merge
5d 17h
Merged PRs (30d)
10

Description

Issue description

Making it easy to define new methods for pybind11 generated classes, in Python code instead of in C++ code, and without actually creating new subclasses.

Reproducible example code

I come across this enhancement implemented by a meta class:

from . import core

# must derive from pybind11's default meta class
class AugmentCxxClass(core.PerfPack.__class__):
    """
    Make it easy to define new methods for pybind11 generated classes, in Python code instead of in C++ code,
    and without actually creating new subclasses.
    """

    def __new__(cls, name, bases, namespace, **kwds):
        assert len(bases) == 1, 'Augment multiple classes at same time ?!'
        for k, v in namespace.items():
            if k in ('__module__', '__qualname__'):
                continue
            for tcls in bases:
                setattr(tcls, k, v)
        return bases[0]

Then for my bound C++ class Freq, I can neatly augment it with python code and re-export it from the outer python module:

class Freq(core.Freq, metaclass=AugmentCxxClass):
    # preserve generated docstring by not defining one here

    def __repr__(self):
        return f'as_freq({self.nomenclature!r})'

    def __str__(self):
        return self.nomenclature

    def __int__(self):
        return self.span

    def __eq__(self, other):
        if isinstance(other, Freq):
            return other.nomenclature == self.nomenclature
        return str(other) == self.nomenclature

This works well for me and I'd think it may be implemented as an official feature to benefit others. I tried to make this as a PR but failed to find home for such python code in current codebase, the blocker is how to obtain pybind11_builtins.pybind11_type to serve as AugmentCxxClass' base class, or errors will occur. Though it can be obtained from any pybind defined wrapper class, even works crossing extension modules. I currently use a separate dummy extension module defining the dummy PerfPack class.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the pybind11_builtins.pybind11_type dependency and the AugmentCxxClass example in the issue; compare how a bound class such as core.Freq is exposed across extension modules. Done means Python-side augmentation is supported officially without requiring a separate dummy extension module.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.