Hmm... yes patch is here... I run fails on classmethod tests ;( don't
know how to solve this yet but all others are okay.
This patch also includes some tests for __metaclass__ and one more
test for staticmethod
2010/11/3 Robert Bradshaw <[email protected]>:
> On Tue, Nov 2, 2010 at 2:20 PM, Vitja Makarov <[email protected]> wrote:
>> It worked!
>
> Excellent! Do you have a patch?
>
>> I've enabled binding and used ExprNodes.PyCFunctionNode instead of
>> ExprNodes.PyCFunctionNode in DefNode.synthesize_assignment_node().
>>
>> Btw __new__ is still decorated with @staticmethod...
>> To solve this PyCFunctionNode should be used for __new__ and probably
>> for all static methods?
>
> __new__ should be a class method, not a static method, right? This
> trick should work fine for static methods. Also, I should note that
> __new__ will require a bit more work to implement fully.
>
>> 2010/11/2 Robert Bradshaw <[email protected]>:
>>> On Tue, Nov 2, 2010 at 2:48 AM, Vitja Makarov <[email protected]>
>>> wrote:
>>>> 2010/11/2 Vitja Makarov <[email protected]>:
>>>>> ps:
>>>>>
>>>>> with my patch I got:
>>>>> failures=29, errors=4
>>>>>
>>>>
>>>> First I tried to create method with NULL
>>>> PyMethod_New(__pyx_t_2, 0, NULL);
>>>>
>>>> But that doesn't worked for @staticmethod that gives SIGSEGV so I turned
>>>> it into
>>>> PyMethod_New(__pyx_t_2, 0, (PyObject *) &PyBaseObject_Type);
>>>>
>>>> But that doesn't work for simple classes, only for object based...
>>>
>>> This is the issue that Greg Ewing was mentioning--you can't make a
>>> method until you have a class. You'll have to make (binding) function
>>> objects, which get turned into methods at class creation time.
>>>
>>> - Robert
>>> _______________________________________________
>>> Cython-dev mailing list
>>> [email protected]
>>> http://codespeak.net/mailman/listinfo/cython-dev
>>>
>> _______________________________________________
>> Cython-dev mailing list
>> [email protected]
>> http://codespeak.net/mailman/listinfo/cython-dev
>>
> _______________________________________________
> Cython-dev mailing list
> [email protected]
> http://codespeak.net/mailman/listinfo/cython-dev
>
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 Wed Nov 03 01:06:26 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:
@@ -7118,16 +7149,38 @@
""",
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);
+ }
+
+ 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 Wed Nov 03 01:06:26 2010 +0300
@@ -1959,6 +1959,9 @@
# staticmethod() was overridden - not much we can do here ...
self.is_staticmethod = False
+ if self.name == '__new__':
+ self.is_staticmethod = 1
+
self.analyse_argument_types(env)
if self.name == '<lambda>':
self.declare_lambda_function(env)
@@ -2203,9 +2206,11 @@
def synthesize_assignment_node(self, env):
import ExprNodes
if env.is_py_class_scope:
- rhs = ExprNodes.UnboundMethodNode(self.pos,
- function = ExprNodes.PyCFunctionNode(self.pos,
- pymethdef_cname = self.entry.pymethdef_cname))
+ rhs = ExprNodes.PyCFunctionNode(self.pos,
+ pymethdef_cname = self.entry.pymethdef_cname)
+ if not self.is_staticmethod and not self.is_classmethod:
+ rhs.binding = True
+
elif env.is_closure_scope:
rhs = ExprNodes.InnerFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname)
@@ -3016,9 +3021,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 Wed Nov 03 01:06:26 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):
diff -r a412783d157a tests/run/staticmethod.pyx
--- a/tests/run/staticmethod.pyx Sun Oct 31 00:20:00 2010 -0700
+++ b/tests/run/staticmethod.pyx Wed Nov 03 01:06:26 2010 +0300
@@ -5,6 +5,8 @@
2
>>> class3.plus1(1)
2
+>>> class4.plus1(1)
+2
"""
def f_plus(a):
@@ -18,3 +20,8 @@
cdef class class3:
plus1 = f_plus
+
+class class4:
+ @staticmethod
+ def plus1(a):
+ return a + 1
_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev