python: Make meta class declarations Python 3 safe

Python 2.x and Python 3 use different meta class syntax. Fix this by
implementing meta classes using the add_metaclass decorator in the six
Python library.

Due to the way meta classes are implemented in six,
MetaParamValue.__new__ seems to be called twice for some classes. This
triggers an assertion which when param that checks that Param types
have only been registered once. I have turned this assertion into a
warning.

The assertion was triggered in params.CheckedInt and params.Enum. It
seems like the cause of the issue is that these classes have their own
meta classes (CheckedIntType and MetaEnum) that inherit from
MetaParamValue and a base class (ParamValue) that also inherits from
MetaParamValue.

Change-Id: I5dea08bf0558cfca57897a124cb131c78114e59e
Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/26083
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Maintainer: Jason Lowe-Power <jason@lowepower.com>
This commit is contained in:
Andreas Sandberg
2019-01-25 11:40:53 +00:00
committed by Giacomo Travaglini
parent ee9a360c60
commit 5d70afd3a9
4 changed files with 17 additions and 15 deletions

View File

@@ -40,6 +40,7 @@
from __future__ import print_function
from __future__ import absolute_import
from six import add_metaclass
import six
if six.PY3:
long = int
@@ -1073,10 +1074,10 @@ class SimObjectCliWrapper(object):
# The SimObject class is the root of the special hierarchy. Most of
# the code in this class deals with the configuration hierarchy itself
# (parent/child node relationships).
@add_metaclass(MetaSimObject)
class SimObject(object):
# Specify metaclass. Any class inheriting from SimObject will
# get this metaclass.
__metaclass__ = MetaSimObject
type = 'SimObject'
abstract = True

View File

@@ -55,6 +55,7 @@
#####################################################################
from __future__ import print_function
from six import add_metaclass
import six
if six.PY3:
long = int
@@ -87,15 +88,17 @@ allParams = {}
class MetaParamValue(type):
def __new__(mcls, name, bases, dct):
cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
assert name not in allParams
if name in allParams:
warn("%s already exists in allParams. This may be caused by the " \
"Python 2.7 compatibility layer." % (name, ))
allParams[name] = cls
return cls
# Dummy base class to identify types that are legitimate for SimObject
# parameters.
@add_metaclass(MetaParamValue)
class ParamValue(object):
__metaclass__ = MetaParamValue
cmd_line_settable = False
# Generate the code needed as a prerequisite for declaring a C++
@@ -233,8 +236,8 @@ class ParamDesc(object):
# that the value is a vector (list) of the specified type instead of a
# single value.
@add_metaclass(MetaParamValue)
class VectorParamValue(list):
__metaclass__ = MetaParamValue
def __setattr__(self, attr, value):
raise AttributeError("Not allowed to set %s on '%s'" % \
(attr, type(self).__name__))
@@ -585,8 +588,8 @@ class CheckedIntType(MetaParamValue):
# class is subclassed to generate parameter classes with specific
# bounds. Initialization of the min and max bounds is done in the
# metaclass CheckedIntType.__init__.
@add_metaclass(CheckedIntType)
class CheckedInt(NumericParamValue):
__metaclass__ = CheckedIntType
cmd_line_settable = True
def _check(self):
@@ -1294,7 +1297,6 @@ allEnums = {}
# Metaclass for Enum types
class MetaEnum(MetaParamValue):
def __new__(mcls, name, bases, dict):
assert name not in allEnums
cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
allEnums[name] = cls
@@ -1445,8 +1447,8 @@ module_init(py::module &m_internal)
# Base class for enum types.
@add_metaclass(MetaEnum)
class Enum(ParamValue):
__metaclass__ = MetaEnum
vals = []
cmd_line_settable = True
@@ -1499,8 +1501,8 @@ class Enum(ParamValue):
return self.value
# This param will generate a scoped c++ enum and its python bindings.
@add_metaclass(MetaEnum)
class ScopedEnum(Enum):
__metaclass__ = MetaEnum
vals = []
cmd_line_settable = True
@@ -1787,8 +1789,8 @@ class MemoryBandwidth(float,ParamValue):
# make_param_value() above that lets these be assigned where a
# SimObject is required.
# only one copy of a particular node
@add_metaclass(Singleton)
class NullSimObject(object):
__metaclass__ = Singleton
_name = 'Null'
def __call__(cls):
@@ -2155,9 +2157,8 @@ VectorSlavePort = VectorResponsePort
# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
# proxy objects (via set_param_desc()) so that proxy error messages
# make sense.
@add_metaclass(Singleton)
class PortParamDesc(object):
__metaclass__ = Singleton
ptype_str = 'Port'
ptype = Port

View File

@@ -25,6 +25,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import print_function
from six import add_metaclass
try:
import builtins
@@ -112,9 +113,8 @@ class code_formatter_meta(type):
}
cls.pattern = re.compile(pat, re.VERBOSE | re.DOTALL | re.MULTILINE)
@add_metaclass(code_formatter_meta)
class code_formatter(object):
__metaclass__ = code_formatter_meta
delim = r'$'
ident = r'[_A-z]\w*'
pos = r'[0-9]+'

View File

@@ -35,12 +35,12 @@
from __future__ import print_function
from __future__ import absolute_import
from six import add_metaclass
from abc import *
@add_metaclass(ABCMeta)
class PyBindExport(object):
__metaclass__ = ABCMeta
@abstractmethod
def export(self, code, cname):
pass