Aurelien Campeas  committed 3475493

[modutils] fix load_module_from_path (closes #100935)

A very old bug in modutils, that leads to doubly loading some modules.
By chance on Linux (or the platform we typically use) it seems one the two module
gets forgoten as soon as loaded.

Unfortunately on Windows, with CubicWeb, it was found that the first module instance
was the one on which the mro was built and the second one hosted the super(...)
call with a different class id for the litteral within super(ThisClass, self)....

The exact reason for the dual behaviour is still unknown but it could well be
one of those 'platform dependant' bits that riddle Python.

  • Participants
  • Parent commits d7f5380
  • Branches stable

Comments (0)

Files changed (4)

File modutils.py Modified

View file
  • Ignore whitespace
  • Hide word diff
         if len(modpath) != len(parts):
             # even with use_sys=False, should try to get outer packages from sys.modules
             module = sys.modules.get(curname)
+        elif use_sys:
+            # because it may have been indirectly loaded through a parent
+            module = sys.modules.get(curname)
         if module is None:
             mp_file, mp_filename, mp_desc = find_module(part, path)
             module = load_module(curname, mp_file, mp_filename, mp_desc)

File test/data/lmfp/__init__.py Added

View file
  • Ignore whitespace
  • Hide word diff
+# force a "direct" python import
+from . import foo

File test/data/lmfp/foo.py Added

View file
  • Ignore whitespace
  • Hide word diff
+import sys
+if not getattr(sys, 'bar', None):
+    sys.just_once = []
+# there used to be two numbers here because
+# of a load_module_from_path bug
+sys.just_once.append(42)

File test/unittest_modutils.py Modified

View file
  • Ignore whitespace
  • Hide word diff
         self.assertRaises(Exception, modutils.modpath_from_file, '/turlututu')
 
 
+class load_module_from_path_tc(ModutilsTestCase):
+
+    def test_do_not_load_twice(self):
+        sys.path.insert(0, self.datadir)
+        foo = modutils.load_module_from_modpath(['lmfp', 'foo'])
+        lmfp = modutils.load_module_from_modpath(['lmfp'])
+        self.assertEqual(len(sys.just_once), 1)
+        sys.path.pop(0)
+        del sys.just_once
+
 class file_from_modpath_tc(ModutilsTestCase):
     """given a mod path (i.e. splited module / package name), return the
     corresponding file, giving priority to source file over precompiled file