diff options
author | Mats Wichmann <mats@linux.com> | 2022-07-17 14:38:07 (GMT) |
---|---|---|
committer | Mats Wichmann <mats@linux.com> | 2022-07-17 17:15:34 (GMT) |
commit | 56d95dcd2af886e04abe1f94a8cb582cd5b9a28a (patch) | |
tree | 6dac127968aae5a00a5df57a841424c0a262bf83 | |
parent | 767abe618f636e2e00b614f0510f2eaa208fb28e (diff) | |
download | SCons-56d95dcd2af886e04abe1f94a8cb582cd5b9a28a.zip SCons-56d95dcd2af886e04abe1f94a8cb582cd5b9a28a.tar.gz SCons-56d95dcd2af886e04abe1f94a8cb582cd5b9a28a.tar.bz2 |
Stop using deprecated load_module
importlib.load_module is deprecated since 3.10 and scheduled for removal
in the 2023 Python release (3.12) - this makes the tests somewhat noisy.
The zip import code was reworked, to use exec_module. A test was added
in the Platform code - there's now a dummy platform module inside a zip
file that the PlatformTests unittest uses.
The tool import code finally dropped the fallback to Python2-style
importing, and the zip import section matches the (now tested) Platform
version. Not sure this is needed at all: the regular import machinery
ought to find a zipfile without extra steps, since here it uses sys.path
(the platform code does *not* use sys.path).
sconsign now just uses import_module, the "my_import" function is no
longer needed but was left in for now. sconsign actually used the "imp"
module, which is deprecated since 3.4.
A little cleaup in the three scripts/ files.
Fixes #4162
Signed-off-by: Mats Wichmann <mats@linux.com>
-rw-r--r-- | SCons/Platform/PlatformTests.py | 11 | ||||
-rw-r--r-- | SCons/Platform/__init__.py | 47 | ||||
-rw-r--r-- | SCons/Platform/testzip.zip | bin | 0 -> 1142 bytes | |||
-rw-r--r-- | SCons/Tool/__init__.py | 67 | ||||
-rw-r--r-- | SCons/Utilities/sconsign.py | 71 | ||||
-rw-r--r-- | scripts/scons-configure-cache.py | 8 | ||||
-rwxr-xr-x | scripts/scons.py | 3 | ||||
-rw-r--r-- | scripts/sconsign.py | 6 |
8 files changed, 110 insertions, 103 deletions
diff --git a/SCons/Platform/PlatformTests.py b/SCons/Platform/PlatformTests.py index bdb8996..195243a 100644 --- a/SCons/Platform/PlatformTests.py +++ b/SCons/Platform/PlatformTests.py @@ -112,6 +112,13 @@ class PlatformTestCase(unittest.TestCase): assert env['HOST_OS'] == 'hpux', env assert env['HOST_ARCH'] != '', env + p = SCons.Platform.Platform('testzip') + assert str(p) == 'testzip', p + env = Environment() + p(env) + assert env['HOST_OS'] == 'zippy', env + assert env['TESTDUMMY'] == 1866, env + p = SCons.Platform.Platform('win32') assert str(p) == 'win32', p env = Environment() @@ -159,10 +166,6 @@ class PlatformTestCase(unittest.TestCase): assert p.synonyms != '', 'SCons.Platform.win32.get_architecture() not setting synonyms' - - - - class TempFileMungeTestCase(unittest.TestCase): def test_MAXLINELENGTH(self): """ Test different values for MAXLINELENGTH with the same diff --git a/SCons/Platform/__init__.py b/SCons/Platform/__init__.py index 93c5cd3..e3da6ed 100644 --- a/SCons/Platform/__init__.py +++ b/SCons/Platform/__init__.py @@ -83,7 +83,7 @@ def platform_default(): return sys.platform -def platform_module(name = platform_default()): +def platform_module(name=platform_default()): """Return the imported module for the platform. This looks for a module name that matches the specified argument. @@ -91,27 +91,34 @@ def platform_module(name = platform_default()): our execution environment. """ full_name = 'SCons.Platform.' + name - if full_name not in sys.modules: - if os.name == 'java': - eval(full_name) - else: + try: + return sys.modules[full_name] + except KeyError: + try: + # the specific platform module is a relative import + mod = importlib.import_module("." + name, __name__) + except ModuleNotFoundError: try: - # the specific platform module is a relative import - mod = importlib.import_module("." + name, __name__) - except ImportError: - try: - import zipimport - importer = zipimport.zipimporter( sys.modules['SCons.Platform'].__path__[0] ) - mod = importer.load_module(full_name) - except ImportError: - raise SCons.Errors.UserError("No platform named '%s'" % name) - setattr(SCons.Platform, name, mod) - return sys.modules[full_name] + # because we don't do this import using sys.path, + # need to try zipimport explicitly. + import zipimport + + parent = sys.modules['SCons.Platform'].__path__[0] + tryname = os.path.join(parent, name + '.zip') + importer = zipimport.zipimporter(tryname) + spec = importer.find_spec(full_name) + mod = importlib.util.module_from_spec(spec) + sys.modules[full_name] = mod + importer.exec_module(mod) + except zipimport.ZipImportError: + raise SCons.Errors.UserError("No platform named '%s'" % name) + + setattr(SCons.Platform, name, mod) + return mod def DefaultToolList(platform, env): - """Select a default tool list for the specified platform. - """ + """Select a default tool list for the specified platform.""" return SCons.Tool.tool_list(platform, env) @@ -328,8 +335,8 @@ class TempFileMunge: def Platform(name = platform_default()): - """Select a canned Platform specification. - """ + """Select a canned Platform specification.""" + module = platform_module(name) spec = PlatformSpec(name, module.generate) return spec diff --git a/SCons/Platform/testzip.zip b/SCons/Platform/testzip.zip Binary files differnew file mode 100644 index 0000000..05d1b1c --- /dev/null +++ b/SCons/Platform/testzip.zip diff --git a/SCons/Tool/__init__.py b/SCons/Tool/__init__.py index 8e4a22d..b618b22 100644 --- a/SCons/Tool/__init__.py +++ b/SCons/Tool/__init__.py @@ -120,32 +120,16 @@ class Tool: if hasattr(module, 'options'): self.options = module.options - def _load_dotted_module_py2(self, short_name, full_name, searchpaths=None): - import imp - - splitname = short_name.split('.') - index = 0 - srchpths = searchpaths - for item in splitname: - file, path, desc = imp.find_module(item, srchpths) - mod = imp.load_module(full_name, file, path, desc) - srchpths = [path] - return mod, file - def _tool_module(self): + """Try to load a tool module. + + This will hunt in the toolpath for both a Python file (toolname.py) + and a Python module (toolname directory), then try the regular + import machinery, then fallback to try a zipfile. + """ oldpythonpath = sys.path sys.path = self.toolpath + sys.path - # sys.stderr.write("Tool:%s\nPATH:%s\n"%(self.name,sys.path)) - - # From: http://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path/67692#67692 - # import importlib.util - # spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py") - # foo = importlib.util.module_from_spec(spec) - # spec.loader.exec_module(foo) - # foo.MyClass() - # Py 3 code - - + # sys.stderr.write("Tool:%s\nPATH:%s\n" % (self.name,sys.path)) # sys.stderr.write("toolpath:%s\n" % self.toolpath) # sys.stderr.write("SCONS.TOOL path:%s\n" % sys.modules['SCons.Tool'].__path__) debug = False @@ -203,19 +187,19 @@ class Tool: # Not sure what to do in the case that there already # exists sys.modules[self.name] but the source file is # different.. ? - module = spec.loader.load_module(spec.name) - sys.modules[found_name] = module + spec.loader.exec_module(module) if add_to_scons_tools_namespace: # If we found it in SCons.Tool, then add it to the module setattr(SCons.Tool, self.name, module) - found_module = module if found_module is not None: sys.path = oldpythonpath return found_module + # we didn't find the module, go back and try some other things + # was this name previously imported? Is there a zipfile? sys.path = oldpythonpath full_name = 'SCons.Tool.' + self.name @@ -223,26 +207,17 @@ class Tool: return sys.modules[full_name] except KeyError: try: - smpath = sys.modules['SCons.Tool'].__path__ - try: - module, file = self._load_dotted_module_py2(self.name, full_name, smpath) - setattr(SCons.Tool, self.name, module) - if file: - file.close() - return module - except ImportError as e: - if str(e) != "No module named %s" % self.name: - raise SCons.Errors.SConsEnvironmentError(e) - try: - import zipimport - importer = zipimport.zipimporter(sys.modules['SCons.Tool'].__path__[0]) - module = importer.load_module(full_name) - setattr(SCons.Tool, self.name, module) - return module - except ImportError as e: - m = "No tool named '%s': %s" % (self.name, e) - raise SCons.Errors.SConsEnvironmentError(m) - except ImportError as e: + import zipimport + parent = sys.modules['SCons.Tool'].__path__[0] + tryname = os.path.join(parent, name + '.zip') + importer = zipimport.zipimporter(tryname) + spec = importer.find_spec(full_name) + module = importlib.util.module_from_spec(spec) + sys.modules[full_name] = module + importer.exec_module(module) + setattr(SCons.Tool, self.name, module) + return module + except zipimporter.ZipImportError as e: m = "No tool named '%s': %s" % (self.name, e) raise SCons.Errors.SConsEnvironmentError(m) diff --git a/SCons/Utilities/sconsign.py b/SCons/Utilities/sconsign.py index e595b2d..4cb598d 100644 --- a/SCons/Utilities/sconsign.py +++ b/SCons/Utilities/sconsign.py @@ -51,13 +51,18 @@ def my_whichdb(filename): def my_import(mname): + """Import database module. + + This was used if the module was *not* SCons.dblite, to allow + for programmatic importing. It is no longer used, in favor of + importlib.import_module, and will be removed eventually. + """ import imp if '.' in mname: i = mname.rfind('.') parent = my_import(mname[:i]) - fp, pathname, description = imp.find_module(mname[i+1:], - parent.__path__) + fp, pathname, description = imp.find_module(mname[i+1:], parent.__path__) else: fp, pathname, description = imp.find_module(mname) return imp.load_module(mname, fp, pathname, description) @@ -371,36 +376,50 @@ def Do_SConsignDir(name): ############################################################################## def main(): - global Do_Call + global Do_Call global nodeinfo_string global args global Verbose global Readable helpstr = """\ - Usage: sconsign [OPTIONS] [FILE ...] - Options: - -a, --act, --action Print build action information. - -c, --csig Print content signature information. - -d DIR, --dir=DIR Print only info about DIR. - -e ENTRY, --entry=ENTRY Print only info about ENTRY. - -f FORMAT, --format=FORMAT FILE is in the specified FORMAT. - -h, --help Print this message and exit. - -i, --implicit Print implicit dependency information. - -r, --readable Print timestamps in human-readable form. - --raw Print raw Python object representations. - -s, --size Print file sizes. - -t, --timestamp Print timestamp information. - -v, --verbose Verbose, describe each field. - """ +Usage: sconsign [OPTIONS] [FILE ...] + +Options: + -a, --act, --action Print build action information. + -c, --csig Print content signature information. + -d DIR, --dir=DIR Print only info about DIR. + -e ENTRY, --entry=ENTRY Print only info about ENTRY. + -f FORMAT, --format=FORMAT FILE is in the specified FORMAT. + -h, --help Print this message and exit. + -i, --implicit Print implicit dependency information. + -r, --readable Print timestamps in human-readable form. + --raw Print raw Python object representations. + -s, --size Print file sizes. + -t, --timestamp Print timestamp information. + -v, --verbose Verbose, describe each field. +""" try: - opts, args = getopt.getopt(sys.argv[1:], "acd:e:f:hirstv", - ['act', 'action', - 'csig', 'dir=', 'entry=', - 'format=', 'help', 'implicit', - 'raw', 'readable', - 'size', 'timestamp', 'verbose']) + opts, args = getopt.getopt( + sys.argv[1:], + 'acd:e:f:hirstv', + [ + 'act', + 'action', + 'csig', + 'dir=', + 'entry=', + 'format=', + 'help', + 'implicit', + 'raw', + 'readable', + 'size', + 'timestamp', + 'verbose', + ], + ) except getopt.GetoptError as err: sys.stderr.write(str(err) + '\n') print(helpstr) @@ -423,7 +442,7 @@ def main(): if dbm_name: try: if dbm_name != "SCons.dblite": - dbm = my_import(dbm_name) + dbm = importlib.import_module(dbm_name) else: import SCons.dblite @@ -466,7 +485,7 @@ def main(): if dbm_name: Map_Module = {'SCons.dblite': 'dblite'} if dbm_name != "SCons.dblite": - dbm = my_import(dbm_name) + dbm = importlib.import_module(dbm_name) else: import SCons.dblite diff --git a/scripts/scons-configure-cache.py b/scripts/scons-configure-cache.py index da0e848..8f81d8a 100644 --- a/scripts/scons-configure-cache.py +++ b/scripts/scons-configure-cache.py @@ -2,7 +2,9 @@ # # SCons - a Software Constructor # -# __COPYRIGHT__ +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -47,7 +49,7 @@ import os import sys # python compatibility check -if sys.version_info < (3, 5, 0): +if sys.version_info < (3, 6, 0): msg = "scons: *** SCons version %s does not run under Python version %s.\n\ Python >= 3.5 is required.\n" sys.stderr.write(msg % (__version__, sys.version.split()[0])) @@ -92,4 +94,4 @@ sys.path = libs + sys.path from SCons.Utilities.ConfigureCache import main if __name__ == "__main__": - main()
\ No newline at end of file + main() diff --git a/scripts/scons.py b/scripts/scons.py index 86a6bf6..6a36ef7 100755 --- a/scripts/scons.py +++ b/scripts/scons.py @@ -41,9 +41,8 @@ __developer__ = "__DEVELOPER__" import os import sys - # Python compatibility check -if sys.version_info < (3, 5, 0): +if sys.version_info < (3, 6, 0): msg = "scons: *** SCons version %s does not run under Python version %s.\n\ Python >= 3.5 is required.\n" sys.stderr.write(msg % (__version__, sys.version.split()[0])) diff --git a/scripts/sconsign.py b/scripts/sconsign.py index 0edd05c..19e0c82 100644 --- a/scripts/sconsign.py +++ b/scripts/sconsign.py @@ -2,7 +2,9 @@ # # SCons - a Software Constructor # -# __COPYRIGHT__ +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -39,7 +41,7 @@ import os import sys # python compatibility check -if sys.version_info < (3, 5, 0): +if sys.version_info < (3, 6, 0): msg = "scons: *** SCons version %s does not run under Python version %s.\n\ Python >= 3.5 is required.\n" sys.stderr.write(msg % (__version__, sys.version.split()[0])) |