scons/replace-imp-with-importlib.patch
2018-07-25 12:27:39 +00:00

319 lines
13 KiB
Diff

From 01a444c023fbc109d0ad1a563c80e3a98c067cb8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= <mcepl@cepl.eu>
Date: Wed, 25 Jul 2018 12:25:03 +0200
Subject: [PATCH] Replace use of imp library with importlib.
imp library has been deprecated since 3.4 and in 3.7 it finally breaks
builds.
Presrving compatibility with python >= 2.7.
---
src/CHANGES.txt | 3 +
src/engine/SCons/Platform/__init__.py | 13 +--
src/engine/SCons/Script/Main.py | 95 ++++++++++++++-------
src/engine/SCons/Tool/__init__.py | 5 +-
src/engine/SCons/Tool/packaging/__init__.py | 29 +++++--
src/engine/SCons/Util.py | 2 +
src/engine/SCons/compat/__init__.py | 8 +-
7 files changed, 102 insertions(+), 53 deletions(-)
--- a/engine/SCons/Platform/__init__.py
+++ b/engine/SCons/Platform/__init__.py
@@ -47,14 +47,15 @@ __revision__ = "src/engine/SCons/Platfor
import SCons.compat
-import imp
import os
+import importlib
import sys
import tempfile
import SCons.Errors
import SCons.Subst
import SCons.Tool
+import SCons.Util
def platform_default():
@@ -100,13 +101,7 @@ def platform_module(name = platform_defa
eval(full_name)
else:
try:
- file, path, desc = imp.find_module(name,
- sys.modules['SCons.Platform'].__path__)
- try:
- mod = imp.load_module(full_name, file, path, desc)
- finally:
- if file:
- file.close()
+ mod = importlib.import_module(full_name)
except ImportError:
try:
import zipimport
@@ -114,7 +109,7 @@ def platform_module(name = platform_defa
mod = importer.load_module(full_name)
except ImportError:
raise SCons.Errors.UserError("No platform named '%s'" % name)
- setattr(SCons.Platform, name, mod)
+ setattr(SCons.Platform, name, mod)
return sys.modules[full_name]
def DefaultToolList(platform, env):
--- a/engine/SCons/Script/Main.py
+++ b/engine/SCons/Script/Main.py
@@ -711,54 +711,89 @@ def _load_site_scons_dir(topdir, site_di
sys.path = [os.path.abspath(site_dir)] + sys.path
site_init_file = os.path.join(site_dir, site_init_filename)
site_tools_dir = os.path.join(site_dir, site_tools_dirname)
- if os.path.exists(site_init_file):
- import imp, re
- try:
+
+ if SCons.Util.PY2 or SCons.Util.PY34:
+ if os.path.exists(site_init_file):
+ import imp, re
try:
- fp, pathname, description = imp.find_module(site_init_modname,
- [site_dir])
- # Load the file into SCons.Script namespace. This is
- # opaque and clever; m is the module object for the
- # SCons.Script module, and the exec ... in call executes a
- # file (or string containing code) in the context of the
- # module's dictionary, so anything that code defines ends
- # up adding to that module. This is really short, but all
- # the error checking makes it longer.
+ try:
+ fp, pathname, description = imp.find_module(site_init_modname,
+ [site_dir])
+ # Load the file into SCons.Script namespace. This is
+ # opaque and clever; m is the module object for the
+ # SCons.Script module, and the exec ... in call executes a
+ # file (or string containing code) in the context of the
+ # module's dictionary, so anything that code defines ends
+ # up adding to that module. This is really short, but all
+ # the error checking makes it longer.
+ try:
+ m = sys.modules['SCons.Script']
+ except Exception as e:
+ fmt = 'cannot import site_init.py: missing SCons.Script module {}'
+ raise SCons.Errors.InternalError(fmt.format(repr(e)))
+ try:
+ sfx = description[0]
+ modname = os.path.basename(pathname)[:-len(sfx)]
+ site_m = {"__file__": pathname, "__name__": modname, "__doc__": None}
+ re_special = re.compile("__[^_]+__")
+ for k in list(m.__dict__.keys()):
+ if not re_special.match(k):
+ site_m[k] = m.__dict__[k]
+
+ # This is the magic.
+ exec(compile(fp.read(), fp.name, 'exec'), site_m)
+ except KeyboardInterrupt:
+ raise
+ except Exception as e:
+ fmt = '*** Error loading site_init file %s:\n'
+ sys.stderr.write(fmt % repr(site_init_file))
+ raise
+ else:
+ for k in site_m:
+ if not re_special.match(k):
+ m.__dict__[k] = site_m[k]
+ except KeyboardInterrupt:
+ raise
+ except ImportError as e:
+ fmt = '*** cannot import site init file %s:\n'
+ sys.stderr.write(fmt % repr(site_init_file))
+ raise
+ finally:
+ if fp:
+ fp.close()
+ else: # Python >= 3.5
+ if os.path.exists(site_init_file):
+ import importlib.util, importlib.machinery
+ try:
+ loader_details = (
+ importlib.machinery.ExtensionFileLoader,
+ importlib.machinery.EXTENSION_SUFFIXES
+ )
+ finder = importlib.machinery.FileFinder(site_dir,
+ loader_details)
+ spec = finder.find_spec(site_init_modname)
try:
m = sys.modules['SCons.Script']
except Exception as e:
fmt = 'cannot import site_init.py: missing SCons.Script module %s'
raise SCons.Errors.InternalError(fmt % repr(e))
try:
- sfx = description[0]
- modname = os.path.basename(pathname)[:-len(sfx)]
- site_m = {"__file__": pathname, "__name__": modname, "__doc__": None}
- re_special = re.compile("__[^_]+__")
- for k in list(m.__dict__.keys()):
- if not re_special.match(k):
- site_m[k] = m.__dict__[k]
-
+ mod = importlib.util.module_from_spec(spec)
# This is the magic.
- exec(compile(fp.read(), fp.name, 'exec'), site_m)
+ exec(mod.__loader__.get_code(mod.__name__), m.__dict__)
except KeyboardInterrupt:
raise
except Exception as e:
- fmt = '*** Error loading site_init file %s:\n'
- sys.stderr.write(fmt % repr(site_init_file))
+ fmt = '*** Error loading site_init file {}:\n'
+ sys.stderr.write(fmt.format(repr(site_init_file)))
raise
- else:
- for k in site_m:
- if not re_special.match(k):
- m.__dict__[k] = site_m[k]
except KeyboardInterrupt:
raise
except ImportError as e:
fmt = '*** cannot import site init file %s:\n'
sys.stderr.write(fmt % repr(site_init_file))
raise
- finally:
- if fp:
- fp.close()
+
if os.path.exists(site_tools_dir):
# prepend to DefaultToolpath
SCons.Tool.DefaultToolpath.insert(0, os.path.abspath(site_tools_dir))
--- a/engine/SCons/Tool/__init__.py
+++ b/engine/SCons/Tool/__init__.py
@@ -54,6 +54,7 @@ import SCons.Scanner.D
import SCons.Scanner.LaTeX
import SCons.Scanner.Prog
import SCons.Scanner.SWIG
+import SCons.Util
import collections
DefaultToolpath=[]
@@ -136,7 +137,7 @@ class Tool(object):
sys.path = self.toolpath + sys.path
# sys.stderr.write("Tool:%s\nPATH:%s\n"%(self.name,sys.path))
- if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] in (0,1,2,3,4)):
+ if SCons.Util.PY2 or SCons.Util.PY34:
# Py 2 code
try:
try:
@@ -238,7 +239,7 @@ class Tool(object):
setattr(SCons.Tool, self.name, module)
found_module = module
-
+
if found_module is not None:
sys.path = oldpythonpath
return found_module
--- a/engine/SCons/Tool/packaging/__init__.py
+++ b/engine/SCons/Tool/packaging/__init__.py
@@ -30,10 +30,10 @@ __revision__ = "src/engine/SCons/Tool/pa
import SCons.Environment
from SCons.Variables import *
from SCons.Errors import *
-from SCons.Util import is_List, make_path_relative
+from SCons.Util import is_List, is_String, make_path_relative, PY2, PY34
from SCons.Warnings import warn, Warning
-import os, imp
+import os
import SCons.Defaults
__all__ = [ 'src_targz', 'src_tarbz2', 'src_zip', 'tarbz2', 'targz', 'zip', 'rpm', 'msi', 'ipk' ]
@@ -63,7 +63,7 @@ def Tag(env, target, source, *more_tags,
for x in more_tags:
kw_tags[x] = ''
- if not SCons.Util.is_List(target):
+ if not is_List(target):
target=[target]
else:
# hmm, sometimes the target list, is a list of a list
@@ -117,8 +117,21 @@ def Package(env, target=None, source=Non
# load the needed packagers.
def load_packager(type):
try:
- file,path,desc=imp.find_module(type, __path__)
- return imp.load_module(type, file, path, desc)
+ if PY2 or PY34:
+ import imp
+ file,path,desc=imp.find_module(type, __path__)
+ return imp.load_module(type, file, path, desc)
+ else:
+ import importlib.util, importlib.machinery
+ loader_details = (
+ importlib.machinery.ExtensionFileLoader,
+ importlib.machinery.EXTENSION_SUFFIXES
+ )
+ finder = importlib.machinery.FileFinder(__path__,
+ loader_details)
+ spec = finder.find_spec(type)
+ mod = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(mod)
except ImportError as e:
raise EnvironmentError("packager %s not available: %s"%(type,str(e)))
@@ -251,12 +264,12 @@ def putintopackageroot(target, source, e
All attributes of the source file will be copied to the new file.
"""
# make sure the packageroot is a Dir object.
- if SCons.Util.is_String(pkgroot): pkgroot=env.Dir(pkgroot)
- if not SCons.Util.is_List(source): source=[source]
+ if is_String(pkgroot): pkgroot=env.Dir(pkgroot)
+ if not is_List(source): source=[source]
new_source = []
for file in source:
- if SCons.Util.is_String(file): file = env.File(file)
+ if is_String(file): file = env.File(file)
if file.is_under(pkgroot):
new_source.append(file)
--- a/engine/SCons/Util.py
+++ b/engine/SCons/Util.py
@@ -35,6 +35,8 @@ import codecs
import pprint
PY3 = sys.version_info[0] == 3
+PY2 = sys.version_info[0] == 2
+PY34 = sys.version_info[0] == 3 and sys.version_info[1] <= 4
try:
from UserDict import UserDict
--- a/engine/SCons/compat/__init__.py
+++ b/engine/SCons/compat/__init__.py
@@ -61,7 +61,7 @@ __revision__ = "src/engine/SCons/compat/
import os
import sys
-import imp # Use the "imp" module to protect imports from fixers.
+import importlib # Use the "importlib" module to protect imports from fixers.
PYPY = hasattr(sys, 'pypy_translation_info')
@@ -71,8 +71,8 @@ def import_as(module, name):
Imports the specified module (from our local directory) as the
specified name, returning the loaded module object.
"""
- dir = os.path.split(__file__)[0]
- return imp.load_module(name, *imp.find_module(module, [dir]))
+ sys.modules[name] = importlib.import_module(module)
+ return sys.modules[name]
def rename_module(new, old):
@@ -81,7 +81,7 @@ def rename_module(new, old):
Used for purely cosmetic name changes in Python 3.x.
"""
try:
- sys.modules[new] = imp.load_module(old, *imp.find_module(old))
+ sys.modules[new] = importlib.import_module(old)
return True
except ImportError:
return False