Commit 2ec4d662 authored by Stefan Behnel's avatar Stefan Behnel

clean up metaclass code

parent dbf0e770
...@@ -1450,7 +1450,7 @@ class NameNode(AtomicExprNode): ...@@ -1450,7 +1450,7 @@ class NameNode(AtomicExprNode):
return # There was an error earlier return # There was an error earlier
if entry.is_builtin and Options.cache_builtins: if entry.is_builtin and Options.cache_builtins:
return # Lookup already cached return # Lookup already cached
elif entry.is_real_dict: elif entry.is_pyclass_attr:
assert entry.type.is_pyobject, "Python global or builtin not a Python object" assert entry.type.is_pyobject, "Python global or builtin not a Python object"
interned_cname = code.intern_identifier(self.entry.name) interned_cname = code.intern_identifier(self.entry.name)
if entry.is_builtin: if entry.is_builtin:
...@@ -1459,7 +1459,7 @@ class NameNode(AtomicExprNode): ...@@ -1459,7 +1459,7 @@ class NameNode(AtomicExprNode):
namespace = entry.scope.namespace_cname namespace = entry.scope.namespace_cname
code.globalstate.use_utility_code(getitem_dict_utility_code) code.globalstate.use_utility_code(getitem_dict_utility_code)
code.putln( code.putln(
'%s = __Pyx_PyDict_GetItem(%s, %s); %s' % ( '%s = PyObject_GetItem(%s, %s); %s' % (
self.result(), self.result(),
namespace, namespace,
interned_cname, interned_cname,
...@@ -1521,9 +1521,9 @@ class NameNode(AtomicExprNode): ...@@ -1521,9 +1521,9 @@ class NameNode(AtomicExprNode):
# in Py2.6+, we need to invalidate the method cache # in Py2.6+, we need to invalidate the method cache
code.putln("PyType_Modified(%s);" % code.putln("PyType_Modified(%s);" %
entry.scope.parent_type.typeptr_cname) entry.scope.parent_type.typeptr_cname)
elif entry.is_real_dict: elif entry.is_pyclass_attr:
code.put_error_if_neg(self.pos, code.put_error_if_neg(self.pos,
'PyDict_SetItem(%s, %s, %s)' % ( 'PyObject_SetItem(%s, %s, %s)' % (
namespace, namespace,
interned_cname, interned_cname,
rhs.py_result())) rhs.py_result()))
...@@ -1608,10 +1608,10 @@ class NameNode(AtomicExprNode): ...@@ -1608,10 +1608,10 @@ class NameNode(AtomicExprNode):
if not self.entry.is_pyglobal: if not self.entry.is_pyglobal:
error(self.pos, "Deletion of local or C global name not supported") error(self.pos, "Deletion of local or C global name not supported")
return return
if self.entry.is_real_dict: if self.entry.is_pyclass_attr:
namespace = self.entry.scope.namespace_cname namespace = self.entry.scope.namespace_cname
code.put_error_if_neg(self.pos, code.put_error_if_neg(self.pos,
'PyDict_DelItemString(%s, "%s")' % ( 'PyMapping_DelItemString(%s, "%s")' % (
namespace, namespace,
self.entry.name)) self.entry.name))
else: else:
...@@ -4494,7 +4494,7 @@ class ClassNode(ExprNode, ModuleNameMixin): ...@@ -4494,7 +4494,7 @@ class ClassNode(ExprNode, ModuleNameMixin):
self.keyword_args.analyse_types(env) self.keyword_args.analyse_types(env)
if self.starstar_arg: if self.starstar_arg:
self.starstar_arg.analyse_types(env) self.starstar_arg.analyse_types(env)
if self.starstar_arg: # make sure we have a Python object as **kwargs mapping
self.starstar_arg = \ self.starstar_arg = \
self.starstar_arg.coerce_to_pyobject(env) self.starstar_arg.coerce_to_pyobject(env)
self.type = py_object_type self.type = py_object_type
...@@ -4504,7 +4504,7 @@ class ClassNode(ExprNode, ModuleNameMixin): ...@@ -4504,7 +4504,7 @@ class ClassNode(ExprNode, ModuleNameMixin):
self.set_mod_name(env) self.set_mod_name(env)
def may_be_none(self): def may_be_none(self):
return False return True
gil_message = "Constructing Python class" gil_message = "Constructing Python class"
...@@ -4540,6 +4540,7 @@ class ClassNode(ExprNode, ModuleNameMixin): ...@@ -4540,6 +4540,7 @@ class ClassNode(ExprNode, ModuleNameMixin):
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
class BoundMethodNode(ExprNode): class BoundMethodNode(ExprNode):
# Helper class used in the implementation of Python # Helper class used in the implementation of Python
# class definitions. Constructs an bound method # class definitions. Constructs an bound method
...@@ -7184,10 +7185,12 @@ create_class_utility_code = UtilityCode( ...@@ -7184,10 +7185,12 @@ create_class_utility_code = UtilityCode(
proto = """ proto = """
static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
PyObject *modname, PyObject *kwargs); /*proto*/ PyObject *modname, PyObject *kwargs); /*proto*/
static int __Pyx_PrepareClass(PyObject *metaclass, PyObject *bases, PyObject *name,
PyObject *mkw, PyObject *dict); /*proto*/
""", """,
impl = """ impl = """
static int __Pyx_PrepareClass(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *mkw, PyObject *dict) static int __Pyx_PrepareClass(PyObject *metaclass, PyObject *bases, PyObject *name,
{ PyObject *mkw, PyObject *dict) {
PyObject *prep; PyObject *prep;
PyObject *pargs; PyObject *pargs;
PyObject *ns; PyObject *ns;
...@@ -7219,9 +7222,8 @@ static int __Pyx_PrepareClass(PyObject *metaclass, PyObject *bases, PyObject *na ...@@ -7219,9 +7222,8 @@ static int __Pyx_PrepareClass(PyObject *metaclass, PyObject *bases, PyObject *na
return 0; return 0;
} }
static PyObject *__Pyx_CreateClass( static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
PyObject *bases, PyObject *dict, PyObject *name, PyObject *modname, PyObject *kwargs) PyObject *modname, PyObject *kwargs) {
{
PyObject *result = NULL; PyObject *result = NULL;
PyObject *metaclass = NULL; PyObject *metaclass = NULL;
PyObject *mkw = NULL; PyObject *mkw = NULL;
...@@ -7232,7 +7234,7 @@ static PyObject *__Pyx_CreateClass( ...@@ -7232,7 +7234,7 @@ static PyObject *__Pyx_CreateClass(
/* Python3 metaclasses */ /* Python3 metaclasses */
if (kwargs) { if (kwargs) {
mkw = PyDict_Copy(kwargs); /* Don't modify kwargs passed in! */ mkw = PyDict_Copy(kwargs); /* Don't modify kwargs passed in! */
if (mkw == NULL) if (!mkw)
return NULL; return NULL;
metaclass = PyDict_GetItemString(mkw, "metaclass"); metaclass = PyDict_GetItemString(mkw, "metaclass");
if (metaclass) { if (metaclass) {
...@@ -7243,19 +7245,16 @@ static PyObject *__Pyx_CreateClass( ...@@ -7243,19 +7245,16 @@ static PyObject *__Pyx_CreateClass(
goto bad; goto bad;
} }
} }
if (!metaclass) {
/* Python2 __metaclass__ */ /* Python2 __metaclass__ */
if (metaclass == NULL) {
metaclass = PyDict_GetItemString(dict, "__metaclass__"); metaclass = PyDict_GetItemString(dict, "__metaclass__");
if (metaclass) if (!metaclass) {
Py_INCREF(metaclass);
}
/* Default metaclass */ /* Default metaclass */
if (metaclass == NULL) {
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) { if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
PyObject *base = PyTuple_GET_ITEM(bases, 0); PyObject *base = PyTuple_GET_ITEM(bases, 0);
metaclass = PyObject_GetAttrString(base, "__class__"); metaclass = PyObject_GetAttrString(base, "__class__");
if (metaclass == NULL) { if (!metaclass) {
PyErr_Clear(); PyErr_Clear();
metaclass = (PyObject *)base->ob_type; metaclass = (PyObject *)base->ob_type;
} }
...@@ -7268,6 +7267,7 @@ static PyObject *__Pyx_CreateClass( ...@@ -7268,6 +7267,7 @@ static PyObject *__Pyx_CreateClass(
} else } else
metaclass = (PyObject *) &PyType_Type; metaclass = (PyObject *) &PyType_Type;
#endif #endif
}
Py_INCREF(metaclass); Py_INCREF(metaclass);
} }
if (mkw && PyDict_Size(mkw) > 0) { if (mkw && PyDict_Size(mkw) > 0) {
...@@ -7280,7 +7280,6 @@ static PyObject *__Pyx_CreateClass( ...@@ -7280,7 +7280,6 @@ static PyObject *__Pyx_CreateClass(
} }
bad: bad:
Py_DECREF(metaclass); Py_DECREF(metaclass);
if (mkw)
Py_XDECREF(mkw); Py_XDECREF(mkw);
return result; return result;
} }
......
...@@ -70,7 +70,7 @@ class Entry(object): ...@@ -70,7 +70,7 @@ class Entry(object):
# or class attribute during # or class attribute during
# class construction # class construction
# is_member boolean Is an assigned class member # is_member boolean Is an assigned class member
# is_real_dict boolean Is a real dict, PyClass attributes dict # is_pyclass_attr boolean Is a name in a Python class namespace
# is_variable boolean Is a variable # is_variable boolean Is a variable
# is_cfunction boolean Is a C function # is_cfunction boolean Is a C function
# is_cmethod boolean Is a C method of an extension type # is_cmethod boolean Is a C method of an extension type
...@@ -132,7 +132,7 @@ class Entry(object): ...@@ -132,7 +132,7 @@ class Entry(object):
is_cglobal = 0 is_cglobal = 0
is_pyglobal = 0 is_pyglobal = 0
is_member = 0 is_member = 0
is_real_dict = 0 is_pyclass_attr = 0
is_variable = 0 is_variable = 0
is_cfunction = 0 is_cfunction = 0
is_cmethod = 0 is_cmethod = 0
...@@ -1419,7 +1419,7 @@ class PyClassScope(ClassScope): ...@@ -1419,7 +1419,7 @@ class PyClassScope(ClassScope):
entry = Scope.declare_var(self, name, type, pos, entry = Scope.declare_var(self, name, type, pos,
cname, visibility, is_cdef) cname, visibility, is_cdef)
entry.is_pyglobal = 1 entry.is_pyglobal = 1
entry.is_real_dict = 1 entry.is_pyclass_attr = 1
return entry return entry
def add_default_value(self, type): def add_default_value(self, type):
......
...@@ -12,6 +12,7 @@ class Foo(object): ...@@ -12,6 +12,7 @@ class Foo(object):
""" """
__metaclass__ = Base __metaclass__ = Base
class Py3Base(type): class Py3Base(type):
def __new__(cls, name, bases, attrs, foo=None): def __new__(cls, name, bases, attrs, foo=None):
attrs['foo'] = foo attrs['foo'] = foo
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment