Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use py::module_local() for Imath bindings #1323

Conversation

JeanChristopheMorinPerso
Copy link
Member

This PR fixes an issue reported in Slack (see https://academysoftwarefdn.slack.com/archives/CMQ9J4BQC/p1654121088621319).

The issue in question is that importing OpenTImelineIO in Katana would raise an import error like ImportError: generic_type: type "V2d" is already registered!.

The issue comes from the fact that Katana ships Python bindings for Imath made with Pybind11 and OTIO also provides parts of Imath using Pybind11.

The solution to this problem is to make the classes provided by OTIO module-local (see https://pybind11.readthedocs.io/en/stable/advanced/classes.html#module-local-class-bindings).

To quote the documentation:

When creating a binding for a class, pybind11 by default makes that binding “global” across modules. What this means is that a type defined in one module can be returned from any module resulting in the same Python type. For example, this allows the following:

// In the module1.cpp binding code for module1:
py::class_<Pet>(m, "Pet")
   .def(py::init<std::string>())
   .def_readonly("name", &Pet::name);
// In the module2.cpp binding code for module2:
m.def("create_pet", [](std::string name) { return new Pet(name); });
from module1 import Pet
from module2 import create_pet
pet1 = Pet("Kitty")
pet2 = create_pet("Doggy")
pet2.name()
'Doggy'

When writing binding code for a library, this is usually desirable: this allows, for example, splitting up a complex library into multiple Python modules.

In some cases, however, this can cause conflicts. For example, suppose two unrelated modules make use of an external C++ library and each provide custom bindings for one of that library’s classes. This will result in an error when a Python program attempts to import both modules (directly or indirectly) because of conflicting definitions on the external type:

// dogs.cpp

// Binding for external library class:
py::class<pets::Pet>(m, "Pet")
   .def("name", &pets::Pet::name);

// Binding for local extension class:
py::class<Dog, pets::Pet>(m, "Dog")
   .def(py::init<std::string>());
// cats.cpp, in a completely separate project from the above dogs.cpp.

// Binding for external library class:
py::class<pets::Pet>(m, "Pet")
   .def("get_name", &pets::Pet::name);

// Binding for local extending class:
py::class<Cat, pets::Pet>(m, "Cat")
   .def(py::init<std::string>());
import cats
import dogs
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
ImportError: generic_type: type "Pet" is already registered!

Using py::module_local() fixes that for us.

Signed-off-by: Jean-Christophe Morin <jean_christophe_morin@hotmail.com>
@codecov-commenter
Copy link

codecov-commenter commented Jun 4, 2022

Codecov Report

Merging #1323 (7c2fd78) into main (bc96625) will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #1323   +/-   ##
=======================================
  Coverage   86.17%   86.17%           
=======================================
  Files         195      195           
  Lines       19806    19806           
  Branches     2313     2313           
=======================================
  Hits        17068    17068           
  Misses       2174     2174           
  Partials      564      564           
Flag Coverage Δ
py-unittests 86.17% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
...ntimelineio/opentimelineio-bindings/otio_imath.cpp 61.53% <ø> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update bc96625...7c2fd78. Read the comment docs.

@JeanChristopheMorinPerso JeanChristopheMorinPerso changed the title Use py::module_local() for Imath classes binded with Pybind11 Use py::module_local() for Imath bindings Jun 4, 2022
Copy link
Collaborator

@meshula meshula left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for discovering this solution!

@meshula meshula merged commit ead2036 into AcademySoftwareFoundation:main Jun 5, 2022
@JeanChristopheMorinPerso JeanChristopheMorinPerso deleted the imath_module_local_classes branch June 6, 2022 21:56
@ssteinbach ssteinbach added this to the Public Beta 15 milestone Sep 19, 2022
MichaelPlug pushed a commit to MichaelPlug/OpenTimelineIO that referenced this pull request Aug 5, 2023
…ySoftwareFoundation#1323)

Signed-off-by: Jean-Christophe Morin <jean_christophe_morin@hotmail.com>
Signed-off-by: Michele Spina <michelespina96@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants