Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
cython
Commits
a750a1ce
Commit
a750a1ce
authored
Nov 05, 2010
by
Vitja Makarov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Py3 metaclasses initial support.
parent
78a87802
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
186 additions
and
56 deletions
+186
-56
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+113
-29
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+4
-2
Cython/Compiler/Parsing.py
Cython/Compiler/Parsing.py
+46
-25
tests/run/metaclass.pyx
tests/run/metaclass.pyx
+23
-0
No files found.
Cython/Compiler/ExprNodes.py
View file @
a750a1ce
...
...
@@ -4480,14 +4480,23 @@ class ClassNode(ExprNode, ModuleNameMixin):
# dict ExprNode Class dict (not owned by this node)
# doc ExprNode or None Doc string
# module_name EncodedString Name of defining module
# keyword_args ExprNode or None Py3 Dict of keyword arguments, passed to __new__
# starstar_arg ExprNode or None Py3 Dict of extra keyword args, same here
subexprs
=
[
'bases'
,
'doc'
]
subexprs
=
[
'bases'
,
'
keyword_args'
,
'starstar_arg'
,
'
doc'
]
def
analyse_types
(
self
,
env
):
self
.
bases
.
analyse_types
(
env
)
if
self
.
doc
:
self
.
doc
.
analyse_types
(
env
)
self
.
doc
=
self
.
doc
.
coerce_to_pyobject
(
env
)
if
self
.
keyword_args
:
self
.
keyword_args
.
analyse_types
(
env
)
if
self
.
starstar_arg
:
self
.
starstar_arg
.
analyse_types
(
env
)
if
self
.
starstar_arg
:
self
.
starstar_arg
=
\
self
.
starstar_arg
.
coerce_to_pyobject
(
env
)
self
.
type
=
py_object_type
self
.
is_temp
=
1
env
.
use_utility_code
(
create_class_utility_code
);
...
...
@@ -4501,6 +4510,19 @@ class ClassNode(ExprNode, ModuleNameMixin):
def
generate_result_code
(
self
,
code
):
cname
=
code
.
intern_identifier
(
self
.
name
)
if
self
.
keyword_args
and
self
.
starstar_arg
:
code
.
put_error_if_neg
(
self
.
pos
,
"PyDict_Update(%s, %s)"
%
(
self
.
keyword_args
.
py_result
(),
self
.
starstar_arg
.
py_result
()))
keyword_code
=
self
.
keyword_args
.
py_result
()
elif
self
.
keyword_args
:
keyword_code
=
self
.
keyword_args
.
py_result
()
elif
self
.
starstar_arg
:
keyword_code
=
self
.
starstar_arg
.
py_result
()
else
:
keyword_code
=
'NULL'
if
self
.
doc
:
code
.
put_error_if_neg
(
self
.
pos
,
'PyDict_SetItemString(%s, "__doc__", %s)'
%
(
...
...
@@ -4508,12 +4530,13 @@ class ClassNode(ExprNode, ModuleNameMixin):
self
.
doc
.
py_result
()))
py_mod_name
=
self
.
get_py_mod_name
(
code
)
code
.
putln
(
'%s = __Pyx_CreateClass(%s, %s, %s, %s); %s'
%
(
'%s = __Pyx_CreateClass(%s, %s, %s, %s
, %s
); %s'
%
(
self
.
result
(),
self
.
bases
.
py_result
(),
self
.
dict
.
py_result
(),
cname
,
py_mod_name
,
keyword_code
,
code
.
error_goto_if_null
(
self
.
result
(),
self
.
pos
)))
code
.
put_gotref
(
self
.
py_result
())
...
...
@@ -7159,45 +7182,106 @@ static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
create_class_utility_code
=
UtilityCode
(
proto
=
"""
static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, PyObject *modname); /*proto*/
static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
PyObject *modname, PyObject *kwargs); /*proto*/
"""
,
impl
=
"""
static int __Pyx_PrepareClass(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *mkw, PyObject *dict)
{
PyObject *prep;
PyObject *pargs;
PyObject *ns;
prep = PyObject_GetAttrString(metaclass, "__prepare__");
if (prep == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1;
PyErr_Clear();
return 0;
}
pargs = PyTuple_Pack(2, name, bases);
if (pargs == NULL) {
Py_DECREF(prep);
return -1;
}
ns = PyEval_CallObjectWithKeywords(prep, pargs, mkw);
Py_DECREF(pargs);
Py_DECREF(prep);
if (ns == NULL)
return -1;
/* XXX: This is hack, merge namespace back to dict,
__prepare__ should be ran before dict initialization */
if (PyDict_Merge(dict, ns, 0)) {
Py_DECREF(ns);
return -1;
}
Py_DECREF(ns);
return 0;
}
static PyObject *__Pyx_CreateClass(
PyObject *bases, PyObject *
methods, PyObject *name, PyObject *modname
)
PyObject *bases, PyObject *
dict, PyObject *name, PyObject *modname, PyObject *kwargs
)
{
PyObject *result = 0;
#if PY_MAJOR_VERSION < 3
PyObject *metaclass = 0, *base;
#endif
PyObject *result = NULL;
PyObject *metaclass = NULL;
PyObject *mkw = NULL;
if (PyDict_SetItemString(methods, "__module__", modname) < 0)
goto bad;
#if PY_MAJOR_VERSION < 3
metaclass = PyDict_GetItemString(methods, "__metaclass__");
if (PyDict_SetItemString(dict, "__module__", modname) < 0)
return NULL;
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;
/* Python3 metaclasses */
if (kwargs) {
mkw = PyDict_Copy(kwargs); /* Don't modify kwargs passed in! */
if (mkw == NULL)
return NULL;
metaclass = PyDict_GetItemString(mkw, "metaclass");
if (metaclass) {
Py_INCREF(metaclass);
if (PyDict_DelItemString(mkw, "metaclass") < 0)
goto bad;
if (__Pyx_PrepareClass(metaclass, bases, name, mkw, dict))
goto bad;
}
}
else {
metaclass = (PyObject *) &PyClass_Type;
/* Python2 __metaclass__ */
if (metaclass == NULL) {
metaclass = PyDict_GetItemString(dict, "__metaclass__");
if (metaclass)
Py_INCREF(metaclass);
}
/* Default metaclass */
if (metaclass == NULL) {
#if PY_MAJOR_VERSION < 3
if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
PyObject *base = PyTuple_GET_ITEM(bases, 0);
metaclass = PyObject_GetAttrString(base, "__class__");
if (metaclass == NULL) {
PyErr_Clear();
metaclass = (PyObject *)base->ob_type;
}
} else
metaclass = (PyObject *) &PyClass_Type;
#else
if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
PyObject *base = PyTuple_GET_ITEM(bases, 0);
metaclass = (PyObject *)base->ob_type;
} else
metaclass = (PyObject *) &PyType_Type;
#endif
Py_INCREF(metaclass);
}
result = PyObject_CallFunctionObjArgs(metaclass, name, bases, methods, NULL);
Py_DECREF(metaclass);
#else
/* it seems that python3+ handle __metaclass__ itself */
result = PyObject_CallFunctionObjArgs((PyObject *)&PyType_Type, name, bases, methods, NULL);
#endif
if (mkw && PyDict_Size(mkw) > 0) {
PyObject *margs;
margs = PyTuple_Pack(3, name, bases, dict, NULL);
result = PyEval_CallObjectWithKeywords(metaclass, margs, mkw);
Py_DECREF(margs);
} else {
result = PyObject_CallFunctionObjArgs(metaclass, name, bases, dict, NULL);
}
bad:
Py_DECREF(metaclass);
if (mkw)
Py_XDECREF(mkw);
return result;
}
"""
)
...
...
Cython/Compiler/Nodes.py
View file @
a750a1ce
...
...
@@ -2940,7 +2940,8 @@ class PyClassDefNode(ClassDefNode):
child_attrs
=
[
"body"
,
"dict"
,
"classobj"
,
"target"
]
decorators
=
None
def
__init__
(
self
,
pos
,
name
,
bases
,
doc
,
body
,
decorators
=
None
):
def
__init__
(
self
,
pos
,
name
,
bases
,
doc
,
body
,
decorators
=
None
,
keyword_args
=
None
,
starstar_arg
=
None
):
StatNode
.
__init__
(
self
,
pos
)
self
.
name
=
name
self
.
doc
=
doc
...
...
@@ -2955,7 +2956,8 @@ class PyClassDefNode(ClassDefNode):
else
:
doc_node
=
None
self
.
classobj
=
ExprNodes
.
ClassNode
(
pos
,
name
=
name
,
bases
=
bases
,
dict
=
self
.
dict
,
doc
=
doc_node
)
bases
=
bases
,
dict
=
self
.
dict
,
doc
=
doc_node
,
keyword_args
=
keyword_args
,
starstar_arg
=
starstar_arg
)
self
.
target
=
ExprNodes
.
NameNode
(
pos
,
name
=
name
)
def
as_cclass
(
self
):
...
...
Cython/Compiler/Parsing.py
View file @
a750a1ce
...
...
@@ -381,7 +381,7 @@ def p_trailer(s, node1):
# arglist: argument (',' argument)* [',']
# argument: [test '='] test # Really [keyword '='] test
def
p_call
(
s
,
function
):
def
p_call
_parse
(
s
):
# s.sy == '('
pos
=
s
.
position
()
s
.
next
()
...
...
@@ -428,29 +428,43 @@ def p_call(s, function):
if
s
.
sy
==
','
:
s
.
next
()
s
.
expect
(
')'
)
return
positional_args
,
keyword_args
,
star_arg
,
starstar_arg
def
p_call_prepare_full
(
pos
,
positional_args
,
keyword_args
,
star_arg
):
arg_tuple
=
None
keyword_dict
=
None
if
positional_args
or
not
star_arg
:
arg_tuple
=
ExprNodes
.
TupleNode
(
pos
,
args
=
positional_args
)
if
star_arg
:
star_arg_tuple
=
ExprNodes
.
AsTupleNode
(
pos
,
arg
=
star_arg
)
if
arg_tuple
:
arg_tuple
=
ExprNodes
.
binop_node
(
pos
,
operator
=
'+'
,
operand1
=
arg_tuple
,
operand2
=
star_arg_tuple
)
else
:
arg_tuple
=
star_arg_tuple
if
keyword_args
:
keyword_args
=
[
ExprNodes
.
DictItemNode
(
pos
=
key
.
pos
,
key
=
key
,
value
=
value
)
for
key
,
value
in
keyword_args
]
keyword_dict
=
ExprNodes
.
DictNode
(
pos
,
key_value_pairs
=
keyword_args
)
return
arg_tuple
,
keyword_dict
def
p_call
(
s
,
function
):
# s.sy == '('
pos
=
s
.
position
()
positional_args
,
keyword_args
,
star_arg
,
starstar_arg
=
\
p_call_parse
(
s
)
if
not
(
keyword_args
or
star_arg
or
starstar_arg
):
return
ExprNodes
.
SimpleCallNode
(
pos
,
function
=
function
,
args
=
positional_args
)
else
:
arg_tuple
=
None
keyword_dict
=
None
if
positional_args
or
not
star_arg
:
arg_tuple
=
ExprNodes
.
TupleNode
(
pos
,
args
=
positional_args
)
if
star_arg
:
star_arg_tuple
=
ExprNodes
.
AsTupleNode
(
pos
,
arg
=
star_arg
)
if
arg_tuple
:
arg_tuple
=
ExprNodes
.
binop_node
(
pos
,
operator
=
'+'
,
operand1
=
arg_tuple
,
operand2
=
star_arg_tuple
)
else
:
arg_tuple
=
star_arg_tuple
if
keyword_args
:
keyword_args
=
[
ExprNodes
.
DictItemNode
(
pos
=
key
.
pos
,
key
=
key
,
value
=
value
)
for
key
,
value
in
keyword_args
]
keyword_dict
=
ExprNodes
.
DictNode
(
pos
,
key_value_pairs
=
keyword_args
)
arg_tuple
,
keyword_dict
=
p_call_prepare_full
(
pos
,
positional_args
,
keyword_args
,
star_arg
)
return
ExprNodes
.
GeneralCallNode
(
pos
,
function
=
function
,
positional_args
=
arg_tuple
,
...
...
@@ -2607,16 +2621,23 @@ def p_class_statement(s, decorators):
s
.
next
()
class_name
=
EncodedString
(
p_ident
(
s
)
)
class_name
.
encoding
=
s
.
source_encoding
arg_tuple
=
None
keyword_dict
=
None
starstar_arg
=
None
if
s
.
sy
==
'('
:
s
.
next
()
base_list
=
p_simple_expr_list
(
s
)
s
.
expect
(
')'
)
else
:
base_list
=
[]
positional_args
,
keyword_args
,
star_arg
,
starstar_arg
=
\
p_call_parse
(
s
)
arg_tuple
,
keyword_dict
=
p_call_prepare_full
(
pos
,
positional_args
,
keyword_args
,
star_arg
)
if
arg_tuple
is
None
:
# XXX: empty arg_tuple
arg_tuple
=
ExprNodes
.
TupleNode
(
pos
,
args
=
[])
doc
,
body
=
p_suite
(
s
,
Ctx
(
level
=
'class'
),
with_doc
=
1
)
return
Nodes
.
PyClassDefNode
(
pos
,
name
=
class_name
,
bases
=
ExprNodes
.
TupleNode
(
pos
,
args
=
base_list
),
bases
=
arg_tuple
,
keyword_args
=
keyword_dict
,
starstar_arg
=
starstar_arg
,
doc
=
doc
,
body
=
body
,
decorators
=
decorators
)
def
p_c_class_definition
(
s
,
pos
,
ctx
):
...
...
tests/run/metaclass.pyx
View file @
a750a1ce
...
...
@@ -11,3 +11,26 @@ class Foo(object):
True
"""
__metaclass__
=
Base
class
Py3Base
(
type
):
def
__new__
(
cls
,
name
,
bases
,
attrs
,
foo
=
None
):
attrs
[
'foo'
]
=
foo
return
type
.
__new__
(
cls
,
name
,
bases
,
attrs
)
def
__init__
(
self
,
cls
,
attrs
,
obj
,
foo
=
None
):
pass
@
staticmethod
def
__prepare__
(
name
,
bases
,
**
kwargs
):
return
{
'bar'
:
666
,
'dirty'
:
True
}
class
Py3Foo
(
object
,
metaclass
=
Py3Base
,
foo
=
123
):
"""
>>> obj = Py3Foo()
>>> obj.foo
123
>>> obj.bar
666
>>> obj.dirty
False
"""
dirty
=
False
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment