I tried to implement class dict filling, patch is attached.
Could you take a look at the patch and tell me am I going right way?
Here is example of metaclass stuff that works, __new__ is decorated
with staticmethod as type() does not turn PyMethods into staticmethods
it works only with PyFunction so PyCFunction will not work too.
__new__ should be converted into staticmethod in Cython
class Base(type):
@staticmethod
def __new__(cls, name, bases, attrs):
print 'Creating class'
return type.__new__(cls, name, bases, attrs)
class Foo(object):
__metaclass__ = Base
ps:
with my patch I got:
failures=29, errors=4
diff -r a412783d157a Cython/Compiler/ExprNodes.py
--- a/Cython/Compiler/ExprNodes.py Sun Oct 31 00:20:00 2010 -0700
+++ b/Cython/Compiler/ExprNodes.py Tue Nov 02 12:06:32 2010 +0300
@@ -1441,6 +1441,22 @@
return # There was an error earlier
if entry.is_builtin and Options.cache_builtins:
return # Lookup already cached
+ elif entry.is_real_dict:
+ assert entry.type.is_pyobject, "Python global or builtin not a Python object"
+ interned_cname = code.intern_identifier(self.entry.name)
+ if entry.is_builtin:
+ namespace = Naming.builtins_cname
+ else: # entry.is_pyglobal
+ namespace = entry.scope.namespace_cname
+ code.globalstate.use_utility_code(getitem_dict_utility_code)
+ code.putln(
+ '%s = __Pyx_PyDict_GetItem(%s, %s); %s' % (
+ self.result(),
+ namespace,
+ interned_cname,
+ code.error_goto_if_null(self.result(), self.pos)))
+ code.put_gotref(self.py_result())
+
elif entry.is_pyglobal or entry.is_builtin:
assert entry.type.is_pyobject, "Python global or builtin not a Python object"
interned_cname = code.intern_identifier(self.entry.name)
@@ -1495,8 +1511,16 @@
rhs.free_temps(code)
# in Py2.6+, we need to invalidate the method cache
code.putln("PyType_Modified(%s);" %
- entry.scope.parent_type.typeptr_cname)
- else:
+ entry.scope.parent_type.typeptr_cname)
+ elif entry.is_real_dict:
+ code.put_error_if_neg(self.pos,
+ 'PyDict_SetItem(%s, %s, %s)' % (
+ namespace,
+ interned_cname,
+ rhs.py_result()))
+ rhs.generate_disposal_code(code)
+ rhs.free_temps(code)
+ else:
code.put_error_if_neg(self.pos,
'PyObject_SetAttr(%s, %s, %s)' % (
namespace,
@@ -1575,10 +1599,17 @@
if not self.entry.is_pyglobal:
error(self.pos, "Deletion of local or C global name not supported")
return
- code.put_error_if_neg(self.pos,
- '__Pyx_DelAttrString(%s, "%s")' % (
- Naming.module_cname,
- self.entry.name))
+ if self.entry.is_real_dict:
+ namespace = self.entry.scope.namespace_cname
+ code.put_error_if_neg(self.pos,
+ 'PyDict_DelItemString(%s, "%s")' % (
+ namespace,
+ self.entry.name))
+ else:
+ code.put_error_if_neg(self.pos,
+ '__Pyx_DelAttrString(%s, "%s")' % (
+ Naming.module_cname,
+ self.entry.name))
def annotate(self, code):
if hasattr(self, 'is_called') and self.is_called:
@@ -4521,6 +4552,9 @@
def generate_result_code(self, code):
class_cname = code.pyclass_stack[-1].classobj.result()
+ if class_cname is None:
+ ### XXX: if NULL is given then staticmethod doesn't work
+ class_cname = '(PyObject *) &PyBaseObject_Type'
code.putln(
"%s = PyMethod_New(%s, 0, %s); %s" % (
self.result(),
@@ -7118,16 +7152,41 @@
""",
impl = """
static PyObject *__Pyx_CreateClass(
- PyObject *bases, PyObject *dict, PyObject *name, PyObject *modname)
+ PyObject *bases, PyObject *methods, PyObject *name, PyObject *modname)
{
PyObject *result = 0;
-
- if (PyDict_SetItemString(dict, "__module__", modname) < 0)
+#if PY_MAJOR_VERSION < 3
+ PyObject *metaclass = 0, *base;
+#endif
+
+ if (PyDict_SetItemString(methods, "__module__", modname) < 0)
goto bad;
#if PY_MAJOR_VERSION < 3
- result = PyClass_New(bases, dict, name);
+ metaclass = PyDict_GetItemString(methods, "__metaclass__");
+
+ if (metaclass != NULL)
+ Py_INCREF(metaclass);
+ else if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
+ base = PyTuple_GET_ITEM(bases, 0);
+ metaclass = PyObject_GetAttrString(base, "__class__");
+ if (metaclass == NULL) {
+ PyErr_Clear();
+ metaclass = (PyObject *)base->ob_type;
+ Py_INCREF(metaclass);
+ }
+ }
+ else {
+ metaclass = (PyObject *) &PyClass_Type;
+ Py_INCREF(metaclass);
+ }
+
+
+ /* metaclass = (PyObject *)&PyType_Type; */
+
+ result = PyObject_CallFunctionObjArgs(metaclass, name, bases, methods, NULL);
#else
- result = PyObject_CallFunctionObjArgs((PyObject *)&PyType_Type, name, bases, dict, NULL);
+ /* it seems that python3+ handle __metaclass__ itself */
+ result = PyObject_CallFunctionObjArgs((PyObject *)&PyType_Type, name, bases, methods, NULL);
#endif
bad:
return result;
diff -r a412783d157a Cython/Compiler/Nodes.py
--- a/Cython/Compiler/Nodes.py Sun Oct 31 00:20:00 2010 -0700
+++ b/Cython/Compiler/Nodes.py Tue Nov 02 12:06:32 2010 +0300
@@ -3016,9 +3016,10 @@
code.pyclass_stack.append(self)
cenv = self.scope
self.dict.generate_evaluation_code(code)
+ cenv.namespace_cname = cenv.class_obj_cname = self.dict.result()
+ self.body.generate_execution_code(code)
self.classobj.generate_evaluation_code(code)
cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result()
- self.body.generate_execution_code(code)
self.target.generate_assignment_code(self.classobj, code)
self.dict.generate_disposal_code(code)
self.dict.free_temps(code)
diff -r a412783d157a Cython/Compiler/Symtab.py
--- a/Cython/Compiler/Symtab.py Sun Oct 31 00:20:00 2010 -0700
+++ b/Cython/Compiler/Symtab.py Tue Nov 02 12:06:32 2010 +0300
@@ -70,6 +70,7 @@
# or class attribute during
# class construction
# is_member boolean Is an assigned class member
+ # is_real_dict boolean Is a real dict, PyClass attributes dict
# is_variable boolean Is a variable
# is_cfunction boolean Is a C function
# is_cmethod boolean Is a C method of an extension type
@@ -131,6 +132,7 @@
is_cglobal = 0
is_pyglobal = 0
is_member = 0
+ is_real_dict = 0
is_variable = 0
is_cfunction = 0
is_cmethod = 0
@@ -1405,6 +1407,7 @@
entry = Scope.declare_var(self, name, type, pos,
cname, visibility, is_cdef)
entry.is_pyglobal = 1
+ entry.is_real_dict = 1
return entry
def add_default_value(self, type):
_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev