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
Gwenaël Samain
cython
Commits
c73a9b2d
Commit
c73a9b2d
authored
Feb 26, 2013
by
Robert Bradshaw
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'main/master'
Conflicts: Cython/Compiler/Options.py
parents
0ec2ff40
4ebc647c
Changes
30
Hide whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
1418 additions
and
533 deletions
+1418
-533
CHANGES.rst
CHANGES.rst
+9
-0
Cython/Compiler/Builtin.py
Cython/Compiler/Builtin.py
+14
-7
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+258
-193
Cython/Compiler/ModuleNode.py
Cython/Compiler/ModuleNode.py
+63
-16
Cython/Compiler/Naming.py
Cython/Compiler/Naming.py
+2
-0
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+3
-0
Cython/Compiler/Optimize.py
Cython/Compiler/Optimize.py
+118
-80
Cython/Compiler/Options.py
Cython/Compiler/Options.py
+5
-2
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/ParseTreeTransforms.py
+5
-0
Cython/Compiler/Parsing.py
Cython/Compiler/Parsing.py
+2
-0
Cython/Compiler/PyrexTypes.py
Cython/Compiler/PyrexTypes.py
+5
-5
Cython/Compiler/Symtab.py
Cython/Compiler/Symtab.py
+2
-1
Cython/Compiler/TypeSlots.py
Cython/Compiler/TypeSlots.py
+14
-0
Cython/Compiler/Visitor.pxd
Cython/Compiler/Visitor.pxd
+5
-0
Cython/Compiler/Visitor.py
Cython/Compiler/Visitor.py
+11
-1
Cython/Utility/ObjectHandling.c
Cython/Utility/ObjectHandling.c
+8
-0
Cython/Utility/Optimize.c
Cython/Utility/Optimize.c
+0
-157
Cython/Utility/StringTools.c
Cython/Utility/StringTools.c
+188
-0
docs/src/userguide/extension_types.rst
docs/src/userguide/extension_types.rst
+49
-0
runtests.py
runtests.py
+3
-3
tests/errors/e_exttype_freelist.pyx
tests/errors/e_exttype_freelist.pyx
+24
-0
tests/run/constant_folding.py
tests/run/constant_folding.py
+133
-0
tests/run/constant_folding_cy.pyx
tests/run/constant_folding_cy.pyx
+82
-0
tests/run/ct_DEF.pyx
tests/run/ct_DEF.pyx
+9
-0
tests/run/exttype_freelist.pyx
tests/run/exttype_freelist.pyx
+93
-0
tests/run/tp_new.pyx
tests/run/tp_new.pyx
+42
-8
tests/run/tp_new_cimport.srctree
tests/run/tp_new_cimport.srctree
+86
-0
tests/run/unbound_special_methods.pyx
tests/run/unbound_special_methods.pyx
+69
-0
tests/run/unicode_slicing.pyx
tests/run/unicode_slicing.pyx
+97
-60
tests/run/unicodemethods.pyx
tests/run/unicodemethods.pyx
+19
-0
No files found.
CHANGES.rst
View file @
c73a9b2d
...
...
@@ -8,6 +8,15 @@ Cython Changelog
Features added
--------------
* A new class decorator ``@cython.freelist(N)`` creates a static freelist of N
instances for an extension type, thus avoiding the costly allocation step if
possible. This can speed up object instantiation by 20-30% in suitable
scenarios.
* Fast extension type instantiation using the ``Type.__new__(Type)`` idiom has
gained support for passing arguments. It is also a bit faster for types defined
inside of the module.
* The Python2-only dict methods ``.iter*()`` and ``.view*()`` (requires Python 2.7)
are automatically mapped to the equivalent keys/values/items methods in Python 3
for typed dictionaries.
...
...
Cython/Compiler/Builtin.py
View file @
c73a9b2d
...
...
@@ -268,20 +268,26 @@ builtin_types_table = [
BuiltinAttribute
(
'imag'
,
'cval.imag'
,
field_type
=
PyrexTypes
.
c_double_type
),
]),
(
"bytes"
,
"PyBytes_Type"
,
[]),
(
"str"
,
"PyString_Type"
,
[]),
(
"unicode"
,
"PyUnicode_Type"
,
[
BuiltinMethod
(
"join"
,
"TO"
,
"T"
,
"PyUnicode_Join"
),
(
"bytes"
,
"PyBytes_Type"
,
[
BuiltinMethod
(
"__contains__"
,
"TO"
,
"b"
,
"PySequence_Contains"
),
]),
(
"str"
,
"PyString_Type"
,
[
BuiltinMethod
(
"__contains__"
,
"TO"
,
"b"
,
"PySequence_Contains"
),
]),
(
"unicode"
,
"PyUnicode_Type"
,
[
BuiltinMethod
(
"__contains__"
,
"TO"
,
"b"
,
"PyUnicode_Contains"
),
BuiltinMethod
(
"join"
,
"TO"
,
"T"
,
"PyUnicode_Join"
),
]),
(
"tuple"
,
"PyTuple_Type"
,
[]),
(
"tuple"
,
"PyTuple_Type"
,
[
BuiltinMethod
(
"__contains__"
,
"TO"
,
"b"
,
"PySequence_Contains"
),
]),
(
"list"
,
"PyList_Type"
,
[
BuiltinMethod
(
"insert"
,
"TzO"
,
"r"
,
"PyList_Insert"
),
(
"list"
,
"PyList_Type"
,
[
BuiltinMethod
(
"__contains__"
,
"TO"
,
"b"
,
"PySequence_Contains"
),
BuiltinMethod
(
"insert"
,
"TzO"
,
"r"
,
"PyList_Insert"
),
BuiltinMethod
(
"reverse"
,
"T"
,
"r"
,
"PyList_Reverse"
),
BuiltinMethod
(
"append"
,
"TO"
,
"r"
,
"__Pyx_PyList_Append"
,
utility_code
=
UtilityCode
.
load
(
"ListAppend"
,
"Optimize.c"
)),
]),
(
"dict"
,
"PyDict_Type"
,
[
BuiltinMethod
(
"items"
,
"T"
,
"O"
,
"__Pyx_PyDict_Items"
,
(
"dict"
,
"PyDict_Type"
,
[
BuiltinMethod
(
"__contains__"
,
"TO"
,
"b"
,
"PyDict_Contains"
),
BuiltinMethod
(
"items"
,
"T"
,
"O"
,
"__Pyx_PyDict_Items"
,
utility_code
=
UtilityCode
.
load
(
"py_dict_items"
,
"Builtins.c"
)),
BuiltinMethod
(
"keys"
,
"T"
,
"O"
,
"__Pyx_PyDict_Keys"
,
utility_code
=
UtilityCode
.
load
(
"py_dict_keys"
,
"Builtins.c"
)),
...
...
@@ -309,7 +315,8 @@ builtin_types_table = [
]),
# ("file", "PyFile_Type", []), # not in Py3
(
"set"
,
"PySet_Type"
,
[
BuiltinMethod
(
"clear"
,
"T"
,
"r"
,
"PySet_Clear"
,
(
"set"
,
"PySet_Type"
,
[
BuiltinMethod
(
"__contains__"
,
"TO"
,
"b"
,
"PySequence_Contains"
),
BuiltinMethod
(
"clear"
,
"T"
,
"r"
,
"PySet_Clear"
,
utility_code
=
py_set_utility_code
),
# discard() and remove() have a special treatment for unhashable values
# BuiltinMethod("discard", "TO", "r", "PySet_Discard",
...
...
Cython/Compiler/ExprNodes.py
View file @
c73a9b2d
...
...
@@ -247,14 +247,7 @@ class ExprNode(Node):
# whether this node with a memoryview type should be broadcast
memslice_broadcast
=
False
try
:
_get_child_attrs
=
operator
.
attrgetter
(
'subexprs'
)
except
AttributeError
:
# Python 2.3
def
__get_child_attrs
(
self
):
return
self
.
subexprs
_get_child_attrs
=
__get_child_attrs
child_attrs
=
property
(
fget
=
_get_child_attrs
)
child_attrs
=
property
(
fget
=
operator
.
attrgetter
(
'subexprs'
))
def
not_implemented
(
self
,
method_name
):
print_call_chain
(
method_name
,
"not implemented"
)
###
...
...
@@ -304,8 +297,6 @@ class ExprNode(Node):
return
typecast
(
type
,
py_object_type
,
self
.
result
())
return
typecast
(
type
,
self
.
ctype
(),
self
.
result
())
return
typecast
(
type
,
self
.
ctype
(),
self
.
result
())
def
py_result
(
self
):
# Return the result code cast to PyObject *.
return
self
.
result_as
(
py_object_type
)
...
...
@@ -434,7 +425,7 @@ class ExprNode(Node):
def
analyse_as_extension_type
(
self
,
env
):
# If this node can be interpreted as a reference to an
# extension type, return its type, else None.
# extension type
or builtin type
, return its type, else None.
return
None
def
analyse_types
(
self
,
env
):
...
...
@@ -806,6 +797,23 @@ class ExprNode(Node):
else
:
return
self
@
classmethod
def
from_node
(
cls
,
node
,
**
kwargs
):
"""Instantiate this node class from another node, properly
copying over all attributes that one would forget otherwise.
"""
attributes
=
"cf_state cf_maybe_null cf_is_null"
.
split
()
for
attr_name
in
attributes
:
if
attr_name
in
kwargs
:
continue
try
:
value
=
getattr
(
node
,
attr_name
)
except
AttributeError
:
pass
else
:
kwargs
[
attr_name
]
=
value
return
cls
(
node
.
pos
,
**
kwargs
)
class
AtomicExprNode
(
ExprNode
):
# Abstract base class for expression nodes which have
...
...
@@ -1083,6 +1091,15 @@ class BytesNode(ConstNode):
# start off as Python 'bytes' to support len() in O(1)
type
=
bytes_type
def
calculate_constant_result
(
self
):
self
.
constant_result
=
self
.
value
def
as_sliced_node
(
self
,
start
,
stop
,
step
=
None
):
value
=
StringEncoding
.
BytesLiteral
(
self
.
value
[
start
:
stop
:
step
])
value
.
encoding
=
self
.
value
.
encoding
return
BytesNode
(
self
.
pos
,
value
=
value
,
constant_result
=
value
)
def
compile_time_value
(
self
,
denv
):
return
self
.
value
...
...
@@ -1164,6 +1181,25 @@ class UnicodeNode(PyConstNode):
bytes_value
=
None
type
=
unicode_type
def
calculate_constant_result
(
self
):
self
.
constant_result
=
self
.
value
def
as_sliced_node
(
self
,
start
,
stop
,
step
=
None
):
if
_string_contains_surrogates
(
self
.
value
[:
stop
]):
# this is unsafe as it may give different results in different runtimes
return
None
value
=
StringEncoding
.
EncodedString
(
self
.
value
[
start
:
stop
:
step
])
value
.
encoding
=
self
.
value
.
encoding
if
self
.
bytes_value
is
not
None
:
bytes_value
=
StringEncoding
.
BytesLiteral
(
self
.
bytes_value
[
start
:
stop
:
step
])
bytes_value
.
encoding
=
self
.
bytes_value
.
encoding
else
:
bytes_value
=
None
return
UnicodeNode
(
self
.
pos
,
value
=
value
,
bytes_value
=
bytes_value
,
constant_result
=
value
)
def
coerce_to
(
self
,
dst_type
,
env
):
if
dst_type
is
self
.
type
:
pass
...
...
@@ -1190,21 +1226,7 @@ class UnicodeNode(PyConstNode):
## and (0xDC00 <= self.value[1] <= 0xDFFF))
def
contains_surrogates
(
self
):
# Check if the unicode string contains surrogate code points
# on a CPython platform with wide (UCS-4) or narrow (UTF-16)
# Unicode, i.e. characters that would be spelled as two
# separate code units on a narrow platform.
for
c
in
map
(
ord
,
self
.
value
):
if
c
>
65535
:
# can only happen on wide platforms
return
True
# We only look for the first code unit (D800-DBFF) of a
# surrogate pair - if we find one, the other one
# (DC00-DFFF) is likely there, too. If we don't find it,
# any second code unit cannot make for a surrogate pair by
# itself.
if
0xD800
<=
c
<=
0xDBFF
:
return
True
return
False
return
_string_contains_surrogates
(
self
.
value
)
def
generate_evaluation_code
(
self
,
code
):
self
.
result_code
=
code
.
get_py_string_const
(
self
.
value
)
...
...
@@ -1229,6 +1251,24 @@ class StringNode(PyConstNode):
is_identifier
=
None
unicode_value
=
None
def
calculate_constant_result
(
self
):
self
.
constant_result
=
self
.
value
def
as_sliced_node
(
self
,
start
,
stop
,
step
=
None
):
value
=
type
(
self
.
value
)(
self
.
value
[
start
:
stop
:
step
])
value
.
encoding
=
self
.
value
.
encoding
if
self
.
unicode_value
is
not
None
:
if
_string_contains_surrogates
(
self
.
unicode_value
[:
stop
]):
# this is unsafe as it may give different results in different runtimes
return
None
unicode_value
=
StringEncoding
.
EncodedString
(
self
.
unicode_value
[
start
:
stop
:
step
])
else
:
unicode_value
=
None
return
StringNode
(
self
.
pos
,
value
=
value
,
unicode_value
=
unicode_value
,
constant_result
=
value
,
is_identifier
=
self
.
is_identifier
)
def
coerce_to
(
self
,
dst_type
,
env
):
if
dst_type
is
not
py_object_type
and
not
str_type
.
subtype_of
(
dst_type
):
# if dst_type is Builtin.bytes_type:
...
...
@@ -1263,35 +1303,24 @@ class IdentifierStringNode(StringNode):
is_identifier
=
True
class
LongNode
(
AtomicExprNode
):
# Python long integer literal
#
# value string
type
=
py_object_type
def
calculate_constant_result
(
self
):
self
.
constant_result
=
Utils
.
str_to_number
(
self
.
value
)
def
compile_time_value
(
self
,
denv
):
return
Utils
.
str_to_number
(
self
.
value
)
def
analyse_types
(
self
,
env
):
self
.
is_temp
=
1
return
self
def
may_be_none
(
self
):
return
False
gil_message
=
"Constructing Python long int"
def
generate_result_code
(
self
,
code
):
code
.
putln
(
'%s = PyLong_FromString((char *)"%s", 0, 0); %s'
%
(
self
.
result
(),
self
.
value
,
code
.
error_goto_if_null
(
self
.
result
(),
self
.
pos
)))
code
.
put_gotref
(
self
.
py_result
())
def
_string_contains_surrogates
(
ustring
):
"""
Check if the unicode string contains surrogate code points
on a CPython platform with wide (UCS-4) or narrow (UTF-16)
Unicode, i.e. characters that would be spelled as two
separate code units on a narrow platform.
"""
for
c
in
map
(
ord
,
ustring
):
if
c
>
65535
:
# can only happen on wide platforms
return
True
# We only look for the first code unit (D800-DBFF) of a
# surrogate pair - if we find one, the other one
# (DC00-DFFF) is likely there, too. If we don't find it,
# any second code unit cannot make for a surrogate pair by
# itself.
if
0xD800
<=
c
<=
0xDBFF
:
return
True
return
False
class
ImagNode
(
AtomicExprNode
):
...
...
@@ -1499,10 +1528,10 @@ class NameNode(AtomicExprNode):
entry
=
self
.
entry
if
not
entry
:
entry
=
env
.
lookup
(
self
.
name
)
if
entry
and
entry
.
is_type
and
entry
.
type
.
is_extension_type
:
return
entry
.
type
else
:
return
None
if
entry
and
entry
.
is_type
:
if
entry
.
type
.
is_extension_type
or
entry
.
type
.
is_builtin_type
:
return
entry
.
type
return
None
def
analyse_target_declaration
(
self
,
env
):
if
not
self
.
entry
:
...
...
@@ -1580,6 +1609,7 @@ class NameNode(AtomicExprNode):
self
.
is_temp
=
False
self
.
is_used_as_rvalue
=
True
self
.
use_managed_ref
=
True
return
self
def
nogil_check
(
self
,
env
):
self
.
nogil
=
True
...
...
@@ -2611,7 +2641,7 @@ class IndexNode(ExprNode):
return
py_object_type
index_type
=
self
.
index
.
infer_type
(
env
)
if
index_type
and
index_type
.
is_int
or
isinstance
(
self
.
index
,
(
IntNode
,
LongNode
)
):
if
index_type
and
index_type
.
is_int
or
isinstance
(
self
.
index
,
IntNode
):
# indexing!
if
base_type
is
unicode_type
:
# Py_UCS4 will automatically coerce to a unicode string
...
...
@@ -2655,18 +2685,18 @@ class IndexNode(ExprNode):
return
py_object_type
def
analyse_types
(
self
,
env
):
self
.
analyse_base_and_index_types
(
env
,
getting
=
1
)
return
self
return
self
.
analyse_base_and_index_types
(
env
,
getting
=
True
)
def
analyse_target_types
(
self
,
env
):
self
.
analyse_base_and_index_types
(
env
,
setting
=
1
)
if
self
.
type
.
is_const
:
node
=
self
.
analyse_base_and_index_types
(
env
,
setting
=
True
)
if
node
.
type
.
is_const
:
error
(
self
.
pos
,
"Assignment to const dereference"
)
if
not
self
.
is_lvalue
():
error
(
self
.
pos
,
"Assignment to non-lvalue of type '%s'"
%
self
.
type
)
return
self
if
not
node
.
is_lvalue
():
error
(
self
.
pos
,
"Assignment to non-lvalue of type '%s'"
%
node
.
type
)
return
node
def
analyse_base_and_index_types
(
self
,
env
,
getting
=
0
,
setting
=
0
,
analyse_base
=
True
):
def
analyse_base_and_index_types
(
self
,
env
,
getting
=
False
,
setting
=
False
,
analyse_base
=
True
):
# Note: This might be cleaned up by having IndexNode
# parsed in a saner way and only construct the tuple if
# needed.
...
...
@@ -2690,7 +2720,7 @@ class IndexNode(ExprNode):
# Do not visit child tree if base is undeclared to avoid confusing
# error messages
self
.
type
=
PyrexTypes
.
error_type
return
return
self
is_slice
=
isinstance
(
self
.
index
,
SliceNode
)
...
...
@@ -2739,9 +2769,10 @@ class IndexNode(ExprNode):
if
len
(
indices
)
-
len
(
newaxes
)
>
self
.
base
.
type
.
ndim
:
self
.
type
=
error_type
return
error
(
indices
[
self
.
base
.
type
.
ndim
].
pos
,
"Too many indices specified for type %s"
%
self
.
base
.
type
)
error
(
indices
[
self
.
base
.
type
.
ndim
].
pos
,
"Too many indices specified for type %s"
%
self
.
base
.
type
)
return
self
axis_idx
=
0
for
i
,
index
in
enumerate
(
indices
[:]):
...
...
@@ -2784,7 +2815,8 @@ class IndexNode(ExprNode):
else
:
self
.
type
=
error_type
return
error
(
index
.
pos
,
"Invalid index for memoryview specified"
)
error
(
index
.
pos
,
"Invalid index for memoryview specified"
)
return
self
self
.
memslice_index
=
self
.
memslice_index
and
not
self
.
memslice_slice
self
.
original_indices
=
indices
...
...
@@ -2849,7 +2881,7 @@ class IndexNode(ExprNode):
if
not
MemoryView
.
validate_axes
(
self
.
pos
,
axes
):
self
.
type
=
error_type
return
return
self
self
.
type
=
PyrexTypes
.
MemoryViewSliceType
(
self
.
base
.
type
.
dtype
,
axes
)
...
...
@@ -2920,15 +2952,15 @@ class IndexNode(ExprNode):
PyrexTypes
.
c_py_ssize_t_type
,
env
)
elif
not
self
.
index
.
type
.
is_int
:
error
(
self
.
pos
,
"Invalid index type '%s'"
%
self
.
index
.
type
)
"Invalid index type '%s'"
%
self
.
index
.
type
)
elif
base_type
.
is_cpp_class
:
function
=
env
.
lookup_operator
(
"[]"
,
[
self
.
base
,
self
.
index
])
if
function
is
None
:
error
(
self
.
pos
,
"Indexing '%s' not supported for index type '%s'"
%
(
base_type
,
self
.
index
.
type
))
self
.
type
=
PyrexTypes
.
error_type
self
.
result_code
=
"<error>"
return
return
self
func_type
=
function
.
type
if
func_type
.
is_ptr
:
func_type
=
func_type
.
base_type
...
...
@@ -2940,11 +2972,12 @@ class IndexNode(ExprNode):
self
.
parse_indexed_fused_cdef
(
env
)
else
:
error
(
self
.
pos
,
"Attempting to index non-array type '%s'"
%
base_type
)
"Attempting to index non-array type '%s'"
%
base_type
)
self
.
type
=
PyrexTypes
.
error_type
self
.
wrap_in_nonecheck_node
(
env
,
getting
)
return
self
def
wrap_in_nonecheck_node
(
self
,
env
,
getting
):
if
not
env
.
directives
[
'nonecheck'
]
or
not
self
.
base
.
may_be_none
():
...
...
@@ -3455,23 +3488,15 @@ class SliceIndexNode(ExprNode):
self
.
base
=
self
.
base
.
analyse_types
(
env
)
if
self
.
base
.
type
.
is_memoryviewslice
:
# Gross hack here! But we do not know the type until this point,
# and we cannot create and return a new node. So we change the
# type...
none_node
=
NoneNode
(
self
.
pos
)
index
=
SliceNode
(
self
.
pos
,
start
=
self
.
start
or
none_node
,
stop
=
self
.
stop
or
none_node
,
step
=
none_node
)
del
self
.
start
del
self
.
stop
self
.
index
=
index
self
.
__class__
=
IndexNode
self
.
analyse_base_and_index_types
(
env
,
getting
=
getting
,
setting
=
not
getting
,
analyse_base
=
False
)
return
self
index_node
=
IndexNode
(
self
.
pos
,
index
,
base
=
self
.
base
)
return
index_node
.
analyse_base_and_index_types
(
env
,
getting
=
getting
,
setting
=
not
getting
,
analyse_base
=
False
)
if
self
.
start
:
self
.
start
=
self
.
start
.
analyse_types
(
env
)
...
...
@@ -3929,23 +3954,6 @@ class SimpleCallNode(CallNode):
self
.
is_temp
=
1
else
:
self
.
args
=
[
arg
.
analyse_types
(
env
)
for
arg
in
self
.
args
]
if
self
.
self
and
func_type
.
args
:
# Coerce 'self' to the type expected by the method.
self_arg
=
func_type
.
args
[
0
]
if
self_arg
.
not_none
:
# C methods must do the None test for self at *call* time
self
.
self
=
self
.
self
.
as_none_safe_node
(
"'NoneType' object has no attribute '%s'"
,
error
=
'PyExc_AttributeError'
,
format_args
=
[
self
.
function
.
entry
.
name
])
expected_type
=
self_arg
.
type
if
self_arg
.
accept_builtin_subtypes
:
self
.
coerced_self
=
CMethodSelfCloneNode
(
self
.
self
)
else
:
self
.
coerced_self
=
CloneNode
(
self
.
self
)
self
.
coerced_self
=
self
.
coerced_self
.
coerce_to
(
expected_type
,
env
)
# Insert coerced 'self' argument into argument list.
self
.
args
.
insert
(
0
,
self
.
coerced_self
)
self
.
analyse_c_function_call
(
env
)
return
self
...
...
@@ -3965,6 +3973,11 @@ class SimpleCallNode(CallNode):
self
.
type
=
error_type
return
if
self
.
self
:
args
=
[
self
.
self
]
+
self
.
args
else
:
args
=
self
.
args
if
self
.
function
.
type
.
is_cpp_class
:
overloaded_entry
=
self
.
function
.
type
.
scope
.
lookup
(
"operator()"
)
if
overloaded_entry
is
None
:
...
...
@@ -3986,7 +3999,7 @@ class SimpleCallNode(CallNode):
else
:
alternatives
=
overloaded_entry
.
all_alternatives
()
entry
=
PyrexTypes
.
best_match
(
self
.
args
,
alternatives
,
self
.
pos
,
env
)
entry
=
PyrexTypes
.
best_match
(
args
,
alternatives
,
self
.
pos
,
env
)
if
not
entry
:
self
.
type
=
PyrexTypes
.
error_type
...
...
@@ -3998,24 +4011,60 @@ class SimpleCallNode(CallNode):
self
.
function
.
type
=
entry
.
type
func_type
=
self
.
function_type
()
else
:
entry
=
None
func_type
=
self
.
function_type
()
if
not
func_type
.
is_cfunction
:
error
(
self
.
pos
,
"Calling non-function type '%s'"
%
func_type
)
self
.
type
=
PyrexTypes
.
error_type
self
.
result_code
=
"<error>"
return
# Check no. of args
max_nargs
=
len
(
func_type
.
args
)
expected_nargs
=
max_nargs
-
func_type
.
optional_arg_count
actual_nargs
=
len
(
self
.
args
)
actual_nargs
=
len
(
args
)
if
func_type
.
optional_arg_count
and
expected_nargs
!=
actual_nargs
:
self
.
has_optional_args
=
1
self
.
is_temp
=
1
# check 'self' argument
if
entry
and
entry
.
is_cmethod
and
func_type
.
args
:
formal_arg
=
func_type
.
args
[
0
]
arg
=
args
[
0
]
if
formal_arg
.
not_none
:
if
self
.
self
:
self
.
self
=
self
.
self
.
as_none_safe_node
(
"'NoneType' object has no attribute '%s'"
,
error
=
'PyExc_AttributeError'
,
format_args
=
[
entry
.
name
])
else
:
# unbound method
arg
=
arg
.
as_none_safe_node
(
"descriptor '%s' requires a '%s' object but received a 'NoneType'"
,
format_args
=
[
entry
.
name
,
formal_arg
.
type
.
name
])
if
self
.
self
:
if
formal_arg
.
accept_builtin_subtypes
:
arg
=
CMethodSelfCloneNode
(
self
.
self
)
else
:
arg
=
CloneNode
(
self
.
self
)
arg
=
self
.
coerced_self
=
arg
.
coerce_to
(
formal_arg
.
type
,
env
)
elif
formal_arg
.
type
.
is_builtin_type
:
# special case: unbound methods of builtins accept subtypes
arg
=
arg
.
coerce_to
(
formal_arg
.
type
,
env
)
if
arg
.
type
.
is_builtin_type
and
isinstance
(
arg
,
PyTypeTestNode
):
arg
.
exact_builtin_type
=
False
args
[
0
]
=
arg
# Coerce arguments
some_args_in_temps
=
False
for
i
in
xrange
(
min
(
max_nargs
,
actual_nargs
)):
formal_type
=
func_type
.
args
[
i
].
type
arg
=
self
.
args
[
i
].
coerce_to
(
formal_type
,
env
)
formal_arg
=
func_type
.
args
[
i
]
formal_type
=
formal_arg
.
type
arg
=
args
[
i
].
coerce_to
(
formal_type
,
env
)
if
formal_arg
.
not_none
:
# C methods must do the None checks at *call* time
arg
=
arg
.
as_none_safe_node
(
"cannot pass None into a C function argument that is declared 'not None'"
)
if
arg
.
is_temp
:
if
i
>
0
:
# first argument in temp doesn't impact subsequent arguments
...
...
@@ -4035,19 +4084,21 @@ class SimpleCallNode(CallNode):
if
i
>
0
:
# first argument doesn't matter
some_args_in_temps
=
True
arg
=
arg
.
coerce_to_temp
(
env
)
self
.
args
[
i
]
=
arg
args
[
i
]
=
arg
# handle additional varargs parameters
for
i
in
xrange
(
max_nargs
,
actual_nargs
):
arg
=
self
.
args
[
i
]
arg
=
args
[
i
]
if
arg
.
type
.
is_pyobject
:
arg_ctype
=
arg
.
type
.
default_coerced_ctype
()
if
arg_ctype
is
None
:
error
(
self
.
args
[
i
].
pos
,
"Python object cannot be passed as a varargs parameter"
)
else
:
self
.
args
[
i
]
=
arg
=
arg
.
coerce_to
(
arg_ctype
,
env
)
args
[
i
]
=
arg
=
arg
.
coerce_to
(
arg_ctype
,
env
)
if
arg
.
is_temp
and
i
>
0
:
some_args_in_temps
=
True
if
some_args_in_temps
:
# if some args are temps and others are not, they may get
# constructed in the wrong order (temps first) => make
...
...
@@ -4057,7 +4108,7 @@ class SimpleCallNode(CallNode):
for
i
in
xrange
(
actual_nargs
-
1
):
if
i
==
0
and
self
.
self
is
not
None
:
continue
# self is ok
arg
=
self
.
args
[
i
]
arg
=
args
[
i
]
if
arg
.
nonlocally_immutable
():
# locals, C functions, unassignable types are safe.
pass
...
...
@@ -4076,6 +4127,8 @@ class SimpleCallNode(CallNode):
warning
(
arg
.
pos
,
"Argument evaluation order in C function call is undefined and may not be as expected"
,
0
)
break
self
.
args
[:]
=
args
# Calc result type and code fragment
if
isinstance
(
self
.
function
,
NewExprNode
):
self
.
type
=
PyrexTypes
.
CPtrType
(
self
.
function
.
class_type
)
...
...
@@ -4697,19 +4750,21 @@ class AttributeNode(ExprNode):
return
self
.
obj
.
type_dependencies
(
env
)
def
infer_type
(
self
,
env
):
if
self
.
analyse_as_cimported_attribute
(
env
,
0
):
return
self
.
entry
.
type
elif
self
.
analyse_as_unbound_cmethod
(
env
):
return
self
.
entry
.
type
else
:
obj_type
=
self
.
obj
.
infer_type
(
env
)
self
.
analyse_attribute
(
env
,
obj_type
=
obj_type
)
if
obj_type
.
is_builtin_type
and
self
.
type
.
is_cfunction
:
# special case: C-API replacements for C methods of
# builtin types cannot be inferred as C functions as
# that would prevent their use as bound methods
return
py_object_type
return
self
.
type
# FIXME: this is way too redundant with analyse_types()
node
=
self
.
analyse_as_cimported_attribute_node
(
env
,
target
=
False
)
if
node
is
not
None
:
return
node
.
entry
.
type
node
=
self
.
analyse_as_unbound_cmethod_node
(
env
)
if
node
is
not
None
:
return
node
.
entry
.
type
obj_type
=
self
.
obj
.
infer_type
(
env
)
self
.
analyse_attribute
(
env
,
obj_type
=
obj_type
)
if
obj_type
.
is_builtin_type
and
self
.
type
.
is_cfunction
:
# special case: C-API replacements for C methods of
# builtin types cannot be inferred as C functions as
# that would prevent their use as bound methods
return
py_object_type
return
self
.
type
def
analyse_target_declaration
(
self
,
env
):
pass
...
...
@@ -4724,21 +4779,19 @@ class AttributeNode(ExprNode):
def
analyse_types
(
self
,
env
,
target
=
0
):
self
.
initialized_check
=
env
.
directives
[
'initializedcheck'
]
if
self
.
analyse_as_cimported_attribute
(
env
,
target
):
self
.
entry
.
used
=
True
elif
not
target
and
self
.
analyse_as_unbound_cmethod
(
env
):
self
.
entry
.
used
=
True
else
:
self
.
analyse_as_ordinary_attribute
(
env
,
target
)
if
self
.
entry
:
self
.
entry
.
used
=
True
# may be mutated in a namenode now :)
if
self
.
is_attribute
:
self
.
wrap_obj_in_nonecheck
(
env
)
return
self
node
=
self
.
analyse_as_cimported_attribute_node
(
env
,
target
)
if
node
is
None
and
not
target
:
node
=
self
.
analyse_as_unbound_cmethod_node
(
env
)
if
node
is
None
:
node
=
self
.
analyse_as_ordinary_attribute_node
(
env
,
target
)
assert
node
is
not
None
if
node
.
entry
:
node
.
entry
.
used
=
True
if
node
.
is_attribute
:
node
.
wrap_obj_in_nonecheck
(
env
)
return
node
def
analyse_as_cimported_attribute
(
self
,
env
,
target
):
def
analyse_as_cimported_attribute
_node
(
self
,
env
,
target
):
# Try to interpret this as a reference to an imported
# C const, type, var or function. If successful, mutates
# this node into a NameNode and returns 1, otherwise
...
...
@@ -4747,33 +4800,36 @@ class AttributeNode(ExprNode):
if
module_scope
:
entry
=
module_scope
.
lookup_here
(
self
.
attribute
)
if
entry
and
(
entry
.
is_cglobal
or
entry
.
is_cfunction
or
entry
.
is_type
or
entry
.
is_const
):
self
.
mutate_into_name_node
(
env
,
entry
,
target
)
# FIXME
entry
.
used
=
1
return
1
return
0
entry
.
is_cglobal
or
entry
.
is_cfunction
or
entry
.
is_type
or
entry
.
is_const
):
return
self
.
as_name_node
(
env
,
entry
,
target
)
return
None
def
analyse_as_unbound_cmethod
(
self
,
env
):
def
analyse_as_unbound_cmethod
_node
(
self
,
env
):
# Try to interpret this as a reference to an unbound
# C method of an extension type
. If successful, mutates
#
this node into a NameNode and returns 1
, otherwise
# returns
0
.
# C method of an extension type
or builtin type. If successful,
#
creates a corresponding NameNode and returns it
, otherwise
# returns
None
.
type
=
self
.
obj
.
analyse_as_extension_type
(
env
)
if
type
:
entry
=
type
.
scope
.
lookup_here
(
self
.
attribute
)
if
entry
and
entry
.
is_cmethod
:
# Create a temporary entry describing the C method
# as an ordinary function.
ubcm_entry
=
Symtab
.
Entry
(
entry
.
name
,
"%s->%s"
%
(
type
.
vtabptr_cname
,
entry
.
cname
),
entry
.
type
)
ubcm_entry
.
is_cfunction
=
1
ubcm_entry
.
func_cname
=
entry
.
func_cname
ubcm_entry
.
is_unbound_cmethod
=
1
self
.
mutate_into_name_node
(
env
,
ubcm_entry
,
None
)
# FIXME
return
1
return
0
if
type
.
is_builtin_type
:
if
not
self
.
is_called
:
# must handle this as Python object
return
None
ubcm_entry
=
entry
else
:
# Create a temporary entry describing the C method
# as an ordinary function.
ubcm_entry
=
Symtab
.
Entry
(
entry
.
name
,
"%s->%s"
%
(
type
.
vtabptr_cname
,
entry
.
cname
),
entry
.
type
)
ubcm_entry
.
is_cfunction
=
1
ubcm_entry
.
func_cname
=
entry
.
func_cname
ubcm_entry
.
is_unbound_cmethod
=
1
return
self
.
as_name_node
(
env
,
ubcm_entry
,
target
=
False
)
return
None
def
analyse_as_type
(
self
,
env
):
module_scope
=
self
.
obj
.
analyse_as_module
(
env
)
...
...
@@ -4791,8 +4847,9 @@ class AttributeNode(ExprNode):
module_scope
=
self
.
obj
.
analyse_as_module
(
env
)
if
module_scope
:
entry
=
module_scope
.
lookup_here
(
self
.
attribute
)
if
entry
and
entry
.
is_type
and
entry
.
type
.
is_extension_type
:
return
entry
.
type
if
entry
and
entry
.
is_type
:
if
entry
.
type
.
is_extension_type
or
entry
.
type
.
is_builtin_type
:
return
entry
.
type
return
None
def
analyse_as_module
(
self
,
env
):
...
...
@@ -4805,20 +4862,18 @@ class AttributeNode(ExprNode):
return
entry
.
as_module
return
None
def
mutate_into
_name_node
(
self
,
env
,
entry
,
target
):
#
Mutate this node into a NameN
ode and complete the
def
as
_name_node
(
self
,
env
,
entry
,
target
):
#
Create a corresponding NameNode from this n
ode and complete the
# analyse_types phase.
self
.
__class__
=
NameNode
self
.
name
=
self
.
attribute
self
.
entry
=
entry
del
self
.
obj
del
self
.
attribute
node
=
NameNode
.
from_node
(
self
,
name
=
self
.
attribute
,
entry
=
entry
)
if
target
:
NameNode
.
analyse_target_types
(
self
,
env
)
# FIXME
node
=
node
.
analyse_target_types
(
env
)
else
:
NameNode
.
analyse_rvalue_entry
(
self
,
env
)
node
=
node
.
analyse_rvalue_entry
(
env
)
node
.
entry
.
used
=
1
return
node
def
analyse_as_ordinary_attribute
(
self
,
env
,
target
):
def
analyse_as_ordinary_attribute
_node
(
self
,
env
,
target
):
self
.
obj
=
self
.
obj
.
analyse_types
(
env
)
self
.
analyse_attribute
(
env
)
if
self
.
entry
and
self
.
entry
.
is_cmethod
and
not
self
.
is_called
:
...
...
@@ -4835,6 +4890,7 @@ class AttributeNode(ExprNode):
error
(
self
.
pos
,
"Assignment to an immutable object field"
)
#elif self.type.is_memoryviewslice and not target:
# self.is_temp = True
return
self
def
analyse_attribute
(
self
,
env
,
obj_type
=
None
):
# Look up attribute and set self.type and self.member.
...
...
@@ -6760,14 +6816,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
def
analyse_types
(
self
,
env
):
if
self
.
binding
:
if
self
.
specialized_cpdefs
or
self
.
is_specialization
:
env
.
use_utility_code
(
UtilityCode
.
load_cached
(
"FusedFunction"
,
"CythonFunction.c"
))
else
:
env
.
use_utility_code
(
UtilityCode
.
load_cached
(
"CythonFunction"
,
"CythonFunction.c"
))
self
.
analyse_default_args
(
env
)
#TODO(craig,haoyu) This should be moved to a better place
self
.
set_qualified_name
(
env
,
self
.
def_node
.
name
)
return
self
...
...
@@ -6867,14 +6916,18 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
code
.
put_gotref
(
self
.
py_result
())
def
generate_cyfunction_code
(
self
,
code
):
def_node
=
self
.
def_node
if
self
.
specialized_cpdefs
:
constructor
=
"__pyx_FusedFunction_NewEx"
def_node
=
self
.
specialized_cpdefs
[
0
]
elif
self
.
is_specialization
:
else
:
def_node
=
self
.
def_node
if
self
.
specialized_cpdefs
or
self
.
is_specialization
:
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"FusedFunction"
,
"CythonFunction.c"
))
constructor
=
"__pyx_FusedFunction_NewEx"
else
:
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"CythonFunction"
,
"CythonFunction.c"
))
constructor
=
"__Pyx_CyFunction_NewEx"
if
self
.
code_object
:
...
...
@@ -9199,6 +9252,11 @@ class CmpNode(object):
self
.
special_bool_cmp_utility_code
=
UtilityCode
.
load_cached
(
"PyDictContains"
,
"ObjectHandling.c"
)
self
.
special_bool_cmp_function
=
"__Pyx_PyDict_Contains"
return
True
elif
self
.
operand2
.
type
is
Builtin
.
unicode_type
:
self
.
operand2
=
self
.
operand2
.
as_none_safe_node
(
"'NoneType' object is not iterable"
)
self
.
special_bool_cmp_utility_code
=
UtilityCode
.
load_cached
(
"PyUnicodeContains"
,
"StringTools.c"
)
self
.
special_bool_cmp_function
=
"__Pyx_PyUnicode_Contains"
return
True
else
:
if
not
self
.
operand2
.
type
.
is_pyobject
:
self
.
operand2
=
self
.
operand2
.
coerce_to_pyobject
(
env
)
...
...
@@ -9717,6 +9775,8 @@ class PyTypeTestNode(CoercionNode):
# object is an instance of a particular extension type.
# This node borrows the result of its argument node.
exact_builtin_type
=
True
def
__init__
(
self
,
arg
,
dst_type
,
env
,
notnone
=
False
):
# The arg is know to be a Python object, and
# the dst_type is known to be an extension type.
...
...
@@ -9758,12 +9818,17 @@ class PyTypeTestNode(CoercionNode):
def
generate_result_code
(
self
,
code
):
if
self
.
type
.
typeobj_is_available
():
if
not
self
.
type
.
is_builtin_type
:
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"ExtTypeTest"
,
"ObjectHandling.c"
))
code
.
putln
(
"if (!(%s)) %s"
%
(
self
.
type
.
type_test_code
(
self
.
arg
.
py_result
(),
self
.
notnone
),
code
.
error_goto
(
self
.
pos
)))
if
self
.
type
.
is_builtin_type
:
type_test
=
self
.
type
.
type_test_code
(
self
.
arg
.
py_result
(),
self
.
notnone
,
exact
=
self
.
exact_builtin_type
)
else
:
type_test
=
self
.
type
.
type_test_code
(
self
.
arg
.
py_result
(),
self
.
notnone
)
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"ExtTypeTest"
,
"ObjectHandling.c"
))
code
.
putln
(
"if (!(%s)) %s"
%
(
type_test
,
code
.
error_goto
(
self
.
pos
)))
else
:
error
(
self
.
pos
,
"Cannot test type of extern C class "
"without type object name specification"
)
...
...
Cython/Compiler/ModuleNode.py
View file @
c73a9b2d
...
...
@@ -1044,30 +1044,52 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
else
:
unused_marker
=
'CYTHON_UNUSED '
need_self_cast
=
type
.
vtabslot_cname
or
have_entries
or
cpp_class_attrs
if
base_type
:
freelist_size
=
0
# not currently supported
else
:
freelist_size
=
scope
.
directives
.
get
(
'freelist'
,
0
)
freelist_name
=
scope
.
mangle_internal
(
Naming
.
freelist_name
)
freecount_name
=
scope
.
mangle_internal
(
Naming
.
freecount_name
)
decls
=
code
.
globalstate
[
'decls'
]
decls
.
putln
(
"static PyObject *%s(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/"
%
slot_func
)
code
.
putln
(
""
)
if
freelist_size
:
code
.
putln
(
"static %s[%d];"
%
(
scope
.
parent_type
.
declaration_code
(
freelist_name
),
freelist_size
))
code
.
putln
(
"static int %s = 0;"
%
freecount_name
)
code
.
putln
(
""
)
code
.
putln
(
"static PyObject *%s(PyTypeObject *t, %sPyObject *a, %sPyObject *k) {"
%
(
scope
.
mangle_internal
(
"tp_new"
),
unused_marker
,
unused_marker
))
%
(
slot_func
,
unused_marker
,
unused_marker
))
need_self_cast
=
type
.
vtabslot_cname
or
have_entries
or
cpp_class_attrs
if
need_self_cast
:
code
.
putln
(
"%s;"
%
scope
.
parent_type
.
declaration_code
(
"p"
))
code
.
putln
(
"%s;"
%
scope
.
parent_type
.
declaration_code
(
"p"
))
if
base_type
:
tp_new
=
TypeSlots
.
get_base_slot_function
(
scope
,
tp_slot
)
if
tp_new
is
None
:
tp_new
=
"%s->tp_new"
%
base_type
.
typeptr_cname
code
.
putln
(
"PyObject *o = %s(t, a, k);"
%
tp_new
)
code
.
putln
(
"PyObject *o = %s(t, a, k);"
%
tp_new
)
else
:
code
.
putln
(
"PyObject *o = (*t->tp_alloc)(t, 0);"
)
code
.
putln
(
"if (!o) return 0;"
)
code
.
putln
(
"PyObject *o;"
)
if
freelist_size
:
code
.
putln
(
"if ((%s > 0) & (t->tp_basicsize == sizeof(%s))) {"
%
(
freecount_name
,
type
.
declaration_code
(
""
,
deref
=
True
)))
code
.
putln
(
"o = (PyObject*)%s[--%s];"
%
(
freelist_name
,
freecount_name
))
code
.
putln
(
"PyObject_INIT(o, t);"
)
if
scope
.
needs_gc
():
code
.
putln
(
"PyObject_GC_Track(o);"
)
code
.
putln
(
"} else {"
)
code
.
putln
(
"o = (*t->tp_alloc)(t, 0);"
)
code
.
putln
(
"if (!o) return 0;"
)
if
freelist_size
and
not
base_type
:
code
.
putln
(
'}'
)
if
need_self_cast
:
code
.
putln
(
"p = %s;"
%
type
.
cast_code
(
"o"
))
code
.
putln
(
"p = %s;"
%
type
.
cast_code
(
"o"
))
#if need_self_cast:
# self.generate_self_cast(scope, code)
if
type
.
vtabslot_cname
:
...
...
@@ -1191,8 +1213,20 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"CallNextTpDealloc"
,
"ExtensionTypes.c"
))
else
:
code
.
putln
(
"(*Py_TYPE(o)->tp_free)(o);"
)
freelist_size
=
scope
.
directives
.
get
(
'freelist'
,
0
)
if
freelist_size
:
freelist_name
=
scope
.
mangle_internal
(
Naming
.
freelist_name
)
freecount_name
=
scope
.
mangle_internal
(
Naming
.
freecount_name
)
type
=
scope
.
parent_type
code
.
putln
(
"if ((%s < %d) & (Py_TYPE(o)->tp_basicsize == sizeof(%s))) {"
%
(
freecount_name
,
freelist_size
,
type
.
declaration_code
(
""
,
deref
=
True
)))
code
.
putln
(
"%s[%s++] = %s;"
%
(
freelist_name
,
freecount_name
,
type
.
cast_code
(
"o"
)))
code
.
putln
(
"} else {"
)
code
.
putln
(
"(*Py_TYPE(o)->tp_free)(o);"
)
if
freelist_size
:
code
.
putln
(
"}"
)
code
.
putln
(
"}"
)
...
...
@@ -2049,6 +2083,19 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
PyrexTypes
.
py_object_type
,
clear_before_decref
=
True
,
nanny
=
False
)
for
entry
in
env
.
c_class_entries
:
cclass_type
=
entry
.
type
if
cclass_type
.
is_external
or
cclass_type
.
base_type
:
continue
if
cclass_type
.
scope
.
directives
.
get
(
'freelist'
,
0
):
scope
=
cclass_type
.
scope
freelist_name
=
scope
.
mangle_internal
(
Naming
.
freelist_name
)
freecount_name
=
scope
.
mangle_internal
(
Naming
.
freecount_name
)
code
.
putln
(
"while (%s > 0) {"
%
freecount_name
)
code
.
putln
(
"PyObject* o = (PyObject*)%s[--%s];"
%
(
freelist_name
,
freecount_name
))
code
.
putln
(
"(*Py_TYPE(o)->tp_free)(o);"
)
code
.
putln
(
"}"
)
# for entry in env.pynum_entries:
# code.put_decref_clear(entry.cname,
# PyrexTypes.py_object_type,
...
...
Cython/Compiler/Naming.py
View file @
c73a9b2d
...
...
@@ -103,6 +103,8 @@ global_code_object_cache_find = pyrex_prefix + 'find_code_object'
global_code_object_cache_insert
=
pyrex_prefix
+
'insert_code_object'
genexpr_id_ref
=
'genexpr'
freelist_name
=
'freelist'
freecount_name
=
'freecount'
line_c_macro
=
"__LINE__"
...
...
Cython/Compiler/Nodes.py
View file @
c73a9b2d
...
...
@@ -4189,6 +4189,9 @@ class CClassDefNode(ClassDefNode):
%
base_class_entry
.
type
.
name
)
else
:
self
.
base_type
=
base_class_entry
.
type
if
env
.
directives
.
get
(
'freelist'
,
0
)
>
0
:
warning
(
self
.
pos
,
"freelists cannot be used on subtypes, only the base class can manage them"
,
1
)
has_body
=
self
.
body
is
not
None
if
self
.
module_name
and
self
.
visibility
!=
'extern'
:
module_path
=
self
.
module_name
.
split
(
"."
)
...
...
Cython/Compiler/Optimize.py
View file @
c73a9b2d
from
Cython.Compiler
import
TypeSlots
from
Cython.Compiler.ExprNodes
import
not_a_constant
import
cython
cython
.
declare
(
UtilityCode
=
object
,
EncodedString
=
object
,
BytesLiteral
=
object
,
Nodes
=
object
,
ExprNodes
=
object
,
PyrexTypes
=
object
,
Builtin
=
object
,
...
...
@@ -1787,13 +1789,14 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform):
node
=
ExprNodes
.
PythonCapiCallNode
(
coerce_node
.
pos
,
"__Pyx_PyBytes_GetItemInt"
,
self
.
PyBytes_GetItemInt_func_type
,
args
=
[
args
=
[
arg
.
base
.
as_none_safe_node
(
"'NoneType' object is not subscriptable"
),
index_node
.
coerce_to
(
PyrexTypes
.
c_py_ssize_t_type
,
env
),
bound_check_node
,
],
is_temp
=
True
,
utility_code
=
load_c_utility
(
'bytes_index'
))
is_temp
=
True
,
utility_code
=
UtilityCode
.
load_cached
(
'bytes_index'
,
'StringTools.c'
))
if
coerce_node
.
type
is
not
PyrexTypes
.
c_char_type
:
node
=
node
.
coerce_to
(
coerce_node
.
type
,
env
)
return
node
...
...
@@ -2140,14 +2143,22 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform):
Pyx_tp_new_func_type
=
PyrexTypes
.
CFuncType
(
PyrexTypes
.
py_object_type
,
[
PyrexTypes
.
CFuncTypeArg
(
"type"
,
Builtin
.
type_type
,
None
)
PyrexTypes
.
CFuncTypeArg
(
"type"
,
PyrexTypes
.
py_object_type
,
None
),
PyrexTypes
.
CFuncTypeArg
(
"args"
,
Builtin
.
tuple_type
,
None
),
])
def
_handle_simple_slot__new__
(
self
,
node
,
args
,
is_unbound_method
):
"""Replace 'exttype.__new__(exttype)' by a call to exttype->tp_new()
Pyx_tp_new_kwargs_func_type
=
PyrexTypes
.
CFuncType
(
PyrexTypes
.
py_object_type
,
[
PyrexTypes
.
CFuncTypeArg
(
"type"
,
PyrexTypes
.
py_object_type
,
None
),
PyrexTypes
.
CFuncTypeArg
(
"args"
,
Builtin
.
tuple_type
,
None
),
PyrexTypes
.
CFuncTypeArg
(
"kwargs"
,
Builtin
.
dict_type
,
None
),
])
def
_handle_any_slot__new__
(
self
,
node
,
args
,
is_unbound_method
,
kwargs
=
None
):
"""Replace 'exttype.__new__(exttype, ...)' by a call to exttype->tp_new()
"""
obj
=
node
.
function
.
obj
if
not
is_unbound_method
or
len
(
args
)
!=
1
:
if
not
is_unbound_method
or
len
(
args
)
<
1
:
return
node
type_arg
=
args
[
0
]
if
not
obj
.
is_name
or
not
type_arg
.
is_name
:
...
...
@@ -2165,21 +2176,53 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform):
# different types - may or may not lead to an error at runtime
return
node
# FIXME: we could potentially look up the actual tp_new C
# method of the extension type and call that instead of the
# generic slot. That would also allow us to pass parameters
# efficiently.
args_tuple
=
ExprNodes
.
TupleNode
(
node
.
pos
,
args
=
args
[
1
:])
args_tuple
=
args_tuple
.
analyse_types
(
self
.
current_env
(),
skip_children
=
True
)
if
not
type_arg
.
type_entry
:
if
type_arg
.
type_entry
:
ext_type
=
type_arg
.
type_entry
.
type
if
ext_type
.
is_extension_type
and
ext_type
.
typeobj_cname
:
tp_slot
=
TypeSlots
.
ConstructorSlot
(
"tp_new"
,
'__new__'
)
slot_func_cname
=
TypeSlots
.
get_slot_function
(
ext_type
.
scope
,
tp_slot
)
if
slot_func_cname
:
cython_scope
=
self
.
context
.
cython_scope
PyTypeObjectPtr
=
PyrexTypes
.
CPtrType
(
cython_scope
.
lookup
(
'PyTypeObject'
).
type
)
pyx_tp_new_kwargs_func_type
=
PyrexTypes
.
CFuncType
(
PyrexTypes
.
py_object_type
,
[
PyrexTypes
.
CFuncTypeArg
(
"type"
,
PyTypeObjectPtr
,
None
),
PyrexTypes
.
CFuncTypeArg
(
"args"
,
PyrexTypes
.
py_object_type
,
None
),
PyrexTypes
.
CFuncTypeArg
(
"kwargs"
,
PyrexTypes
.
py_object_type
,
None
),
])
type_arg
=
ExprNodes
.
CastNode
(
type_arg
,
PyTypeObjectPtr
)
if
not
kwargs
:
kwargs
=
ExprNodes
.
NullNode
(
node
.
pos
,
type
=
PyrexTypes
.
py_object_type
)
# hack?
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
slot_func_cname
,
pyx_tp_new_kwargs_func_type
,
args
=
[
type_arg
,
args_tuple
,
kwargs
],
is_temp
=
True
)
else
:
# arbitrary variable, needs a None check for safety
type_arg
=
type_arg
.
as_none_safe_node
(
"object.__new__(X): X is not a type object (NoneType)"
)
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"__Pyx_tp_new"
,
self
.
Pyx_tp_new_func_type
,
args
=
[
type_arg
],
utility_code
=
tpnew_utility_code
,
is_temp
=
node
.
is_temp
utility_code
=
UtilityCode
.
load_cached
(
'tp_new'
,
'ObjectHandling.c'
)
if
kwargs
:
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"__Pyx_tp_new_kwargs"
,
self
.
Pyx_tp_new_kwargs_func_type
,
args
=
[
type_arg
,
args_tuple
,
kwargs
],
utility_code
=
utility_code
,
is_temp
=
node
.
is_temp
)
else
:
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"__Pyx_tp_new"
,
self
.
Pyx_tp_new_func_type
,
args
=
[
type_arg
,
args_tuple
],
utility_code
=
utility_code
,
is_temp
=
node
.
is_temp
)
### methods of builtin types
...
...
@@ -2341,7 +2384,8 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform):
method_name
=
node
.
function
.
attribute
if
method_name
==
'istitle'
:
# istitle() doesn't directly map to Py_UNICODE_ISTITLE()
utility_code
=
load_c_utility
(
"py_unicode_istitle"
)
utility_code
=
UtilityCode
.
load_cached
(
"py_unicode_istitle"
,
"StringTools.c"
)
function_name
=
'__Pyx_Py_UNICODE_ISTITLE'
else
:
utility_code
=
None
...
...
@@ -2897,41 +2941,9 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform):
args
[
arg_index
]
=
args
[
arg_index
].
coerce_to_boolean
(
self
.
current_env
())
unicode_tailmatch_utility_code
=
load_c_utility
(
'unicode_tailmatch'
)
bytes_tailmatch_utility_code
=
load_c_utility
(
'bytes_tailmatch'
)
str_tailmatch_utility_code
=
UtilityCode
(
proto
=
'''
static CYTHON_INLINE int __Pyx_PyStr_Tailmatch(PyObject* self, PyObject* arg, Py_ssize_t start,
Py_ssize_t end, int direction);
'''
,
# We do not use a C compiler macro here to avoid "unused function"
# warnings for the *_Tailmatch() function that is not being used in
# the specific CPython version. The C compiler will generate the same
# code anyway, and will usually just remove the unused function.
impl
=
'''
static CYTHON_INLINE int __Pyx_PyStr_Tailmatch(PyObject* self, PyObject* arg, Py_ssize_t start,
Py_ssize_t end, int direction)
{
if (PY_MAJOR_VERSION < 3)
return __Pyx_PyBytes_Tailmatch(self, arg, start, end, direction);
else
return __Pyx_PyUnicode_Tailmatch(self, arg, start, end, direction);
}
'''
,
requires
=
[
unicode_tailmatch_utility_code
,
bytes_tailmatch_utility_code
]
)
tpnew_utility_code
=
UtilityCode
(
proto
=
"""
static CYTHON_INLINE PyObject* __Pyx_tp_new(PyObject* type_obj) {
return (PyObject*) (((PyTypeObject*)(type_obj))->tp_new(
(PyTypeObject*)(type_obj), %(TUPLE)s, NULL));
}
"""
%
{
'TUPLE'
:
Naming
.
empty_tuple
}
)
unicode_tailmatch_utility_code
=
UtilityCode
.
load_cached
(
'unicode_tailmatch'
,
'StringTools.c'
)
bytes_tailmatch_utility_code
=
UtilityCode
.
load_cached
(
'bytes_tailmatch'
,
'StringTools.c'
)
str_tailmatch_utility_code
=
UtilityCode
.
load_cached
(
'str_tailmatch'
,
'StringTools.c'
)
class
ConstantFolding
(
Visitor
.
VisitorTransform
,
SkipDeclarations
):
...
...
@@ -2991,8 +3003,8 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
import
traceback
,
sys
traceback
.
print_exc
(
file
=
sys
.
stdout
)
NODE_TYPE_ORDER
=
[
ExprNodes
.
CharNode
,
ExprNodes
.
Int
Node
,
ExprNodes
.
Long
Node
,
ExprNodes
.
FloatNode
]
NODE_TYPE_ORDER
=
[
ExprNodes
.
BoolNode
,
ExprNodes
.
Char
Node
,
ExprNodes
.
Int
Node
,
ExprNodes
.
FloatNode
]
def
_widest_node_class
(
self
,
*
nodes
):
try
:
...
...
@@ -3011,13 +3023,13 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
return
node
if
not
node
.
operand
.
is_literal
:
return
node
if
isinstance
(
node
,
ExprNodes
.
NotNode
)
:
return
ExprNodes
.
BoolNode
(
node
.
pos
,
value
=
bool
(
node
.
constant_result
),
constant_result
=
bool
(
node
.
constant_result
))
if
node
.
operator
==
'!'
:
return
ExprNodes
.
BoolNode
(
node
.
pos
,
value
=
bool
(
node
.
constant_result
),
constant_result
=
bool
(
node
.
constant_result
))
elif
isinstance
(
node
.
operand
,
ExprNodes
.
BoolNode
):
return
ExprNodes
.
IntNode
(
node
.
pos
,
value
=
str
(
int
(
node
.
constant_result
)),
type
=
PyrexTypes
.
c_int_type
,
constant_result
=
int
(
node
.
constant_result
))
return
ExprNodes
.
IntNode
(
node
.
pos
,
value
=
str
(
int
(
node
.
constant_result
)),
type
=
PyrexTypes
.
c_int_type
,
constant_result
=
int
(
node
.
constant_result
))
elif
node
.
operator
==
'+'
:
return
self
.
_handle_UnaryPlusNode
(
node
)
elif
node
.
operator
==
'-'
:
...
...
@@ -3025,20 +3037,24 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
return
node
def
_handle_UnaryMinusNode
(
self
,
node
):
if
isinstance
(
node
.
operand
,
ExprNodes
.
LongNode
):
return
ExprNodes
.
LongNode
(
node
.
pos
,
value
=
'-'
+
node
.
operand
.
value
,
constant_result
=
node
.
constant_result
)
def
_negate
(
value
):
if
value
.
startswith
(
'-'
):
value
=
value
[
1
:]
else
:
value
=
'-'
+
value
return
value
if
isinstance
(
node
.
operand
,
ExprNodes
.
FloatNode
):
# this is a safe operation
return
ExprNodes
.
FloatNode
(
node
.
pos
,
value
=
'-'
+
node
.
operand
.
value
,
constant_result
=
node
.
constant_result
)
return
ExprNodes
.
FloatNode
(
node
.
pos
,
value
=
_negate
(
node
.
operand
.
value
)
,
constant_result
=
node
.
constant_result
)
node_type
=
node
.
operand
.
type
if
node_type
.
is_int
and
node_type
.
signed
or
\
isinstance
(
node
.
operand
,
ExprNodes
.
IntNode
)
and
node_type
.
is_pyobject
:
return
ExprNodes
.
IntNode
(
node
.
pos
,
value
=
'-'
+
node
.
operand
.
value
,
type
=
node_type
,
longness
=
node
.
operand
.
longness
,
constant_result
=
node
.
constant_result
)
isinstance
(
node
.
operand
,
ExprNodes
.
IntNode
)
and
node_type
.
is_pyobject
:
return
ExprNodes
.
IntNode
(
node
.
pos
,
value
=
_negate
(
node
.
operand
.
value
)
,
type
=
node_type
,
longness
=
node
.
operand
.
longness
,
constant_result
=
node
.
constant_result
)
return
node
def
_handle_UnaryPlusNode
(
self
,
node
):
...
...
@@ -3083,18 +3099,26 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
widest_type
=
PyrexTypes
.
widest_numeric_type
(
type1
,
type2
)
else
:
widest_type
=
PyrexTypes
.
py_object_type
target_class
=
self
.
_widest_node_class
(
operand1
,
operand2
)
if
target_class
is
None
:
return
node
elif
target_class
is
ExprNodes
.
IntNode
:
if
target_class
is
ExprNodes
.
BoolNode
and
node
.
operator
in
'+-//<<%**>>'
:
# C arithmetic results in at least an int type
target_class
=
ExprNodes
.
IntNode
if
target_class
is
ExprNodes
.
CharNode
and
node
.
operator
in
'+-//<<%**>>&|^'
:
# C arithmetic results in at least an int type
target_class
=
ExprNodes
.
IntNode
if
target_class
is
ExprNodes
.
IntNode
:
unsigned
=
getattr
(
operand1
,
'unsigned'
,
''
)
and
\
getattr
(
operand2
,
'unsigned'
,
''
)
longness
=
"LL"
[:
max
(
len
(
getattr
(
operand1
,
'longness'
,
''
)),
len
(
getattr
(
operand2
,
'longness'
,
''
)))]
new_node
=
ExprNodes
.
IntNode
(
pos
=
node
.
pos
,
unsigned
=
unsigned
,
longness
=
longness
,
value
=
str
(
node
.
constant_result
),
constant_result
=
node
.
constant_result
)
unsigned
=
unsigned
,
longness
=
longness
,
value
=
str
(
int
(
node
.
constant_result
)
),
constant_result
=
int
(
node
.
constant_result
)
)
# IntNode is smart about the type it chooses, so we just
# make sure we were not smarter this time
if
widest_type
.
is_pyobject
or
new_node
.
type
.
is_pyobject
:
...
...
@@ -3102,7 +3126,7 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
else
:
new_node
.
type
=
PyrexTypes
.
widest_numeric_type
(
widest_type
,
new_node
.
type
)
else
:
if
isinstance
(
node
,
ExprNodes
.
BoolNode
)
:
if
target_class
is
ExprNodes
.
BoolNode
:
node_value
=
node
.
constant_result
else
:
node_value
=
str
(
node
.
constant_result
)
...
...
@@ -3178,10 +3202,24 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
def
visit_SliceIndexNode
(
self
,
node
):
self
.
_calculate_const
(
node
)
# normalise start/stop values
if
node
.
start
and
node
.
start
.
constant_result
is
None
:
node
.
start
=
None
if
node
.
stop
and
node
.
stop
.
constant_result
is
None
:
node
.
stop
=
None
if
node
.
start
is
None
or
node
.
start
.
constant_result
is
None
:
start
=
node
.
start
=
None
else
:
start
=
node
.
start
.
constant_result
if
node
.
stop
is
None
or
node
.
stop
.
constant_result
is
None
:
stop
=
node
.
stop
=
None
else
:
stop
=
node
.
stop
.
constant_result
# cut down sliced constant sequences
if
node
.
constant_result
is
not
not_a_constant
:
base
=
node
.
base
if
base
.
is_sequence_constructor
:
base
.
args
=
base
.
args
[
start
:
stop
]
return
base
elif
base
.
is_string_literal
:
base
=
base
.
as_sliced_node
(
start
,
stop
)
if
base
is
not
None
:
return
base
return
node
def
visit_ForInStatNode
(
self
,
node
):
...
...
Cython/Compiler/Options.py
View file @
c73a9b2d
...
...
@@ -125,7 +125,8 @@ directive_defaults = {
# experimental, subject to change
'binding'
:
None
,
'experimental_cpp_class_def'
:
False
'experimental_cpp_class_def'
:
False
,
'freelist'
:
0
,
}
# Extra warning directives
...
...
@@ -155,6 +156,7 @@ directive_types = {
'cclass'
:
None
,
'returns'
:
type
,
'set_initial_path'
:
str
,
'freelist'
:
int
,
'c_string_type'
:
one_of
(
'bytes'
,
'str'
,
'unicoode'
),
}
...
...
@@ -172,7 +174,8 @@ directive_scopes = { # defaults to available everywhere
'set_initial_path'
:
(
'module'
,),
'test_assert_path_exists'
:
(
'function'
,
'class'
,
'cclass'
),
'test_fail_if_path_exists'
:
(
'function'
,
'class'
,
'cclass'
),
# Avoid scope-specific to/from_py_functions.
'freelist'
:
(
'cclass'
,),
# Avoid scope-specific to/from_py_functions for c_string.
'c_string_type'
:
(
'module'
,),
'c_string_encoding'
:
(
'module'
,),
}
...
...
Cython/Compiler/ParseTreeTransforms.py
View file @
c73a9b2d
...
...
@@ -883,6 +883,11 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
raise
PostParseError
(
pos
,
'The %s directive takes one compile-time boolean argument'
%
optname
)
return
(
optname
,
args
[
0
].
value
)
elif
directivetype
is
int
:
if
kwds
is
not
None
or
len
(
args
)
!=
1
or
not
isinstance
(
args
[
0
],
ExprNodes
.
IntNode
):
raise
PostParseError
(
pos
,
'The %s directive takes one compile-time integer argument'
%
optname
)
return
(
optname
,
int
(
args
[
0
].
value
))
elif
directivetype
is
str
:
if
kwds
is
not
None
or
len
(
args
)
!=
1
or
not
isinstance
(
args
[
0
],
(
ExprNodes
.
StringNode
,
ExprNodes
.
UnicodeNode
)):
...
...
Cython/Compiler/Parsing.py
View file @
c73a9b2d
...
...
@@ -693,6 +693,8 @@ def wrap_compile_time_constant(pos, value):
rep
=
repr
(
value
)
if
value
is
None
:
return
ExprNodes
.
NoneNode
(
pos
)
elif
value
is
Ellipsis
:
return
ExprNodes
.
EllipsisNode
(
pos
)
elif
isinstance
(
value
,
bool
):
return
ExprNodes
.
BoolNode
(
pos
,
value
=
value
)
elif
isinstance
(
value
,
int
):
...
...
Cython/Compiler/PyrexTypes.py
View file @
c73a9b2d
...
...
@@ -984,8 +984,8 @@ class BuiltinObjectType(PyObjectType):
def
isinstance_code
(
self
,
arg
):
return
'%s(%s)'
%
(
self
.
type_check_function
(
exact
=
False
),
arg
)
def
type_test_code
(
self
,
arg
,
notnone
=
False
):
type_check
=
self
.
type_check_function
(
exact
=
True
)
def
type_test_code
(
self
,
arg
,
notnone
=
False
,
exact
=
True
):
type_check
=
self
.
type_check_function
(
exact
=
exact
)
check
=
'likely(%s(%s))'
%
(
type_check
,
arg
)
if
not
notnone
:
check
+=
'||((%s) == Py_None)'
%
arg
...
...
@@ -1033,9 +1033,6 @@ class PyExtensionType(PyObjectType):
is_extension_type
=
1
has_attributes
=
1
def
needs_nonecheck
(
self
):
return
True
objtypedef_cname
=
None
def
__init__
(
self
,
name
,
typedef_flag
,
base_type
,
is_external
=
0
):
...
...
@@ -1060,6 +1057,9 @@ class PyExtensionType(PyObjectType):
if
scope
:
scope
.
parent_type
=
self
def
needs_nonecheck
(
self
):
return
True
def
subtype_of_resolved_type
(
self
,
other_type
):
if
other_type
.
is_extension_type
or
other_type
.
is_builtin_type
:
return
self
is
other_type
or
(
...
...
Cython/Compiler/Symtab.py
View file @
c73a9b2d
...
...
@@ -1310,6 +1310,7 @@ class ModuleScope(Scope):
if
defining
or
implementing
:
scope
=
CClassScope
(
name
=
name
,
outer_scope
=
self
,
visibility
=
visibility
)
scope
.
directives
=
self
.
directives
.
copy
()
if
base_type
and
base_type
.
scope
:
scope
.
declare_inherited_c_attributes
(
base_type
.
scope
)
type
.
set_scope
(
scope
)
...
...
@@ -1891,7 +1892,7 @@ class CClassScope(ClassScope):
def
declare_cfunction
(
self
,
name
,
type
,
pos
,
cname
=
None
,
visibility
=
'private'
,
api
=
0
,
in_pxd
=
0
,
defining
=
0
,
modifiers
=
(),
utility_code
=
None
):
if
get_special_method_signature
(
name
):
if
get_special_method_signature
(
name
)
and
not
self
.
parent_type
.
is_builtin_type
:
error
(
pos
,
"Special methods must be declared with 'def', not 'cdef'"
)
args
=
type
.
args
if
not
args
:
...
...
Cython/Compiler/TypeSlots.py
View file @
c73a9b2d
...
...
@@ -493,11 +493,13 @@ def get_special_method_signature(name):
else
:
return
None
def
get_property_accessor_signature
(
name
):
# Return signature of accessor for an extension type
# property, else None.
return
property_accessor_signatures
.
get
(
name
)
def
get_base_slot_function
(
scope
,
slot
):
# Returns the function implementing this slot in the baseclass.
# This is useful for enabling the compiler to optimize calls
...
...
@@ -511,6 +513,18 @@ def get_base_slot_function(scope, slot):
return
parent_slot
return
None
def
get_slot_function
(
scope
,
slot
):
# Returns the function implementing this slot in the baseclass.
# This is useful for enabling the compiler to optimize calls
# that recursively climb the class hierarchy.
slot_code
=
slot
.
slot_code
(
scope
)
if
slot_code
!=
'0'
:
entry
=
scope
.
parent_scope
.
lookup_here
(
scope
.
parent_type
.
name
)
if
entry
.
visibility
!=
'extern'
:
return
slot_code
return
None
#------------------------------------------------------------------------------------------
#
# Signatures for generic Python functions and methods.
...
...
Cython/Compiler/Visitor.pxd
View file @
c73a9b2d
...
...
@@ -28,8 +28,13 @@ cdef class EnvTransform(CythonTransform):
cdef
public
list
env_stack
cdef
class
MethodDispatcherTransform
(
EnvTransform
):
@
cython
.
final
cdef
_visit_binop_node
(
self
,
node
)
@
cython
.
final
cdef
_find_handler
(
self
,
match_name
,
bint
has_kwargs
)
@
cython
.
final
cdef
_dispatch_to_handler
(
self
,
node
,
function
,
arg_list
,
kwargs
)
@
cython
.
final
cdef
_dispatch_to_method_handler
(
self
,
attr_name
,
self_arg
,
is_unbound_method
,
type_name
,
node
,
arg_list
,
kwargs
)
...
...
Cython/Compiler/Visitor.py
View file @
c73a9b2d
...
...
@@ -492,7 +492,17 @@ class MethodDispatcherTransform(EnvTransform):
args
=
node
.
args
return
self
.
_dispatch_to_handler
(
node
,
function
,
args
,
None
)
def
visit_PrimaryCmpNode
(
self
,
node
):
if
node
.
cascade
:
# not currently handled below
self
.
visitchildren
(
node
)
return
node
return
self
.
_visit_binop_node
(
node
)
def
visit_BinopNode
(
self
,
node
):
return
self
.
_visit_binop_node
(
node
)
def
_visit_binop_node
(
self
,
node
):
self
.
visitchildren
(
node
)
# FIXME: could special case 'not_in'
special_method_name
=
find_special_method_for_binary_operator
(
node
.
operator
)
...
...
@@ -591,7 +601,7 @@ class MethodDispatcherTransform(EnvTransform):
if
self_arg
is
not
None
:
arg_list
=
[
self_arg
]
+
list
(
arg_list
)
if
kwargs
:
return
method_handler
(
node
,
arg_list
,
kwargs
,
is_unbound_method
)
return
method_handler
(
node
,
arg_list
,
is_unbound_method
,
kwargs
)
else
:
return
method_handler
(
node
,
arg_list
,
is_unbound_method
)
...
...
Cython/Utility/ObjectHandling.c
View file @
c73a9b2d
...
...
@@ -650,3 +650,11 @@ bad:
__Pyx_PyObject_CallMethodTuple(obj, name, PyTuple_Pack(1, arg1))
#define __Pyx_PyObject_CallMethod0(obj, name) \
__Pyx_PyObject_CallMethodTuple(obj, name, (Py_INCREF($empty_tuple), $empty_tuple))
/////////////// tp_new.proto ///////////////
#define __Pyx_tp_new(type_obj, args) __Pyx_tp_new_kwargs(type_obj, args, NULL)
static
CYTHON_INLINE
PyObject
*
__Pyx_tp_new_kwargs
(
PyObject
*
type_obj
,
PyObject
*
args
,
PyObject
*
kwargs
)
{
return
(
PyObject
*
)
(((
PyTypeObject
*
)
type_obj
)
->
tp_new
((
PyTypeObject
*
)
type_obj
,
args
,
kwargs
));
}
Cython/Utility/Optimize.c
View file @
c73a9b2d
...
...
@@ -112,163 +112,6 @@ static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix) {
}
/////////////// py_unicode_istitle.proto ///////////////
// Py_UNICODE_ISTITLE() doesn't match unicode.istitle() as the latter
// additionally allows character that comply with Py_UNICODE_ISUPPER()
#if PY_VERSION_HEX < 0x030200A2
static
CYTHON_INLINE
int
__Pyx_Py_UNICODE_ISTITLE
(
Py_UNICODE
uchar
)
#else
static
CYTHON_INLINE
int
__Pyx_Py_UNICODE_ISTITLE
(
Py_UCS4
uchar
)
#endif
{
return
Py_UNICODE_ISTITLE
(
uchar
)
||
Py_UNICODE_ISUPPER
(
uchar
);
}
/////////////// unicode_tailmatch.proto ///////////////
// Python's unicode.startswith() and unicode.endswith() support a
// tuple of prefixes/suffixes, whereas it's much more common to
// test for a single unicode string.
static
int
__Pyx_PyUnicode_Tailmatch
(
PyObject
*
s
,
PyObject
*
substr
,
Py_ssize_t
start
,
Py_ssize_t
end
,
int
direction
)
{
if
(
unlikely
(
PyTuple_Check
(
substr
)))
{
Py_ssize_t
i
,
count
=
PyTuple_GET_SIZE
(
substr
);
for
(
i
=
0
;
i
<
count
;
i
++
)
{
int
result
;
#if CYTHON_COMPILING_IN_CPYTHON
result
=
PyUnicode_Tailmatch
(
s
,
PyTuple_GET_ITEM
(
substr
,
i
),
start
,
end
,
direction
);
#else
PyObject
*
sub
=
PySequence_GetItem
(
substr
,
i
);
if
(
unlikely
(
!
sub
))
return
-
1
;
result
=
PyUnicode_Tailmatch
(
s
,
sub
,
start
,
end
,
direction
);
Py_DECREF
(
sub
);
#endif
if
(
result
)
{
return
result
;
}
}
return
0
;
}
return
PyUnicode_Tailmatch
(
s
,
substr
,
start
,
end
,
direction
);
}
/////////////// bytes_tailmatch.proto ///////////////
static
int
__Pyx_PyBytes_SingleTailmatch
(
PyObject
*
self
,
PyObject
*
arg
,
Py_ssize_t
start
,
Py_ssize_t
end
,
int
direction
)
{
const
char
*
self_ptr
=
PyBytes_AS_STRING
(
self
);
Py_ssize_t
self_len
=
PyBytes_GET_SIZE
(
self
);
const
char
*
sub_ptr
;
Py_ssize_t
sub_len
;
int
retval
;
#if PY_VERSION_HEX >= 0x02060000
Py_buffer
view
;
view
.
obj
=
NULL
;
#endif
if
(
PyBytes_Check
(
arg
)
)
{
sub_ptr
=
PyBytes_AS_STRING
(
arg
);
sub_len
=
PyBytes_GET_SIZE
(
arg
);
}
#if PY_MAJOR_VERSION < 3
// Python 2.x allows mixing unicode and str
else
if
(
PyUnicode_Check
(
arg
)
)
{
return
PyUnicode_Tailmatch
(
self
,
arg
,
start
,
end
,
direction
);
}
#endif
else
{
#if PY_VERSION_HEX < 0x02060000
if
(
unlikely
(
PyObject_AsCharBuffer
(
arg
,
&
sub_ptr
,
&
sub_len
)))
return
-
1
;
#else
if
(
unlikely
(
PyObject_GetBuffer
(
self
,
&
view
,
PyBUF_SIMPLE
)
==
-
1
))
return
-
1
;
sub_ptr
=
(
const
char
*
)
view
.
buf
;
sub_len
=
view
.
len
;
#endif
}
if
(
end
>
self_len
)
end
=
self_len
;
else
if
(
end
<
0
)
end
+=
self_len
;
if
(
end
<
0
)
end
=
0
;
if
(
start
<
0
)
start
+=
self_len
;
if
(
start
<
0
)
start
=
0
;
if
(
direction
>
0
)
{
/* endswith */
if
(
end
-
sub_len
>
start
)
start
=
end
-
sub_len
;
}
if
(
start
+
sub_len
<=
end
)
retval
=
!
memcmp
(
self_ptr
+
start
,
sub_ptr
,
sub_len
);
else
retval
=
0
;
#if PY_VERSION_HEX >= 0x02060000
if
(
view
.
obj
)
PyBuffer_Release
(
&
view
);
#endif
return
retval
;
}
static
int
__Pyx_PyBytes_Tailmatch
(
PyObject
*
self
,
PyObject
*
substr
,
Py_ssize_t
start
,
Py_ssize_t
end
,
int
direction
)
{
if
(
unlikely
(
PyTuple_Check
(
substr
)))
{
Py_ssize_t
i
,
count
=
PyTuple_GET_SIZE
(
substr
);
for
(
i
=
0
;
i
<
count
;
i
++
)
{
int
result
;
#if CYTHON_COMPILING_IN_CPYTHON
result
=
__Pyx_PyBytes_SingleTailmatch
(
self
,
PyTuple_GET_ITEM
(
substr
,
i
),
start
,
end
,
direction
);
#else
PyObject
*
sub
=
PySequence_GetItem
(
substr
,
i
);
if
(
unlikely
(
!
sub
))
return
-
1
;
result
=
__Pyx_PyBytes_SingleTailmatch
(
self
,
sub
,
start
,
end
,
direction
);
Py_DECREF
(
sub
);
#endif
if
(
result
)
{
return
result
;
}
}
return
0
;
}
return
__Pyx_PyBytes_SingleTailmatch
(
self
,
substr
,
start
,
end
,
direction
);
}
/////////////// bytes_index.proto ///////////////
static
CYTHON_INLINE
char
__Pyx_PyBytes_GetItemInt
(
PyObject
*
bytes
,
Py_ssize_t
index
,
int
check_bounds
)
{
if
(
check_bounds
)
{
Py_ssize_t
size
=
PyBytes_GET_SIZE
(
bytes
);
if
(
unlikely
(
index
>=
size
)
|
((
index
<
0
)
&
unlikely
(
index
<
-
size
)))
{
PyErr_Format
(
PyExc_IndexError
,
"string index out of range"
);
return
-
1
;
}
}
if
(
index
<
0
)
index
+=
PyBytes_GET_SIZE
(
bytes
);
return
PyBytes_AS_STRING
(
bytes
)[
index
];
}
/////////////// dict_getitem_default.proto ///////////////
static
PyObject
*
__Pyx_PyDict_GetItemDefault
(
PyObject
*
d
,
PyObject
*
key
,
PyObject
*
default_value
);
/*proto*/
...
...
Cython/Utility/StringTools.c
View file @
c73a9b2d
...
...
@@ -109,6 +109,14 @@ static CYTHON_INLINE int __Pyx_PyUnicodeBufferContainsUCS4(Py_UNICODE* buffer, P
}
//////////////////// PyUnicodeContains.proto ////////////////////
static
CYTHON_INLINE
int
__Pyx_PyUnicode_Contains
(
PyObject
*
substring
,
PyObject
*
text
,
int
eq
)
{
int
result
=
PyUnicode_Contains
(
text
,
substring
);
return
unlikely
(
result
<
0
)
?
result
:
(
result
==
(
eq
==
Py_EQ
));
}
//////////////////// StrEquals.proto ////////////////////
//@requires: BytesEquals
//@requires: UnicodeEquals
...
...
@@ -410,3 +418,183 @@ static CYTHON_INLINE PyObject* __Pyx_PyUnicode_Substring(
return
PyUnicode_FromUnicode
(
PyUnicode_AS_UNICODE
(
text
)
+
start
,
stop
-
start
);
#endif
}
/////////////// py_unicode_istitle.proto ///////////////
// Py_UNICODE_ISTITLE() doesn't match unicode.istitle() as the latter
// additionally allows character that comply with Py_UNICODE_ISUPPER()
#if PY_VERSION_HEX < 0x030200A2
static
CYTHON_INLINE
int
__Pyx_Py_UNICODE_ISTITLE
(
Py_UNICODE
uchar
)
#else
static
CYTHON_INLINE
int
__Pyx_Py_UNICODE_ISTITLE
(
Py_UCS4
uchar
)
#endif
{
return
Py_UNICODE_ISTITLE
(
uchar
)
||
Py_UNICODE_ISUPPER
(
uchar
);
}
/////////////// unicode_tailmatch.proto ///////////////
// Python's unicode.startswith() and unicode.endswith() support a
// tuple of prefixes/suffixes, whereas it's much more common to
// test for a single unicode string.
static
int
__Pyx_PyUnicode_Tailmatch
(
PyObject
*
s
,
PyObject
*
substr
,
Py_ssize_t
start
,
Py_ssize_t
end
,
int
direction
)
{
if
(
unlikely
(
PyTuple_Check
(
substr
)))
{
Py_ssize_t
i
,
count
=
PyTuple_GET_SIZE
(
substr
);
for
(
i
=
0
;
i
<
count
;
i
++
)
{
int
result
;
#if CYTHON_COMPILING_IN_CPYTHON
result
=
PyUnicode_Tailmatch
(
s
,
PyTuple_GET_ITEM
(
substr
,
i
),
start
,
end
,
direction
);
#else
PyObject
*
sub
=
PySequence_GetItem
(
substr
,
i
);
if
(
unlikely
(
!
sub
))
return
-
1
;
result
=
PyUnicode_Tailmatch
(
s
,
sub
,
start
,
end
,
direction
);
Py_DECREF
(
sub
);
#endif
if
(
result
)
{
return
result
;
}
}
return
0
;
}
return
PyUnicode_Tailmatch
(
s
,
substr
,
start
,
end
,
direction
);
}
/////////////// bytes_tailmatch.proto ///////////////
static
int
__Pyx_PyBytes_SingleTailmatch
(
PyObject
*
self
,
PyObject
*
arg
,
Py_ssize_t
start
,
Py_ssize_t
end
,
int
direction
)
{
const
char
*
self_ptr
=
PyBytes_AS_STRING
(
self
);
Py_ssize_t
self_len
=
PyBytes_GET_SIZE
(
self
);
const
char
*
sub_ptr
;
Py_ssize_t
sub_len
;
int
retval
;
#if PY_VERSION_HEX >= 0x02060000
Py_buffer
view
;
view
.
obj
=
NULL
;
#endif
if
(
PyBytes_Check
(
arg
)
)
{
sub_ptr
=
PyBytes_AS_STRING
(
arg
);
sub_len
=
PyBytes_GET_SIZE
(
arg
);
}
#if PY_MAJOR_VERSION < 3
// Python 2.x allows mixing unicode and str
else
if
(
PyUnicode_Check
(
arg
)
)
{
return
PyUnicode_Tailmatch
(
self
,
arg
,
start
,
end
,
direction
);
}
#endif
else
{
#if PY_VERSION_HEX < 0x02060000
if
(
unlikely
(
PyObject_AsCharBuffer
(
arg
,
&
sub_ptr
,
&
sub_len
)))
return
-
1
;
#else
if
(
unlikely
(
PyObject_GetBuffer
(
self
,
&
view
,
PyBUF_SIMPLE
)
==
-
1
))
return
-
1
;
sub_ptr
=
(
const
char
*
)
view
.
buf
;
sub_len
=
view
.
len
;
#endif
}
if
(
end
>
self_len
)
end
=
self_len
;
else
if
(
end
<
0
)
end
+=
self_len
;
if
(
end
<
0
)
end
=
0
;
if
(
start
<
0
)
start
+=
self_len
;
if
(
start
<
0
)
start
=
0
;
if
(
direction
>
0
)
{
/* endswith */
if
(
end
-
sub_len
>
start
)
start
=
end
-
sub_len
;
}
if
(
start
+
sub_len
<=
end
)
retval
=
!
memcmp
(
self_ptr
+
start
,
sub_ptr
,
sub_len
);
else
retval
=
0
;
#if PY_VERSION_HEX >= 0x02060000
if
(
view
.
obj
)
PyBuffer_Release
(
&
view
);
#endif
return
retval
;
}
static
int
__Pyx_PyBytes_Tailmatch
(
PyObject
*
self
,
PyObject
*
substr
,
Py_ssize_t
start
,
Py_ssize_t
end
,
int
direction
)
{
if
(
unlikely
(
PyTuple_Check
(
substr
)))
{
Py_ssize_t
i
,
count
=
PyTuple_GET_SIZE
(
substr
);
for
(
i
=
0
;
i
<
count
;
i
++
)
{
int
result
;
#if CYTHON_COMPILING_IN_CPYTHON
result
=
__Pyx_PyBytes_SingleTailmatch
(
self
,
PyTuple_GET_ITEM
(
substr
,
i
),
start
,
end
,
direction
);
#else
PyObject
*
sub
=
PySequence_GetItem
(
substr
,
i
);
if
(
unlikely
(
!
sub
))
return
-
1
;
result
=
__Pyx_PyBytes_SingleTailmatch
(
self
,
sub
,
start
,
end
,
direction
);
Py_DECREF
(
sub
);
#endif
if
(
result
)
{
return
result
;
}
}
return
0
;
}
return
__Pyx_PyBytes_SingleTailmatch
(
self
,
substr
,
start
,
end
,
direction
);
}
/////////////// str_tailmatch.proto ///////////////
static
CYTHON_INLINE
int
__Pyx_PyStr_Tailmatch
(
PyObject
*
self
,
PyObject
*
arg
,
Py_ssize_t
start
,
Py_ssize_t
end
,
int
direction
);
/////////////// str_tailmatch ///////////////
//@requires: bytes_tailmatch
//@requires: unicode_tailmatch
static
CYTHON_INLINE
int
__Pyx_PyStr_Tailmatch
(
PyObject
*
self
,
PyObject
*
arg
,
Py_ssize_t
start
,
Py_ssize_t
end
,
int
direction
)
{
// We do not use a C compiler macro here to avoid "unused function"
// warnings for the *_Tailmatch() function that is not being used in
// the specific CPython version. The C compiler will generate the same
// code anyway, and will usually just remove the unused function.
if
(
PY_MAJOR_VERSION
<
3
)
return
__Pyx_PyBytes_Tailmatch
(
self
,
arg
,
start
,
end
,
direction
);
else
return
__Pyx_PyUnicode_Tailmatch
(
self
,
arg
,
start
,
end
,
direction
);
}
/////////////// bytes_index.proto ///////////////
static
CYTHON_INLINE
char
__Pyx_PyBytes_GetItemInt
(
PyObject
*
bytes
,
Py_ssize_t
index
,
int
check_bounds
)
{
if
(
check_bounds
)
{
Py_ssize_t
size
=
PyBytes_GET_SIZE
(
bytes
);
if
(
unlikely
(
index
>=
size
)
|
((
index
<
0
)
&
unlikely
(
index
<
-
size
)))
{
PyErr_Format
(
PyExc_IndexError
,
"string index out of range"
);
return
-
1
;
}
}
if
(
index
<
0
)
index
+=
PyBytes_GET_SIZE
(
bytes
);
return
PyBytes_AS_STRING
(
bytes
)[
index
];
}
docs/src/userguide/extension_types.rst
View file @
c73a9b2d
...
...
@@ -339,6 +339,7 @@ subtyped at the C level by foreign code.
C methods
=========
Extension types can have C methods as well as Python methods. Like C
functions, C methods are declared using :keyword:`cdef` or :keyword:`cpdef` instead of
:keyword:`def`. C methods are "virtual", and may be overridden in derived
...
...
@@ -379,6 +380,7 @@ method using the usual Python technique, i.e.::
Parrot.describe(self)
Forward-declaring extension types
===================================
...
...
@@ -405,6 +407,52 @@ definition, for example,::
cdef class A(B):
# attributes and methods
Fast instantiation
===================
Cython provides two ways to speed up the instantiation of extension types.
The first one is a direct call to the ``__new__()`` special static method,
as known from Python. For an extension type ``Penguin``, you could use
the following code::
cdef class Penguin:
cdef object food
def __cinit__(self, food):
self.food = food
def __init__(self, food):
print("eating!")
normal_penguin = Penguin('fish')
fast_penguin = Penguin.__new__(Penguin, 'wheat') # note: not calling __init__() !
Note that the path through ``__new__()`` will *not* call the type's
``__init__()`` method (again, as known from Python). Thus, in the example
above, the first instantiation will print ``eating!``, but the second will
not. This is only one of the reasons why the ``__cinit__()`` method is
safer and preferable over the normal ``__init__()`` method for extension
types.
The second performance improvement applies to types that are often created
and deleted in a row, so that they can benefit from a freelist. Cython
provides the decorator ``@cython.freelist(N)`` for this, which creates a
statically sized freelist of ``N`` instances for a given type. Example::
cimport cython
@cython.freelist(8)
cdef class Penguin:
cdef object food
def __cinit__(self, food):
self.food = food
penguin = Penguin('fish 1')
penguin = None
penguin = Penguin('fish 2') # does not need to allocate memory!
Making extension types weak-referenceable
==========================================
...
...
@@ -418,6 +466,7 @@ object called :attr:`__weakref__`. For example,::
cdef object __weakref__
Public and external extension types
====================================
...
...
runtests.py
View file @
c73a9b2d
...
...
@@ -746,7 +746,8 @@ class CythonRunTestCase(CythonCompileTestCase):
self.success = False
self.runCompileTest()
failures, errors = len(result.failures), len(result.errors)
self.run_tests(result)
if not self.cython_only:
self.run_tests(result)
if failures == len(result.failures) and errors == len(result.errors):
# No new errors...
self.success = True
...
...
@@ -761,8 +762,7 @@ class CythonRunTestCase(CythonCompileTestCase):
pass
def run_tests(self, result):
if not self.cython_only:
self.run_doctests(self.module, result)
self.run_doctests(self.module, result)
def run_doctests(self, module_name, result):
def run_test(result):
...
...
tests/errors/e_exttype_freelist.pyx
0 → 100644
View file @
c73a9b2d
# mode: error
# tag: freelist, werror
cimport
cython
@
cython
.
freelist
(
8
)
cdef
class
ExtType
:
pass
@
cython
.
freelist
(
8
)
cdef
class
ExtTypeObject
(
object
):
pass
cdef
class
ExtSubTypeOk
(
ExtType
):
pass
@
cython
.
freelist
(
8
)
cdef
class
ExtSubTypeFail
(
ExtType
):
pass
_ERRORS
=
"""
18:5: freelists cannot be used on subtypes, only the base class can manage them
"""
tests/run/constant_folding.py
0 → 100644
View file @
c73a9b2d
# coding=utf8
# mode: run
# tag: constant_folding
import
cython
@
cython
.
test_fail_if_path_exists
(
"//UnaryMinusNode"
,
"//UnaryPlusNode"
,
)
def
unop_floats
():
"""
>>> unop_floats()
(False, 2.0, -2.0, False, 2.0, -2.0, -2.0)
"""
not1
=
not
2.0
plus1
=
+
2.0
minus1
=
-
2.0
not3
=
not
not
not
2.0
plus3
=
+++
2.0
minus3
=
---
2.0
mix
=
+-++--
2.0
return
not1
,
plus1
,
minus1
,
not3
,
plus3
,
minus3
,
mix
@
cython
.
test_fail_if_path_exists
(
"//UnaryMinusNode"
,
"//UnaryPlusNode"
,
)
def
unop_ints
():
"""
>>> unop_ints()
(False, 2, -2, False, 2, -2, -2)
"""
not1
=
not
2
plus1
=
+
2
minus1
=
-
2
not3
=
not
not
not
2
plus3
=
+++
2
minus3
=
---
2
mix
=
+-++--
2
return
not1
,
plus1
,
minus1
,
not3
,
plus3
,
minus3
,
mix
@
cython
.
test_fail_if_path_exists
(
"//UnaryMinusNode"
,
"//UnaryPlusNode"
,
"//NotNode"
,
)
def
unop_bool
():
"""
>>> unop_bool()
(False, 1, -1, False, 1, -1, -1)
"""
not1
=
not
True
plus1
=
+
True
minus1
=
-
True
not3
=
not
not
not
True
plus3
=
+++
True
minus3
=
---
True
mix
=
+-++--
True
return
not1
,
plus1
,
minus1
,
not3
,
plus3
,
minus3
,
mix
@
cython
.
test_fail_if_path_exists
(
"//AddNode"
,
"//SubNode"
,
)
def
binop_bool
():
"""
>>> binop_bool()
(2, 1, 0, True, True, 1, False, 2, 2, -2, False, True, 1, False)
"""
plus1
=
True
+
True
pmix1
=
True
+
0
minus1
=
True
-
True
and1
=
True
&
True
or1
=
True
|
True
ormix1
=
True
|
0
xor1
=
True
^
True
plus3
=
False
+
True
+
False
+
True
pmix3
=
False
+
True
+
0
+
True
minus3
=
False
-
True
-
False
-
True
and3
=
False
&
True
&
False
&
True
or3
=
False
|
True
|
False
|
True
ormix3
=
False
|
0
|
False
|
True
xor3
=
False
^
True
^
False
^
True
return
plus1
,
pmix1
,
minus1
,
and1
,
or1
,
ormix1
,
xor1
,
plus3
,
pmix3
,
minus3
,
and3
,
or3
,
ormix3
,
xor3
@
cython
.
test_fail_if_path_exists
(
"//SliceIndexNode"
,
)
def
slicing2
():
"""
>>> slicing2()
([1, 2, 3, 4], [3, 4], [1, 2, 3, 4], [3, 4], (1, 2, 3, 4), (3, 4), (1, 2, 3, 4), (3, 4))
"""
lst0
=
[
1
,
2
,
3
,
4
][:]
lst1
=
[
1
,
2
,
3
,
4
][
2
:]
lst2
=
[
1
,
2
,
3
,
4
][:
4
]
lst3
=
[
1
,
2
,
3
,
4
][
2
:
4
]
tpl0
=
(
1
,
2
,
3
,
4
)[:]
tpl1
=
(
1
,
2
,
3
,
4
)[
2
:]
tpl2
=
(
1
,
2
,
3
,
4
)[:
4
]
tpl3
=
(
1
,
2
,
3
,
4
)[
2
:
4
]
return
lst0
,
lst1
,
lst2
,
lst3
,
tpl0
,
tpl1
,
tpl2
,
tpl3
@
cython
.
test_fail_if_path_exists
(
"//SliceIndexNode"
,
)
def
str_slicing2
():
"""
>>> a,b,c,d = str_slicing2()
>>> a == 'abc
\
\
xE9def'[:]
True
>>> b == 'abc
\
\
xE9def'[2:]
True
>>> c == 'abc
\
\
xE9def'[:4]
True
>>> d == 'abc
\
\
xE9def'[2:4]
True
"""
str0
=
'abc
\
xE9
def'
[:]
str1
=
'abc
\
xE9
def'
[
2
:]
str2
=
'abc
\
xE9
def'
[:
4
]
str3
=
'abc
\
xE9
def'
[
2
:
4
]
return
str0
,
str1
,
str2
,
str3
tests/run/constant_folding_cy.pyx
0 → 100644
View file @
c73a9b2d
# coding=utf8
# mode: run
# tag: constant_folding
cimport
cython
bstring
=
b'abc
\
xE9
def'
ustring
=
u'abc
\
xE9
def'
surrogates_ustring
=
u'abc
\
U00010000
def'
@
cython
.
test_fail_if_path_exists
(
"//SliceIndexNode"
,
)
def
bytes_slicing2
():
"""
>>> a,b,c,d = bytes_slicing2()
>>> a == bstring[:]
True
>>> b == bstring[2:]
True
>>> c == bstring[:4]
True
>>> d == bstring[2:4]
True
"""
str0
=
b'abc
\
xE9
def'
[:]
str1
=
b'abc
\
xE9
def'
[
2
:]
str2
=
b'abc
\
xE9
def'
[:
4
]
str3
=
b'abc
\
xE9
def'
[
2
:
4
]
return
str0
,
str1
,
str2
,
str3
@
cython
.
test_fail_if_path_exists
(
"//SliceIndexNode"
,
)
def
unicode_slicing2
():
"""
>>> a,b,c,d = unicode_slicing2()
>>> a == ustring[:]
True
>>> b == ustring[2:]
True
>>> c == ustring[:4]
True
>>> d == ustring[2:4]
True
"""
str0
=
u'abc
\
xE9
def'
[:]
str1
=
u'abc
\
xE9
def'
[
2
:]
str2
=
u'abc
\
xE9
def'
[:
4
]
str3
=
u'abc
\
xE9
def'
[
2
:
4
]
return
str0
,
str1
,
str2
,
str3
@
cython
.
test_assert_path_exists
(
"//SliceIndexNode"
,
)
def
unicode_slicing_unsafe_surrogates2
():
"""
>>> unicode_slicing_unsafe_surrogates2() == surrogates_ustring[2:]
True
"""
ustring
=
u'abc
\
U00010000
def'
[
2
:]
return
ustring
@
cython
.
test_fail_if_path_exists
(
"//SliceIndexNode"
,
)
def
unicode_slicing_safe_surrogates2
():
"""
>>> unicode_slicing_safe_surrogates2() == surrogates_ustring[:2]
True
>>> print(unicode_slicing_safe_surrogates2())
ab
"""
ustring
=
u'abc
\
U00010000
def'
[:
2
]
return
ustring
tests/run/ct_DEF.pyx
View file @
c73a9b2d
...
...
@@ -29,8 +29,10 @@ DEF TRUE = TRUE_FALSE[0]
DEF
FALSE
=
TRUE_FALSE
[
1
]
DEF
INT_TUPLE1
=
TUPLE
[:
2
]
DEF
INT_TUPLE2
=
TUPLE
[
1
:
4
:
2
]
DEF
ELLIPSIS
=
...
DEF
EXPRESSION
=
int
(
float
(
2
*
2
))
+
int
(
str
(
2
))
+
int
(
max
(
1
,
2
,
3
))
+
sum
([
TWO
,
FIVE
])
def
c
():
"""
>>> c()
...
...
@@ -148,6 +150,13 @@ def false():
cdef
bint
false
=
FALSE
return
false
def
ellipsis
():
"""
>>> ellipsis()
Ellipsis
"""
return
ELLIPSIS
@
cython
.
test_assert_path_exists
(
'//IntNode'
)
@
cython
.
test_fail_if_path_exists
(
'//AddNode'
)
def
expression
():
...
...
tests/run/exttype_freelist.pyx
0 → 100644
View file @
c73a9b2d
# mode: run
# tag: freelist
cimport
cython
@
cython
.
freelist
(
8
)
cdef
class
ExtTypeNoGC
:
"""
>>> obj = ExtTypeNoGC()
>>> obj = ExtTypeNoGC()
>>> obj = ExtTypeNoGC()
>>> obj = ExtTypeNoGC()
>>> obj = ExtTypeNoGC()
>>> obj = ExtTypeNoGC()
"""
@
cython
.
freelist
(
8
)
cdef
class
ExtTypeWithGC
:
"""
>>> obj = ExtTypeWithGC()
>>> obj = ExtTypeWithGC()
>>> obj = ExtTypeWithGC()
>>> obj = ExtTypeWithGC()
>>> obj = ExtTypeWithGC()
>>> obj = ExtTypeWithGC()
"""
cdef
attribute
def
__init__
(
self
):
self
.
attribute
=
object
()
def
tpnew_ExtTypeWithGC
():
"""
>>> obj = tpnew_ExtTypeWithGC()
>>> obj = tpnew_ExtTypeWithGC()
>>> obj = tpnew_ExtTypeWithGC()
>>> obj = tpnew_ExtTypeWithGC()
>>> obj = tpnew_ExtTypeWithGC()
>>> obj = tpnew_ExtTypeWithGC()
"""
return
ExtTypeWithGC
.
__new__
(
ExtTypeWithGC
)
cdef
class
ExtSubType
(
ExtTypeWithGC
):
"""
>>> obj = ExtSubType()
>>> obj = ExtSubType()
>>> obj = ExtSubType()
>>> obj = ExtSubType()
>>> obj = ExtSubType()
>>> obj = ExtSubType()
"""
cdef
class
LargerExtSubType
(
ExtSubType
):
"""
>>> obj = LargerExtSubType()
>>> obj = LargerExtSubType()
>>> obj = LargerExtSubType()
>>> obj = LargerExtSubType()
>>> obj = LargerExtSubType()
>>> obj = LargerExtSubType()
"""
cdef
attribute2
def
__cinit__
(
self
):
self
.
attribute2
=
object
()
@
cython
.
freelist
(
8
)
cdef
class
ExtTypeWithRefCycle
:
"""
>>> obj = first = ExtTypeWithRefCycle()
>>> obj.attribute is None
True
>>> obj = ExtTypeWithRefCycle(obj)
>>> obj.attribute is first
True
>>> obj = ExtTypeWithRefCycle(obj)
>>> obj = ExtTypeWithRefCycle(obj)
>>> obj = ExtTypeWithRefCycle(obj)
>>> obj = ExtTypeWithRefCycle(obj)
>>> obj.attribute is not None
True
>>> first.attribute = obj
>>> del obj, first
"""
cdef
public
attribute
def
__init__
(
self
,
obj
=
None
):
self
.
attribute
=
obj
tests/run/tp_new.pyx
View file @
c73a9b2d
...
...
@@ -2,28 +2,32 @@
cimport
cython
cdef
class
MyType
:
def
__cinit__
(
self
):
cdef
public
args
,
kwargs
def
__cinit__
(
self
,
*
args
,
**
kwargs
):
self
.
args
,
self
.
kwargs
=
args
,
kwargs
print
"CINIT"
def
__init__
(
self
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
print
"INIT"
cdef
class
MySubType
(
MyType
):
def
__cinit__
(
self
):
def
__cinit__
(
self
,
*
args
,
**
kwargs
):
self
.
args
,
self
.
kwargs
=
args
,
kwargs
print
"CINIT(SUB)"
def
__init__
(
self
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
print
"INIT"
class
MyClass
(
object
):
def
__cinit__
(
self
):
def
__cinit__
(
self
,
*
args
,
**
kwargs
):
self
.
args
,
self
.
kwargs
=
args
,
kwargs
print
"CINIT"
def
__init__
(
self
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
print
"INIT"
class
MyTypeSubClass
(
MyType
):
def
__cinit__
(
self
):
def
__cinit__
(
self
,
*
args
,
**
kwargs
):
# not called: Python class!
print
"CINIT(PYSUB)"
def
__init__
(
self
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
print
"INIT"
# only these can be safely optimised:
...
...
@@ -51,6 +55,36 @@ def make_new_typed_target():
m
=
MyType
.
__new__
(
MyType
)
return
m
@
cython
.
test_assert_path_exists
(
'//PythonCapiCallNode'
)
@
cython
.
test_fail_if_path_exists
(
'//SimpleCallNode/AttributeNode'
)
def
make_new_with_args
():
"""
>>> isinstance(make_new_with_args(), MyType)
CINIT
(1, 2, 3)
{}
True
"""
m
=
MyType
.
__new__
(
MyType
,
1
,
2
,
3
)
print
m
.
args
print
m
.
kwargs
return
m
@
cython
.
test_assert_path_exists
(
'//PythonCapiCallNode'
)
@
cython
.
test_fail_if_path_exists
(
'//SimpleCallNode/AttributeNode'
)
def
make_new_with_args_kwargs
():
"""
>>> isinstance(make_new_with_args_kwargs(), MyType)
CINIT
(1, 2, 3)
{'a': 4}
True
"""
m
=
MyType
.
__new__
(
MyType
,
1
,
2
,
3
,
a
=
4
)
print
m
.
args
print
m
.
kwargs
return
m
@
cython
.
test_assert_path_exists
(
'//PythonCapiCallNode'
)
@
cython
.
test_fail_if_path_exists
(
'//SimpleCallNode/AttributeNode'
)
def
make_new_builtin
():
...
...
tests/run/tp_new_cimport.srctree
0 → 100644
View file @
c73a9b2d
PYTHON setup.py build_ext --inplace
PYTHON -c "import tp_new_tests; tp_new_tests.test_all()"
PYTHON -c "import tp_new_tests; tp_new_tests.test_sub()"
######## setup.py ########
from Cython.Build.Dependencies import cythonize
from distutils.core import setup
setup(
ext_modules = cythonize("**/*.pyx"),
)
######## tp_new_tests.py ########
def test_all():
test_a()
test_b()
test_a_in_b()
test_sub()
def test_a():
import a
assert isinstance(a.tpnew_ExtTypeA(), a.ExtTypeA)
assert a.tpnew_ExtTypeA().attrA == 123
def test_b():
import b
assert isinstance(b.tpnew_ExtTypeB(), b.ExtTypeB)
assert b.tpnew_ExtTypeB().attrB == 234
def test_a_in_b():
import a,b
assert isinstance(b.tpnew_ExtTypeA(), a.ExtTypeA)
assert b.tpnew_ExtTypeA().attrA == 123
def test_sub():
import b
assert isinstance(b.tpnew_SubExtTypeA(), b.SubExtTypeA)
assert b.tpnew_SubExtTypeA().attrAB == 345
assert b.tpnew_SubExtTypeA().attrA == 123
######## a.pxd ########
cdef class ExtTypeA:
cdef readonly attrA
######## a.pyx ########
cdef class ExtTypeA:
def __cinit__(self):
self.attrA = 123
def tpnew_ExtTypeA():
return ExtTypeA.__new__(ExtTypeA)
######## b.pxd ########
from a cimport ExtTypeA
cdef class ExtTypeB:
cdef readonly attrB
cdef class SubExtTypeA(ExtTypeA):
cdef readonly attrAB
######## b.pyx ########
from a cimport ExtTypeA
cdef class ExtTypeB:
def __cinit__(self):
self.attrB = 234
cdef class SubExtTypeA(ExtTypeA):
def __cinit__(self):
self.attrAB = 345
def tpnew_ExtTypeA():
return ExtTypeA.__new__(ExtTypeA)
def tpnew_ExtTypeB():
return ExtTypeB.__new__(ExtTypeB)
def tpnew_SubExtTypeA():
return SubExtTypeA.__new__(SubExtTypeA)
tests/run/unbound_special_methods.pyx
0 → 100644
View file @
c73a9b2d
# mode: run
# tag: special_method
cimport
cython
text
=
u'ab jd sdflk as sa sadas asdas fsdf '
@
cython
.
test_fail_if_path_exists
(
"//CoerceFromPyTypeNode"
)
@
cython
.
test_assert_path_exists
(
"//CoerceToPyTypeNode"
,
"//AttributeNode"
,
"//AttributeNode[@entry.cname = 'PyUnicode_Contains']"
)
def
unicode_contains
(
unicode
s
,
substring
):
"""
>>> unicode_contains(text, 'fl')
True
>>> unicode_contains(text, 'XYZ')
False
>>> unicode_contains(None, 'XYZ')
Traceback (most recent call last):
AttributeError: 'NoneType' object has no attribute '__contains__'
"""
return
s
.
__contains__
(
substring
)
@
cython
.
test_fail_if_path_exists
(
"//CoerceFromPyTypeNode"
)
@
cython
.
test_assert_path_exists
(
# "//CoerceToPyTypeNode",
"//NameNode[@entry.cname = 'PyUnicode_Contains']"
)
def
unicode_contains_unbound
(
unicode
s
,
substring
):
"""
>>> unicode_contains_unbound(text, 'fl')
True
>>> unicode_contains_unbound(text, 'XYZ')
False
>>> unicode_contains_unbound(None, 'XYZ') # doctest: +ELLIPSIS
Traceback (most recent call last):
TypeError: descriptor '__contains__' requires a '...' object but received a 'NoneType'
"""
return
unicode
.
__contains__
(
s
,
substring
)
cdef
class
UnicodeSubclass
(
unicode
):
"""
>>> u = UnicodeSubclass(text)
>>> 'fl' in u
False
>>> 'XYZ' in u
True
>>> u.method('fl')
False
>>> u.method('XYZ')
True
>>> u.operator('fl')
False
>>> u.operator('XYZ')
True
"""
def
__contains__
(
self
,
substring
):
return
substring
not
in
(
self
+
u'x'
)
def
method
(
self
,
other
):
return
self
.
__contains__
(
other
)
def
operator
(
self
,
other
):
return
other
in
self
tests/run/unicode_slicing.pyx
View file @
c73a9b2d
# coding: utf-8
__doc__
=
u"""
>>>
do_slice1
(u'abcdef', 2, 3)
>>>
slice_start_end
(u'abcdef', 2, 3)
c
>>>
do_slice2
(u'abcdef', 2, 3)
>>>
slice_start
(u'abcdef', 2, 3)
cdef
>>>
do_slice3
(u'abcdef', 2, 3)
>>>
slice_end
(u'abcdef', 2, 3)
ab
>>>
do_slice4
(u'abcdef', 2, 3)
>>>
slice_all
(u'abcdef', 2, 3)
abcdef
>>>
do_slice5
(u'abcdef', 2, 3)
>>>
slice_start_none
(u'abcdef', 2, 3)
cdef
>>>
do_slice6
(u'abcdef', 2, 3)
>>>
slice_none_end
(u'abcdef', 2, 3)
ab
>>>
do_slice7
(u'abcdef', 2, 3)
>>>
slice_none_none
(u'abcdef', 2, 3)
abcdef
>>> do_slice1(u'abcdef', 2, 10)
>>> slice_start_end(u'abcdef', 2, 10)
cdef
>>>
do_slice2
(u'abcdef', 2, 10)
>>>
slice_start
(u'abcdef', 2, 10)
cdef
>>>
do_slice3
(u'abcdef', 2, 10)
>>>
slice_end
(u'abcdef', 2, 10)
ab
>>>
do_slice4
(u'abcdef', 2, 10)
>>>
slice_all
(u'abcdef', 2, 10)
abcdef
>>> do_slice1(u'abcdef', 0, 5)
>>> slice_start_end(u'abcdef', 0, 5)
abcde
>>>
do_slice2
(u'abcdef', 0, 5)
>>>
slice_start
(u'abcdef', 0, 5)
abcdef
>>>
do_slice3
(u'abcdef', 0, 5)
>>>
slice_end
(u'abcdef', 0, 5)
<BLANKLINE>
>>>
do_slice4
(u'abcdef', 0, 5)
>>>
slice_all
(u'abcdef', 0, 5)
abcdef
>>>
do_slice5
(u'abcdef', 0, 5)
>>>
slice_start_none
(u'abcdef', 0, 5)
abcdef
>>>
do_slice6
(u'abcdef', 0, 5)
>>>
slice_none_end
(u'abcdef', 0, 5)
<BLANKLINE>
>>>
do_slice7
(u'abcdef', 0, 5)
>>>
slice_none_none
(u'abcdef', 0, 5)
abcdef
>>> do_slice1(u'abcdef', -6, -1)
>>> slice_start_end(u'abcdef', -6, -1)
abcde
>>> do_slice2(u'abcdef', -6, -1)
>>> slice_start(u'abcdef', -6, -1)
abcdef
>>> slice_end(u'abcdef', -6, -1)
<BLANKLINE>
>>> slice_all(u'abcdef', -6, -1)
abcdef
>>> slice_start_none(u'abcdef', -6, -1)
abcdef
>>>
do_slice3
(u'abcdef', -6, -1)
>>>
slice_none_end
(u'abcdef', -6, -1)
<BLANKLINE>
>>>
do_slice4
(u'abcdef', -6, -1)
>>>
slice_none_none
(u'abcdef', -6, -1)
abcdef
>>> do_slice5(u'abcdef', -6, -1)
>>> slice_start_end(u'abcdef', -6, -7)
<BLANKLINE>
>>> slice_start(u'abcdef', -6, -7)
abcdef
>>> slice_end(u'abcdef', -6, -7)
<BLANKLINE>
>>> slice_all(u'abcdef', -6, -7)
abcdef
>>> slice_start_none(u'abcdef', -6, -7)
abcdef
>>>
do_slice6(u'abcdef', -6, -1
)
>>>
slice_none_end(u'abcdef', -6, -7
)
<BLANKLINE>
>>>
do_slice7(u'abcdef', -6, -1
)
>>>
slice_none_none(u'abcdef', -6, -7
)
abcdef
>>> do_slice1(u'aАbБcСdДeЕfФ', 2, 8)
>>> slice_start_end(u'abcdef', -7, -7)
<BLANKLINE>
>>> slice_start(u'abcdef', -7, -7)
abcdef
>>> slice_end(u'abcdef', -7, -7)
<BLANKLINE>
>>> slice_all(u'abcdef', -7, -7)
abcdef
>>> slice_start_none(u'abcdef', -7, -7)
abcdef
>>> slice_none_end(u'abcdef', -7, -7)
<BLANKLINE>
>>> slice_none_none(u'abcdef', -7, -7)
abcdef
>>> slice_start_end(u'aАbБcСdДeЕfФ', 2, 8)
bБcСdД
>>>
do_slice2
(u'aАbБcСdДeЕfФ', 2, 8)
>>>
slice_start
(u'aАbБcСdДeЕfФ', 2, 8)
bБcСdДeЕfФ
>>>
do_slice3
(u'aАbБcСdДeЕfФ', 2, 8)
>>>
slice_end
(u'aАbБcСdДeЕfФ', 2, 8)
aА
>>>
do_slice4
(u'aАbБcСdДeЕfФ', 2, 8)
>>>
slice_all
(u'aАbБcСdДeЕfФ', 2, 8)
aАbБcСdДeЕfФ
>>>
do_slice5
(u'aАbБcСdДeЕfФ', 2, 8)
>>>
slice_start_none
(u'aАbБcСdДeЕfФ', 2, 8)
bБcСdДeЕfФ
>>>
do_slice6
(u'aАbБcСdДeЕfФ', 2, 8)
>>>
slice_none_end
(u'aАbБcСdДeЕfФ', 2, 8)
aА
>>>
do_slice7
(u'aАbБcСdДeЕfФ', 2, 8)
>>>
slice_none_none
(u'aАbБcСdДeЕfФ', 2, 8)
aАbБcСdДeЕfФ
>>> do_slice1(u'АБСДЕФ', 2, 4)
>>> slice_start_end(u'АБСДЕФ', 2, 4)
СД
>>>
do_slice2
(u'АБСДЕФ', 2, 4)
>>>
slice_start
(u'АБСДЕФ', 2, 4)
СДЕФ
>>>
do_slice3
(u'АБСДЕФ', 2, 4)
>>>
slice_end
(u'АБСДЕФ', 2, 4)
АБ
>>>
do_slice4
(u'АБСДЕФ', 2, 4)
>>>
slice_all
(u'АБСДЕФ', 2, 4)
АБСДЕФ
>>>
do_slice5
(u'АБСДЕФ', 2, 4)
>>>
slice_start_none
(u'АБСДЕФ', 2, 4)
СДЕФ
>>>
do_slice6
(u'АБСДЕФ', 2, 4)
>>>
slice_none_end
(u'АБСДЕФ', 2, 4)
АБ
>>>
do_slice7
(u'АБСДЕФ', 2, 4)
>>>
slice_none_none
(u'АБСДЕФ', 2, 4)
АБСДЕФ
>>> do_slice1(u'АБСДЕФ', -4, -2)
>>> slice_start_end(u'АБСДЕФ', -4, -2)
СД
>>>
do_slice2
(u'АБСДЕФ', -4, -2)
>>>
slice_start
(u'АБСДЕФ', -4, -2)
СДЕФ
>>>
do_slice3
(u'АБСДЕФ', -4, -2)
>>>
slice_end
(u'АБСДЕФ', -4, -2)
АБ
>>>
do_slice4
(u'АБСДЕФ', -4, -2)
>>>
slice_all
(u'АБСДЕФ', -4, -2)
АБСДЕФ
>>>
do_slice5
(u'АБСДЕФ', -4, -2)
>>>
slice_start_none
(u'АБСДЕФ', -4, -2)
СДЕФ
>>>
do_slice6
(u'АБСДЕФ', -4, -2)
>>>
slice_none_end
(u'АБСДЕФ', -4, -2)
АБ
>>>
do_slice7
(u'АБСДЕФ', -4, -2)
>>>
slice_none_none
(u'АБСДЕФ', -4, -2)
АБСДЕФ
>>> do_slice1(None, 2, 4)
>>> slice_start_end(None, 2, 4)
Traceback (most recent call last):
TypeError: 'NoneType' object is not subscriptable
>>>
do_slice2
(None, 2, 4)
>>>
slice_start
(None, 2, 4)
Traceback (most recent call last):
TypeError: 'NoneType' object is not subscriptable
>>>
do_slice3
(None, 2, 4)
>>>
slice_end
(None, 2, 4)
Traceback (most recent call last):
TypeError: 'NoneType' object is not subscriptable
>>>
do_slice4
(None, 2, 4)
>>>
slice_all
(None, 2, 4)
Traceback (most recent call last):
TypeError: 'NoneType' object is not subscriptable
>>>
do_slice5
(None, 2, 4)
>>>
slice_start_none
(None, 2, 4)
Traceback (most recent call last):
TypeError: 'NoneType' object is not subscriptable
>>>
do_slice6
(None, 2, 4)
>>>
slice_none_end
(None, 2, 4)
Traceback (most recent call last):
TypeError: 'NoneType' object is not subscriptable
>>>
do_slice7
(None, 2, 4)
>>>
slice_none_none
(None, 2, 4)
Traceback (most recent call last):
TypeError: 'NoneType' object is not subscriptable
"""
...
...
@@ -121,23 +158,23 @@ import sys
if
sys
.
version_info
[
0
]
>=
3
:
__doc__
=
__doc__
.
replace
(
u"(u'"
,
u"('"
).
replace
(
u" u'"
,
u" '"
)
def
do_slice1
(
unicode
s
,
int
i
,
int
j
):
def
slice_start_end
(
unicode
s
,
int
i
,
int
j
):
print
(
s
[
i
:
j
])
def
do_slice2
(
unicode
s
,
int
i
,
int
j
):
def
slice_start
(
unicode
s
,
int
i
,
int
j
):
print
(
s
[
i
:])
def
do_slice3
(
unicode
s
,
int
i
,
int
j
):
def
slice_end
(
unicode
s
,
int
i
,
int
j
):
print
(
s
[:
i
])
def
do_slice4
(
unicode
s
,
int
i
,
int
j
):
def
slice_all
(
unicode
s
,
int
i
,
int
j
):
print
(
s
[:])
def
do_slice5
(
unicode
s
,
int
i
,
int
j
):
def
slice_start_none
(
unicode
s
,
int
i
,
int
j
):
print
(
s
[
i
:
None
])
def
do_slice6
(
unicode
s
,
int
i
,
int
j
):
def
slice_none_end
(
unicode
s
,
int
i
,
int
j
):
print
(
s
[
None
:
i
])
def
do_slice7
(
unicode
s
,
int
i
,
int
j
):
def
slice_none_none
(
unicode
s
,
int
i
,
int
j
):
print
(
s
[
None
:
None
])
tests/run/unicodemethods.pyx
View file @
c73a9b2d
...
...
@@ -364,6 +364,25 @@ def endswith_start_end(unicode s, sub, start, end):
return
'NO MATCH'
# unicode.__contains__(s, sub)
@
cython
.
test_fail_if_path_exists
(
"//CoerceFromPyTypeNode"
,
"//AttributeNode"
)
@
cython
.
test_assert_path_exists
(
"//CoerceToPyTypeNode"
,
"//PrimaryCmpNode"
)
def
in_test
(
unicode
s
,
substring
):
"""
>>> in_test(text, 'sa')
True
>>> in_test(text, 'XYZ')
False
>>> in_test(None, 'sa')
Traceback (most recent call last):
TypeError: 'NoneType' object is not iterable
"""
return
substring
in
s
# unicode.find(s, sub, [start, [end]])
@
cython
.
test_fail_if_path_exists
(
...
...
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