From e4adb7000dd9cf3688771fd32d0bf52df4f9d58e Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Wed, 13 May 2020 11:08:23 -0600 Subject: Eliminate Py2-compat with_metaclass jig SCons has used a wrapper trick because the way a class declares it uses a metaclass differs between Py2 and Py3. Drop this usage and list the metaclass the Py3 way. Along the way, stop reusing the type class name as a parameter, as it might be confusing (SCons and packaging). Signed-off-by: Mats Wichmann --- SCons/Executor.py | 6 +++--- SCons/Node/__init__.py | 4 ++-- SCons/SConf.py | 4 ++-- SCons/Tool/packaging/__init__.py | 6 +++--- SCons/compat/__init__.py | 42 +++------------------------------------- 5 files changed, 13 insertions(+), 49 deletions(-) diff --git a/SCons/Executor.py b/SCons/Executor.py index fb2224f..e012ab6 100644 --- a/SCons/Executor.py +++ b/SCons/Executor.py @@ -35,7 +35,7 @@ from SCons.Debug import logInstanceCreation import SCons.Errors import SCons.Memoize import SCons.Util -from SCons.compat import with_metaclass, NoSlotsPyPy +from SCons.compat import NoSlotsPyPy class Batch(object): """Remembers exact association between targets @@ -154,7 +154,7 @@ _execute_str_map = {0 : execute_null_str, 1 : execute_actions_str} -class Executor(object, with_metaclass(NoSlotsPyPy)): +class Executor(object, metaclass=NoSlotsPyPy): """A class for controlling instances of executing an action. This largely exists to hold a single association of an action, @@ -587,7 +587,7 @@ def get_NullEnvironment(): nullenv = NullEnvironment() return nullenv -class Null(object, with_metaclass(NoSlotsPyPy)): +class Null(object, metaclass=NoSlotsPyPy): """A null Executor, with a null build Environment, that does nothing when the rest of the methods call it. diff --git a/SCons/Node/__init__.py b/SCons/Node/__init__.py index c3565bf..c1bb822 100644 --- a/SCons/Node/__init__.py +++ b/SCons/Node/__init__.py @@ -62,7 +62,7 @@ from SCons.Util import MD5signature from SCons.Debug import Trace -from SCons.compat import with_metaclass, NoSlotsPyPy +from SCons.compat import NoSlotsPyPy print_duplicate = 0 @@ -511,7 +511,7 @@ class BuildInfoBase(object): setattr(self, key, value) -class Node(object, with_metaclass(NoSlotsPyPy)): +class Node(object, metaclass=NoSlotsPyPy): """The base Node class, for entities that we know how to build, or use to build other Nodes. """ diff --git a/SCons/SConf.py b/SCons/SConf.py index e0e492b..eac4fb0 100644 --- a/SCons/SConf.py +++ b/SCons/SConf.py @@ -64,9 +64,9 @@ SCons.Conftest.LogErrorMessages = 0 build_type = None build_types = ['clean', 'help'] -def SetBuildType(type): +def SetBuildType(buildtype): global build_type - build_type = type + build_type = buildtype # to be set, if we are in dry-run mode dryrun = 0 diff --git a/SCons/Tool/packaging/__init__.py b/SCons/Tool/packaging/__init__.py index b6dd42e..6ac244c 100644 --- a/SCons/Tool/packaging/__init__.py +++ b/SCons/Tool/packaging/__init__.py @@ -121,12 +121,12 @@ def Package(env, target=None, source=None, **kw): PACKAGETYPE=PACKAGETYPE.split(',') # load the needed packagers. - def load_packager(type): + def load_packager(pkgtype): try: # the specific packager is a relative import - return importlib.import_module("." + type, __name__) + return importlib.import_module("." + pkgtype, __name__) except ImportError as e: - raise SConsEnvironmentError("packager %s not available: %s" % (type, str(e))) + raise SConsEnvironmentError("packager %s not available: %s" % (pkgtype, str(e))) packagers = list(map(load_packager, PACKAGETYPE)) diff --git a/SCons/compat/__init__.py b/SCons/compat/__init__.py index 18bef48..abf663d 100644 --- a/SCons/compat/__init__.py +++ b/SCons/compat/__init__.py @@ -96,47 +96,11 @@ except AttributeError: shutil.SameFileError = SameFileError -def with_metaclass(meta, *bases): - """ - Function from jinja2/_compat.py. License: BSD. - - Use it like this:: - - class BaseForm(object): - pass - - class FormType(type): - pass - - class Form(with_metaclass(FormType, BaseForm)): - pass - - This requires a bit of explanation: the basic idea is to make a - dummy metaclass for one level of class instantiation that replaces - itself with the actual metaclass. Because of internal type checks - we also need to make sure that we downgrade the custom metaclass - for one level to something closer to type (that's why __call__ and - __init__ comes back from type etc.). - - This has the advantage over six.with_metaclass of not introducing - dummy classes into the final MRO. - """ - - class metaclass(meta): - __call__ = type.__call__ - __init__ = type.__init__ - - def __new__(cls, name, this_bases, d): - if this_bases is None: - return type.__new__(cls, name, (), d) - return meta(name, bases, d) - - return metaclass('temporary_class', None, {}) - class NoSlotsPyPy(type): - """ - Workaround for PyPy not working well with __slots__ and __class__ assignment. + """ Metaclass for PyPy compatitbility. + + PyPy does not work well with __slots__ and __class__ assignment. """ def __new__(meta, name, bases, dct): -- cgit v0.12 From 9996381c139d5d69c4a66edad8a7560a1d337976 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Thu, 14 May 2020 09:05:58 -0600 Subject: [PR #3651] sider complaints led to packaging init cleanup Signed-off-by: Mats Wichmann --- CHANGES.txt | 2 + SCons/Tool/packaging/__init__.py | 171 ++++++++++++++++++++------------------- 2 files changed, 92 insertions(+), 81 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index f336170..431ecc1 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -142,6 +142,8 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER has different function. - Update xml files in SCons to reflect changed relative paths after code restructuring (src/engine/SCons -> SCons) + - Drop the with_metaclass jig which was designed to let class + definitions using a metaclass be written the same for Py2/Py3. diff --git a/SCons/Tool/packaging/__init__.py b/SCons/Tool/packaging/__init__.py index 6ac244c..e029bcc 100644 --- a/SCons/Tool/packaging/__init__.py +++ b/SCons/Tool/packaging/__init__.py @@ -1,8 +1,3 @@ -"""SCons.Tool.Packaging - -SCons Packaging Tool. -""" - # # __COPYRIGHT__ # @@ -25,6 +20,11 @@ SCons Packaging Tool. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +"""SCons.Tool.Packaging + +SCons Packaging Tool. +""" + __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import importlib @@ -32,9 +32,10 @@ from inspect import getfullargspec import SCons.Defaults import SCons.Environment -from SCons.Variables import * -from SCons.Errors import * +from SCons.Errors import UserError, SConsEnvironmentError +from SCons.Script import AddOption, GetOption from SCons.Util import is_List, make_path_relative +from SCons.Variables import * from SCons.Warnings import warn, Warning @@ -48,21 +49,22 @@ __all__ = [ # Utility and Builder function # def Tag(env, target, source, *more_tags, **kw_tags): - """ Tag a file with the given arguments, just sets the accordingly named - attribute on the file object. + """ Tag a file with the given arguments. + + Just sets the accordingly named attribute on the file object. TODO: FIXME """ if not target: - target=source - first_tag=None + target = source + first_tag = None else: - first_tag=source + first_tag = source if first_tag: kw_tags[first_tag[0]] = '' - if len(kw_tags) == 0 and len(more_tags) == 0: + if not kw_tags and not more_tags: raise UserError("No tags given.") # XXX: sanity checks @@ -70,55 +72,56 @@ def Tag(env, target, source, *more_tags, **kw_tags): kw_tags[x] = '' if not SCons.Util.is_List(target): - target=[target] + target = [target] else: - # hmm, sometimes the target list, is a list of a list + # hmm, sometimes the target list is a list of a list # make sure it is flattened prior to processing. # TODO: perhaps some bug ?!? - target=env.Flatten(target) + target = env.Flatten(target) for t in target: - for (k,v) in kw_tags.items(): + for k, v in kw_tags.items(): # all file tags have to start with PACKAGING_, so we can later # differentiate between "normal" object attributes and the # packaging attributes. As the user should not be bothered with # that, the prefix will be added here if missing. - if k[:10] != 'PACKAGING_': - k='PACKAGING_'+k + if not k.startswith('PACKAGING_'): + k = 'PACKAGING_' + k t.Tag(k, v) def Package(env, target=None, source=None, **kw): """ Entry point for the package tool. """ - # check if we need to find the source files ourself + # check if we need to find the source files ourselves if not source: source = env.FindInstalledFiles() - if len(source)==0: + if not source: raise UserError("No source for Package() given") # decide which types of packages shall be built. Can be defined through # four mechanisms: command line argument, keyword argument, - # environment argument and default selection( zip or tar.gz ) in that + # environment argument and default selection (zip or tar.gz) in that # order. - try: kw['PACKAGETYPE']=env['PACKAGETYPE'] - except KeyError: pass + try: + kw['PACKAGETYPE'] = env['PACKAGETYPE'] + except KeyError: + pass if not kw.get('PACKAGETYPE'): - from SCons.Script import GetOption kw['PACKAGETYPE'] = GetOption('package_type') if kw['PACKAGETYPE'] is None: if 'Tar' in env['BUILDERS']: - kw['PACKAGETYPE']='targz' + kw['PACKAGETYPE'] = 'targz' elif 'Zip' in env['BUILDERS']: - kw['PACKAGETYPE']='zip' + kw['PACKAGETYPE'] = 'zip' else: raise UserError("No type for Package() given") - PACKAGETYPE=kw['PACKAGETYPE'] - if not is_List(PACKAGETYPE): - PACKAGETYPE=PACKAGETYPE.split(',') + packagetype = kw['PACKAGETYPE'] + if not is_List(packagetype): + packagetype = packagetype.split(',') # load the needed packagers. def load_packager(pkgtype): @@ -126,46 +129,48 @@ def Package(env, target=None, source=None, **kw): # the specific packager is a relative import return importlib.import_module("." + pkgtype, __name__) except ImportError as e: - raise SConsEnvironmentError("packager %s not available: %s" % (pkgtype, str(e))) + raise SConsEnvironmentError("packager %s not available: %s" + % (pkgtype, str(e))) - packagers = list(map(load_packager, PACKAGETYPE)) + packagers = [load_packager(p) for p in packagetype] # set up targets and the PACKAGEROOT try: - # fill up the target list with a default target name until the PACKAGETYPE - # list is of the same size as the target list. - if not target: target = [] + # fill up the target list with a default target name until the + # PACKAGETYPE list is of the same size as the target list. + if not target: + target = [] - size_diff = len(PACKAGETYPE)-len(target) - default_name = "%(NAME)s-%(VERSION)s" + size_diff = len(packagetype) - len(target) + default_name = "%(NAME)s-%(VERSION)s" - if size_diff>0: - default_target = default_name%kw - target.extend( [default_target]*size_diff ) + if size_diff > 0: + default_target = default_name % kw + target.extend([default_target] * size_diff) if 'PACKAGEROOT' not in kw: - kw['PACKAGEROOT'] = default_name%kw + kw['PACKAGEROOT'] = default_name % kw except KeyError as e: - raise SCons.Errors.UserError( "Missing Packagetag '%s'"%e.args[0] ) + raise UserError("Missing Packagetag '%s'" % e.args[0]) # setup the source files - source=env.arg2nodes(source, env.fs.Entry) + source = env.arg2nodes(source, env.fs.Entry) # call the packager to setup the dependencies. - targets=[] + targets = [] try: for packager in packagers: - t=[target.pop(0)] - t=packager.package(env,t,source, **kw) + t = [target.pop(0)] + t = packager.package(env, t, source, **kw) targets.extend(t) - assert( len(target) == 0 ) + assert len(target) == 0 except KeyError as e: - raise SCons.Errors.UserError( "Missing Packagetag '%s' for %s packager"\ - % (e.args[0],packager.__name__) ) - except TypeError as e: + raise UserError("Missing Packagetag '%s' for %s packager" + % (e.args[0], packager.__name__)) + except TypeError: # this exception means that a needed argument for the packager is # missing. As our packagers get their "tags" as named function # arguments we need to find out which one is missing. @@ -180,30 +185,28 @@ def Package(env, target=None, source=None, **kw): # now remove any args for which we have a value in kw. args = [x for x in args if x not in kw] - if len(args)==0: - raise # must be a different error, so re-raise - elif len(args)==1: - raise SCons.Errors.UserError( "Missing Packagetag '%s' for %s packager"\ - % (args[0],packager.__name__) ) - else: - raise SCons.Errors.UserError( "Missing Packagetags '%s' for %s packager"\ - % (", ".join(args),packager.__name__) ) - - target=env.arg2nodes(target, env.fs.Entry) - targets.extend(env.Alias( 'package', targets )) + if not args: + raise # must be a different error, so re-raise + elif len(args) == 1: + raise UserError("Missing Packagetag '%s' for %s packager" + % (args[0], packager.__name__)) + raise UserError("Missing Packagetags '%s' for %s packager" + % (", ".join(args), packager.__name__)) + + target = env.arg2nodes(target, env.fs.Entry) + #XXX: target set above unused... what was the intent? + targets.extend(env.Alias('package', targets)) return targets # # SCons tool initialization functions # - -added = None +added = False def generate(env): - from SCons.Script import AddOption global added if not added: - added = 1 + added = True AddOption('--package-type', dest='package_type', default=None, @@ -224,11 +227,11 @@ def exists(env): # XXX def options(opts): opts.AddVariables( - EnumVariable( 'PACKAGETYPE', + EnumVariable('PACKAGETYPE', 'the type of package to create.', None, allowed_values=list(map( str, __all__ )), ignorecase=2 - ) + ) ) # @@ -238,9 +241,12 @@ def options(opts): def copy_attr(f1, f2): """ copies the special packaging file attributes from f1 to f2. """ - copyit = lambda x: not hasattr(f2, x) and x[:10] == 'PACKAGING_' if f1._tags: - pattrs = [tag for tag in f1._tags if copyit(tag)] + pattrs = [ + tag + for tag in f1._tags + if lambda tag: not hasattr(f2, tag) and tag.startswith('PACKAGING_') + ] for attr in pattrs: f2.Tag(attr, f1.GetTag(attr)) @@ -258,28 +264,32 @@ def putintopackageroot(target, source, env, pkgroot, honor_install_location=1): 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 SCons.Util.is_String(pkgroot): + pkgroot = env.Dir(pkgroot) + if not SCons.Util.is_List(source): + source = [source] new_source = [] for file in source: - if SCons.Util.is_String(file): file = env.File(file) + if SCons.Util.is_String(file): + file = env.File(file) if file.is_under(pkgroot): new_source.append(file) else: - if file.GetTag('PACKAGING_INSTALL_LOCATION') and\ + if file.GetTag('PACKAGING_INSTALL_LOCATION') and \ honor_install_location: - new_name=make_path_relative(file.GetTag('PACKAGING_INSTALL_LOCATION')) + new_name = make_path_relative(file.GetTag('PACKAGING_INSTALL_LOCATION')) else: - new_name=make_path_relative(file.get_path()) + new_name = make_path_relative(file.get_path()) - new_file=pkgroot.File(new_name) - new_file=env.CopyAs(new_file, file)[0] + new_file = pkgroot.File(new_name) + new_file = env.CopyAs(new_file, file)[0] copy_attr(file, new_file) new_source.append(new_file) - return (target, new_source) + return target, new_source + def stripinstallbuilder(target, source, env): """ Strips the install builder action from the source list and stores @@ -293,12 +303,11 @@ def stripinstallbuilder(target, source, env): return not (file.has_builder() and hasattr(file.builder, 'name') and file.builder.name in ["InstallBuilder", "InstallAsBuilder"]) - if len([src for src in source if has_no_install_location(src)]): warn(Warning, "there are files to package which have no\ InstallBuilder attached, this might lead to irreproducible packages") - n_source=[] + n_source = [] for s in source: if has_no_install_location(s): n_source.append(s) @@ -308,7 +317,7 @@ def stripinstallbuilder(target, source, env): copy_attr(s, ss) ss.Tag('PACKAGING_INSTALL_LOCATION', s.get_path()) - return (target, n_source) + return target, n_source # Local Variables: # tab-width:4 -- cgit v0.12