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

Reply via email to