diff --git a/src/rez/tests/test_utils_py23.py b/src/rez/tests/test_utils_py23.py new file mode 100644 index 000000000..96b2c04de --- /dev/null +++ b/src/rez/tests/test_utils_py23.py @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright Contributors to the Rez Project + + +""" +unit tests for 'utils.py23' module +""" +import os +import sys +import tempfile + +from rez.tests.util import TestBase +from rez.utils import py23 + + +class TestLoadModuleFromFile(TestBase): + def test_load_module(self): + """Ensure that the imported module does not show up in sys.modules""" + # Random chars are used in the module name to ensure that the module name is unique + # and the test won't fail because some other module with the same name + # shows up in sys.modules + module = 'utils_test_7cd3a335' + + filename = '{0}.py'.format(module) + tmpdir = tempfile.mkdtemp(prefix="rez_selftest_") + + with open(os.path.join(tmpdir, filename), 'w') as fd: + fd.write('') + + py23.load_module_from_file( + module, + os.path.join(tmpdir, filename) + ) + self.assertEqual(sys.modules.get(module), None, msg='Module was found in sys.modules') diff --git a/src/rez/utils/py23.py b/src/rez/utils/py23.py index 3acb29271..09168a8e1 100644 --- a/src/rez/utils/py23.py +++ b/src/rez/utils/py23.py @@ -8,6 +8,8 @@ Put any code here that deals with py2/3 interoperability, beyond simple cases that use (for eg) the six module. """ +import sys + from rez.vendor.six import six @@ -38,8 +40,20 @@ def load_module_from_file(name, filepath): if six.PY2: import imp with open(filepath) as f: - return imp.load_source(name, filepath, f) + module = imp.load_source(name, filepath, f) + # Keep the module out of sys.modules. See comment in the `else:` + # for more info + if name in sys.modules: + del sys.modules[name] + return module else: - from importlib.machinery import SourceFileLoader - return SourceFileLoader(name, filepath).load_module() + # The below code will import the module _without_ adding it to + # sys.modules. We want this otherwise we can't import multiple + # versions of the same module + # See: https://github.com/AcademySoftwareFoundation/rez/issues/1483 + import importlib.util + spec = importlib.util.spec_from_file_location(name, filepath) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module