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
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
cython
Commits
395b9584
Commit
395b9584
authored
Sep 01, 2016
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch '_binding_methods'
parents
ceafa531
5f0eb2c6
Changes
13
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
413 additions
and
103 deletions
+413
-103
CHANGES.rst
CHANGES.rst
+3
-0
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+24
-12
Cython/Compiler/ModuleNode.py
Cython/Compiler/ModuleNode.py
+2
-1
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+19
-7
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/ParseTreeTransforms.py
+20
-3
Cython/Compiler/TypeSlots.py
Cython/Compiler/TypeSlots.py
+6
-0
Cython/Utility/CythonFunction.c
Cython/Utility/CythonFunction.c
+36
-40
Cython/Utility/ObjectHandling.c
Cython/Utility/ObjectHandling.c
+73
-23
tests/run/cpdef_optargs.pyx
tests/run/cpdef_optargs.pyx
+92
-0
tests/run/cpdef_optargs_pure.pxd
tests/run/cpdef_optargs_pure.pxd
+1
-0
tests/run/cpdef_optargs_pure.py
tests/run/cpdef_optargs_pure.py
+52
-0
tests/run/cpdef_void_return.pyx
tests/run/cpdef_void_return.pyx
+0
-0
tests/run/line_profile_test.srctree
tests/run/line_profile_test.srctree
+85
-17
No files found.
CHANGES.rst
View file @
395b9584
...
...
@@ -46,6 +46,9 @@ Bugs fixed
* Some function signatures in ``libc.math`` and ``numpy.pxd`` were incorrect.
Patch by Michael Seifert.
* Misplaced usages of the module-level ``linetrace`` and ``profile`` directives
were silently ignored.
Other changes
-------------
...
...
Cython/Compiler/ExprNodes.py
View file @
395b9584
...
...
@@ -1877,11 +1877,13 @@ class NameNode(AtomicExprNode):
def
analyse_target_types
(
self
,
env
):
self
.
analyse_entry
(
env
,
is_target
=
True
)
if
self
.
entry
.
is_cfunction
and
self
.
entry
.
as_variable
:
if
self
.
entry
.
is_overridable
or
not
self
.
is_lvalue
()
and
self
.
entry
.
fused_cfunction
:
entry
=
self
.
entry
if
entry
.
is_cfunction
and
entry
.
as_variable
:
# FIXME: unify "is_overridable" flags below
if
(
entry
.
is_overridable
or
entry
.
type
.
is_overridable
)
or
not
self
.
is_lvalue
()
and
entry
.
fused_cfunction
:
# We need this for assigning to cpdef names and for the fused 'def' TreeFragment
self
.
entry
=
self
.
entry
.
as_variable
self
.
type
=
self
.
entry
.
type
entry
=
self
.
entry
=
entry
.
as_variable
self
.
type
=
entry
.
type
if
self
.
type
.
is_const
:
error
(
self
.
pos
,
"Assignment to const '%s'"
%
self
.
name
)
...
...
@@ -1890,10 +1892,10 @@ class NameNode(AtomicExprNode):
if
not
self
.
is_lvalue
():
error
(
self
.
pos
,
"Assignment to non-lvalue '%s'"
%
self
.
name
)
self
.
type
=
PyrexTypes
.
error_type
self
.
entry
.
used
=
1
if
self
.
entry
.
type
.
is_buffer
:
entry
.
used
=
1
if
entry
.
type
.
is_buffer
:
from
.
import
Buffer
Buffer
.
used_buffer_aux_vars
(
self
.
entry
)
Buffer
.
used_buffer_aux_vars
(
entry
)
return
self
def
analyse_rvalue_entry
(
self
,
env
):
...
...
@@ -5583,7 +5585,7 @@ class PyMethodCallNode(SimpleCallNode):
len
(
args
)
+
1
,
self_arg
,
', '
.
join
(
arg
.
py_result
()
for
arg
in
args
)))
code
.
putln
(
"%s = __Pyx_PyFunction_FastCall(%s, %s+1-%s, %d+%s
, NULL
); %s"
%
(
code
.
putln
(
"%s = __Pyx_PyFunction_FastCall(%s, %s+1-%s, %d+%s); %s"
%
(
self
.
result
(),
function
,
Naming
.
quick_temp_cname
,
...
...
@@ -8730,8 +8732,16 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
default_args
=
[]
default_kwargs
=
[]
annotations
=
[]
# For global cpdef functions and def/cpdef methods in cdef classes, we must use global constants
# for default arguments to avoid the dependency on the CyFunction object as 'self' argument
# in the underlying C function. Basically, cpdef functions/methods are static C functions,
# so their optional arguments must be static, too.
# TODO: change CyFunction implementation to pass both function object and owning object for method calls
must_use_constants
=
env
.
is_c_class_scope
or
(
self
.
def_node
.
is_wrapper
and
env
.
is_module_scope
)
for
arg
in
self
.
def_node
.
args
:
if
arg
.
default
:
if
arg
.
default
and
not
must_use_constants
:
if
not
arg
.
default
.
is_literal
:
arg
.
is_dynamic
=
True
if
arg
.
type
.
is_pyobject
:
...
...
@@ -8820,8 +8830,10 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
self
.
pos
,
args
=
[
defaults_tuple
,
defaults_kwdict
])),
decorators
=
None
,
name
=
StringEncoding
.
EncodedString
(
"__defaults__"
))
defaults_getter
.
analyse_declarations
(
env
)
defaults_getter
=
defaults_getter
.
analyse_expressions
(
env
)
# defaults getter must never live in class scopes, it's always a module function
module_scope
=
env
.
global_scope
()
defaults_getter
.
analyse_declarations
(
module_scope
)
defaults_getter
=
defaults_getter
.
analyse_expressions
(
module_scope
)
defaults_getter
.
body
=
defaults_getter
.
body
.
analyse_expressions
(
defaults_getter
.
local_scope
)
defaults_getter
.
py_wrapper_required
=
False
...
...
@@ -8891,7 +8903,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
elif
def_node
.
is_classmethod
:
flags
.
append
(
'__Pyx_CYFUNCTION_CLASSMETHOD'
)
if
def_node
.
local_scope
.
parent_scope
.
is_c_class_scope
:
if
def_node
.
local_scope
.
parent_scope
.
is_c_class_scope
and
not
def_node
.
entry
.
is_anonymous
:
flags
.
append
(
'__Pyx_CYFUNCTION_CCLASS'
)
if
flags
:
...
...
Cython/Compiler/ModuleNode.py
View file @
395b9584
...
...
@@ -1975,12 +1975,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def
generate_method_table
(
self
,
env
,
code
):
if
env
.
is_c_class_scope
and
not
env
.
pyfunc_entries
:
return
binding
=
env
.
directives
[
'binding'
]
code
.
putln
(
""
)
code
.
putln
(
"static PyMethodDef %s[] = {"
%
(
env
.
method_table_cname
))
for
entry
in
env
.
pyfunc_entries
:
if
not
entry
.
fused_cfunction
:
if
not
entry
.
fused_cfunction
and
not
(
binding
and
entry
.
is_overridable
)
:
code
.
put_pymethoddef
(
entry
,
","
)
code
.
putln
(
"{0, 0, 0, 0}"
)
...
...
Cython/Compiler/Nodes.py
View file @
395b9584
...
...
@@ -197,6 +197,7 @@ class Node(object):
is_nonecheck
=
0
is_literal
=
0
is_terminator
=
0
is_wrapper
=
False
# is a DefNode wrapper for a C function
temps
=
None
# All descendants should set child_attrs to a list of the attributes
...
...
@@ -1879,7 +1880,7 @@ class FuncDefNode(StatNode, BlockNode):
if
profile
or
linetrace
:
# this looks a bit late, but if we don't get here due to a
# fatal error before hand, it's not really worth tracing
if
isinstance
(
self
,
DefNode
)
and
self
.
is_wrapper
:
if
self
.
is_wrapper
:
trace_name
=
self
.
entry
.
name
+
" (wrapper)"
else
:
trace_name
=
self
.
entry
.
name
...
...
@@ -2243,6 +2244,11 @@ class CFuncDefNode(FuncDefNode):
def
unqualified_name
(
self
):
return
self
.
entry
.
name
@
property
def
code_object
(
self
):
# share the CodeObject with the cpdef wrapper (if available)
return
self
.
py_func
.
code_object
if
self
.
py_func
else
None
def
analyse_declarations
(
self
,
env
):
self
.
is_c_class_method
=
env
.
is_c_class_scope
if
self
.
directive_locals
is
None
:
...
...
@@ -2360,6 +2366,7 @@ class CFuncDefNode(FuncDefNode):
is_wrapper
=
1
)
self
.
py_func
.
is_module_scope
=
env
.
is_module_scope
self
.
py_func
.
analyse_declarations
(
env
)
self
.
py_func
.
entry
.
is_overridable
=
True
self
.
py_func_stat
=
StatListNode
(
self
.
pos
,
stats
=
[
self
.
py_func
])
self
.
py_func
.
type
=
PyrexTypes
.
py_object_type
self
.
entry
.
as_variable
=
self
.
py_func
.
entry
...
...
@@ -2436,7 +2443,10 @@ class CFuncDefNode(FuncDefNode):
def
analyse_expressions
(
self
,
env
):
self
.
local_scope
.
directives
=
env
.
directives
if
self
.
py_func
is
not
None
:
if
self
.
py_func_stat
is
not
None
:
# this will also analyse the default values and the function name assignment
self
.
py_func_stat
=
self
.
py_func_stat
.
analyse_expressions
(
env
)
elif
self
.
py_func
is
not
None
:
# this will also analyse the default values
self
.
py_func
=
self
.
py_func
.
analyse_expressions
(
env
)
else
:
...
...
@@ -3022,16 +3032,17 @@ class DefNode(FuncDefNode):
def
needs_assignment_synthesis
(
self
,
env
,
code
=
None
):
if
self
.
is_staticmethod
:
return
True
if
self
.
is_wrapper
or
self
.
specialized_cpdefs
or
self
.
entry
.
is_fused_specialized
:
if
self
.
specialized_cpdefs
or
self
.
entry
.
is_fused_specialized
:
return
False
if
self
.
no_assignment_synthesis
:
return
False
# Should enable for module level as well, that will require more testing...
if
self
.
entry
.
is_special
:
return
False
if
self
.
entry
.
is_anonymous
:
return
True
if
env
.
is_module_scope
:
if
env
.
is_module_scope
or
env
.
is_c_class_scope
:
if
code
is
None
:
return
env
.
directives
[
'binding'
]
return
self
.
local_scope
.
directives
[
'binding'
]
else
:
return
code
.
globalstate
.
directives
[
'binding'
]
return
env
.
is_py_class_scope
or
env
.
is_closure_scope
...
...
@@ -3044,7 +3055,8 @@ class DefNode(FuncDefNode):
def
generate_function_definitions
(
self
,
env
,
code
):
if
self
.
defaults_getter
:
self
.
defaults_getter
.
generate_function_definitions
(
env
,
code
)
# defaults getter must never live in class scopes, it's always a module function
self
.
defaults_getter
.
generate_function_definitions
(
env
.
global_scope
(),
code
)
# Before closure cnames are mangled
if
self
.
py_wrapper_required
:
...
...
Cython/Compiler/ParseTreeTransforms.py
View file @
395b9584
...
...
@@ -1697,6 +1697,8 @@ if VALUE is not None:
def
visit_DefNode
(
self
,
node
):
node
=
self
.
visit_FuncDefNode
(
node
)
env
=
self
.
current_env
()
if
isinstance
(
node
,
Nodes
.
DefNode
)
and
node
.
is_wrapper
:
env
=
env
.
parent_scope
if
(
not
isinstance
(
node
,
Nodes
.
DefNode
)
or
node
.
fused_py_func
or
node
.
is_generator_body
or
not
node
.
needs_assignment_synthesis
(
env
)):
...
...
@@ -1949,13 +1951,28 @@ class CalculateQualifiedNamesTransform(EnvTransform):
return
node
def
visit_PyCFunctionNode
(
self
,
node
):
orig_qualified_name
=
self
.
qualified_name
[:]
if
node
.
def_node
.
is_wrapper
and
self
.
qualified_name
and
self
.
qualified_name
[
-
1
]
==
'<locals>'
:
self
.
qualified_name
.
pop
()
self
.
_set_qualname
(
node
)
else
:
self
.
_set_qualname
(
node
,
node
.
def_node
.
name
)
self
.
visitchildren
(
node
)
self
.
qualified_name
=
orig_qualified_name
return
node
def
visit_DefNode
(
self
,
node
):
if
node
.
is_wrapper
and
self
.
qualified_name
:
assert
self
.
qualified_name
[
-
1
]
==
'<locals>'
,
self
.
qualified_name
orig_qualified_name
=
self
.
qualified_name
[:]
self
.
qualified_name
.
pop
()
self
.
_set_qualname
(
node
)
self
.
_super_visit_FuncDefNode
(
node
)
self
.
qualified_name
=
orig_qualified_name
else
:
self
.
_set_qualname
(
node
,
node
.
name
)
return
self
.
visit_FuncDefNode
(
node
)
self
.
visit_FuncDefNode
(
node
)
return
node
def
visit_FuncDefNode
(
self
,
node
):
orig_qualified_name
=
self
.
qualified_name
[:]
...
...
Cython/Compiler/TypeSlots.py
View file @
395b9584
...
...
@@ -99,6 +99,12 @@ class Signature(object):
self
.
exception_check
=
ret_format
!=
'r'
and
self
.
error_value
is
not
None
self
.
is_staticmethod
=
False
def
__repr__
(
self
):
return
'<Signature[%s(%s%s)]>'
%
(
self
.
ret_format
,
', '
.
join
(
self
.
fixed_arg_format
),
'*'
if
self
.
has_generic_args
else
''
)
def
num_fixed_args
(
self
):
return
len
(
self
.
fixed_arg_format
)
...
...
Cython/Utility/CythonFunction.c
View file @
395b9584
...
...
@@ -571,13 +571,10 @@ __Pyx_CyFunction_repr(__pyx_CyFunctionObject *op)
#endif
}
#if CYTHON_COMPILING_IN_PYPY
// originally copied from PyCFunction_Call() in CPython's Objects/methodobject.c
// PyPy does not have this function
static
PyObject
*
__Pyx_CyFunction_Call
(
PyObject
*
func
,
PyObject
*
arg
,
PyObject
*
kw
)
{
static
PyObject
*
__Pyx_CyFunction_CallMethod
(
PyObject
*
func
,
PyObject
*
self
,
PyObject
*
arg
,
PyObject
*
kw
)
{
// originally copied from PyCFunction_Call() in CPython's Objects/methodobject.c
PyCFunctionObject
*
f
=
(
PyCFunctionObject
*
)
func
;
PyCFunction
meth
=
f
->
m_ml
->
ml_meth
;
PyObject
*
self
=
f
->
m_self
;
Py_ssize_t
size
;
switch
(
f
->
m_ml
->
ml_flags
&
(
METH_VARARGS
|
METH_KEYWORDS
|
METH_NOARGS
|
METH_O
))
{
...
...
@@ -625,11 +622,38 @@ static PyObject * __Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject
f
->
m_ml
->
ml_name
);
return
NULL
;
}
#else
static
PyObject
*
__Pyx_CyFunction_Call
(
PyObject
*
func
,
PyObject
*
arg
,
PyObject
*
kw
)
{
return
PyCFunction_Call
(
func
,
arg
,
kw
);
static
CYTHON_INLINE
PyObject
*
__Pyx_CyFunction_Call
(
PyObject
*
func
,
PyObject
*
arg
,
PyObject
*
kw
)
{
return
__Pyx_CyFunction_CallMethod
(
func
,
((
PyCFunctionObject
*
)
func
)
->
m_self
,
arg
,
kw
);
}
static
PyObject
*
__Pyx_CyFunction_CallAsMethod
(
PyObject
*
func
,
PyObject
*
args
,
PyObject
*
kw
)
{
PyObject
*
result
;
__pyx_CyFunctionObject
*
cyfunc
=
(
__pyx_CyFunctionObject
*
)
func
;
if
(
cyfunc
->
flags
&
__Pyx_CYFUNCTION_CCLASS
)
{
Py_ssize_t
argc
;
PyObject
*
new_args
;
PyObject
*
self
;
argc
=
PyTuple_GET_SIZE
(
args
);
new_args
=
PyTuple_GetSlice
(
args
,
1
,
argc
);
if
(
unlikely
(
!
new_args
))
return
NULL
;
self
=
PyTuple_GetItem
(
args
,
0
);
if
(
unlikely
(
!
self
))
{
Py_DECREF
(
new_args
);
return
NULL
;
}
result
=
__Pyx_CyFunction_CallMethod
(
func
,
self
,
new_args
,
kw
);
Py_DECREF
(
new_args
);
}
else
{
result
=
__Pyx_CyFunction_Call
(
func
,
args
,
kw
);
}
return
result
;
}
#endif
static
PyTypeObject
__pyx_CyFunctionType_type
=
{
PyVarObject_HEAD_INIT
(
0
,
0
)
...
...
@@ -650,7 +674,7 @@ static PyTypeObject __pyx_CyFunctionType_type = {
0
,
/*tp_as_sequence*/
0
,
/*tp_as_mapping*/
0
,
/*tp_hash*/
__Pyx_CyFunction_Call
,
/*tp_call*/
__Pyx_CyFunction_Call
AsMethod
,
/*tp_call*/
0
,
/*tp_str*/
0
,
/*tp_getattro*/
0
,
/*tp_setattro*/
...
...
@@ -694,10 +718,6 @@ static PyTypeObject __pyx_CyFunctionType_type = {
static
int
__pyx_CyFunction_init
(
void
)
{
#if !CYTHON_COMPILING_IN_PYPY
// avoid a useless level of call indirection
__pyx_CyFunctionType_type
.
tp_call
=
PyCFunction_Call
;
#endif
__pyx_CyFunctionType
=
__Pyx_FetchCommonType
(
&
__pyx_CyFunctionType_type
);
if
(
__pyx_CyFunctionType
==
NULL
)
{
return
-
1
;
...
...
@@ -968,38 +988,14 @@ static PyObject *
__pyx_FusedFunction_callfunction
(
PyObject
*
func
,
PyObject
*
args
,
PyObject
*
kw
)
{
__pyx_CyFunctionObject
*
cyfunc
=
(
__pyx_CyFunctionObject
*
)
func
;
PyObject
*
result
;
int
static_specialized
=
(
cyfunc
->
flags
&
__Pyx_CYFUNCTION_STATICMETHOD
&&
!
((
__pyx_FusedFunctionObject
*
)
func
)
->
__signatures__
);
if
(
cyfunc
->
flags
&
__Pyx_CYFUNCTION_CCLASS
&&
!
static_specialized
)
{
Py_ssize_t
argc
;
PyObject
*
new_args
;
PyObject
*
self
;
PyObject
*
m_self
;
argc
=
PyTuple_GET_SIZE
(
args
);
new_args
=
PyTuple_GetSlice
(
args
,
1
,
argc
);
if
(
!
new_args
)
return
NULL
;
self
=
PyTuple_GetItem
(
args
,
0
);
if
(
!
self
)
return
NULL
;
m_self
=
cyfunc
->
func
.
m_self
;
cyfunc
->
func
.
m_self
=
self
;
result
=
__Pyx_CyFunction_Call
(
func
,
new_args
,
kw
);
cyfunc
->
func
.
m_self
=
m_self
;
Py_DECREF
(
new_args
);
return
__Pyx_CyFunction_CallAsMethod
(
func
,
args
,
kw
);
}
else
{
re
sult
=
__Pyx_CyFunction_Call
(
func
,
args
,
kw
);
re
turn
__Pyx_CyFunction_Call
(
func
,
args
,
kw
);
}
return
result
;
}
// Note: the 'self' from method binding is passed in in the args tuple,
...
...
Cython/Utility/ObjectHandling.c
View file @
395b9584
...
...
@@ -1273,7 +1273,7 @@ static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name
#if CYTHON_FAST_PYCALL
if
(
PyFunction_Check
(
function
))
{
PyObject
*
args
[
2
]
=
{
self
,
arg
};
result
=
__Pyx_PyFunction_FastCall
(
function
,
args
,
2
,
NULL
);
result
=
__Pyx_PyFunction_FastCall
(
function
,
args
,
2
);
goto
done
;
}
#endif
...
...
@@ -1321,7 +1321,7 @@ static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name
#if CYTHON_FAST_PYCALL
if
(
PyFunction_Check
(
function
))
{
PyObject
*
args
[
3
]
=
{
self
,
arg1
,
arg2
};
result
=
__Pyx_PyFunction_FastCall
(
function
,
args
,
3
,
NULL
);
result
=
__Pyx_PyFunction_FastCall
(
function
,
args
,
3
);
goto
done
;
}
#endif
...
...
@@ -1341,7 +1341,7 @@ static PyObject* __Pyx_PyObject_CallMethod2(PyObject* obj, PyObject* method_name
#if CYTHON_FAST_PYCALL
if
(
PyFunction_Check
(
method
))
{
PyObject
*
args
[
2
]
=
{
arg1
,
arg2
};
result
=
__Pyx_PyFunction_FastCall
(
method
,
args
,
2
,
NULL
);
result
=
__Pyx_PyFunction_FastCall
(
method
,
args
,
2
);
goto
done
;
}
else
#endif
...
...
@@ -1433,11 +1433,14 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject
/////////////// PyFunctionFastCall.proto ///////////////
#if CYTHON_FAST_PYCALL
#define __Pyx_PyFunction_FastCall(func, args, nargs) \
__Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL)
// let's assume that the non-public C-API function might still change during the 3.6 beta phase
#if 1 || PY_VERSION_HEX < 0x030600B1
static
PyObject
*
__Pyx_PyFunction_FastCall
(
PyObject
*
func
,
PyObject
**
args
,
int
nargs
,
PyObject
*
kwargs
);
static
PyObject
*
__Pyx_PyFunction_FastCall
Dict
(
PyObject
*
func
,
PyObject
**
args
,
int
nargs
,
PyObject
*
kwargs
);
#else
#define __Pyx_PyFunction_FastCall
(func, args, nargs, kwargs) _PyFunction_FastCall
(func, args, nargs, kwargs)
#define __Pyx_PyFunction_FastCall
Dict(func, args, nargs, kwargs) _PyFunction_FastCallDict
(func, args, nargs, kwargs)
#endif
#endif
...
...
@@ -1447,8 +1450,8 @@ static PyObject *__Pyx_PyFunction_FastCall(PyObject *func, PyObject **args, int
#if CYTHON_FAST_PYCALL
#include "frameobject.h"
static
PyObject
*
__Pyx_PyFunction_FastCallNoKw
(
PyObject
**
args
,
Py_ssize_t
na
,
PyCodeObject
*
co
,
PyObject
*
globals
)
{
static
PyObject
*
__Pyx_PyFunction_FastCallNoKw
(
Py
CodeObject
*
co
,
Py
Object
**
args
,
Py_ssize_t
na
,
PyObject
*
globals
)
{
PyFrameObject
*
f
;
PyThreadState
*
tstate
=
PyThreadState_GET
();
PyObject
**
fastlocals
;
...
...
@@ -1483,7 +1486,7 @@ static PyObject* __Pyx_PyFunction_FastCallNoKw(PyObject **args, Py_ssize_t na,
#if 1 || PY_VERSION_HEX < 0x030600B1
static
PyObject
*
__Pyx_PyFunction_FastCall
(
PyObject
*
func
,
PyObject
**
args
,
int
nargs
,
CYTHON_UNUSED
PyObject
*
kwargs
)
{
static
PyObject
*
__Pyx_PyFunction_FastCall
Dict
(
PyObject
*
func
,
PyObject
**
args
,
int
nargs
,
PyObject
*
kwargs
)
{
PyCodeObject
*
co
=
(
PyCodeObject
*
)
PyFunction_GET_CODE
(
func
);
PyObject
*
globals
=
PyFunction_GET_GLOBALS
(
func
);
PyObject
*
argdefs
=
PyFunction_GET_DEFAULTS
(
func
);
...
...
@@ -1494,18 +1497,60 @@ static PyObject *__Pyx_PyFunction_FastCall(PyObject *func, PyObject **args, int
//PyObject *name, *qualname;
//#endif
#endif
PyObject
*
kwtuple
,
**
k
;
PyObject
**
d
;
int
nd
;
Py_ssize_t
nk
;
PyObject
*
result
;
assert
(
kwargs
==
NULL
||
PyDict_Check
(
kwargs
));
nk
=
kwargs
?
PyDict_Size
(
kwargs
)
:
0
;
/* CPython issue #27128: support for keywords will come later */
assert
(
kwargs
==
NULL
);
if
(
Py_EnterRecursiveCall
(
" while calling a Python object"
))
{
return
NULL
;
}
if
(
argdefs
==
NULL
&&
co
->
co_argcount
==
nargs
&&
if
(
#if PY_MAJOR_VERSION >= 3
co
->
co_kwonlyargcount
==
0
&&
#endif
likely
(
kwargs
==
NULL
||
nk
==
0
)
&&
co
->
co_flags
==
(
CO_OPTIMIZED
|
CO_NEWLOCALS
|
CO_NOFREE
))
{
return
__Pyx_PyFunction_FastCallNoKw
(
args
,
nargs
,
co
,
globals
);
/* Fast paths */
if
(
argdefs
==
NULL
&&
co
->
co_argcount
==
nargs
)
{
result
=
__Pyx_PyFunction_FastCallNoKw
(
co
,
args
,
nargs
,
globals
);
goto
done
;
}
else
if
(
nargs
==
0
&&
argdefs
!=
NULL
&&
co
->
co_argcount
==
Py_SIZE
(
argdefs
))
{
/* function called with no arguments, but all parameters have
a default value: use default values as arguments .*/
args
=
&
PyTuple_GET_ITEM
(
argdefs
,
0
);
result
=
__Pyx_PyFunction_FastCallNoKw
(
co
,
args
,
Py_SIZE
(
argdefs
),
globals
);
goto
done
;
}
}
if
(
kwargs
!=
NULL
)
{
Py_ssize_t
pos
,
i
;
kwtuple
=
PyTuple_New
(
2
*
nk
);
if
(
kwtuple
==
NULL
)
{
result
=
NULL
;
goto
done
;
}
k
=
&
PyTuple_GET_ITEM
(
kwtuple
,
0
);
pos
=
i
=
0
;
while
(
PyDict_Next
(
kwargs
,
&
pos
,
&
k
[
i
],
&
k
[
i
+
1
]))
{
Py_INCREF
(
k
[
i
]);
Py_INCREF
(
k
[
i
+
1
]);
i
+=
2
;
}
nk
=
i
/
2
;
}
else
{
kwtuple
=
NULL
;
k
=
NULL
;
}
closure
=
PyFunction_GET_CLOSURE
(
func
);
...
...
@@ -1534,16 +1579,21 @@ static PyObject *__Pyx_PyFunction_FastCall(PyObject *func, PyObject **args, int
// closure, name, qualname);
//#elif PY_MAJOR_VERSION >= 3
#if PY_MAJOR_VERSION >= 3
re
turn
PyEval_EvalCodeEx
((
PyObject
*
)
co
,
globals
,
(
PyObject
*
)
NULL
,
re
sult
=
PyEval_EvalCodeEx
((
PyObject
*
)
co
,
globals
,
(
PyObject
*
)
NULL
,
args
,
nargs
,
NULL
,
0
,
k
,
(
int
)
nk
,
d
,
nd
,
kwdefs
,
closure
);
#else
re
turn
PyEval_EvalCodeEx
(
co
,
globals
,
(
PyObject
*
)
NULL
,
re
sult
=
PyEval_EvalCodeEx
(
co
,
globals
,
(
PyObject
*
)
NULL
,
args
,
nargs
,
NULL
,
0
,
k
,
(
int
)
nk
,
d
,
nd
,
closure
);
#endif
Py_XDECREF
(
kwtuple
);
done:
Py_LeaveRecursiveCall
();
return
result
;
}
#endif // CPython < 3.6
#endif // CYTHON_FAST_PYCALL
...
...
@@ -1573,7 +1623,7 @@ static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) {
static
CYTHON_INLINE
PyObject
*
__Pyx_PyObject_CallOneArg
(
PyObject
*
func
,
PyObject
*
arg
)
{
#if CYTHON_FAST_PYCALL
if
(
PyFunction_Check
(
func
))
{
return
__Pyx_PyFunction_FastCall
(
func
,
&
arg
,
1
,
NULL
);
return
__Pyx_PyFunction_FastCall
(
func
,
&
arg
,
1
);
}
#endif
#ifdef __Pyx_CyFunction_USED
...
...
@@ -1620,7 +1670,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); /*proto
static
CYTHON_INLINE
PyObject
*
__Pyx_PyObject_CallNoArg
(
PyObject
*
func
)
{
#if CYTHON_FAST_PYCALL
if
(
PyFunction_Check
(
func
))
{
return
__Pyx_PyFunction_FastCall
(
func
,
NULL
,
0
,
NULL
);
return
__Pyx_PyFunction_FastCall
(
func
,
NULL
,
0
);
}
#endif
#ifdef __Pyx_CyFunction_USED
...
...
@@ -1667,7 +1717,7 @@ static PyObject* __Pyx_PyObject_CallMatrixMethod(PyObject* method, PyObject* arg
#if CYTHON_FAST_PYCALL
if
(
PyFunction_Check
(
function
))
{
PyObject
*
args
[
2
]
=
{
self
,
arg
};
result
=
__Pyx_PyFunction_FastCall
(
function
,
args
,
2
,
NULL
);
result
=
__Pyx_PyFunction_FastCall
(
function
,
args
,
2
);
goto
done
;
}
#endif
...
...
tests/run/cpdef_optargs.pyx
0 → 100644
View file @
395b9584
# mode: run
# tag: cyfunction
# cython: binding=True
cimport
cython
class
PyClass
(
object
):
a
=
2
class
PyClass99
(
object
):
a
=
99
def
pymethod
(
self
,
x
,
y
=
1
,
z
=
PyClass
):
"""
>>> obj = PyClass99()
>>> obj.pymethod(0)
(0, 1, 2)
"""
return
x
,
y
,
z
.
a
cdef
class
CyClass
:
cpdef
cpmethod
(
self
,
x
,
y
=
1
,
z
=
PyClass
):
"""
>>> obj = CyClass()
>>> obj.cpmethod(0)
(0, 1, 2)
>>> obj.cpmethod(0, 3)
(0, 3, 2)
>>> obj.cpmethod(0, 3, PyClass)
(0, 3, 2)
>>> obj.cpmethod(0, 3, 5)
Traceback (most recent call last):
AttributeError: 'int' object has no attribute 'a'
"""
return
x
,
y
,
z
.
a
y_value
=
3
p_class
=
PyClass
cpdef
cpmethod2
(
self
,
x
,
y
=
y_value
,
z
=
p_class
):
"""
>>> obj = CyClass()
>>> obj.cpmethod2(0)
(0, 3, 2)
"""
return
x
,
y
,
z
.
a
def
pymethod
(
self
,
x
,
y
=
y_value
,
z
=
p_class
):
"""
>>> obj = CyClass()
>>> obj.pymethod(0)
(0, 3, 2)
"""
return
x
,
y
,
z
.
a
# change values to check that defaults above stay unmodified
y_value
=
98
p_class
=
PyClass99
cpdef
func
(
x
,
y
=
1
,
z
=
PyClass
):
"""
>>> func(0)
(0, 1, 2)
>>> func(0, 3)
(0, 3, 2)
>>> func(0, 3, PyClass)
(0, 3, 2)
>>> func(0, 3, 5)
Traceback (most recent call last):
AttributeError: 'int' object has no attribute 'a'
"""
return
x
,
y
,
z
.
a
@
cython
.
ccall
def
pyfunc
(
x
,
y
=
1
,
z
=
PyClass
):
"""
>>> pyfunc(0)
(0, 1, 2)
>>> pyfunc(0, 3)
(0, 3, 2)
>>> pyfunc(0, 3, PyClass)
(0, 3, 2)
>>> pyfunc(0, 3, 5)
Traceback (most recent call last):
AttributeError: 'int' object has no attribute 'a'
"""
return
x
,
y
,
z
.
a
tests/run/cpdef_optargs_pure.pxd
0 → 100644
View file @
395b9584
cpdef
func
(
x
,
y
=*
,
z
=*
)
tests/run/cpdef_optargs_pure.py
0 → 100644
View file @
395b9584
# mode: run
# tag: cyfunction
# cython: binding=True
import
cython
class
PyClass
(
object
):
a
=
2
class
PyClass99
(
object
):
a
=
99
def
pymethod
(
self
,
x
,
y
=
1
,
z
=
PyClass
):
"""
>>> obj = PyClass99()
>>> obj.pymethod(0)
(0, 1, 2)
"""
return
x
,
y
,
z
.
a
def
func
(
x
,
y
=
1
,
z
=
PyClass
):
"""
>>> func(0)
(0, 1, 2)
>>> func(0, 3)
(0, 3, 2)
>>> func(0, 3, PyClass)
(0, 3, 2)
>>> func(0, 3, 5)
Traceback (most recent call last):
AttributeError: 'int' object has no attribute 'a'
"""
return
x
,
y
,
z
.
a
@
cython
.
ccall
def
pyfunc
(
x
,
y
=
1
,
z
=
PyClass
):
"""
>>> pyfunc(0)
(0, 1, 2)
>>> pyfunc(0, 3)
(0, 3, 2)
>>> pyfunc(0, 3, PyClass)
(0, 3, 2)
>>> pyfunc(0, 3, 5)
Traceback (most recent call last):
AttributeError: 'int' object has no attribute 'a'
"""
return
x
,
y
,
z
.
a
tests/run/cpdef.pyx
→
tests/run/cpdef
_void_return
.pyx
View file @
395b9584
File moved
tests/run/line_profile_test.srctree
View file @
395b9584
...
...
@@ -7,10 +7,6 @@ from distutils.extension import Extension
from distutils.core import setup
from Cython.Build import cythonize
from Cython.Compiler.Options import _directive_defaults
_directive_defaults['linetrace'] = True
_directive_defaults['binding'] = True
extensions = [
Extension("collatz", ["collatz.pyx"], define_macros=[('CYTHON_TRACE', '1')])
]
...
...
@@ -21,8 +17,6 @@ setup(
######## test_profile.py ###########
from collatz import collatz
try:
import line_profiler
except ImportError:
...
...
@@ -30,24 +24,98 @@ except ImportError:
import sys
sys.exit(0)
profile = line_profiler.LineProfiler(collatz)
profile.runcall(collatz, 19)
profile.print_stats()
stats = profile.get_stats()
assert len(stats.timings) > 0, "No profile stats."
for key, timings in stats.timings.items():
if key[-1] == 'collatz':
def assert_stats(profile, name):
profile.print_stats()
stats = profile.get_stats()
assert len(stats.timings) > 0, "No profile stats."
for key, timings in stats.timings.items():
if key[-1] == name:
assert len(timings) > 0
break
else:
raise ValueError("No stats for collatz.")
else:
raise ValueError("No stats for %s." % name)
from collatz import collatz
func = collatz
profile = line_profiler.LineProfiler(func)
profile.runcall(func, 19)
assert_stats(profile, func.__name__)
from collatz import cp_collatz
func = cp_collatz
profile = line_profiler.LineProfiler(func)
profile.runcall(func, 19)
assert_stats(profile, func.__name__)
from collatz import PyClass
obj = PyClass()
func = obj.py_pymethod
profile = line_profiler.LineProfiler(func)
profile.runcall(func)
assert_stats(profile, func.__name__)
from collatz import CClass
obj = CClass()
func = obj.c_pymethod
profile = line_profiler.LineProfiler(func)
profile.runcall(func)
assert_stats(profile, func.__name__)
func = obj.cp_pymethod
profile = line_profiler.LineProfiler(func)
profile.runcall(func, 19)
assert_stats(profile, func.__name__)
######## collatz.pyx ###########
# cython: linetrace=True
cimport cython
@cython.binding(True)
def collatz(n):
while n > 1:
if n % 2 == 0:
n //= 2
else:
n = 3*n+1
@cython.binding(True)
cpdef cp_collatz(n):
while n > 1:
if n % 2 == 0:
n //= 2
else:
n = 3*n+1
@cython.binding(True)
class PyClass(object):
def py_pymethod(self):
x = 1
for i in range(10):
a = x + 2
return a * 3
@cython.binding(True)
cdef class CClass:
def c_pymethod(self, c=2):
for i in range(10):
a = c + 1
y = self.cmethod(c + a)
return y * 4
cpdef cp_pymethod(self, r):
for i in range(10):
a = r + 1
z = self.c_pymethod(a) + self.cmethod(r)
return z * 2
cdef cmethod(self, s):
for i in range(10):
p = s + 3
return p * 5
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