Python bindings for smtk::common::Managers

Currently the contents of smtk::common::Managers are only available to C++ operations and not Python. I will update PybindManagers.h to add Python accessors to the contents. A couple design issues came up, so I want to record my thinking and give everyone an opportunity to comment.

1. Python signature

The specific C++ function to add to the Python bindings is templated:

template<typename Type> const Type& get() const

(The method is actually inherited from the base class smtk::common::TypeContainer which, being fully templated, has no Python bindings.)

For Python, my plan is to use a string argument to specify the C++ typename. The pybind11-generated method signature would be:

def get(self, type_name: string) -> object

The implementation will be C++ code in PybindManagers.h with an if-else chain checking for each manager type (smtk::operation::Manager, smtk::project::Manager, etc). This might be considered a bit fragile, but we really don’t add managers to SMTK very often.

2. Drop task manager from PybindManagers.h?

I noticed that the insert_or_assign methods PybindManagers.h include an overload for smtk::task::Manager. @dcthomp with the recent change to make each project own a separate task manager instance (MR 2853), should the task manager method be removed?

I don’t think accessing any type of object held by smtk::common::Managers is possible, but many objects should be available to scripts via smtk/common/pybind11/PybindManagers.h.

This isn’t hugely different from what’s already in the source above (there are just methods named to fetch particular objects). Other than breaking backward compatibility (or having duplicate interfaces), I don’t care whether we keep what’s there or switch to something else.

I don’t see a need to drop the task manager; we shouldn’t prevent applications from holding a task manager. We just don’t want code to assume that the application state is where it is held.

It could be useful, for example, for plugins to provide the application with a task manager to handle startup (tasks exposed before a plugin is loaded).

Might be a side issue, but I don’t plan to “switch” anything. The only methods currently in smtk/common/PybindManagers.h are insert_or assign() methods. So you can put stuff into the Managers instance in Python but there are no methods for getting anything back. I just want to add a get() method.

One thing I think we should discuss is how to expose the plugin manager and various Registrar objects to Python. We already have this:

// Given a manager instance (mgr), call the `registerTo()`
// method of every extant Registrar in the plugin system:
smtk::plugin::Manager::instance()->registerPluginsTo(mgr);

for some managers (resource, operation, task) but not all. We also need to improve the coverage of which Registrars are wrapped. So far there are:

  • smtk/attribute/pybind11/PybindRegistrar.h
  • smtk/operation/pybind11/PybindRegistrar.h
  • smtk/task/pybind11/PybindRegistrar.h
  • smtk/mesh/pybind11/PybindRegistrar.h
  • smtk/project/pybind11/PybindRegistrar.h
  • smtk/model/pybind11/PybindRegistrar.h
  • smtk/resource/pybind11/PybindRegistrar.h

but many others are not. I don’t know how to test this (to ensure that no Registrar exists without a binding).

Ah, I was under the impression that insert_or_assign() returned the manager. We could change the existing python bindings to return the manager. I don’t think that would break anything since the manager returned should evaluate to an appropriately-truthy value for any pre-existing python scripts.

Also, note that in ParaView’s python, the wrapper for pqSMTKBehavior (in smtk/extension/paraview/appcomponents/pybind11/PybindpqSMTKBehavior.h) lets you fetch managers from the smtk::common::Managers instance held by the pqSMTKWrapper object on each server.