mirror of
https://github.com/opencv/opencv.git
synced 2024-11-28 05:06:29 +08:00
Merge pull request #21525 from VadimLevin:dev/vlevin/pysubmodules-refcounter-fix
This commit is contained in:
commit
ac51ba38f9
@ -2184,18 +2184,22 @@ static PyObject* createSubmodule(PyObject* parent_module, const std::string& nam
|
|||||||
submodule_name.c_str());
|
submodule_name.c_str());
|
||||||
if (!submodule)
|
if (!submodule)
|
||||||
{
|
{
|
||||||
|
/// Populates global modules dictionary and returns borrowed reference to it
|
||||||
submodule = PyImport_AddModule(full_submodule_name.c_str());
|
submodule = PyImport_AddModule(full_submodule_name.c_str());
|
||||||
|
if (!submodule)
|
||||||
|
{
|
||||||
|
/// Return `PyImport_AddModule` NULL with an exception set on failure.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/// Populates parent module dictionary. Submodule lifetime should be managed
|
||||||
|
/// by the global modules dictionary and parent module dictionary, so Py_DECREF after
|
||||||
|
/// successfull call to the `PyDict_SetItemString` is redundant.
|
||||||
if (PyDict_SetItemString(parent_module_dict, submodule_name.c_str(), submodule) < 0) {
|
if (PyDict_SetItemString(parent_module_dict, submodule_name.c_str(), submodule) < 0) {
|
||||||
Py_CLEAR(submodule);
|
|
||||||
return PyErr_Format(PyExc_ImportError,
|
return PyErr_Format(PyExc_ImportError,
|
||||||
"Can't register a submodule '%s' (full name: '%s')",
|
"Can't register a submodule '%s' (full name: '%s')",
|
||||||
submodule_name.c_str(), full_submodule_name.c_str()
|
submodule_name.c_str(), full_submodule_name.c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/// PyDict_SetItemString doesn't steal a reference so the reference counter
|
|
||||||
/// of the submodule should be decremented to bind submodule lifetime to the
|
|
||||||
/// parent module
|
|
||||||
Py_DECREF(submodule);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
submodule_name_start = submodule_name_end + 1;
|
submodule_name_start = submodule_name_end + 1;
|
||||||
|
@ -602,10 +602,18 @@ class Arguments(NewOpenCVTests):
|
|||||||
msg="Module is not generated for nested namespace")
|
msg="Module is not generated for nested namespace")
|
||||||
self.assertTrue(hasattr(cv.utils.nested, "testEchoBooleanFunction"),
|
self.assertTrue(hasattr(cv.utils.nested, "testEchoBooleanFunction"),
|
||||||
msg="Function in nested module is not available")
|
msg="Function in nested module is not available")
|
||||||
self.assertEqual(sys.getrefcount(cv.utils.nested), 2,
|
|
||||||
msg="Nested submodule lifetime should be managed by "
|
# Nested submodule is managed by the global submodules dictionary
|
||||||
"the parent module so the reference count should be "
|
# and parent native module
|
||||||
"2, because `getrefcount` temporary increases it.")
|
expected_ref_count = 2
|
||||||
|
|
||||||
|
# `getrefcount` temporary increases reference counter by 1
|
||||||
|
actual_ref_count = sys.getrefcount(cv.utils.nested) - 1
|
||||||
|
|
||||||
|
self.assertEqual(actual_ref_count, expected_ref_count,
|
||||||
|
msg="Nested submodule reference counter has wrong value\n"
|
||||||
|
"Expected: {}. Actual: {}".format(expected_ref_count, actual_ref_count))
|
||||||
|
|
||||||
for flag in (True, False):
|
for flag in (True, False):
|
||||||
self.assertEqual(flag, cv.utils.nested.testEchoBooleanFunction(flag),
|
self.assertEqual(flag, cv.utils.nested.testEchoBooleanFunction(flag),
|
||||||
msg="Function in nested module returns wrong result")
|
msg="Function in nested module returns wrong result")
|
||||||
|
Loading…
Reference in New Issue
Block a user