Multiple registration safety and unit testing
Hello all, I'd like to allow a class to be registered more than once and wanted to get your opinion if this change would be a good idea. 'boost::python::class_' always adds a class to the current scope and registers it in the global registry. The global registry code (particularly the 'insert' function in 'src/converter/registry.cpp') asserts that the class hasn't been registered already. This, of course, prevents multiple registrations of the same type. There is a use case, though, where multiple registrations of the same type is both necessary and safe. Generally, a c++ component which has a 'class_' call may not know the name of the module it will eventually end up in. It would still be desirable to write a unit test for this component. If we write a unit test and put the 'class_' into some dummy module we run into a problem where other unit tests might call 'class_' in another scope. The safety of multiple 'class_' calls stems from always using the same conversion function. Semantically everything is a-okay. I'm proposing to change the precondition of the 'boost::python::converter::registry::insert' function from: The behavior is undefined unless the specified 'type_info' object has not already been registered. to: The behavior is undefined unless the specified 'type_info' object has not already been registered with a semantically different converter Any objections? -- David Sankel
On 29.01.2016 19:19, David Sankel wrote:
Hello all,
I'd like to allow a class to be registered more than once and wanted to get your opinion if this change would be a good idea.
'boost::python::class_' always adds a class to the current scope and registers it in the global registry. The global registry code (particularly the 'insert' function in 'src/converter/registry.cpp') asserts that the class hasn't been registered already. This, of course, prevents multiple registrations of the same type.
There is a use case, though, where multiple registrations of the same type is both necessary and safe. Generally, a c++ component which has a 'class_' call may not know the name of the module it will eventually end up in. It would still be desirable to write a unit test for this component. If we write a unit test and put the 'class_' into some dummy module we run into a problem where other unit tests might call 'class_' in another scope.
The safety of multiple 'class_' calls stems from always using the same conversion function. Semantically everything is a-okay.
I'm proposing to change the precondition of the 'boost::python::converter::registry::insert' function from:
The behavior is undefined unless the specified 'type_info' object has not already been registered.
to:
The behavior is undefined unless the specified 'type_info' object has not already been registered with a semantically different converter
Any objections?
Yes. Can you describe your use-case ? And what do you mean exactly by "semantically different" ? :-) Thanks, Stefan -- ...ich hab' noch einen Koffer in Berlin...
On Sat, Jan 30, 2016 at 7:30 AM, Stefan Seefeld <stefan@seefeld.name> wrote:
On 29.01.2016 19:19, David Sankel wrote:
Hello all,
I'd like to allow a class to be registered more than once and wanted to get your opinion if this change would be a good idea.
'boost::python::class_' always adds a class to the current scope and registers it in the global registry. The global registry code (particularly the 'insert' function in 'src/converter/registry.cpp') asserts that the class hasn't been registered already. This, of course, prevents multiple registrations of the same type.
There is a use case, though, where multiple registrations of the same type is both necessary and safe. Generally, a c++ component which has a 'class_' call may not know the name of the module it will eventually end up in. It would still be desirable to write a unit test for this component. If we write a unit test and put the 'class_' into some dummy module we run into a problem where other unit tests might call 'class_' in another scope.
The safety of multiple 'class_' calls stems from always using the same conversion function. Semantically everything is a-okay.
I'm proposing to change the precondition of the 'boost::python::converter::registry::insert' function from:
The behavior is undefined unless the specified 'type_info' object has not already been registered.
to:
The behavior is undefined unless the specified 'type_info' object has not already been registered with a semantically different converter
Any objections?
Yes. Can you describe your use-case ? And what do you mean exactly by "semantically different" ? :-)
In one '.cpp' file I have something like: void addFooAssets() { boost::python::class_< Foo > ( /* etc. */ ) .def( /* etc */ ); } // testing code follows. BOOST_PYTHON_MODULE( fooTest ) { addFooAssets(); } BOOST_AUTO_TEST_CASE( fooAssets ) { // import 'fooTest' and check that all is good. } In another '.cpp' file, I have something like: void initBarPackage() { boost::python::object barPackage = boost::python::scope(); barPackage.attr( "__path__" ) = "bar"; boost::python::object barFooPackage( boost::python::handle<>( boost::python::borrowed(::PyImport_AddModule( "bar.foo" ) ) ) ); barPackage.attr( "foo" ) = barFooPackage; { const boost::python::scope fooScope( barFooPackage ); addFooAssets(); } } // testing code follows If I run the unit test for "foo" and that for "bar" in the same test run, then I'll get 'class_' called twice. It is harmless to call it twice though since the registration is identical for both calls. When I say "semantically" the same, I mean that something like the 'to_python' member could point to a different function as long as they "do" the same thing. -- David Sankel
Hi David, I'm just reviewing Boost.Python PRs, and looking at https://github.com/boostorg/python/pull/55 I was reminded of this little exchange. Sorry for having dropped the ball here... On 01.02.2016 17:36, David Sankel wrote:
On Sat, Jan 30, 2016 at 7:30 AM, Stefan Seefeld <stefan@seefeld.name <mailto:stefan@seefeld.name>> wrote:
Yes. Can you describe your use-case ? And what do you mean exactly by "semantically different" ? :-)
In one '.cpp' file I have something like:
void addFooAssets() { boost::python::class_< Foo > ( /* etc. */ ) .def( /* etc */ ); }
// testing code follows.
BOOST_PYTHON_MODULE( fooTest ) { addFooAssets(); }
BOOST_AUTO_TEST_CASE( fooAssets ) { // import 'fooTest' and check that all is good. }
In another '.cpp' file, I have something like:
void initBarPackage() { boost::python::object barPackage = boost::python::scope(); barPackage.attr( "__path__" ) = "bar";
boost::python::object barFooPackage( boost::python::handle<>( boost::python::borrowed(::PyImport_AddModule( "bar.foo" ) ) ) ); barPackage.attr( "foo" ) = barFooPackage;
{ const boost::python::scope fooScope( barFooPackage ); addFooAssets(); } }
// testing code follows
What do you attempt to do in the above ? Why not simply create "bar" via BOOST_PYTHON_MODULE(bar) ? For example: BOOST_PYTHON_MODULE(bar) { object barPackage = scope(); object barFooPackage = import("foo"); barPackage.attr( "foo" ) = barFooPackage; } should have the effect you are seeking, if I understand correctly. There is no need to invoke "addFooAssets()" twice. Stefan -- ...ich hab' noch einen Koffer in Berlin...
participants (2)
-
David Sankel -
Stefan Seefeld