diff options
author | Daniel Holth <dholth@fastmail.fm> | 2016-06-06 00:23:12 (GMT) |
---|---|---|
committer | Daniel Holth <dholth@fastmail.fm> | 2016-06-06 00:23:12 (GMT) |
commit | e4b799e8dc348159c5f2d70bdf49819c4d8270bc (patch) | |
tree | f8cd8e050e2aa4ccd886ab7a05cceb5e20c6a0f6 | |
parent | aa5a0468340338cc3423a06d6d55e1b52a713bc5 (diff) | |
download | SCons-e4b799e8dc348159c5f2d70bdf49819c4d8270bc.zip SCons-e4b799e8dc348159c5f2d70bdf49819c4d8270bc.tar.gz SCons-e4b799e8dc348159c5f2d70bdf49819c4d8270bc.tar.bz2 |
avoid using __slots__ on Node and Executor (but only on PyPy)
-rw-r--r-- | src/engine/SCons/Executor.py | 6 | ||||
-rw-r--r-- | src/engine/SCons/Node/__init__.py | 5 | ||||
-rw-r--r-- | src/engine/SCons/compat/__init__.py | 47 |
3 files changed, 54 insertions, 4 deletions
diff --git a/src/engine/SCons/Executor.py b/src/engine/SCons/Executor.py index 7107fde..dd5088d 100644 --- a/src/engine/SCons/Executor.py +++ b/src/engine/SCons/Executor.py @@ -35,7 +35,7 @@ import SCons.Debug from SCons.Debug import logInstanceCreation import SCons.Errors import SCons.Memoize - +from SCons.compat import with_metaclass, 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): +class Executor(object, with_metaclass(NoSlotsPyPy)): """A class for controlling instances of executing an action. This largely exists to hold a single association of an action, @@ -580,7 +580,7 @@ def get_NullEnvironment(): nullenv = NullEnvironment() return nullenv -class Null(object): +class Null(object, with_metaclass(NoSlotsPyPy)): """A null Executor, with a null build Environment, that does nothing when the rest of the methods call it. diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index 1a76b60..e714172 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -57,6 +57,8 @@ import SCons.Util from SCons.Debug import Trace +from SCons.compat import with_metaclass, NoSlotsPyPy + print_duplicate = 0 def classname(obj): @@ -489,7 +491,8 @@ class BuildInfoBase(object): if key not in ('__weakref__',): setattr(self, key, value) -class Node(object): + +class Node(object, with_metaclass(NoSlotsPyPy)): """The base Node class, for entities that we know how to build, or use to build other Nodes. """ diff --git a/src/engine/SCons/compat/__init__.py b/src/engine/SCons/compat/__init__.py index 0ddbdd5..285c4ac 100644 --- a/src/engine/SCons/compat/__init__.py +++ b/src/engine/SCons/compat/__init__.py @@ -63,6 +63,8 @@ import os import sys import imp # Use the "imp" module to protect imports from fixers. +PYPY = hasattr(sys, 'pypy_translation_info') + def import_as(module, name): """ Imports the specified module (from our local directory) as the @@ -135,6 +137,51 @@ except AttributeError: del _UserString +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. + """ + def __new__(meta, name, bases, dct): + if PYPY and '__slots__' in dct: + dct['__slats__'] = dct.pop('__slots__') + return super(NoSlotsPyPy, meta).__new__(meta, name, bases, dct) + + # Local Variables: # tab-width:4 # indent-tabs-mode:nil |